GitHub - casouri/isolate: Surrounding magics, extensible
source link: https://github.com/casouri/isolate
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
README.org
isolate.el
This package provides a powerful surrounding tool. It helps you to add, delete and change pairs.
Inspired by siege-mode.
Table of Contents
Why you want it
PowerfulIt can recognize complex input, for example, html tags. Straight forwardEach action (add/delete/change) has two variants:quick
and long
. quick
takes one key like (
and long
takes a longer input like <div class="">
.
Easily extendableYou can define new complex pairs easily by wrting regexp.
Introduction
How it works
- User input the left side of the pair,
isolate
completes the right size by looking up “rule book” (which defines pairs)isolate
add/delete the pair
Recognize?
Basically, isolate
provides three ways to regognize a pair:
- normal pairing, e.g.
(
to)
,+
to+
. - recognize pairs by regexp, e.g. regognize
<xxx>
as the left of a html tag, complete it with</xxx>
. - recognize pairs by a shortcut, e.g.
org-src
as a shortcut of#+BEGIN_SRC
and#+END_SRC
.
This works for both adding and deleting.
Add examples
An example for the first case
Command: isolate-quick-add
1. input: ( HELLO -> (HELLO) 2. input: ) HELLO -> ( HELLO )
A side node: segmentation
When you separate your input into segements on the left, isolate inverse the order of them on the right.
The separator is “,” by default.
ABC -> 1,2,3ABC -> 123ABC321
An example for the second case
By inserting <div>
on the left, isolate completes the html pair for you.
And it even recognizes a more complex input and completed the pair correctly.
Command: isolate-long-add
1. HELLO -> <p>HELLO -> <p>HELLO</p> 2. HELLO -> <div class="">,<p>HELLO -> <div class=""><p>HELLO</p></div> 3. HELLO -> <div class="">,⮐,<p>,⮐,HELLO -> <div class=""> <p> HELLO </p> </div>
An example for the third case
Command: isolate-long-add
HELLO -> org-srcHELLO ->
#+BEGIN_SRC
HELLO
#+END_SRC
Delete examples
Above features also apply to change and delete commands
Command: isolate-quick-delete
1. input: ( (HELLO) -> HELLO 2. input: ) ( HELLO ) -> HELLO
The shortcuts are especially useful in deleting
Command: isolate-long-delete
1. <t> -> html tag 2. <div> -> div tag 3. <xxx> -> xxx tag
Command: isolate-long-delete
Featuring shortcuts appeared above
input: org-src
#+BEGIN_SRC
HELLO
#+END_SRC
-> HELLO
You can extend it!
All of these cool featurea are implemented by regexp matching (except segmentation). Therefore, you can extend these isolation magics by writing regexp rules! It’s very easy!
Install
isolate
is not in melpa,
you need to intall and load manually or by quelpa.
Usage
There are six commands avaliable:
isolate-quick-add
isolate-long-add
isolate-quick-delete
isolate-long-delete
isolate-quick-change
isolate-long-change
Quick commads asks for a key and add/delete/change the pair matches to it.
Long commands allows you to make more complex edits and
apply the change with C-c C-c
If you use evil, I suggest binding quick commands to s
operators
and long commands to S
operators.
Long add
C-c C-aGo to beginning of left sideC-c C-eGo to end of left sideC-c C-cFinish editC-c qAbort editLong delete
In minibuffer:
C-pMatch outter pairC-nMatch inner pairRETFinish editC-gAbort editSegmentation
You can segment your input with a special separator (default to “,”).
isolate
inverses the order of segments on the right side:
1,2,3 -> 321
A very good use case is line surrounding:
(,RET -> RET)
which looks like:
( surrounded-text )
Quick command shortcuts
)
, ]
, }
and >
are translated to pair with space:
( surrounded-text )
Comparison with alternatives
evil-surround
evil-surroundisolaterequires evilyesnofiddle with text objectsyesno (straight forward!)extendingwrite hooks for each major modespecify major mode (and other) condition(s) in rule listregexpnoyesembrace
evil-surroundisolateextendingembrace-language-minor-modespecify major mode (and other) condition(s) in rule listregexpnoyessiege-mode
evil-surroundisolateextendingI’m nor familiarspecify major mode (and other) condition(s) in rule listregexpyesyesabilitiesaddadd, change, deleteCustomizaion
The biggest part!
Rule list
The matching rule is in isolate-pair-list
.
isolate
try to match user input whth a pair in this list.
How does isolate uses this rule list:
For add functions, isolates record user input (the left side), calculates the right side, insert right side and the end of region.
The calculating part is where the rule list apply.
isolate
uses the user input to match each “pair” in the
rule list, and outputs a left and right side string.
There are three ways to match left side and gets a pair, as described in the documentation below.
If the user input doesn’t match anything, isolate
simply uses it as-is.
Here is the default value and documentation of it:
(defvar isolate-pair-list '(((to-left . "`") (to-right . "'") (no-regexp . t) (condition . (lambda (_) (if (equal major-mode 'emacs-lisp-mode) t nil)))) ((to-left . "(") (to-right . ")")) ((to-left . "[") (to-right . "]") (no-regexp . t)) ((to-left . "{") (to-right . "}")) ((to-left . "<") (to-right . ">")) ((from . "<\\([^ ]+\\).*>") (to-right . (lambda (left) (format "</%s>" (match-string 1 left))))) ((to-left . "\\{begin}") (to-right . "\\{end}")) ((from . "org-src") (to-left . "#+BEGIN_SRC\n") (to-right . "#+END_SRC\n") (no-regexp . t)) ) "Matching pairs. Each element is an alist with five possible keys: 'from, 'to-left, to-right, no-regexp and condition. Only ('from or 'to-left) and 'to-right are required. 'right is required, one of 'from and 'to-left is required, 'condition is optional. 1. If only 'to-left, and it equal to user input, and matches and condition passes, 'to-left is used as left of pair, 'to-right is used as right of pair. 2. If only 'from, and the regexp of 'from matches user input, user-input is used as left of pair and 'to-right is used as right of pair. 3. If both 'from and 'to-left exists, 'from as regexp is used to match user-input, if it matches, 'to-left is used as left of pair and 'to-right is used as right of pair. In addition, 'to-left and 'to-right can be a function that takes user input as argument and return a string. If they are functions, and you have a regexp 'from, you can use (match-string num user-input) to get regexp matched groups. 'condition, if exist, should be a function that takes user input as argument and return a boolean. You can use it to check major modes, etc. 'no-regexp only affects delete commands, if you want to search the matched pair plainly by text rather than by regexp, add \(no-regexp . t\). This is especially important for pairs that contains regexp keywords such as [, \\, +, etc. A word of 'from: \"^\" and \"$\" are added automatically to from before matching. Also don't forget regexp escapes.")
Delete function’s extended rule list.
There is also isolate-delete-extended-pair-list
.
This rule list is used by delete functions
in addition to isolate-pair-list
.
So it’s called “extended” list.
The pairs in this list are tried first, then
are that of isolate-pair-list
.
How does delete function uses rule lists:
First, delete function asks for user input. Then it do the same thing as in add functions: Try to calculate out a pair.
When it gets a pair, or doesn’t match anything and ends up
with the original input, isolate
uses the calculated (or not)
left and right string to match text in buffer.
If it can found the paired text, you can delete them.
Note that with (match-string)
you can compose generic rules!
Here is the default value:
(defvar isolate-delete-extended-pair-list '(((to-left . "\\") (to-right . "\\") (no-regexp . t)) ((to-left . "+") (to-right . "+") (no-regexp . t)) ((to-left . ".") (to-right . ".") (no-regexp . t)) ((to-left . "*") (to-right . "*") (no-regexp . t)) ((to-left . "?") (to-right . "?") (no-regexp . t)) ((to-left . "^") (to-right . "^") (no-regexp . t)) ((to-left . "$") (to-right . "$") (no-regexp . t)) ((from . "<t>") (to-left . "<[^/]+?>") (to-right . "</.+?>")) ((from . "<\\([^ ]+\\)[^<>]*>") (to-left . (lambda (user-input) (format "<%s *.*?>" (match-string 1 user-input)))) (to-right . (lambda (user-input) (format "< *?/%s *?>" (match-string 1 user-input)))))) "Rule list. Detail see `isolate-pair-list'.")
Shortcuts for quick commands
The last rule list is for quick commands. This is how “pair with space” are achieved.
When using quick commands you enter a key. But before isolate matches this single character to a pair, the string goes trhough a translator.
Basically, you can “translate” some predefined keys to longer strings, for example:
) -> "(, " (parans -> parens with space)
The rule list is isolate-quick-shortcut-list
,
its default value is:
(defvar isolate-quick-shortcut-list '(((from . "]") (to . "[, ")) ((from . ")") (to . "(, ")) ((from . "}") (to . "{, ")) ((from . ">") (to . "<, ")) ) "Shortcuts for `isolate-quick-xxx' functions. For example, by default \"]\" is mapped to \"[ \", etc. Each element is an alist representing a shortcut. Each shortcut have three possible keys: 'from, 'to and 'condition. 'from and 'to are strings \(not regexp!\), 'condition is a function that takes user input as argument. 'condition is optional. If 'condition exists and returns nil, the shortcut will be ignored.")
Contribution
Contribution is welcomed! Especially matching rules. As you can see, right now there aren’t much of them.
For examples, there can be more latex pairs, but I don’t use latex so I don’t know any.
Also, if you think documentation needs improvement, please let my know so I know how to do better.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK