X-Git-Url: https://code.delx.au/gnu-emacs-elpa/blobdiff_plain/8f2c03248b5517d82588a05f357805cbb0f384ed..e52579348d8529b0cff08a1f0a676cb0cc6f61c3:/company-cmake.el diff --git a/company-cmake.el b/company-cmake.el index a466f60b7..010df32e4 100644 --- a/company-cmake.el +++ b/company-cmake.el @@ -1,9 +1,9 @@ -;;; company-cmake.el --- company-mode completion back-end for CMake +;;; company-cmake.el --- company-mode completion backend for CMake -;; Copyright (C) 2013 Free Software Foundation, Inc. +;; Copyright (C) 2013-2014 Free Software Foundation, Inc. ;; Author: Chen Bin -;; Version: 0.1 +;; Version: 0.2 ;; 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 @@ -29,7 +29,7 @@ (require 'cl-lib) (defgroup company-cmake nil - "Completion back-end for CMake." + "Completion backend for CMake." :group 'company) (defcustom company-cmake-executable @@ -45,48 +45,115 @@ 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\\)?\\)\\(.*\\)" + (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 + "\\(.*\\)\\(.*\\)" + (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_" (match-string 2 candidate)))) + + ;; C flags + ((string-match "^\\(.*_\\)IS_GNU\\(C\\|CXX\\|G77\\)$" candidate) + (setq candidate (concat (match-string 1 candidate) "IS_GNU"))) + + ;; C flags + ((string-match "^\\(.*_\\)OVERRIDE_\\(C\\|CXX\\|Fortran\\)$" candidate) + (setq candidate (concat (match-string 1 candidate) "OVERRIDE_"))) + + ((string-match "^\\(.*\\)\\(_DEBUG\\|_RELEASE\\|_RELWITHDEBINFO\\|_MINSIZEREL\\)\\(.*\\)$" candidate) + (setq candidate (concat (match-string 1 candidate) + "_" + (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,7 +178,7 @@ 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)) (cl-case command