]> code.delx.au - gnu-emacs-elpa/blobdiff - company-cmake.el
Add support for company-face
[gnu-emacs-elpa] / company-cmake.el
index 0c96eb676a70e508d85b1472a1f8dd2b91d7df08..010df32e43d25f4193bd66e12a6b11473a29895e 100644 (file)
@@ -1,24 +1,22 @@
-;;; company-cmake.el --- company-mode completion back-end for CMake
+;;; company-cmake.el --- company-mode completion backend for CMake
 
-;; Copyright (C) 2013  Chen Bin
+;; Copyright (C) 2013-2014  Free Software Foundation, Inc.
 
 ;; Author: Chen Bin <chenbin DOT sh AT gmail>
-;; Version: 0.1
+;; Version: 0.2
 
-;; This file is NOT part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
+;; 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.
 
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 ;;
 ;; commands used by CMake.  And their descriptions.
 
 ;;; Code:
+
 (require 'company)
+(require 'cl-lib)
 
 (defgroup company-cmake nil
-  "Completion back-end for CMake."
+  "Completion backend for CMake."
   :group 'company)
 
 (defcustom company-cmake-executable
 They affect which types of symbols we get completion candidates for.")
 
 (defvar company-cmake--completion-pattern
-  "^\\(%s[a-zA-Z0-9_]%s\\)$"
+  "^\\(%s[a-zA-Z0-9_<>]%s\\)$"
   "Regexp to match the candidates.")
 
 (defvar company-cmake-modes '(cmake-mode)
   "Major modes in which cmake may complete.")
 
+(defvar company-cmake--candidates-cache nil
+  "Cache for the raw candidates.")
+
 (defvar company-cmake--meta-command-cache nil
   "Cache for command arguments to retrieve descriptions for the candidates.")
 
-(defun company-cmake--parse-output (prefix cmd)
-  "Analyze the temp buffer and collect lines."
-  (goto-char (point-min))
-  (let ((pattern (format company-cmake--completion-pattern
+(defun company-cmake--replace-tags (rlt)
+  (setq rlt (replace-regexp-in-string
+             "\\(.*?\\(IS_GNU\\)?\\)<LANG>\\(.*\\)"
+             (lambda (_match)
+               (mapconcat 'identity
+                          (if (match-beginning 2)
+                              '("\\1CXX\\3" "\\1C\\3" "\\1G77\\3")
+                            '("\\1CXX\\3" "\\1C\\3" "\\1Fortran\\3"))
+                          "\n"))
+             rlt t))
+  (setq rlt (replace-regexp-in-string
+             "\\(.*\\)<CONFIG>\\(.*\\)"
+             (mapconcat 'identity '("\\1DEBUG\\2" "\\1RELEASE\\2"
+                                    "\\1RELWITHDEBINFO\\2" "\\1MINSIZEREL\\2")
+                        "\n")
+             rlt))
+  rlt)
+
+(defun company-cmake--fill-candidates-cache (arg)
+  "Fill candidates cache if needed."
+  (let (rlt)
+    (unless company-cmake--candidates-cache
+      (setq company-cmake--candidates-cache (make-hash-table :test 'equal)))
+
+    ;; If hash is empty, fill it.
+    (unless (gethash arg company-cmake--candidates-cache)
+      (with-temp-buffer
+        (let ((res (call-process company-cmake-executable nil t nil arg)))
+          (unless (zerop res)
+            (message "cmake executable exited with error=%d" res)))
+        (setq rlt (buffer-string)))
+      (setq rlt (company-cmake--replace-tags rlt))
+      (puthash arg rlt company-cmake--candidates-cache))
+    ))
+
+(defun company-cmake--parse (prefix content cmd)
+  (let ((start 0)
+        (pattern (format company-cmake--completion-pattern
                          (regexp-quote prefix)
                          (if (zerop (length prefix)) "+" "*")))
-        (case-fold-search nil)
-        lines match)
-    (while (re-search-forward pattern nil t)
-      (setq match (match-string-no-properties 1))
-      (puthash match cmd company-cmake--meta-command-cache)
-      (push match lines))
-    lines))
+        (lines (split-string content "\n"))
+        match
+        rlt)
+    (dolist (line lines)
+      (when (string-match pattern line)
+        (let ((match (match-string 1 line)))
+          (when match
+            (puthash match cmd company-cmake--meta-command-cache)
+            (push match rlt)))))
+    rlt))
 
 (defun company-cmake--candidates (prefix)
-  (let ((res 0)
-        results
-        cmd)
-    (setq company-cmake--meta-command-cache (make-hash-table :test 'equal))
+  (let (results
+        cmd-opts
+        str)
+
+    (unless company-cmake--meta-command-cache
+      (setq company-cmake--meta-command-cache (make-hash-table :test 'equal)))
+
     (dolist (arg company-cmake-executable-arguments)
-      (with-temp-buffer
-        (setq res (call-process company-cmake-executable nil t nil arg))
-        (unless (eq 0 res)
-          (message "cmake executable exited with error=%d" res))
-        (setq cmd (replace-regexp-in-string "-list$" "" arg) )
-        (setq results (nconc results (company-cmake--parse-output prefix cmd)))))
+      (company-cmake--fill-candidates-cache arg)
+      (setq cmd-opts (replace-regexp-in-string "-list$" "" arg) )
+
+      (setq str (gethash arg company-cmake--candidates-cache))
+      (when str
+        (setq results (nconc results
+                             (company-cmake--parse prefix str cmd-opts)))))
     results))
 
-(defun company-cmake--meta (prefix)
-  (let ((cmd-opts (gethash prefix company-cmake--meta-command-cache))
+(defun company-cmake--unexpand-candidate (candidate)
+  (cond
+   ((string-match "^CMAKE_\\(C\\|CXX\\|Fortran\\)\\(_.*\\)$" candidate)
+    (setq candidate (concat "CMAKE_<LANG>" (match-string 2 candidate))))
+
+   ;; C flags
+   ((string-match "^\\(.*_\\)IS_GNU\\(C\\|CXX\\|G77\\)$" candidate)
+    (setq candidate (concat (match-string 1 candidate) "IS_GNU<LANG>")))
+
+   ;; C flags
+   ((string-match "^\\(.*_\\)OVERRIDE_\\(C\\|CXX\\|Fortran\\)$" candidate)
+    (setq candidate (concat (match-string 1 candidate) "OVERRIDE_<LANG>")))
+
+   ((string-match "^\\(.*\\)\\(_DEBUG\\|_RELEASE\\|_RELWITHDEBINFO\\|_MINSIZEREL\\)\\(.*\\)$" candidate)
+    (setq candidate (concat (match-string 1 candidate)
+                            "_<CONFIG>"
+                            (match-string 3 candidate)))))
+  candidate)
+
+(defun company-cmake--meta (candidate)
+  (let ((cmd-opts (gethash candidate company-cmake--meta-command-cache))
         result)
+    (setq candidate (company-cmake--unexpand-candidate candidate))
+
+    ;; Don't cache the documentation of every candidate (command)
+    ;; Cache in this case will cost too much memory.
     (with-temp-buffer
-      (call-process company-cmake-executable nil t nil cmd-opts prefix)
+      (call-process company-cmake-executable nil t nil cmd-opts candidate)
       ;; Go to the third line, trim it and return the result.
       ;; Tested with cmake 2.8.9.
       (goto-char (point-min))
@@ -96,10 +163,12 @@ They affect which types of symbols we get completion candidates for.")
       (setq result (replace-regexp-in-string "^[ \t\n\r]+" "" result))
       result)))
 
-(defun company-cmake--doc-buffer (prefix)
-  (let ((cmd-opts (gethash prefix company-cmake--meta-command-cache)))
+(defun company-cmake--doc-buffer (candidate)
+  (let ((cmd-opts (gethash candidate company-cmake--meta-command-cache)))
+
+    (setq candidate (company-cmake--unexpand-candidate candidate))
     (with-temp-buffer
-      (call-process company-cmake-executable nil t nil cmd-opts prefix)
+      (call-process company-cmake-executable nil t nil cmd-opts candidate)
       ;; Go to the third line, trim it and return the doc buffer.
       ;; Tested with cmake 2.8.9.
       (goto-char (point-min))
@@ -109,10 +178,10 @@ They affect which types of symbols we get completion candidates for.")
                                        (point-max))))))
 
 (defun company-cmake (command &optional arg &rest ignored)
-  "`company-mode' completion back-end for CMake.
+  "`company-mode' completion backend for CMake.
 CMake is a cross-platform, open-source make system."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-cmake))
     (init (when (memq major-mode company-cmake-modes)
             (unless company-cmake-executable