smart-jump icon indicating copy to clipboard operation
smart-jump copied to clipboard

#+TITLE: Smart Jump

[[https://travis-ci.org/jojojames/smart-jump][file:https://travis-ci.org/jojojames/smart-jump.svg?branch=master]] [[https://melpa.org/#/smart-jump][file:https://melpa.org/packages/smart-jump-badge.svg]]

  • About This packages tries to smartly go to definition leveraging several methods to do so.

    If one method fails, this package will go on to the next one, eventually falling back to the default xref.

  • Install Install using ~use-package~.

    #+begin_src emacs-lisp :tangle yes (use-package smart-jump :ensure t) #+end_src

    Take a look at the examples below to ~register~ a ~smart-jump~ and then use it with the standard jump keys. (e.g. ~M-., M-, M-?~).

    Alternatively, clone this repo, add it to Emacs' ~load-path~ and then require ~smart-jump~.

    There's also some ready made ~smart-jumps~.

    There are two ways to set up default registers.

    Call ~smart-jump-setup-default-registers.~ #+begin_src emacs-lisp :tangle yes (use-package smart-jump :ensure t :config (smart-jump-setup-default-registers)) #+end_src

    Bind commands to smart-jump-go, smart-jump-back and smart-jump-references. #+begin_src emacs-lisp :tangle yes (use-package smart-jump :ensure t :commands (smart-jump-go smart-jump-back smart-jump-references)) #+end_src Upon running one of these commands, smart-jump will register jumps for you.

#+begin_src emacs-lisp :tangle yes (use-package smart-jump :ensure t :bind (("M-." . smart-jump-go) ("M-," . smart-jump-back) ("M-?" . smart-jump-references))) #+end_src

Defer smart-jump by using :bind.

#+begin_src emacs-lisp :tangle yes (use-package smart-jump :ensure t :commands (smart-jump-go smart-jump-back smart-jump-references) :init (with-eval-after-load 'general (general-define-key :states '(normal visual motion) :keymaps 'override "M-." 'smart-jump-go "M-," 'smart-jump-back "M-?" 'smart-jump-references))) #+end_src

Defer smart-jump in evil with general.

The deferred approaches allows one to save some startup-time by avoiding having to load the package as well as loop through all the jump registrations.

  • Examples ** Bare minimum example Sets up smart-jump for python-mode with anaconda. smart-jump will first attempt to jump using anaconda and, falling back to xref if anaconda fails.

    #+begin_src emacs-lisp :tangle yes (smart-jump-register :modes 'python-mode :jump-fn 'anaconda-mode-find-definitions :pop-fn 'anaconda-mode-go-back :refs-fn 'anaconda-mode-find-references :should-jump #'smart-jump-python-anaconda-available-p :heuristic 'point :async 600) #+end_src ** Multiple modes Sets up smart-jump for both emacs-lisp-mode and lisp-interaction-mode. #+begin_src emacs-lisp :tangle yes (smart-jump-register :modes '(emacs-lisp-mode lisp-interaction-mode) :jump-fn 'elisp-slime-nav-find-elisp-thing-at-point :pop-fn 'pop-tag-mark :should-jump t :heuristic 'error :async nil) #+end_src ** Supporting Asynchronous Functions Sometimes GoToDefinition is written in an asynchronous fashion which makes it tricky to fallback to the next GoToDefinition method. This package supports that case. Just set the ~:async~ parameter. #+begin_src emacs-lisp :tangle yes (smart-jump-register :modes 'java-mode :jump-fn 'ggtags-find-tag-dwim :pop-fn 'ggtags-prev-mark :should-jump t :heuristic 'point :async t)

    #+end_src

    #+begin_src emacs-lisp :tangle yes ;; This sets a custom timeout. (smart-jump-register :modes 'csharp-mode :jump-fn 'omnisharp-go-to-definition :pop-fn 'pop-tag-mark :should-jump t :heuristic 'point :async 500) #+end_src ** Finding References with Fallback #+begin_src emacs-lisp :tangle yes (smart-jump-register :modes 'tide-mode :jump-fn 'tide-jump-to-definition :pop-fn 'tide-jump-back :refs-fn 'tide-references :should-jump t :heuristic 'point :async t) #+end_src ** A more complex example Register different GoToDefinition functions with c-mode.

    #+begin_src emacs-lisp :tangle yes (smart-jump-register :modes '(c-mode c++-mode) :jump-fn 'ggtags-find-tag-dwim :pop-fn 'ggtags-prev-mark :refs-fn 'ggtags-find-reference :should-jump t :heuristic 'point :async 500 :order 2)

    (smart-jump-register :modes '(c-mode c++-mode) :jump-fn 'rtags-find-symbol-at-point :pop-fn 'rtags-location-stack-back :refs-fn 'rtags-find-all-references-at-point :should-jump (lambda () (and (fboundp 'rtags-executable-find) (rtags-executable-find "rc") (rtags-is-indexed))) :heuristic 'point :async 500 :order 1) #+end_src

    In this case, the fallback strategy is ->

    • For Jumping ~rtags-find-symbol-at-point~ -> ~ggtags-find-tag-dwim~ -> ~xref~

    • For Finding References ~rtags-find-all-references-at-point~ -> ~ggtags-find-reference~ -> ~smart-jump-simple-find-references~

    The ~:order~ keyword in this case designates the sort order of the jumps.

    Take a look at [[file:examples.org][this for more examples.]]

  • Archived Code Peek to Definition [[./screenshots/peek.png]]

    #+begin_src emacs-lisp :tangle yes ;;; This is code that used to be in smart-jump that I'm moving here now. ;;;###autoload (defun smart-jump-peek () "Peek at definition." (interactive) (smart-jump-make-peek-frame 'smart-jump-go))

(defun smart-jump-make-peek-frame (find-definition-function &rest args) "Make a new frame for peeking definition.

Credits to @tuhdo.

http://tuhdo.github.io/emacs-frame-peek.html" (let (doc-frame x y ;; 1. Find the absolute position of the current beginning of the ;; symbol at point, in pixels. (abs-pixel-pos (save-excursion ;; (beginning-of-thing 'symbol) (beginning-of-line) (window-absolute-pixel-position)))) (setq x (car abs-pixel-pos)) (setq y (+ (cdr abs-pixel-pos) (frame-char-height)))

;; 2. Create a new invisible frame, with the current buffer in it.
(setq doc-frame (make-frame '((name . "*SmartJump Peek*")
                              (width . 80)
                              (visibility . nil)
                              (height . 20)
                              (min-width  . t)
                              (min-height . t)
                              (border-width . 0)
                              (internal-border-width . 0)
                              (vertical-scroll-bars . nil)
                              (horizontal-scroll-bars . nil)
                              (left-fringe . 0)
                              (right-fringe . 0)
                              (tool-bar-lines . 0)
                              (line-spacing . 0)
                              (unsplittable . t)
                              (no-other-frame . t)
                              (no-special-glyphs . t))))

;; 3. Position the new frame right under the beginning of the
;; symbol at point.
(set-frame-position doc-frame x y)

;; 4. Jump to the symbol at point.
(with-selected-frame doc-frame
  (apply find-definition-function args)
  (recenter-top-bottom 0))

;; 5. Make frame visible again.
(make-frame-visible doc-frame)))

#+end_src

  • Help Wanted :) Look into issue tracker! Add tests! Add more default ~smart-jump~ registers.
  • Running Tests #+begin_src sh :tangle yes cask make test make lint make compile #+end_src