Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing several very useful paredit commands #5

Open
bpstahlman opened this issue Sep 2, 2014 · 17 comments
Open

Missing several very useful paredit commands #5

bpstahlman opened this issue Sep 2, 2014 · 17 comments

Comments

@bpstahlman
Copy link
Collaborator

I love vim-sexp, and am very excited about the possibility of using vim-sexp instead of paredit; having used it for several weeks, however, there are several useful paredit commands I really miss: e.g.,
paredit-forward-down
paredit-forward-up
paredit-backward-down
paredit-backward-up
paredit-split-sexp
paredit-join-sexps
paredit-splice-sexp-killing-backward
paredit-splice-sexp-killing-forward

If vim-sexp had these commands, I think it would be "no contest" between it and vim paredit (and possibly even emacs paredit)...

@guns
Copy link
Owner

guns commented Sep 2, 2014

Hello, thanks for the feedback!

I'm afraid I might need some clarification on these commands:

paredit-forward-down
paredit-forward-up
paredit-backward-down
paredit-backward-up

Do these work differently from the following mappings?

vim-sexp/doc/vim-sexp.txt

Lines 143 to 174 in b0878de

( *<Plug>(sexp_move_to_prev_bracket)*
) *<Plug>(sexp_move_to_next_bracket)*
[count] paired brackets backward or forward, |exclusive|.
When used in |operator-pending| mode, the following exceptions apply:
* [count] is ignored
* Backward motion excludes the foremost bracket
* Forward motion from a bracket excludes both the current bracket
and the last bracket, unless the resulting selection is empty,
in which case the motion includes both brackets
The default mappings shadow the internal |(| and |)| mappings. These
sentence object motions are of limited use in code buffers, but if
you disagree, see |g:sexp_mappings| for documentation on changing the
default mappings.
<M-b> *<Plug>(sexp_move_to_prev_element_head)*
<M-w> *<Plug>(sexp_move_to_next_element_head)*
[count] sibling elements backward or forward, |exclusive|, placing the
cursor on the head of an element. Movement is bounded by the parent
list, if any.
Analogous to |b| and |w| motions.
g<M-e> *<Plug>(sexp_move_to_prev_element_tail)*
<M-e> *<Plug>(sexp_move_to_next_element_tail)*
[count] sibling elements backward or forward, |inclusive|, placing the
cursor on the tail of an element. Movement is bounded by the parent
list, if any.
Analogous to |ge| and |e| motions.

I use ( and ) to move the cursor to a parent sexp, and the elementwise mappings to operate on adjacent sexps.

paredit-split-sexp
paredit-join-sexps

I did think of implementing these, but I never got around to it because I don't use them myself. Since you do, however, I'll gladly add them when I return from my current hiatus.

paredit-splice-sexp-killing-backward
paredit-splice-sexp-killing-forward

These seem identical to vim-sexp's raise mappings:

vim-sexp/doc/vim-sexp.txt

Lines 257 to 260 in b0878de

<LocalLeader>o *<Plug>(sexp_raise_list)*
<LocalLeader>O *<Plug>(sexp_raise_element)*
Replace [count] enclosing lists (compound FORMs) with the current
list, element, or visual selection.

The difference between the two mappings is that one operates on the current compound form, while the other operated on the current sexp (aka element). The current compound form is also the current element when the cursor is on a bracket. These commands also work in visual mode so that you can replace the parent form with multiple child sexps.

You may also be interested in the swap commands, which move a compound form/element within a parent form:

vim-sexp/doc/vim-sexp.txt

Lines 262 to 276 in b0878de

<M-k> *<Plug>(sexp_swap_list_backward)*
<M-j> *<Plug>(sexp_swap_list_forward)*
<M-h> *<Plug>(sexp_swap_element_backward)*
<M-l> *<Plug>(sexp_swap_element_forward)*
Swap the current list (compound FORM), element, or visual selection
[count] times with the adjacent list or element. Does nothing if there
is no adjacent element in the desired direction.
If moving a visual selection, the selection is first expanded to cover
all partially selected lists and elements so that structural integrity
is maintained.
If moving an even number of elements with a visual selection, the
swap is done pairwise to preserve the associative structure of the
containing compound form.

Again, I don't have much experience with paredit, so please let me know if I am misunderstanding these commands. I will implement the split and join commands when I am available. Thanks!

@bpstahlman
Copy link
Collaborator Author

Sung Pae,
See comments inline...

On Tue, Sep 2, 2014 at 4:11 PM, Sung Pae [email protected] wrote:

Hello, thanks for the feedback!

I'm afraid I might need some clarification on these commands:

paredit-forward-down
paredit-forward-up
paredit-backward-down
paredit-backward-up

Do these work differently from the following mappings?

vim-sexp/doc/vim-sexp.txt

Lines 143 to 174 in b0878de

