Emacs: (SQLなどの)予約語をすべて大文字にする

ひさしぶりに Emacs Lisp を書きました。ググりながら10分くらいで書いた適当なもの。

たとえば、全部小文字で書いたSQLを後から予約語だけ大文字にしたい、みたいなときに使う想定です。

フェイスが font-lock-keyword-face になっている箇所を大文字にしているので、SQL の場合は sql-mode になっている状態で実行します。

(progn
  (goto-char (point-min))
  (while (not (eobp))
    (let ((faces-at-point (get-char-property (point) 'face)))
      (when (eq 'font-lock-keyword-face faces-at-point)
        (upcase-word 1))
      (forward-char 1))))

Emacs: 現在位置のSQLをよしなに選択+コピーする

EmacsSQL 書く → リージョン選択(現在位置から先頭に移動して末尾に移動) → コピー

というのを何回も繰り返す場合、

  • 手数が多くてだるい
  • カーソルを移動させると、元の位置に戻るのがだるい

というあたりがだるかったので改善してみた。

完成形

(defun my-sql:query-beginning ()
  (let (beg beg-para beg-sc)
    (save-excursion
      (backward-paragraph)
      (setq beg-para (+ (point) 1)))
    (save-excursion
      (when (search-backward-regexp ";\n" nil t)
          (setq beg-sc (+ (point) 2))))
    (if beg-sc
        (max beg-para beg-sc)
      beg-para)))

(defun my-sql:query-end ()
  (let (end end-para end-sc)
    (save-excursion
      (forward-paragraph)
      (setq end-para (- (point) 1)))
    (save-excursion
      (when (search-forward-regexp ";\n" nil t)
          (setq end-sc (- (point) 1))))
    (if end-sc
        (min end-para end-sc)
      end-para)))

(defun my-sql:copy-current-query ()
  "Copy current query."
  (interactive)
  (kill-ring-save
   (my-sql:query-beginning)
   (my-sql:query-end)))

(global-set-key (kbd "C-M-h") 'my-sql:copy-current-query)

メモ

まず、今いる位置から動かずに1キーストロークで段落選択してコピーできるようにしてみた。mark-paragraph 使えば簡単。

(defun copy-current-query ()
  "..."
  (interactive)
  (save-excursion
    (mark-paragraph)
    (kill-ring-save (region-beginning) (region-end))))

これの不満点:

  • 選択範囲の先頭に余計な改行が付く … 困るわけではないが余計なので削りたい
  • 選択範囲の末尾に余計な改行が付く … 最後のセミコロンの後に改行が付いていると、RDBMSクライアントのプロンプトにペーストしたときに即実行されてしまうのが嫌。最後の改行なしでペーストして、(場合によっては深呼吸などして)確認した後にエンター押下で実行させたい。ワンクッション置きたい。
(defun copy-current-query ()
  "..."
  (interactive)
  (let (beg end)
    (save-excursion

      (backward-paragraph)
      (setq beg (+ (point) 1))
      
      (forward-paragraph)
      (setq end (- (point) 1))

      (kill-ring-save beg end))))

まだ不満な点:

選択の単位として段落を使うと、たとえば1行ずつのSQLをこのように並べて書いていて

select * from table1 limit 10;
select * from table2 limit 10;
select * from table3 order by created_at desc limit 10;

真ん中のクエリだけコピーしたいのに3行ともコピーされてしまう。1行ごとに改行入れればよいけど、ワンライナーのために無駄に行を消費したくない。

そこで、区切りとして前方、後方の ";\n" を探すようにしてみる。
セミコロン書かない+段落で見れば良いというケースもあるので、段落境界と比較して近い方を使うようにする。

(defun copy-current-query ()
  "..."
  (interactive)
  (let (beg beg-para beg-sc
        end end-para end-sc)
    (save-excursion
      (backward-paragraph)
      (setq beg-para (+ (point) 1))
      (forward-paragraph)
      (setq end-para (- (point) 1)))

    (save-excursion
      (if (search-backward-regexp ";\n" nil t)
          (setq beg-sc (+ (point) 2))
        (setq beg-sc beg-para)))

    (save-excursion
      (if (search-forward-regexp ";\n" nil t)
          (setq end-sc (- (point) 1))
        (setq end-sc end-para)))

    (setq beg (max beg-para beg-sc))
    (setq end (min end-para end-sc))

    (kill-ring-save beg end)))

大体いい感じになった。
選択範囲の始点・終点を求める部分は使いまわせそうなので、関数を抽出する。こうしておくと、たとえば、今いるクエリをフォーマットする場合なんかに流用できる。

関数が複数になったので名前空間的に my-sql: というプレフィックスを付けてみた。

;; 上の完成形と同じなのでコード省略

関数ごとに目的がはっきりしているし、良いと思う。


以下おまけ。自分用設定的なもの。

視覚的フィードバックが何もないと不安になるので、どこをコピーしたのか分かるように一定時間ハイライトさせる。

一定時間だけ指定範囲をハイライトする Emacs Lisp | anobota を使用)

(require 'volatile-highlight)

(defun my-sql:copy-current-query ()
  "..."
  (interactive)
  (let ((beg (my-sql:query-beginning))
        (end (my-sql:query-end)))
    (kill-ring-save beg end)
    (volatile-highlight beg end 1)))

フォーマット。
参考: (書きかけ)EmacsでSQLの整形(要Ruby) | anobota

(defun my-sql:format-currenty-query ()
  "Format current query"
  (interactive)
  (shell-command-on-region
   (my-sql:query-beginning) (my-sql:query-end)
   (format "ruby %s" anbt-sql-formatter:formatter-path)
   nil t)
  (volatile-highlight (my-sql:query-beginning) (my-sql:query-end) 0.2))

(global-set-key (kbd "C-S-f") 'my-sql:format-currenty-query)

Anythingの "Files from Current Directory" でバックアップファイルを表示しないようにする

setq でいいんだっけ……と思いつつ以下を .emacs に追加。

(setq anything-c-source-files-in-current-dir+
  '((name . "Files from Current Directory")
    (candidates . (lambda ()
                    (with-current-buffer anything-current-buffer
                      (directory-files (anything-c-current-directory) t "[^~]$"))))
    (candidate-transformer anything-c-highlight-files)
    (type . file)))

anything-config.el から該当箇所をコピペして directory-files の第3引数の正規表現を追加しただけ。

Emacs: (solved) 新しいフレームを開いたときのフォントサイズがおかしい

修正前:

(set-frame-font "Takaoゴシック-10")

これで新しいフレームを開くと、普通に Emacs を起動したときよりも大きいフォントで表示される。
それは困るというか嫌なのでちょっとぐぐって次のように修正したら解決した。

;; 下のを追記したらこっちは不要っぽい
;; (set-frame-font "Takaoゴシック-10")

(setq default-frame-alist
      (append '((font . "Takaoゴシック-10"))
              default-frame-alist))

emacsclient で新しいフレームを開いたときもこれで大丈夫でした。



環境:

org-mode: 「アンダースコアで下付き」を無効にする

  • アンダースコアはファイル名や変数名で頻出する
  • 一方で下付きが必要なことはほとんどない(自分は)
  • 「アンダースコアで下付き」はアンダースコアの前にバックスラッシュを置くと抑制できるが、いちいちめんどくさいし、人間が読むのに邪魔



#+OPTIONS: ^:{}

で解決した(「ハット ^ で上付き」も無効になる)。
上のように指定した場合、

_{下付きにしたい文字列}

で下付きにできる(上付きも同様)。



  • emacs-version: "23.1.1"
  • org-version: "7.7"

で確認した。

一定時間だけ指定範囲をハイライトする Emacs Lisp

volatile-highlight.el - Gist


ハイライトしたい範囲の開始ポイントと終了ポイントを指定すると 一時的に指定範囲をハイライトする。 ハイライトする時間はデフォルトは 0.1秒なので、一瞬キラっとする感じ。

;; require する
(require 'volatile-highlight)

;; 使う
(volatile-highlight 1 10) ; 開始位置、終了位置
(volatile-highlight 1 10 2) ; 開始位置、終了位置、ハイライトさせる時間(秒)

ハイライトに使っているフェイスは volatile-highlight-face で、たとえば背景色を変えたい場合は

(set-face-background 'volatile-highlight-face "#ff8")

のように指定する。

デフォルトのハイライト持続時間を変更したい場合は volatile-highlight:default-duration-sec に秒数をセットする。

(setq volatile-highlight:default-duration-sec 10)

eval-defun または eval-last-sexp して一瞬キラッとさせたい場合の例:

(require 'thingatpt) ; for beginning-of-sexp

(defadvice eval-defun
  (after blink-after-eval-defun activate)
  (let (beg end)
    (save-excursion
      (end-of-defun) (forward-char -1)
      (setq end (point))
      (beginning-of-defun)
      (setq beg (point)))
    (volatile-highlight beg end 0.2)))
(ad-activate 'eval-defun)

(defadvice eval-last-sexp
  (after blink-after-eval-last-sexp activate)
  (let (beg end)
    (save-excursion
      (setq end (point))
      (beginning-of-sexp)
      (setq beg (point)))
    (volatile-highlight beg end 0.2)))
(ad-activate 'eval-last-sexp)

追記 2011-10-26

修正しました。変更点は以下の通り。

  • 複数の箇所を同時にハイライトできるようにした
  • volatile-highlight の3番目の引数で持続時間を指定できるようにした(optional)
  • 変数名などを修正

関連記事

参考

imcap.el を改造してみた(指定秒後の撮影など)

修正点:

  • 指定秒後にスクリーンショットを撮れるようにした
  • imcap-directory が存在しなかったら作成する
  • モードに合わせて挿入する文字列のフォーマットを変える(org-mode なら "file:..."、howm-mode なら ">>> ..."、それ以外なら cacoo.el のフォーマット "[img:...]")
  • 画像表示は cacoo.el にまかせる

なるべく .emacs.el の方で挙動を変えられるようにして、そのために必要な修正を imcap.el に加えるかたちになっています。

元の imcap.el のライセンスが不明なのでとりあえず diff を貼っときます。

diff:

.emacs.el: