unix-conf/.emacs.d/elpa/ac-c-headers-20151021.134/ac-c-headers.el
2016-02-18 14:53:30 +01:00

175 lines
6.2 KiB
EmacsLisp

;;; ac-c-headers.el --- auto-complete source for C headers
;; Copyright (C) 2013-2015 zk_phi
;; 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 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
;; Author: zk_phi
;; URL: http://hins11.yu-yake.com/
;; Package-Version: 20151021.134
;; Version: 1.0.0
;; Package-Requires: ((auto-complete "1.3.1"))
;;; Commentary:
;; Require this script (and auto-complete) then add to ac-sources.
;;
;; (add-hook 'c-mode-hook
;; (lambda ()
;; (add-to-list 'ac-sources 'ac-source-c-headers)
;; (add-to-list 'ac-sources 'ac-source-c-header-symbols t)))
;;
;; then header filenames and symbols in imported headers are completed.
;;
;; #include <s[tdio.h>] <- ac-source-c-headers
;; pr[intf] <- ac-source-c-header-symbols
;;; Change Log:
;; 1.0.0 first released
;;; Code:
(require 'find-file)
;; + constants
(defconst ac-c-headers-version "1.0.0")
;; + filenames
(defvar ac-c-headers--files-cache nil
"list of (PREFIX . FILE-OR-DIRECTORY ...)")
(defun ac-c-headers--files-update (&optional prefix)
(setq prefix (or prefix ""))
(unless (assoc prefix ac-c-headers--files-cache)
(setq ac-c-headers--files-cache
(cons (cons prefix
(apply 'append
(mapcar
(lambda (dir)
(let ((path (concat (file-name-as-directory dir) prefix)))
(when (file-accessible-directory-p path)
(delq nil
(mapcar
(lambda (file)
(cond ((file-directory-p (concat path file))
(concat file "/"))
((string-match "\\h$" file)
file)
(t
nil)))
(directory-files path nil))))))
cc-search-directories)))
ac-c-headers--files-cache))))
(defun ac-c-headers--files-list (&optional point)
"returns possible completions at the point"
(save-excursion
(when point (goto-char point))
(when (looking-back "[<\"]\\([^<>\"]*?\\)\\([^<>\"/]*\\)")
(let ((prefix (match-string 1)))
(unless (assoc prefix ac-c-headers--files-cache)
(ac-c-headers--files-update prefix))
(cdr (assoc prefix ac-c-headers--files-cache))))))
;; + symbols in headers
(defvar ac-c-headers--symbols-cache nil
"list of (HEADER . SYMBOL ...)")
(defun ac-c-headers--search-header-file (header)
(catch 'found
(dolist (prefix cc-search-directories)
(let ((file (concat prefix
(unless (string-match "/$" prefix) "/")
header)))
(when (file-exists-p file)
(throw 'found file))))))
(defun ac-c-headers--symbols-update (header)
(unless (assoc header ac-c-headers--symbols-cache)
(let ((file (ac-c-headers--search-header-file header)))
(when (and file (file-exists-p file))
(with-temp-buffer
(insert-file-contents file)
;; delete /* comments */
(goto-char (point-min))
(while (search-forward-regexp
"/\\*\\([^*]\\|\\*[^/]\\)*\\*/" nil t)
(replace-match ""))
;; delete // comments
(goto-char (point-min))
(while (search-forward-regexp "//.*$" nil t)
(replace-match ""))
;; search symbols
(setq ac-c-headers--symbols-cache
(cons (cons header
(delete-dups
(let ((res nil))
(goto-char (point-min))
(while (search-forward-regexp
"\\_<[a-zA-Z_]*\\_>" nil t)
(setq res (cons (match-string 0) res)))
res)))
ac-c-headers--symbols-cache)))))))
(defun ac-c-headers--symbols-list (&optional buffer)
"returns possible completions for the buffer"
(setq buffer (or buffer (current-buffer)))
(with-current-buffer buffer
(let ((res nil) header)
(save-excursion
(goto-char (point-min))
(while (search-forward-regexp
"^#include *[<\"]\\([^>\"]*\\)[>\"]" nil t)
(setq header (match-string 1))
(unless (assoc header ac-c-headers--symbols-cache)
(ac-c-headers--symbols-update header))
(setq res (append (cdr (assoc header ac-c-headers--symbols-cache))
res))))
res)))
;; + ac-sources
(defvar ac-source-c-headers
'((prefix . "#include *[<\"][^<>\"]*?\\([^<>\"/]*\\)")
(candidates . ac-c-headers--files-list)
(action . (lambda ()
(when (string-match "\\.h$" candidate)
(ac-c-headers--symbols-update candidate)
(cond ((looking-at "[>\"]")
(forward-char 1)
(newline-and-indent))
((looking-back "#include *<\\([^<]*\\)")
(insert ">\n"))
(t
(insert "\"\n"))))))
(symbol . "h")
(requires . 0)
(cache)))
(defvar ac-source-c-header-symbols
'((candidates . ac-c-headers--symbols-list)
(symbol . "h")
(cache)))
;; + provide
(provide 'ac-c-headers)
;;; ac-c-headers.el ends here