drym-org / symex.el

An intuitive way to edit Lisp symbolic expressions ("symexes") structurally in Emacs
Other
271 stars 22 forks source link

Splice funkiness for me on doom and emacs 29.1 #132

Open johnabs opened 5 months ago

johnabs commented 5 months ago

To whom it may concern,

I'm currently trying to get the full functionality of symex mode working, and I'm having some trouble with splice.

Basically, I have some strange (to me) behavior and wanted to see if it was intentional:

(f1 (|x1| x2)) (the || represents my block cursor's position) running - or M-x symex-splice does nothing.

If I change my cursor in symex mode to highlight the whole symex (f1 |(x1 x2)| ), I instead get the error of "No surrounding delimiters found".

But if I do this (f1 |( x1 x2 )| ), splice works as intended (note the added spacing between the parameters in the parens and the parens, both must be present for splice to detect the delimiters, this is a similar issue with change-delimiter, the spaces must be there).

I tested every other command, and they all behave as intended, from what I can tell, but this seems odd to me. Any feedback on the matter would be greatly appreciated.

Thank you so much for your time and consideration.

Best, John

countvajhula commented 5 months ago

Hi John, thanks for the report! Let's get to the bottom of this funkiness.

What Lisp dialect are you using? Is it ELisp or Clojure or something else? What does C-h v tree-sitter-mode in the buffer show? In the case where it says "No surrounding delimiters found", could you look in your *Messages* buffer to see if there is any further context there? Typically, it would include some form of stacktrace or mention the name of the function that is the source of the error. If you wouldn't mind copying that and pasting it here, that would be helpful.

I'm not able to reproduce this locally, but I'm using a relatively old version of Emacs at the moment, so that could have something to do with it.

For reference, in your example, the intended behavior is that it should work in your second case, i.e. (f1 |(x1 x2)|), since Symex operates on the currently referenced (single) expression. In this case, we are referring to the symex (x1 x2) which we intend to splice into the containing symex. On the other hand, in (f1 (|x1| x2)), we are referring to the symex x1 alone. In this case, it would be possible to "raise" it via K to replace the containing expression with just x1, but it's not possible to splice (x1 x2) since we aren't referring to it in this case. Does that make sense? If you are still interested in this behavior, of course, there are ways to make it work that way (e.g. a keyboard macro would probably make the most sense here).

johnabs commented 5 months ago

Hi count, thanks for the response! (hope that's how you prefer to be referred to, lol)

I'm currently using common lisp with SBCL, though it also fails with elisp. As a quick aside, I was concerned that evil-smartparens may have been conflicting with evil-cleverparens so I disabled it, but that wasn't it either :/ Also, (not sure if this helps) I do have evil-everywhere enabled.

As for your questions:

  1. tree-sitter-mode in variable search seems to be set to nil; when trying to enable tree-sitter-mode to change this, it returns No language registered for major mode 'lisp-mode', not sure if that matters or if I need to fix it.

  2. When I check into the Messages buffer, I only see evil-select-paren: No surrounding delimiters found with no further detail, and I can't expand it or find any more information (at least that I'm aware of). I tried to run this function myself on the symex to play around with it, but it's not defined as interactive.

I also tried drilling into the various function definitions of the symex, evil-surround, etc. I also tried enabling evil-cleverparens in the lisp buffer, but still nothing. I did find this interesting tidbit in the evil-select-parens function: If the selection is exclusive, whitespace at the end or at the beginning of the selection until the end-of-line or beginning-of-line is ignored but I'm not sure if it applies here.

Also, just to clarify, I wasn't necessarily trying to change the default behavior, just trying to exhaust all the possible ways I could think of to get it to recognize the surrounding delimeters, and happened to stumble upon the spacing thing when I was testing symex-change-delimiter which added the spacing for me, which helped me find the "fix" to get it working.

Thanks for your help so far, sorry I couldn't provide more useful information, I'm kinda groping around in the dark here, so I hope some of the info I provided ends up being useful to diagnosing the issue :/

countvajhula commented 5 months ago

That all sounds good, thanks for the thoroughness. Can you do M-x toggle-debug-on-error and try again? That should give us a stacktrace when the "No surrounding delimiters" error happens.

johnabs commented 5 months ago

Okay, got it! Here's the trace:

  error("No surrounding delimiters found")
  evil-select-paren("( " " )" 1847 1847 nil 1 t)
  evil-surround-outer-overlay(("( " . " )") 40)
  evil-embrace-evil-surround-change(40)
  apply(evil-embrace-evil-surround-change 40)
  evil-surround-change(40)
  symex-change-delimiter()
  funcall-interactively(symex-change-delimiter)
  command-execute(symex-change-delimiter)
countvajhula commented 5 months ago

It could be a recent change in evil-surround that may require a change to how we use it, or possibly, evil-surround itself is interacting with some other setting in your configuration.

I'm curious what happens if you use evil-surround directly, e.g. here:

(f1 |(x1 x2))

where | indicates the cursor position on the opening paren, and while you're in evil Normal state, if you say cs)], does that work?

In the same example, if you try M-: (evil-surround-change (following-char)), does that work (it should wait for an additional character from you and then surround with that character)?

Fwiw, as part of the upcoming (and delayed 😅) 2.0 release, we've started to eliminate dependency on evil-surround as part of a broader effort to trim dependencies (including, eventually, Evil itself), so I suspect it would be addressed when 2.0 is released, but of course, let's keep going to identify the cause for now.

johnabs commented 5 months ago

Interestingly, this halfway works! Running cs)] works fine, but trying the the M-: (evil-surround (following-char)) fails, and does not prompt me, with the following error:

