Emacs で行番号を指定してファイルを開く

Posted on
qiita Emacs ShellScript

この記事はQiitaの記事をエクスポートしたものです。内容が古くなっている可能性があります。

:bulb: 以下、emacs の部分は、あなたの Emacs 利用形態(新しい Emacs ではなくすでに起動している Emacs 上で開くとか)に合わせて emacsclient -n とかにしてください。

ターミナルから行番号を指定して開く

Emacs のコマンドラインヘルプを見ると…

$ emacs --help
Usage: /usr/local/opt/emacs-mac/bin/emacs [OPTION-OR-FILENAME]...

Run Emacs, the extensible, customizable, self-documenting real-time
display editor.  The recommended way to start Emacs for normal editing
is with no options at all.

(snip)

Action options:

FILE                    visit FILE using find-file
+LINE                   go to line LINE in next FILE
+LINE:COLUMN            go to line LINE, column COLUMN, in next FILE

(snip)

ということで、/path/to/hoge ファイルの__20行目__を開くときは

$ emacs +20 /path/to/file

__20行目の40文字目__を開くときは

$ emacs +20:40 /path/to/file

です :exclamation:

/path/to/file:20 で開きたい

  • RSpec の行指定
  • grep -n の出力
  • ag の出力

と同じスタイルで開きたい場合、同じようにシェル関数を用意しておいて、

function e {
    local args
    args=`echo $1 | sed -E "s/([^:]+):([0-9:]+)/+\2 \1/g"`
    eval "emacs $args"
}
$ e /path/to/file:20

書いてて思ったんですけど、これ ag + peco と組み合わせると超便利コマンドが生まれるのでは… :bulb:

/path/to/file 20 で開きたい

シェルだと補完が効いて、ファイル名の後に半角スペースが1個入ってしまう。じゃあそのまま第二引数で行番号を指定したい。

こういうシェル関数を .bashrc とか .zshrc に用意しておいて、

function e {
    local args
    args="+$2 $1"
    eval "emacs $args"
}
$ e /path/to/file 20

どっちでも開けるようにしたい!

自分はどちらのスタイルでも開けるように、以下の様なシェル関数を .zshrc に定義してあります。

https://github.com/dtan4/dot.zsh/blob/0df6620f853d6a98de7b17de179dbbe3fc835f09/.zshrc.function#L22-L32

function e {
    local args

    if [[ $# -eq 2 ]]; then
        args="+$2 $1"
    else
        args=`echo $1 | sed -E "s/([^:]+):([0-9:]+)/+\2 \1/g"`
    fi

    eval "emacsclient -n $args"
}

Emacs 上で行番号を指定して開く

そういうことができるコマンドは Emacs に存在しないので、既存の C-x C-f (find-file) を拡張することで対処します。以下のコードを init.el なりに追加しましょう。

;; http://stackoverflow.com/questions/3139970/open-a-file-at-line-with-filenameline-syntax/3141456#3141456
(defadvice find-file (around find-file-line-number
                             (filename &optional wildcards)
                             activate)
  "Turn files like file.cpp:14 into file.cpp and going to the 14-th line."
  (save-match-data
    (let* ((matched (string-match "^\\(.*\\):\\([0-9]+\\):?$" filename))
           (line-number (and matched
                             (match-string 2 filename)
                             (string-to-number (match-string 2 filename))))
           (filename (if matched (match-string 1 filename) filename)))
      ad-do-it
      (when line-number
        ;; goto-line is for interactive use
        (goto-char (point-min))
        (forward-line (1- line-number))))))

これで、C-x C-f /path/to/file:20 すればちゃんと20行目で開くようになります。

REF