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

C, C++の関連ファイルを開く

続・C言語の関連ファイルを開くの続き。


実はファイルパス中で拡張子の前以外に「.」があると、関連ファイルを開けないという
バグを結構前に発見してそのまま放置してたんだけど、そろそろ直すことにした。
原因は単にフルパスのファイル名から拡張子を取り除く正規表現
拡張子の前以外に「.」があることを考慮に入れてなかったということなので、
修正自体はサッと済んだ。あとついでにC++のファイルも行き来できるようにした。
C++の拡張子ってたくさんあってもしかしたら抜けがあるかもしれないけど、
それはまあ気付いたら追加していく感じで。

(defun c-open-relational-file (how-open-type)
  (interactive "nOpen-Type: ")
  (defun get-opened-file-name-prefix (file-name)
    (string-match "/\\([^./]+\\)\\.[^.]+$" file-name)
    (match-string 1 file-name))
  (defun get-ext-type (file-name)
    (string-match "\\.\\([^.]+\\)$" file-name)
    (match-string 1 file-name))
  (defun get-opening-file-name (file-name-prefix ext-list)
    (let ((opening-file-name (concat file-name-prefix "." (car ext-list))))
      (cond ((null (car ext-list))             nil)
            ((file-exists-p opening-file-name) opening-file-name)
            (t                                 (get-opening-file-name file-name-prefix
                                                                      (cdr ext-list))))))
  (let* ((ext-map '(
                    ("h" . ("c" "cpp" "cxx" "cc" "c++"))
                    ("c" . ("h" "s"))
                    ("s" . ("c"))
                    ("cpp" . ("hpp" "h" "hxx" "h++"))
                    ("hpp" . ("cpp" "cxx" "cc" "c++"))
                    ))
         (opened-file-name (buffer-file-name (window-buffer)))
         (opened-file-name-prefix (get-opened-file-name-prefix opened-file-name))
         (opened-file-ext-type (get-ext-type opened-file-name))
         (opening-file-ext-type-list (cdr (assoc opened-file-ext-type ext-map)))
         (opening-file-name (get-opening-file-name opened-file-name-prefix
                                                   opening-file-ext-type-list))
         (opening-file-buffer (find-file-noselect opening-file-name)))
    (cond ((= how-open-type 1) (elscreen-switch-or-create opening-file-buffer))
          ((= how-open-type 2) (progn (split-window-horizontally)
                                      (other-window 1)
                                      (switch-to-buffer opening-file-buffer)))
          (t                   (message "Illegal Type")))))

ちなみ上記で使っているelscreen-switch-or-createは普段から愛用しているelscreen.el用の自作拡張elispです。
既存のswitch-to-bufferをelscreenで使いやすいようにラップした感じです。

(defun elscreen-switch-or-create (buf)
  (defun create-new-buf (buf)
    (if (equal elscreen-default-buffer-name (buffer-name (window-buffer)))
        (switch-to-buffer buf)
      (elscreen-create)
      (switch-to-buffer buf)))
  (defun switch-to-elscreen-create-inner (screen-list buf)
    (cond ((null (elscreen-get-window-configuration (car screen-list)))
           nil)
          ((equal (car screen-list) (elscreen-find-screen-by-buffer (buffer-name buf)))
           (elscreen-goto (car screen-list)))
        (t
         (switch-to-elscreen-create-inner (cdr screen-list) buf))))
  (if (null (switch-to-elscreen-create-inner (elscreen-get-screen-list) buf))
      (create-new-buf buf)
    t))