cute-jumper/embrace.el

Add/Change/Delete pairs based on `expand-region', similar to `evil-surround'.

Emacs Lisp

149

55 commits

updated Mar 29, 2024

See the code

README

#+TITLE: embrace.el

[[http://melpa.org/#/embrace][file:http://melpa.org/packages/embrace-badge.svg]]
[[http://stable.melpa.org/#/embrace][file:http://stable.melpa.org/packages/embrace-badge.svg]]

Add/Change/Delete pairs based on [[https://github.com/magnars/expand-region.el][expand-region]].

For =evil-surround= integration, see [[https://github.com/cute-jumper/evil-embrace.el][evil-embrace]].

* Overview
This package is heavily inspired by [[https://github.com/timcharper/evil-surround][evil-surround]] (which is a port of the vim
plugin [[https://github.com/tpope/vim-surround][surround.vim]]). But instead of using =evil= and its text objects, this
package relies on another excellent package [[https://github.com/magnars/expand-region.el][expand-region]].

For Emacs users who don't like =evil= and thus don't use =evil-surround=,
=embrace= provides similar commands that can be found in =evil-surround=. =Evil=
is absolutely *not* required. For =evil-surround= users, =embrace= can make your
=evil-surround= commands even better! (Have you noticed that =evil-surround=
doesn't work on many custom pairs?)

* Usage
   There are three commands: =embrace-add=, =embrace-change= and
   =embrace-delete= that can add, change, and delete surrounding pairs
   respectively. You can bind these commands to your favorite key bindings.

   There is also a dispatch command =embrace-commander=. After invoking
   =embrace-commander=, you can hit:
   - =a= for =embrace-add=
   - =c= for =embrace-change=
   - =d= for =embrace-delete=

** Example

   It might be a little hard for users who have no experience in =evil= and
   =evil-surround= to understand what =embrace= can do. So let's give an example
   to show what =embrace= can do fist. You can look at the following sections to
   see the meaning of key bindings. In this example, I bind
   @@html:<kbd>@@C-,@@html:</kbd>@@ to =embrace-commander=. Assume we have
   following text in =c-mode= and the cursor position is indicated by ~|~:
   : fo|o

   Press @@html:<kbd>@@C-, a w '@@html:</kbd>@@ to add '' to the current word:
   : 'fo|o'

   Press @@html:<kbd>@@C-, a q {@@html:</kbd>@@ to add {} to outside of the quotes:
   : {'fo|o'}

   Press @@html:<kbd>@@C-, c ' "@@html:</kbd>@@ to change the '' to "":
   : {"fo|o"}

   Press @@html:<kbd>@@C-, c { t@@html:</kbd>@@, and then enter the tag: body class="page-body", to change the {} to a tag:
   : <body class="page-body">"fo|o"</body>

   Press @@html:<kbd>@@C-, c t f@@html:</kbd>@@, and enter the function name =bar= to change the tag to a
   function call:
   : bar("fo|o")

   Press @@html:<kbd>@@C-, d f@@html:</kbd>@@ to remove the function call:
   : "fo|o"

   If you're an =evil-surround= user, you might notice that the last command
   can't be achieved by =evil-surround=. However, it works in =embrace=! And
   yes, you can find even more examples in which =evil-surround= doesn't work
   while =embrace= works!

** Screencasts
   For non =evil-mode= users, use the following settings (they will be explained
   later):
   : (global-set-key (kbd "C-,") #'embrace-commander)
   : (add-hook 'org-mode-hook #'embrace-org-mode-hook)

   Open an org-mode file, we can perform the following pair changing:

   [[./screencasts/embrace.gif]]

   For =evil-mode= users, here is a similar screencast (see [[https://github.com/cute-jumper/evil-embrace.el][evil-embrace]] for more
   details):

   [[https://github.com/cute-jumper/evil-embrace.el/blob/master/screencasts/evil-embrace.gif]]

   And we have a friendly help system (Yes, it is based on some simplified code
   from [[https://github.com/justbur/emacs-which-key][which-key]]):

   Help to select a semantic unit:

   [[./screencasts/help_unit.png]]

   Help to delete a pair:

   [[./screencasts/help.png]]


** =embrace-change= and =embrace-delete=
   These two commands can change and delete the surround pair respectively. For
   =evil-surround= users, =embrace-change= is similar to =cs= and
   =embrace-delete= is similar to =ds=.

   The surrounding pair is specified by a key, which is very similar to the key
   used for Vim's text objects. For example, =(= stands for the surrounding pair
   =(= and =)=, and ={= stands for the surrouding pair, ={= and =}=. The default
   key mappings are shown below:
   | Key | Left                | right    |
   |-----+---------------------+----------|
   | (   | "("                 | ")"      |
   | )   | "( "                | " )"     |
   | {   | "{"                 | "}"      |
   | }   | "{ "                | " }"     |
   | [   | "["                 | "]"      |
   | ]   | "[ "                | " ]"     |
   | >   | "<"                 | ">"      |
   | "   | "\""                | "\""     |
   | '   | "\'"                | "\'"     |
   | t   | "<foo bar=100>"     | "</foo>" |
   | f   | "func("             | ")"      |

   Note that for =t= and =f= key, the real content is based on the user's input.

** =embrace-add=
   This command is similar to =evil-surround='s =ys= command. We need to enter a
   key for the semantic unit to which we want to add a surrounding pair. The
   semantic unit is marked by the functions provided by =expand-region=.

   Here is the default mapping:
   | key | mark function          |
   |-----+------------------------|
   | w   | er/mark-word           |
   | s   | er/mark-symbol         |
   | d   | er/mark-defun          |
   | p   | er/mark-outside-pairs  |
   | P   | er/mark-inside-pairs   |
   | q   | er/mark-outside-quotes |
   | Q   | er/mark-inside-quotes  |
   | .   | er/mark-sentence       |
   | h   | er/mark-paragraph      |

   After pressing a key to select the semantic unit, you can press another key
   to add the surrounding pair, which is the same as =embrace-change= and
   =embrace-delete=.


* Customization
** Adding More Semantic Units
   You can modify the variable =embrace-semantic-units-alist= and note that
   this variable is buffer-local so it is better to change the value in a hook:
   : (add-hook 'text-mode-hook
   :     (lambda ()
   :        (add-to-list 'embrace-semantic-units-alist '(?e . er/mark-email))))

** Adding More Surrounding Pairs
   Use the command =embrace-add-pair= to add a pair:
   : (embrace-add-pair key left right)

   The change is also buffer-local, so wrap it in a hook function:
   : (add-hook 'LaTeX-mode-hook
   :     (lambda ()
   :        (embrace-add-pair ?e "\\begin{" "}")))

   If you want add something like the =t= key for the tag, you can look at the
   function =embrace-add-pair-regexp= in the source code, and if you're planning
   to use =embrace-add-pair-regexp=, you should also use =embrace-build-help= to
   build the user-friendly help message.

   Note that if you're using =embrace-add-pair= to add an existing key, then it
   will replace the old one.


** Disable Help Message
   If you find the help message annoying, use the following code to disable it:
   : (setq embrace-show-help-p nil)

** Example Settings
   I recommend binding a convenient key for =embrace-commander=. For example,
   : (global-set-key (kbd "C-,") #'embrace-commander)

   We have defined several example hook functions that provide additional key
   bindings which can be used in different major modes. Right now there are
   hooks for =LaTeX-mode= and =org-mode=:

   =LaTeX-mode=:
   | Key | Left       | Right |
   |-----+------------+-------|
   | =   | \verb\vert | \vert |
   | ~   | \texttt{   | }     |
   | /   | \emph{     | }     |
   | *   | \textbf{   | }     |

   =org-mode=:
   | Key | Left             | Right             |
   |-----+------------------+-------------------|
   | =   | =                | =                 |
   | ~   | ~                | ~                 |
   | /   | /                | /                 |
   | *   | *                | *                 |
   | _   | _                | _                 |
   | +   | +                | +                 |
   | k   | ~@@html:<kbd>@@~ | ~@@html:</kbd>@@~ |

   =ruby-mode (and enh-ruby-mode)=:
   | Key | Left | Right |
   |-----+------+-------|
   | d   | do   | end   |
   | #   | #{   | }     |

   To use them:
   : (add-hook 'LaTeX-mode-hook 'embrace-LaTeX-mode-hook)
   : (add-hook 'org-mode-hook 'embrace-org-mode-hook)
   : (add-hook 'ruby-mode-hook 'embrace-ruby-mode-hook) ;; or 'enh-ruby-mode-hook

   The code for the three hooks above (which are defined in =embrace.el=):
   : (defun embrace-LaTeX-mode-hook ()
   :   (dolist (lst '((?= "\\verb|" . "|")
   :                  (?~ "\\texttt{" . "}")
   :                  (?/ "\\emph{" . "}")
   :                  (?* "\\textbf{" . "}")))
   :     (embrace-add-pair (car lst) (cadr lst) (cddr lst))))
   : (defun embrace-org-mode-hook ()
   :   (dolist (lst '((?= "=" . "=")
   :                  (?~ "~" . "~")
   :                  (?/ "/" . "/")
   :                  (?* "*" . "*")
   :                  (?_ "_" . "_")
   :                  (?+ "+" . "+")
   :                  (?k "@@html:<kbd>@@" . "@@html:</kbd>@@")))
   :     (embrace-add-pair (car lst) (cadr lst) (cddr lst))))
   : (defun embrace-ruby-mode-hook ()
   :   (dolist (lst '((?# "#{" "}")
   :                  (?d "do" "end")))
   :     (embrace-add-pair (car lst) (cadr lst) (caddr lst))))

   You can define and use your own hook function similar to the code above.

   Welcome to add some settings for more major modes.

* For =evil-surround= Users
** Where =embrace= is better
  From the previous example, you can see that =embrace= actually replicates all
  the funcionalities provided in =evil-surround= and it can even do more than
  =evil-surround=. Actually, they are quite different. Since =embrace= uses
  =expand-region= behind the scene, you can expect it to work as long as
  =expand-region= works. Unlike =evil-surround=, which is restricted to the
  pre-defined text objects, =embrace= can define nearly arbitrary surrounding
  pairs and three core commands always work. On the contratry, you get nearly no
  customization in =evil-surround=: custom pairs don't work in =cs= or =ds= if
  you don't have a corresponding text object defined (they work in =ys=).

  *TL;DR*: =embrace= is more customizable.
** Why not use together?
   Sure! You can make =embrace= and =evil-surround= work together. Look at
   [[https://github.com/cute-jumper/evil-embrace.el][evil-embrace]]!

* Contributions
This package is still in early stage, but it is quite usable right now. More
functions can be added and the evil integration is not perfect yet.
Contributions are always welcome!
* Related Packages
  - [[https://github.com/cute-jumper/evil-embrace.el][evil-embrace]]
  - [[https://github.com/magnars/expand-region.el][expand-region]]
  - [[https://github.com/timcharper/evil-surround][evil-surround]]
  - [[https://github.com/magnars/change-inner.el][change-inner]]
  - [[https://github.com/Fuco1/smartparens][smartparens]]

Not written in Markdown, so it's shown here as plain text — view it formatted on GitHub.

emacs
evil-surround
expand-region

Contributors

cute-jumper

48 commits

syohex

2 commits

dcluna

1 commits

LemonBreezes

1 commits

cute-jumper/embrace.el

Add/Change/Delete pairs based on `expand-region', similar to `evil-surround'.

Emacs Lisp

149

55 commits

updated Mar 29, 2024

See the code

README

#+TITLE: embrace.el

[[http://melpa.org/#/embrace][file:http://melpa.org/packages/embrace-badge.svg]]
[[http://stable.melpa.org/#/embrace][file:http://stable.melpa.org/packages/embrace-badge.svg]]

Add/Change/Delete pairs based on [[https://github.com/magnars/expand-region.el][expand-region]].

For =evil-surround= integration, see [[https://github.com/cute-jumper/evil-embrace.el][evil-embrace]].

* Overview
This package is heavily inspired by [[https://github.com/timcharper/evil-surround][evil-surround]] (which is a port of the vim
plugin [[https://github.com/tpope/vim-surround][surround.vim]]). But instead of using =evil= and its text objects, this
package relies on another excellent package [[https://github.com/magnars/expand-region.el][expand-region]].

For Emacs users who don't like =evil= and thus don't use =evil-surround=,
=embrace= provides similar commands that can be found in =evil-surround=. =Evil=
is absolutely *not* required. For =evil-surround= users, =embrace= can make your
=evil-surround= commands even better! (Have you noticed that =evil-surround=
doesn't work on many custom pairs?)

* Usage
   There are three commands: =embrace-add=, =embrace-change= and
   =embrace-delete= that can add, change, and delete surrounding pairs
   respectively. You can bind these commands to your favorite key bindings.

   There is also a dispatch command =embrace-commander=. After invoking
   =embrace-commander=, you can hit:
   - =a= for =embrace-add=
   - =c= for =embrace-change=
   - =d= for =embrace-delete=

** Example

   It might be a little hard for users who have no experience in =evil= and
   =evil-surround= to understand what =embrace= can do. So let's give an example
   to show what =embrace= can do fist. You can look at the following sections to
   see the meaning of key bindings. In this example, I bind
   @@html:<kbd>@@C-,@@html:</kbd>@@ to =embrace-commander=. Assume we have
   following text in =c-mode= and the cursor position is indicated by ~|~:
   : fo|o

   Press @@html:<kbd>@@C-, a w '@@html:</kbd>@@ to add '' to the current word:
   : 'fo|o'

   Press @@html:<kbd>@@C-, a q {@@html:</kbd>@@ to add {} to outside of the quotes:
   : {'fo|o'}

   Press @@html:<kbd>@@C-, c ' "@@html:</kbd>@@ to change the '' to "":
   : {"fo|o"}

   Press @@html:<kbd>@@C-, c { t@@html:</kbd>@@, and then enter the tag: body class="page-body", to change the {} to a tag:
   : <body class="page-body">"fo|o"</body>

   Press @@html:<kbd>@@C-, c t f@@html:</kbd>@@, and enter the function name =bar= to change the tag to a
   function call:
   : bar("fo|o")

   Press @@html:<kbd>@@C-, d f@@html:</kbd>@@ to remove the function call:
   : "fo|o"

   If you're an =evil-surround= user, you might notice that the last command
   can't be achieved by =evil-surround=. However, it works in =embrace=! And
   yes, you can find even more examples in which =evil-surround= doesn't work
   while =embrace= works!

** Screencasts
   For non =evil-mode= users, use the following settings (they will be explained
   later):
   : (global-set-key (kbd "C-,") #'embrace-commander)
   : (add-hook 'org-mode-hook #'embrace-org-mode-hook)

   Open an org-mode file, we can perform the following pair changing:

   [[./screencasts/embrace.gif]]

   For =evil-mode= users, here is a similar screencast (see [[https://github.com/cute-jumper/evil-embrace.el][evil-embrace]] for more
   details):

   [[https://github.com/cute-jumper/evil-embrace.el/blob/master/screencasts/evil-embrace.gif]]

   And we have a friendly help system (Yes, it is based on some simplified code
   from [[https://github.com/justbur/emacs-which-key][which-key]]):

   Help to select a semantic unit:

   [[./screencasts/help_unit.png]]

   Help to delete a pair:

   [[./screencasts/help.png]]


** =embrace-change= and =embrace-delete=
   These two commands can change and delete the surround pair respectively. For
   =evil-surround= users, =embrace-change= is similar to =cs= and
   =embrace-delete= is similar to =ds=.

   The surrounding pair is specified by a key, which is very similar to the key
   used for Vim's text objects. For example, =(= stands for the surrounding pair
   =(= and =)=, and ={= stands for the surrouding pair, ={= and =}=. The default
   key mappings are shown below:
   | Key | Left                | right    |
   |-----+---------------------+----------|
   | (   | "("                 | ")"      |
   | )   | "( "                | " )"     |
   | {   | "{"                 | "}"      |
   | }   | "{ "                | " }"     |
   | [   | "["                 | "]"      |
   | ]   | "[ "                | " ]"     |
   | >   | "<"                 | ">"      |
   | "   | "\""                | "\""     |
   | '   | "\'"                | "\'"     |
   | t   | "<foo bar=100>"     | "</foo>" |
   | f   | "func("             | ")"      |

   Note that for =t= and =f= key, the real content is based on the user's input.

** =embrace-add=
   This command is similar to =evil-surround='s =ys= command. We need to enter a
   key for the semantic unit to which we want to add a surrounding pair. The
   semantic unit is marked by the functions provided by =expand-region=.

   Here is the default mapping:
   | key | mark function          |
   |-----+------------------------|
   | w   | er/mark-word           |
   | s   | er/mark-symbol         |
   | d   | er/mark-defun          |
   | p   | er/mark-outside-pairs  |
   | P   | er/mark-inside-pairs   |
   | q   | er/mark-outside-quotes |
   | Q   | er/mark-inside-quotes  |
   | .   | er/mark-sentence       |
   | h   | er/mark-paragraph      |

   After pressing a key to select the semantic unit, you can press another key
   to add the surrounding pair, which is the same as =embrace-change= and
   =embrace-delete=.


* Customization
** Adding More Semantic Units
   You can modify the variable =embrace-semantic-units-alist= and note that
   this variable is buffer-local so it is better to change the value in a hook:
   : (add-hook 'text-mode-hook
   :     (lambda ()
   :        (add-to-list 'embrace-semantic-units-alist '(?e . er/mark-email))))

** Adding More Surrounding Pairs
   Use the command =embrace-add-pair= to add a pair:
   : (embrace-add-pair key left right)

   The change is also buffer-local, so wrap it in a hook function:
   : (add-hook 'LaTeX-mode-hook
   :     (lambda ()
   :        (embrace-add-pair ?e "\\begin{" "}")))

   If you want add something like the =t= key for the tag, you can look at the
   function =embrace-add-pair-regexp= in the source code, and if you're planning
   to use =embrace-add-pair-regexp=, you should also use =embrace-build-help= to
   build the user-friendly help message.

   Note that if you're using =embrace-add-pair= to add an existing key, then it
   will replace the old one.


** Disable Help Message
   If you find the help message annoying, use the following code to disable it:
   : (setq embrace-show-help-p nil)

** Example Settings
   I recommend binding a convenient key for =embrace-commander=. For example,
   : (global-set-key (kbd "C-,") #'embrace-commander)

   We have defined several example hook functions that provide additional key
   bindings which can be used in different major modes. Right now there are
   hooks for =LaTeX-mode= and =org-mode=:

   =LaTeX-mode=:
   | Key | Left       | Right |
   |-----+------------+-------|
   | =   | \verb\vert | \vert |
   | ~   | \texttt{   | }     |
   | /   | \emph{     | }     |
   | *   | \textbf{   | }     |

   =org-mode=:
   | Key | Left             | Right             |
   |-----+------------------+-------------------|
   | =   | =                | =                 |
   | ~   | ~                | ~                 |
   | /   | /                | /                 |
   | *   | *                | *                 |
   | _   | _                | _                 |
   | +   | +                | +                 |
   | k   | ~@@html:<kbd>@@~ | ~@@html:</kbd>@@~ |

   =ruby-mode (and enh-ruby-mode)=:
   | Key | Left | Right |
   |-----+------+-------|
   | d   | do   | end   |
   | #   | #{   | }     |

   To use them:
   : (add-hook 'LaTeX-mode-hook 'embrace-LaTeX-mode-hook)
   : (add-hook 'org-mode-hook 'embrace-org-mode-hook)
   : (add-hook 'ruby-mode-hook 'embrace-ruby-mode-hook) ;; or 'enh-ruby-mode-hook

   The code for the three hooks above (which are defined in =embrace.el=):
   : (defun embrace-LaTeX-mode-hook ()
   :   (dolist (lst '((?= "\\verb|" . "|")
   :                  (?~ "\\texttt{" . "}")
   :                  (?/ "\\emph{" . "}")
   :                  (?* "\\textbf{" . "}")))
   :     (embrace-add-pair (car lst) (cadr lst) (cddr lst))))
   : (defun embrace-org-mode-hook ()
   :   (dolist (lst '((?= "=" . "=")
   :                  (?~ "~" . "~")
   :                  (?/ "/" . "/")
   :                  (?* "*" . "*")
   :                  (?_ "_" . "_")
   :                  (?+ "+" . "+")
   :                  (?k "@@html:<kbd>@@" . "@@html:</kbd>@@")))
   :     (embrace-add-pair (car lst) (cadr lst) (cddr lst))))
   : (defun embrace-ruby-mode-hook ()
   :   (dolist (lst '((?# "#{" "}")
   :                  (?d "do" "end")))
   :     (embrace-add-pair (car lst) (cadr lst) (caddr lst))))

   You can define and use your own hook function similar to the code above.

   Welcome to add some settings for more major modes.

* For =evil-surround= Users
** Where =embrace= is better
  From the previous example, you can see that =embrace= actually replicates all
  the funcionalities provided in =evil-surround= and it can even do more than
  =evil-surround=. Actually, they are quite different. Since =embrace= uses
  =expand-region= behind the scene, you can expect it to work as long as
  =expand-region= works. Unlike =evil-surround=, which is restricted to the
  pre-defined text objects, =embrace= can define nearly arbitrary surrounding
  pairs and three core commands always work. On the contratry, you get nearly no
  customization in =evil-surround=: custom pairs don't work in =cs= or =ds= if
  you don't have a corresponding text object defined (they work in =ys=).

  *TL;DR*: =embrace= is more customizable.
** Why not use together?
   Sure! You can make =embrace= and =evil-surround= work together. Look at
   [[https://github.com/cute-jumper/evil-embrace.el][evil-embrace]]!

* Contributions
This package is still in early stage, but it is quite usable right now. More
functions can be added and the evil integration is not perfect yet.
Contributions are always welcome!
* Related Packages
  - [[https://github.com/cute-jumper/evil-embrace.el][evil-embrace]]
  - [[https://github.com/magnars/expand-region.el][expand-region]]
  - [[https://github.com/timcharper/evil-surround][evil-surround]]
  - [[https://github.com/magnars/change-inner.el][change-inner]]
  - [[https://github.com/Fuco1/smartparens][smartparens]]

Not written in Markdown, so it's shown here as plain text — view it formatted on GitHub.

emacs
evil-surround
expand-region

Contributors

cute-jumper

48 commits

syohex

2 commits

dcluna

1 commits

LemonBreezes

1 commits

Languages

Emacs Lisp

100.0%