forked from OSchip/llvm-project
[clang-include-fixer] Added Emacs integration for clang-include-fixer.
Patch by Jens Massberg! Thanks a lot. Differential Revision: https://reviews.llvm.org/D22805 llvm-svn: 276853
This commit is contained in:
parent
470b81ca69
commit
57d070e6fd
|
@ -75,6 +75,25 @@ You can customize the number of headers being shown by setting
|
|||
|
||||
See ``clang-include-fixer.py`` for more details.
|
||||
|
||||
Integrate with Emacs
|
||||
--------------------
|
||||
To run `clang-include-fixer` on a potentially unsaved buffer in Emacs.
|
||||
Ensure that Emacs finds ``clang-include-fixer.el`` by adding the directory containing the file to the ``load-path``
|
||||
and requiring the `clang-include-fixer` in your ```.emacs``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
(add-to-list 'load-path "path/to/llvm/source/tools/clang/tools/extra/include-fixer/tool/"
|
||||
(require 'clang-include-fixer)
|
||||
|
||||
Within Emacs the tool can be invoked with the command ``M-x clang-include-fixer``.
|
||||
|
||||
Make sure Emacs can find :program:`clang-include-fixer`:
|
||||
|
||||
- Add the path to :program:`clang-include-fixer` to the PATH environment variable.
|
||||
|
||||
See ``clang-include-fixer.el`` for more details.
|
||||
|
||||
How it Works
|
||||
============
|
||||
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
;;; clang-include-fxier.el --- Emacs integration of the clang include fixer
|
||||
|
||||
;; Keywords: tools, c
|
||||
;; Package-Requires: ((json "1.2"))
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This package allows to invoke the 'clang-include-fixer' within Emacs.
|
||||
;; 'clang-include-fixer' provides an automated way of adding #include
|
||||
;; directives for missing symbols in one translation unit, see
|
||||
;; <http://clang.llvm.org/extra/include-fixer.html>.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'json)
|
||||
|
||||
(defgroup clang-include-fixer nil
|
||||
"Include fixer."
|
||||
:group 'tools)
|
||||
|
||||
(defcustom clang-include-fixer-executable
|
||||
"clang-include-fixer"
|
||||
"Location of the `clang-include-fixer' executable.
|
||||
|
||||
A string containing the name or the full path of the executable."
|
||||
:group 'clang-include-fixer
|
||||
:type 'string
|
||||
:risky t)
|
||||
|
||||
(defcustom clang-include-fixer-input-format
|
||||
"yaml"
|
||||
"clang-include-fixer input format."
|
||||
:group 'clang-include-fixer
|
||||
:type 'string
|
||||
:risky t)
|
||||
|
||||
(defcustom clang-include-fixer-init-string
|
||||
""
|
||||
"clang-include-fixer input format."
|
||||
:group 'clang-include-fixer
|
||||
:type 'string
|
||||
:risky t)
|
||||
|
||||
|
||||
(defun clang-include-fixer-call-executable (callee
|
||||
include-fixer-parameter-a
|
||||
&optional include-fixer-parameter-b
|
||||
&optional include-fixer-parameter-c
|
||||
)
|
||||
"Calls clang-include-fixer with parameters INCLUDE-FIXER-PARAMETER-[ABC].
|
||||
If the call was successful the returned result is stored in a temp buffer
|
||||
and the function CALLEE is called on this temp buffer."
|
||||
|
||||
(let ((temp-buffer (generate-new-buffer " *clang-include-fixer-temp*"))
|
||||
(temp-file (make-temp-file "clang-include-fixer")))
|
||||
(unwind-protect
|
||||
(let (status stderr operations)
|
||||
(if (eq include-fixer-parameter-c nil)
|
||||
(setq status
|
||||
(call-process-region
|
||||
(point-min) (point-max) clang-include-fixer-executable
|
||||
nil `(,temp-buffer ,temp-file) nil
|
||||
|
||||
"-stdin"
|
||||
include-fixer-parameter-a
|
||||
(buffer-file-name)
|
||||
))
|
||||
(setq status
|
||||
(call-process-region
|
||||
(point-min) (point-max) clang-include-fixer-executable
|
||||
nil `(,temp-buffer ,temp-file) nil
|
||||
|
||||
"-stdin"
|
||||
include-fixer-parameter-a
|
||||
include-fixer-parameter-b
|
||||
include-fixer-parameter-c
|
||||
(buffer-file-name)
|
||||
)))
|
||||
|
||||
(setq stderr
|
||||
(with-temp-buffer
|
||||
(insert-file-contents temp-file)
|
||||
(when (> (point-max) (point-min))
|
||||
(insert ": "))
|
||||
(buffer-substring-no-properties
|
||||
(point-min) (line-end-position))))
|
||||
|
||||
(cond
|
||||
((stringp status)
|
||||
(error "(clang-include-fixer killed by signal %s%s)" status
|
||||
stderr))
|
||||
((not (equal 0 status))
|
||||
(error "(clang-include-fixer failed with code %d%s)" status
|
||||
stderr)))
|
||||
(funcall callee temp-buffer))
|
||||
(delete-file temp-file)
|
||||
(when (buffer-name temp-buffer) (kill-buffer temp-buffer)))))
|
||||
|
||||
|
||||
(defun clang-include-fixer-replace_buffer (temp-buffer)
|
||||
"Replace current buffer by content of TEMP-BUFFER"
|
||||
|
||||
(with-current-buffer temp-buffer
|
||||
(setq temp-start (point-min))
|
||||
(setq temp-end (point-max))
|
||||
)
|
||||
(barf-if-buffer-read-only)
|
||||
(erase-buffer)
|
||||
(save-excursion
|
||||
(insert-buffer-substring temp-buffer temp-start temp-end)))
|
||||
|
||||
|
||||
(defun clang-include-fixer-add-header (temp-buffer)
|
||||
"Analyse the result of include-fixer stored in TEMP_BUFFER and add a
|
||||
missing header if there is any. If there are multiple possible headers
|
||||
the user can select one of them to be included."
|
||||
|
||||
(with-current-buffer temp-buffer
|
||||
(setq result (buffer-substring (point-min) (point-max)))
|
||||
(setq include-fixer-context
|
||||
(let ((json-object-type 'plist))
|
||||
(json-read-from-string result))))
|
||||
|
||||
;; The header-infos is already sorted by include-fixer.
|
||||
(setq header-infos (plist-get include-fixer-context :HeaderInfos))
|
||||
(setq query-symbol-infos (plist-get include-fixer-context :QuerySymbolInfos))
|
||||
|
||||
(if (eq 0 (length query-symbol-infos))
|
||||
(message "The file is fine, no need to add a header.")
|
||||
|
||||
(setq symbol-info (elt query-symbol-infos 0))
|
||||
(setq symbol (plist-get symbol-info :RawIdentifier))
|
||||
(setq symbol-offset (plist-get (plist-get symbol-info :Range)
|
||||
:Offset))
|
||||
|
||||
;; Check the number of choices
|
||||
(if (eq 0 (length header-infos))
|
||||
(progn
|
||||
(goto-char (1+ symbol-offset))
|
||||
(message (concat "Couldn't find header for '" symbol "'.")))
|
||||
|
||||
(setq symbol-length (plist-get (plist-get symbol-info :Range)
|
||||
:Length))
|
||||
(goto-char (1+ symbol-offset))
|
||||
(setq symbol-overlay (make-overlay (1+ symbol-offset)
|
||||
(+ symbol-offset symbol-length +1)))
|
||||
(overlay-put symbol-overlay 'face '(:background "green" :foreground
|
||||
"black"))
|
||||
|
||||
(message (number-to-string symbol-offset))
|
||||
(message (number-to-string symbol-length))
|
||||
|
||||
(if (eq 1 (length header-infos))
|
||||
(progn
|
||||
(setq missing-header
|
||||
(plist-get (elt header-infos 0) :Header))
|
||||
(message (concat "Only one include is missing: "
|
||||
missing-header )))
|
||||
|
||||
;; Now iterate over vector and add items to list
|
||||
(setq include-list '())
|
||||
(setq index 0)
|
||||
(while (< index (length header-infos))
|
||||
(setq entry (elt header-infos index))
|
||||
(add-to-list 'include-list (plist-get entry :Header))
|
||||
(setq index (1+ index))
|
||||
)
|
||||
|
||||
(setq option-message (concat "Select include for '"
|
||||
symbol
|
||||
"' :"))
|
||||
(setq missing-header (ido-completing-read
|
||||
option-message include-list)))
|
||||
|
||||
;; Now select set correct header info.
|
||||
(setq header-plist '())
|
||||
(setq index 0)
|
||||
(while (< index (length header-infos))
|
||||
(setq entry (elt header-infos index))
|
||||
(setq index (1+ index))
|
||||
(if (eq (plist-get entry :Header) missing-header)
|
||||
(setq header-plist entry)))
|
||||
(setq include-fixer-context (plist-put
|
||||
include-fixer-context
|
||||
':HeaderInfos (vector header-plist)))
|
||||
|
||||
(clang-include-fixer-call-executable
|
||||
'clang-include-fixer-replace_buffer
|
||||
(concat "-insert-header=" (json-encode include-fixer-context)))
|
||||
(delete-overlay symbol-overlay))))
|
||||
|
||||
|
||||
(defun clang-include-fixer ()
|
||||
"Invokes the Include Fixer to insert missing C++ headers."
|
||||
(interactive)
|
||||
|
||||
(message (concat "Calling the include fixer. "
|
||||
"This might take some seconds. Please wait."))
|
||||
|
||||
(clang-include-fixer-call-executable
|
||||
'clang-include-fixer-add-header
|
||||
(concat "-db=" clang-include-fixer-input-format)
|
||||
(concat "-input=" clang-include-fixer-init-string)
|
||||
"-output-headers"))
|
||||
|
||||
(provide 'clang-include-fixer)
|
||||
;;; clang-include-fixer.el ends here
|
Loading…
Reference in New Issue