タイムスタンプを自動更新したい

HTML などを編集して保存するときに、自動的にタイムスタンプが挿入+更新されると結構便利。今までは、html-helper-mode の機能を使ってこれを実現してたのだけど、psgmlモードに乗り換えたので、どうしようか困っていた(参考:2007-08-11 - 英語とプログラミング気まぐれ日記)。


google で検索してみると、以下の内容を .emacs に追加すればよいみたい。

;;; Time stamp
;;; ファイルの中で最初に表れる「Last modified:」という文字列が
;;; あったらそこに「曜日 月 日 時間 年 タイムゾーン」の順にタイムスタンプ
(setq time-stamp-line-limit 10000) ;行数制限をとっぱらう(変えるなと書いてあるが)
(if (not (memq 'time-stamp write-file-hooks))
    (setq write-file-hooks
          (cons 'time-stamp write-file-hooks)))
(setq time-stamp-format "%3a %3b %02d %02H:%02M:%02S %:y %Z")
(setq time-stamp-start "Last modified:[ \t]")
(setq time-stamp-end "$")


これで「Last modified:」の後に、空白かタブがあると、上書き保存時に time-stamp-format で指定したフォーマットでタイムスタンプを挿入/更新してくれる。

参考

設定:情報源(Time stamp 項を参照)

html-helper-mode => psgmlモード HTMLの編集をより便利にしたい

html-helper-mode はキーバインドが覚えにくいので psgmlモードを代わりに使うことにした。psgmlモード なら「C-c C-e タグ名 RET」でタグの挿入ができるらしいので、覚えるキーバインドが少なそうだ。


ここから先の内容は、(情報源)の内容の要約版みたいなものなので、詳しくはそちらを参照。

PSGMLの入手とインストール

1.A GNU Emacs mode for SGML filesから「Version 1.3.1」をダウンロードする


2.psgml-1.3.1.tar.gz をロードパスの通ったディレクトリに入れる(C:\meadow\site-lisp とか)


3.psgml-1.3.1.tar.gz を解凍・展開し、そのディレクトリに移動する

$ gunzip -dc psgml-1.3.1.tar.gz | tar xf -
$ cd psgml-1.3.1


4.以下のようにビルドする(ここ良く理解してない)

$ ./configure
$ make EMACS=meadow
$ make EMACS=meadow install

追記(2007年8月31日(金))

実は、上のビルドは「EMACS=meadow」を指定すれば大丈夫だろうと自分で勝手に考えて実行してしまった(これでも良いのかも知れないけど)。Meadowの場合は、以下のようにするらしい。
参考:

% meadow -batch -q -l ./psgml-maint.el -f psgml-compile-files

DTDの入手とインストール

1.W3Cのページから DTD をダウンロードする
XHTML™ 1.1 - Module-based XHTML - Second EditionGzip'd TAR archive. をダウンロードする)


XHTML 1.0: The Extensible HyperText Markup Language (Second Edition):以下、xhtml11のみについて手順を説明するが、他のDTDも同じように追加できる。ただし、カタログを編集する必要あり。(参考:カタログの書き方


2.自分のホームディレクトリに ~/DTD というディレクトリを作ってそこに解凍・展開する

$ mkdir -m755 DTD
$ tar zxf xhtml11.tgz -C DTD


3.~/DTD/xhtml11-20070216/DTD/ 以下に catalogファイルとdtdがあることを確認してみる

$ ls DTD/xhtml11-20070216/DTD/*
DTD/xhtml11-20070216/DTD/VERSION*
DTD/xhtml11-20070216/DTD/xhtml11-flat.dtd*    ← これを使う(カタログ内で指定されてるので、明示的に指定しなくてOK)
DTD/xhtml11-20070216/DTD/xhtml11-model-1.mod*
DTD/xhtml11-20070216/DTD/xhtml11.cat*         ← このカタログを指定する
DTD/xhtml11-20070216/DTD/xhtml11.dtd*
DTD/xhtml11-20070216/DTD/xml1.dcl*
DTD/xhtml11-20070216/DTD/xml1n.dcl*

.emacsの設定

以下の内容を、.emacs に追加する。以上で設定完了。

;;; PSGML の設定
(autoload 'sgml-mode "psgml" "Major mode to edit SGML files." t)
(autoload 'xml-mode "psgml" "Major mode to edit XML files." t)
(setq auto-mode-alist
      (append
       '(("\\.html$" . xml-mode)
         ("\\.xhtml$" . xml-mode))
       auto-mode-alist))

;; カタログファイルの指定
(setq sgml-catalog-files '("~/DTD/xhtml11-20070216/DTD/xhtml11.cat"))

;; DOCTYPE 宣言の設定
(setq sgml-custom-dtd
      '(("XHTML 1.1"
         "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
                      \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">")
	("XHTML 1.0"
	 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"
                      \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">")
        ))

;; sgml-mode hookで変数をsetq
(add-hook 'sgml-mode-hook
          (lambda ()
            (setq tab-width                             2
                  sgml-indent-step                      2
		  sgml-indent-data                      t
                  indent-tabs-mode                      nil
                  sgml-xml-p                            t
                  sgml-always-quote-attributes          t
                  sgml-system-identifiers-are-preferred t
                  sgml-auto-activate-dtd                t
                  sgml-recompile-out-of-date-cdtd       t
                  sgml-auto-insert-required-elements    t
                  sgml-insert-missing-element-comment   t
                  sgml-balanced-tag-edit                t
                  sgml-default-doctype-name             "XHTML 1.1"
                  sgml-ecat-files                       nil
                  sgml-general-insert-case              'lower
                  sgml-entity-insert-case               'lower
                  sgml-normalize-trims                  t
                  sgml-insert-defaulted-attributes      nil
                  sgml-live-element-indicator           t
                  sgml-active-dtd-indicator             t
                  sgml-minimize-attributes              nil
                  sgml-omittag                          nil
                  sgml-omittag-transparent              nil
                  sgml-shorttag                         nil
                  sgml-tag-region-if-active             t
                  sgml-xml-validate-command             "xmllint --noout --valid %s %s"

                  )
            ))

;; これ以下はお好みで

;; font-lock
(font-lock-mode 1)
(setq font-lock-support-mode   'jit-lock-mode
      jit-lock-stealth-verbose nil
      font-lock-verbose nil)

;; PSGML デフォルトのfont-lockを使う場合
;;(setq sgml-set-face t
;;    sgml-markup-faces '((start-tag  . font-lock-builtin-face)
;;                          (end-tag    . font-lock-builtin-face)
;;                          (ms-start   . font-lock-variable-name-face)
;;                          (ms-end     . font-lock-variable-name-face)
;;                          (comment    . font-lock-comment-face)
;;                          (ignored    . font-lock-warning-face)
;;                          (pi         . font-lock-preprocessor-face)
;;                          (sgml       . font-lock-type-face)
;;                          (doctype    . font-lock-constant-face)
;;                          (entity     . font-lock-string-face)
;;                          (shortref   . font-lock-reference-face)))

;; My original font-lock-keywords
(add-hook 'sgml-mode-hook
          '(lambda ()
             (make-local-variable 'font-lock-defaults)
             (setq sgml-set-face nil
                   font-lock-defaults '(xml-font-lock-keywords-2 nil))
             (turn-on-font-lock)
             ))

(defvar xml-font-lock-keywords-1
  (list
   ;; タグ開始区切子 & タグ終了区切子
   '("<\\|>" 0 font-lock-keyword-face t)
   ;; スラッシュ
   '("\\(/\\)>" 1 font-lock-keyword-face t)
   '("<\\(/\\)" 1 font-lock-keyword-face t)
   ;; 要素名
   '("\\(</?\\)\\([a-zA-Z]+[a-zA-Z0-9-_:]*\\)" 2  font-lock-builtin-face t)
   ;; コメント
   '("\\(<!--\\([^-]\\|-[^-]\\|--[^>]\\)*-->\\)" 1 font-lock-comment-face t)
   ;; 命令処理
   '("\\(<\\?[a-zA-Z]*\\>[^<>]*\\(<[^>]*>[^<>]*\\)*\\?>\\)" 1 font-lock-type-face t)
   ;; DOCTYPE, ENTITY, ATTLIST, NOTATION等々 マーク宣言
   '("\\(<![a-zA-Z]+\\>[^<>]*\\(<[^>]*>[^<>]*\\)*>\\)" 1 font-lock-constant-face t)
   ;; °
   '("\\<\\([a-zA-Z]+[a-zA-Z-_:]*\\)=" 1 font-lock-variable-name-face t)
   ;; 属性値
   '("=?\\(\"[^\"]*\"\\|'[^\']*'\\)" 1 font-lock-string-face t)
   ;; 数値文字参照, 文字実体参照, パラメータ実体参照
   '("\\(&#[0-9]+;\\|&[a-zA-Z]+;\\|%[^'\";]+;\\)" 1 font-lock-reference-face t)
   ;; CDATA 等々 マーク区間 (マーク指定区域)
   '("\\(<!\\[[^\\[]+\\[[^]]+]]>\\)" 1 font-lock-warning-face t)
   ))

(defvar xml-font-lock-keywords-2
  (append
   xml-font-lock-keywords-1
   (list
    ;; SSI
    `(,(concat "\\(<!--#\\(fsize\\|flastmod\\|printenv\\|"
               "include\\|echo\\|config\\|exec\\|set\\|"
               "if\\|elif\\|else\\|endif\\)\\>[ \t\n]+"
               "\\([^-]\\|-[^-]\\|--[^>]\\)*-->\\)")
      1 'bold t)
    ;; php
    '("\\(<\\?\\(php\\|=\\)[^?>]+\\?>\\)" 1 font-lock-function-name-face t)
    ;; eRuby, JSP, ASP
    '("\\(<%\\(=\\)?\\>[^%>]+%>\\)" 1 font-lock-function-name-face t)
    )))

使い方

.html ファイルを開くとモードラインに(XML)と表示されているはず。そこで、C-c C-e タグ名 RET と入力すると、そのタグが挿入できる。もちろん TAB で補完もできる。

参考

:情報源
PSGMLモードを使うキーバインドのみ参照した
:カタログファイルの書き方
html writing memo:PSGMLモードの使い方

psgmlモードと定型文補完(スニペット)で楽々HTML編集

詳しくは、以下の情報源を参照。
emacs + snippet.el の定型文補完(スニペット)で楽々HTML編集 - Goodpic


一応、.emacs に追加する設定をメモとして残しておく。

;;------------------------------------------------
;; PSGML 用のsnippetを記述
;;------------------------------------------------

;; snippetを有効にする(abbrev-modeの強化バージョンみたいなもの。)
;; 注:このsnippetモードは、内部でabbrev-modeを使ってるので、abbrev-modeを有効にしておく必要がある
(require 'snippet)

;; snippet.el で、addrev に定型文を追加する
(add-hook 'sgml-mode-hook
           '(lambda ()
			  (setq-default abbrev-mode t) ;; abbrev-mode をon
			  (snippet-with-abbrev-table 'global-abbrev-table 
	  ("htdiv3" . "<div class=\"section\">\n$>$><h3>$${title}</h3>\n$><p>$${body}</p>\n$.</div>$>")
	  ("htdiv4" . "<div class=\"section\">\n$>$><h4>$${title}</h4>\n$><p>$${body}</p>\n$.</div>$>")
	  ("htdivr" . "<div class=\"section refer\">\n$><ul class=\"source\">\n$>$><li><cite><a href=\"$${cite}\">$${title}</a></cite> より</li>\n</ul>$>\n$><blockquote cite=\"$${cite}\" title=\"$${title}\">\n$><p>$${body}</p>\n</blockquote>$>\n</div>$>")
          ("hthref" .  "<a href=\"$${url}\">$${title}</a>") ;; 続けて複数指定できる
	  )
))


上の設定を .emacs に追加しておけば、psgmlモードに入ると定型文補完(スニペット)が有効になる。上の設定例の場合、.html ファイルを開いて、psgmlモードに入り、「hthref RET 又は SPACE」と入力すると、

<a href="url">title</a>

という定型文が補完される。良く使う定型文を何個か登録しておくと便利そう。

(X)HTMLの雛形を自動挿入したい

今まで、(X)HTML の雛形は html-helper-mode の機能を使って挿入していた(参考:2007-08-11 - 英語とプログラミング気まぐれ日記)。だけど、html-helper-mode の代わりに、psgmlモード を使うことにしたので、この機能が使えなくなってしまった。


いろいろ探し回ったら、html-helper-mode の機能を使わないで雛形を作る方法を見つけたのでメモしておく。

作業手順

  1. 挿入したい内容を書いたテンプレートファイルを適当なディレクトリに用意する(この例では /cygdrive/c/meadow/site-lisp/template/ )。
  2. 以下の内容を .emacs に追加する。以上。
;; Mode Check Template
; テンプレート(この例では default.html)の格納されたディレクトリのパスを指定する
(setq auto-insert-directory "/cygdrive/c/meadow/site-lisp/template/")
(auto-insert-mode t)
(setq auto-insert-query nil) ;; テンプレート挿入時に尋ねない

(setq auto-insert-alist
      (append
       '(
         ; sgml-mode の時は default.htmlを読み込む
         (sgml-mode . "default.html")
         ("\\.html$" . "default.html")
         ("\\.htm$" . "default.html")
         )
       auto-insert-alist))


拡張子とテンプレートファイルの組み合わせを変えてやれば、もちろん .html ファイル以外にも適用できる。