;;; -*- Mode: Lisp; Package: editor -*- ;;; frame-util.l --- フレーム関連拡張 Lisp。 ;; ;; Created: [2006/05/12] ;; Last updated: [2007/09/26] ;; ;;; Commentary: ;; ;; フレーム関連拡張 Lisp。以下のような事ができます。 ;; ;; ・フレーム毎のバッファ、ウィンドウ状態 (フレームセッション) をファ ;; イルに保存。 ;; ;; ・カレントフレームにフレームセッション情報をロード。ロードするファ ;; イルも選択可能。 ;; ;; ・タブ並び順でフレーム移動。移動時、保存したフレームセッションをロ ;; ード可能。 ;; ;; ・フレーム名を指定して移動 & フレームセッションロード。 ;; ・フレーム削除。削除するフレームをミニバッファで指定可能。 ;; ;; ・新規フレーム作成。ミニバッファでフレーム名を指定可能。そのフレー ;; ム名のフレームセッションがあればロード。 ;; ;; ;; ダウンロードページ :http://www5f.biglobe.ne.jp/~memo/dir/index.html ;; 不具合報告とか :http://www5f.biglobe.ne.jp/~memo/chalow/2007-06-23-1.html ;; ;; ;; 導入: ;; ;; ".xyzzy" か "siteinit.l" に以下を記述。キー設定 (global-set-key の ;; 所) は各自の好みに合わせて変更して下さい。 ;; ;; (in-package "editor") ;; ;;==================================== ;; ;; フレーム名を指定して移動 ;; ;; ;; ;; 数引数を付け実行したとき、移動前のフレームセッションを保存しバッ ;; ;; ファを削除、そして移動し移動先のフレームセッションをロードする。 ;; ;; ;; (autoload 'frame-util-select-pframe "frame-util" t) ;; (global-set-key #\F4 'frame-util-select-pframe) ;; ;; ;;==================================== ;; ;; フレーム削除 ;; ;; ;; ;; 数引数を付け実行したとき、削除するフレームをミニバッファで指定できる。 ;; ;; ;; (autoload 'frame-util-delete-pseudo-frame "frame-util" t) ;; (global-set-key '(#\C-x #\M-k) 'frame-util-delete-pseudo-frame) ;; ;; ;;==================================== ;; ;; フレームセッション保存 ;; ;; ;; ;; 数引数を付け実行したとき、保存ファイル名を指定できる。 ;; ;; ;; (autoload 'frame-util-save-session "frame-util" t) ;; (global-set-key '(#\C-x #\M-s) 'frame-util-save-session) ;; ;; ;;==================================== ;; ;; 新規フレーム作成 ;; ;; ;; ;; 数引数を付け実行したとき、作成するフレーム名を指定でき、移動前の ;; ;; フレームセッションを保存したのち指定したフレーム名を作成。またそ ;; ;; のフレームセッションがあればロードする。 ;; ;; ;; (autoload 'frame-util-session-new-pframe "frame-util" t) ;; (global-set-key #\M-F4 'frame-util-session-new-pframe) ;; ;; ;;==================================== ;; ;; カレントフレームにフレームセッション情報をロード ;; ;; ;; ;; 数引数を付け実行したとき、ロードするフレームセッションファイルを ;; ;; 選択できる。 ;; ;; ;; (autoload 'frame-util-load-session-current-frame "frame-util" t) ;; (global-set-key #\C-M-F4 'frame-util-load-session-current-frame) ;; ;; ;;==================================== ;; ;; タブ並び順で前のフレームに移動 ;; ;; ;; ;; 数引数を付け実行したとき、フレームセッションの保存 & ロードを行う。 ;; ;; ;; (autoload 'frame-util-session-previous-pframe "frame-util" t) ;; (global-set-key #\M-F2 'frame-util-session-previous-pframe) ;; ;; ;;==================================== ;; ;; タブ並び順で次のフレームに移動 ;; ;; ;; ;; 数引数を付け実行したとき、フレームセッションの保存 & ロードを行う。 ;; ;; ;; (autoload 'frame-util-session-next-pframe "frame-util" t) ;; (global-set-key #\M-F3 'frame-util-session-next-pframe) ;; (in-package "user") ;; ;; ;; 設定: ;; ;; (setf ;; ;; フレームセッションファイルの保存ディレクトリパス ;; *frame-util-session-path* (concat (user-config-path) ;; ".frame-util/" ;; ) ;; ;; 削除しないバッファのリスト ;; *frame-util-buffer-list* '( ;; "*Buffer List*" ;; "*grep*" ;; "*info*" ;; "*info2*" ;; "*Reference*" ;; "*scratch*" ;; "*Shell*" ;; ) ;; ;; フレームセッションを保存 & ロードしないフレームのリスト ;; *frame-util-frame-list* '( ;; "2ch" ;; "CalMemo" ;; "cFTP" ;; "HE" ;; "infoman" ;; "KaMail" ;; "RSS" ;; ) ;; ) ;; ;;; Change Log: ;; ;; 2007-09-26 ;; ;; * frame-util-session-new-pframe がおかしかったのを修正。 ;; ;; * frame-util-session-new-pframe でフレーム名を補完入力可能に。 ;; ;; 2007-06-23 ;; ;; * 初版公開。 ;; ;; ;; めも: ;; ;; ネットワーク越しのファイルをたくさん開くとき遅かった。 ;; ;;; License: ;; ;; Copyright (c) 2007, Masanori Miyajima. All rights reserved. ;; ;; Redistribution and use in source and binary forms, with or without ;; modification, are permitted provided that the following conditions ;; are met: ;; ;; * Redistributions of source code must retain the above copyright ;; notice, this list of conditions and the following disclaimer. ;; ;; * Redistributions in binary form must reproduce the above copyright ;; notice, this list of conditions and the following disclaimer in ;; the documentation and/or other materials provided with the ;; distribution. ;; ;; * The names of itscontributors may be used to endorse or promote ;; products derived from this software without specific prior written ;; permission. ;; ;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS ;; IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ;; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ;; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ;; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ;; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ;; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ;; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ;; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;; ;;; Code: (provide "frame-util") (in-package "editor") (export '( *frame-util-session-path* *frame-util-buffer-list* *frame-util-frame-list* frame-util-next-pframe frame-util-previous-pframe frame-util-select-pframe frame-util-delete-pseudo-frame frame-util-save-session frame-util-session-new-pframe frame-util-load-session-current-frame frame-util-session-previous-pframe frame-util-session-next-pframe ) "editor" ) ;;; フレーム構造体 (defstruct (pseudo-frame (:constructor pseudo-frame-constructor (name winconf save-p selected-fn deleted-fn) ) ) name winconf save-p selected-fn deleted-fn ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Defvar (defvar *frame-util-session-path* (concat (user-config-path) ".frame-util/" ) "フレームセッションファイルの保存ディレクトリパス。" ) (defvar *frame-util-buffer-list* '( "*Buffer List*" "*grep*" "*info*" "*info2*" "*Reference*" "*scratch*" "*Shell*" ) "削除しないバッファのリスト。" ) (defvar *frame-util-frame-list* '( "2ch" "CalMemo" "cFTP" "HE" "infoman" "KaMail" "RSS" ) "フレームセッションを保存 & ロードしないフレームのリスト。" ) ;;; Defvar ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Defun (defun frame-util-move-frame (&optional arg) "\ タブ並び順でフレーム移動。 ARG:t のとき前、nil のとき次のフレームに移動。 フレームが 1 つ以上ないと nil を返す。 " (let ( ;; 現在のフレームの *pseudo-frame-list* 中の位置 (先頭 1) (let-frame-list-pos (1+ (position (pseudo-frame-name *current-pseudo-frame*) *pseudo-frame-list* :key #'pseudo-frame-name :test #'string= ) ) ) ;; *pseudo-frame-list* の要素数 (let-frame-list-len (length *pseudo-frame-list*)) ) (if (> let-frame-list-len 1) ;; フレームが 2 つ以上ある時 (progn (if arg ;; 前のフレーム (if (= let-frame-list-pos 1) (setf let-frame-list-pos let-frame-list-len) (setf let-frame-list-pos (1- let-frame-list-pos)) ) ;; 次のフレーム (if (= let-frame-list-pos let-frame-list-len) (setf let-frame-list-pos 1) (setf let-frame-list-pos (1+ let-frame-list-pos)) ) ) ;; フレーム移動 (select-pseudo-frame (nth (1- let-frame-list-pos) *pseudo-frame-list*)) t ) ;; フレームが 1 つのとき nil ) ) ) ;;==================================== ;; Session (defun frame-util-restore-session (binfo finfo) "\ フレームセッション状態復元。 " ;; ウィンドウ状態保存 (save-current-pseudo-frame) ;; バッファ復元 (restore-buffer-info binfo) (let ( (let-current nil) (let-frame (or (find-pseudo-frame (car finfo)) (create-pseudo-frame-1 (car finfo) t) ) ) ) (setf (pseudo-frame-winconf let-frame) (readable-winconf-to-winconf (cadr finfo))) (when (caddr finfo) (setf let-current let-frame) ) (when let-current (setf *current-pseudo-frame* nil) (select-pseudo-frame let-current) ) ) ) (defun frame-util-save-session-info (stream) "\ フレームセッションファイルの内容を出力。 STREAM:フレームセッションファイルへのストリーム。 " ;; 現ウィンドウ状態保存 (save-current-pseudo-frame) (let* ( ;; カレントフレーム (let-frame *current-pseudo-frame*) ;; フレーム名、ウィンドウ状態、カレントフレームか (t or nil) のリスト (let-finfo (list (pseudo-frame-name let-frame) (winconf-to-readable-winconf (pseudo-frame-winconf let-frame)) (eq let-frame *current-pseudo-frame*) ) ) ;; 全バッファ情報のリスト (let-binfo (list-buffer-info)) ) ;;==================================== ;; フレームセッションファイルの出力 (princ ";;; frame-util session file.\n" stream) (write `(in-package ,(package-name *package*)) :stream stream :escape t) (terpri stream) (write `(frame-util-restore-session ',let-binfo ',let-finfo) :stream stream :escape t) (terpri stream) ;; フレームセッションファイルの出力 ;;==================================== ) ) (defun frame-util-write-session-file (file-path) "\ フレームセッションファイルを作成。 FILE-PATH:作成するフレームセッションファイルのパス。 " (unless (file-directory-p *frame-util-session-path*) ;; 保存ディレクトリがなければ作成 (create-directory *frame-util-session-path*) ) (with-open-file ( stream file-path :direction :output :if-exists :supersede :if-does-not-exist :create ) (frame-util-save-session-info stream) t ) ) (defun frame-util-load-session (file-path) "\ フレームセッションファイルをロード。 FILE-PATH:ロードするフレームセッションファイルのパス。 FILE-PATH がフレームセッションファイルでなければエラー、読込不可のとき nil、そうでなければ t を返す。 " (if (file-readable-p file-path) (progn (with-open-file ( s file-path :direction :input :if-does-not-exist :error ) (unless (equal (read-line s nil) ";;; frame-util session file.") (error "frame-util Session File ではありません") ) ) (long-operation (load file-path :verbose nil :print nil) ) t ) ;; ファイルが読込不可のとき nil ) ) (defun frame-util-save-session-kill-buffer (frame-name) "\ 指定フレームでなければフレームセッションを保存 & バッファ削除。 FRAME-NAME:フレームセッションを保存するフレーム名。 成功すれば t、指定フレームであれば nil を返す。 " (if (find frame-name *frame-util-frame-list* :test 'string= ) ;; 指定フレームのとき nil (progn ;; フレームセッションファイルを作成 (frame-util-write-session-file (merge-pathnames frame-name *frame-util-session-path* ) ) ;; バッファ削除 (dolist (list-buff (buffer-list) t) ;; 隠しバッファ、指定バッファでなければ削除 (unless (or (string-equal (buffer-name list-buff) " " :start1 0 :end1 1 ) (find (buffer-name list-buff) *frame-util-buffer-list* :test 'string= ) ) (kill-buffer list-buff) ) ) ) ) ) (defun frame-util-session-move-frame (arg session-p) "\ タブ並び順でフレーム移動。 ARG : t - 前のフレーム。 nil - 次のフレーム。 SESSION-P : t - セッションを保存 & ロード。 nil - セッションを保存 & ロードしない。 " (let ( ;; フレーム名 (まずは移動前フレーム名を設定) (let-frame-name (pseudo-frame-name *current-pseudo-frame*)) ;; 移動先フレームのフレームセッションファイルパス let-session-file-path ) (if session-p ;; 指定フレームでなければ移動前のフレームセッション保存 & バッファ削除 (frame-util-save-session-kill-buffer let-frame-name) ) ;; フレーム移動 (when (frame-util-move-frame arg) ;; 移動先フレーム名設定 (setf let-frame-name (pseudo-frame-name *current-pseudo-frame*)) (if (or (not session-p) (find (intern let-frame-name) *frame-util-frame-list* :test 'string= ) ) ;; 指定フレームのとき nil ;; SESSION-P が t かつ指定フレームでなければフレームセッションロード (progn ;; フレームセッションファイルパス (setf let-session-file-path (merge-pathnames let-frame-name *frame-util-session-path* ) ) ;; フレームセッションロード (frame-util-load-session let-session-file-path) ) ) ) ) ) ;; Session ;;==================================== ;;==================================== ;; Interactive (defun frame-util-next-pframe () "\ タブ並び順で次のフレームに移動。 " (interactive) (frame-util-move-frame) ) (defun frame-util-previous-pframe () "\ タブ並び順で前のフレームに移動。 " (interactive) (frame-util-move-frame t) ) ;;------------------------------------ ;; Session (defun frame-util-select-pframe (frame-name &optional arg) "\ フレーム名を指定して移動。 数引数を付け実行したとき、移動前のフレームセッションを保存しバッファを削 除、そして移動し移動先のフレームセッションをロードする。 FRAME-NAME:移動するフレーム名。 ARG: t のとき移動前フレームのバッファ削除 & フレームセッション保存をし、移動 先のフレームセッションをロード。 指定したフレーム名 FRAME-NAME が存在しなければエラー、ARG が nil or 指定 フレームのとき nil を返す。 " (interactive (list (completing-read "Frame: " (mapcar #'pseudo-frame-name *pseudo-frame-list*) :must-match t ) (if *prefix-args* ;; 数引数を付け実行したとき t ) ) ) (let ( ;; フレームセッションファイルパス let-session-file-path ) (if arg ;; 指定フレームでなければフレームセッション保存 & バッファ削除 (frame-util-save-session-kill-buffer (pseudo-frame-name *current-pseudo-frame*)) ) ;; フレーム移動 (select-pseudo-frame (or (find-pseudo-frame frame-name) (error "~aはフレームではありません" frame-name) ) ) (if (or (not arg) (find frame-name *frame-util-frame-list* :test 'string= ) ) ;; ARG が nil or 指定フレームのとき nil ;; ARG が non-nil で指定フレームでなければフレームセッションロード (progn ;; フレームセッションファイルパス (setf let-session-file-path (merge-pathnames frame-name *frame-util-session-path* ) ) ;; フレームセッションロード (if (frame-util-load-session let-session-file-path) (progn (message "Load \"~A\"." frame-name) t ) (progn (message "フレームセッション\"~A\"はありません。" frame-name) nil ) ) ) ) ) ) (defun frame-util-delete-pseudo-frame (frame) "\ フレーム削除。 数引数が付いたとき削除するフレームを指定できる。 FRAME:削除するフレーム。 " (interactive (list (if *prefix-args* ;; 数引数付きで呼び出されたとき (find-pseudo-frame (completing-read "Frame: " (mapcar #'pseudo-frame-name *pseudo-frame-list*) :must-match t ) ) ;; カレントフレーム *current-pseudo-frame* ) ) ) (pseudo-frame-check-minibuffer) (and (pseudo-frame-deleted-fn frame) (funcall (pseudo-frame-deleted-fn frame)) ) (when (eq frame *current-pseudo-frame*) (other-pseudo-frame) ) (setf *pseudo-frame-list* (delete (pseudo-frame-name frame) *pseudo-frame-list* :key #'pseudo-frame-name :test #'string= ) ) (when (tool-bar-exist-p 'pseudo-frame-bar) (tab-bar-delete-item 'pseudo-frame-bar frame) ) (unless *pseudo-frame-list* (init-pseudo-frame) ) t ) (defun frame-util-save-session (file-name) "\ フレームセッション保存。 数引数を付け実行したとき、保存ファイル名を指定できる。 FILE-NAME:保存するフレームセッションファイル名。 " (interactive (list (if *prefix-args* (read-string "File Name: ") ;; カレントフレーム名 (pseudo-frame-name *current-pseudo-frame*) ) ) ) (frame-util-write-session-file (merge-pathnames file-name *frame-util-session-path* ) ) (message "Save \"~A\"." file-name) t ) (defun frame-util-session-new-pframe (frame-name) "\ 新規フレーム作成。 数引数付きで実行すると作成するフレーム名を指定でき、移動前のフレームセッ ションを保存したのち指定したフレーム名を作成し、そのフレームセッションが あればロードする。 FRAME-NAME:作成するフレーム名。 " (interactive (list (progn ;; ミニバッファであればエラー (pseudo-frame-check-minibuffer) ;; 新規フレーム名定義 (multiple-value-bind (def counter) (unique-pseudo-frame-name) (let ( (let-name (if *prefix-args* (completing-read "New frame: " (mapcar #'file-namestring (directory *frame-util-session-path* :absolute t) ) :default def ) "" ) ) ) (when (or (string= let-name "") (string= let-name def) ) (setf let-name def) (setf *pseudo-frame-counter* (+ counter 1)) ) let-name ) ) ) ) ) (if *prefix-args* ;; フレームセッション保存 (frame-util-write-session-file (merge-pathnames (pseudo-frame-name *current-pseudo-frame*) *frame-util-session-path* ) ) ) ;; フレーム作成 (create-pseudo-frame frame-name) ;; 数引数付きで実行し指定フレームでなければフレームセッションをロード (if (or (not *prefix-args*) (find frame-name *frame-util-frame-list* :test 'string= ) ) ;; 数引数付きでない or 指定フレームのとき nil ;; フレームセッションロード (if (frame-util-load-session (merge-pathnames frame-name *frame-util-session-path* ) ) (progn (message "Load \"~A\"" frame-name) t ) (progn (message "フレームセッション\"~A\"はありません。" frame-name) nil ) ) ) ) (defun frame-util-load-session-current-frame (session) "\ カレントフレームにフレームセッション情報をロード。 数引数を付け実行したとき、ロードするフレームセッションファイルを選択でき る。 SESSION:ロードするセッションファイル名。 " (interactive (list (if *prefix-args* ;; 数引数付きで呼び出されたとき (completing-read "Session: " (mapcar #'file-namestring (directory *frame-util-session-path* :absolute t) ) :must-match t ) ;; カレントフレーム名 (pseudo-frame-name *current-pseudo-frame*) ) ) ) ;; フレームセッションロード (if (frame-util-load-session (merge-pathnames session *frame-util-session-path* ) ) (progn (message "Load \"~A\"." session) t ) (progn (message "フレームセッション\"~A\"はありません。" session) nil ) ) ) (defun frame-util-session-previous-pframe (&optional session-p) "\ タブ並び順で前のフレームに移動。 数引数付きで呼び出されたときフレームセッションを保存 & ロードする。 SESSION-P:non-nil のときフレームセッションを保存 & ロード。 " (interactive ;; 数引数付きで呼び出されたとき (if *prefix-args* ;; フレームセッションを保存 & ロード (list t) ) ) (frame-util-session-move-frame t session-p) ) (defun frame-util-session-next-pframe (&optional session-p) "\ タブ並び順で次のフレームに移動。 数引数付きで呼び出されたときフレームセッションを保存 & ロードする。 SESSION-P:non-nil のときフレームセッションを保存 & ロード。 " (interactive ;; 数引数付きで呼び出されたとき (if *prefix-args* ;; フレームセッションを保存 & ロード (list t) ) ) (frame-util-session-move-frame nil session-p) ) ;; Session ;;------------------------------------ ;; Interactive ;;==================================== ;;; Defun ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; frame-util.l ends here