587 lines
24 KiB
EmacsLisp
587 lines
24 KiB
EmacsLisp
;;; bungee.el --- Fast symbol navigation with Elisp-based caching -*- lexical-binding: t; -*-
|
|
|
|
;;; Commentary:
|
|
;; Bungee provides fast symbol navigation for C++ and QML files using
|
|
;; an Elisp-based cache system. It can work standalone or with the
|
|
;; Python symbol_finder.py for indexing.
|
|
|
|
;;; Code:
|
|
|
|
(require 'json)
|
|
(require 'cl-lib)
|
|
(require 'xref nil t)
|
|
(require 'pulse nil t)
|
|
(require 'grep nil t)
|
|
|
|
(defgroup bungee nil
|
|
"Fast symbol navigation with caching."
|
|
:group 'tools)
|
|
|
|
(defcustom bungee-cache-directory ".symbol_cache"
|
|
"Directory for symbol cache files."
|
|
:type 'string
|
|
:group 'bungee)
|
|
|
|
(defcustom bungee-python-indexer nil
|
|
"Path to Python indexer script (optional). If nil, use Elisp indexer."
|
|
:type '(choice (const :tag "Use Elisp indexer" nil)
|
|
(file :tag "Python script path"))
|
|
:group 'bungee)
|
|
|
|
(defcustom bungee-auto-update t
|
|
"Automatically update cache when files change."
|
|
:type 'boolean
|
|
:group 'bungee)
|
|
|
|
(defcustom bungee-save-json-cache nil
|
|
"Also save cache in JSON format for Python compatibility."
|
|
:type 'boolean
|
|
:group 'bungee)
|
|
|
|
;; Cache data structures
|
|
(defvar bungee--symbol-cache nil
|
|
"In-memory symbol cache. Hash table mapping file paths to symbol lists.")
|
|
|
|
(defvar bungee--index-cache nil
|
|
"In-memory index cache. Hash table mapping file paths to modification times.")
|
|
|
|
(defvar bungee--cache-loaded nil
|
|
"Whether the cache has been loaded from disk.")
|
|
|
|
(cl-defstruct bungee-symbol
|
|
"A symbol in the codebase."
|
|
name ; Symbol name
|
|
file-path ; Absolute file path
|
|
line-number ; Line number (1-based)
|
|
symbol-type ; 'class, 'function, 'property, etc.
|
|
context) ; Line content for context
|
|
|
|
;; Cache management functions
|
|
(defun bungee--cache-dir ()
|
|
"Get the cache directory path."
|
|
(let ((root (or (and (fboundp 'project-current)
|
|
(project-current)
|
|
(fboundp 'project-root)
|
|
(ignore-errors
|
|
(car (project-roots (project-current)))))
|
|
default-directory)))
|
|
(expand-file-name bungee-cache-directory root)))
|
|
|
|
(defun bungee--cache-file-path (filename)
|
|
"Get path for cache FILENAME."
|
|
(expand-file-name filename (bungee--cache-dir)))
|
|
|
|
(defun bungee--load-cache ()
|
|
"Load cache from disk into memory."
|
|
(let ((cache-file (bungee--cache-file-path "bungee-cache.el"))
|
|
(json-symbols-file (bungee--cache-file-path "symbols.json"))
|
|
(json-index-file (bungee--cache-file-path "index.json")))
|
|
|
|
;; Initialize hash tables
|
|
(setq bungee--symbol-cache (make-hash-table :test 'equal))
|
|
(setq bungee--index-cache (make-hash-table :test 'equal))
|
|
|
|
(cond
|
|
;; Prefer Elisp cache if it exists
|
|
((file-exists-p cache-file)
|
|
(load cache-file nil t)
|
|
;; Convert loaded lists back to symbol structs
|
|
(let ((new-cache (make-hash-table :test 'equal)))
|
|
(maphash (lambda (file-path symbol-lists)
|
|
(puthash file-path
|
|
(mapcar (lambda (s)
|
|
(make-bungee-symbol
|
|
:name (nth 0 s)
|
|
:file-path (nth 1 s)
|
|
:line-number (nth 2 s)
|
|
:symbol-type (nth 3 s)
|
|
:context (nth 4 s)))
|
|
symbol-lists)
|
|
new-cache))
|
|
bungee--symbol-cache)
|
|
(setq bungee--symbol-cache new-cache))
|
|
(message "Loaded Elisp cache: %d files" (hash-table-count bungee--index-cache)))
|
|
|
|
;; Fall back to JSON if available
|
|
((and (file-exists-p json-symbols-file) (file-exists-p json-index-file))
|
|
(bungee--load-json-cache json-symbols-file json-index-file)
|
|
(message "Loaded JSON cache: %d files" (hash-table-count bungee--index-cache)))
|
|
|
|
(t
|
|
(message "No cache found. Run `bungee-index-directory' to create one.")))
|
|
|
|
(setq bungee--cache-loaded t)))
|
|
|
|
(defun bungee--load-json-cache (symbols-file index-file)
|
|
"Load JSON cache from SYMBOLS-FILE and INDEX-FILE."
|
|
;; Load symbols
|
|
(when (file-exists-p symbols-file)
|
|
(let* ((json-object-type 'hash-table)
|
|
(json-array-type 'list)
|
|
(json-key-type 'string)
|
|
(symbols-data (json-read-file symbols-file)))
|
|
(maphash (lambda (file-path symbols-list)
|
|
(let ((symbols (mapcar (lambda (s)
|
|
(make-bungee-symbol
|
|
:name (gethash "name" s)
|
|
:file-path (gethash "file_path" s)
|
|
:line-number (gethash "line_number" s)
|
|
:symbol-type (intern (gethash "symbol_type" s))
|
|
:context (gethash "context" s)))
|
|
symbols-list)))
|
|
(puthash file-path symbols bungee--symbol-cache)))
|
|
symbols-data)))
|
|
|
|
;; Load index
|
|
(when (file-exists-p index-file)
|
|
(let* ((json-object-type 'hash-table)
|
|
(json-key-type 'string)
|
|
(index-data (json-read-file index-file)))
|
|
(maphash (lambda (file-path info)
|
|
(puthash file-path (gethash "mtime" info) bungee--index-cache))
|
|
index-data))))
|
|
|
|
(defun bungee--ensure-cache ()
|
|
"Ensure cache is loaded."
|
|
(unless bungee--cache-loaded
|
|
(bungee--load-cache)))
|
|
|
|
(defun bungee--save-cache ()
|
|
"Save in-memory cache to disk as Elisp code."
|
|
(let ((cache-dir (bungee--cache-dir)))
|
|
(unless (file-exists-p cache-dir)
|
|
(make-directory cache-dir t))
|
|
|
|
;; Save as Elisp file for fast loading
|
|
(with-temp-file (bungee--cache-file-path "bungee-cache.el")
|
|
(insert ";;; bungee-cache.el --- Bungee symbol cache -*- lexical-binding: t; -*-\n")
|
|
(insert ";;; This file is auto-generated. Do not edit.\n\n")
|
|
|
|
;; Save symbol cache
|
|
(insert "(setq bungee--symbol-cache (make-hash-table :test 'equal))\n\n")
|
|
(maphash (lambda (file-path symbols)
|
|
(insert (format "(puthash %S\n '(" (abbreviate-file-name file-path)))
|
|
(dolist (symbol symbols)
|
|
(insert (format "\n %S"
|
|
(list (bungee-symbol-name symbol)
|
|
(bungee-symbol-file-path symbol)
|
|
(bungee-symbol-line-number symbol)
|
|
(bungee-symbol-symbol-type symbol)
|
|
(bungee-symbol-context symbol)))))
|
|
(insert ")\n bungee--symbol-cache)\n\n"))
|
|
bungee--symbol-cache)
|
|
|
|
;; Save index cache
|
|
(insert "(setq bungee--index-cache (make-hash-table :test 'equal))\n\n")
|
|
(maphash (lambda (file-path mtime)
|
|
(insert (format "(puthash %S %S bungee--index-cache)\n"
|
|
(abbreviate-file-name file-path) mtime)))
|
|
bungee--index-cache)
|
|
|
|
(insert "\n;;; bungee-cache.el ends here\n"))
|
|
|
|
;; Optionally save as JSON for compatibility with Python tool
|
|
(when bungee-save-json-cache
|
|
(bungee--save-json-cache))))
|
|
|
|
(defun bungee--save-json-cache ()
|
|
"Save cache in JSON format for Python compatibility."
|
|
(let ((cache-dir (bungee--cache-dir)))
|
|
;; Save symbols
|
|
(let ((symbols-file (expand-file-name "symbols.json" cache-dir))
|
|
(symbols-data (make-hash-table :test 'equal)))
|
|
(maphash (lambda (file-path symbols)
|
|
(puthash file-path
|
|
(mapcar (lambda (s)
|
|
`((name . ,(bungee-symbol-name s))
|
|
(file_path . ,(bungee-symbol-file-path s))
|
|
(line_number . ,(bungee-symbol-line-number s))
|
|
(symbol_type . ,(symbol-name (bungee-symbol-symbol-type s)))
|
|
(context . ,(bungee-symbol-context s))))
|
|
symbols)
|
|
symbols-data))
|
|
bungee--symbol-cache)
|
|
(with-temp-file symbols-file
|
|
(insert (json-encode symbols-data))))
|
|
|
|
;; Save index
|
|
(let ((index-file (expand-file-name "index.json" cache-dir))
|
|
(index-data (make-hash-table :test 'equal)))
|
|
(maphash (lambda (file-path mtime)
|
|
(puthash file-path
|
|
`((mtime . ,mtime)
|
|
(symbol_count . ,(length (gethash file-path bungee--symbol-cache))))
|
|
index-data))
|
|
bungee--index-cache)
|
|
(with-temp-file index-file
|
|
(insert (json-encode index-data))))))
|
|
|
|
(defun bungee--file-cached-p (file-path)
|
|
"Check if FILE-PATH is cached and up to date."
|
|
(bungee--ensure-cache)
|
|
(let ((cached-mtime (gethash file-path bungee--index-cache))
|
|
(current-mtime (and (file-exists-p file-path)
|
|
(float-time (nth 5 (file-attributes file-path))))))
|
|
(and cached-mtime current-mtime (>= cached-mtime current-mtime))))
|
|
|
|
;; Elisp-based parsing
|
|
(defun bungee--parse-qml-file (file-path)
|
|
"Parse a QML file and extract symbols."
|
|
(let ((symbols '())
|
|
(case-fold-search nil))
|
|
(with-temp-buffer
|
|
(insert-file-contents file-path)
|
|
(goto-char (point-min))
|
|
|
|
;; Find QML types
|
|
(save-excursion
|
|
(while (re-search-forward "^\\s-*\\([A-Z]\\w*\\)\\s-*{" nil t)
|
|
(push (make-bungee-symbol
|
|
:name (match-string 1)
|
|
:file-path file-path
|
|
:line-number (line-number-at-pos)
|
|
:symbol-type 'class
|
|
:context (buffer-substring-no-properties
|
|
(line-beginning-position)
|
|
(line-end-position)))
|
|
symbols)))
|
|
|
|
;; Find properties (including readonly)
|
|
;; Format: [readonly] property <type> <name>
|
|
(goto-char (point-min))
|
|
(while (re-search-forward "^\\s-*\\(?:readonly\\s-+\\)?property\\s-+[\\w.<>]+\\s-+\\([a-zA-Z_]\\w*\\)" nil t)
|
|
(push (make-bungee-symbol
|
|
:name (match-string 1)
|
|
:file-path file-path
|
|
:line-number (line-number-at-pos)
|
|
:symbol-type 'property
|
|
:context (buffer-substring-no-properties
|
|
(line-beginning-position)
|
|
(line-end-position)))
|
|
symbols))
|
|
|
|
;; Find signals
|
|
(goto-char (point-min))
|
|
(while (re-search-forward "^\\s-*signal\\s-+\\([a-zA-Z_]\\w*\\)" nil t)
|
|
(push (make-bungee-symbol
|
|
:name (match-string 1)
|
|
:file-path file-path
|
|
:line-number (line-number-at-pos)
|
|
:symbol-type 'signal
|
|
:context (buffer-substring-no-properties
|
|
(line-beginning-position)
|
|
(line-end-position)))
|
|
symbols))
|
|
|
|
;; Find functions
|
|
(goto-char (point-min))
|
|
(while (re-search-forward "^\\s-*function\\s-+\\([a-zA-Z_]\\w*\\)\\s-*(" nil t)
|
|
(push (make-bungee-symbol
|
|
:name (match-string 1)
|
|
:file-path file-path
|
|
:line-number (line-number-at-pos)
|
|
:symbol-type 'function
|
|
:context (buffer-substring-no-properties
|
|
(line-beginning-position)
|
|
(line-end-position)))
|
|
symbols))
|
|
|
|
;; Find ids
|
|
(goto-char (point-min))
|
|
(while (re-search-forward "^\\s-*id:\\s-*\\([a-zA-Z_]\\w*\\)" nil t)
|
|
(push (make-bungee-symbol
|
|
:name (match-string 1)
|
|
:file-path file-path
|
|
:line-number (line-number-at-pos)
|
|
:symbol-type 'variable
|
|
:context (buffer-substring-no-properties
|
|
(line-beginning-position)
|
|
(line-end-position)))
|
|
symbols)))
|
|
|
|
(nreverse symbols)))
|
|
|
|
(defun bungee--parse-cpp-file (file-path)
|
|
"Parse a C++ file and extract symbols."
|
|
(let ((symbols '())
|
|
(case-fold-search nil))
|
|
(with-temp-buffer
|
|
(insert-file-contents file-path)
|
|
(goto-char (point-min))
|
|
|
|
;; Find classes/structs
|
|
(save-excursion
|
|
(while (re-search-forward "^\\s-*\\(?:class\\|struct\\|union\\)\\s-+\\([A-Za-z_]\\w*\\)" nil t)
|
|
(push (make-bungee-symbol
|
|
:name (match-string 1)
|
|
:file-path file-path
|
|
:line-number (line-number-at-pos)
|
|
:symbol-type 'class
|
|
:context (buffer-substring-no-properties
|
|
(line-beginning-position)
|
|
(line-end-position)))
|
|
symbols)))
|
|
|
|
;; Find namespaces
|
|
(goto-char (point-min))
|
|
(while (re-search-forward "^\\s-*namespace\\s-+\\([A-Za-z_]\\w*\\)" nil t)
|
|
(push (make-bungee-symbol
|
|
:name (match-string 1)
|
|
:file-path file-path
|
|
:line-number (line-number-at-pos)
|
|
:symbol-type 'namespace
|
|
:context (buffer-substring-no-properties
|
|
(line-beginning-position)
|
|
(line-end-position)))
|
|
symbols))
|
|
|
|
;; Find enums
|
|
(goto-char (point-min))
|
|
(while (re-search-forward "^\\s-*enum\\s-+\\(?:class\\s-+\\)?\\([A-Za-z_]\\w*\\)" nil t)
|
|
(push (make-bungee-symbol
|
|
:name (match-string 1)
|
|
:file-path file-path
|
|
:line-number (line-number-at-pos)
|
|
:symbol-type 'enum
|
|
:context (buffer-substring-no-properties
|
|
(line-beginning-position)
|
|
(line-end-position)))
|
|
symbols))
|
|
|
|
;; Basic function detection (simplified)
|
|
(goto-char (point-min))
|
|
(while (re-search-forward "^\\s-*\\(?:\\w+\\s-+\\)*\\([A-Za-z_]\\w*\\)\\s-*([^)]*)[^;{]*{" nil t)
|
|
(let ((name (match-string 1)))
|
|
(unless (member name '("if" "while" "for" "switch" "catch"))
|
|
(push (make-bungee-symbol
|
|
:name name
|
|
:file-path file-path
|
|
:line-number (line-number-at-pos)
|
|
:symbol-type 'function
|
|
:context (buffer-substring-no-properties
|
|
(line-beginning-position)
|
|
(line-end-position)))
|
|
symbols)))))
|
|
|
|
(nreverse symbols)))
|
|
|
|
(defun bungee--index-file (file-path &optional force)
|
|
"Index FILE-PATH. If FORCE is non-nil, reindex even if cached."
|
|
(bungee--ensure-cache)
|
|
(when (or force (not (bungee--file-cached-p file-path)))
|
|
(let ((symbols (cond
|
|
((string-match-p "\\.qml\\'" file-path)
|
|
(bungee--parse-qml-file file-path))
|
|
((string-match-p "\\.\\(cpp\\|cc\\|cxx\\|c\\+\\+\\|hpp\\|h\\|hh\\|hxx\\|h\\+\\+\\)\\'" file-path)
|
|
(bungee--parse-cpp-file file-path))
|
|
(t nil))))
|
|
(when symbols
|
|
(puthash file-path symbols bungee--symbol-cache)
|
|
(puthash file-path (float-time (nth 5 (file-attributes file-path))) bungee--index-cache)
|
|
(message "Indexed %s: %d symbols" file-path (length symbols))))))
|
|
|
|
;; Symbol lookup functions
|
|
(defun bungee-find-symbol (symbol-name &optional exact-match)
|
|
"Find all symbols matching SYMBOL-NAME. If EXACT-MATCH is non-nil, use exact matching."
|
|
(bungee--ensure-cache)
|
|
(let ((results '()))
|
|
(maphash (lambda (_ symbols)
|
|
(dolist (symbol symbols)
|
|
(when (if exact-match
|
|
(string= (bungee-symbol-name symbol) symbol-name)
|
|
(string-match-p (regexp-quote symbol-name)
|
|
(bungee-symbol-name symbol)))
|
|
(push symbol results))))
|
|
bungee--symbol-cache)
|
|
(sort results (lambda (a b)
|
|
(or (string< (bungee-symbol-name a) (bungee-symbol-name b))
|
|
(< (bungee-symbol-line-number a) (bungee-symbol-line-number b)))))))
|
|
|
|
(defun bungee-find-definition (symbol-name)
|
|
"Find the most likely definition of SYMBOL-NAME."
|
|
(let ((symbols (bungee-find-symbol symbol-name t)))
|
|
;; Prioritize by symbol type
|
|
(or (cl-find-if (lambda (s) (eq (bungee-symbol-symbol-type s) 'class)) symbols)
|
|
(cl-find-if (lambda (s) (eq (bungee-symbol-symbol-type s) 'namespace)) symbols)
|
|
(cl-find-if (lambda (s) (eq (bungee-symbol-symbol-type s) 'function)) symbols)
|
|
(cl-find-if (lambda (s) (eq (bungee-symbol-symbol-type s) 'property)) symbols)
|
|
(car symbols))))
|
|
|
|
;; Interactive commands
|
|
(defun bungee-jump-to-definition ()
|
|
"Jump to definition of symbol at point."
|
|
(interactive)
|
|
(let* ((symbol-name (or (thing-at-point 'symbol t)
|
|
(read-string "Symbol: ")))
|
|
(symbol (bungee-find-definition symbol-name)))
|
|
(if symbol
|
|
(progn
|
|
(push-mark)
|
|
(find-file (bungee-symbol-file-path symbol))
|
|
(goto-char (point-min))
|
|
(forward-line (1- (bungee-symbol-line-number symbol)))
|
|
(when (fboundp 'pulse-momentary-highlight-one-line)
|
|
(pulse-momentary-highlight-one-line (point)))
|
|
(message "Found: %s" (bungee-symbol-context symbol)))
|
|
(message "No definition found for '%s'" symbol-name))))
|
|
|
|
(defun bungee-find-references ()
|
|
"Find all references to symbol at point."
|
|
(interactive)
|
|
(let* ((symbol-name (or (thing-at-point 'symbol t)
|
|
(read-string "Find references to: ")))
|
|
(symbols (bungee-find-symbol symbol-name)))
|
|
(if symbols
|
|
(let ((buffer (get-buffer-create "*Bungee References*")))
|
|
(with-current-buffer buffer
|
|
(let ((inhibit-read-only t))
|
|
(erase-buffer)
|
|
(insert (format "References to '%s':\n\n" symbol-name))
|
|
(dolist (symbol symbols)
|
|
(insert (format "%s:%d: %s [%s]\n"
|
|
(bungee-symbol-file-path symbol)
|
|
(bungee-symbol-line-number symbol)
|
|
(bungee-symbol-context symbol)
|
|
(bungee-symbol-symbol-type symbol))))
|
|
(goto-char (point-min))
|
|
(grep-mode)))
|
|
(display-buffer buffer))
|
|
(message "No references found for '%s'" symbol-name))))
|
|
|
|
(defun bungee-index-directory (&optional directory force)
|
|
"Index all files in DIRECTORY. If FORCE is non-nil, reindex all files."
|
|
(interactive "DDirectory to index: \nP")
|
|
(let* ((dir (or directory default-directory))
|
|
(files (directory-files-recursively
|
|
dir
|
|
"\\.\\(qml\\|cpp\\|cc\\|cxx\\|c\\+\\+\\|hpp\\|h\\|hh\\|hxx\\|h\\+\\+\\)\\'"
|
|
nil
|
|
(lambda (d) (not (or (string-match-p "/\\." d)
|
|
(string-match-p "/node_modules" d)
|
|
(string-match-p "/CMakeFiles" d))))))
|
|
(count 0))
|
|
(dolist (file files)
|
|
(when (or force (not (bungee--file-cached-p file)))
|
|
(bungee--index-file file force)
|
|
(setq count (1+ count))))
|
|
(bungee--save-cache)
|
|
(message "Indexed %d files" count)))
|
|
|
|
(defun bungee-index-current-file ()
|
|
"Index or reindex the current file."
|
|
(interactive)
|
|
(when buffer-file-name
|
|
(bungee--index-file buffer-file-name t)
|
|
(bungee--save-cache)))
|
|
|
|
(defun bungee-cache-status ()
|
|
"Show cache status."
|
|
(interactive)
|
|
(bungee--ensure-cache)
|
|
(let ((file-count (hash-table-count bungee--index-cache))
|
|
(symbol-count 0))
|
|
(maphash (lambda (_ symbols)
|
|
(setq symbol-count (+ symbol-count (length symbols))))
|
|
bungee--symbol-cache)
|
|
(message "Bungee cache: %d files, %d symbols" file-count symbol-count)))
|
|
|
|
(defun bungee-clear-cache ()
|
|
"Clear the in-memory cache."
|
|
(interactive)
|
|
(setq bungee--symbol-cache nil
|
|
bungee--index-cache nil
|
|
bungee--cache-loaded nil)
|
|
(message "Bungee cache cleared"))
|
|
|
|
;; Python indexer integration (optional)
|
|
(defun bungee-index-with-python (&optional force)
|
|
"Index using Python script if configured."
|
|
(interactive "P")
|
|
(if bungee-python-indexer
|
|
(let* ((root (or (when (fboundp 'project-root)
|
|
(car (project-roots (project-current))))
|
|
default-directory))
|
|
(cmd (format "python3 %s --index %s --root %s --cache-dir %s"
|
|
(shell-quote-argument bungee-python-indexer)
|
|
(if force "--force" "")
|
|
(shell-quote-argument root)
|
|
(shell-quote-argument (bungee--cache-dir)))))
|
|
(message "Running: %s" cmd)
|
|
(shell-command cmd)
|
|
(bungee-clear-cache)
|
|
(bungee--load-cache))
|
|
(message "Python indexer not configured. Use `bungee-index-directory' instead.")))
|
|
|
|
;; Auto-update on save
|
|
(defun bungee--after-save-hook ()
|
|
"Update index after saving a file."
|
|
(when (and bungee-auto-update
|
|
buffer-file-name
|
|
(string-match-p "\\.\\(qml\\|cpp\\|cc\\|cxx\\|c\\+\\+\\|hpp\\|h\\|hh\\|hxx\\|h\\+\\+\\)\\'"
|
|
buffer-file-name))
|
|
(bungee--index-file buffer-file-name t)
|
|
(bungee--save-cache)))
|
|
|
|
;; Minor mode
|
|
(defvar bungee-mode-map
|
|
(let ((map (make-sparse-keymap)))
|
|
(define-key map (kbd "M-.") 'bungee-jump-to-definition)
|
|
(define-key map (kbd "M-?") 'bungee-find-references)
|
|
(define-key map (kbd "C-c b i") 'bungee-index-directory)
|
|
(define-key map (kbd "C-c b f") 'bungee-index-current-file)
|
|
(define-key map (kbd "C-c b s") 'bungee-cache-status)
|
|
(define-key map (kbd "C-c b c") 'bungee-clear-cache)
|
|
(define-key map (kbd "C-c b p") 'bungee-index-with-python)
|
|
map)
|
|
"Keymap for bungee-mode.")
|
|
|
|
;;;###autoload
|
|
(define-minor-mode bungee-mode
|
|
"Minor mode for fast symbol navigation with caching."
|
|
:lighter " Bungee"
|
|
:keymap bungee-mode-map
|
|
(if bungee-mode
|
|
(add-hook 'after-save-hook 'bungee--after-save-hook nil t)
|
|
(remove-hook 'after-save-hook 'bungee--after-save-hook t)))
|
|
|
|
;;;###autoload
|
|
(define-globalized-minor-mode global-bungee-mode
|
|
bungee-mode
|
|
(lambda ()
|
|
(when (and (not (minibufferp))
|
|
buffer-file-name
|
|
(string-match-p "\\.\\(qml\\|cpp\\|cc\\|cxx\\|c\\+\\+\\|hpp\\|h\\|hh\\|hxx\\|h\\+\\+\\)\\'"
|
|
buffer-file-name))
|
|
(bungee-mode 1))))
|
|
|
|
;; xref integration
|
|
(when (fboundp 'xref-make)
|
|
(defun bungee-xref-backend () 'bungee)
|
|
|
|
(cl-defmethod xref-backend-identifier-at-point ((_backend (eql bungee)))
|
|
(thing-at-point 'symbol t))
|
|
|
|
(cl-defmethod xref-backend-definitions ((_backend (eql bungee)) identifier)
|
|
(let ((symbol (bungee-find-definition identifier)))
|
|
(when symbol
|
|
(list (xref-make (bungee-symbol-context symbol)
|
|
(xref-make-file-location
|
|
(bungee-symbol-file-path symbol)
|
|
(bungee-symbol-line-number symbol)
|
|
0))))))
|
|
|
|
(cl-defmethod xref-backend-references ((_backend (eql bungee)) identifier)
|
|
(mapcar (lambda (symbol)
|
|
(xref-make (bungee-symbol-context symbol)
|
|
(xref-make-file-location
|
|
(bungee-symbol-file-path symbol)
|
|
(bungee-symbol-line-number symbol)
|
|
0)))
|
|
(bungee-find-symbol identifier)))
|
|
|
|
(add-hook 'bungee-mode-hook
|
|
(lambda ()
|
|
(add-hook 'xref-backend-functions 'bungee-xref-backend nil t))))
|
|
|
|
(provide 'bungee)
|
|
;;; bungee.el ends here |