summaryrefslogtreecommitdiff
path: root/elpa/js2-highlight-vars-20170418.1829/js2-highlight-vars.el
blob: 5eb754c7a2a67a930183d87a7f1438ff2bd1d128 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
;;; js2-highlight-vars.el --- highlight occurrences of the variable under cursor

;; Copyright (C) 2009  Free Software Foundation, Inc.
;; Author:  Mihai Bazon <mihai.bazon@gmail.com>
;; Version: 0.1.0
;; Package-Version: 20170418.1829
;; Package-Commit: e3bb177e50f76b272e8073a94d4f46be6512a163
;; URL: http://mihai.bazon.net/projects/editing-javascript-with-emacs-js2-mode/js2-highlight-vars-mode
;; Package-Requires: ((emacs "24.4") (js2-mode "20150908"))

;;; Commentary:
;;
;; This is a minor mode on top of js2-mode which highlights all
;; occurrences of the variable under the cursor within its defining
;; scope.

;;; Installation:
;;
;; Install this package from MELPA using `M-x install-package` and put
;; the following in your ~/.emacs.d/init.el:
;; (eval-after-load "js2-highlight-vars-autoloads"
;;   '(add-hook 'js2-mode-hook (lambda () (js2-highlight-vars-mode))))
;;
;; If you aren't already using MELPA, see:
;; http://melpa.milkbox.net/#/getting-started

;; GNU Emacs 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,
;; 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/>.

;;; Code:

