Vim Tips Wiki
Register
Advertisement

Previous TipNext Tip

Tip: #812 - Keep the modified flag after writing to a file

Created: October 29, 2004 16:06 Complexity: intermediate Author: hari_vim at yahoo dot com Version: 5.7 Karma: 2/4 Imported from: Tip#812

I have seen this being asked in vim mailing list several times, including the recent one which suggested that it should work this way when 'cp' is reset. Basically what happens is that when you modify a file and write contents to a different file, Vim resets the 'modified' flag, which is a Vi compatible behavior. For those who don't want the 'modified' flag reset, the suggested alternative is to use :saveas command instead of :write command, but this changes the name of the current buffer rather than what is wanted. So I have cooked up the following solution which seems to work for regular files, but it is not a fool proof mechanism. The problem is plugins like netrw that catch the event that is triggered when you try to write contents to a different file, and the below solution also uses the same mechanism, so it would end up getting triggered unexpectedly (actually, netrw might work just fine, but you would get ugly error messages in addition).


I have provided a simple workaround for taking care of at least netrw. Basically, it checks if netrw would react to the event and if so skip itself. A more sophisticated solution would actually parse the output of ":au BufWriteCmd" and automatically check if there are other event handlers for this file, but there are not all that many plugins that take advantage of this event (actually I am aware of only netrw), so the workaround should be sufficient (actually, I haven't tested the netrw filenames, so I am not sure it would work). What you should do is to run the ":au BufWriteCmd" before installing this solution and see what other autocommands exist, other than those that are for netrw. You will have to then tweek the code that returns early from the BufWrite() function.


OK, enough said, the solution follows. You basically put the below code in your vimrc and your :write's will work as expected (ie., as described at the start).



cut here-----------

function! SetBufWriteAuEnabled(enabled)

aug BufWrite 
au! 
if a:enabled 
au BufWriteCmd * :call BufWrite() 
endif 
aug END 

endfunction

call SetBufWriteAuEnabled(1)


function! BufWrite()

let fileName = expand('<afile>') 
" If the filename already matches netrw's criteria, then don't do anything. 
if fileName =~ 'ftp://\

Comments

This autocommand modifies the regular :w and :wq functionality. The fix is to avoid the work around when writing is happening to the same file. Here is the new code:

" ----------cut here----------- function! SetBufWriteAuEnabled(enabled)

aug BufWrite 
au! 
if a:enabled 
au BufWriteCmd * :call BufWrite() 
endif 
aug END 

endfunction call SetBufWriteAuEnabled(1)

function! BufWrite()

let fileName = expand('<afile>') 
" If the filename already matches netrw's criteria, then don't do anything. 
if fileName =~ 'ftp://\%7Crcp://\%7Cscp://\%7Cdav://\%7Crync://\%7Csftp://' 
return 
endif 
let _modifiable = &modified 
exec 'w'.(v:cmdbang?'!':) v:cmdarg fileName 
" This autocommand gets triggered by Vim even if the writing is happening to 
" the same file, so we don't want to modify the behavior of bare :w or :wq 
" commands. 
if expand('%') !=# fileName 
" This *is* the actual work around. Restore the 'modified' flag. 
let &modified = _modifiable 
endif 

endfunction " ----------cut here-----------

Thanks to Mathias Michaelis for reporting this.

Hari

hari_vim at yahoo dot com , November 1, 2004 11:04


This autocommand modifies the regular :w and :wq functionality. The fix is to avoid the work around when writing is happening to the same file. Here is the new code:

" ----------cut here----------- function! SetBufWriteAuEnabled(enabled)

aug BufWrite 
au! 
if a:enabled 
au BufWriteCmd * :call BufWrite() 
endif 
aug END 

endfunction call SetBufWriteAuEnabled(1)

function! BufWrite()

let fileName = expand('<afile>') 
" If the filename already matches netrw's criteria, then don't do anything. 
if fileName =~ 'ftp://\%7Crcp://\%7Cscp://\%7Cdav://\%7Crync://\%7Csftp://' 
return 
endif 
let _modifiable = &modified 
exec 'w'.(v:cmdbang?'!':) v:cmdarg fileName 
" This autocommand gets triggered by Vim even if the writing is happening to 
" the same file, so we don't want to modify the behavior of bare :w or :wq 
" commands. 
if expand('%') !=# fileName 
" This *is* the actual work around. Restore the 'modified' flag. 
let &modified = _modifiable 
endif 

endfunction " ----------cut here-----------

Thanks to Mathias Michaelis for reporting this.

Hari

hari_vim at yahoo dot com , November 1, 2004 11:06


Sorry for the duplication in adding the above note.

Hari

hari_vim at yahoo dot com , November 1, 2004 11:07


0) Nice tip, quite useful!

1) However, this tip uses the v:cmdbang variable, which was only added in patch 6.2.485, so - generally speaking - you'll have to run vim 6.3 to use this tip. I'm still running 6.2, so I used this workaround: (...) if exists("v:cmdbang")

exec 'w'.(v:cmdbang?'!':) v:cmdarg fileName 

else

exec 'w' v:cmdarg fileName 

endif (...)

2) Splitting hairs: I'd say it would be better to avoid the confusing variable _modifiable (as the 'modifiable' option seems to have little to do with this tip). Maybe it would be better to use something like: TmpModified or _modified.

Paul Bolle

pebolle--AT--tiscali.nl , November 3, 2004 14:41


Right, I did mean to call it _modified, not _modifiable. Good catch.

Thanks for the clarification on the version requirement, it didn't occur to me. Hari

hari_vim at yahoo dot com , November 8, 2004 14:09


what shall i save the file as?? please.

Anonymous , November 10, 2004 1:25


Just put it in your vimrc.

pebolle--AT--tiscali.nl , November 13, 2004 4:59


Advertisement