lispy icon indicating copy to clipboard operation
lispy copied to clipboard

Non-intuitive string termination

Open bpstahlman opened this issue 8 years ago • 17 comments

When I hit " to enter a quoted string, Lispy inserts a pair of quotes and leaves point between them to allow me to enter the text of the string. This feels natural and is pretty much the way lisp editors generally work (and the way paren pairs work even in Lispy). When I've finished entering the string, however, there doesn't appear to be a natural way to terminate the string and move on to insert the next sexp. Initially, I would hit ", expecting point to move past the closing quote, but this resulted in a pair of escaped quotes being inserted in the string. I can imagine that there are situations in which you'd want a pair of escaped quotes inside the string, but this is a much less common use case than the one in which you simply want to hit " to terminate the string. I see that I can hit C-f in this situation. Is that the recommended way? Is the reason for not making the "move past terminating quote" functionality the default that this would force the "insert pair of escaped quotes" functionality to be moved to something like lispy-quotes with a negative arg (since positive arg is already used to unquote a string)?

bpstahlman avatar Jan 16 '17 19:01 bpstahlman

@bpstahlman C-f seems to be the only way, but you can bind (kbd "\"") to lispy-doublequote if you want " to terminate.

I have a slightly related question: How to delete an empty string?

I would expect DEL and C-d, but they go in and out of quotes without deleting anything. Even M-x lispy-splice removes parentheses instead of quotes. Maybe I'm lacking creativity, but tell me how to delete an empty string?

Somelauw avatar Jan 17 '17 21:01 Somelauw

@Somelauw With point inside the empty string, DEL moves point just to the right of the empty string (just past the closing "). From that position, a subsequent DEL will delete the entire string.

bpstahlman avatar Jan 18 '17 12:01 bpstahlman

@bpstahlman thanks, there is a difference between lispy-delete-backward and lispy-backward-delete and I was using the latter instead of the former.

Somelauw avatar Jan 18 '17 13:01 Somelauw

I see that I can hit C-f in this situation. Is that the recommended way?

Yes, that's what I do. Using lispy-alt-line, which I bind to RET in my own config also works to escape strings.

abo-abo avatar Jan 18 '17 16:01 abo-abo

@Somelauw When inside a string, delete it:

  • if from the end, C-d C-d
  • if from the start, DEL DEL

abo-abo avatar Jan 18 '17 16:01 abo-abo

@abo-abo Ok. Thanks. I wasn't aware of lispy-alt-line as it doesn't appear in the documentation. Just found it in lispy.el. Fwiw, I would say that in the case of strings (unlike lists), needing to "escape from" the sexp is much more common than needing to nest a pair of delimiters within it, to the point that most users would probably be fine with doing something extra to get the nesting behavior if it meant they could simply hit " in the common case to escape from the string. Even more significant than the extra keystroke is the violation of the "principle of least surprise," which can be especially problematic for new users. (My son was thrown by the same thing when he started using lispy a few days ago... ;-) But perhaps backwards-compatibility is the issue...

bpstahlman avatar Jan 18 '17 16:01 bpstahlman

@bpstahlman I've just gone to binding " to nil in lispy-mode-map, and letting smartparens take care of that pair.

@abo-abo What is the rationale for having to call lispy-delete or lispy-delete-backward twice to delete empty strings? You can already lispy-alt-line or C-f/b to move out of the empty string.

The way deleting empty lists works from within is inconsistent as well. From (|), lispy-delete-backward will kill the pair, but lispy-delete will first move point out of pair and require another keypress.

sooheon avatar May 13 '17 09:05 sooheon

What is the rationale for having to call lispy-delete or lispy-delete-backward twice to delete empty strings?

I'll give an example. In this case, it's correct to delete at once with C-d, since the cursor is before an atom (it's like you press C-d on one char):

|"test"

But what about C-d in this case:

"test|"

It feels unnatural for C-d to delete backwards. So the first C-d will move out backwards, to reduce the deletion to the natural case. Works exactly the same way with lists.

abo-abo avatar May 13 '17 10:05 abo-abo

I think the consistency could be improved.

You are correct that C-d from the following states are equivalent:

(test|)
"test|"

But here:

(|test)

lispy-delete-backward will remove the entire sexp immediately, and I find this intuitive, because in the following, backspace will kill the pair (but, another inconsistency, C-d won't).

(|)

If it feels unnatural to kill a whole atom when deleting from within, that's ok, but I think the behavior when backspacing or C-d from within an empty list or string should always be just to kill the pair.

I think this could be accounted for with a variable `lispy-delete-atom-from-within'. When true, C-d from any of the following:

(|)
(foo|)
"|"
"foo|"

or backspace from one of the following:

(|)
(|fooo)
"|"
"|bar"

Will always just kill the whole thing.

Thoughts? If you think this is ok but don't want to spend time on it, I could make a PR

sooheon avatar May 13 '17 13:05 sooheon

Thoughts? If you think this is ok but don't want to spend time on it, I could make a PR

sounds good.

abo-abo avatar May 13 '17 14:05 abo-abo

I think it may make more sense to rename the variable to something like lispy-delete-string-or-sexp-from-within or lispy-delete-entire-from-within since "atom" only describes the string part.

noctuid avatar May 14 '17 16:05 noctuid

I guess string-or-sexp is most descriptive

sooheon avatar May 15 '17 01:05 sooheon

@noctuid I agree. @sooheon Either string-or-sexp or plain sexp is fine with me.

abo-abo avatar May 15 '17 10:05 abo-abo

Stupid question, I'm not all too well versed in Emacs, how do I bind " to nil in the lispy-mode-map? Doing (define-key lispy-mode-map (kbd "\"") nil) doesn't do anything.

sondr3 avatar May 24 '17 01:05 sondr3

@sondr3

(define-key lispy-mode-map-lispy (kbd "\"") nil)

abo-abo avatar May 24 '17 08:05 abo-abo

Thanks you @abo-abo, that worked 😄

sondr3 avatar May 24 '17 12:05 sondr3

I believe this issue could be closed unless there's an intention to make lispy-doublequote the default behavior for " which I think fits more naturally according to what the main point of the issue was. It would be even better if this function would actually insert a \"\" if we are not at the end of the string instead of a single \" but that's a minor nitpick, (define-key lispy-mode-map-lispy (kbd "\"") 'lispy-doublequote) is enough for me.

zzantares avatar Apr 07 '20 05:04 zzantares