Debugger entered--Lisp error: (void-function evil-surround)
  (evil-surround (following-char))
  eval-expression((evil-surround (following-char)) nil nil 127)
  funcall-interactively(eval-expression (evil-surround (following-char)) nil nil 127)
  command-execute(eval-expression)

Also, note that there may be a distinction: the keybinding method uses evil-change. I checked the definition in evil-commands.el, and this does not seem to use evil-surround.

countvajhula commented 5 months ago

Sorry, I had a typo in my comment that I fixed. It should be M-: (evil-surround-change (following-char)). Does that work?

johnabs commented 5 months ago

Okay, I tried that, but it doesn't prompt for a character, it just errors with

Debugger entered--Lisp error: (error "No surrounding delimiters found")
  error("No surrounding delimiters found")
  evil-select-paren("( " " )" 1847 1847 nil 1 t)
  evil-surround-outer-overlay(("( " . " )") 40)
  evil-embrace-evil-surround-change(40)
  apply(evil-embrace-evil-surround-change 40)
  evil-surround-change(40)
  eval-expression((evil-surround-change (following-char)) nil nil 127)
  funcall-interactively(eval-expression (evil-surround-change (following-char)) nil nil 127)
  command-execute(eval-expression)
countvajhula commented 5 months ago

Yeah, that looks like the error we're seeing. I've just tried with the latest version of evil-surround and the latest version of evil, and I'm not able to reproduce this on my end. That is, M-: (evil-surround-change (following-char)) works and prompts for a character. I am using an old version of Emacs, but that seems unlikely to be connected here. I'm curious if anyone else is able to reproduce this, maybe @devcarbon-com ?

anonimitoraf commented 4 months ago

Hey @johnabs, I also use doom and also get this error. I found that removing the evil-surround-delete advice fixes it

(advice-remove 'evil-surround-delete 'evil-embrace-evil-surround-delete)

Unsure yet if this breaks anything else though

jezcope commented 2 months ago

To add more confusion to the mix... I have disabled evil-embrace.el in my doom setup, so it never loads and its advice is never added to evil-surround-*, but I still get an error trying to do symex-splice:

Debugger entered--Lisp error: (error "No surrounding delimiters found")
  error("No surrounding delimiters found")
  evil-select-paren("( " " )" 638 638 nil 1 t)
  evil-surround-outer-overlay(("( " . " )") 40)
  evil-surround-delete(40)
  symex-splice()
  funcall-interactively(symex-splice)
  command-execute(symex-splice)

Interestingly, if I add spaces after the opening delimiter and before the closing delimiter, it works perfectly. 🤔

anonimitoraf commented 2 months ago

Hey @jezcope, you sure evil-surround-delete isn't being overridden?

jezcope commented 2 months ago

Yes, but Doom had pinned an older version of evil-surround so adding (unpin! evil-surround) and running doom sync -u fixed that problem. I'm just figuring out a consistent way to disable the surround/embrace integration (which Doom activates by default) and then I'll document the solution here. 🙂

anonimitoraf commented 2 months ago

Does (advice-remove 'evil-surround-delete 'evil-embrace-evil-surround-delete) work for you?

jezcope commented 2 months ago

Ok, so this is what gets symex-splice working correctly for me on Doom emacs.

Add to config.el (this disables all of the evil-embrace advice):

(after! (:and evil-surround evil-embrace)
  (evil-embrace-disable-evil-surround-integration))

Add to packages.el:

(unpin! evil-surround)

Run doom sync -u (the -u is necessary for it to update the unpinned evil-surround to the latest version).

I think maybe documenting this is sufficient until 2.0 comes out without the evil-surround dependency? It's mostly specific to Doom emacs because that's what's pinning versions of dependencies and automatically enabling all the advice on evil-surround-*, which evil-embrace doesn't do by default. Maybe add a paragraph to https://github.com/drym-org/symex.el?tab=readme-ov-file#tips?

countvajhula commented 2 months ago

Thank you for your help identifying the root cause @anonimitoraf 🙂

@jezcope Glad you were able to resolve it! I would recommend creating an issue on the evil-surround or evil-embrace repo so they can take appropriate action on a fix.

In the meantime, sounds like a paragraph in the README explaining the issue for Doom emacs users, and the workaround, would be useful. A PR would be appreciated as I'm not familiar with Doom myself. Otherwise I can just include a simple pointer to this issue.

countvajhula commented 2 months ago

I've reported the issue upstream and added a pointer to this issue in the README. I think that's all we can do on the Symex end for now -- we wait on either an upstream fix, or on Symex 2.0 being merged, whichever comes first 🙂 Thanks all.

countvajhula commented 4 weeks ago

Actually as people are still running into this, closing wasn't the right thing to do -- reopening until it is resolved one way or another (see my previous comment).