Major mode for AppleScript


ちょっとした編集などの度にいちいち AppleScript Editor を開くのも嫌なので作ってみました.既に applescript-mode.el というのもあるんですがそれとは別物です.

追記(同日)

はてブで指摘があったので,早速,as- から apples- に名称変更しました.記事内容やリンクも更新されています.

リポジトリ

apples-mode という名前でやってます.

# URL: http://github.com/tequilasunset/apples-mode

$ git clone git://github.com/tequilasunset/apples-mode.git

動作環境

テストは GNU Emacs 23.2.1 on Mac OS X 10.6.6 で行っています.

機能

  • キーワードの色付け
  • インデント
  • AppleScript の実行と結果の表示
  • エラー箇所のハイライト
  • 機能の殆どはメニューからアクセス可能

というメジャーモードっぽい機能が揃っています.下の画像はエラーを出してみたところです.flymake のように常時実行はできませんが,エラー箇所をハイライトしてその位置にカーソルを飛ばします.

インストール

モノをロードパスに置いて

(autoload 'apples-mode "apples-mode" "Happy AppleScripting!" t)
(autoload 'apples-open-scratch "apples-mode" "Open scratch buffer for AppleScript." t)
(add-to-list 'auto-mode-alist '("\\.\\(applescri\\|sc\\)pt\\'" . apples-mode))

あるいは,

(require 'apples-mode)
(add-to-list 'auto-mode-alist '("\\.\\(applescri\\|sc\\)pt\\'" . apples-mode))

とします.バイトコンパイル推奨ですが,しょうもない warnings は無視してください.apples-mode.el と同じ階層にある apples-mode というディレクトリには yasnippet 向けのスニペットが入っています.

お試し用のコードがないよって人は AppleScript Editor の Help メニューから探ってみてください.

コンパイル済みのコードはそのままでは編集できないので,コマンド apples-decompile を使ってデコンパイルする必要があります.あるいは,コマンド apples-open-scratch を使って一からコードを書いてみてください.実行用のコマンドは幾つかありますが,apples-run-region/buffer が使いやすいと思います.

既知のバグ

初めて書いたメジャーモードなのでかなりバギーだと思ってください.

display dialog コマンドがこけることがある.

これが結構致命的なんですが,display dialog コマンドはそのままでは実行できないのでこちらを参考に一時ファイルをかませて実行しています.これで取り敢えず実行出来るようになるんですが,それでも時々下のようなエラーが出ます(apples-mode ではエラーではなく返り値として表示されます).日本語環境だと日本語で表示されるかもしれません.

A identifier can't go after this “"”.
A property can’t go after this “\"”.

一時ファイルのコーディングに問題があるような気がしますが(AppleScript Editor に直接コードをコピペするとうまくいくけど,osascript や do-applescript から一時ファイルを指定して実行すると躓くので),解決策を模索中といったところです(実際にはスーパーハッカーの登場を期待しているわけですが).

whitespace.el が動作していないかもしれない.

そもそも僕の whitespace.el の設定が正しいのかも不明ですが,ハイライトが上手くなされていないようです.ただし,これは elisp のみ(シンタックスクラスかな?)の問題なのですぐに修正されると思います.

その他にも大小様々なバグがあると思いますが,Emacs から AppleScript を実行してみるのも結構楽しいので是非トライしてみてください.

更新

2011/01/20

現在,v0.0.2 ですが,display dialog に関するバグは既に修正されています.
まだ,細かいバグも残っていますが,ひと通りの機能は揃ったと思います.

2011/01/17

whitespace.el に関するバグを修正しました.hook に問題があったようです.
まず,僕の使っている whitespace.el (v12.1) にはバグがあるようで,例えば,

(global-whitespace-mode 1)

としていても,メジャーモードを変更するとハイライトが消えてしまいます.なので init file に次のような修正を加えます.

;; For the whitespace.el v12.1
(defun global-whitespace-mode-enable-in-buffers ()
  ;; `global-*-mode-enable-in-buffers' is generally created by the macro
  ;; `define-global-minor-mode'.
  ;; Also added to the hook `after-change-major-mode-hook'.
  (unless whitespace-mode
    (whitespace-turn-on-if-enabled)
    ;; Include the scratch buffer
    (when (string= (buffer-name) "*scratch*")
      (whitespace-turn-on))))
(add-hook 'after-change-major-mode-hook
          'global-whitespace-mode-enable-in-buffers)

で,apples-mode を最新のやつに更新すると,適切にハイライトしてくれるようになります.
余談ですが,メジャーモードを定義するときには run-hooks ではなくて,run-mode-hooks を使わないと after-change-major-mode-hook が実行されないようです.古いメジャーモード(js2-mode とか)では run-hooks のままになっていて,メジャーモードの変更に global-minor-mode が追従してくれないかもしれません.

auto-complete-latex-light.el

去年 auto-complete-latex というものを作ったんですが,機能が多すぎて重くなったり,設定方法が特殊だったりと色々いけていない面があったんで,機能を大幅に削減した簡易ヴァージョンを作ってみました.

# URL: https://github.com/tequilasunset/auto-complete-latex-light

$ git clone git://github.com/tequilasunset/auto-complete-latex-light.git

作業効率が格段に向上したりといったことはありませんが,無いよりはマシかな程度には感じられると思います.auto-complete-latex は初めて書いた elisp なんで思い入れが深いのかも.

tabbar.el 2.0 の導入

Emacs Wikiversion 2.0 が上がっていることに気がついたので,導入してみました.

主な変更点

ver 1.3 からどこら辺が変わったのか.

  • タブ上でマウスホイールをスクロールさせるとタブ移動
  • 画像が使える(ver 1.3 でも使えたかも?)

初期設定

タブ上でマウスホイールを使わない

正直いらないです.

(tabbar-mwheel-mode -1)
グループを使わない(1.3 とやり方が違う)
(setq tabbar-buffer-groups-function nil)
左側のボタンを消す(これも 1.3 と違う)
(dolist (btn '(tabbar-buffer-home-button
               tabbar-scroll-left-button
               tabbar-scroll-right-button))
  (set btn (cons (cons "" nil)
                 (cons "" nil))))
ウィンドウからタブがはみ出たときの動作
  • タブをスクロールさせる(デフォルト)
(setq tabbar-auto-scroll-flag t)
  • タブを省略して表示
(setq tabbar-auto-scroll-flag nil)

こんな感じになります.以前似たようなことやったなあ.

  • スクロールも省略もさせない(そのままはみ出させたい場合)
(setq tabbar-auto-scroll-flag nil)
(defadvice tabbar-buffer-tab-label (around my-tabbar-ad-dont-shorten activate)
  (let ((tabbar-auto-scroll-flag t))
    ad-do-it))
タブに表示させるバッファ名

1.3 とやり方は変わっていませんでした.僕の場合はこんな感じ

(defvar my-tabbar-displayed-buffers
  '("*scratch*" "*Messages*" "*Backtrace*" "*Colors*" "*Faces*" "*vc-")
  "*Regexps matches buffer names always included tabs.")

(defun my-tabbar-buffer-list ()
  "Return the list of buffers to show in tabs.
Exclude buffers whose name starts with a space or an asterisk.
The current buffer and buffers matches `my-tabbar-displayed-buffers'
are always included."
  (let* ((hides (list ?\  ?\*))
         (re (regexp-opt my-tabbar-displayed-buffers))
         (cur-buf (current-buffer))
         (tabs (delq nil
                     (mapcar (lambda (buf)
                               (let ((name (buffer-name buf)))
                                 (when (or (string-match re name)
                                           (not (memq (aref name 0) hides)))
                                   buf)))
                             (buffer-list)))))
    ;; Always include the current buffer.
    (if (memq cur-buf tabs)
        tabs
      (cons cur-buf tabs))))

(setq tabbar-buffer-list-function 'my-tabbar-buffer-list)
タブ移動のキーバインド

僕は Mac のデフォルトと同じように command + shift + cursor にしてます.

(global-set-key (kbd "<S-s-right>") 'tabbar-forward-tab)
(global-set-key (kbd "<S-s-left>") 'tabbar-backward-tab)
フェイス

1.3 から変更されて,tabbar-hoge-face だったのが tabbar-hoge になっています.

タブの間

長さを指定するだけならこんな感じ

(setq tabbar-separator '(1.5))
タブ上でのマウスクリック

ホイールクリックで kill-buffer するように弄ってます.それだけ.

(defun my-tabbar-buffer-help-on-tab (tab)
  "Return the help string shown when mouse is onto TAB."
  (if tabbar--buffer-show-groups
      (let* ((tabset (tabbar-tab-tabset tab))
             (tab (tabbar-selected-tab tabset)))
        (format "mouse-1: switch to buffer %S in group [%s]"
                (buffer-name (tabbar-tab-value tab)) tabset))
    (format "\
mouse-1: switch to buffer %S\n\
mouse-2: kill this buffer\n\
mouse-3: delete other windows"
            (buffer-name (tabbar-tab-value tab)))))

(defun my-tabbar-buffer-select-tab (event tab)
  "On mouse EVENT, select TAB."
  (let ((mouse-button (event-basic-type event))
        (buffer (tabbar-tab-value tab)))
    (cond
     ((eq mouse-button 'mouse-2)
      (with-current-buffer buffer
        (kill-buffer)))
     ((eq mouse-button 'mouse-3)
      (delete-other-windows))
     (t
      (switch-to-buffer buffer)))
    ;; Don't show groups.
    (tabbar-buffer-show-groups nil)))

(setq tabbar-help-on-tab-function 'my-tabbar-buffer-help-on-tab)
(setq tabbar-select-tab-function 'my-tabbar-buffer-select-tab)
super + number でタブ指定

以前の物がそのまま使える

タブをカラフルにする

以前やった改造は 2.0 だとより泥臭いやり方になってしまうので,今回はなしで.

まとめ

画像とか使わないなら 1.3 で十分な気がする.なんか便利な使い方知っている人がいたら教えてください.

init ファイル作りがしんどい

取り敢えずこんなのをでっち上げてみた.
init-file-maker.el
予め,init ファイルのあるディレクトリを指定しておいて,

M-x ifm:make RET

すると,そのディレクトリに適当なファイルを作って,テンプレを挿入するってだけ.ここまでしないと拡張を導入する気がしないってのもあれだけど.因みに,複数ファイル構成のパッケージには対応していません.