kovisoft / slimv

Official mirror of Slimv versions released on vim.org
454 stars 60 forks source link

Broken dot command after "ce" #83

Closed mihaicristiantanase closed 5 years ago

mihaicristiantanase commented 5 years ago

In a Lisp buffer with the following contents:

'(val1 val2)

when I do (starting in Normal mode at the beginning of the line):

wcea<ESC>w.

I get:

'(a aval2)

The expected behavior is to end up with:

'(a a)
kovisoft commented 5 years ago

Yeah, this is a known issue and reported in https://github.com/kovisoft/paredit/issues/25 Unfortunately I don't know yet how to fix it, this seems to be a bug in vim. Currently the only workaround is to temporarily disable paredit mode via ,(.

mihaicristiantanase commented 5 years ago

So, it's from paredit plugin.

I've also noticed that, in the following Lisp buffer:

;; this is a test comment

(defun a ())

(defun b ())

with the cursor on the first line (Normal mode), I do:

2dap  // delete first 2 paragraphs
u     // undo
P     // paste the paragraphs back

The first 2 lines (the comment + the empty line) disappear.

Is this the same issue as the one mentioned here?

mihaicristiantanase commented 5 years ago

Disabling paredit mode fixes the issue.

kovisoft commented 5 years ago

The problem with the 2dap example in your comment is fixed in commit https://github.com/kovisoft/slimv/commit/2bedede57afcbbfdcb60d551a4aaec72a3d3b203

mihaicristiantanase commented 5 years ago

I've checked, but there are lots of issues with the fix: First result (2dapP):

;; this is a test comment

(defun a ())

(defun b ());; this is a test comment

(defun a ())

(defun b ())

Repeating uu2dapP a few times leads to lots of duplicated lines:

;; this is a test comment

(defun a ())

(defun b ());; this is a test comment

(defun a ())

;; this is a test comment

(defun a ())

;; this is a test comment

(defun a ())

;; this is a test comment

(defun a ())

;; this is a test comment

(defun a ())

;; this is a test comment

(defun a ())

;; this is a test comment

(defun a ())

;; this is a test comment

(defun a ())

;; this is a test comment

;; this is a test comment

(defun a ())

(defun b ())
kovisoft commented 5 years ago

That is quite strange, if I make the same test, it's okay for me. So the difference must be due to a vim option that is different in our systems. What is your value of this option?

:set clipboard?

What is pasted into vim if you enter these commands, then you press P?

:call setreg('"','"')
:call setreg('+','+')
:call setreg('*','*')

What is the output if you first yank (yy) an empty line, then start your test case without pasting (2dap) and type this command?

:reg
mihaicristiantanase commented 5 years ago
:set clipboard?
→ clipboard=unnamed

Running 2dap, then the 3 commands, then P leads to:

*(defun b ())

:reg before P leads to:

Screen Shot 2019-10-06 at 9 42 43 AM

Running P afterwords adds an empty line in the top.

kovisoft commented 5 years ago

Thanks for the assistance. I've set clipboard=unnamed but still was not able to reproduce the problem. Please add the below debug statements to paredit.vim and repeat your original 2dap test (with the cursor being on the ;; this is a test comment line and without the final P):

Add this line to PareditOpFunc() before the if s:repeat > 0 line (before the first if in the function):

echomsg 'PareditOpFunc repeat='.s:repeat.' register='.v:register.':'.getreg(v:register)

Add this line to PareditSetDelete() anywhere in the function:

echomsg 'PareditSetDelete clear register='.v:register

Please send me the relevant parts of the output of the :mess and :reg commands after the test. I'm wondering what register is used on your system and why it differs from my system.

kovisoft commented 5 years ago

Oh, and just one more idea: could you please make a test with the following lines (there are two of them) replaced in function PareditOpFunc()?

let putreg = oldreg . getreg( '"' )

with the below version (i.e. replace '"' with v:register)

let putreg = oldreg . getreg( v:register )

Thanks.

mihaicristiantanase commented 5 years ago

Results with echomsg (w/o P):

Messages maintainer: Bram Moolenaar <Bram@vim.org>
"/tmp/a.lisp" 5L, 54C
PareditSetDelete clear register=*
PareditOpfunc repeat=2 register=*:(defun b ())
PareditOpfunc repeat=1 register=*:(defun b ())^@;; this is a test comment
Press ENTER or type command to continue

Results with v:register (after P):

PareditSetDelete ;; this is a test comment

(defun a ())

(defun b ())
kovisoft commented 5 years ago

Thanks for doing the tests. How do you interpret the last result? Does it mean that 2dap deleted the two paragraphs (only defun b remained), then after pressing P the originally deleted two paragraphs were pasted but also some gibberish from a register (PareditSetDelete) was also pasted? And in this case what was the output for :mess and :reg? Sorry, I'm a little confused, probably because I asked you to do multiple things. So please just repeat the last test (with v:register) but also please provide the :mess and :reg output. Thanks again.

