From 988cf9d8c21499ebdec0eb6d15ba4d92d5a2830d Mon Sep 17 00:00:00 2001 From: Dmitry Gutov Date: Wed, 10 Apr 2013 04:34:00 +0400 Subject: [PATCH] Support c++-mode in company-clang; templatify calls in C and C++ Close #7 * company-clang--completion-pattern: Ignore (Hidden) entries. * company-clang--parse-output: Add function arguments to the candidate text, * unless we're dealing with ObjC (no problem with overloads there). * company-clang: Templatify function call in C in C++, same as `company-eclim'. * company-eclim--templatify: Move to company-template.el, rename to `company-template-c-like-templatify', don't strip the argument types from fields. Detecting where the type ends and the arg name begins is hard for C and C++, because there may be no argument name. And showing types is useful anyway. * company-template-add-field: Change the third argument from string to number. * company-template-move-to-first: When no fields, jump to the end. --- NEWS.md | 6 +++++ company-clang.el | 61 ++++++++++++++++++++++++++------------------- company-eclim.el | 15 +---------- company-template.el | 33 ++++++++++++++++-------- 4 files changed, 65 insertions(+), 50 deletions(-) diff --git a/NEWS.md b/NEWS.md index 9a8fc7d61..a788f5987 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,11 @@ # History of user-visible changes +## Next + +* `company-eclim` and `company-clang` do not strip argument types from fields. +* `company-clang` expand function calls into templates for all three modes now. +* `company-clang` supports `c++-mode` by default. + ## 2013-04-01 (0.6.7) * Two `company-elisp` tweaks. diff --git a/company-clang.el b/company-clang.el index 178170fcd..8b0770d03 100644 --- a/company-clang.el +++ b/company-clang.el @@ -55,7 +55,7 @@ Prefix files (-include ...) can be selected with "A function to determine the prefix file for the current buffer." :type '(function :tag "Guesser function" nil)) -(defvar company-clang-modes '(c-mode objc-mode) +(defvar company-clang-modes '(c-mode c++-mode objc-mode) "Major modes which clang may complete.") ;; prefix ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -100,15 +100,16 @@ Prefix files (-include ...) can be selected with ;; parsing ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; TODO: How to handle OVERLOAD and Pattern? +;; TODO: Handle Pattern (syntactic hints would be neat). +;; Do we ever see OVERLOAD (or OVERRIDE)? (defconst company-clang--completion-pattern - "^COMPLETION: \\_<\\(%s[a-zA-Z0-9_:]*\\)\\(?: : \\(.*\\)$\\)?") + "^COMPLETION: \\_<\\(%s[a-zA-Z0-9_:]*\\)\\(?: : \\(.*\\)$\\)?$") (defconst company-clang--error-buffer-name "*clang error*") (defvar company-clang--meta-cache nil) -(defun company-clang--parse-output (prefix) +(defun company-clang--parse-output (prefix objc) (goto-char (point-min)) (let ((pattern (format company-clang--completion-pattern (regexp-quote prefix))) @@ -117,13 +118,22 @@ Prefix files (-include ...) can be selected with (setq company-clang--meta-cache (make-hash-table :test 'equal)) (while (re-search-forward pattern nil t) (setq match (match-string-no-properties 1)) - (let ((meta (match-string-no-properties 2))) - (when (and meta (not (string= match meta))) - (puthash match meta company-clang--meta-cache))) (unless (equal match "Pattern") + (let ((meta (match-string-no-properties 2))) + (when (and meta (not (string= match meta))) + (setq meta (company-clang--strip-formatting meta)) + (when (and (not objc) (string-match "\\((.*)\\)" meta)) + (setq match (concat match (match-string 1 meta)))) + (puthash match meta company-clang--meta-cache))) (push match lines))) lines)) +(defun company-clang--strip-formatting (text) + (replace-regexp-in-string + "#]" " " + (replace-regexp-in-string "[<{[]#\\|#[>}]" "" text t) + t)) + (defun company-clang--handle-error (res args) (goto-char (point-min)) (let* ((buf (get-buffer-create company-clang--error-buffer-name)) @@ -147,12 +157,13 @@ Prefix files (-include ...) can be selected with (goto-char (point-min)))))) (defun company-clang--call-process (prefix &rest args) - (with-temp-buffer - (let ((res (apply 'call-process company-clang-executable nil t nil args))) - (unless (eq 0 res) - (company-clang--handle-error res args)) - ;; Still try to get any useful input. - (company-clang--parse-output prefix)))) + (let ((objc (derived-mode-p 'objc-mode))) + (with-temp-buffer + (let ((res (apply 'call-process company-clang-executable nil t nil args))) + (unless (eq 0 res) + (company-clang--handle-error res args)) + ;; Still try to get any useful input. + (company-clang--parse-output prefix objc))))) (defsubst company-clang--build-location (pos) (save-excursion @@ -207,8 +218,9 @@ Prefix files (-include ...) can be selected with (let* ((name (format "arg%d" cnt)) (len (length name))) (incf end len) - (company-template-add-field templ (match-end 0) name) - (goto-char (+ (match-end 0) len)) + (let ((pt (point))) + (insert name) + (company-template-add-field templ pt (point))) (when (< (point) end) (insert " ") (incf end)) @@ -240,18 +252,15 @@ Completions only work correctly when the buffer has been saved. (not (company-in-string-or-comment)) (or (company-grab-symbol) 'stop))) (candidates (company-clang--candidates arg)) - (meta (let ((meta (gethash arg company-clang--meta-cache))) - (when meta - (replace-regexp-in-string - "#]" " " - (replace-regexp-in-string "[<{[]#\\|#[>}]" "" meta t) - t)))) - (crop (and (derived-mode-p 'objc-mode) - (string-match ":" arg) + (meta (gethash arg company-clang--meta-cache)) + (crop (and (string-match ":\\|(" arg) (substring arg 0 (match-beginning 0)))) - (post-completion (and (derived-mode-p 'objc-mode) - (string-match ":" arg) - (company-clang-objc-templatify arg))))) + (post-completion (cond + ((derived-mode-p 'objc-mode) + (string-match ":" arg) + (company-clang-objc-templatify arg)) + (t + (company-template-c-like-templatify arg)))))) (provide 'company-clang) ;;; company-clang.el ends here diff --git a/company-eclim.el b/company-eclim.el index eb9518709..864f550ed 100644 --- a/company-eclim.el +++ b/company-eclim.el @@ -142,19 +142,6 @@ eclim can only complete correctly when the buffer has been saved." (defun company-eclim--meta (candidate) (gethash candidate company-eclim--doc)) -(defun company-eclim--templatify (call) - (let* ((end (point)) - (beg (- (point) (length call))) - (templ (company-template-declare-template beg end))) - (save-excursion - (goto-char beg) - (while (re-search-forward "\\([(,] ?\\)\\([^ ]+ \\)\\([^ ,)]*\\)" end t) - (let ((name (match-string 3))) - (replace-match "\\1" t) - (decf end (length (match-string 2))) - (company-template-add-field templ (point) name)))) - (company-template-move-to-first templ))) - (defun company-eclim (command &optional arg &rest ignored) "`company-mode' completion back-end for Eclim. Eclim provides access to Eclipse Java IDE features for other editors. @@ -179,7 +166,7 @@ Completions only work correctly when the buffer has been saved. (crop (when (string-match "(" arg) (substring arg 0 (match-beginning 0)))) (post-completion (when (string-match "([^)]" arg) - (company-eclim--templatify arg))))) + (company-template-c-like-templatify arg))))) (provide 'company-eclim) ;;; company-eclim.el ends here diff --git a/company-template.el b/company-template.el index ffceda16b..fd4447fb1 100644 --- a/company-template.el +++ b/company-template.el @@ -47,9 +47,8 @@ (defun company-template-move-to-first (templ) (interactive) - (let ((fields (overlay-get templ 'company-template-fields))) - (push-mark) - (goto-char (apply 'min (mapcar 'overlay-start fields))))) + (goto-char (overlay-start templ)) + (company-template-forward-field)) (defun company-template-forward-field () (interactive) @@ -92,15 +91,13 @@ (delq templ company-template--buffer-templates)) (delete-overlay templ)) -(defun company-template-add-field (templ pos text) +(defun company-template-add-field (templ beg end) + "Add a field to template TEMPL, from BEG to END." (assert templ) (save-excursion - (save-excursion - (goto-char pos) - (insert text) - (when (> (point) (overlay-end templ)) - (move-overlay templ (overlay-start templ) (point)))) - (let ((ov (make-overlay pos (+ pos (length text)))) + (when (> end (overlay-end templ)) + (move-overlay templ (overlay-start templ) end)) + (let ((ov (make-overlay beg end)) (siblings (overlay-get templ 'company-template-fields))) ;; (overlay-put ov 'evaporate t) (overlay-put ov 'intangible t) @@ -140,5 +137,21 @@ (unless company-template--buffer-templates (remove-hook 'post-command-hook 'company-template-post-command t))) +;; common ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun company-template-c-like-templatify (call) + (let* ((end (point)) + (beg (- (point) (length call)))) + (goto-char beg) + (when (search-forward "(" end 'move) + (if (eq (char-after) ?\)) + (forward-char 1) + (let ((templ (company-template-declare-template beg end))) + (while (re-search-forward (concat " *\\([^,)]*\\)[,)]") end t) + (company-template-add-field templ + (match-beginning 1) + (match-end 1))) + (company-template-move-to-first templ)))))) + (provide 'company-template) ;;; company-template.el ends here -- 2.39.2