diff options
-rw-r--r-- | runtime/doc/options.txt | 11 | ||||
-rw-r--r-- | runtime/doc/quickref.txt | 1 | ||||
-rw-r--r-- | runtime/optwin.vim | 5 | ||||
-rw-r--r-- | src/nvim/buffer.c | 2 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/change.c | 4 | ||||
-rw-r--r-- | src/nvim/fileio.c | 11 | ||||
-rw-r--r-- | src/nvim/option.c | 2 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/options.lua | 9 | ||||
-rw-r--r-- | src/nvim/testdir/test_fixeol.vim | 23 |
11 files changed, 59 insertions, 13 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index a04d02946d..4718876b29 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -2135,6 +2135,15 @@ A jump table for the options with a short description can be found at |Q_op|. See 'fileencoding' to control file-content encoding. + *'endoffile'* *'eof'* *'noendoffile'* *'noeof'* +'endoffile' 'eof' boolean (default on) + local to buffer + Indicates that a CTRL-Z character was found at the end of the file + when reading it. Normally only happens when 'fileformat' is "dos". + When writing a file and this option is off and the 'binary' option + is on, or 'fixeol' option is off, no CTRL-Z will be written at the + end of the file. + *'endofline'* *'eol'* *'noendofline'* *'noeol'* 'endofline' 'eol' boolean (default on) local to buffer @@ -2490,7 +2499,7 @@ A jump table for the options with a short description can be found at |Q_op|. 'fixendofline' 'fixeol' boolean (default on) local to buffer When writing a file and this option is on, <EOL> at the end of file - will be restored if missing. Turn this option off if you want to + will be restored if missing. Turn this option off if you want to preserve the situation from the original file. When the 'binary' option is set the value of this option doesn't matter. diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt index 2f91498857..e4a3dae08b 100644 --- a/runtime/doc/quickref.txt +++ b/runtime/doc/quickref.txt @@ -689,6 +689,7 @@ Short explanation of each option: *option-list* 'display' 'dy' list of flags for how to display text 'eadirection' 'ead' in which direction 'equalalways' works 'encoding' 'enc' encoding used internally +'endoffile' 'eof' write CTRL-Z at end of the file 'endofline' 'eol' write <EOL> for last line in file 'equalalways' 'ea' windows are automatically made the same size 'equalprg' 'ep' external program to use for "=" command diff --git a/runtime/optwin.vim b/runtime/optwin.vim index 57e5392b98..db21066819 100644 --- a/runtime/optwin.vim +++ b/runtime/optwin.vim @@ -1,7 +1,7 @@ " These commands create the option window. " " Maintainer: Bram Moolenaar <Bram@vim.org> -" Last Change: 2022 Oct 15 +" Last Change: 2022 Oct 28 " If there already is an option window, jump to that one. let buf = bufnr('option-window') @@ -956,6 +956,9 @@ call <SID>BinOptionL("bin") call <SID>AddOption("endofline", gettext("last line in the file has an end-of-line")) call append("$", "\t" .. s:local_to_buffer) call <SID>BinOptionL("eol") +call <SID>AddOption("endoffile", gettext("last line in the file followed by CTRL-Z")) +call append("$", "\t" .. s:local_to_buffer) +call <SID>BinOptionL("eof") call <SID>AddOption("fixendofline", gettext("fixes missing end-of-line at end of text file")) call append("$", "\t" .. s:local_to_buffer) call <SID>BinOptionL("fixeol") diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 8016904702..ade5c35450 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -689,6 +689,8 @@ void buf_clear_file(buf_T *buf) { buf->b_ml.ml_line_count = 1; unchanged(buf, true, true); + buf->b_p_eof = false; + buf->b_start_eof = false; buf->b_p_eol = true; buf->b_start_eol = true; buf->b_p_bomb = false; diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 043a31bf16..52449faa5b 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -675,6 +675,7 @@ struct file_buffer { char *b_p_cfu; ///< 'completefunc' char *b_p_ofu; ///< 'omnifunc' char *b_p_tfu; ///< 'tagfunc' + int b_p_eof; ///< 'endoffile' int b_p_eol; ///< 'endofline' int b_p_fixeol; ///< 'fixendofline' int b_p_et; ///< 'expandtab' @@ -793,6 +794,7 @@ struct file_buffer { linenr_T b_no_eol_lnum; // non-zero lnum when last line of next binary // write should not have an end-of-line + int b_start_eof; // last line had eof (CTRL-Z) when it was read int b_start_eol; // last line had eol when it was read int b_start_ffc; // first char of 'ff' when edit started char *b_start_fenc; // 'fileencoding' when edit started or NULL diff --git a/src/nvim/change.c b/src/nvim/change.c index 2424a8a2eb..c6df98651d 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -539,6 +539,7 @@ void unchanged(buf_T *buf, int ff, bool always_inc_changedtick) void save_file_ff(buf_T *buf) { buf->b_start_ffc = (unsigned char)(*buf->b_p_ff); + buf->b_start_eof = buf->b_p_eof; buf->b_start_eol = buf->b_p_eol; buf->b_start_bomb = buf->b_p_bomb; @@ -573,7 +574,8 @@ bool file_ff_differs(buf_T *buf, bool ignore_empty) if (buf->b_start_ffc != *buf->b_p_ff) { return true; } - if ((buf->b_p_bin || !buf->b_p_fixeol) && buf->b_start_eol != buf->b_p_eol) { + if ((buf->b_p_bin || !buf->b_p_fixeol) + && (buf->b_start_eof != buf->b_p_eof || buf->b_start_eol != buf->b_p_eol)) { return true; } if (!buf->b_p_bin && buf->b_start_bomb != buf->b_p_bomb) { diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index cfdd6fe697..2ba2f4c9c9 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -524,6 +524,8 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, // Don't change 'eol' if reading from buffer as it will already be // correctly set when reading stdin. if (!read_buffer) { + curbuf->b_p_eof = false; + curbuf->b_start_eof = false; curbuf->b_p_eol = true; curbuf->b_start_eol = true; } @@ -1628,6 +1630,7 @@ failed: if (!error && !got_int && linerest != 0 + // TODO(vim): should we handle CTRL-Z differently here for 'endoffile'? && !(!curbuf->b_p_bin && fileformat == EOL_DOS && *line_start == Ctrl_Z @@ -1635,6 +1638,9 @@ failed: // remember for when writing if (set_options) { curbuf->b_p_eol = false; + if (*line_start == Ctrl_Z && ptr == line_start + 1) { + curbuf->b_p_eof = true; + } } *ptr = NUL; len = (colnr_T)(ptr - line_start + 1); @@ -3191,6 +3197,11 @@ restore_backup: len = 0; write_info.bw_start_lnum = lnum; } + if (!buf->b_p_fixeol && buf->b_p_eof) { + // write trailing CTRL-Z + (void)write_eintr(write_info.bw_fd, "\x1a", 1); + } + // write failed or last line has no EOL: stop here if (end == 0 || (lnum == end diff --git a/src/nvim/option.c b/src/nvim/option.c index 06662afd08..8de86ce76e 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -3978,6 +3978,8 @@ static char_u *get_varp(vimoption_T *p) return (char_u *)&(curbuf->b_p_cfu); case PV_OFU: return (char_u *)&(curbuf->b_p_ofu); + case PV_EOF: + return (char_u *)&(curbuf->b_p_eof); case PV_EOL: return (char_u *)&(curbuf->b_p_eol); case PV_FIXEOL: diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 19e4780e0a..7c33773e41 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -497,6 +497,7 @@ EXTERN char_u *p_ef; // 'errorfile' EXTERN char *p_efm; // 'errorformat' EXTERN char *p_gefm; // 'grepformat' EXTERN char *p_gp; // 'grepprg' +EXTERN int p_eof; ///< 'endoffile' EXTERN int p_eol; ///< 'endofline' EXTERN char *p_ei; // 'eventignore' EXTERN int p_et; ///< 'expandtab' @@ -858,6 +859,7 @@ enum { BV_CFU, BV_DEF, BV_INC, + BV_EOF, BV_EOL, BV_FIXEOL, BV_EP, diff --git a/src/nvim/options.lua b/src/nvim/options.lua index ba483d3714..088aa40fda 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -641,6 +641,15 @@ return { defaults={if_true=macros('ENC_DFLT')} }, { + full_name='endoffile', abbreviation='eof', + short_desc=N_("write CTRL-Z for last line in file"), + type='bool', scope={'buffer'}, + no_mkrc=true, + redraw={'statuslines'}, + varname='p_eof', + defaults={if_true=true} + }, + { full_name='endofline', abbreviation='eol', short_desc=N_("write <EOL> for last line in file"), type='bool', scope={'buffer'}, diff --git a/src/nvim/testdir/test_fixeol.vim b/src/nvim/testdir/test_fixeol.vim index 32cb059e26..9d6c900bdb 100644 --- a/src/nvim/testdir/test_fixeol.vim +++ b/src/nvim/testdir/test_fixeol.vim @@ -1,16 +1,17 @@ -" Tests for 'fixeol' and 'eol' +" Tests for 'fixeol', 'eof' and 'eol' + func Test_fixeol() " first write two test files – with and without trailing EOL " use Unix fileformat for consistency set ff=unix enew! - call setline('.', 'with eol') + call setline('.', 'with eol or eof') w! XXEol enew! - set noeol nofixeol - call setline('.', 'without eol') + set noeof noeol nofixeol + call setline('.', 'without eol or eof') w! XXNoEol - set eol fixeol + set eol eof fixeol bwipe XXEol XXNoEol " try editing files with 'fixeol' disabled @@ -33,16 +34,18 @@ func Test_fixeol() w >>XXTestEol w >>XXTestNoEol - call assert_equal(['with eol', 'END'], readfile('XXEol')) - call assert_equal(['without eolEND'], readfile('XXNoEol')) - call assert_equal(['with eol', 'stays eol', 'END'], readfile('XXTestEol')) - call assert_equal(['without eol', 'stays withoutEND'], + call assert_equal(['with eol or eof', 'END'], readfile('XXEol')) + call assert_equal(['without eol or eofEND'], readfile('XXNoEol')) + call assert_equal(['with eol or eof', 'stays eol', 'END'], readfile('XXTestEol')) + call assert_equal(['without eol or eof', 'stays withoutEND'], \ readfile('XXTestNoEol')) call delete('XXEol') call delete('XXNoEol') call delete('XXTestEol') call delete('XXTestNoEol') - set ff& fixeol& eol& + set ff& fixeol& eof& eol& enew! endfunc + +" vim: shiftwidth=2 sts=2 expandtab |