]> code.delx.au - gnu-emacs-elpa/blob - company-semantic.el
* company-safe-substring: consider composition when to <= str's width
[gnu-emacs-elpa] / company-semantic.el
1 ;;; company-semantic.el --- A company-mode back-end using CEDET Semantic
2
3 ;; Copyright (C) 2009-2011 Free Software Foundation, Inc.
4
5 ;; Author: Nikolaj Schumacher
6
7 ;; This file is part of GNU Emacs.
8
9 ;; GNU Emacs is free software: you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation, either version 3 of the License, or
12 ;; (at your option) any later version.
13
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
21
22
23 ;;; Commentary:
24 ;;
25
26 ;;; Code:
27
28 (require 'company)
29 (or (require 'semantic-analyze nil t)
30 (require 'semantic/analyze))
31 (eval-when-compile (require 'cl))
32
33 (defcustom company-semantic-metadata-function 'company-semantic-summary-and-doc
34 "The function turning a semantic tag into doc information."
35 :group 'company
36 :type 'function)
37
38 (defvar company-semantic-modes '(c-mode c++-mode jde-mode java-mode))
39
40 (defvar company-semantic--current-tags nil
41 "Tags for the current context.")
42
43 (defun company-semantic-doc-or-summary (tag)
44 (or (semantic-documentation-for-tag tag)
45 (and (require 'semantic-idle nil t)
46 (require 'semantic/idle nil t)
47 (funcall semantic-idle-summary-function tag nil t))))
48
49 (defun company-semantic-summary-and-doc (tag)
50 (let ((doc (semantic-documentation-for-tag tag))
51 (summary (funcall semantic-idle-summary-function tag nil t)))
52 (and (stringp doc)
53 (string-match "\n*\\(.*\\)$" doc)
54 (setq doc (match-string 1 doc)))
55 (concat (funcall semantic-idle-summary-function tag nil t)
56 (when doc
57 (if (< (+ (length doc) (length summary) 4) (window-width))
58 " -- "
59 "\n"))
60 doc)))
61
62 (defun company-semantic-doc-buffer (tag)
63 (let ((doc (semantic-documentation-for-tag tag)))
64 (when doc
65 (with-current-buffer (company-doc-buffer)
66 (insert (funcall semantic-idle-summary-function tag nil t)
67 "\n"
68 doc)
69 (current-buffer)))))
70
71 (defsubst company-semantic-completions (prefix)
72 (ignore-errors
73 (let ((completion-ignore-case nil)
74 (context (semantic-analyze-current-context)))
75 (setq company-semantic--current-tags
76 (semantic-analyze-possible-completions context))
77 (all-completions prefix company-semantic--current-tags))))
78
79 (defun company-semantic-completions-raw (prefix)
80 (setq company-semantic--current-tags nil)
81 (dolist (tag (semantic-analyze-find-tags-by-prefix prefix))
82 (unless (eq (semantic-tag-class tag) 'include)
83 (push tag company-semantic--current-tags)))
84 (delete "" (mapcar 'semantic-tag-name company-semantic--current-tags)))
85
86 (defun company-semantic--pre-prefix-length (prefix-length)
87 "Sum up the length of all chained symbols before POS.
88 Symbols are chained by \".\" or \"->\"."
89 (save-excursion
90 (let ((pos (point)))
91 (goto-char (- (point) prefix-length))
92 (while (looking-back "->\\|\\.")
93 (goto-char (match-beginning 0))
94 (skip-syntax-backward "w_"))
95 (- pos (point)))))
96
97 (defun company-semantic--grab ()
98 "Grab the semantic prefix, but return everything before -> or . as length."
99 (let ((symbol (company-grab-symbol)))
100 (when symbol
101 (cons symbol (company-semantic--pre-prefix-length (length symbol))))))
102
103 ;;;###autoload
104 (defun company-semantic (command &optional arg &rest ignored)
105 "A `company-mode' completion back-end using CEDET Semantic."
106 (interactive (list 'interactive))
107 (case command
108 (interactive (company-begin-backend 'company-semantic))
109 (prefix (and (memq major-mode company-semantic-modes)
110 (semantic-active-p)
111 (not (company-in-string-or-comment))
112 (or (company-semantic--grab) 'stop)))
113 (candidates (if (and (equal arg "")
114 (not (looking-back "->\\|\\.")))
115 (company-semantic-completions-raw arg)
116 (company-semantic-completions arg)))
117 (meta (funcall company-semantic-metadata-function
118 (assoc arg company-semantic--current-tags)))
119 (doc-buffer (company-semantic-doc-buffer
120 (assoc arg company-semantic--current-tags)))
121 ;; Because "" is an empty context and doesn't return local variables.
122 (no-cache (equal arg ""))
123 (location (let ((tag (assoc arg company-semantic--current-tags)))
124 (when (buffer-live-p (semantic-tag-buffer tag))
125 (cons (semantic-tag-buffer tag)
126 (semantic-tag-start tag)))))))
127
128 (provide 'company-semantic)
129 ;;; company-semantic.el ends here