(require 'js2-mode)

(js2-deflocal js2-highlight-vars-mode nil)

(defface js2-highlight-vars-face
  `((((class color) (background light))
     (:background "light green"))
    (((class color) (background dark))
     (:background "royal blue")))
  "Face for highlighting variables"
  :group 'js2-mode)

(defface js2-highlight-vars-second-face
  `((((class color) (background light))
     (:background "light pink"))
    (((class color) (background dark))
     (:background "blue violet")))
  "Face for highlighting variables"
  :group 'js2-mode)

(defvar js2-highlight-vars-local-keymap
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "M-n")       'js2-highlight-vars-next)
    (define-key map (kbd "C-<down>")  'js2-highlight-vars-next)
    (define-key map (kbd "M-p")       'js2-highlight-vars-prev)
    (define-key map (kbd "C-<up>")    'js2-highlight-vars-prev)
    (define-key map (kbd "M-r")       'js2-highlight-vars-rename)
    map))

(js2-deflocal js2--highlight-vars-tokens nil)
(js2-deflocal js2--highlight-vars-current-token nil)
(js2-deflocal js2--highlight-vars-current-token-name nil)
(js2-deflocal js2--highlight-vars-post-command-timer nil)

(defun js2--do-highlight-vars ()
  "Highlight variable under cursor within the defining scope"
  (interactive)
  (setq js2--highlight-vars-post-command-timer nil)
  (unless js2--highlight-vars-tokens
    (let ((node (js2-node-at-point))
          (tokens nil)
          name
          scope)
      (unless (js2-name-node-p node)
        (setq node (js2-node-at-point (- (point) 1))))
      (when (and node (js2-name-node-p node))
        (setq scope (js2-node-get-enclosing-scope node)
              name (js2-name-node-name node)
              js2--highlight-vars-current-token (js2-node-abs-pos node)
              js2--highlight-vars-current-token-name name)
        (setq scope (js2-get-defining-scope scope name))
        (with-silent-modifications
          (js2-visit-ast
           scope
           (lambda (node end-p)
             (when (and (not end-p)
                        (js2-name-node-p node)
                        (string= name (js2-name-node-name node)))
               (let* ((beg (js2-node-abs-pos node))
                      (end (+ beg (js2-node-len node)))
                      (new-scope (js2-node-get-enclosing-scope node))
                      (new-scope (js2-get-defining-scope new-scope name))
                      (ovl (make-overlay beg end)))
                 (add-to-list 'tokens beg t)
                 (overlay-put ovl 'keymap js2-highlight-vars-local-keymap)
                 (overlay-put ovl 'face
                              (if (eq new-scope scope)
                                  'js2-highlight-vars-face
                                'js2-highlight-vars-second-face))
                 (overlay-put ovl 'evaporate t)
                 (overlay-put ovl 'js2-highlight-vars t)))
             t)))
        (setq js2--highlight-vars-tokens tokens)))))

(defun js2-highlight-vars-next ()
  (interactive)
  (let ((inhibit-point-motion-hooks t)
        (diff (- (point) js2--highlight-vars-current-token))
        (next (catch 'done
                (dolist (pos js2--highlight-vars-tokens)
                  (when (> pos (point))
                    (throw 'done pos))))))
    (when next
      (setq js2--highlight-vars-current-token next)
      (goto-char next)
      (forward-char diff))))

(defun js2-highlight-vars-prev ()
  (interactive)
  (let ((inhibit-point-motion-hooks t)
        (diff (- (point) js2--highlight-vars-current-token))
        (prev (catch 'done
                (dolist (pos (reverse js2--highlight-vars-tokens))
                  (when (and (< pos (point))
                             (not (= pos js2--highlight-vars-current-token)))
                    (throw 'done pos))))))
    (when prev
      (setq js2--highlight-vars-current-token prev)
      (goto-char prev)
      (forward-char diff))))

(defun js2-highlight-vars-rename (new-name)
  (interactive "*sRename variable to: ")
  (let ((len (length js2--highlight-vars-current-token-name))
        (inhibit-point-motion-hooks t)
        (ovl (make-overlay 1 1))
        (all nil)
        doit)
    (unwind-protect
        (progn
          (overlay-put ovl 'face 'highlight)
          (dolist (pos (mapcar (lambda(pos)
                                 (let ((m (make-marker)))
                                   (set-marker m pos))) js2--highlight-vars-tokens))
            (goto-char pos)
            (move-overlay ovl pos (+ pos len))
            (setq doit (if all
                           ?y
                         (read-char "Replace this occurrence? (y/n/!)")))
            (when (= doit ?!)
              (setq all t
                    doit ?y))
            (when (= doit ?y)
              (insert new-name)
              (delete-char len))))
      (delete-overlay ovl))))

(defun js2--unhighlight-vars (&rest ignore)
  (setq js2--highlight-vars-tokens nil
        js2--highlight-vars-current-token nil)
  (remove-overlays (point-min) (point-max)
                   'js2-highlight-vars t))

(defun js2-highlight-vars-post-command-hook ()
  (ignore-errors
    (let* ((overlays (overlays-at (point)))
           (ovl (and overlays
                     (catch 'found
                       (dolist (ovl overlays)
                         (when (overlay-get ovl 'js2-highlight-vars)
                           (throw 'found ovl)))
                       nil))))
      (if (and ovl
               (string= js2--highlight-vars-current-token-name
                        (buffer-substring (overlay-start ovl)
                                          (overlay-end ovl))))
          (setq js2--highlight-vars-current-token (overlay-start ovl))
        (js2--unhighlight-vars)
        (when js2--highlight-vars-post-command-timer
          (cancel-timer js2--highlight-vars-post-command-timer))
        (setq js2--highlight-vars-post-command-timer
              (run-with-timer 0.5 nil 'js2--do-highlight-vars))))))

;;;###autoload
(define-minor-mode js2-highlight-vars-mode
  "Minor mode that highlights occurrences of the variable under
cursor in js2-mode buffers"
  nil " vars" nil
  (if js2-highlight-vars-mode
      (progn
        (add-hook 'post-command-hook 'js2-highlight-vars-post-command-hook nil t))
    (remove-hook 'post-command-hook 'js2-highlight-vars-post-command-hook t)
    (js2--unhighlight-vars)
    (kill-local-variable js2--highlight-vars-tokens)
    (kill-local-variable js2--highlight-vars-current-token)))

(provide 'js2-highlight-vars)

;;; js2-highlight-vars.el ends here