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:
parent
b88172db48
commit
6dfb07b3bf
4 changed files with 183 additions and 196 deletions
|
@ -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 doesn’t work in /normal/ and /visual/ states, we’ll 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 doesn’t work in /normal/ and /visual/ states, we’ll bind snipe only for those:
|
||||||
|
|
|
@ -139,10 +139,10 @@ Lots of things to learn and keep straight. Let’s 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")
|
||||||
|
|
|
@ -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 don’t 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 lispy’s “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= don’t 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 doesn’t 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 don’t 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. Let’s suppose we entered this:
|
|
||||||
** Clever Keybindings
|
|
||||||
Adding a bunch of meta-key keybindings to the Normal state seems like I’m 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 doesn’t 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 isn’t 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,16 +245,16 @@ 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
|
||||||
|
|
||||||
And we just need to bind it.
|
And we just need to bind it.
|
||||||
|
|
|
@ -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 we’ll 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 we’ll 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= isn’t 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 doesn’t 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.
|
||||||
|
|
Loading…
Reference in a new issue