mihaicristiantanase commented 5 years ago

Sorry for the "too comprised" response I gave previously :)

So, here are the changes I make to paredit.vim:

diff --git a/plugin/paredit.vim b/plugin/paredit.vim
index 77af128..8160ede 100644
--- a/plugin/paredit.vim
+++ b/plugin/paredit.vim
@@ -279,6 +279,7 @@ function! PareditOpfunc( func, type, visualmode )
     set virtualedit=all
     let regname = v:register
     let save_0 = getreg( '0' )
+    echomsg 'PareditOpFunc repeat='.s:repeat.' register='.v:register.':'.getreg(v:register)
     if s:repeat > 0
         let oldreg = getreg( v:register )
         let s:repeat = s:repeat - 1
@@ -302,10 +303,10 @@ function! PareditOpfunc( func, type, visualmode )
     if !g:paredit_mode || (a:visualmode && (a:type == 'block' || a:type == "\<C-V>"))
         " Block mode is too difficult to handle at the moment
         silent exe "normal! d"
-        let putreg = oldreg . getreg( '"' )
+        let putreg = oldreg . getreg( v:register )
     else
         silent exe "normal! y"
-        let putreg = oldreg . getreg( '"' )
+        let putreg = oldreg . getreg( v:register )
         if a:func == 'd'
             " Register "0 is corrupted by the above 'y' command
             call setreg( '0', save_0 ) 
@@ -361,6 +362,7 @@ endfunction

 " Set delete mode also saving repeat count
 function! PareditSetDelete( count )
+    echomsg 'PareditSetDelete clear register='.v:register
     let s:repeat = a:count
     call setreg( v:register, '' ) 
     set opfunc=PareditDelete
:mess
Messages maintainer: Bram Moolenaar <Bram@vim.org>
"a.lisp" 5L, 54C
PareditSetDelete clear register=*
PareditOpFunc repeat=2 register=*:;; this is a test comment testingstuff
PareditOpFunc repeat=1 register=*:;; this is a test comment testingstuff^@;; this is a test comment
Press ENTER or type command to continue
:reg
--- Registers ---
""   Messages maintainer: Bram Moolenaar <Bram@vim.org>^J"a.lisp" 5L, 54C^JPareditSetDelete clear register=*^JPareditOpFunc repeat=2 register=*:;; this is a test comment testingstuff^JPareditOpFunc repeat
"0   Messages maintainer: Bram Moolenaar <Bram@vim.org>^J"a.lisp" 5L, 54C^JPareditSetDelete clear register=*^JPareditOpFunc repeat=2 register=*:;; this is a test comment testingstuff^JPareditOpFunc repeat
"1   (defun a ())^J^J
"2   ;; this is a test comment^J^J
"3   (defun a ())^J^J
"4   ;; this is a test comment^J^J
"5   (defun a ())^J^J
"6   ;; this is a test comment^J^J
"7   Plug 'tpope/vim-fugitive'^J
"8   (defun a ())^J^J
"9   ;; this is a test comment^J^J
"*   testingstuff
":   Reg
Press ENTER or type command to continue

After doing P, this is the buffer:

Messages maintainer: Bram Moolenaar <Bram@vim.org>
"a.lisp" 5L, 54C
PareditSetDelete clear register=*
PareditOpFunc repeat=2 register=*:;; this is a test comment testingstuff
PareditOpFunc repeat=1 register=*:;; this is a test comment testingstuff^@;; this is a test comment
Press ENTER or type command to continue(defun b ())

Obs: 'testingstuff' string is a text I had in clipboard before doing the 2dap combo.

mihaicristiantanase commented 5 years ago

My impression is that the bug has become worse after 2bedede

kovisoft commented 5 years ago

TBH I'm completely clueless, because as I understand from your logs, your system is using the * register for yanking and pasting, and at the beginning the * register is cleared (in PareditSetDelete), but then soon in PareditOpFunc this * register is printed in the log and it has some garbage value. How is this possible I can't explain. It was cleared and no yank/delete operation was performed up to the log message. I really need some more thorough debugging, so it would be nice if I could reproduce the problem on my system.

Is it possible that you send me your .vimrc file? You can find my email address in |slimv-credits| part of the slimv doc. Thanks for the cooperation.

mihaicristiantanase commented 5 years ago

To reproduce the bug I have this setup: .vim/ structure:

├── autoload
│   └── plug.vim
└── plugged
    └── slimv
        ├── ..........

.vimrc:

set clipboard=unnamed
call plug#begin('~/.vim/plugged')
Plug 'kovisoft/slimv'
call plug#end()

Computer: macOS Mojave 10.14.5

========================== I've nailed the problem to

set clipboard=unnamed

Removing this line fixes the bug.

kovisoft commented 5 years ago

Thank you, I really appreciate your kind assistance. I tried to create the same config on my system: I used your .vimrc, I downloaded plug.vim and created the same directory structure as yours, but unfortunately I was still unable to reproduce the problem.

