I would like to write a buffer which isn't the current buffer to a temp file. I have found two ways to do this:

(assuming buffer 42 is the one to be written)

Either use writefile():

call writefile(getbufline(42, 1, '$'), tmpfile)

Or switch to the target buffer, use :write, and switch back again:

let current = bufnr('')
noautocmd buffer 42
" ... code to store &modified, '[, and '] ...
execute 'noautocmd keepalt silent write!' tmpfile
" ... code to restore &modified, '[, and '] ...
execute 'noautocmd buffer' current

The problem with writefile() is that it assumes your line endings are NL. If they are CRNL you have to insert the CRs yourself. Either way, you have to assume that all the lines have the same ending – which they really should, but you never know...

The problem with the second is that when you switch away from the current buffer, unknown side-effects might happen. For example, if the current buffer is a neovim terminal buffer, neovim will close it when you leave it.

Is there a better approach than either of these? Is there a better way to implement either of these?

Many thanks in advance!

  • The good news is I don't think you need to worry about mixed-line endings. Unless forced by the 'fileformats' setting Vim opens these as unix, and lines ending CRLF will just have a CR visible in the buffer. The mixed endings will therefore be preserved when you write out the file with LF endings. (And if 'fileformats' doesn't contain unix, then LF endings seem to be converted to CRLF on opening.) The bad news is I don't think there's any way of finding out what the buffer's 'fileformat' is without switching to it so you can't really use your writefile() solution anyway. :( – Rich Feb 12 at 16:51
  • wouldn't getbufvar(...,'&fileformat') work? – Mass Feb 12 at 16:57
  • @Mass Terrific. Thanks! Writing up a solution now. – Rich Feb 12 at 17:02
up vote 1 down vote accepted

I don't think you need to worry about mixed line endings. Unless forced by the 'fileformats' setting, Vim opens files containing these as unix, and lines ending CRLF will just have a CR visible in the buffer. The mixed endings will therefore be preserved when you write out the file with LF endings.

(And if 'fileformats' doesn't contain unix, then LF endings seem to be converted to CRLF on opening, so you can't actually have mixed endings if 'fileformat' is set to dos: therefore writing with CRLFs is correct.)

Therefore, you can do something like this:

let buffer_contents = getbufline(buffer_number, 1, '$')

if (getbufvar(buffer_number, '&fileformat') ==# 'dos')
  let buffer_contents = map(buffer_contents, 'v:val."\r"')
endif

call writefile(buffer_contents, tmpfile)

(Credit to @Mass for the method of accessing the buffer's current 'fileformat')

  • OK, I'm persuaded :) Thanks! Hopefully (file) encodings will take care of themselves... – Andy Stewart Feb 13 at 10:29
  • @AndyStewart Yeah, they should. Essentially, if a line-ending doesn't match the current setting, Vim will just treat it as a regular character in the line and write it out verbatim. – Rich Feb 13 at 10:42
  • I meant using the same encoding that the original file had when writing to the temp file. Eg utf-8 or some windows encoding etc. – Andy Stewart Feb 13 at 16:36
  • @AndyStewart Oh. Hmmm. Not sure. Be sure to report back if you try it out though! – Rich Feb 13 at 19:56
  • It turns out you need to correct the encoding if &encoding != &fileencoding, e.g. call map(bufcontents, 'iconv(v:val, &encoding, &fileencoding)'). – Andy Stewart Mar 19 at 14:56

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.