読者です 読者をやめる 読者になる 読者になる

find-header-file.el

Emacs

エラーコード12が何なのか調べようとして気軽に「less /usr/include/errno.h」としたところ、実はこのファイルにはエラー番号の定義はないことを発見した。おそらく、ここからincludeされているにあるらしい。(errno.hを追跡していたらひどい目にあった)

CやC++だと上記のようにヘッダファイルを見たら別のヘッダファイルをインクルードしてるだけで、さらにそのファイルを探さないといけないようなことが結構あります。自分も常日頃面倒だなあと思いつつ、何もしてなかったのですが、上記のエントリをきっかけに、ちょっと重い腰を上げて、以下のようなelispを書いてみました。

;; Author:Tatsuhiko Kubo
;; This elisp can open header file on current line.

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.


(defvar find-header-file-header-file-prefixes (list "/usr/include/"
						    "/usr/local/include/"
						    ))

(defun find-header-file-current-char ()
  (char-to-string (char-after (point))))

(defun find-header-file-current-line-string ()
  (let ((line-string ""))
    (save-excursion 
      (while (not (bolp))
	(backward-char))
      (while (not (eolp))
	(setq line-string (concat line-string (find-header-file-current-char)))
	(forward-char)))
    line-string))

(defun find-header-file-buffer-on-path (prefix-list filename)
  (if (null (car prefix-list))
      nil
    (if (file-exists-p (concat (car prefix-list) filename))
	(find-file-noselect (concat (car prefix-list) filename))
      (find-header-file-buffer-on-path (cdr prefix-list) filename))))

(defun find-header-file ()
  (interactive)
  (let ((current-line-string (find-header-file-current-line-string))
	(header-file-buffer nil))
    (cond ((string-match "^\\s-*#\\s-*include\\s-*<\\s-*\\([^< ]+\\)\\s-*>" current-line-string)
	   (let ((header-file-path (match-string 1 current-line-string)))
	     (setq header-file-buffer (find-header-file-buffer-on-path find-header-file-header-file-prefixes
								       header-file-path))))
	  ((string-match "^\\s-*#\\s-*include\\s-*\"\\([^\"]+\\)\"\\s-*" current-line-string)
	   (let* ((header-file-path (match-string 1 current-line-string))
		  (buffer           (if (file-exists-p (concat default-directory header-file-path))
					(find-file-noselect (concat default-directory header-file-path))
				      nil)))
	     (setq header-file-buffer buffer)
	     (if (null header-file-buffer)
		 (setq header-file-buffer (find-header-file-buffer-on-path find-header-file-header-file-prefixes
									   header-file-path))
	       nil)))
	  (t nil))
    (if (null header-file-buffer)
	(message "not found header file")
;;      (elscreen-switch-or-create header-file-buffer)))) ;; 自分用
      (switch-to-buffer header-file-buffer))))


例えば、以下のようにstdio.hをインクルードするように書かれた行にカーソルを持って行き、

#include <stdio.h>


M-x find-header-fileを実行すると、/usr/include、/usr/local/includeの順にstdio.hが存在するか調べ、ヘッダファイルがダブルクオートで囲まれているなら、単にカレントディレクトリから探します。自分で言うのもなんですが、結構便利です。


それから、話は変わりますが、やっぱりEmacsLispの正規表現は自分で書いていても見づらいです。あと、どうにかしてnamespaceっぽいことがしたい。