Merge pull request #1 from jmaschme/emacs
First cut at emacs auto-complete support
This commit is contained in:
commit
e858ae2268
|
@ -1 +1,16 @@
|
||||||
#EMACS Integration
|
#EMACS Integration
|
||||||
|
|
||||||
|
This is a first cut at emacs support. It is far from complete.
|
||||||
|
|
||||||
|
##Requirements
|
||||||
|
* You must have the [auto-complete](https://github.com/auto-complete/auto-complete) package
|
||||||
|
* This integration will not automatically start dcd-server, so you'll have to do hat yourself.
|
||||||
|
* Make sure dcd-client is in your path
|
||||||
|
* Add the following to your .emacs
|
||||||
|
|
||||||
|
(require 'ac-dcd)
|
||||||
|
(add-to-list 'ac-modes 'd-mode)
|
||||||
|
(defun ac-d-mode-setup ()
|
||||||
|
(setq ac-sources (append '(ac-source-dcd) ac-sources))
|
||||||
|
(global-auto-complete-mode t))
|
||||||
|
(add-hook 'd-mode-hook 'ac-d-mode-setup)
|
||||||
|
|
|
@ -0,0 +1,229 @@
|
||||||
|
;;; ac-dcd.el --- Auto Completion source for dcd for GNU Emacs
|
||||||
|
|
||||||
|
;; 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
;;
|
||||||
|
;; Auto Completion source for dcd. This code was modified from ac-dscanner.el,
|
||||||
|
;; which originally came from auto-complete-clang-async.el
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(provide 'ac-dcd)
|
||||||
|
(require 'auto-complete)
|
||||||
|
|
||||||
|
(defcustom ac-dcd-executable
|
||||||
|
(executable-find "dcd-client")
|
||||||
|
"*Location of dcd-client executable"
|
||||||
|
:group 'auto-complete
|
||||||
|
:type 'file)
|
||||||
|
|
||||||
|
;;; Extra compilation flags to pass to dcd.
|
||||||
|
(defcustom ac-dcd-flags nil
|
||||||
|
"Extra flags to pass to the Dcd executable.
|
||||||
|
This variable will typically contain include paths, e.g., ( \"-I~/MyProject\", \"-I.\" )."
|
||||||
|
:group 'auto-complete
|
||||||
|
:type '(repeat (string :tag "Argument" "")))
|
||||||
|
|
||||||
|
(defconst ac-dcd-completion-pattern
|
||||||
|
"^\\(%s[^\s\n]*\\)[ \t]+[cisuvmkfgepM]")
|
||||||
|
|
||||||
|
(defconst ac-dcd-error-buffer-name "*dcd error*")
|
||||||
|
|
||||||
|
(defun ac-dcd-parse-output (prefix)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(let ((pattern (format ac-dcd-completion-pattern
|
||||||
|
(regexp-quote prefix)))
|
||||||
|
lines match detailed_info
|
||||||
|
(prev-match ""))
|
||||||
|
(while (re-search-forward pattern nil t)
|
||||||
|
(setq match (match-string-no-properties 1))
|
||||||
|
(unless (string= "Pattern" match)
|
||||||
|
(setq detailed_info (match-string-no-properties 2))
|
||||||
|
(if (string= match prev-match)
|
||||||
|
(progn
|
||||||
|
(when detailed_info
|
||||||
|
(setq match (propertize match
|
||||||
|
'ac-dcd-help
|
||||||
|
(concat
|
||||||
|
(get-text-property 0 'ac-dcd-help (car lines))
|
||||||
|
"\n"
|
||||||
|
detailed_info)))
|
||||||
|
(setf (car lines) match)))
|
||||||
|
(setq prev-match match)
|
||||||
|
(when detailed_info
|
||||||
|
(setq match (propertize match 'ac-dcd-help detailed_info)))
|
||||||
|
(push match lines))))
|
||||||
|
lines))
|
||||||
|
|
||||||
|
(defun ac-dcd-handle-error (res args)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(let* ((buf (get-buffer-create ac-dcd-error-buffer-name))
|
||||||
|
(cmd (concat ac-dcd-executable " " (mapconcat 'identity args " ")))
|
||||||
|
(pattern (format ac-dcd-completion-pattern ""))
|
||||||
|
(err (if (re-search-forward pattern nil t)
|
||||||
|
(buffer-substring-no-properties (point-min)
|
||||||
|
(1- (match-beginning 0)))
|
||||||
|
;; Warn the user more agressively if no match was found.
|
||||||
|
(message "dcd-client failed with error %d:\n%s" res cmd)
|
||||||
|
(buffer-string))))
|
||||||
|
(with-current-buffer buf
|
||||||
|
(let ((inhibit-read-only t))
|
||||||
|
(erase-buffer)
|
||||||
|
(insert (current-time-string)
|
||||||
|
(format "\ndcd-client failed with error %d:\n" res)
|
||||||
|
cmd "\n\n")
|
||||||
|
(insert err)
|
||||||
|
(setq buffer-read-only t)
|
||||||
|
(goto-char (point-min))))))
|
||||||
|
|
||||||
|
(defun ac-dcd-call-process (prefix &rest args)
|
||||||
|
(let ((buf (get-buffer-create "*dcd-output*"))
|
||||||
|
res)
|
||||||
|
(with-current-buffer buf (erase-buffer))
|
||||||
|
(setq res (apply 'call-process-region (point-min) (point-max)
|
||||||
|
ac-dcd-executable nil buf nil args))
|
||||||
|
(with-current-buffer buf
|
||||||
|
(unless (eq 0 res)
|
||||||
|
(ac-dcd-handle-error res args))
|
||||||
|
;; Still try to get any useful input.
|
||||||
|
(ac-dcd-parse-output prefix))))
|
||||||
|
|
||||||
|
(defsubst ac-dcd-build-complete-args (pos)
|
||||||
|
(append '()
|
||||||
|
'("-c")
|
||||||
|
(list (format "%s" pos))
|
||||||
|
ac-dcd-flags))
|
||||||
|
|
||||||
|
|
||||||
|
(defsubst ac-dcd-clean-document (s)
|
||||||
|
(when s
|
||||||
|
(setq s (replace-regexp-in-string "<#\\|#>\\|\\[#" "" s))
|
||||||
|
(setq s (replace-regexp-in-string "#\\]" " " s)))
|
||||||
|
s)
|
||||||
|
|
||||||
|
(defun ac-dcd-document (item)
|
||||||
|
(if (stringp item)
|
||||||
|
(let (s)
|
||||||
|
(setq s (get-text-property 0 'ac-dcd-help item))
|
||||||
|
(ac-dcd-clean-document s))))
|
||||||
|
|
||||||
|
(defsubst ac-in-string/comment ()
|
||||||
|
"Return non-nil if point is in a literal (a comment or string)."
|
||||||
|
(nth 8 (syntax-ppss)))
|
||||||
|
|
||||||
|
(defun ac-dcd-candidate ()
|
||||||
|
(unless (ac-in-string/comment)
|
||||||
|
(save-restriction
|
||||||
|
(widen)
|
||||||
|
(apply 'ac-dcd-call-process
|
||||||
|
ac-prefix
|
||||||
|
(ac-dcd-build-complete-args (point))))))
|
||||||
|
|
||||||
|
(defvar ac-template-start-point nil)
|
||||||
|
(defvar ac-template-candidates (list "ok" "no" "yes:)"))
|
||||||
|
|
||||||
|
(defun ac-dcd-action ()
|
||||||
|
(interactive)
|
||||||
|
(let ((help (ac-dcd-clean-document (get-text-property 0 'ac-dcd-help (cdr ac-last-completion))))
|
||||||
|
(raw-help (get-text-property 0 'ac-dcd-help (cdr ac-last-completion)))
|
||||||
|
(candidates (list)) ss fn args (ret-t "") ret-f)
|
||||||
|
(setq ss (split-string raw-help "\n"))
|
||||||
|
(dolist (s ss)
|
||||||
|
(when (string-match "\\[#\\(.*\\)#\\]" s)
|
||||||
|
(setq ret-t (match-string 1 s)))
|
||||||
|
(setq s (replace-regexp-in-string "\\[#.*?#\\]" "" s)))
|
||||||
|
(cond (candidates
|
||||||
|
(setq candidates (delete-dups candidates))
|
||||||
|
(setq candidates (nreverse candidates))
|
||||||
|
(setq ac-template-candidates candidates)
|
||||||
|
(setq ac-template-start-point (point))
|
||||||
|
(ac-complete-template)
|
||||||
|
(unless (cdr candidates) ;; unless length > 1
|
||||||
|
(message (replace-regexp-in-string "\n" " ; " help))))
|
||||||
|
(t
|
||||||
|
(message (replace-regexp-in-string "\n" " ; " help))))))
|
||||||
|
|
||||||
|
(defun ac-dcd-prefix ()
|
||||||
|
(or (ac-prefix-symbol)
|
||||||
|
(let ((c (char-before)))
|
||||||
|
(when (or (eq ?\. c)
|
||||||
|
(and (eq ?> c)
|
||||||
|
(eq ?- (char-before (1- (point)))))
|
||||||
|
(and (eq ?: c)
|
||||||
|
(eq ?: (char-before (1- (point))))))
|
||||||
|
(point)))))
|
||||||
|
|
||||||
|
(ac-define-source dcd
|
||||||
|
'((candidates . ac-dcd-candidate)
|
||||||
|
(prefix . ac-dcd-prefix)
|
||||||
|
(requires . 0)
|
||||||
|
(document . ac-dcd-document)
|
||||||
|
(action . ac-dcd-action)
|
||||||
|
(cache)))
|
||||||
|
|
||||||
|
(defun ac-dcd-same-count-in-string (c1 c2 s)
|
||||||
|
(let ((count 0) (cur 0) (end (length s)) c)
|
||||||
|
(while (< cur end)
|
||||||
|
(setq c (aref s cur))
|
||||||
|
(cond ((eq c1 c)
|
||||||
|
(setq count (1+ count)))
|
||||||
|
((eq c2 c)
|
||||||
|
(setq count (1- count))))
|
||||||
|
(setq cur (1+ cur)))
|
||||||
|
(= count 0)))
|
||||||
|
|
||||||
|
(defun ac-dcd-split-args (s)
|
||||||
|
(let ((sl (split-string s ", *")))
|
||||||
|
(cond ((string-match "<\\|(" s)
|
||||||
|
(let ((res (list)) (pre "") subs)
|
||||||
|
(while sl
|
||||||
|
(setq subs (pop sl))
|
||||||
|
(unless (string= pre "")
|
||||||
|
(setq subs (concat pre ", " subs))
|
||||||
|
(setq pre ""))
|
||||||
|
(cond ((and (ac-dcd-same-count-in-string ?\< ?\> subs)
|
||||||
|
(ac-dcd-same-count-in-string ?\( ?\) subs))
|
||||||
|
(push subs res))
|
||||||
|
(t
|
||||||
|
(setq pre subs))))
|
||||||
|
(nreverse res)))
|
||||||
|
(t
|
||||||
|
sl))))
|
||||||
|
|
||||||
|
(defun ac-template-candidate ()
|
||||||
|
ac-template-candidates)
|
||||||
|
|
||||||
|
(defun ac-template-action ()
|
||||||
|
(interactive)
|
||||||
|
(unless (null ac-template-start-point)
|
||||||
|
(let ((pos (point)) sl (snp "")
|
||||||
|
(s (get-text-property 0 'raw-args (cdr ac-last-completion)))))))
|
||||||
|
|
||||||
|
(defun ac-template-prefix ()
|
||||||
|
ac-template-start-point)
|
||||||
|
|
||||||
|
|
||||||
|
;; this source shall only be used internally.
|
||||||
|
(ac-define-source template
|
||||||
|
'((candidates . ac-template-candidate)
|
||||||
|
(prefix . ac-template-prefix)
|
||||||
|
(requires . 0)
|
||||||
|
(action . ac-template-action)
|
||||||
|
(document . ac-dcd-document)
|
||||||
|
(cache)
|
||||||
|
(symbol . "t")))
|
||||||
|
|
||||||
|
;;; auto-complete-dcd.el ends here
|
Loading…
Reference in New Issue