changeset 6933:62ba356c2d4e v7.4.785

patch 7.4.785 Problem: On some systems automatically adding the missing EOL causes problems. Setting 'binary' has too many side effects. Solution: Add the 'fixeol' option, default on. (Pavel Samarkin)
author Bram Moolenaar <bram@vim.org>
date Fri, 17 Jul 2015 14:18:08 +0200
parents 727f3fececd8
children be7bd53ad376
files runtime/doc/options.txt runtime/optwin.vim src/buffer.c src/fileio.c src/memline.c src/netbeans.c src/ops.c src/option.c src/option.h src/os_unix.c src/os_win32.c src/structs.h src/testdir/Make_amiga.mak src/testdir/Make_dos.mak src/testdir/Make_ming.mak src/testdir/Make_os2.mak src/testdir/Make_vms.mms src/testdir/Makefile src/testdir/test_fixeol.in src/testdir/test_fixeol.ok src/version.c
diffstat 21 files changed, 118 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1,4 +1,4 @@
-*options.txt*	For Vim version 7.4.  Last change: 2015 Jul 10
+*options.txt*	For Vim version 7.4.  Last change: 2015 Jul 17
 
 
 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
@@ -2671,15 +2671,16 @@ A jump table for the options with a shor
 			local to buffer
 			{not in Vi}
 	When writing a file and this option is off and the 'binary' option
-	is on, no <EOL> will be written for the last line in the file.  This
-	option is automatically set when starting to edit a new file, unless
-	the file does not have an <EOL> for the last line in the file, in
-	which case it is reset.  Normally you don't have to set or reset this
-	option.  When 'binary' is off the value is not used when writing the
-	file.  When 'binary' is on it is used to remember the presence of a
-	<EOL> for the last line in the file, so that when you write the file
-	the situation from the original file can be kept.  But you can change
-	it if you want to.
+	is on, or 'fixeol' option is off, no <EOL> will be written for the
+	last line in the file.  This option is automatically set or reset when
+	starting to edit a new file, depending on whether file has an <EOL>
+	for the last line in the file.  Normally you don't have to set or
+	reset this option.
+	When 'binary' is off and 'fixeol' is on the value is not used when
+	writing the file.  When 'binary' is on or 'fixeol' is off it is used
+	to remember the presence of a <EOL> for the last line in the file, so
+	that when you write the file the situation from the original file can
+	be kept.  But you can change it if you want to.
 
 			     *'equalalways'* *'ea'* *'noequalalways'* *'noea'*
 'equalalways' 'ea'	boolean	(default on)
@@ -3064,6 +3065,17 @@ A jump table for the options with a shor
 	  fold:c	Folded			|hl-Folded|
 	  diff:c	DiffDelete		|hl-DiffDelete|
 
+		*'fixendofline'* *'fixeol'* *'nofixendofline'* *'nofixeol'*
+'fixendofline' 'fixeol'	boolean	(default on)
+			local to buffer
+			{not in Vi}
+	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
+	preserve the situation from the original file.
+	When the 'binary' option is set the value of this option doesn't
+	matter.
+	See the 'endofline' option.
+
 					*'fkmap'* *'fk'* *'nofkmap'* *'nofk'*
 'fkmap' 'fk'		boolean (default off)			*E198*
 			global
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -954,6 +954,9 @@ call <SID>BinOptionL("bin")
 call append("$", "endofline\tlast line in the file has an end-of-line")
 call append("$", "\t(local to buffer)")
 call <SID>BinOptionL("eol")
+call append("$", "fixeol\tfixes missing end-of-line at end of text file")
+call append("$", "\t(local to buffer)")
+call <SID>BinOptionL("fixeol")
 if has("multi_byte")
   call append("$", "bomb\tprepend a Byte Order Mark to the file")
   call append("$", "\t(local to buffer)")
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -547,6 +547,7 @@ buf_clear_file(buf)
     buf->b_shortname = FALSE;
 #endif
     buf->b_p_eol = TRUE;
+    buf->b_p_fixeol = TRUE;
     buf->b_start_eol = TRUE;
 #ifdef FEAT_MBYTE
     buf->b_p_bomb = FALSE;
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -2623,10 +2623,10 @@ failed:
 #endif
 
     /*
-     * Trick: We remember if the last line of the read didn't have
-     * an eol even when 'binary' is off, for when writing it again with
-     * 'binary' on.  This is required for
-     * ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work.
+     * We remember if the last line of the read didn't have
+     * an eol even when 'binary' is off, to support turning 'fixeol' off,
+     * or writing the read again with 'binary' on.  The latter is required
+     * for ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work.
      */
     curbuf->b_no_eol_lnum = read_no_eol_lnum;
 
@@ -4547,7 +4547,7 @@ restore_backup:
 	/* write failed or last line has no EOL: stop here */
 	if (end == 0
 		|| (lnum == end
-		    && write_bin
+		    && (write_bin || !buf->b_p_fixeol)
 		    && (lnum == buf->b_no_eol_lnum
 			|| (lnum == buf->b_ml.ml_line_count && !buf->b_p_eol))))
 	{
--- a/src/memline.c
+++ b/src/memline.c
@@ -5361,8 +5361,10 @@ ml_find_line_or_offset(buf, lnum, offp)
 	if (ffdos)
 	    size += lnum - 1;
 
-	/* Don't count the last line break if 'bin' and 'noeol'. */
-	if (buf->b_p_bin && !buf->b_p_eol && buf->b_ml.ml_line_count == lnum)
+	/* Don't count the last line break if 'noeol' and ('bin' or
+	 * 'nofixeol'). */
+	if ((!buf->b_p_fixeol || buf->b_p_bin) && !buf->b_p_eol
+					   && buf->b_ml.ml_line_count == lnum)
 	    size -= ffdos + 1;
     }
 
--- a/src/netbeans.c
+++ b/src/netbeans.c
@@ -3802,7 +3802,7 @@ get_buf_size(buf_T *bufp)
 	    }
 	}
 	/* Correction for when last line doesn't have an EOL. */
-	if (!bufp->b_p_eol && bufp->b_p_bin)
+	if (!bufp->b_p_eol && (bufp->b_p_bin || !bufp->b_p_fixeol))
 	    char_count -= eol_size;
     }
 
--- a/src/ops.c
+++ b/src/ops.c
@@ -7052,7 +7052,7 @@ cursor_pos_info()
 					   &char_count_cursor, len, eol_size);
 		    if (lnum == curbuf->b_ml.ml_line_count
 			    && !curbuf->b_p_eol
-			    && curbuf->b_p_bin
+			    && (curbuf->b_p_bin || !curbuf->b_p_fixeol)
 			    && (long)STRLEN(s) < len)
 			byte_count_cursor -= eol_size;
 		}
@@ -7076,7 +7076,7 @@ cursor_pos_info()
 	}
 
 	/* Correction for when last line doesn't have an EOL. */
-	if (!curbuf->b_p_eol && curbuf->b_p_bin)
+	if (!curbuf->b_p_eol && (curbuf->b_p_bin || !curbuf->b_p_fixeol))
 	    byte_count -= eol_size;
 
 	if (VIsual_active)
--- a/src/option.c
+++ b/src/option.c
@@ -98,6 +98,7 @@
 # define PV_INC		OPT_BOTH(OPT_BUF(BV_INC))
 #endif
 #define PV_EOL		OPT_BUF(BV_EOL)
+#define PV_FIXEOL	OPT_BUF(BV_FIXEOL)
 #define PV_EP		OPT_BOTH(OPT_BUF(BV_EP))
 #define PV_ET		OPT_BUF(BV_ET)
 #ifdef FEAT_MBYTE
@@ -306,6 +307,7 @@ static char_u	*p_cfu;
 static char_u	*p_ofu;
 #endif
 static int	p_eol;
+static int	p_fixeol;
 static int	p_et;
 #ifdef FEAT_MBYTE
 static char_u	*p_fenc;
@@ -1169,6 +1171,9 @@ static struct vimoption
 			    {(char_u *)"", (char_u *)0L}
 #endif
 			    SCRIPTID_INIT},
+    {"fixendofline",  "fixeol", P_BOOL|P_VI_DEF|P_RSTAT,
+			    (char_u *)&p_fixeol, PV_FIXEOL,
+			    {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
     {"fkmap",	    "fk",   P_BOOL|P_VI_DEF,
 #ifdef FEAT_FKMAP
 			    (char_u *)&p_fkmap, PV_NONE,
@@ -7781,6 +7786,11 @@ set_bool_option(opt_idx, varp, value, op
     {
 	redraw_titles();
     }
+    /* when 'fixeol' is changed, redraw the window title */
+    else if ((int *)varp == &curbuf->b_p_fixeol)
+    {
+	redraw_titles();
+    }
 # ifdef FEAT_MBYTE
     /* when 'bomb' is changed, redraw the window title and tab page text */
     else if ((int *)varp == &curbuf->b_p_bomb)
@@ -10176,6 +10186,7 @@ get_varp(p)
 	case PV_OFU:	return (char_u *)&(curbuf->b_p_ofu);
 #endif
 	case PV_EOL:	return (char_u *)&(curbuf->b_p_eol);
+	case PV_FIXEOL:	return (char_u *)&(curbuf->b_p_fixeol);
 	case PV_ET:	return (char_u *)&(curbuf->b_p_et);
 #ifdef FEAT_MBYTE
 	case PV_FENC:	return (char_u *)&(curbuf->b_p_fenc);
@@ -11894,6 +11905,7 @@ save_file_ff(buf)
  * from when editing started (save_file_ff() called).
  * Also when 'endofline' was changed and 'binary' is set, or when 'bomb' was
  * changed and 'binary' is not set.
+ * Also when 'endofline' was changed and 'fixeol' is not set.
  * When "ignore_empty" is true don't consider a new, empty buffer to be
  * changed.
  */
@@ -11912,7 +11924,7 @@ file_ff_differs(buf, ignore_empty)
 	return FALSE;
     if (buf->b_start_ffc != *buf->b_p_ff)
 	return TRUE;
-    if (buf->b_p_bin && buf->b_start_eol != buf->b_p_eol)
+    if ((buf->b_p_bin || !buf->b_p_fixeol) && buf->b_start_eol != buf->b_p_eol)
 	return TRUE;
 #ifdef FEAT_MBYTE
     if (!buf->b_p_bin && buf->b_start_bomb != buf->b_p_bomb)
--- a/src/option.h
+++ b/src/option.h
@@ -962,6 +962,7 @@ enum
     , BV_INC
 #endif
     , BV_EOL
+    , BV_FIXEOL
     , BV_EP
     , BV_ET
     , BV_FENC
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -4624,7 +4624,8 @@ mch_call_shell(cmd, options)
 				/* Finished a line, add a NL, unless this line
 				 * should not have one. */
 				if (lnum != curbuf->b_op_end.lnum
-					|| !curbuf->b_p_bin
+					|| (!curbuf->b_p_bin
+					    && curbuf->b_p_fixeol)
 					|| (lnum != curbuf->b_no_eol_lnum
 					    && (lnum !=
 						    curbuf->b_ml.ml_line_count
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -4173,7 +4173,8 @@ sub_process_writer(LPVOID param)
 	    /* Finished a line, add a NL, unless this line should not have
 	     * one. */
 	    if (lnum != curbuf->b_op_end.lnum
-		|| !curbuf->b_p_bin
+		|| (!curbuf->b_p_bin
+		    && curbuf->b_p_fixeol)
 		|| (lnum != curbuf->b_no_eol_lnum
 		    && (lnum != curbuf->b_ml.ml_line_count
 			|| curbuf->b_p_eol)))
--- a/src/structs.h
+++ b/src/structs.h
@@ -635,7 +635,7 @@ typedef struct memline
     int		ml_flags;
 
     infoptr_T	*ml_stack;	/* stack of pointer blocks (array of IPTRs) */
-    int		ml_stack_top;	/* current top if ml_stack */
+    int		ml_stack_top;	/* current top of ml_stack */
     int		ml_stack_size;	/* total number of entries in ml_stack */
 
     linenr_T	ml_line_lnum;	/* line number of cached line, 0 if not valid */
@@ -1586,6 +1586,7 @@ struct file_buffer
     char_u	*b_p_ofu;	/* 'omnifunc' */
 #endif
     int		b_p_eol;	/* 'endofline' */
+    int		b_p_fixeol;	/* 'fixendofline' */
     int		b_p_et;		/* 'expandtab' */
     int		b_p_et_nobin;	/* b_p_et saved for binary mode */
 #ifdef FEAT_MBYTE
--- a/src/testdir/Make_amiga.mak
+++ b/src/testdir/Make_amiga.mak
@@ -45,6 +45,7 @@ SCRIPTS = test1.out test3.out test4.out 
 		test_command_count.out \
 		test_erasebackword.out \
 		test_eval.out \
+		test_fixeol.out \
 		test_increment.out \
 		test_insertcount.out \
 		test_listchars.out \
@@ -195,6 +196,7 @@ test_command_count.out: test_command_cou
 test_erasebackword.out: test_erasebackword.in
 test_eval.out: test_eval.in
 test_increment.out: test_increment.in
+test_fixeol.out: test_fixeol.in
 test_insertcount.out: test_insertcount.in
 test_listchars.out: test_listchars.in
 test_listlbr.out: test_listlbr.in
--- a/src/testdir/Make_dos.mak
+++ b/src/testdir/Make_dos.mak
@@ -44,6 +44,7 @@ SCRIPTS =	test3.out test4.out test5.out 
 		test_command_count.out \
 		test_erasebackword.out \
 		test_eval.out \
+		test_fixeol.out \
 		test_increment.out \
 		test_insertcount.out \
 		test_listchars.out \
--- a/src/testdir/Make_ming.mak
+++ b/src/testdir/Make_ming.mak
@@ -66,6 +66,7 @@ SCRIPTS =	test3.out test4.out test5.out 
 		test_command_count.out \
 		test_erasebackword.out \
 		test_eval.out \
+		test_fixeol.out \
 		test_increment.out \
 		test_insertcount.out \
 		test_listchars.out \
--- a/src/testdir/Make_os2.mak
+++ b/src/testdir/Make_os2.mak
@@ -46,6 +46,7 @@ SCRIPTS = test1.out test3.out test4.out 
 		test_command_count.out \
 		test_erasebackword.out \
 		test_eval.out \
+		test_fixeol.out \
 		test_increment.out \
 		test_insertcount.out \
 		test_listchars.out \
--- a/src/testdir/Make_vms.mms
+++ b/src/testdir/Make_vms.mms
@@ -4,7 +4,7 @@
 # Authors:	Zoltan Arpadffy, <arpadffy@polarhome.com>
 #		Sandor Kopanyi,  <sandor.kopanyi@mailbox.hu>
 #
-# Last change:  2015 Jul 10
+# Last change:  2015 Jul 17
 #
 # This has been tested on VMS 6.2 to 8.3 on DEC Alpha, VAX and IA64.
 # Edit the lines in the Configuration section below to select.
@@ -105,6 +105,7 @@ SCRIPT = test1.out  test2.out  test3.out
 	 test_command_count.out \
 	 test_erasebackword.out \
 	 test_eval.out \
+	 test_fixeol.out \
 	 test_increment.out \
 	 test_insertcount.out \
 	 test_listchars.out \
--- a/src/testdir/Makefile
+++ b/src/testdir/Makefile
@@ -42,6 +42,7 @@ SCRIPTS = test1.out test2.out test3.out 
 		test_command_count.out \
 		test_erasebackword.out \
 		test_eval.out \
+		test_fixeol.out \
 		test_increment.out \
 		test_insertcount.out \
 		test_listchars.out \
new file mode 100644
--- /dev/null
+++ b/src/testdir/test_fixeol.in
@@ -0,0 +1,40 @@
+Tests for 'fixeol'                         vim: set ft=vim :
+ 
+STARTTEST
+:" first write two test files – with and without trailing EOL
+:" use Unix fileformat for consistency
+:set ff=unix
+:enew!
+awith eol:w! XXEol
+:enew!
+:set noeol nofixeol
+awithout eol:w! XXNoEol
+:set eol fixeol
+:bwipe XXEol XXNoEol
+:"
+:" try editing files with 'fixeol' disabled
+:e! XXEol
+ostays eol:set nofixeol
+:w! XXTestEol
+:e! XXNoEol
+ostays without:set nofixeol
+:w! XXTestNoEol
+:bwipe XXEol XXNoEol XXTestEol XXTestNoEol
+:set fixeol
+:"
+:" Append "END" to each file so that we can see what the last written char was.
+ggdGaEND:w >>XXEol
+:w >>XXNoEol
+:w >>XXTestEol
+:w >>XXTestNoEol
+:"
+:" Concatenate the results
+:e! test.out
+a0:$r XXEol
+:$r XXNoEol
+Go1:$r XXTestEol
+:$r XXTestNoEol
+:w
+:qa!
+ENDTEST
+
new file mode 100644
--- /dev/null
+++ b/src/testdir/test_fixeol.ok
@@ -0,0 +1,10 @@
+0
+with eol
+END
+without eolEND
+1
+with eol
+stays eol
+END
+without eol
+stays withoutEND
--- a/src/version.c
+++ b/src/version.c
@@ -742,6 +742,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    785,
+/**/
     784,
 /**/
     783,