Home | History | Annotate | Download | only in clang
      1 ;;; clang-rename.el --- Renames every occurrence of a symbol found at <offset>.  -*- lexical-binding: t; -*-
      2 
      3 ;; Keywords: tools, c
      4 
      5 ;;; Commentary:
      6 
      7 ;; To install clang-rename.el make sure the directory of this file is in your
      8 ;; `load-path' and add
      9 ;;
     10 ;;   (require 'clang-rename)
     11 ;;
     12 ;; to your .emacs configuration.
     13 
     14 ;;; Code:
     15 
     16 (defgroup clang-rename nil
     17   "Integration with clang-rename"
     18   :group 'c)
     19 
     20 (defcustom clang-rename-binary "clang-rename"
     21   "Path to clang-rename executable."
     22   :type '(file :must-match t)
     23   :group 'clang-rename)
     24 
     25 ;;;###autoload
     26 (defun clang-rename (new-name)
     27   "Rename all instances of the symbol at point to NEW-NAME using clang-rename."
     28   (interactive "sEnter a new name: ")
     29   (save-some-buffers :all)
     30   ;; clang-rename should not be combined with other operations when undoing.
     31   (undo-boundary)
     32   (let ((output-buffer (get-buffer-create "*clang-rename*")))
     33     (with-current-buffer output-buffer (erase-buffer))
     34     (let ((exit-code (call-process
     35                       clang-rename-binary nil output-buffer nil
     36                       (format "-offset=%d"
     37                               ;; clang-rename wants file (byte) offsets, not
     38                               ;; buffer (character) positions.
     39                               (clang-rename--bufferpos-to-filepos
     40                                ;; Emacs treats one character after a symbol as
     41                                ;; part of the symbol, but clang-rename doesnt.
     42                                ;; Use the beginning of the current symbol, if
     43                                ;; available, to resolve the inconsistency.
     44                                (or (car (bounds-of-thing-at-point 'symbol))
     45                                    (point))
     46                                'exact))
     47                       (format "-new-name=%s" new-name)
     48                       "-i" (buffer-file-name))))
     49       (if (and (integerp exit-code) (zerop exit-code))
     50           ;; Success; revert current buffer so it gets the modifications.
     51           (progn
     52             (kill-buffer output-buffer)
     53             (revert-buffer :ignore-auto :noconfirm :preserve-modes))
     54         ;; Failure; append exit code to output buffer and display it.
     55         (let ((message (clang-rename--format-message
     56                         "clang-rename failed with %s %s"
     57                         (if (integerp exit-code) "exit status" "signal")
     58                         exit-code)))
     59           (with-current-buffer output-buffer
     60             (insert ?\n message ?\n))
     61           (message "%s" message)
     62           (display-buffer output-buffer))))))
     63 
     64 (defalias 'clang-rename--bufferpos-to-filepos
     65   (if (fboundp 'bufferpos-to-filepos)
     66       'bufferpos-to-filepos
     67     ;; Emacs 24 doesnt have bufferpos-to-filepos, simulate it using
     68     ;; position-bytes.
     69     (lambda (position &optional _quality _coding-system)
     70       (1- (position-bytes position)))))
     71 
     72 ;; format-message is new in Emacs 25.1.  Provide a fallback for older
     73 ;; versions.
     74 (defalias 'clang-rename--format-message
     75   (if (fboundp 'format-message) 'format-message 'format))
     76 
     77 (provide 'clang-rename)
     78 
     79 ;;; clang-rename.el ends here
     80