Download
(provide 'clibpc)
(eval-when-compile
(require 'cl))
(require 'complete)
(defvar clibpc-header-file-regexp "\\.h$"
"The file match this regexp will be scaned.")
(defvar clibpc-include-path
'("/usr/include/gtk-2.0"
"/usr/include/glib-2.0"
"/usr/include/libglade-2.0/")
"The header file directories. The files that match
`clibpc-header-file-regexp' in these directory will all be scaned
by `clibpc-parse-header'.")
(defvar clibpc-obarray nil
"All functions in lib. Every symbol in this obarray has a value
(FILE . POS), which FILE and POS is the position of the symbol
declared in header files. The symbol may have a property document
which is the declaration of the function.")
(defvar clibpc-regexp-list
'(("^\\(?:\\(?:G_CONST_RETURN\\|extern\\|const\\)\\s-+\\)?[a-zA-Z][_a-zA-Z0-9]*\
\\(?:\\s-*[*]*[ \t\n]+\\|\\s-+[*]*\\)\\([a-zA-Z][_a-zA-Z0-9]*\\)\\s-*(" . 1)
("^\\s-*#\\s-*define\\s-+\\([a-zA-Z][_a-zA-Z0-9]*\\)" . 1))
"The line match this regexp will add to obarray.
The car part of cons cell is the regexp to search, and cdr part
is the parenthesized expression of the function name.")
(defvar clibpc-cache-file "~/.emacs.d/clibpc-symbols.el"
"Save parsed data to this file.")
(defun clibpc-parse-header (file &optional arg)
"Extract function name and declaration position using
`clibpc-regexp-list'. If arg in non-nil or call interactively, the
symbol extracted will not save to clibpc-cache-file. So you can add
symbol just for current session."
(interactive "fHeader file: \nP")
(or arg (setq arg (called-interactively-p)))
(let (sym)
(with-temp-buffer
(insert-file-contents file)
(dolist (re clibpc-regexp-list)
(goto-char (point-min))
(while (re-search-forward (car re) nil t)
(setq sym (intern (match-string (cdr re)) clibpc-obarray))
(set sym (cons file (line-beginning-position)))
(and arg (put sym 'no-save arg)))))))
(defun clibpc-parse-directory (dir &optional non-recursively)
"Extract function name and declaration position using
`clibpc-regexp-list' in DIR. If with prefix arg, the header file
just in this DIR will be read."
(interactive "DInclude path: \nP")
(mapc
(lambda (f)
(if (and (file-directory-p f) (not non-recursively))
(clibpc-parse-directory f)
(if (and (file-regular-p f)
(string-match clibpc-header-file-regexp f))
(clibpc-parse-header f (called-interactively-p)))))
(directory-files dir t "[^.]$")))
(defun clibpc-symbol-document (symbol)
(or (get symbol 'document)
(with-temp-buffer
(let ((file (symbol-value symbol)))
(insert-file-contents (car file))
(goto-char (cdr file))
(put symbol 'document
(replace-regexp-in-string
"[ \t\n]\\{2,\\}" " "
(buffer-substring (point)
(if (looking-at "^\\s-*#define")
(line-end-position)
(progn (re-search-forward ")") (point))))))))))
(defun clibpc-eldoc-function ()
(let (string symbol done)
(save-excursion
(while (not (or done symbol))
(if (and (setq string (thing-at-point 'symbol))
(intern-soft string clibpc-obarray))
(setq symbol (intern-soft string clibpc-obarray))
(setq done (null (re-search-backward "\\>\\s-*(" (line-beginning-position) t))))))
(when (and symbol (clibpc-symbol-document symbol))
(message "[%s] %s"
(file-name-nondirectory (car (symbol-value symbol)))
(clibpc-symbol-document symbol)))))
(defun clibpc-describe-function (func)
(interactive
(let ((sym (thing-at-point 'symbol)))
(list (completing-read
(if (and sym (intern-soft sym clibpc-obarray))
(format "Describe function(default %s): " sym)
"Describe function: ")
clibpc-obarray nil t nil nil sym))))
(let ((symbol (intern-soft func clibpc-obarray))
(inhibit-read-only t))
(when symbol
(save-excursion
(with-output-to-temp-buffer (help-buffer)
(require 'button)
(princ func)
(princ " is declared in `")
(princ (file-name-nondirectory (car (symbol-value symbol))))
(princ "'\n\n")
(princ (clibpc-symbol-document symbol))
(princ "\n\n")
(with-current-buffer standard-output
(goto-char (point-min))
(make-text-button (progn (re-search-forward "`") (point))
(1- (line-end-position))
'file (symbol-value symbol)
'action (lambda (but)
(let ((file (button-get but 'file)))
(switch-to-buffer (find-file-noselect (car file)))
(goto-char (cdr file)))))))))))
(defun clibpc-complete-function ()
(interactive)
(let* ((end (point))
(beg (save-excursion
(with-syntax-table lisp-mode-syntax-table
(backward-sexp 1)
(while (= (char-syntax (following-char)) ?\')
(forward-char 1))
(point))))
(minibuffer-completion-table clibpc-obarray)
(minibuffer-completion-predicate 'identity)
(PC-not-minibuffer t))
(if (equal last-command 'PC-lisp-complete-symbol)
(PC-do-completion nil beg PC-lisp-complete-end t)
(if PC-lisp-complete-end
(move-marker PC-lisp-complete-end end)
(setq PC-lisp-complete-end (copy-marker end t)))
(PC-do-completion nil beg end t))))
(defun clibpc-save-symbols (file)
(interactive
(list (read-file-name "Save to: "
(file-name-directory clibpc-cache-file)
(file-name-nondirectory clibpc-cache-file))))
(with-temp-buffer
(insert "(")
(mapatoms (lambda (s)
(or (get s 'no-save)
(insert (format "(%S . %S)\n"
s (symbol-value s)))))
clibpc-obarray)
(insert ")")
(write-region (point-min) (point-max) file nil 'nomessage)))
(defun clibpc-load-symbols (file)
(interactive
(list (read-file-name "Save to: "
(file-name-directory clibpc-cache-file)
(file-name-nondirectory clibpc-cache-file) t)))
(with-temp-buffer
(insert-file-contents file)
(goto-char (point-min))
(dolist (sym (read (current-buffer)))
(set (intern (symbol-name (car sym)) clibpc-obarray) (cdr sym)))))
(defun clibpc-rebuild-obarray ()
(interactive)
(setq clibpc-obarray (make-vector 1511 0))
(message "Wait while building symbol table...")
(dolist (dir clibpc-include-path)
(and (file-exists-p dir) (clibpc-parse-directory dir)))
(message "done!")
(clibpc-save-symbols clibpc-cache-file))
(unless clibpc-obarray
(if (and clibpc-cache-file (file-exists-p clibpc-cache-file))
(progn
(setq clibpc-obarray (make-vector 1511 0))
(clibpc-load-symbols clibpc-cache-file))
(clibpc-rebuild-obarray)))