( *<Plug>(sexp_move_to_prev_bracket)*
) *<Plug>(sexp_move_to_next_bracket)*
[count] paired brackets backward or forward, |exclusive|.
When used in |operator-pending| mode, the following exceptions apply:
* [count] is ignored
* Backward motion excludes the foremost bracket
* Forward motion from a bracket excludes both the current bracket
and the last bracket, unless the resulting selection is empty,
in which case the motion includes both brackets
The default mappings shadow the internal |(| and |)| mappings. These
sentence object motions are of limited use in code buffers, but if
you disagree, see |g:sexp_mappings| for documentation on changing the
default mappings.
<M-b> *<Plug>(sexp_move_to_prev_element_head)*
<M-w> *<Plug>(sexp_move_to_next_element_head)*
[count] sibling elements backward or forward, |exclusive|, placing the
cursor on the head of an element. Movement is bounded by the parent
list, if any.
Analogous to |b| and |w| motions.
g<M-e> *<Plug>(sexp_move_to_prev_element_tail)*
<M-e> *<Plug>(sexp_move_to_next_element_tail)*
[count] sibling elements backward or forward, |inclusive|, placing the
cursor on the tail of an element. Movement is bounded by the parent
list, if any.
Analogous to |ge| and |e| motions.

I use ( and ) to move the cursor to a parent sexp, and the elementwise
mappings to operate on adjacent sexps.

( and ) are good for moving up the sexp tree, but often you need to move
down: e.g., when you've jumped to a define with [[ or ]] and you need to
operate on something several levels deep. Of course, you could always use
Vim's / to get where you're going, but that forces you to operate on the
forms as text rather than as structured s-expressions. Since M-w and M-b
work only within the current level, they can't be used for downward
movements either.

paredit-split-sexp
paredit-join-sexps

I did think of implementing these, but I never got around to it because I
don't use them myself. Since you do, however, I'll gladly add them when I
return from my current hiatus.

Thanks! They can be useful, though perhaps aren't used as often as some of
the others.

paredit-splice-sexp-killing-backward
paredit-splice-sexp-killing-forward

These seem identical to vim-sexp's raise mappings:

Backward and forward killing splice are more like vim-sexp's splice
command; the difference is that with paredit's splice killing
backward/forward commands, you can splice only the text on one side of the
cursor (deleting the text on the other side): e.g.,

Given the following... (cursor indicated by | )
(1 2 3 | 4 5 6)

paredit-splice-sexp-killing-backward ==> 4 5 6
paredit-splice-sexp-killing-forward ==> 1 2 3

vim-sexp/doc/vim-sexp.txt

Lines 257 to 260 in b0878de

<LocalLeader>o *<Plug>(sexp_raise_list)*
<LocalLeader>O *<Plug>(sexp_raise_element)*
Replace [count] enclosing lists (compound FORMs) with the current
list, element, or visual selection.

The difference between the two mappings is that one operates on the
current compound form, while the other operated on the current sexp (aka
element). The current compound form is also the current element when the
cursor is on a bracket. These commands also work in visual mode so that you
can replace the parent form with multiple child sexps.

Yes. The distinction between current element and current form is very nice,
and I do appreciate the ability to operate on the visual selection, but
when backward/forward killing behavior is what you need, having to select
visually first can break your flow...

You may also be interested in the swap commands, which move a compound
form/element within a parent form:

Yes. I am familiar with those - a very nice touch. I especially like that
such commands support counts.

vim-sexp/doc/vim-sexp.txt

Lines 262 to 276 in b0878de

<M-k> *<Plug>(sexp_swap_list_backward)*
<M-j> *<Plug>(sexp_swap_list_forward)*
<M-h> *<Plug>(sexp_swap_element_backward)*
<M-l> *<Plug>(sexp_swap_element_forward)*
Swap the current list (compound FORM), element, or visual selection
[count] times with the adjacent list or element. Does nothing if there
is no adjacent element in the desired direction.
If moving a visual selection, the selection is first expanded to cover
all partially selected lists and elements so that structural integrity
is maintained.
If moving an even number of elements with a visual selection, the
swap is done pairwise to preserve the associative structure of the
containing compound form.

Again, I don't have much experience with paredit, so please let me know if
I am misunderstanding these commands. I will implement the split and join
commands when I am available. Thanks!

Vim-sexp is a great plugin! I was extremely excited when I found it
recently. I appreciate the work that must have gone into it. I believe that
by adding the missing paredit functionality, you could eliminate one of the
last remaining reasons why even some longtime Vim users sometimes feel
drawn to emacs for lisp...

Sincerely,
Brett Stahlman


Reply to this email directly or view it on GitHub
#5 (comment).

@bpstahlman
Copy link
Collaborator Author

Another useful feature would be the ability to specify a numeric count for the wrap commands: i.e., wrap the current sexp and the next {count}-1 sexps. I know you can select them visually, but that's a bit more work than simply specifying a count.

