程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Emacs自動填充頭文件

Emacs自動填充頭文件

編輯:關於C語言

目標
1. 寫 C/C++ 代碼時候,可以根據自動補全頭文件。注意,是補全,也就是說至少我們需要輸入幾個字符讓它幫忙補全。
2. 如果頭文件存放在搜索路徑的子目錄中,可以自動列出子目錄中的文件,並將這些文件添加到用於補齊的候選名單中。
3. 補齊完成之後,可以自動判斷到底應該使用 #include還是 #include “FILE” 。
方案
emacser.org 上有一篇文章,其中提到了這個解決方法,主要是利用了 abbrev-mode 和 skeleton-mode 來實現,通過這個方法,我們輸入 inc, 然後按空格, 會提示輸入文件名稱。
代碼如下:
View CodeLISP
;; 安裝 abbrev
(mapc
 (lambda (mode)
   (define-abbrev-table mode '(
                               ("inc" "" skeleton-include 1)
                               )))
 '(c-mode-abbrev-table c++-mode-abbrev-table))
 
;; 輸入 inc , 可以自動提示輸入文件名稱,可以自動補全.
(define-skeleton skeleton-include
  "generate include<>" ""
  > "#include <"
  (completing-read "Include File:"
                   (mapcar #'(lambda (f) (list f ))
                           (apply 'append
                                  (mapcar
                                   #'(lambda (dir)
                                       (directory-files dir))
                                   (list "/usr/include"
                                         "/usr/local/include"
                                         "/usr/include/g++-3")))))
  ">")
該方法有若干局限性:
• 頭文件的搜索路徑是寫死的,如果某個目錄不存在,上面的代碼會報錯,不能補全。
• 無法補全搜索路徑的子目錄下的文件 ( 即前面的 AIM 2)。
• 沒有判斷在 #include 一個文件的時候,是應該使用符號 <> 還是符號 “” (即前面的 AIM 3)
解決方法並不復雜,對應如下:
• 通過某種方法來從系統中自動獲取 include 的搜索路徑。比如 CEDET 提供的: semantic-gcc-get-include-paths 函數。
• 重定義 minibuffer-mode 下的按鍵 “/”。將其綁定到一個用於搜索和展開某個目錄,並更新 minibuffer-completion-table 的函數(minibuffer-completion-table 是 minibuffer-mode 中補全的候選 list)。
• 在 skeleton-include 中不使用 <> 或者 “。我們可以使用一個特殊的標記,然後在 skeleton-include 的結尾,根據頭文件的路徑判斷到底應該使用什麼符號。
整理以後的代碼實現如下:
View CodeLISP
;; 輸入 inc , 可以自動提示輸入文件名稱,可以自動補全.
;; Provided by [email protected]
(mapc
 (lambda (mode)
   (define-abbrev-table mode '(
                               ("inc" "" skeleton-include 1)
                               )))
 '(c-mode-abbrev-table c++-mode-abbrev-table))
 
(defconst yc/inc-dir-list
  (append (semantic-gcc-get-include-paths "c++") '("./")) "nil")
(defvar inc-minibuffer-compl-list nil "nil")
 
(defun yc/update-minibuffer-complete-table ( )
  "Complete minibuffer"
  (interactive)
  (let ((prompt (minibuffer-prompt))
        (comp-part (minibuffer-contents-no-properties)))
    (when (and (string= "Include File:" prompt)
               (> (length comp-part) 0))
      (setq minibuffer-completion-table
            (append minibuffer-completion-table
                    (let ((inc-files nil)
                          (dirname nil)
                          (tmp-name nil))
                      (mapc
                       (lambda (d)
                         (setq dirname (format "%s/%s" d comp-part))
                         (when (file-exists-p dirname)
                           (mapc
                            (lambda (x)
                              (when (not (or (string= "." x)
                                             (string= ".." x)))
                                (setq tmp-name (format "%s/%s" comp-part x))
                                (add-to-list 'inc-files tmp-name)))
                            (directory-files dirname))))
                       yc/inc-dir-list)
                      inc-files)))))
  (insert "/"))
 
(let ((map minibuffer-local-completion-map))
  (define-key map "/" 'yc/update-minibuffer-complete-table))
 
(defun yc/update-inc-marks ( )
  "description"
    (let ((statement (buffer-substring-no-properties
                      (point-at-bol) (point-at-eol)))
          (inc-file nil)
          (to-begin nil)
          (to-end nil)
          (yc/re-include
           (rx "#include" (+ ascii) "|XXX|" (group (+ ascii)) "|XXX|")))
      (when (string-match yc/re-include statement)
        (setq inc-file (match-string 1 statement))
        (if (file-exists-p (format "./%s" inc-file))
            (setq to-begin "\"" to-end "\"")
          (setq to-begin "<" to-end ">")
          )
        (move-beginning-of-line 1)
        (kill-line)
        (insert (format "#include %s%s%s" to-begin inc-file to-end))
        (move-end-of-line 1))))
 
(define-skeleton skeleton-include
  "generate include<>" ""
  > "#include |XXX|"
  (completing-read
   "Include File:"
   (mapcar
    (lambda (f) (list f ))
    (apply
     'append
     (mapcar
      (lambda (dir)
        (directory-files
         dir nil
         "\\(\\.h\\)?"))
      yc/inc-dir-list))))
  "|XXX|"
  (yc/update-inc-marks))
使用和效果
使用方法很簡單:
1. 將上述的代碼添加到 Emacs 的配置文件後,打開一個 C/C++ 程序,
2. 輸入 inc 然後按下空格,然後在 minibuffer 中輸入部分頭文件的名字,並通過 TAB 來補全。
3. 如果頭文件位於子目錄中,則輸入目錄名後輸入 “/” 。這樣子目錄中的內容也會添加到補齊的候選名單中,然後就又可以繼續他過 TAB 補全了。
4. 確認 minibuffer 中填寫的內容無誤後,回車, skeleton-include 將自動更新標記符號。
截圖:
 
下面是幾張截圖:

Include 系統文件

Include 自定義文件

全部完成後截圖 


作者  bigclean  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved