kovisoft / slimv

Official mirror of Slimv versions released on vim.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Evaluate expression command making new line before evaluating

IshiRenga opened this issue · comments

When I try to evaluate an expression with ,e, it makes a new line and then tries evaluating but gives Form is empty. instead. I have also tried calling the eval expression from command mode call SlimvEvalExp() but it results in the same behavior. Same with evaluate defun, but evaluate buffer works correctly. I have tried with the cursor inside the expression and with it on the parens.

using:
neovim 0.8.3
latest slimv commit 48f21d0

I was unable to reproduce the problem, maybe some vim options are differently set up on your system. Could you please send me your .vimrc file (without any sensitive information)? Also please send me an example .lisp file or s-expression and some details on where you place the cursor when pressing ,e and then where the cursor moves afterwards. The selected expression is stored in register s, so please attach the output of :reg.

What happens if instead of pressing ,e you execute this command?

:call SlimvSelectForm(1)

Does it store anything in register s?
Thank you in advance.

I appreciate you taking a look.
As you said about possible different vim options and as I had many neovim plugins, I retested with a stock config with just packer and slimv, but unfortunately I am still getting the same outcome.

Here is my .vimrc: vimrc.txt. It's pretty minimal. There shouldn't be any other configs loaded from my normal neovim setup.

A minimal s-expression I'm testing with is simply (+ 1 1). Here are screenshots showing cursor locations and where it moves to:
Before on paren:
image
After:
image

Before in parens:
image
After:
image

And just to show that the repl is connected to the swank server:
image

Here is the :reg s output:

:reg s
Type Name Content
Press ENTER or type command to continue

I should note that I was previously getting an error showing that register because neovim couldn't recognize my clipboard manager. I just installed xclip and the error went away in :checkhealth and :reg. Just wanted to mention that in case there is something else is missing and I don't even know.

When I run :call SlimvSelectForm(1), it is the same behavior as above (just moving to the next line) and nothing is stored in s.

Thank you for your very detailed description. Let's dig into SlimvSelectForm. First let's check if register s is working properly:
Please select any text in visual mode (v), then press "sy and check :reg s. Does the selection appear in the s register?

There are some vim options that may affect the behaviour of text selection. Please tell me your settings for these vim options:

:set clipboard?
:set selection?
:set whichwrap?
:set virtualedit?

(Edit: I see now in your .vimrc that clipboard=unnamedplus)

SlimvSelectForm internally executes two searchpair calls: the first one locates the starting (, the second one locates the ending ).
I'd like to ask you to do that manually:

  • Place the cursor somewhere inside the expression
  • Execute this statement. Does it move the cursor to the starting (?
:call searchpair( '(', '', ')', 'bW')
  • Press v for entering visual selection mode.
  • Execute this statement (the '<,'> part is automatically inserted by vim upon pressing : in visual mode). Does it move the cursor to the ending )?
:'<,'>call searchpair( '(', '', ')', 'W')

If all the above works as intended, then I think we'll need to do some debugging in SlimvSelectForm.
Thank you for your kind assistance.

Here is the output after copying to the s register:

:reg s
Type Name Content
l "s (+ 1 1)^J

And the settings for:

:set clipboard?
clipboard=

:set selection?
selection=inclusive

:set whichwrap
whichwrap=b,s

:set virtualedit?
virtualedit=

Executing :call searchpair( '(', '', ')', 'bW') does move the cursor to the starting (, and :'<,'>call searchpair( '(', '', ')', 'W') moves to the ending ) correctly. Even though it's in visual mode, it doesn't select the text when the cursor moved. I would have expected it to since it was in visual mode, but maybe not.

Thanks, it seems that vim handles the visual mode + searchpair combo differently, depending on whether executed from vimscript or entered manually. Especially that later on the script executes a :normal o command, that should jump the cursor to the other end of the visual selection. But this does not seem to work when manually executing the statements.

Anyway, that just gave me an idea: maybe the :normal o is causing troubles for you in neovim. So I created a modified version of SlimvSelectForm(), this does not contain the :normal o line. Instead it uses an extra searchpair to jump to the beginning of the selection. Please replace this function in your slimv.vim and check if it solves the problem:

function! SlimvSelectForm( extended )
    if SlimvGetFiletype() == 'r'
        silent! normal va(
        silent! normal "sY
        return 1
    endif
    " Search the opening '(' if we are standing on a special form prefix character
    let c = col( '.' ) - 1
    let firstchar = getline( '.' )[c]
    while c < len( getline( '.' ) ) && match( "'`#", getline( '.' )[c] ) >= 0
        normal! l
        let c = c + 1
    endwhile
    " select the whole form
    if getline( '.' )[c] != '('
        call searchpair( '(', '', ')', 'bW', s:skip_sc )
    endif
    call searchpair( '(', '', ')', 'W', s:skip_sc )
    let save_sel = &selection
    set selection=inclusive
    let p1 = getpos('.')
    silent! normal v
    call searchpair( '(', '', ')', 'bW', s:skip_sc )
    let p2 = getpos('.')
    if firstchar != '(' && firstchar != ')' && p1[1] == p2[1] && (p1[2] == p2[2] || p1[2] == p2[2]+1)
        " Empty selection and no paren found, select current word instead
        normal! vvaw
    elseif a:extended || (firstchar != '(' && firstchar != ')')
        " Handle '() or #'() etc. type special syntax forms (but stop at prompt)
        let c = col( '.' ) - 2
        while c >= 0 && match( ' \t()>', getline( '.' )[c] ) < 0
            normal! h
            let c = c - 1
        endwhile
    endif
    silent normal! "sy
    let &selection=save_sel
    let sel = SlimvGetSelection()
    if sel == ''
        call SlimvError( "Form is empty." )
        return 0
    elseif sel == '(' || sel == '[' || sel == '{'
        call SlimvError( "Form is unbalanced." )
        return 0
    else
        return 1
    endif
endfunction

Yes, that change does fix it and the s-expression gets executed now, but it also doesn't seem to clear out the s register and always evaluates the same expression, even on a different one.

Thank you for testing it. That is very strange. Is it working one time, but not afterwards? I could understand if it didn't work at all, but I cannot explain why it is working only once. Is it possible that it does not work at all, but for some reason you had the contents of the s register initially set to the same expression that you wanted to evaluate?

Please try this:

  • open a new neovim session
  • put some garbage into the s register: select some random text and press "sy
  • verify the contents of the s register: :reg s, does it contain the garbage?
  • evaluate your expression
  • verify the contents of the s register, does it contain your expression and not the original garbage?
  • evaluate another expression
  • verify the contents of the s register, does it contain the expression you evaluated first?
  • clear the s register: :call setreg('s', [])
  • check that the register is removed from the :reg output
  • evaluate another expression
  • verify the contents of the s register, does it still contain the expression you evaluated first or the latest one?

If clearing the s register solves the issue, then please also check the same but instead of evaluating an expression, just simply yank it into the s register:

  • open a new neovim session
  • put something into the s register: select text and press "sy
  • verify the contents of the s register: :reg s
  • put something else into the s register: select some new text and press "sy
  • verify the contents of the s register: :reg s
  • clear the s register: :call setreg('s', [])
  • check that the register is removed from the :reg output
  • put something else into the s register: select some new text and press "sy
  • verify the contents of the s register: :reg s

Thank you again for your kind assistance.

Oh yeah, you're right, sorry. It must have been data still held in that register because after clearing the register, it no longer evaluated properly.
Ok so with a blank s register, the current behavior with the new function from above is that the cursor moves to the left paren and gives the Form is empty. error.

Before:
image
After:
image

Ah, thanks, as least that's consistent now. :)
So either we have some problem with that specific s register, or we have some problem with mixing the normal v and searchpair() functions. In vim you can mix these calls (at least from vimscript), which means that even in visual mode you can call searchpair and that moves the cursor to the requested paren and at the same time extends the visual selection.

Maybe this one does not work properly in neovim. I have created a simple test function to demonstrate it:

:exe "function! TEST()\n call searchpair('(', '', ')', 'W')\n silent! normal v\n call searchpair('(', '', ')', 'bW')\n endfunction"

If you execute the above command, it will create a new function TEST(). After defining the function just place the cursor somewhere inside the expression, and execute it:

:call TEST()

The function first moves the cursor to the ending paren, then starts visual mode, and moves the cursor to the starting paren.
In vim the result is that the whole expression is selected and vim stays in visual mode. You can then yank it to whatever register you desire.

I suppose that if you do the same in neovim, then the visual mode is not extended to the whole expression, instead it will be an empty selection, maybe neovim even exits visual mode. Could you please check the above?

When I run that function, I get the same result as before (cursor moves to the front, doesn't select, and is not in visual mode). I checked it in normal vim, and it does exactly as you said it should. Hm it's interesting that there is a difference in behavior between the 2.

OK, thanks, so it seems to be an incompatibility between legacy vim and neovim. Now I'm wondering if this is true only for :searchpair or for all ex commands. I mean maybe whatever ex command you execute in visual selection mode, then it makes neovim forget the original position where v was started. What if we replace the second :searchpair with a :setpos call?

This is a modified version of our TEST() function, which moves the cursor to line 1, column 1 after selecting visual mode:

:exe "function! TEST()\n call searchpair('(', '', ')', 'W')\n silent! normal v\n call setpos('.', [0,1,1,0])\n endfunction"

Again, please check it the same way via:

:call TEST()

Running that modified function moves the cursor to line 1, column 1, but it is not in visual mode.

Thank you for the feedback. So it seems that this is really an incompatibility between vim and neovim. In neovim vimscript when we enter visual mode (:normal! v) and then execute an ex command that moves the cursor, then neovim exits visual mode. When we do the same in vim, it remains in visual mode. That is only true when the statements are executed from vimscript. If we do the same manually in interactive mode, then vim also exits visual mode.

I'll try to come up with another approach, something to replace :normal! v in the script.

I'm not sure if this is a bug in neovim, or it is just an undocumented feature in vim.
Would you mind to file a ticket about it in neovim? Maybe then accept it as a bug, maybe they explain why it has to be like this.

Thanks again!

Thank you for your analysis. I was going to submit the bug report to neovim, but I decided to double check on a different computer and actually everything worked correctly. I was able to narrow it down to a plugin I had for neovim that, even while disabled, still somehow had an effect and hijacked this specific visual mode functionality. I was able to fix it and now slimv works as I'd expect.

I apologize for the inconvenience , but thank you again and I appreciate your time. The test function you gave was helpful in quickly finding the culprit. I'll close this issue since it wasn't an issue with slimv.

No problem at all, and I thank you very much for the information. I was not suspecting that another plugin was causing troubles.