Swap clever parens for lispyville

The lispy+lispyville is more feature-rich than the
smart-parens+clever. Both are fantastic, but I'm switching my lisp
work for lispyville.
This commit is contained in:
Howard Abrams 2023-03-17 19:16:58 -07:00
parent b88172db48
commit 6dfb07b3bf
4 changed files with 183 additions and 196 deletions

View file

@ -359,7 +359,7 @@ What text objects are known?
- ~o~ :: symbol, like a variable - ~o~ :: symbol, like a variable
- ~~ :: a string, surround by quotes, also ~`~ for backticks - ~~ :: a string, surround by quotes, also ~`~ for backticks
- ~)~ :: parenthesis, also ~}~ and ~]~, see ~g~ - ~)~ :: parenthesis, also ~}~ and ~]~, see ~g~
- ~g~ :: within a brace, paren, etc., with the [[Better Parenthesis with Text Object][my extensions below]], see ~b~ and ~f~ for similar functionality. - ~x~ :: within a brace, paren, etc., with the [[Better Parenthesis with Text Object][my extensions below]], see ~b~ and ~f~ for similar functionality.
- ~d~ :: a /defun/, or code block, similar to ~p~. - ~d~ :: a /defun/, or code block, similar to ~p~.
- ~i~ :: indention area, for YAML and Python, with the [[Text Objects based on Indentation][evil-indent-plus]] package - ~i~ :: indention area, for YAML and Python, with the [[Text Objects based on Indentation][evil-indent-plus]] package
- ~t~ :: an HTML tag - ~t~ :: an HTML tag
@ -444,8 +444,8 @@ Extend the text object to call this function for both /inner/ and /outer/:
#+end_src #+end_src
And the keybindings: And the keybindings:
#+begin_src emacs-lisp #+begin_src emacs-lisp
(define-key evil-inner-text-objects-map "g" #'ha-evil-inner-paren) (define-key evil-inner-text-objects-map "x" #'ha-evil-inner-paren)
(define-key evil-outer-text-objects-map "g" #'ha-evil-a-paren) (define-key evil-outer-text-objects-map "x" #'ha-evil-a-paren)
#+end_src #+end_src
*** Key Chord *** Key Chord
@ -1303,6 +1303,7 @@ Not sure what is in a register? Have it show you when you hit ~”~ or ~@~ with
evil-owl-extra-posframe-args '(:width 50 :height 20 :background-color "#444") evil-owl-extra-posframe-args '(:width 50 :height 20 :background-color "#444")
evil-owl-max-string-length 50) evil-owl-max-string-length 50)
(evil-owl-mode)) (evil-owl-mode))
#+end_src #+end_src
*** Evil Snipe *** Evil Snipe
Doom introduced me to [[https://github.com/hlissner/evil-snipe][evil-snipe]], like =f= and =t=, but with two characters, and can, when configured, search more than the current line. My issue is that [[Evil Surround]] uses the same keybindings. Since surround doesnt work in /normal/ and /visual/ states, well bind snipe only for those: Doom introduced me to [[https://github.com/hlissner/evil-snipe][evil-snipe]], like =f= and =t=, but with two characters, and can, when configured, search more than the current line. My issue is that [[Evil Surround]] uses the same keybindings. Since surround doesnt work in /normal/ and /visual/ states, well bind snipe only for those:

View file

@ -139,10 +139,10 @@ Lots of things to learn and keep straight. Lets try the [[https://github.com/
'(:key "w" :description "word") '(:key "w" :description "word")
'(:key "s" :description "sentence") '(:key "s" :description "sentence")
'(:key "p" :description "paragraph") '(:key "p" :description "paragraph")
'(:key "l" :description "line") '(:key "l" :description "line / list")
'(:key "o" :description "symbol") '(:key "o" :description "symbol")
'(:key "a" :description "argument") '(:key "a" :description "argument")
'(:key "g" :description "s-exp") '(:key "x" :description "s-exp")
'(:key "'" :description "string") '(:key "'" :description "string")
'(:key "d" :description "function") '(:key "d" :description "function")
'(:key "j" :description "smaller indent block") '(:key "j" :description "smaller indent block")

View file

@ -30,6 +30,16 @@ New, /non-literal/ source code comes from [[file:templates/emacs-lisp-mode.el][e
#+begin_src emacs-lisp #+begin_src emacs-lisp
(ha-auto-insert-file (rx ".el" eol) "emacs-lisp-mode.el") (ha-auto-insert-file (rx ".el" eol) "emacs-lisp-mode.el")
#+end_src #+end_src
Perhaps we should have an Emacs Lisp-specific leader for advanced commands:
#+begin_src emacs-lisp
(general-create-definer ha-elisp-leader
:states '(normal visual motion)
:keymaps '(emacs-lisp-mode-map lisp-mode-map)
:prefix ","
:global-prefix "<f17>"
:non-normal-prefix "S-SPC")
#+end_src
* Syntax Display * Syntax Display
** Dim those Parenthesis ** Dim those Parenthesis
The [[https://github.com/tarsius/paren-face][paren-face]] project lowers the color level of parenthesis which I find better. The [[https://github.com/tarsius/paren-face][paren-face]] project lowers the color level of parenthesis which I find better.
@ -86,210 +96,145 @@ While I love packages that add functionality and I dont have to learn anythin
(add-to-list 'evil-goto-definition-functions 'ha-org-code-block-jump) (add-to-list 'evil-goto-definition-functions 'ha-org-code-block-jump)
#+end_src #+end_src
And in case I need to call it directly: ** Lispy
#+begin_src emacs-lisp I like the idea of [[https://github.com/abo-abo/lispy][lispy]] for making a Lisp-specific /keybinding state/ (similar to Evil).
(defun ha-goto-definition ()
(interactive)
(evil-inner-WORD))
#+end_src
** Clever Parenthesis
We need to make sure we keep the [[https://github.com/Fuco1/smartparens][smartparens]] project always in /strict mode/, because who wants to worry about paren-matching:
#+begin_src emacs-lisp
(use-package smartparens
:custom
(smartparens-global-strict-mode t)
My primary use-case is for its refactoring and other unique features. For instance, I love [[help:lispy-ace-paren][lispy-ace-paren]] that puts an /ace label/ on every parenthesis, allowing me to quickly jump to any s-expression.
#+begin_src emacs-lisp
(use-package lispy
:config :config
(sp-with-modes sp-lisp-modes (evil-define-key 'normal emacs-lisp-mode-map
;; disable ', as it's the quote character: "gf" 'lispy-ace-paren
(sp-local-pair "'" nil :actions nil)) "gF" 'lispy-ace-symbol)
(sp-with-modes (-difference sp-lisp-modes sp-clojure-modes) (ha-elisp-leader
;; use the pseudo-quote inside strings where it serve as hyperlink. "r i" '("cond→if" . lispy-to-ifs)
(sp-local-pair "`" "'" "r c" '("if→cond" . lispy-to-cond)
:when '(sp-in-string-p "r d" '("λ→𝑓" . lispy-to-defun)
sp-in-comment-p) "r l" '("𝑓→λ" . lispy-to-lambda)
:skip-match (lambda (ms _mb _me) "r f" '("flatten" . lispy-flatten)
(cond "r b" '("bind var" . lispy-bind-variable)
((equal ms "'") (not (sp-point-in-string-or-comment))) "r u" '("unbind var" . lispy-unbind-variable)
(t (not (sp-point-in-string-or-comment)))))))
:hook "e d" '("edebug" . lispy-edebug)
(prog-mode . smartparens-strict-mode)) "e j" '("debug-step-in" . lispy-debug-step-in)
"e R" '("eval-and-replace" . lispy-eval-and-replace)
"h d" '("describe" . lispy-describe)
"t t" '("ert" . lispy-ert)))
#+end_src #+end_src
** Lispyville
I want an Evil version of [[Lispy]]. The [[https://github.com/noctuid/lispyville][lispyville project]] builds on it to make it Evil. From the README:
#+begin_quote
The main difference from an evil state is that lispys “special” is contextually based on the point (special is when the point is before an opening delimiter, after a closing delimiter, or when there is an active region).
#+end_quote
The [[https://github.com/luxbock/evil-cleverparens][evil-cleverparens]] solves having me create keybindings to the [[https://github.com/Fuco1/smartparens][smartparens]] project by updating the evil states with Lisp-specific bindings. Many of the operations supplied by =lispyville= dont require learning anything new. Similar to [[Clever Parenthesis]], we can
For instance, if our point is placed at this location in this code:
#+begin_src emacs-lisp #+begin_src emacs-lisp
(use-package evil-cleverparens (message "The answer is %d" (+ 2 (* 8 5)‸ 9 (+ 1 4)))
:after smartparens
:custom
(evil-cleverparens-use-additional-bindings t)
(evil-cleverparens-use-additional-movement-keys t)
(evil-cleverparens-use-s-and-S t)
:init
(require 'evil-cleverparens-text-objects)
:hook
(prog-mode . evil-cleverparens-mode)) ;; All the languages!
;; Otherwise: (emacs-lisp-mode . evil-cleverparens-mode)
#+end_src #+end_src
Pressing ~D~ results in:
#+begin_src emacs-lisp
(message "The answer is %d" (+ 2 (* 8 5)‸))
#+end_src
And doesnt delete the trailing parenthesis.
The /trick/ to being effective with the [[https://www.emacswiki.org/emacs/ParEdit][paredit-family]] of extensions is learning the keys. The killer “app” is the slurp/barf sequence. Use the ~<~ key, in normal mode, to barf (or jettison)… in other words, /move/ the paren closer to the point. For instance: The /trick/ to being effective with the [[https://www.emacswiki.org/emacs/ParEdit][paredit-family]] of extensions is learning the keys. The killer “app” is the slurp/barf sequence. Use the ~<~ key, in normal mode, to barf (or jettison)… in other words, /move/ the paren closer to the point. For instance:
#+begin_src emacs-lisp :tangle no #+begin_src emacs-lisp :tangle no
(+ 41 (* ‖1 3)) ⟹ (+ 41 (* ‖1) 3) (+ 41 (* ‸1 3)) ⟹ (+ 41 (* ‸1) 3)
#+end_src #+end_src
Use the ~>~ key to /slurp/ in outside objects into the current expression… in other words, move the paren away from the point. For instance: Use the ~>~ key to /slurp/ in outside objects into the current expression… in other words, move the paren away from the point. For instance:
#+begin_src emacs-lisp :tangle no #+begin_src emacs-lisp :tangle no
(+ 41 (* ‖1) 3) ⟹ (+ 41 (* ‖1 3)) (+ 41 (* ‸1) 3) ⟹ (+ 41 (* ‸1 3))
#+end_src #+end_src
*Opening Parens.* Those two keys seem straight-forward, but they behave differently when the are on the opening parens. *Note:* I used to use the [[https://github.com/luxbock/evil-cleverparens][evil-cleverparens]] project to have similar keybindings but in all programming languages. I found that =lispyville= is a little more reliable, and that I dont really use these types of code manipulation in my day-job programming languages of Python and YAML.
When the point (symbolized by ~‖~) is /on/ the opening paren, ~<~ moves the paren to the left. For instance:
#+begin_src emacs-lisp :tangle no
(+ 41 ‖(* 1 3)) ⟹ (+ ‖(41 * 1 3))
#+end_src
And the ~>~ moves the paren to the right. For instance:
#+begin_src emacs-lisp :tangle no
(+ 41 ‖(* 1 3)) ⟹ (+ 41 * ‖(1 3))
#+end_src
I would like to have a list of what keybindings that work in =normal= mode: #+begin_src emacs-lisp
- ~M-h~ / ~M-l~ move back/forward by functions (use-package lispyville
- ~H~ / ~L~ move back/forward by s-expression :after lispy
- ~M-i~ insert at the beginning of the form :hook ((emacs-lisp-mode-hook lisp-mode-hook) . lispyville-mode)
- ~M-a~ appends at the end of the form
- ~M-o~ new form after the current sexp
- ~M-O~ new form /before/ the current sexp
- ~M-j~ / ~M-k~ drags /thing at point/ and back and forth in the form
- ~>~ slurp forward if at the end of form, at beginning, it barfs backwards
- ~<~ slurp backward if at start of form, at the end, it barfs forwards
- ~M-(~ / ~M-)~ wraps next/previous form in parens (braces and brackets work too)
- ~x~ unwraps if the point is on the =(= of an expression.
- ~D~ deletes an entire s-expression, but this can depend on the position of the point.
The other advantage is moving around by s-expressions. This takes a little getting used to, for instance:
- ~[~ and ~]~ move from paren to paren, essentially, from s-expression.
- ~H~ and ~L~ act similarly to the above.
- ~(~ and ~)~ move up to the parent s-expression
We need a real-world example. Lets suppose we entered this:
** Clever Keybindings
Adding a bunch of meta-key keybindings to the Normal state seems like Im going backwards away from the /key sequences/ of Evil. First, adding frequently used (especially key movements) on the ~g~ key seems nice. Since I never bother with [[help:find-file-at-point][find-file-at-point]], I figured I could re-purpose that keybinding:
#+begin_src emacs-lisp :tangle no
(format "The sum of %d %d is %d" a b (+ a b))
(use-package evil-cleverparens
:general
(:states 'normal :keymaps 'prog-mode-map
"gf" '("evil cleverparens" . evil-cleverparens-hydra/body)
"H" 'evil-cp-backward-sexp
"L" 'ha-cp-forward-sexp))
#+end_src
But we forgot to define the =a= and =b= variables. One approach, after Escaping into the normal state, is to hit ~(~ to just to the beginning of the s-expression, and then type, ~M-(~ to wrap the expression, and type ~i~ to go into insert mode:
For all the rest, why not make a Hydra using the pretty-hydra project:
#+begin_src emacs-lisp :tangle no
(‖ (format "The sum of %d %d is %d" a b (+ a b)))
#+end_src
And now we can enter the =let= expression.
(use-package pretty-hydra
:after evil-cleverparens
:config :config
(pretty-hydra-define evil-cleverparens-hydra (lispyville-set-key-theme '(operators atom-movement
(:color red :quit-key "q") commentary slurp/barf-lispy additional-wrap
("Movement" additional additional-insert))
(("f" ha-cp-beginning-of-next-defun "Next defun")
("C-f" evil-cp-end-of-defun nil) ; M-l
("F" evil-cp-beginning-of-defun "Prev defun") ; M-h
("j" evil-cp-forward-symbol-begin "Next symbol") (evil-define-key '(normal insert emacs) lispyville-mode-map
("k" evil-cp-backward-symbol-begin "Prev symbol") (kbd "M-h") 'lispyville-beginning-of-defun
("J" evil-cp-forward-symbol-end "Next symbol") (kbd "M-l") 'lispyville-beginning-of-next-defun
("K" evil-cp-backward-symbol-end "Prev symbol")) (kbd "M-i") 'lispyville-insert-at-beginning-of-list ; These are useful
(kbd "M-a") 'lispyville-insert-at-end-of-list ; and I want to use
(kbd "M-o") 'lispyville-open-below-list ; these in insert
(kbd "M-O") 'lispyville-open-above-list ; or Emacs state.
"Move S-Exp" ;; The c-w theme is VI-specific. I still use Emacs' M-Delete:
(("h" evil-cp-backward-sexp "Prev s-exp") ; H (kbd "M-DEL") 'lispyville-delete-backward-word)
("C-l" evil-cp-forward-sexp nil) ; L
("l" ha-cp-forward-sexp "Next s-exp")
("C-u" evil-cp-backward-up-sexp nil) ;; Sentence and paragraph movement doesn't make sense in a Lisp world,
("u" ha-sp-up-sexp "Up s-exp") ; See sp-up-sexp ;; so I redefine these based on my own personal expectations:
("d" sp-down-sexp "Inside s-exp")) (evil-define-key 'normal lispyville-mode-map
"H" 'lispyville-backward-sexp-begin
(kbd "M-H") 'lispyville-backward-sexp-end
"L" 'lispyville-forward-sexp-begin
(kbd "M-L") 'lispyville-forward-sexp-end
"(" 'lispyville-previous-opening
")" 'lispyville-next-closing
"{" 'lispyville-backward-up-list
"}" 'lispyville-next-opening)
"Slurping" ;; Visually high-light a region, just hit `(' to wrap it in parens.
((">" evil-cp-> "Barf") ;; Without smartparens, we need to insert a pair of delimiters:
("<" evil-cp-< "Slurp") (evil-define-key '(visual insert emacs) lispyville-mode-map "(" 'lispy-parens)
("w" cp-wrap-round "Wrap") (evil-define-key '(visual insert emacs) lispyville-mode-map "[" 'lispy-brackets)
("b" evil-cp-drag-backward "Drag Backward") ; M-k (evil-define-key '(visual insert emacs) lispyville-mode-map "{" 'lispy-braces))
("g" evil-cp-drag-forward "Drag forward")) ; M-j
"Manipulation"
(("=" sp-indent-defun "Indent defun") ; M-q
("J" sp-join-sexp "Join s-exp") ; M-j
("s" sp-splice-sexp "Splice s-exp") ; M-s
("S" sp-split-sexp "Split s-exp") ; M-S
("t" sp-transpose-sexp "Transpose s-exp") ; M-t
("T" sp-transpose-hybrid-sexp "Transpose hybrid")
("x" sp-convolute-sexp "Convolute s-exp") ; M-v
("r" sp-raise-sexp "Raise s-exp")) ; M-r
"Insert"
(("o" evil-cp-open-below-form "After" :color blue)
("O" evil-cp-open-above-form "Before" :color blue)
("a" ha-cp-append-end "append" :color blue)
("A" evil-cp-append "Append" :color blue)
("i" evil-cp-insert "Insert" :color blue))
"Other"
(("U" evil-undo "Undo")
("R" evil-redo "Redo")
("v" er/expand-region "Expand")
("V" er/contract-region "Contract")))))
Other nifty keybindings that I need to commit to muscle memory include:
| ~M-q~ | =sp-indent-defun= |
| ~M-J~ | =sp-join-sexp= |
| ~M-s~ | =sp-splice-sexp= |
| ~M-S~ | =sp-split-sexp= |
| ~M-t~ | =sp-transpose-sexp= |
| ~M-v~ | =sp-convolute-sexp= |
| ~M-r~ | =sp-raise-sexp= |
(defun ha-cp-beginning-of-next-defun (count)
"Move to the beginning of the next function."
(interactive "P")
(evil-cp-end-of-defun count)
(evil-cp-end-of-defun)
(evil-cp-beginning-of-defun))
(defun ha-sp-up-sexp (count)
"Better opposite of `sp-down-sexp'."
(interactive "P")
(evil-cp-backward-up-sexp count)
(evil-cp-backward-up-sexp)
(sp-down-sexp))
(defun ha-cp-forward-sexp (count)
"Better opposite of `evil-cp-backward-sexp'."
(interactive "P")
(evil-cp-forward-sexp count)
(evil-cp-forward-sexp)
(evil-cp-backward-sexp))
(defun ha-cp-append-end ()
"Append to the end of the current s-expression."
(interactive)
(when (looking-at (rx (any "{" "(" "[")))
(sp-down-sexp))
(sp-end-of-sexp)
(evil-cp-insert 1))
(defun ha-cp-append-after ()
"Append after the current s-expression."
(interactive)
(when (looking-at (rx (any "{" "(" "[")))
(sp-down-sexp))
(sp-end-of-sexp)
(evil-cp-append 1))
#+end_src #+end_src
Instead of converting /all keybindings/, the project supplies /key themes/ to grab specific keybinding groups.
- =operators= :: basic VI operators that keep stuff balanced
- =c-w= :: replaces the ~C-w~, but since that is VI-specific, I rebind this to ~M-Delete~
- =text-objects= :: Add more text-objects, I wrote my [[file:ha-config.org::*Better Parenthesis with Text Object][own version]] for s-expressions, but I might try these
- =atom-movement= :: The ~e~ / ~w~ and ~b~ keys will move by /symbols/ instead of /words/.
- =additional-movement= :: Adds new movement keys, ~H~ / ~L~ for s-expr and the ~(~ / ~)~ for getting to closest expressions. This doesnt work well, but is easy to re-implement.
- =commentary= :: Replace ~gc~ for un/commenting Lisp elements.
- =slurp/bar-lispy= :: always allow ~<~ / ~>~ to slurp/barf even /inside/ an s-expression.
- =additional= :: New ~M-~ bindings for manipulating s-expressions. ~M-J~ is very cool.
- =additional-insert= :: ~M-i~ insert at beginning, and ~M-a~ to insert at the end of a list.
- =wrap= :: like [[file:ha-config.org::*Evil Surround][Evil Surround]] but with one less keystroke. ~M-( M-(~ wraps the entire line.
- =additional-wrap= :: is another version of the =wrap= that automatically wraps current symbol, and then you can slurp in the rest.
- =mark= :: The ~v~ will highlight current symbol, and ~V~ will highlight current s-expression. Continues to work with [[file:ha-config.org::*Expand Region][Expand Region]].
New bindings to remember:
- ~>~ :: slurp
- ~<~ :: barf
- ~H~ :: backward s-expression
- ~L~ :: forward s-expression
- ~M-h~ :: beginning of defun
- ~M-l~ :: end of defun
- ~M-i~ :: insert at beginning of list
- ~M-a~ :: insert at end of list
- ~M-o~ :: open below list … never worry about inserting into a bunch of closing parens.
- ~M-O~ :: open above list
- ~M-j~ :: drag forward
- ~M-k~ :: drag backward
- ~M-J~ :: join
- ~M-s~ :: splice … I could use specific examples for these operations so I would know when to use them.
- ~M-S~ :: split
- ~M-r~ :: raise s-expression
- ~M-R~ :: raise list
- ~M-t~ :: transpose s-expressions
- ~M-v~ :: convolute s-expression
These are all good, but the primary keys I need to figure out, are the s-expression movement keys:
- ~{~ :: backward up list … nice to hit once (maybe twice), but isnt something to use to navigate
- ~}~ :: next opening parenthesis
- ~(~ :: previous opening paren
- ~)~ :: next closing parenthesis
** Eval Current Expression ** Eval Current Expression
The [[https://github.com/xiongtx/eros][eros]] package stands for Evaluation Result OverlayS for Emacs Lisp, and basically shows what each s-expression is near the cursor position instead of in the mini-buffer at the bottom of the window. The [[https://github.com/xiongtx/eros][eros]] package stands for Evaluation Result OverlayS for Emacs Lisp, and basically shows what each s-expression is near the cursor position instead of in the mini-buffer at the bottom of the window.
#+begin_src emacs-lisp #+begin_src emacs-lisp
@ -300,15 +245,15 @@ The [[https://github.com/xiongtx/eros][eros]] package stands for Evaluation Resu
A feature I enjoyed from Spacemacs is the ability to evaluate the s-expression currently containing the point. Not sure how they made it, but [[help:evil-cp-next-closing ][evil-cp-next-closing]] from cleverparens can help: A feature I enjoyed from Spacemacs is the ability to evaluate the s-expression currently containing the point. Not sure how they made it, but [[help:evil-cp-next-closing ][evil-cp-next-closing]] from cleverparens can help:
#+begin_src emacs-lisp #+begin_src emacs-lisp
(defun ha-eval-current-expression () (defun ha-eval-current-expression ()
"Evaluates the expression the point is currently 'in'. "Evaluates the expression the point is currently 'in'.
It does this, by jumping to the end of the current It does this, by jumping to the end of the current
expression (using evil-cleverparens), and evaluating what it expression (using evil-cleverparens), and evaluating what it
finds at that point." finds at that point."
(interactive) (interactive)
(save-excursion (save-excursion
(evil-cp-next-closing) (unless (looking-at (rx (any ")" "]")))
(evil-cp-forward-sexp) (lispyville-next-closing))
(call-interactively 'eval-last-sexp))) (call-interactively 'eval-last-sexp)))
#+end_src #+end_src

View file

@ -166,6 +166,47 @@ To take advantage of this, type:
Note: Yes, we could use [[https://github.com/mrkkrp/vimish-fold][vimish-fold]] (and its cousin, [[https://github.com/alexmurray/evil-vimish-fold][evil-vimish-fold]]) and well see if I need those. Note: Yes, we could use [[https://github.com/mrkkrp/vimish-fold][vimish-fold]] (and its cousin, [[https://github.com/alexmurray/evil-vimish-fold][evil-vimish-fold]]) and well see if I need those.
** Navigation with dumb-jump ** Navigation with dumb-jump
** Smart Parenthesis
We need to make sure we keep the [[https://github.com/Fuco1/smartparens][smartparens]] project always in /strict mode/, because who wants to worry about paren-matching:
#+begin_src emacs-lisp
(use-package smartparens
:custom
(smartparens-global-strict-mode t)
:config
(sp-with-modes sp-lisp-modes
;; disable ', as it's the quote character:
(sp-local-pair "'" nil :actions nil))
(sp-with-modes (-difference sp-lisp-modes sp-clojure-modes)
;; use the pseudo-quote inside strings where it serve as hyperlink.
(sp-local-pair "`" "'"
:when '(sp-in-string-p
sp-in-comment-p)
:skip-match (lambda (ms _mb _me)
(cond
((equal ms "'") (not (sp-point-in-string-or-comment)))
(t (not (sp-point-in-string-or-comment)))))))
:hook
(prog-mode . smartparens-strict-mode))
#+end_src
** Navigation
*** Move by Functions
The =mark-paragraph= and =downcase-word= isnt very useful in a programming context, and makes more sense to use them to jump around function-by-function:
#+begin_src emacs-lisp
(evil-define-key '(normal insert emacs) prog-mode-map
(kbd "M-h") 'beginning-of-defun
(kbd "M-l") 'beginning-of-next-defun)
#+end_src
But one of those functions doesnt exist:
#+begin_src emacs-lisp
(defun beginning-of-next-defun (count)
"Move to the beginning of the following function."
(interactive "P")
(end-of-defun count)
(end-of-defun)
(beginning-of-defun))
#+end_src
Once upon a time, we use to create a =TAGS= file that contained the database for navigating code bases, but with new faster versions of grep, e.g. [[https://beyondgrep.com][ack]], [[https://github.com/ggreer/the_silver_searcher][ag]] (aka, the Silver Searcher), [[https://github.com/Genivia/ugrep][ugrep]] and [[https://github.com/BurntSushi/ripgrep][ripgrep]], we should be able to use them. but I want to: Once upon a time, we use to create a =TAGS= file that contained the database for navigating code bases, but with new faster versions of grep, e.g. [[https://beyondgrep.com][ack]], [[https://github.com/ggreer/the_silver_searcher][ag]] (aka, the Silver Searcher), [[https://github.com/Genivia/ugrep][ugrep]] and [[https://github.com/BurntSushi/ripgrep][ripgrep]], we should be able to use them. but I want to:
- Be in a function, and see its callers. For this, the [[help:rg-dwim][rg-dwim]] function is my bread-and-butter. - Be in a function, and see its callers. For this, the [[help:rg-dwim][rg-dwim]] function is my bread-and-butter.
- Be on a function, and jump to the definition. For this, I use [[https://github.com/jacktasia/dumb-jump][dumb-jump]], which uses the above utilities. - Be on a function, and jump to the definition. For this, I use [[https://github.com/jacktasia/dumb-jump][dumb-jump]], which uses the above utilities.