Then I started to add more echomsg lines and these suddenly broke the delete functionality. It seems that echomsg is not fully compatible with opfunc (or whatever). So I'd like to ask you to remove those echomsg lines and check if anything changes. If still not okay, then please add this line at the beginning of paredit.vim:

let g:debug=''

And replace the previous echomsg lines with these variants:

let g:debug=g:debug.'PareditOpFunc repeat='.s:repeat.' register='.v:register.':'.getreg(v:register)."\n"

and

let g:debug=g:debug.'PareditSetDelete clear register '.v:register."\n"

These statements don't print anything just store the debug string into variable g:debug, this can be printed at the end of the test via;

:echo g:debug

Can you please send me what's the debug text? Thanks again.

mihaicristiantanase commented 5 years ago

So, here are my changes:

diff --git a/plugin/paredit.vim b/plugin/paredit.vim
index 77af128..a9dcb49 100644
--- a/plugin/paredit.vim
+++ b/plugin/paredit.vim
@@ -14,6 +14,8 @@ if &cp || exists( 'g:paredit_loaded' )
     finish
 endif

+let g:debug=''
+
 let g:paredit_loaded = 1

 " Needed to load filetype and indent plugins
@@ -279,6 +281,7 @@ function! PareditOpfunc( func, type, visualmode )
     set virtualedit=all
     let regname = v:register
     let save_0 = getreg( '0' )
+    let g:debug=g:debug.'PareditOpFunc repeat='.s:repeat.' register='.v:register.':'.getreg(v:register)."\n"
     if s:repeat > 0
         let oldreg = getreg( v:register )
         let s:repeat = s:repeat - 1
@@ -361,6 +364,7 @@ endfunction

 " Set delete mode also saving repeat count
 function! PareditSetDelete( count )
+    let g:debug=g:debug.'PareditSetDelete clear register '.v:register."\n"
     let s:repeat = a:count
     call setreg( v:register, '' ) 
     set opfunc=PareditDelete

And this is the result of echo g:debug:

PareditSetDelete clear register *
PareditOpFunc repeat=2 register=*:PareditSetDelete
PareditOpFunc repeat=1 register=*:PareditSetDelete ;; this is a test comment

Press ENTER or type command to continue

Unfortunately, it's still not working.

kovisoft commented 5 years ago

Thank you very much. That is very strange, the * register is cleared, then in the next function call it contains some text (that was yanked before). Maybe some other functions are called on your system that I'm not aware of. Could you please repeat the same test case but with vim verbose mode enabled:

Thanks again.

mihaicristiantanase commented 5 years ago

I've re-done the test, and here's the test.log file: test.log

Hope this helps.

kovisoft commented 5 years ago

Thank you very much. Unfortunately I still don't know what the problem is, so I created a debug version of paredit.vim. I added some extra debug messages to the test.log file and it automatically enables verbose mode during the yank-paste actions. Could you please unzip and replace paredit.vim with this file:

paredit.zip

and simply repeat the 2dapP test, then again please send me the resulting test.log. Thank you and sorry for the troubles.

mihaicristiantanase commented 5 years ago

Sorry for late reply, I had a hard in finding some free time :)

So, I've updated the paredit plugin and re-ran the test. Here's the log file: unnamed-test.log

I've also re-done the test with default clibboard setting. Here's the log file for the scenario in which everything is perfect: default-test.log

You can do a diff between them. Maybe this will help you spot the issue.

Thanks!

kovisoft commented 5 years ago

Thank you very much! It was a good idea to make parallel tests with different clipboard settings. I compared the logfiles and it seems that when clipboard=unnamed then some garbage is appearing in register * between PareditSetDelete and PareditOpfunc on your system (on my systems it doesn't, neither in Windows, nor in Linux). Therefore I modified the code so that the * register is initialized only later in PareditOpfunc. This is the modified debug version:

paredit.zip

Could you please repeat your previous test cases using this version of the script? Thanks again!

mihaicristiantanase commented 5 years ago

I've tested and the bug is fixed! I don't think it's necessary to send you the "test.log" file, but if you need it, please let me know. Please let me know when an "official" fix is added to master, so I can close this issue.

Thank you!

kovisoft commented 5 years ago

Great, thanks! Of course you don't need to send the logfile to me. I'll let you know when I'm ready with the fix. However I must tell you that the original problem with repeating the c command is not yet solved, and unfortunately I don't know how to fix it, because it seems to be vim bug.

Thanks again for your kind assistance!

kovisoft commented 5 years ago

Fixed the count handling in the d command in commit https://github.com/kovisoft/slimv/commit/42ec98e4f80a951455f481ad282153215b8934bd , sorry for the delay and again a big thank you for doing all the test cases for me.

As I mentioned, the original problem with the c operator is still open, there is a paredit issue https://github.com/kovisoft/paredit/issues/25 for that.

mihaicristiantanase commented 5 years ago

Works perfectly. As you mentioned, there's another issue for the "ce" bug. So, I'm closing this one.

Thank you!