1407 lines
46 KiB
EmacsLisp
1407 lines
46 KiB
EmacsLisp
;;; ac-clang.el --- Auto Completion source by libclang for GNU Emacs -*- lexical-binding: t; -*-
|
|
|
|
;;; last updated : 2015/09/05.04:13:04
|
|
|
|
;; Copyright (C) 2010 Brian Jiang
|
|
;; Copyright (C) 2012 Taylan Ulrich Bayirli/Kammer
|
|
;; Copyright (C) 2013 Golevka
|
|
;; Copyright (C) 2013-2015 yaruopooner
|
|
;;
|
|
;; Original Authors: Brian Jiang <brianjcj@gmail.com>
|
|
;; Golevka [https://github.com/Golevka]
|
|
;; Taylan Ulrich Bayirli/Kammer <taylanbayirli@gmail.com>
|
|
;; Many others
|
|
;; Author: yaruopooner [https://github.com/yaruopooner]
|
|
;; URL: https://github.com/yaruopooner/ac-clang
|
|
;; Keywords: completion, convenience, intellisense
|
|
;; Version: 1.6.0
|
|
;; Package-Requires: ((emacs "24") (cl-lib "0.5") (auto-complete "1.4.0") (pos-tip "0.4.6") (yasnippet "0.8.0"))
|
|
|
|
|
|
;; 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:
|
|
;;
|
|
;; * INTRODUCTION:
|
|
;; This program fork from auto-complete-clang-async.el
|
|
;; ac-clang provide code completion and arguments expand.
|
|
;; This program consists of the client(elisp) and server(binary).
|
|
;; The server is executable file, and a self-build is necessary.
|
|
;; The server achieve code completion using libclang of LLVM.
|
|
;;
|
|
;; * FEATURES:
|
|
;; - Basic(same auto-complete-clang-async)
|
|
;; Code Completion by libclang.
|
|
;; Auto Completion support.
|
|
;; Uses a "completion server" process to utilize libclang.
|
|
;; C/C++/Objective-C mode support.
|
|
;; Jump to definition or declaration. return from jumped location.
|
|
;; Jump is an on-the-fly that doesn't use the tag file.
|
|
;; Also provides flymake syntax checking.
|
|
;; A few bugfix and refactoring.
|
|
;;
|
|
;; - Extension
|
|
;; "completion server" process is 1 process per Emacs. (original version is per buffer)
|
|
;; Template Method Parameters expand support.
|
|
;; Manual Completion support.
|
|
;; libclang CXTranslationUnit Flags support.
|
|
;; libclang CXCodeComplete Flags support.
|
|
;; Multibyte support.
|
|
;; Debug Logger Buffer support.
|
|
;; Jump to inclusion-file. return from jumped location.
|
|
;; more a few modified. (client & server)
|
|
;;
|
|
;; - Optional
|
|
;; CMake support.
|
|
;; clang-server.exe and libclang.dll built with Microsoft Visual Studio 2015/2013.
|
|
;; x86_64 Machine Architecture + Windows Platform support. (Visual Studio Predefined Macros)
|
|
;;
|
|
;; * EASY INSTALLATION(Windows Only):
|
|
;; - Visual C++ Redistributable Packages for Visual Studio 2015/2013
|
|
;; Must be installed if don't have a Visual Studio 2015/2013.
|
|
;;
|
|
;; - 2015
|
|
;; [http://www.microsoft.com/download/details.aspx?id=48145]
|
|
;; - 2013
|
|
;; [http://www.microsoft.com/download/details.aspx?id=40784]
|
|
;;
|
|
;; - Completion Server Program
|
|
;; Built with Microsoft Visual Studio 2015/2013.
|
|
;; [https://github.com/yaruopooner/ac-clang/releases]
|
|
;; 1. download clang-server.zip
|
|
;; 2. clang-server.exe and libclang.dll is expected to be available in the PATH or in Emacs' exec-path.
|
|
;;
|
|
;; * STANDARD INSTALLATION(Linux, Windows):
|
|
;; Generate a Unix Makefile or a Visual Studio Project by CMake.
|
|
;;
|
|
;; - Self-Build step
|
|
;; 1. LLVM
|
|
;; checkout, apply patch, generate project, build
|
|
;; It is recommended that you use this shell.
|
|
;; [https://github.com/yaruopooner/llvm-build-shells.git]
|
|
;;
|
|
;; 2. Clang Server
|
|
;; generate project, build
|
|
;;
|
|
;; see clang-server's reference manual.
|
|
;; ac-clang/clang-server/readme.org
|
|
;;
|
|
;; * NOTICE:
|
|
;; - LLVM libclang.[dll, so, ...]
|
|
;; This binary is not official binary.
|
|
;; Because offical libclang has mmap lock problem.
|
|
;; Applied a patch to LLVM's source code in order to solve this problem.
|
|
;;
|
|
;; see clang-server's reference manual.
|
|
;; ac-clang/clang-server/readme.org
|
|
;;
|
|
|
|
|
|
;; Usage:
|
|
;; * DETAILED MANUAL:
|
|
;; For more information and detailed usage, refer to the project page:
|
|
;; [https://github.com/yaruopooner/ac-clang]
|
|
;;
|
|
;; * SETUP:
|
|
;; (require 'ac-clang)
|
|
;;
|
|
;; (setq w32-pipe-read-delay 0) ;; <- Windows Only
|
|
;;
|
|
;; (when (ac-clang-initialize)
|
|
;; (add-hook 'c-mode-common-hook '(lambda ()
|
|
;; (setq ac-clang-cflags CFLAGS)
|
|
;; (ac-clang-activate-after-modify))))
|
|
;;
|
|
;; * DEFAULT KEYBIND
|
|
;; - start auto completion
|
|
;; code completion & arguments expand
|
|
;; `.` `->` `::`
|
|
;; - start manual completion
|
|
;; code completion & arguments expand
|
|
;; `<tab>`
|
|
;; - jump to inclusion-file, definition, declaration / return from it
|
|
;; this is nestable jump.
|
|
;; `M-.` / `M-,`
|
|
;;
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
(require 'cl-lib)
|
|
(require 'auto-complete)
|
|
(require 'pos-tip)
|
|
(require 'yasnippet)
|
|
(require 'flymake)
|
|
|
|
|
|
|
|
|
|
(defconst ac-clang-version "1.6.0")
|
|
(defconst ac-clang-libclang-version nil)
|
|
|
|
|
|
;;;
|
|
;;; for Server vars
|
|
;;;
|
|
|
|
|
|
;; clang-server binary type
|
|
(defvar ac-clang-server-type 'release
|
|
"clang-server binary type
|
|
`release' : release build version
|
|
`debug' : debug build version (server develop only)
|
|
`x86_64' : (obsolete. It will be removed in the future.) 64bit release build version
|
|
`x86_64d' : (obsolete. It will be removed in the future.) 64bit debug build version (server develop only)
|
|
`x86_32' : (obsolete. It will be removed in the future.) 32bit release build version
|
|
`x86_32d' : (obsolete. It will be removed in the future.) 32bit debug build version (server develop only)
|
|
")
|
|
|
|
|
|
;; clang-server launch option values
|
|
(defvar ac-clang-server-stdin-buffer-size nil
|
|
"STDIN buffer size. value range is 1 - 5 MB.
|
|
If the value is nil, will be allocated 1MB.
|
|
The value is specified in MB.")
|
|
|
|
(defvar ac-clang-server-stdout-buffer-size nil
|
|
"STDOUT buffer size. value range is 1 - 5 MB.
|
|
If the value is nil, will be allocated 1MB.
|
|
The value is specified in MB.")
|
|
|
|
(defvar ac-clang-server-logfile nil
|
|
"IPC records output file.(for debug)")
|
|
|
|
|
|
;; server binaries property list
|
|
(defconst ac-clang--server-binaries '(release "clang-server"
|
|
debug "clang-server-debug"))
|
|
|
|
(defconst ac-clang--server-obsolete-binaries '(x86_64 "clang-server-x86_64"
|
|
x86_64d "clang-server-x86_64d"
|
|
x86_32 "clang-server-x86_32"
|
|
x86_32d "clang-server-x86_32d"))
|
|
|
|
|
|
;; server process details
|
|
(defcustom ac-clang--server-executable nil
|
|
"Location of clang-server executable."
|
|
:group 'auto-complete
|
|
:type 'file)
|
|
|
|
|
|
(defconst ac-clang--process-name "Clang-Server")
|
|
|
|
(defconst ac-clang--process-buffer-name "*Clang-Server*")
|
|
(defconst ac-clang--completion-buffer-name "*Clang-Completion*")
|
|
(defconst ac-clang--diagnostics-buffer-name "*Clang-Diagnostics*")
|
|
|
|
(defvar ac-clang--server-process nil)
|
|
(defvar ac-clang--status 'idle
|
|
"clang-server status
|
|
`idle' : job is nothing
|
|
`receive' : receiving command sent result
|
|
`transaction' : transaction execute to received command result
|
|
`shutdown' : shutdown server
|
|
")
|
|
|
|
|
|
(defvar ac-clang--activate-buffers nil)
|
|
|
|
|
|
;; server debug
|
|
(defconst ac-clang--debug-log-buffer-name "*Clang-Log*")
|
|
(defvar ac-clang-debug-log-buffer-p nil)
|
|
(defvar ac-clang-debug-log-buffer-size (* 1024 50))
|
|
|
|
|
|
;; clang-server behaviors
|
|
(defvar ac-clang-clang-translation-unit-flags "CXTranslationUnit_DetailedPreprocessingRecord|CXTranslationUnit_PrecompiledPreamble|CXTranslationUnit_CacheCompletionResults"
|
|
"CXTranslationUnit Flags.
|
|
for Server behavior.
|
|
The value sets flag-name strings or flag-name combined strings.
|
|
Separator is `|'.
|
|
`CXTranslationUnit_DetailedPreprocessingRecord' : Required if you want jump to macro declaration, inclusion-file.
|
|
`CXTranslationUnit_Incomplete' :
|
|
`CXTranslationUnit_PrecompiledPreamble' : Increase completion performance.
|
|
`CXTranslationUnit_CacheCompletionResults' : Increase completion performance.
|
|
`CXTranslationUnit_ForSerialization' :
|
|
`CXTranslationUnit_CXXChainedPCH' :
|
|
`CXTranslationUnit_SkipFunctionBodies' :
|
|
`CXTranslationUnit_IncludeBriefCommentsInCodeCompletion' : Required if you want to brief-comment of completion.
|
|
")
|
|
|
|
(defvar ac-clang-clang-complete-at-flags "CXCodeComplete_IncludeMacros"
|
|
"CXCodeComplete Flags.
|
|
for Server behavior.
|
|
The value sets flag-name strings or flag-name combined strings.
|
|
Separator is `|'.
|
|
`CXCodeComplete_IncludeMacros'
|
|
`CXCodeComplete_IncludeCodePatterns'
|
|
`CXCodeComplete_IncludeBriefComments'
|
|
")
|
|
|
|
(defvar ac-clang-clang-complete-results-limit 0
|
|
"acceptable number of result candidate.
|
|
for Server behavior.
|
|
ac-clang-clang-complete-results-limit == 0 : accept all candidates.
|
|
ac-clang-clang-complete-results-limit != 0 : if number of result candidates greater than ac-clang-clang-complete-results-limit, discard all candidates.
|
|
")
|
|
|
|
|
|
;; client behaviors
|
|
(defvar ac-clang-tmp-pch-automatic-cleanup-p (eq system-type 'windows-nt)
|
|
"automatically cleanup for generated temporary precompiled headers.")
|
|
|
|
|
|
(defvar ac-clang-server-automatic-recovery-p t
|
|
"automatically recover server when command queue reached limitation.")
|
|
|
|
|
|
|
|
;;;
|
|
;;; for auto-complete vars
|
|
;;;
|
|
|
|
;; clang-server response filter pattern for auto-complete candidates
|
|
(defconst ac-clang--completion-pattern "^COMPLETION: \\(%s[^\s\n:]*\\)\\(?: : \\)*\\(.*$\\)")
|
|
|
|
;; auto-complete behaviors
|
|
(defvar ac-clang-async-autocompletion-automatically-p t
|
|
"If autocompletion is automatically triggered when you type `.', `->', `::'")
|
|
|
|
(defvar ac-clang-async-autocompletion-manualtrigger-key "<tab>")
|
|
|
|
|
|
|
|
;; auto-complete faces
|
|
(defface ac-clang-candidate-face
|
|
'((t (:background "lightgray" :foreground "navy")))
|
|
"Face for clang candidate"
|
|
:group 'auto-complete)
|
|
|
|
(defface ac-clang-selection-face
|
|
'((t (:background "navy" :foreground "white")))
|
|
"Face for the clang selected candidate."
|
|
:group 'auto-complete)
|
|
|
|
|
|
|
|
;;;
|
|
;;; for Session vars
|
|
;;;
|
|
|
|
(defvar-local ac-clang--activate-p nil)
|
|
|
|
(defvar-local ac-clang--session-name nil)
|
|
|
|
;; for patch
|
|
(defvar-local ac-clang--suspend-p nil)
|
|
|
|
|
|
;; auto-complete ac-sources backup
|
|
(defvar-local ac-clang--ac-sources-backup nil)
|
|
|
|
|
|
;; auto-complete candidates and completion start-point
|
|
(defvar-local ac-clang--candidates nil)
|
|
(defvar-local ac-clang--start-point nil)
|
|
(defvar-local ac-clang--template-candidates nil)
|
|
(defvar-local ac-clang--template-start-point nil)
|
|
|
|
|
|
;; CFLAGS build behaviors
|
|
(defvar-local ac-clang-language-option-function nil
|
|
"Function to return the language type for option -x.")
|
|
|
|
(defvar-local ac-clang-prefix-header nil
|
|
"The prefix header to pass to the Clang executable.")
|
|
|
|
|
|
;; clang-server session behavior
|
|
(defvar-local ac-clang-cflags nil
|
|
"Extra flags to pass to the Clang executable.
|
|
This variable will typically contain include paths, e.g., (\"-I~/MyProject\" \"-I.\").")
|
|
|
|
|
|
(defvar ac-clang--jump-stack nil
|
|
"The jump stack (keeps track of jumps via jump-inclusion, jump-definition, jump-declaration, jump-smart)")
|
|
|
|
|
|
|
|
|
|
;;;
|
|
;;; primitive functions
|
|
;;;
|
|
|
|
;; server launch option builder
|
|
(defun ac-clang--build-server-launch-options ()
|
|
(append
|
|
(when ac-clang-server-stdin-buffer-size
|
|
(list "--stdin-buffer-size" (format "%d" ac-clang-server-stdin-buffer-size)))
|
|
(when ac-clang-server-stdout-buffer-size
|
|
(list "--stdout-buffer-size" (format "%d" ac-clang-server-stdout-buffer-size)))
|
|
(when ac-clang-server-logfile
|
|
(list "--logfile" (format "%s" ac-clang-server-logfile)))))
|
|
|
|
|
|
;; CFLAGS builders
|
|
(defsubst ac-clang--language-option ()
|
|
(or (and ac-clang-language-option-function
|
|
(funcall ac-clang-language-option-function))
|
|
(cond ((eq major-mode 'c++-mode)
|
|
"c++")
|
|
((eq major-mode 'c-mode)
|
|
"c")
|
|
((eq major-mode 'objc-mode)
|
|
(cond ((string= "m" (file-name-extension (buffer-file-name)))
|
|
"objective-c")
|
|
(t
|
|
"objective-c++")))
|
|
(t
|
|
"c++"))))
|
|
|
|
|
|
(defsubst ac-clang--build-complete-cflags ()
|
|
(append '("-cc1" "-fsyntax-only")
|
|
(list "-x" (ac-clang--language-option))
|
|
ac-clang-cflags
|
|
(when (stringp ac-clang-prefix-header)
|
|
(list "-include-pch" (expand-file-name ac-clang-prefix-header)))))
|
|
|
|
|
|
|
|
(defsubst ac-clang--get-column-bytes ()
|
|
(1+ (length (encode-coding-string (buffer-substring-no-properties (line-beginning-position) (point)) 'binary))))
|
|
|
|
|
|
(defsubst ac-clang--get-buffer-bytes ()
|
|
(1- (position-bytes (point-max))))
|
|
|
|
|
|
(defsubst ac-clang--create-position-string (point)
|
|
(save-excursion
|
|
(goto-char point)
|
|
(format "line:%d\ncolumn:%d\n" (line-number-at-pos) (ac-clang--get-column-bytes))))
|
|
|
|
|
|
(defmacro ac-clang--with-widening (&rest body)
|
|
(declare (indent 0) (debug t))
|
|
`(save-restriction
|
|
(widen)
|
|
(progn ,@body)))
|
|
|
|
|
|
;; (defmacro ac-clang--with-running-server (&rest body)
|
|
;; (declare (indent 0) (debug t))
|
|
;; (when (eq (process-status ac-clang--server-process) 'run)
|
|
;; `(progn ,@body)))
|
|
|
|
|
|
|
|
;;;
|
|
;;; transaction command functions for IPC
|
|
;;;
|
|
|
|
(defvar ac-clang--server-command-queue nil)
|
|
(defvar ac-clang--server-command-queue-limit 4)
|
|
|
|
|
|
(defsubst ac-clang--request-command (sender-function receive-buffer receiver-function args)
|
|
(if (< (length ac-clang--server-command-queue) ac-clang--server-command-queue-limit)
|
|
(progn
|
|
(when (and receive-buffer receiver-function)
|
|
(ac-clang--enqueue-command `(:buffer ,receive-buffer :receiver ,receiver-function :sender ,sender-function :args ,args)))
|
|
(funcall sender-function args))
|
|
(message "ac-clang : The number of requests of the command queue reached the limit.")
|
|
;; This is recovery logic.
|
|
(when ac-clang-server-automatic-recovery-p
|
|
(ac-clang--clear-command-queue)
|
|
;; Send message
|
|
(ac-clang-get-server-specification)
|
|
;; Process response wait(as with thread preemption point)
|
|
(sleep-for 0.1)
|
|
;; When process response is not received, I suppose that server became to deadlock.
|
|
(if (= (length ac-clang--server-command-queue) 0)
|
|
(message "ac-clang : clear server command queue.")
|
|
(ac-clang-reboot-server)))))
|
|
|
|
|
|
(defsubst ac-clang--enqueue-command (command)
|
|
(if ac-clang--server-command-queue
|
|
(nconc ac-clang--server-command-queue (list command))
|
|
(setq ac-clang--server-command-queue (list command))))
|
|
|
|
|
|
(defsubst ac-clang--dequeue-command ()
|
|
(let ((command ac-clang--server-command-queue))
|
|
(setq ac-clang--server-command-queue (cdr command))
|
|
(car command)))
|
|
|
|
|
|
(defsubst ac-clang--get-top-command ()
|
|
(car ac-clang--server-command-queue))
|
|
|
|
|
|
(defsubst ac-clang--clear-command-queue ()
|
|
(setq ac-clang--server-command-queue nil))
|
|
|
|
|
|
|
|
;;;
|
|
;;; sender primitive functions for IPC
|
|
;;;
|
|
|
|
(defsubst ac-clang--process-send-string (string)
|
|
(process-send-string ac-clang--server-process string)
|
|
|
|
(when ac-clang-debug-log-buffer-p
|
|
(let ((log-buffer (get-buffer-create ac-clang--debug-log-buffer-name)))
|
|
(when log-buffer
|
|
(with-current-buffer log-buffer
|
|
(when (and ac-clang-debug-log-buffer-size (> (buffer-size) ac-clang-debug-log-buffer-size))
|
|
(erase-buffer))
|
|
|
|
(goto-char (point-max))
|
|
(pp (encode-coding-string string 'binary) log-buffer)
|
|
(insert "\n"))))))
|
|
|
|
|
|
(defsubst ac-clang--process-send-region (start end)
|
|
(process-send-region ac-clang--server-process start end))
|
|
|
|
|
|
(defun ac-clang--send-set-clang-parameters ()
|
|
(ac-clang--process-send-string (format "translation_unit_flags:%s\n" ac-clang-clang-translation-unit-flags))
|
|
(ac-clang--process-send-string (format "complete_at_flags:%s\n" ac-clang-clang-complete-at-flags))
|
|
(ac-clang--process-send-string (format "complete_results_limit:%d\n" ac-clang-clang-complete-results-limit)))
|
|
|
|
|
|
(defun ac-clang--send-cflags ()
|
|
;; send message head and num_cflags
|
|
(ac-clang--process-send-string (format "num_cflags:%d\n" (length (ac-clang--build-complete-cflags))))
|
|
|
|
(let (cflags)
|
|
;; create CFLAGS strings
|
|
(mapc
|
|
(lambda (arg)
|
|
(setq cflags (concat cflags (format "%s\n" arg))))
|
|
(ac-clang--build-complete-cflags))
|
|
;; send cflags
|
|
(ac-clang--process-send-string cflags)))
|
|
|
|
|
|
(defun ac-clang--send-source-code ()
|
|
(ac-clang--with-widening
|
|
(let ((source-buffuer (current-buffer))
|
|
(cs (coding-system-change-eol-conversion buffer-file-coding-system 'unix)))
|
|
(with-temp-buffer
|
|
(set-buffer-multibyte nil)
|
|
(let ((temp-buffer (current-buffer)))
|
|
(with-current-buffer source-buffuer
|
|
(decode-coding-region (point-min) (point-max) cs temp-buffer)))
|
|
|
|
(ac-clang--process-send-string (format "source_length:%d\n" (ac-clang--get-buffer-bytes)))
|
|
;; (ac-clang--process-send-region (point-min) (point-max))
|
|
(ac-clang--process-send-string (buffer-substring-no-properties (point-min) (point-max)))
|
|
(ac-clang--process-send-string "\n\n")))))
|
|
|
|
|
|
;; (defun ac-clang--send-source-code ()
|
|
;; (ac-clang--with-widening
|
|
;; (ac-clang--process-send-string (format "source_length:%d\n" (ac-clang--get-buffer-bytes)))
|
|
;; (ac-clang--process-send-region (point-min) (point-max))
|
|
;; (ac-clang--process-send-string "\n\n")))
|
|
|
|
|
|
(defsubst ac-clang--send-command (command-type command-name &optional session-name)
|
|
(let ((command (format "command_type:%s\ncommand_name:%s\n" command-type command-name)))
|
|
(when session-name
|
|
(setq command (concat command (format "session_name:%s\n" session-name))))
|
|
(ac-clang--process-send-string command)))
|
|
|
|
|
|
|
|
;;;
|
|
;;; sender command request functions for IPC
|
|
;;;
|
|
|
|
(defun ac-clang--send-server-specification-request (&optional _args)
|
|
(ac-clang--send-command "Server" "GET_SPECIFICATION"))
|
|
|
|
|
|
(defun ac-clang--send-clang-parameters-request (&optional _args)
|
|
(ac-clang--send-command "Server" "SET_CLANG_PARAMETERS")
|
|
(ac-clang--send-set-clang-parameters))
|
|
|
|
|
|
(defun ac-clang--send-create-session-request (&optional _args)
|
|
(ac-clang--with-widening
|
|
(ac-clang--send-command "Server" "CREATE_SESSION" ac-clang--session-name)
|
|
(ac-clang--send-cflags)
|
|
(ac-clang--send-source-code)))
|
|
|
|
|
|
(defun ac-clang--send-delete-session-request (&optional _args)
|
|
(ac-clang--send-command "Server" "DELETE_SESSION" ac-clang--session-name))
|
|
|
|
|
|
(defun ac-clang--send-reset-server-request (&optional _args)
|
|
(ac-clang--send-command "Server" "RESET"))
|
|
|
|
|
|
(defun ac-clang--send-shutdown-request (&optional _args)
|
|
(when (eq (process-status ac-clang--server-process) 'run)
|
|
(ac-clang--send-command "Server" "SHUTDOWN")))
|
|
|
|
|
|
(defun ac-clang--send-suspend-request (&optional _args)
|
|
(ac-clang--send-command "Session" "SUSPEND" ac-clang--session-name))
|
|
|
|
|
|
(defun ac-clang--send-resume-request (&optional _args)
|
|
(ac-clang--send-command "Session" "RESUME" ac-clang--session-name))
|
|
|
|
|
|
(defun ac-clang--send-cflags-request (&optional _args)
|
|
(if (listp ac-clang-cflags)
|
|
(ac-clang--with-widening
|
|
(ac-clang--send-command "Session" "SET_CFLAGS" ac-clang--session-name)
|
|
(ac-clang--send-cflags)
|
|
(ac-clang--send-source-code))
|
|
(message "`ac-clang-cflags' should be a list of strings")))
|
|
|
|
|
|
(defun ac-clang--send-reparse-request (&optional _args)
|
|
(ac-clang--with-widening
|
|
(ac-clang--send-command "Session" "SET_SOURCECODE" ac-clang--session-name)
|
|
(ac-clang--send-source-code)
|
|
(ac-clang--send-command "Session" "REPARSE" ac-clang--session-name)))
|
|
|
|
|
|
(defun ac-clang--send-completion-request (&optional args)
|
|
(ac-clang--with-widening
|
|
(ac-clang--send-command "Session" "COMPLETION" ac-clang--session-name)
|
|
(ac-clang--process-send-string (ac-clang--create-position-string (plist-get args :start-point)))
|
|
(ac-clang--send-source-code)))
|
|
|
|
|
|
(defun ac-clang--send-diagnostics-request (&optional _args)
|
|
(ac-clang--with-widening
|
|
(ac-clang--send-command "Session" "SYNTAXCHECK" ac-clang--session-name)
|
|
(ac-clang--send-source-code)))
|
|
|
|
|
|
(defun ac-clang--send-inclusion-request (&optional _args)
|
|
(ac-clang--with-widening
|
|
(ac-clang--send-command "Session" "INCLUSION" ac-clang--session-name)
|
|
(ac-clang--process-send-string (ac-clang--create-position-string (point)))
|
|
(ac-clang--send-source-code)))
|
|
|
|
|
|
(defun ac-clang--send-definition-request (&optional _args)
|
|
(ac-clang--with-widening
|
|
(ac-clang--send-command "Session" "DEFINITION" ac-clang--session-name)
|
|
(ac-clang--process-send-string (ac-clang--create-position-string (point)))
|
|
(ac-clang--send-source-code)))
|
|
|
|
|
|
(defun ac-clang--send-declaration-request (&optional _args)
|
|
(ac-clang--with-widening
|
|
(ac-clang--send-command "Session" "DECLARATION" ac-clang--session-name)
|
|
(ac-clang--process-send-string (ac-clang--create-position-string (point)))
|
|
(ac-clang--send-source-code)))
|
|
|
|
|
|
(defun ac-clang--send-smart-jump-request (&optional _args)
|
|
(ac-clang--with-widening
|
|
(ac-clang--send-command "Session" "SMARTJUMP" ac-clang--session-name)
|
|
(ac-clang--process-send-string (ac-clang--create-position-string (point)))
|
|
(ac-clang--send-source-code)))
|
|
|
|
|
|
|
|
|
|
;;;
|
|
;;; Receive clang-server responses common filter (receive response by command)
|
|
;;;
|
|
|
|
(defvar ac-clang--transaction-context nil)
|
|
(defvar ac-clang--transaction-context-buffer-name nil)
|
|
(defvar ac-clang--transaction-context-buffer nil)
|
|
(defvar ac-clang--transaction-context-buffer-marker nil)
|
|
(defvar ac-clang--transaction-context-receiver nil)
|
|
(defvar ac-clang--transaction-context-args nil)
|
|
|
|
|
|
(defun ac-clang--process-filter (process output)
|
|
;; command parse for context
|
|
(unless ac-clang--transaction-context
|
|
(if (setq ac-clang--transaction-context (ac-clang--dequeue-command))
|
|
;; setup context
|
|
(progn
|
|
(setq ac-clang--transaction-context-buffer-name (plist-get ac-clang--transaction-context :buffer)
|
|
ac-clang--transaction-context-receiver (plist-get ac-clang--transaction-context :receiver)
|
|
ac-clang--transaction-context-args (plist-get ac-clang--transaction-context :args))
|
|
(setq ac-clang--status 'receive)
|
|
(when ac-clang--transaction-context-buffer-name
|
|
(setq ac-clang--transaction-context-buffer (get-buffer-create ac-clang--transaction-context-buffer-name))
|
|
(with-current-buffer ac-clang--transaction-context-buffer
|
|
(unless (local-variable-p 'ac-clang--transaction-context-buffer-marker)
|
|
;; The buffer created just now.
|
|
(set (make-local-variable 'ac-clang--transaction-context-buffer-marker) (point-min-marker)))
|
|
(erase-buffer))))
|
|
(progn
|
|
(setq ac-clang--transaction-context-buffer (process-buffer process))
|
|
(setq ac-clang--transaction-context-buffer-marker (process-mark process)))))
|
|
|
|
;; Output of the server is appended to context buffer.
|
|
(when ac-clang--transaction-context-buffer
|
|
(ac-clang--append-to-transaction-context-buffer output))
|
|
|
|
;; Check the server response termination.
|
|
(when (and ac-clang--transaction-context (string= (substring output -1 nil) "$"))
|
|
;; execute context receiver.
|
|
(setq ac-clang--status 'transaction)
|
|
(unless (ignore-errors
|
|
(funcall ac-clang--transaction-context-receiver ac-clang--transaction-context-buffer output ac-clang--transaction-context-args)
|
|
t)
|
|
(message "ac-clang : receiver function error!"))
|
|
;; clear current context.
|
|
(setq ac-clang--transaction-context nil
|
|
ac-clang--transaction-context-buffer-name nil
|
|
ac-clang--transaction-context-buffer nil
|
|
ac-clang--transaction-context-receiver nil
|
|
ac-clang--transaction-context-args nil)
|
|
(setq ac-clang--status 'idle)))
|
|
|
|
|
|
(defun ac-clang--append-to-transaction-context-buffer (output)
|
|
"Append output to the transaction context buffer."
|
|
(with-current-buffer ac-clang--transaction-context-buffer
|
|
(save-excursion
|
|
;; Insert the text, advancing the process marker.
|
|
(goto-char ac-clang--transaction-context-buffer-marker)
|
|
(insert output)
|
|
(set-marker ac-clang--transaction-context-buffer-marker (point)))
|
|
(goto-char ac-clang--transaction-context-buffer-marker)))
|
|
|
|
|
|
|
|
|
|
;;;
|
|
;;; receive clang-server responses.
|
|
;;; build completion candidates and fire auto-complete.
|
|
;;;
|
|
|
|
(defun ac-clang--build-completion-candidates (buffer start-word)
|
|
(with-current-buffer buffer
|
|
(goto-char (point-min))
|
|
(let ((pattern (format ac-clang--completion-pattern (regexp-quote start-word)))
|
|
candidates
|
|
candidate
|
|
declaration
|
|
(prev-candidate ""))
|
|
(while (re-search-forward pattern nil t)
|
|
(setq candidate (match-string-no-properties 1))
|
|
(unless (string= "Pattern" candidate)
|
|
(setq declaration (match-string-no-properties 2))
|
|
|
|
(if (string= candidate prev-candidate)
|
|
(progn
|
|
(when declaration
|
|
(setq candidate (propertize candidate 'ac-clang--detail (concat (get-text-property 0 'ac-clang--detail (car candidates)) "\n" declaration)))
|
|
(setf (car candidates) candidate)))
|
|
(setq prev-candidate candidate)
|
|
(when declaration
|
|
(setq candidate (propertize candidate 'ac-clang--detail declaration)))
|
|
(push candidate candidates))))
|
|
candidates)))
|
|
|
|
|
|
(defun ac-clang--receive-completion (buffer _output args)
|
|
(setq ac-clang--candidates (ac-clang--build-completion-candidates buffer (plist-get args :start-word)))
|
|
(setq ac-clang--start-point (plist-get args :start-point))
|
|
|
|
;; (setq ac-show-menu t)
|
|
;; (ac-start :force-init t)
|
|
;; (ac-update))
|
|
(ac-complete-clang-async))
|
|
|
|
|
|
|
|
(defun ac-clang--get-autotrigger-start-point (&optional point)
|
|
(unless point
|
|
(setq point (point)))
|
|
(let ((c (char-before point)))
|
|
(when (or
|
|
;; '.'
|
|
(eq ?. c)
|
|
;; '->'
|
|
(and (eq ?> c)
|
|
(eq ?- (char-before (1- point))))
|
|
;; '::'
|
|
(and (eq ?: c)
|
|
(eq ?: (char-before (1- point)))))
|
|
point)))
|
|
|
|
|
|
(defun ac-clang--get-manualtrigger-start-point ()
|
|
(let* ((symbol-point (ac-prefix-symbol))
|
|
(point (or symbol-point (point)))
|
|
(c (char-before point)))
|
|
(when (or
|
|
(ac-clang--get-autotrigger-start-point point)
|
|
;; ' ' for manual completion
|
|
(eq ?\s c))
|
|
point)))
|
|
|
|
|
|
(defsubst ac-clang--async-completion (start-point)
|
|
(when start-point
|
|
(ac-clang--request-command
|
|
'ac-clang--send-completion-request
|
|
ac-clang--completion-buffer-name
|
|
'ac-clang--receive-completion
|
|
(list :start-word (buffer-substring-no-properties start-point (point)) :start-point start-point))))
|
|
|
|
|
|
(defun ac-clang-async-autocomplete-autotrigger ()
|
|
(interactive)
|
|
|
|
(self-insert-command 1)
|
|
(when ac-clang-async-autocompletion-automatically-p
|
|
(ac-clang--async-completion (ac-clang--get-autotrigger-start-point))))
|
|
|
|
|
|
(defun ac-clang-async-autocomplete-manualtrigger ()
|
|
(interactive)
|
|
|
|
(ac-clang--async-completion (ac-clang--get-manualtrigger-start-point)))
|
|
|
|
|
|
|
|
|
|
;;;
|
|
;;; auto-complete ac-source build functions
|
|
;;;
|
|
|
|
(defsubst ac-clang--candidates ()
|
|
ac-clang--candidates)
|
|
|
|
|
|
(defsubst ac-clang--prefix ()
|
|
ac-clang--start-point)
|
|
|
|
|
|
(defsubst ac-clang--clean-document (s)
|
|
(when s
|
|
(setq s (replace-regexp-in-string "<#\\|#>\\|\\[#" "" s))
|
|
(setq s (replace-regexp-in-string "#\\]" " " s)))
|
|
s)
|
|
|
|
|
|
(defsubst ac-clang--in-string/comment ()
|
|
"Return non-nil if point is in a literal (a comment or string)."
|
|
(nth 8 (syntax-ppss)))
|
|
|
|
|
|
(defun ac-clang--action ()
|
|
(interactive)
|
|
|
|
;; (ac-last-quick-help)
|
|
(let* ((func-name (regexp-quote (substring-no-properties (cdr ac-last-completion))))
|
|
(c/c++-pattern (format "\\(?:^.*%s\\)\\([<(].*)\\)" func-name))
|
|
(objc-pattern (format "\\(?:^.*%s\\)\\(:.*\\)" func-name))
|
|
(detail (get-text-property 0 'ac-clang--detail (cdr ac-last-completion)))
|
|
(help (ac-clang--clean-document detail))
|
|
(declarations (split-string detail "\n"))
|
|
args
|
|
(ret-t "")
|
|
ret-f
|
|
candidates)
|
|
|
|
;; parse function or method overload declarations
|
|
(cl-dolist (declaration declarations)
|
|
;; function result type
|
|
(when (string-match "\\[#\\(.*\\)#\\]" declaration)
|
|
(setq ret-t (match-string 1 declaration)))
|
|
;; remove result type
|
|
(setq declaration (replace-regexp-in-string "\\[#.*?#\\]" "" declaration))
|
|
|
|
;; parse arguments
|
|
(cond (;; C/C++ standard argument
|
|
(string-match c/c++-pattern declaration)
|
|
(setq args (match-string 1 declaration))
|
|
(push (propertize (ac-clang--clean-document args) 'ac-clang--detail ret-t 'ac-clang--args args) candidates)
|
|
;; default argument
|
|
(when (string-match "\{#" args)
|
|
(setq args (replace-regexp-in-string "\{#.*#\}" "" args))
|
|
(push (propertize (ac-clang--clean-document args) 'ac-clang--detail ret-t 'ac-clang--args args) candidates))
|
|
;; variadic argument
|
|
(when (string-match ", \\.\\.\\." args)
|
|
(setq args (replace-regexp-in-string ", \\.\\.\\." "" args))
|
|
(push (propertize (ac-clang--clean-document args) 'ac-clang--detail ret-t 'ac-clang--args args) candidates)))
|
|
|
|
(;; check whether it is a function ptr
|
|
(string-match "^\\([^(]*\\)(\\*)\\((.*)\\)" ret-t)
|
|
(setq ret-f (match-string 1 ret-t)
|
|
args (match-string 2 ret-t))
|
|
(push (propertize args 'ac-clang--detail ret-f 'ac-clang--args "") candidates)
|
|
;; variadic argument
|
|
(when (string-match ", \\.\\.\\." args)
|
|
(setq args (replace-regexp-in-string ", \\.\\.\\." "" args))
|
|
(push (propertize args 'ac-clang--detail ret-f 'ac-clang--args "") candidates)))
|
|
|
|
(;; Objective-C/C++ argument
|
|
(string-match objc-pattern declaration)
|
|
(setq args (match-string 1 declaration))
|
|
(push (propertize (ac-clang--clean-document args) 'ac-clang--detail ret-t 'ac-clang--args args) candidates))))
|
|
|
|
(cond (candidates
|
|
(setq candidates (delete-dups candidates))
|
|
(setq candidates (nreverse candidates))
|
|
(setq ac-clang--template-candidates candidates)
|
|
(setq ac-clang--template-start-point (point))
|
|
(ac-complete-clang-template)
|
|
|
|
(unless (cdr candidates) ;; unless length > 1
|
|
(message (replace-regexp-in-string "\n" " ; " help))))
|
|
(t
|
|
(message (replace-regexp-in-string "\n" " ; " help))))))
|
|
|
|
|
|
(defun ac-clang--document (item)
|
|
(if (stringp item)
|
|
(let (s)
|
|
(setq s (get-text-property 0 'ac-clang--detail item))
|
|
(ac-clang--clean-document s)))
|
|
;; (popup-item-property item 'ac-clang--detail)
|
|
)
|
|
|
|
|
|
|
|
(ac-define-source clang-async
|
|
'((candidates . ac-clang--candidates)
|
|
(candidate-face . ac-clang-candidate-face)
|
|
(selection-face . ac-clang-selection-face)
|
|
(prefix . ac-clang--prefix)
|
|
(requires . 0)
|
|
(action . ac-clang--action)
|
|
(document . ac-clang--document)
|
|
(cache)
|
|
(symbol . "c")))
|
|
|
|
|
|
|
|
(defun ac-clang--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-clang--split-args (s)
|
|
(let ((sl (split-string s ", *")))
|
|
(cond ((string-match "<\\|(" s)
|
|
(let (res
|
|
(pre "")
|
|
subs)
|
|
(while sl
|
|
(setq subs (pop sl))
|
|
(unless (string= pre "")
|
|
(setq subs (concat pre ", " subs))
|
|
(setq pre ""))
|
|
(cond ((and (ac-clang--same-count-in-string ?\< ?\> subs)
|
|
(ac-clang--same-count-in-string ?\( ?\) subs))
|
|
;; (cond ((ac-clang--same-count-in-string ?\< ?\> subs)
|
|
(push subs res))
|
|
(t
|
|
(setq pre subs))))
|
|
(nreverse res)))
|
|
(t
|
|
sl))))
|
|
|
|
|
|
(defsubst ac-clang--template-candidates ()
|
|
ac-clang--template-candidates)
|
|
|
|
|
|
(defsubst ac-clang--template-prefix ()
|
|
ac-clang--template-start-point)
|
|
|
|
|
|
(defun ac-clang--template-action ()
|
|
(interactive)
|
|
|
|
(when ac-clang--template-start-point
|
|
(let ((point (point))
|
|
sl
|
|
(snp "")
|
|
(s (get-text-property 0 'ac-clang--args (cdr ac-last-completion))))
|
|
(cond (;; function ptr call
|
|
(string= s "")
|
|
(setq s (cdr ac-last-completion))
|
|
(setq s (replace-regexp-in-string "^(\\|)$" "" s))
|
|
(setq sl (ac-clang--split-args s))
|
|
(cl-dolist (arg sl)
|
|
(setq snp (concat snp ", ${" arg "}")))
|
|
(yas-expand-snippet (concat "(" (substring snp 2) ")") ac-clang--template-start-point point))
|
|
(;; function args
|
|
t
|
|
(unless (string= s "()")
|
|
(setq s (replace-regexp-in-string "{#" "" s))
|
|
(setq s (replace-regexp-in-string "#}" "" s))
|
|
(setq s (replace-regexp-in-string "<#" "${" s))
|
|
(setq s (replace-regexp-in-string "#>" "}" s))
|
|
(setq s (replace-regexp-in-string ", \\.\\.\\." "}, ${..." s))
|
|
(yas-expand-snippet s ac-clang--template-start-point point)))))))
|
|
|
|
|
|
;; This source shall only be used internally.
|
|
(ac-define-source clang-template
|
|
'((candidates . ac-clang--template-candidates)
|
|
(prefix . ac-clang--template-prefix)
|
|
(requires . 0)
|
|
(action . ac-clang--template-action)
|
|
(document . ac-clang--document)
|
|
(cache)
|
|
(symbol . "t")))
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
;;; receive clang-server responses.
|
|
;;; syntax checking with flymake
|
|
;;;
|
|
|
|
(defun ac-clang--receive-diagnostics (buffer _output _args)
|
|
(let (result-texts)
|
|
(with-current-buffer buffer
|
|
(flymake-log 3 "received %d byte(s) of output from process %d" (ac-clang--get-buffer-bytes) (process-id ac-clang--server-process))
|
|
(setq result-texts (buffer-substring-no-properties (point-min) (point-max))))
|
|
(flymake-parse-output-and-residual result-texts))
|
|
|
|
(flymake-parse-residual)
|
|
(setq flymake-err-info flymake-new-err-info)
|
|
(setq flymake-new-err-info nil)
|
|
(setq flymake-err-info (flymake-fix-line-numbers flymake-err-info 1 (count-lines (point-min) (point-max))))
|
|
(flymake-delete-own-overlays)
|
|
(flymake-highlight-err-lines flymake-err-info))
|
|
|
|
|
|
(defun ac-clang-diagnostics ()
|
|
(interactive)
|
|
|
|
(if ac-clang--suspend-p
|
|
(ac-clang-resume)
|
|
(ac-clang-activate))
|
|
|
|
(ac-clang--request-command 'ac-clang--send-diagnostics-request ac-clang--diagnostics-buffer-name 'ac-clang--receive-diagnostics nil))
|
|
|
|
|
|
|
|
|
|
;;;
|
|
;;; receive clang-server responses.
|
|
;;; jump declaration/definition/smart-jump
|
|
;;;
|
|
|
|
(defun ac-clang--receive-jump (_buffer output _arg)
|
|
(unless (eq (aref output 0) ?$)
|
|
(let* ((parsed (split-string-and-unquote output))
|
|
(filename (pop parsed))
|
|
(line (string-to-number (pop parsed)))
|
|
(column (1- (string-to-number (pop parsed))))
|
|
(new-loc (list filename line column))
|
|
(current-loc (list (buffer-file-name) (line-number-at-pos) (current-column))))
|
|
(when (not (equal current-loc new-loc))
|
|
(push current-loc ac-clang--jump-stack)
|
|
(ac-clang--jump new-loc)))))
|
|
|
|
|
|
(defun ac-clang--jump (location)
|
|
(let* ((filename (pop location))
|
|
(line (pop location))
|
|
(column (pop location)))
|
|
(find-file filename)
|
|
(goto-char (point-min))
|
|
(forward-line (1- line))
|
|
(move-to-column column)))
|
|
|
|
|
|
(defun ac-clang-jump-back ()
|
|
(interactive)
|
|
|
|
(when ac-clang--jump-stack
|
|
(ac-clang--jump (pop ac-clang--jump-stack))))
|
|
|
|
|
|
(defun ac-clang-jump-inclusion ()
|
|
(interactive)
|
|
|
|
(if ac-clang--suspend-p
|
|
(ac-clang-resume)
|
|
(ac-clang-activate))
|
|
|
|
(ac-clang--request-command 'ac-clang--send-inclusion-request ac-clang--process-buffer-name 'ac-clang--receive-jump nil))
|
|
|
|
|
|
(defun ac-clang-jump-definition ()
|
|
(interactive)
|
|
|
|
(if ac-clang--suspend-p
|
|
(ac-clang-resume)
|
|
(ac-clang-activate))
|
|
|
|
(ac-clang--request-command 'ac-clang--send-definition-request ac-clang--process-buffer-name 'ac-clang--receive-jump nil))
|
|
|
|
|
|
(defun ac-clang-jump-declaration ()
|
|
(interactive)
|
|
|
|
(if ac-clang--suspend-p
|
|
(ac-clang-resume)
|
|
(ac-clang-activate))
|
|
|
|
(ac-clang--request-command 'ac-clang--send-declaration-request ac-clang--process-buffer-name 'ac-clang--receive-jump nil))
|
|
|
|
|
|
(defun ac-clang-jump-smart ()
|
|
(interactive)
|
|
|
|
(if ac-clang--suspend-p
|
|
(ac-clang-resume)
|
|
(ac-clang-activate))
|
|
|
|
(ac-clang--request-command 'ac-clang--send-smart-jump-request ac-clang--process-buffer-name 'ac-clang--receive-jump nil))
|
|
|
|
|
|
|
|
|
|
;;;
|
|
;;; sender function for IPC
|
|
;;;
|
|
|
|
(defun ac-clang-get-server-specification ()
|
|
(interactive)
|
|
|
|
(when ac-clang--server-process
|
|
(ac-clang--request-command 'ac-clang--send-server-specification-request ac-clang--process-buffer-name '(lambda (_buffer _output _args)) nil)))
|
|
|
|
|
|
|
|
;;;
|
|
;;; The session control functions
|
|
;;;
|
|
|
|
(defun ac-clang-activate ()
|
|
(interactive)
|
|
|
|
(remove-hook 'first-change-hook 'ac-clang-activate t)
|
|
|
|
(unless ac-clang--activate-p
|
|
;; (if ac-clang--activate-buffers
|
|
;; (ac-clang-update-cflags)
|
|
;; (ac-clang-initialize))
|
|
|
|
(setq ac-clang--activate-p t)
|
|
(setq ac-clang--session-name (buffer-file-name))
|
|
(setq ac-clang--suspend-p nil)
|
|
(setq ac-clang--ac-sources-backup ac-sources)
|
|
(setq ac-sources '(ac-source-clang-async))
|
|
(push (current-buffer) ac-clang--activate-buffers)
|
|
|
|
(ac-clang--send-create-session-request)
|
|
|
|
(local-set-key (kbd ".") 'ac-clang-async-autocomplete-autotrigger)
|
|
(local-set-key (kbd ">") 'ac-clang-async-autocomplete-autotrigger)
|
|
(local-set-key (kbd ":") 'ac-clang-async-autocomplete-autotrigger)
|
|
(local-set-key (kbd ac-clang-async-autocompletion-manualtrigger-key) 'ac-clang-async-autocomplete-manualtrigger)
|
|
|
|
(add-hook 'before-save-hook 'ac-clang-suspend nil t)
|
|
;; (add-hook 'after-save-hook 'ac-clang-deactivate nil t)
|
|
;; (add-hook 'first-change-hook 'ac-clang-activate nil t)
|
|
;; (add-hook 'before-save-hook 'ac-clang-reparse-buffer nil t)
|
|
;; (add-hook 'after-save-hook 'ac-clang-reparse-buffer nil t)
|
|
(add-hook 'before-revert-hook 'ac-clang-deactivate nil t)
|
|
(add-hook 'kill-buffer-hook 'ac-clang-deactivate nil t)))
|
|
|
|
|
|
(defun ac-clang-deactivate ()
|
|
(interactive)
|
|
|
|
(when ac-clang--activate-p
|
|
(remove-hook 'before-save-hook 'ac-clang-suspend t)
|
|
(remove-hook 'first-change-hook 'ac-clang-resume t)
|
|
;; (remove-hook 'before-save-hook 'ac-clang-reparse-buffer t)
|
|
;; (remove-hook 'after-save-hook 'ac-clang-reparse-buffer t)
|
|
(remove-hook 'before-revert-hook 'ac-clang-deactivate t)
|
|
(remove-hook 'kill-buffer-hook 'ac-clang-deactivate t)
|
|
|
|
(ac-clang--send-delete-session-request)
|
|
|
|
(pop ac-clang--activate-buffers)
|
|
(setq ac-sources ac-clang--ac-sources-backup)
|
|
(setq ac-clang--ac-sources-backup nil)
|
|
(setq ac-clang--suspend-p nil)
|
|
(setq ac-clang--session-name nil)
|
|
(setq ac-clang--activate-p nil)
|
|
|
|
;; (unless ac-clang--activate-buffers
|
|
;; (ac-clang-finalize))
|
|
))
|
|
|
|
|
|
(defun ac-clang-activate-after-modify ()
|
|
(interactive)
|
|
|
|
(if (buffer-modified-p)
|
|
(ac-clang-activate)
|
|
(add-hook 'first-change-hook 'ac-clang-activate nil t)))
|
|
|
|
|
|
(defun ac-clang-suspend ()
|
|
(when (and ac-clang--activate-p (not ac-clang--suspend-p))
|
|
(setq ac-clang--suspend-p t)
|
|
(ac-clang--send-suspend-request)
|
|
(add-hook 'first-change-hook 'ac-clang-resume nil t)))
|
|
|
|
|
|
(defun ac-clang-resume ()
|
|
(when (and ac-clang--activate-p ac-clang--suspend-p)
|
|
(setq ac-clang--suspend-p nil)
|
|
(remove-hook 'first-change-hook 'ac-clang-resume t)
|
|
(ac-clang--send-resume-request)))
|
|
|
|
|
|
(defun ac-clang-reparse-buffer ()
|
|
(when ac-clang--server-process
|
|
(ac-clang--send-reparse-request)))
|
|
|
|
|
|
(defun ac-clang-update-cflags ()
|
|
(interactive)
|
|
|
|
(when ac-clang--activate-p
|
|
;; (message "ac-clang-update-cflags %s" ac-clang--session-name)
|
|
(ac-clang--send-cflags-request)))
|
|
|
|
|
|
(defun ac-clang-set-cflags ()
|
|
"Set `ac-clang-cflags' interactively."
|
|
(interactive)
|
|
|
|
(setq ac-clang-cflags (split-string (read-string "New cflags: ")))
|
|
(ac-clang-update-cflags))
|
|
|
|
|
|
(defun ac-clang-set-cflags-from-shell-command ()
|
|
"Set `ac-clang-cflags' to a shell command's output.
|
|
set new cflags for ac-clang from shell command output"
|
|
(interactive)
|
|
|
|
(setq ac-clang-cflags
|
|
(split-string
|
|
(shell-command-to-string
|
|
(read-shell-command "Shell command: " nil nil
|
|
(and buffer-file-name
|
|
(file-relative-name buffer-file-name))))))
|
|
(ac-clang-update-cflags))
|
|
|
|
|
|
(defun ac-clang-set-prefix-header (prefix-header)
|
|
"Set `ac-clang-prefix-header' interactively."
|
|
(interactive
|
|
(let ((default (car (directory-files "." t "\\([^.]h\\|[^h]\\).pch\\'" t))))
|
|
(list
|
|
(read-file-name (concat "Clang prefix header (currently " (or ac-clang-prefix-header "nil") "): ")
|
|
(when default (file-name-directory default))
|
|
default nil (when default (file-name-nondirectory default))))))
|
|
|
|
(cond
|
|
((string-match "^[\s\t]*$" prefix-header)
|
|
(setq ac-clang-prefix-header nil))
|
|
(t
|
|
(setq ac-clang-prefix-header prefix-header))))
|
|
|
|
|
|
|
|
|
|
;;;
|
|
;;; The server control functions
|
|
;;;
|
|
|
|
|
|
(defun ac-clang--clean-tmp-pch ()
|
|
"Clean up temporary precompiled headers."
|
|
|
|
(cl-dolist (pch-file (directory-files temporary-file-directory t "preamble-.*\\.pch$" t))
|
|
(ignore-errors
|
|
(delete-file pch-file)
|
|
t)))
|
|
|
|
|
|
|
|
(defun ac-clang-launch-server ()
|
|
(interactive)
|
|
|
|
(when (and ac-clang--server-executable (not ac-clang--server-process))
|
|
(let ((process-connection-type nil)
|
|
(coding-system-for-write 'binary))
|
|
(setq ac-clang--server-process
|
|
(apply 'start-process
|
|
ac-clang--process-name ac-clang--process-buffer-name
|
|
ac-clang--server-executable (ac-clang--build-server-launch-options))))
|
|
|
|
(if ac-clang--server-process
|
|
(progn
|
|
(setq ac-clang--status 'idle)
|
|
(ac-clang--clear-command-queue)
|
|
|
|
(set-process-coding-system ac-clang--server-process
|
|
(coding-system-change-eol-conversion buffer-file-coding-system nil)
|
|
'binary)
|
|
(set-process-filter ac-clang--server-process 'ac-clang--process-filter)
|
|
(set-process-query-on-exit-flag ac-clang--server-process nil)
|
|
|
|
(ac-clang--send-clang-parameters-request)
|
|
t)
|
|
(display-warning 'ac-clang "clang-server launch failed.")
|
|
nil)))
|
|
|
|
|
|
(defun ac-clang-shutdown-server ()
|
|
(interactive)
|
|
|
|
(when ac-clang--server-process
|
|
(ac-clang--send-shutdown-request)
|
|
|
|
(setq ac-clang--status 'shutdown)
|
|
|
|
(setq ac-clang--server-process nil)
|
|
t))
|
|
|
|
|
|
(defun ac-clang-update-clang-parameters ()
|
|
(interactive)
|
|
|
|
(when ac-clang--server-process
|
|
(ac-clang--send-clang-parameters-request)
|
|
t))
|
|
|
|
|
|
(defun ac-clang-reset-server ()
|
|
(interactive)
|
|
|
|
(when ac-clang--server-process
|
|
(cl-dolist (buffer ac-clang--activate-buffers)
|
|
(with-current-buffer buffer
|
|
(ac-clang-deactivate)))
|
|
(ac-clang--send-reset-server-request)))
|
|
|
|
|
|
(cl-defun ac-clang-reboot-server ()
|
|
(interactive)
|
|
|
|
(let ((buffers ac-clang--activate-buffers))
|
|
(ac-clang-reset-server)
|
|
|
|
(unless (ac-clang-shutdown-server)
|
|
(message "ac-clang : reboot server failed.")
|
|
(cl-return-from ac-clang-reset-server nil))
|
|
|
|
(unless (ac-clang-launch-server)
|
|
(message "ac-clang : reboot server failed.")
|
|
(cl-return-from ac-clang-reset-server nil))
|
|
|
|
(cl-dolist (buffer buffers)
|
|
(with-current-buffer buffer
|
|
(ac-clang-activate))))
|
|
|
|
(message "ac-clang : reboot server success.")
|
|
t)
|
|
|
|
|
|
|
|
|
|
(defun ac-clang-initialize ()
|
|
(interactive)
|
|
|
|
;; server binary decide
|
|
(unless ac-clang--server-executable
|
|
(setq ac-clang--server-executable (executable-find (or (plist-get ac-clang--server-binaries ac-clang-server-type) ""))))
|
|
|
|
;; check obsolete
|
|
(unless ac-clang--server-executable
|
|
(when (setq ac-clang--server-executable (executable-find (or (plist-get ac-clang--server-obsolete-binaries ac-clang-server-type) "")))
|
|
(display-warning 'ac-clang "The clang-server which you are using is obsolete. please replace to the new binary.")))
|
|
|
|
;; (message "ac-clang-initialize")
|
|
(if ac-clang--server-executable
|
|
(when (ac-clang-launch-server)
|
|
;; Optional keybindings
|
|
(define-key ac-mode-map (kbd "M-.") 'ac-clang-jump-smart)
|
|
(define-key ac-mode-map (kbd "M-,") 'ac-clang-jump-back)
|
|
;; (define-key ac-mode-map (kbd "C-c `") 'ac-clang-diagnostics))
|
|
|
|
(add-hook 'kill-emacs-hook 'ac-clang-finalize)
|
|
|
|
(when (and (eq system-type 'windows-nt) (boundp 'w32-pipe-read-delay) (> w32-pipe-read-delay 0))
|
|
(display-warning 'ac-clang "Please set the appropriate value for `w32-pipe-read-delay'. Because a pipe delay value is large value. Ideal value is 0. see help of `w32-pipe-read-delay'."))
|
|
|
|
t)
|
|
(display-warning 'ac-clang "clang-server binary not found.")
|
|
nil))
|
|
|
|
|
|
(defun ac-clang-finalize ()
|
|
(interactive)
|
|
|
|
;; (message "ac-clang-finalize")
|
|
(when (ac-clang-shutdown-server)
|
|
(define-key ac-mode-map (kbd "M-.") nil)
|
|
(define-key ac-mode-map (kbd "M-,") nil)
|
|
|
|
(setq ac-clang--server-executable nil)
|
|
|
|
(when ac-clang-tmp-pch-automatic-cleanup-p
|
|
(ac-clang--clean-tmp-pch))
|
|
|
|
t))
|
|
|
|
|
|
|
|
|
|
|
|
(provide 'ac-clang)
|
|
|
|
;; Local Variables:
|
|
;; coding: utf-8
|
|
;; indent-tabs-mode: nil
|
|
;; End:
|
|
|
|
;;; ac-clang.el ends here
|