xyzzyのLispコードのサンプルです。
Lispコードのファイルの内容をLispオブジェクトの形でLisp環境に取り込みます。ロードするファイルのコードは、Lisp式のソースコードかバイトコンパイル済みコードである必要があります。
以下は、各種ロード関係の関数の違い
についてです。
loadload-library*.lcがあればそれをロードします。*.lcがなければ*.lをロードします。autoloadrequire*modules*次の例では、foo.lというファイルをロードする。
(load "foo.l")load-library等でライブラリをロードする対象パスを*load-path*にリストで設定することもできます。
;; ライブラリをロードするパスを追加する。
(setq *load-path*
(cons (merge-pathnames "bar" (user-homedir-pathname))
*load-path*))この例は、ユーザのホームディレクトリにあるbarというサブディレクトリもライブラリをロードする際の検索対象となる。但し、追加されるパスのサブディレクトリについては、検索対象から除外される。
.xyzzyから.xyzzy.lをロードする。.xyzzyに大量のLispコードを記述する場合には、.xyzzy.lという別の名前のファイルへ内容をコピーして、それをバイトコンパイルし、.xyzzyでは下記の様にloadでバイトコンパイル済みファイル(.xyzzy.lc)をロードする記述のみしておくと良い。
(load ".xyzzy.lc")この例は、次の様に工夫すると何かと便利である。
(defvar *init-file-name* (merge-pathnames ".xyzzy.l" (user-homedir-pathname)))
;; コンパイル済みファイルがあれば、それを対象とする。
(if (file-exist-p (concat *init-file-name* "c"))
(setq *init-file-name* (concat *init-file-name* "c")))
;; Lispファイルのロード
(if (file-exist-p *init-file-name*)
(load *init-file-name*)
;; .xyzzy.lファイルが無い場合は、デフォルトの初期化ファイルを利用する。
;; 但し、user-homedir-pathname と si:system-root が異なる場合のみ。
(unless (equalp (user-homedir-pathname) (si:system-root))
(load (merge-pathnames ".xyzzy" (si:system-root)))))この例は、.xyzzy.lc(コンパイル済みの.xyzzy.l)ファイルがあればそれをロードし、コンパイル済みで無ければ.xyzzy.lをロードするが、それも無ければ全てのユーザ共通の初期化ファイルを(マルチユーザ環境の場合のみ)ロードする。
次の例では、前記と同様の結果を得ることができる。
(unless (equalp (user-homedir-pathname) (si:system-root))
(setq *load-path*
(cons (merge-pathnames "site-lisp" (user-homedir-pathname))
*load-path*))
)
(if (file-exist-p (merge-pathnames ".xyzzy.*" (user-homedir-pathname)))
(require "../.xyzzy")
(unless (equalp (user-homedir-pathname) (si:system-root))
(load (merge-pathnames ".xyzzy" (si:system-root)))))この例では、マルチユーザ環境であれば、*load-path* に ~/site-lispディレクトリを追加するので、当該ユーザの為のライブラリの管理にも便利である。
メニューバーのツールより共通設定を選択してバックアップファイルのタブでバックアップファイルを作成するの項目にチェックを入れることで、保存するファイルのバックアップファイルを作成することができます。
初期設定では、保存するファイルと同じディレクトリにバックアップファイルを作成しますが、これを好みに応じて変更することができます。
次のLispコードでは、全てのバックアップファイルは c:/backup-files/ の下に作成される。
;;; 特定フォルダに全てのバックアップファイルを作成する。
(require "backup")
(setq *backup-directory* "c:/backup-files/")
(setq *hierarchic-backup-directory* nil)ディレクトリ毎にバックアップファイルの作成先を変更することも次のような記述で可能である。
;;; バックアップファイルの作成先を好みの場所に変更する。
(require "backup")
(setq *backup-directory*
'(("d:/foo/" . "d:/backup-files-foo/")
("" . "d:/common-backup/")))
(setq *hierarchic-backup-directory* t)この例は、d:/foo/bar.txt, d:/foo/bar/baz.txt 等、d:/foo/ で始まるファイルは、すべて d:/backup-files-foo/ の下にバックアップファイルが作成され、マッチしないファイルは d:/common-backup/ の下にバックアップファイルが作成される。詳細は、backup.lファイルのコメントを見ると良い。
因みに私の場合、次の様な設定でバックアップを利用している。
(require "backup")
(setq *backup-directory*
;; siteinit.l に設定があれば、ユーザ設定を上書き利用する。
(list
(cons (merge-pathnames "public_html" (concat "D:/home/" (user-name)))
(merge-pathnames "public_html-backup/" (concat "D:/home/" (user-name))))
'("" . "d:/common-backup/")
))
(setq *hierarchic-backup-directory* t)$XYZZY/lisp/backup.l辞書の導入方法については、$XYZZY/etc/README.gendicファイルに記載があります。記載内容に従って、次の辞書を導入することで辞書機能を利用することができます。
$XYZZY/etc/README.gendic次のLispコードでは、辞書を選択することを可能にする。
;;; 辞書選択
;; 辞書の位置
(defvar *dictionary-eijiro-path* (merge-pathnames "edict/eijiro/" (si:system-root)))
(defvar *dictionary-gene-path* (merge-pathnames "edict/gene/" (si:system-root)))
;; メニュー定義
(setq *my-dictionary-popup-menu*
(define-popup-menu
(:popup nil "英和(&E)"
(:item nil "英辞郎(&E)"
#'(lambda ()
(interactive)
(setq *edict-dictionary-path* *dictionary-eijiro-path*))
#'(lambda ()
(if (path-equal *edict-dictionary-path* *dictionary-eijiro-path*)
:check)))
(:item nil "GENE(&G)"
#'(lambda ()
(interactive)
(setq *edict-dictionary-path* *dictionary-gene-path*))
#'(lambda ()
(if (path-equal *edict-dictionary-path* *dictionary-gene-path*)
:check)))
)))
;; フローティングポップアップメニュー
(defun init-dictionary ()
(interactive)
(track-popup-menu *my-dictionary-popup-menu*))このLispコードは、フローティングポップアップメニューにて辞書選択メニューを提供する。
更に、必要ならば次の例の様な記述を追加することで、辞書選択メニューを辞書のメニュー項目に追加することができる。
;; [ツール] → [辞書] にポップアップメニューを追加
(add-hook '*init-app-menus-hook*
#'(lambda ()
(add-popup-menu *dictionary-popup-menu*
*my-dictionary-popup-menu* "辞書の切り替え(&C)")))他にも、辞書のツールバーを登録したい場合もあるだろう。
;; tool-bar: 辞書
(defun dictionary-tool-bar ()
(create-tool-bar
'dictionary-tool-bar
(merge-pathnames "toolbar.bmp" (etc-path))
'(("辞書" 36 edict-mode (lambda () (when edict-mode :check))))))
(define-command-bar 'dictionary-tool-bar "辞書引きモード(&D)");; タイトルバーのフォーマット
;(setq-default title-bar-format "%p %v %#h - %#F") ; 標準
(setq-default title-bar-format "%b %#*(%M) [%k:%l] - %p %v%#h")表示する情報を指定する文字列は、文字の並び順に表示されます。
;; モードラインフォーマット
;(setq-default mode-line-format "--%*- %b (%M) [%k:%l] %P %f") ; 標準
(setq-default mode-line-format "--%*- %b (%M) [%k:%l] %P %f [%i]")表示する情報を指定する文字列は、タイトルバーのフォーマットと同様です。
;; ステータスバーに表示する情報
;(setq *status-bar-format* "T") ; 標準
(setq *status-bar-format* "cupT")表示する情報を指定する文字列は、文字の並び順に表示されます。
下記は、タイトルバーのフォーマット及びモードラインのフォーマットで表示する情報を指定する文字列の一覧である。
%*%#*%r%#r%p%v%h%#h%b%f%#f%F%#F%M%m%k%l%imode-line-formatのみ)%Pmode-line-formatのみ)下記は、ステータスバーのフォーマットで表示する情報を指定する文字列の一覧である。
tpcuT$XYZZY/html/OChangeLog.html (Wed Aug 09 2000 Version 0.2.1.153)次の例では、起動時からメニューを非表示にする。
;; 起動時からメニューを非表示
(add-hook '*post-startup-hook*
#'(lambda ()
(set-menu nil)))次の例では、メニューの表示状態の切り替えを行う事ができる。
;;; メニューいらんよなの切り替えスイッチ
(add-hook '*init-app-menus-hook*
#'(lambda ()
(let ((toggle-app-menu *app-menu*))
(defun toggle-app-menu ()
(interactive)
(set-menu (setq toggle-app-menu
(unless toggle-app-menu *app-menu*)))))))次の例は、メニューにカレントバッファを閉じる為のクローズボックスを追加することができる。
;;; メニューにクローズボックス
(add-hook '*init-app-menus-hook*
#'(lambda ()
(add-menu-item *app-menu* 'close-box :close-box
#'kill-selected-buffer)))$XYZZY/html/ChangeLog.html (Fri Feb 16 2001 Version 0.2.1.180)次の例では、フローティングポップアップメニューより選択された項目の表示状態を変更することができる。
;;; 表示状態切り替えメニュー
(defun my-apps-popup ()
(interactive)
(track-popup-menu
(define-popup-menu
(:item nil "メニュー(&A)"
'toggle-app-menu)
(:item nil "垂直スクロールバー(&V)"
'toggle-vscroll-bar)
(:item nil "水平スクロールバー(&H)"
'toggle-hscroll-bar)
(:item nil "行番号(&#)"
'toggle-line-number)
(:item nil "ルーラー(&+)"
'toggle-ruler)
(:item nil "折り返し(&F)"
'toggle-fold-line)
(:item nil "行カーソル(&O)"
'toggle-cursor-line)
(:item nil "モード行(&M)"
'toggle-mode-line)
(:item nil "ファンクションキー(&B)"
'toggle-function-bar)
(:item nil "リードオンリー(&R)"
'toggle-read-only))))
;; C-RBtnUpで独自のポップアップメニューにします。
(global-set-key #\C-RBtnUp 'my-apps-popup);;; 表示状態切り替えメニュー
(defvar *my-toggle-popup-menu*
(define-popup-menu
(:item nil "行番号(&#)"
'toggle-line-number
#'(lambda ()
(or (zerop (logand (get-window-flags) *window-flag-line-number*)) :check)))
(:item nil "ルーラ(&+)"
'toggle-ruler
#'(lambda ()
(or (zerop (logand (get-window-flags) *window-flag-ruler*)) :check)))
(:item nil "モード行(&M)"
'toggle-mode-line
#'(lambda ()
(or (zerop (logand (get-window-flags) *window-flag-mode-line*)) :check)))
;------------------------------
:sep
(:popup nil "ファンクションキー"
(:item nil "表示しない(&N)"
'toggle-function-bar
#'(lambda ()
(and (zerop (logand (get-window-flags) ed::*window-flag-function-bar*)) :check)))
:sep
(:item nil "&4個"
#'(lambda ()
(interactive)
(set-number-of-function-bar-labels 4))
#'(lambda ()
(if (= 4 (number-of-function-bar-labels))
:check
)))
(:item nil "&5個"
#'(lambda ()
(interactive)
(set-number-of-function-bar-labels 5))
#'(lambda ()
(if (= 5 (number-of-function-bar-labels))
:check
)))
(:item nil "&8個"
#'(lambda ()
(interactive)
(set-number-of-function-bar-labels 8))
#'(lambda ()
(if (= 8 (number-of-function-bar-labels))
:check
)))
(:item nil "1&0個"
#'(lambda ()
(interactive)
(set-number-of-function-bar-labels 10))
#'(lambda ()
(if (= 10 (number-of-function-bar-labels))
:check
)))
(:item nil "1&2個"
#'(lambda ()
(interactive)
(set-number-of-function-bar-labels 12))
#'(lambda ()
(if (= 12 (number-of-function-bar-labels))
:check
)))
(:item nil "&15個"
#'(lambda ()
(interactive)
(set-number-of-function-bar-labels 15))
#'(lambda ()
(if (= 15 (number-of-function-bar-labels))
:check
)))
)
))
(defun toggle-setting-menu ()
(interactive)
(track-popup-menu *my-toggle-popup-menu*))
(global-set-key #\C-RBtnUp 'toggle-setting-menu)
(add-hook '*init-app-menus-hook*
#'(lambda ()
(let ((view (get-menu *app-menu* 'ed::view)))
(insert-popup-menu view 5 *my-toggle-popup-menu* "表示する?(&V)")
)))次の例では、ミニバッファに入ったときIMEを自動的にOFFにすることができる。
;;; ミニバッファに入ったときIMEをOFFにする
(export '(*ime-mode-into-minibuffer*))
(defvar *ime-mode-into-minibuffer* nil)
(defun ime-state-get-and-setoff (bef-buffer file-name)
(interactive)
(setq *ime-mode-into-minibuffer* (get-ime-mode))
(toggle-ime nil))
(defun ime-state-set (bef-buffer file-name)
(interactive)
(toggle-ime *ime-mode-into-minibuffer*))
(add-hook '*enter-minibuffer-hook* 'ime-state-get-and-setoff)
(add-hook '*exit-minibuffer-hook* 'ime-state-set)次の例では、xyzzy自身をEmacs同様にC-zキーでタスクバーにアイコン化する方法を示す。
;;; C-z でアイコン化
(require "wip/winapi")
(c:define-dll-entry winapi:BOOL ShowWindow (winapi:HWND c:int) "user32")
(global-set-key #\C-z #'(lambda () (interactive)
(ShowWindow (get-window-handle) 6)))同様に、タスクトレイ(タスクバーの通知領域)にアイコンを表示したいのであれば、ttrayを導入すると良い。
取り敢えず設定例のみ。
;; ファイラの初期ディレクトリ
(setq *filer-primary-directory* (si:system-root)) ; 左側
(setq *filer-secondary-directory* (user-homedir-pathname)) ; 右側;; ファイラの初期ファイルマスク
;; 2画面用
(setq *filer-primary-file-mask* '("*")) ; 左側
(setq *filer-secondary-file-mask* '("*")) ; 右側
;; 1画面用
(setq *filer-last-file-mask* '("*"));; ファイラのパスマスクリスト
(setq *filer-path-masks*
'(("すべてのファイル" "*")
("ドキュメント" "*.doc" "*.txt" "*.man" "*readme*")
("C/C++" "*.c" "*.h" "*.cpp" "*.cxx" "*.cc" "*.inl")
("Lisp" "*.l" "*.el" "*.lsp" "*.lisp")
("Visual Basic" "*.bas" "*.frm" "*.vbp")
("実行ファイル" "*.exe" "*.com" "*.bat" "*.pif")
("アーカイブ" . ("*.lzh" "*.zip" "*.arj" "*.tar" "*.bz2" "*.gz"
"*.Z" "*.tbz" "*.taz" "*.tgz" "*.cab" "*.rar"
"*.gza" "*.bza" "*.yz1" "*.7z"))
("バックアップ" "*~" "*.bak")
("自動セーブ" "#*#")));; 削除時のゴミ箱使用
(setq *filer-use-recycle-bin* t);; ファイラのステータスウィンドウへのファイル名の表示
(setq *filer-echo-filename* t);; ファイラのジャンプ用のディレクトリ(連想リスト)
(setq *filer-directories*
(list
(cons "home" (concat "D:/home/" (user-name)))
(cons "homedir" (user-homedir-pathname))
(cons "xyzzy" (si:system-root))
(cons "lisp" (merge-pathnames "lisp" (si:system-root)))
(cons "site-lisp" (merge-pathnames "site-lisp" (si:system-root)))
(cons "Windows" (get-windows-directory))
;(cons "System" (get-system-directory))
(cons "DeskTop" (get-special-folder-location :desktop))
(cons "Personal" (get-special-folder-location :personal))
;(cons "Program Files" (get-special-folder-location :programs))
;(cons "Recent" (get-special-folder-location :recent))
;(cons "SendTo" (get-special-folder-location :send-to))
;(cons "Start Menu" (get-special-folder-location :start-menu))
;(cons "Startup" (get-special-folder-location :startup))
;(cons "ShellNew" (get-special-folder-location :templates))
(cons "Temp" (or (map-backslash-to-slash (si:getenv "TEMP"))
(map-backslash-to-slash (si:getenv "TMP"))))
(cons "public_html"
(merge-pathnames "public_html" (concat "D:/home/" (user-name))))
'("share" . "d:/share/")
));; ファイラの送るのリンク先
(setq *filer-send-to-list*
(list
'("C:/" . "C:/")
'("D:/" . "D:/")
(cons "homedir" (user-homedir-pathname))
));; ファイラのガイドテキスト
(setq *filer-guide-text*
'("A:属性 C:コピー D:削除 E:解凍 F:検索 J:DIR移動 \
K:mkdir L:ドライブ M:移動 N:ファイル名 O:圧縮 P:DIR??"
"R:名前変更 S:DIR?? T:ショートカット U:DIRサイズ V:リスト X:実行 .:マスク \
/:マーク *:load Home:トグル S-Home:クリア End:リロード F3:実行 M-h:ヘルプ"))ファイラのガイドテキストを表示する必要の無い場合には、次の様に変数の値をnilと示せば良い。
(setq *filer-guide-text* nil);;; ガイドテキストをポップアップ表示
(setq *popup-filer-guide-text*
(concat
"A:属性\t\tB:バイトコンパイル\tC:コピー\t\tD:削除\t\tE:解凍\n"
"F:検索\t\tG:ファイル名検索\tJ:DIR移動\tK:mkdir\t\tL:ドライブ\n"
"M:移動\t\tN:ファイル名\tO:圧縮\t\tP:DIR??\t\tQ:終了\n"
"R:名前変更\tS:DIR??\t\tT:ショートカット\tU:DIRサイズ\tV:リスト\n"
"W:閲覧\t\tX:実行\t\tY:ショートカット\tZ:プロパティ\n"
"\n"
"*:load\t\t.:マスク\t\t/:マーク\t\t<:先頭\t\t>:末尾\n"
"@:別名コピー\t\:ルート\t\t=:比較\t\t^:イジェクト\t]:送る\n"
"\n"
"C-h:上ディレクトリ\tC-r:後isearch\tC-s:前isearch\tC-u:ディレクトリサイズ\n"
"C-1:ファイル広\tC-2:サイズ広\tC-3:日時広\tC-4:属性広\n"
"C-M-1:ファイル狭\tC-M-2:サイズ狭\tC-M-3:日時狭\tC-M-4:属性狭\n"
"\n"
"M-g:grep\tM-r:gresreg\tM-v:リードオンリー\n"
"\n"
"F3:実行\t\tF5:マークトグル\tF6:ソート\t\tS-F10:ポップアップメニュー\n"
"\n"
"TAB:移動\tSPC:マーク\n"
"Home:トグル(ファイル)\tS-Home:クリア\tC-Home:トグル(含Dir)\tS-C-Home:全ファイルマーク\n"
"End:リロード\n"
"\n"
))
(define-key filer-keymap #\M-h
#'(lambda () (interactive)
(message-box *popup-filer-guide-text*)
))追加登録しているキーがあれば、次の様に記述しておくと良い。
;; カスタマイズ
(setq *popup-filer-guide-text*
(concat
*popup-filer-guide-text*
"\n"
"M-f:diff\t\tM-h:ガイド\tM-s:小文字\t"M-x:実行\tM-Home:トグル(Dir)\n"
));;; 大文字のファイル名をファイラで一括して小文字へ
(defun filer-downcase-filename ()
(let ((files (filer-get-mark-files)))
(when (and files (yes-or-no-p "小文字にしまっせ"))
(filer-subscribe-to-reload (filer-get-directory))
(mapc #'(lambda (x) (rename-file x (string-downcase x))) files)
(filer-demand-reload)
(filer-goto-file (file-namestring (car files))))
t))
(define-key filer-keymap #\M-s 'filer-downcase-filename);;; ディレクトリ全部を選択
(defun filer-directory-select ()
(filer-mark-all nil)
(filer-toggle-mark-files))
(define-key filer-keymap #\M-Home 'filer-directory-select);;; 二画面ファイラから選択してテキストの比較
(defun my-filer-diff-file ()
(let ((file1 (ed::filer-fetch-file nil nil))
(file2 (ed::filer-fetch-file nil t)))
(unless (and file1 file2)
(error "diffするファイルを指定して"))
(diff file1 file2)
(and (find-buffer ed::*diff-new-buffer-name*)
(find-buffer ed::*diff-old-buffer-name*)
(filer-cancel))))
(define-key filer-keymap #\M-f 'my-filer-diff-file);;; 一画面ファイラから二画面ファイラを開く
(defun filer-open-dual-window ()
(interactive)
(unless (filer-dual-window-p)
(let ((*filer-primary-directory* (filer-get-directory))
(*filer-secondary-directory* (filer-get-directory)))
(filer-cancel)
(open-filer))))
(define-key filer-keymap #\M-2 'filer-open-dual-window);;; 一画面ファイラの表示
;; 現在開いているファイルのディレクトリを表示する。
(defun open-single-filer ()
(interactive)
(toggle-ime nil)
(multiple-value-bind (files result)
(filer nil t nil nil)
(when result
(dolist (f files t)
(unless (file-directory-p f)
(find-file f)
(add-history f '*minibuffer-file-name-history*))))))
(define-key ctl-x-map #\d 'open-single-filer);;; エクスプローラの表示
(defun open-explorer ()
(interactive)
(call-process
(concat "c:/windows/EXPLORER.EXE /e," ; for Windows 9x/Me
;; 現在開いているファイルのディレクトリ
(map-slash-to-backslash
(directory-namestring (or (get-buffer-file-name)
(si:system-root)))
))));;; ファイラ選択メニュー
(add-hook '*init-app-menus-hook*
#'(lambda ()
(let ((tools (get-menu *app-menu* 'ed::tools)))
;; [ツール] → [ファイラ] のカスタマイズ
(delete-menu tools 18 t) ; 元々のメニューを削除
(insert-popup-menu tools 18
(define-popup-menu
(:item nil "二画面ファイラ(&D)" 'open-filer)
(:item nil "一画面ファイラ(&C)" 'open-single-filer)
(:item nil "エクスプローラ(&E)" 'open-explorer)
) "ファイラ(&F)..."))));;; ファイラから「ファイルの実行」後にファイラを閉じる
(define-key filer-keymap #\M-x
#'(lambda ()
(interactive)
(ed::filer-shell-execute)
(ed::filer-cancel)))次の例は、find-file するときに最初に表示されるディレクトリをホームディレクトリに設定している。
(cd "~/")上記の例は、xyzzyでは次の様に記述することもできる。
(set-default-directory "~/")これらの例は、作業中のバッファのファイルパスが無効の場合にのみ有効である。
;;; カレントバッファのファイルをバイトコンパイル
(defun byte-compile-this-file ()
(interactive)
(if (string= "l" (pathname-type (get-buffer-file-name)))
(byte-compile-file (get-buffer-file-name))))siteinit.lのバイトコンパイルとダンプファイルの削除;;; siteinit.lのバイトコンパイルとダンプファイルの削除
(defun compile-and-delete-dump-file ()
(interactive)
(and (find-buffer "siteinit.l")
(eval-buffer "siteinit.l"))
(byte-compile-file
(concat (si:system-root) "site-lisp/siteinit.l"))
(let ((dumpfile
(concat (si:system-root) "xyzzy."
(case (os-platform)
(whistler "wxp")
(windows-2000 "w2k")
(windows-nt "wnt")
(windows-me "wme")
(windows-98 "w98")
(windows-95 "w95")
(win32s "32s")
(t "nt")))))
(and (file-exist-p dumpfile)
(delete-file dumpfile)
(princ (concat "delete " (file-namestring dumpfile) "..."))))
(princ "done.\n"))
(global-set-key '(#\C-c #\b) 'compile-and-delete-dump-file);;; siteinit.lのバイトコンパイルとダンプファイルの削除
(defun byte-compile-and-delete-dump-file ()
(interactive)
(and (find-buffer "siteinit.l")
(eval-buffer "siteinit.l"))
(byte-compile-file
(merge-pathnames "site-lisp/siteinit.l" (si:system-root)))
(let ((path (namestring (si:dump-image-path))))
(and (file-exist-p path)
(princ (concat "delete "
(if (path-equal (directory-namestring path) (si:system-root))
(file-namestring path)
path)
"..."))
(delete-file path)))
(princ "done.\n"))
(global-set-key '(#\C-c #\b) 'byte-compile-and-delete-dump-file)この例では、起動時の引数に [-config config-directory] を指定していてもダンプファイルの削除が行える。
;;; bufferら(*.l)をコンパイル
(defun byte-compile-open-buffers()
(interactive)
(let ((b-n) (error-msges))
(with-output-to-temp-buffer ("*byte-compile*" nil)
(dolist (a-b (buffer-list))
(setq b-n (get-buffer-file-name a-b))
;(pathname-type(file-namestring b-n))
(if(and b-n
(string= "l" (pathname-type b-n)))
(if ;(msgbox "do ~A" b-n)
(byte-compile-file b-n)
(setq error-msges (concat error-msges "\n compiled:" b-n))
;(setq error-msges (concat error-msges "\n not :" b-n))
)
)))
(msgbox "do compile\n~A" error-msges)));;; 保存時に自動的にバイトコンパイル
(add-hook '*after-save-buffer-hook*
#'(lambda ()
(interactive)
(let ((bn (get-buffer-file-name)))
(if (and (string= "l" (pathname-type bn))
(file-exist-p (format nil "~Ac" bn)))
(if (path-equal bn (merge-pathnames "site-lisp/siteinit.l" (si:system-root)))
(byte-compile-and-delete-dump-file)
(save-excursion
(byte-compile-file bn)))))))(defun debug ()
(interactive)
(setq *error-output* (make-buffer-stream (create-new-buffer "*Stack Trace*")))
(setq si:*trace-on-error* t))以下を .xyzzy に書いておけば emacs 風のバッファ名指定ができる。
;; emacs 風のバッファ名指定
(pushnew '(#\B . emacs-interactive-buffer-name)
*interactive-specifier-alist* :test #'equal)
(pushnew '(#\b . emacs-interactive-exist-buffer-name)
*interactive-specifier-alist* :test #'equal)$XYZZY/lisp/buffer.l (241行辺り)次の例は、デフォルトの漢字コードをEUC-JP、改行コードをLFに設定している。
;; 漢字コード・改行コードの初期設定(euc-jp/lf)
(setq *default-fileio-encoding* *encoding-euc-jp*
*default-eol-code* *eol-lf*)$XYZZY/lisp/encoding.leval-print-last-sexpeval-last-sexpeval-defuneval-expression;;; *scratch* バッファの削除許否 [t:許|nil:否] の設定
(setq *kill-buffer-kills-scratch* t)デフォルトでは、nil になっています。
;;; *scratch* バッファを自動で保存・復元する。
;; *scratch* バッファの漢字コード・改行コードの設定
(save-excursion
(set-buffer "*scratch*")
(change-fileio-encoding *encoding-euc-jp*) ; EUC-JP
(change-eol-code *eol-lf*)) ; LF
;; *scratch* を終了時に保存
(add-hook '*kill-xyzzy-hook*
#'(lambda ()
(set-buffer (find-buffer "*scratch*"))
(write-file "~/.scratch")))
;; *scratch* を起動時に復元
(add-hook '*post-startup-hook*
#'(lambda ()
(let ((file "~/.scratch"))
(when (file-exist-p file)
(set-buffer (find-buffer "*scratch*"))
;(erase-buffer (selected-buffer))
(insert-file-contents file t)
(message "*scratch* restored")))))内容をより強化した scratch-plus.l を配布中です。
;;; フォーカスのないウィンドウで右クリックするとそれを閉じる
(defun mouse-right-press (&optional apps)
(interactive)
(if (eq (selected-window) *last-mouse-window*)
(mouse-menu-popup apps)
(let ((l (selected-window)))
(set-window *last-mouse-window*)
(delete-window)
(set-window l)
(cancel-mouse-event))))
(global-set-key #\RBtnUp 'mouse-right-press)(setq *popup-completion-list-default* :always)
(setq *minibuffer-popup-completion-list* :always)尚、各変数の値を :always では無く :never にすると、初期値同様の*Completion*バッファでの表示となる。
$XYZZY/html/ChangeLog.html (Tue Sep 25 2001 Version 0.2.2.211)次の例は、バッファ全体を一発でインデントし直すのに便利である。
;;; 一発インデント
(defun indent-current-buffer ()
(interactive)
(when mode-specific-indent-command
(indent-region (point-min) (point-max))
(message "indent buffer")))
(global-set-key #\C-F8 'indent-current-buffer)
(set-function-bar-label #\C-F8 "一発インデント")一発インデントの為のツールバーが必要ならば、次の例の様な記述を追加しておくと良いだろう。
;;; tool-bar: 一発インデント
(defun indent-current-buffer-tool-bar ()
(create-tool-bar
'indent-current-buffer-tool-bar
(merge-pathnames "toolbar.bmp" (etc-path))
'(("一発インデント" 32 indent-current-buffer (lambda () (or mode-specific-indent-command :disable))))))
(define-command-bar 'indent-current-buffer-tool-bar "一発インデント(&I)");;; バッファ全体のインデント
(defun indent-buffer ()
(interactive)
(when mode-specific-indent-command
(save-excursion
(goto-char (point-min))
(funcall mode-specific-indent-command)
(indent-region (point-min) (point-max)))))リージョンを選択し、M-x: tabify でスペースをタブに、M-x: untabify でタブをスペースに変換できます。
また、セレクションでは、M-x: tabify-selection 及び M-x: untabify-selection で相互に変換が行えます。同様に 編集
→変換
メニューからも実行できます。
地味な機能ですが、覚えておくと非常に便利です。
;; ナローイングした領域の表示状態
(setq hide-restricted-region nil)ナローイングした領域の表示状態は、デフォルト設定と同じ nil ならば薄く表示し、non-nil ならば非表示となる。
リージョンを指定して、C-x n (narrow-to-region) とすると、指定した範囲以外を移動・編集できないようにすることができます。
以下の例では、セレクションで範囲の指定を行いナローイングすることができる。
;;; セレクションでナローイング
(defun narrow-to-selection ()
(interactive "*")
(let ((type (get-selection-type)))
(if type
(let ((pre (pre-selection-p)))
(selection-start-end (start end)
(narrow-to-region start end)
(cond ((< start end)
(goto-char (point-min))
(start-selection type pre (point-max)))
(t
(goto-char (point-max))
(start-selection type pre (point-min))))))
(error "範囲が選択されていません。"))))ワイディング(制限された領域を元に戻す)操作は narrow-to-region と同じく C-x w (widen) です。
次の例では、新規に作成したバッファのデフォルトのモードをtext-modeにする。
;; デフォルトのモード
(setq *default-buffer-mode* 'text-mode)次の例では、テキストモードやそれに関するモードでは、自動詰め込みモードを有効にする。
(add-hook '*text-mode-hook*
'(lambda () (auto-fill-mode t)))これは、ノーマルフック変数にフック関数を追加する場合の一例である。フックとは、ある特定の状況で既存のプログラムから呼び出される関数/関数群を格納しておく変数のことで、xyzzyには、設定用のフックが数多くあります。
ファイルの名称や拡張子とメジャーモードとの対応関係は、*auto-mode-alist*変数に格納されます。
次の例では、ファイルを開く際に.txtというファイル拡張子ならば、自動的にtext-modeになる。
(setq *auto-mode-alist*
(append '(("\\.txt$" . text-mode))
*auto-mode-alist*)次の例では、前記と同様の結果を得ることができる。
(pushnew '("\\.txt$" . text-mode) *auto-mode-alist*)また、複数のファイルや拡張子に対する指定を同時に加えるのであれば、次の様に記述すると良い。
(setq *auto-mode-alist*
(append '(("\\.\\(xht[ml]?\\|rdf\\|rss\\)" . xml-mode)
("\\.s?html?" . html-mode))
*auto-mode-alist*)次の例では、前記と同様の結果を得ることができる。
(pushnew '("\\.\\(xht[ml]?\\|rdf\\|rss\\)" . xml-mode) *auto-mode-alist*)
(pushnew '("\\.s?html?" . html-mode) *auto-mode-alist*)(setq *keyword-load-path* '("~/keywords"))この例では、キーワードファイルを使う場合に、ユーザのホームディレクトリにある keywordsディレクトリ内に格納されたキーワードファイルを優先的に使用することができる。
(setq *eshell* "bash -i")
(setq *shell-command-option* (concat "/E:2048" *shell-command-option*))shell-modeでCygwinのbashを使用する場合には、Cygwinをインストールし、環境変数のPATHとSHELLを適切に設定しておく必要ある。
PATH$PATH;d:\cygwin\bin;d:\cygwin\usr\local\bin;SHELL/bin/bash尚、Cygwinについての詳細は、本サイト内のCygwin備忘録をご覧下さい。
インクリメンタルサーチを使うには、初期化ファイルに次のコードを追加すると良い。
(require "isearch")(require "dabbrev")
(global-set-key #\M-/ 'dabbrev-expand)
(global-set-key #\C-\; 'dabbrev-popup)dabbrev-popupについては、補完の候補のポップアップ設定もしておくと良い。
英語のスペルチェックを行いたい場合には、ispellが必要になります。最も手っ取り早いのは、xyzzyの作者・亀井氏のサイトにて入手できる Ispell for Win32 を導入することです。
Ispellを導入したら、初期化ファイルに実行ファイルのパスを次のように指定しておきましょう。
;; Ispell --- スペルチェック
(setq *ispell-command*
(map-slash-to-backslash (merge-pathnames "bin/ispell.exe" (si:system-root))))また、ツールバーを登録しておくと手軽にIspellを使用できます。
;; Ispell --- ツールバー
(defun ispell-tool-bar ()
(create-tool-bar
'ispell-tool-bar
(merge-pathnames "toolbar.bmp" (etc-path))
'(("ispell" 15 (lambda () (interactive)
(ed::map-selection #'ispell-region)) :selection))))
(define-command-bar 'ispell-tool-bar "Ispell(&I)")尚、ツールバーを削除したい場合には、ESC-ESCとキーを押してミニバッファに Eval: と表示されたら (delete-command-bar 'ispell-tool-bar) と入力し、Enterキーを押します。最後にIspellの為のツールバーの記述を削除してください。
xyzzyにてテキストの比較を行いたい場合には、diffが必要になります(diff関連の拡張Lispを導入する場合も同様)。その際、Cygwinを導入してそのdiff.exeを使うのも良いが、態々Cygwinを導入したくないならば、Cygwinから必要なファイルだけを抜き出して使う方法もあるので、その方法を次に説明する。
尚、Cygwinを導入する際には、本サイト内のCygwin備忘録を参考にしてみて下さい。
$XYZZY/bin ディレクトリを作成する。diff.exe, cygwin1.dll, cygintl-1.dll を$XYZZY/bin ディレクトリに置く。$XYZZY/site-lisp/siteinit.lに下記のLispコードを書いておく(要:再ダンプ)。;; diff --- テキストの比較
(in-package "editor")
(setq *diff-command-name*
(map-slash-to-backslash (merge-pathnames "bin/diff.exe" (si:system-root))))
(in-package "user")注釈
GNU patch 2.5.4 と GNU diff 2.7 を Win32 用に Make した GNU patch GNU diff for Win32 を使用すれば、Cygwinから必要なファイルだけを抜き出す手間が省けます。
css-modeでCSS2の@規則(@import、@pageなど)や最重要指定(!important)を色付けしたい場合には、初期化ファイルにシンタクッステーブルを指定すると良い。
;; @規則や!に色付けする。
(set-syntax-word ed::*css-mode-syntax-table* #\@)
(set-syntax-word ed::*css-mode-syntax-table* #\!)更に、キーワードファイル(*keyword-load-path*/CSS)にキーワードを下記例の様に追加しておく必要がある。
···
;;; At-rules
;*0b
@charset
@font-face
@import
@media
@page
;;; Inheritance
;*2b
!important
inherit
···-*- encoding: UTF-8N -*- 認識(setf (gethash "UTF-8N" *mime-charset-name-hash-table*) *encoding-utf8n*)Another HTML-lint のソースを入手して導入することで、HTMLの文法チェックが気軽に行えます。これをxyzzyのhtml-modeで利用できる様にすると非常に便利です。
次の例では、カレントバッファのモードがhtml-modeの時、AHL コマンドラインヴァージョン(htmllint)を利用したHTMLの構文チェックを行える。
;;; Another HTML-lint
;; for the Command line version
(add-hook 'ed::*html-mode-hook*
#'(lambda ()
(defvar *htmllint-file* "D:/usr/local/htmllint/htmllint")
(defun htmllint-exec ()
(interactive)
(let ((file (get-buffer-file-name (selected-buffer))))
(when file
(pipe-command
(format nil "perl \"~A\" \"~A\""
(map-slash-to-backslash *htmllint-file*)
(map-slash-to-backslash file))))))
(define-key ed::*html-mode-map* '(#\C-c #\l) 'htmllint-exec)))次の例では、カレントバッファのモードがhtml-modeの時、AHL ゲートウェイCGIヴァージョン(htmllint.cgi)を利用したHTMLの構文チェックが行える。
;;; Another HTML-lint
;; for the gateway version
(add-hook 'ed::*html-mode-hook*
#'(lambda ()
(defvar *htmllint-string*
"http://127.0.0.1/htmllint/htmllint.cgi?V;X=w3m;URL=")
(defun htmllint-cgi ()
(interactive)
(let ((file (get-buffer-file-name)))
(when file
(shell-execute (concat *htmllint-string* file) t)
)))
(define-key ed::*html-mode-map* '(#\C-c #\C-l) 'htmllint-cgi)))この例では、デフォルトのブラウザに検証結果を表示するが、browser.dll或いはbrowser.dll 拡張版 + browserexを活用する場合には、当該行を次の様に修正することでxyzzy上に表示することもできる。
;(shell-execute (concat *htmllint-string* file) t)
(bx:close-browser)
(bx:navigate (concat *htmllint-string* file))この例は、browserexを活用することができる。また、html+-modeを導入しそれで利用したい場合には、html-modeに関する記述部分を変更する必要がある。
html+-modeを導入する際にsiteinit.lに追加するLispコードの例を以下に示す。
(in-package "editor")
(export 'html+-mode)
(autoload 'html+-mode "html+-mode" t)
(pushnew '("\\.s?html?" . html+-mode) *auto-mode-alist* :test 'equal)
;; charsetで指定された文字コードの使用
(setq *html+-detect-charset* t)
;; DOCTYPE毎に異なる補完リストの生成
(setq *html+-use-html-kwd* t)
(setq *html-default-doctype* "HTML4.01 strict") ; 初期値及び未指定時
;; インデント付けの対象外とするタグ
(setq *html+-tags-list-no-indent* '("PRE" "XMP" "CODE" "SAMP"))
(in-package "user")注釈
拡張lispのclickable-uriを導入すると、マウスの左ダブルクリック操作によるウェブブラウザ、メーラー等の起動が可能になります。
私の場合、browserexも愛用させて頂いているので、コマンド指定にそれを指定して利用しています。
(when (find "clickable-uri" *modules* :test #'string-equal)
(when (and (packagep (find-package "browserex"))
(symbolp (find-symbol "navigate" "browserex")))
(push '("^https?:" . bx:navigate)
*clickable-uri-open-command-alist*)
(push '("^file:" . bx:navigate)
*clickable-uri-open-command-alist*)))
次の例では、XHTMLファミリ文書に対してHTML文書の為のファイル拡張子を含む場合に、ファイルを開く時点で自動的にxml-modeに切り替えることができる。
;;; XHTML/HTMLで適切なモードを自動選択する。
(defun html-select-mode ()
(interactive)
(save-excursion
(goto-char (point-min))
(if (scan-buffer "<\\?xml[^>]+>" :regexp t)
(xml-mode)
(if (scan-buffer "<!DOCTYPE[ \t\r\n]+" :regexp t)
(html+-mode)))))
(pushnew '("\\.s?html?" . html-select-mode) *auto-mode-alist* :test 'equal)更に、コンテント・ネゴシエーション等による拡張子無しのURIのソースを開く際に、XHTML/HTMLの適切なモードを自動選択するには、次の様な記述もしておくと良い。
;; 拡張子無しのソースを開く場合の設定(コンテント・ネゴシエーションへの対処)
;; MsIE や Mozilla (XUL of "ContextMenu Extensions") で有効。
(pushnew '("(/Temporary Internet Files/\\|/TEMP(.*)$)" . html-select-mode)
*auto-mode-alist* :test 'equal)尚、XHTMLの為の拡張子をxml-modeに関連付けするには、次の様な記述を初期化ファイルに追加記載しておく必要がある。
(pushnew '("\\.xht[ml]?" . xml-mode) *auto-mode-alist* :test #'equal)注釈
.html [RFC2854] は元来 HTML の為のファイル拡張子であり、XHTML の為のファイル拡張子ではない。一般に、この拡張子を XHTML に対して使用するのは適切ではない。然しながら、XHTML1の Appendix C. HTML Compatibility Guidelines
(所謂、互換ガイドライン)に基づく XHTML 1.0 に対してのみは、HTML のファイル拡張子も許されるようである。
The file extensions 'html' or 'htm' are commonly used, but other extensions denoting file formats for preprocessing are also common.
[ 引用: The 'text/html' Media Type -- RFC 2854 より ]
There are three known file extensions that are currently in use for XHTML 1.0; ".xht", ".xhtml", and ".html".
[ 引用: The 'application/xhtml+xml' Media Type -- RFC 3236 より ]