Re: formatexpr, append() and undo

2006-05-16 Thread Jiří Černý
On Mon, May 15, 2006 at 06:26:55PM -0400, Benji Fisher wrote:
 
 
 Please do post the script you use, simplified as much as possible,
 so we can test it.  I tried
 
 :call append(line($), This line brought to you by append())
 
 and then (in Normal mode)
 
 u
 
 and it worked fine.  This is with vim 7.0.
 

Here are the scripts and the test case. It is relatively complicated,
but I did not find a simpler one. It works in vim 7.0 (Included patches:
1-17)

1. First you need the script that I wrote and a small test file. They
attached to this email. Put it into files format.vim and foo

2. vim -U NONE -u NONE foo
:set nocompatible
:source format.vim
:set tw=20 this is not necessary, it only saves some typing

3. now go to the first line of , type o (open line) and
start to type something like the text below between the two lines of
=. Do not hit Enter, let the vim format the text.

lajsdf lkjfd lkasjfd
alskjdf aslkjfd
;laskdjf salkjfd    one needs first to 
l;askjdf ;alskjdf   write some normal lines
;lsajdf lsakjdf
aslkjfd
$laskjdf dfsaf$ lsdk    (*)
fasldkfj asdlkjf
asdflj
$laksjdf asfldkj    (**)

(*) this formula is important, it was started at the previous line but
was moved by the formatting mechanism to this line
(**) this formula was also started one line above 

4. Now hit ESC and 'u'. I do not get back two lines of ===. 
The last three (or two, it depends what exactly did you type) lines of
the text remain (partially with different formatting). 
Moreover, when I hit 'u' again vim says 'Already at oldest change'
It is not possible to undo to the original state.

I hope the description is good enough and the bug is reproducible. 

Regards,

Jiri



==
==
if exists(b:did_my_tex_format_pluggin)
finish
endif

let b:did_my_tex_format_pluggin = 1

setlocal formatoptions=tcqr 
setlocal formatexpr=MyTeXFormat(v:lnum,v:count)


fun! MyTeXFormat(lnum,count)
if tw  10 let the vim do the job if tw is to small
return 1
endif
if mode()==i
return SIDMyFormatInsert(a:lnum,a:count)
elseif mode()==R
return SIDMyFormatReplace(a:lnum,a:count)
else
return SIDMyFormatGQ(a:lnum,a:count)
endif
endfun

fun! s:MyFormatInsert(lnum,count)   
if a:count!=1
echoerr Assertion failed: count1
return 1
endif

if col(.)  tw
return 0
endif

let line = getline(a:lnum)
let curlineindent = indent(a:lnum)
let aftercursor = line[col(.)-1:]
let beforecursor = line[:col(.)-2]

let dolarpos = SIDFindDolar(beforecursor,0)
if dolarpos == -1 no dolars, vim do the job
return 1
endif

let evendolars = 0
let newpos = dolarpos
while newpos != -1 count dollars find the last one 
let olddolarpos = dolarpos
let dolarpos = newpos
let evendolars =  1 -  evendolars   
let newpos = SIDFindDolar(beforecursor,dolarpos + 1)
endwhile

if evendolars == 0 
if dolarpos  tw vim can do the job
return 1
elseif olddolarpos  curlineindent  
let dolarpos = olddolarpos break at the start of the 
formula
else 
call append(a:lnum,XX) 
let newline =   aftercursor
call setline(a:lnum+1,newline)
call cursor(a:lnum+1,1)
return 0
endif
endif

if beforecursor[dolarpos-1]=='$' double dollars
let dolarpos = dolarpos - 1
endif

if beforecursor[dolarpos-1] != ' ' no space before $
let dolarpos = strridx(beforecursor,' ',dolarpos-1)
let dolarpos = dolarpos + 1
endif
if dolarpos != curlineindent formula does not start at first char
call setline(a:lnum,strpart(beforecursor,0,dolarpos))
call append(a:lnum,XX)
let newline =  strpart(beforecursor,dolarpos) . aftercursor
call setline(a:lnum+1,newline)
call cursor(a:lnum+1,strlen(beforecursor)-dolarpos+1)
return 0
endif
return 0
endfun

fun! s:MyFormatReplace(lnum,count)
FIXME make something useful
I never use replace mode
return 1
endfun

fun! s:MyFormatGQ(lnum,count)
probably useles, vim does not know about ''latex type paragraphs''
return 1
endfun

fun! s:FindDolar(s, pos)
let i = match(a:s,'\%(^\|[^\\]\)\$',a:pos)
if i == -1 
return -1
endif
if a:s[i] != '$'
   

Re: formatexpr, append() and undo

2006-05-16 Thread Benji Fisher
On Tue, May 16, 2006 at 08:33:43AM +0200, Jiří Černý wrote:
 
 Here are the scripts and the test case. It is relatively complicated,
 but I did not find a simpler one. It works in vim 7.0 (Included patches:
 1-17)

 I have simplified the example somewhat.  I may look at it some more
later, or maybe someone else will take it from here.  Save the attached
files foo (unchanged) and format.vim (simplified) and start vim with

$ vim -u NONE +source format.vim foo

On the first (blank) line, start Insert mode and type

12345 
$67890 1234$ 5678
9012

letting vim do the line breaks.  Then Esc back to Normal mode and u to
undo:  the 9012 line is left and 'modified' is not set.

 Curiously, if I *do* add the line break myself after the first
line, the problem seems to go away.  The bug seems to surface only when
two lines have been changed by the function.

HTH --Benji Fisher

==
==
set nocp tw=20
set laststatus=2 so I can watch the 'modified' flag

setlocal formatoptions=tcqr 
setlocal formatexpr=MyTeXFormat(v:lnum,v:count)

fun! MyTeXFormat(lnum,count)
let line = getline(a:lnum)
let curlineindent = indent(a:lnum)
let aftercursor = line[col(.)-1:]
let beforecursor = line[:col(.)-2]

let numdollars = len(substitute(beforecursor, '[^$]', '', 'g'))
let evendolars = numdollars % 2
let dolarpos = matchend(beforecursor, '.*\$')

if evendolars == 0 
if dolarpos  tw vim can do the job
return 1
endif
endif

if beforecursor[dolarpos-1] != ' ' no space before $
let dolarpos = strridx(beforecursor,' ',dolarpos-1)
let dolarpos = dolarpos + 1
endif
if dolarpos != curlineindent formula does not start at first char
call setline(a:lnum,strpart(beforecursor,0,dolarpos))
call append(a:lnum,XX)
let newline =  strpart(beforecursor,dolarpos) . aftercursor
call setline(a:lnum+1,newline)
call cursor(a:lnum+1,strlen(beforecursor)-dolarpos+1)
return 0
endif
return 0
endfun