@gregspurrier
Copy link

+1 for downward movements. I miss these from emacs paredit.

@bhurlow
Copy link

bhurlow commented Dec 6, 2015

+1 for downward movements as well. This would complete the vim sexp experience!

@bpstahlman
Copy link
Collaborator Author

Just wondering about the status of vim-sexp development in general. I see no commits to master in the past year, and I noticed several forks have been created... I was very excited about the plugin's potential initially, but I'm concerned that development may have stalled...

@bhurlow
Copy link

bhurlow commented Aug 8, 2016

Brett,

I've moved away from vim-sexp entirely as have other people I imagine. Am currently
going the 'parinfer' route, see here:
https://github.com/bhurlow/vim-parinfer

On Mon, Aug 1, 2016 at 2:08 PM, Brett Stahlman [email protected]
wrote:

Just wondering about the status of vim-sexp development in general. I see
no commits to master in the past year, and I noticed several forks have
been created... I was very excited about the plugin's potential initially,
but I'm concerned that development may have stalled...


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#5 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/ABSyWONVIaAn1F3VnWNR2jdLUHfKhhfbks5qbjY3gaJpZM4CdrVB
.

@bpstahlman
Copy link
Collaborator Author

@bhurlow Thanks Brian. An intriguing concept. I've been reading through the docs, and may have a question or two for you (if you don't mind) after I've had a chance to digest...

@bhurlow
Copy link

bhurlow commented Aug 9, 2016

@bpstahlman which S expression lang are you targeting?

@bpstahlman
Copy link
Collaborator Author

Primarily Clojure and Scheme. Have also worked with Picolisp. I've tried
Paredit, Slimv, Fireplace, etc... At one point, I cobbled together an
approach that used "screen" to send snippets to a running interpreter. Have
even toyed with the idea of using Emacs/Evil, though as a longtime Vim
user, I'd prefer sticking with an editor that feels natural. When vim-sexp
came along, I was really excited, but there are a few things it still
needs, and I'm starting to wonder whether it's been abandoned…

On Aug 9, 2016 6:40 PM, "Brian Hurlow" [email protected] wrote:

@bpstahlman https://github.com/bpstahlman which S expression lang are
you targeting?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#5 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/AC7pQELb5Cv7Nmgn0qpZRxUWfoLkYDsiks5qeQ_YgaJpZM4CdrVB
.

@guns
Copy link
Owner

guns commented Aug 10, 2016

Howdy all!

vim-sexp is not abandoned, but its maintainer is a little busy! For now, compound and element text objects work well, and moving sexps around still feels awesome.

We should add the commands listed in this issue, but I think their present omission is merely inconvenient. Feature parity with the emacs paredit plugin is a goal, but the real meat and potatoes of vim-sexp are the text objects.

The S-expression text objects compose well with vim idioms and other plugins, so I consider vim-sexp a success by that metric.

Evaluation of Lisp forms is explicitly not a goal of this project. vim-sexp is a text-editing plugin that provides idiomatic ways to manipulate symbolic forms. It can be combined with REPL plugins like Fireplace¹ or screen.vim to provide a complete Lisp programming experience, but that is a task left to the user or to another plugin.

I am probably not the right person to write a Lisp IDE since my own preferences in that space are unidiomatic.

Anyway, thank you all for your comments, and could you please keep non-topical discussion off this issue page?

@bpstahlman
Copy link
Collaborator Author

Understood. Thanks. Incidentally @bhurlow , I've been corresponding with the author of parinfer, and from what I can tell, parinfer and vim-sexp are not necessarily mutually-exclusive. It might be possible to use vim-sexp for its powerful s-expression editing capability, and use parinfer (e.g., in remaps of << and >>) to handle paren recalculation in response to indent changes.

@spellman
Copy link

+1 for split and join :)

@Sleepful
Copy link

the ( ) keybinds do the same thing as the vanilla [( and ]) commands in nvim :)

now the only missing piece is the down-forward!

@Sleepful
Copy link

Shameless self-promotion ahead...

For now, this can be used as a bit of a band-aid over the navigation: https://github.com/Sleepful/leap-by-word.nvim

You can use it like s( and then jump straight to any opening parenthesis for example.

@Sleepful
Copy link

A few alternatives that can be explored (but need to be worked on) would be:

  • adding a treesitter command, somehow.
  • adding a mini.ai command, somehow.
  • working on a PR in this repo (probably nicest one for everyone else)

@Sleepful
Copy link

oh wait nvm, looks like paredit-forward-down also called downward movements are already implemented, seems to be this one:

<M-]>                                         *<Plug>(sexp_flow_to_next_open)*

https://github.com/guns/vim-sexp/blob/master/doc/vim-sexp.txt#L246C1-L247C79

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants