smartparens
smartparens copied to clipboard
Way to wrap region and stay inside pairs
Sorry if this feature was asked or presented in Smartparens, I was unable to find it, and hack upon Smartparens to implement it myself. This is similar to https://github.com/Fuco1/smartparens/issues/508
TL;DR
Provide a way to wrap region and stay inside pairs with point resting at beginning or end of region depending on what key is pressed without depending on region orientation. E.g.
(|some text) ;; user selected "some text" and pressed "("
(some text|) ;; user selected "some text" and pressed ")"
[|some text] ;; user selected "some text" and pressed "["
[some text}] ;; user selected "some text" and pressed "]"
;; and so on
When writing in Lisp languages it is extremely useful, and Paredit does this for opening parenthesis, which I find very helpful.
More detailed explanation
Currently it is possible to select a region and press ( or ) and have this outcome:
(%
represents region, |
represents point)
Region:
%some text|
press (:
(some text)|
It works the same with ) Region:
%some text|
press ):
(some text)|
If we reverse region, we get the desired outcome when pressing (. Region:
|some text%
press (:
(|some text)
But if we press ) we are out of the pairs again: Region:
|some text%
press ):
(some text)|
There also is a variable sp-wrap-respect-direction
, which I can set to true, and this will work mostly like I want it to without manually reversing region, however it keeps the point outside of the parentheses:
Region:
%some text|
press (:
|(some text)
It works the same with ) Region:
%some text|
press ):
(some text)|
A possible solution was suggested in Emacs chat in telegram:
(setq sp-wrap-respect-direction t)
(defun sp--wrap-fix-cursor-position (_id action _context)
(when (and (eq action 'wrap)
(eq (point)
;; position before delimiter
(marker-position (sp-get sp-last-wrapped-region :beg))))
(goto-char
;; position after delimiter
(sp-get sp-last-wrapped-region :beg-in))))
(sp-pair "(" nil :post-handlers '(:add sp--wrap-fix-cursor-position))
This makes ( behave like in Paredit.
So to summarize, you want the exact same behaviour as we get when sp-wrap-respect-direction
and additional always (or only in some cases?) to position the cursor inside the pair. Is this correct?
Yes, I want a toggle that will make it possible to define this behaviour for all pairs. Like sp-wrap-respect-direction
, makes smartparens respect direction, I want a way of being able make it stay inside or go outside by toggling some variable.,
I mean I do this all the time, when wrapping stuff in Org mode, and want to continue typing inside wrapped region right away. My workflow requires this much more often, compared to when I simply forgot to wrap something and want to type additional text after wrapping. E.g.
I have this text in a Org mode buffer:
Function sum-of-squares will compute the sum of squares....
I've forgotten to wrap "sum-of-squares" with =
. Which means that I would select it, and press =, with sp-wrap-respect-direction
set to t
producing:
Function |=sum-of-squares= will compute the sum of squares....
(|
represents the cursor)
This makes little sense, as I would not want to add more text before the already existing text. More than that, with org-hide-emphasis-markers
set to t
it is impossible to acutally add something before sum
or after squares
without deleting either text of the =
With the option I'm asking set to t
, pressing = it should produce
Function =|sum-of-squares= will compute the sum of squares....
Which makes much more sense in the long run, because =
is not directional pair, and since there's already text after wrapped region so the chances I would want to add something after the last =
are minimal.
I also thing, that when writing code, you wrap things only if you're changing the existing code, and wrapping usually means that you will need to change things inside wrapped region. Maybe you're changing things and then wrap, but I'm not and hence this setting would be very useful :)
Answering your question: yes, always
What you say makes sense and in org mode I also often fight the same issue (note that you can sp-down-sexp
to jump in the =asd=
pair).
I think I would like this with the string-like delimiters, but for code I'm not so sure. I don't consciously remember this ever annoying me too much. Since a per-pair setting is already mentioned in your answer, adding a global setting might make sense).
I think instead of adding more settings I will extend sp--run-hook-with-args
(which fires the events based on the pair) to also fire a global hook. This way you can add your function from above to this hook and it will always trigger.
Overall I'm quite happy that even after 8 years the extension API/configuration is still capable of solving almost any issue... but it is clunky as hell, especially for newcomers. Bad thing is I don't quite have ideas how to make it nicer and also backward compatible.