(cl-defmethod xref-backend-references ((_backend (eql 'elisp)) identifier)
(let* ((pos (get-text-property 0 'pos identifier))
- (enable-local-variables nil)
(gc-cons-threshold (* 1024 1024 1024)))
(or (elisp-make-xrefs (and pos (elisp-local-references pos)))
(let (res
(unless (eq beg (caar lla))
(push (cons beg len) lla))))
(when lla
- (with-work-buffer
- (insert-file-contents file)
- (pcase-dolist (`(,beg . ,len) lla)
- (goto-char beg)
- (push
- (let* ((begg (pos-bol))
- (endd (pos-eol))
- (line (buffer-substring begg endd))
- (cur (- beg begg)))
- (add-face-text-property
- cur (+ len cur) 'xref-match t line)
- (xref-make-match
- line
- (xref-make-file-pos-location
- file beg (line-number-at-pos beg))
- len))
- all))))
+ (if-let ((buf (get-file-buffer file)))
+ (with-current-buffer buf
+ (save-excursion
+ (pcase-dolist (`(,beg . ,len) lla)
+ (goto-char beg)
+ (push
+ (let* ((begg (pos-bol))
+ (endd (pos-eol))
+ (line (buffer-substring begg endd))
+ (cur (- beg begg)))
+ (add-face-text-property
+ cur (+ len cur) 'xref-match t line)
+ (xref-make-match
+ line
+ (xref-make-file-pos-location
+ file beg (line-number-at-pos beg))
+ len))
+ all))))
+ (with-work-buffer
+ (insert-file-contents file)
+ (pcase-dolist (`(,beg . ,len) lla)
+ (goto-char beg)
+ (push
+ (let* ((begg (pos-bol))
+ (endd (pos-eol))
+ (line (buffer-substring begg endd))
+ (cur (- beg begg)))
+ (add-face-text-property
+ cur (+ len cur) 'xref-match t line)
+ (xref-make-match
+ line
+ (xref-make-file-pos-location
+ file beg (line-number-at-pos beg))
+ len))
+ all)))))
(when all (setq res (nconc res (nreverse all))))))
res))))
+(defun elisp-project-references (str typ)
+ (let (res
+ (types
+ (case (scope-get-symbol-type-property typ :namespace)
+ (face '(defface face))
+ (feature '(feature))
+ (widget-type '(widget-type))
+ (condition '(condition))
+ (icon '(deficon icon))
+ (coding '(defcoding coding))
+ (charset '(defcharset charset))
+ (variable '(defvar variable constant))
+ (symbol-type '(symbol-type symbol-type-definition))
+ (function '(defun function macro special-form major-mode)))))
+ (require 'project)
+ (dolist-with-progress-reporter
+ (file
+ (seq-filter
+ (lambda (file) (string= (file-name-extension file) "el"))
+ (project-files (project-current))))
+ "Scanning for references"
+ (let (hits)
+ (pcase-dolist (`(,type ,beg ,len . ,_) (gethash str (elisp-sym-name-index file)))
+ (when (or (null types) (memq type types))
+ (unless (eq beg (caar hits))
+ (push (cons beg len) hits))))
+ (when hits (push (cons file hits) res))))
+ (nreverse res)))
+
(defun elisp-make-xref (beg len)
(let* ((beg-end (save-excursion
(goto-char beg)
(defvar elisp-sym-name-index-cache (make-hash-table :test #'equal))
(defun elisp-sym-name-index (file)
- (let ((cached (gethash file elisp-sym-name-index-cache))
- (modtime (file-attribute-modification-time (file-attributes file))))
- (cdr
- (if (time-less-p (or (car cached) 0) modtime)
- (puthash file (cons modtime
- (with-work-buffer
- (setq lexical-binding t)
- (insert-file-contents file)
- (elisp-sym-name-index-1 file)))
- elisp-sym-name-index-cache)
- cached))))
-
-(defun elisp-sym-name-index-1 (file)
- (let ((all (make-hash-table :test #'equal)))
+ (if-let ((buf (get-file-buffer file))
+ ((buffer-modified-p buf)))
+ (with-current-buffer buf (elisp-sym-name-index-1 file))
+ (let ((cached (gethash file elisp-sym-name-index-cache))
+ (modtime (file-attribute-modification-time (file-attributes file))))
+ (cdr
+ (if (time-less-p (or (car cached) 0) modtime)
+ (puthash file (cons modtime
+ (with-work-buffer
+ (setq lexical-binding t)
+ (insert-file-contents file)
+ (elisp-sym-name-index-1 file)))
+ elisp-sym-name-index-cache)
+ cached)))))
+
+(defun elisp-sym-name-index-1 (source)
+ (let ((all (make-hash-table :test #'equal))
+ (scope-assume-func-p t))
(save-excursion
(goto-char (point-min))
(condition-case e
(list type beg len)
(gethash (buffer-substring beg (+ beg len)) all)))))
(end-of-file all)
- (error (message "Encountered error while scanning %s: %S" file e) all)))))
+ (error (message "Encountered error while scanning %s: %S" source e) all)))))
(provide 'elisp-mode)
;;; elisp-mode.el ends here
(defun elisp-refactor-backend () '(elisp rename extract))
(cl-defmethod refactor-backend-read-scoped-identifier ((_backend (eql elisp)))
- (let* ((pos (point)))
+ (let ((scope-assume-func-p t)
+ (pos (point)))
(save-excursion
(beginning-of-defun-raw)
(catch 'var-def
- (scope (lambda (_type beg len _id &optional def)
+ (scope (lambda (typ beg len _id &optional def)
(when (<= beg pos (+ beg len))
(throw 'var-def
(cons (propertize
(buffer-substring-no-properties beg (+ beg len))
- 'pos beg)
+ 'pos beg 'type typ)
(unless def 'project))))))
(user-error "No symbol to rename at point")))))
res))))
(cl-defmethod refactor-backend-rename-edits
- ((_backend (eql elisp)) _old _new (_scope (eql project)))
- (error "Not implemented"))
+ ((_backend (eql elisp)) old new (_scope (eql project)))
+ (let ((type (get-text-property 0 'typ old)))
+ (let (res)
+ (pcase-dolist (`(,file . ,hits) (elisp-project-references old type))
+ (push (cons file
+ (let (ser)
+ (pcase-dolist (`(,beg . ,len) hits)
+ (push (list beg (+ beg len) new) ser))
+ ser))
+ res))
+ res)))
(cl-defmethod refactor-backend-rename-highlight-regions
((_backend (eql elisp)) old (_scope (eql nil)))
(alist-set beg res (+ beg len)))
res))
+(cl-defmethod refactor-backend-rename-highlight-regions
+ ((_backend (eql elisp)) old (_scope (eql project)))
+ (let (res)
+ (pcase-dolist (`(,beg . ,len)
+ (alist-get buffer-file-name (elisp-project-references old (get-text-property 0 'type old)) nil nil #'string=))
+ (alist-set beg res (+ beg len)))
+ res))
+
(cl-defmethod refactor-backend-extract-validate-region
((_backend (eql elisp)) beg end)
(unless (ignore-errors (read (buffer-substring beg end)) t)