changeset 7689:20dc2763a3b9 v7.4.1143

commit https://github.com/vim/vim/commit/f7edf40448a09e04eec3bd05e043f7fea93b07c9 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Jan 19 23:36:15 2016 +0100 patch 7.4.1143 Problem: Can't sort on floating point numbers. Solution: Add the "f" flag to ":sort". (Alex Jakushev) Also add the "f" flag to sort().
author Christian Brabandt <cb@256bit.org>
date Tue, 19 Jan 2016 23:45:05 +0100
parents f56cebad5ba2
children 0f193b74d989
files runtime/doc/change.txt src/eval.c src/ex_cmds.c src/testdir/test57.in src/testdir/test57.ok src/testdir/test_sort.vim src/version.c
diffstat 7 files changed, 186 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -1,4 +1,4 @@
-*change.txt*    For Vim version 7.4.  Last change: 2016 Jan 02
+*change.txt*    For Vim version 7.4.  Last change: 2016 Jan 19
 
 
 		  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -1745,7 +1745,7 @@ Vim has a sorting function and a sorting
 found here: |sort()|, |uniq()|.
 
 							*:sor* *:sort*
-:[range]sor[t][!] [i][u][r][n][x][o][b] [/{pattern}/]
+:[range]sor[t][!] [b][f][i][n][o][r][u][x] [/{pattern}/]
 			Sort lines in [range].  When no range is given all
 			lines are sorted.
 
@@ -1753,10 +1753,18 @@ found here: |sort()|, |uniq()|.
 
 			With [i] case is ignored.
 
+			Options [n][f][x][o][b] are mutually exclusive.
+
 			With [n] sorting is done on the first decimal number
 			in the line (after or inside a {pattern} match).
 			One leading '-' is included in the number.
 
+			With [f] sorting is done on the Float in the line.
+			The value of Float is determined similar to passing
+			the text (after or inside a {pattern} match) to
+			str2float() function. This option is available only
+			if Vim was compiled with Floating point support.
+
 			With [x] sorting is done on the first hexadecimal
 			number in the line (after or inside a {pattern}
 			match).  A leading "0x" or "0X" is ignored.
@@ -1768,10 +1776,10 @@ found here: |sort()|, |uniq()|.
 			With [b] sorting is done on the first binary number in
 			the line (after or inside a {pattern} match).
 
-			With [u] only keep the first of a sequence of
-			identical lines (ignoring case when [i] is used).
-			Without this flag, a sequence of identical lines
-			will be kept in their original order.
+			With [u] (u stands for unique) only keep the first of
+			a sequence of identical lines (ignoring case when [i]
+			is used).  Without this flag, a sequence of identical
+			lines will be kept in their original order.
 			Note that leading and trailing white space may cause
 			lines to be different.
 
--- a/src/eval.c
+++ b/src/eval.c
@@ -809,6 +809,9 @@ static typval_T *alloc_tv __ARGS((void))
 static typval_T *alloc_string_tv __ARGS((char_u *string));
 static void init_tv __ARGS((typval_T *varp));
 static long get_tv_number __ARGS((typval_T *varp));
+#ifdef FEAT_FLOAT
+static float_T get_tv_float(typval_T *varp);
+#endif
 static linenr_T get_tv_lnum __ARGS((typval_T *argvars));
 static linenr_T get_tv_lnum_buf __ARGS((typval_T *argvars, buf_T *buf));
 static char_u *get_tv_string __ARGS((typval_T *varp));
@@ -18143,6 +18146,9 @@ typedef struct
 static int	item_compare_ic;
 static int	item_compare_numeric;
 static int	item_compare_numbers;
+#ifdef FEAT_FLOAT
+static int	item_compare_float;
+#endif
 static char_u	*item_compare_func;
 static dict_T	*item_compare_selfdict;
 static int	item_compare_func_err;
@@ -18182,6 +18188,16 @@ item_compare(s1, s2)
 	return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
     }
 
+#ifdef FEAT_FLOAT
+    if (item_compare_float)
+    {
+	float_T	v1 = get_tv_float(tv1);
+	float_T	v2 = get_tv_float(tv2);
+
+	return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
+    }
+#endif
+
     /* tv2string() puts quotes around a string and allocates memory.  Don't do
      * that for string variables. Use a single quote when comparing with a
      * non-string to do what the docs promise. */
@@ -18316,6 +18332,9 @@ do_sort_uniq(argvars, rettv, sort)
 	item_compare_ic = FALSE;
 	item_compare_numeric = FALSE;
 	item_compare_numbers = FALSE;
+#ifdef FEAT_FLOAT
+	item_compare_float = FALSE;
+#endif
 	item_compare_func = NULL;
 	item_compare_selfdict = NULL;
 	if (argvars[1].v_type != VAR_UNKNOWN)
@@ -18346,6 +18365,13 @@ do_sort_uniq(argvars, rettv, sort)
 			item_compare_func = NULL;
 			item_compare_numbers = TRUE;
 		    }
+#ifdef FEAT_FLOAT
+		    else if (STRCMP(item_compare_func, "f") == 0)
+		    {
+			item_compare_func = NULL;
+			item_compare_float = TRUE;
+		    }
+#endif
 		    else if (STRCMP(item_compare_func, "i") == 0)
 		    {
 			item_compare_func = NULL;
@@ -21613,6 +21639,40 @@ get_tv_number_chk(varp, denote)
     return n;
 }
 
+#ifdef FEAT_FLOAT
+    static float_T
+get_tv_float(varp)
+    typval_T	*varp;
+{
+    switch (varp->v_type)
+    {
+	case VAR_NUMBER:
+	    return (float_T)(varp->vval.v_number);
+#ifdef FEAT_FLOAT
+	case VAR_FLOAT:
+	    return varp->vval.v_float;
+	    break;
+#endif
+	case VAR_FUNC:
+	    EMSG(_("E891: Using a Funcref as a Float"));
+	    break;
+	case VAR_STRING:
+	    EMSG(_("E892: Using a String as a Float"));
+	    break;
+	case VAR_LIST:
+	    EMSG(_("E893: Using a List as a Float"));
+	    break;
+	case VAR_DICT:
+	    EMSG(_("E894: Using a Dictionary as a Float"));
+	    break;
+	default:
+	    EMSG2(_(e_intern2), "get_tv_float()");
+	    break;
+    }
+    return 0;
+}
+#endif
+
 /*
  * Get the lnum from the first argument.
  * Also accepts ".", "$", etc., but that only works for the current buffer.
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -275,18 +275,30 @@ linelen(has_tab)
 static char_u	*sortbuf1;
 static char_u	*sortbuf2;
 
-static int	sort_ic;		/* ignore case */
-static int	sort_nr;		/* sort on number */
-static int	sort_rx;		/* sort on regex instead of skipping it */
-
-static int	sort_abort;		/* flag to indicate if sorting has been interrupted */
+static int	sort_ic;	/* ignore case */
+static int	sort_nr;	/* sort on number */
+static int	sort_rx;	/* sort on regex instead of skipping it */
+#ifdef FEAT_FLOAT
+static int	sort_flt;	/* sort on floating number */
+#endif
+
+static int	sort_abort;	/* flag to indicate if sorting has been interrupted */
 
 /* Struct to store info to be sorted. */
 typedef struct
 {
     linenr_T	lnum;			/* line number */
-    long	start_col_nr;		/* starting column number or number */
-    long	end_col_nr;		/* ending column number */
+    union {
+	struct
+	{
+	    long	start_col_nr;		/* starting column number */
+	    long	end_col_nr;		/* ending column number */
+	} line;
+	long	value;		/* value if sorting by integer */
+#ifdef FEAT_FLOAT
+	float_T value_flt;	/* value if sorting by float */
+#endif
+    } st_u;
 } sorti_T;
 
 static int
@@ -319,19 +331,24 @@ sort_compare(s1, s2)
     /* When sorting numbers "start_col_nr" is the number, not the column
      * number. */
     if (sort_nr)
-	result = l1.start_col_nr == l2.start_col_nr ? 0
-				 : l1.start_col_nr > l2.start_col_nr ? 1 : -1;
+	result = l1.st_u.value == l2.st_u.value ? 0
+				 : l1.st_u.value > l2.st_u.value ? 1 : -1;
+#ifdef FEAT_FLOAT
+    else if (sort_flt)
+	result = l1.st_u.value_flt == l2.st_u.value_flt ? 0
+			     : l1.st_u.value_flt > l2.st_u.value_flt ? 1 : -1;
+#endif
     else
     {
 	/* We need to copy one line into "sortbuf1", because there is no
 	 * guarantee that the first pointer becomes invalid when obtaining the
 	 * second one. */
-	STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.start_col_nr,
-					 l1.end_col_nr - l1.start_col_nr + 1);
-	sortbuf1[l1.end_col_nr - l1.start_col_nr] = 0;
-	STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.start_col_nr,
-					 l2.end_col_nr - l2.start_col_nr + 1);
-	sortbuf2[l2.end_col_nr - l2.start_col_nr] = 0;
+	STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.st_u.line.start_col_nr,
+		     l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr + 1);
+	sortbuf1[l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr] = 0;
+	STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.st_u.line.start_col_nr,
+		     l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr + 1);
+	sortbuf2[l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr] = 0;
 
 	result = sort_ic ? STRICMP(sortbuf1, sortbuf2)
 						 : STRCMP(sortbuf1, sortbuf2);
@@ -382,6 +399,9 @@ ex_sort(eap)
 	goto sortend;
 
     sort_abort = sort_ic = sort_rx = sort_nr = 0;
+#ifdef FEAT_FLOAT
+    sort_flt = 0;
+#endif
 
     for (p = eap->arg; *p != NUL; ++p)
     {
@@ -393,9 +413,16 @@ ex_sort(eap)
 	    sort_rx = TRUE;
 	else if (*p == 'n')
 	{
-	    sort_nr = 2;
+	    sort_nr = 1;
 	    ++format_found;
 	}
+#ifdef FEAT_FLOAT
+	else if (*p == 'f')
+	{
+	    sort_flt = 1;
+	    ++format_found;
+	}
+#endif
 	else if (*p == 'b')
 	{
 	    sort_what = STR2NR_BIN + STR2NR_FORCE;
@@ -460,7 +487,8 @@ ex_sort(eap)
 	goto sortend;
     }
 
-    /* From here on "sort_nr" is used as a flag for any number sorting. */
+    /* From here on "sort_nr" is used as a flag for any integer number
+     * sorting. */
     sort_nr += sort_what;
 
     /*
@@ -494,7 +522,7 @@ ex_sort(eap)
 	    if (regmatch.regprog != NULL)
 		end_col = 0;
 
-	if (sort_nr)
+	if (sort_nr || sort_flt)
 	{
 	    /* Make sure vim_str2nr doesn't read any digits past the end
 	     * of the match, by temporarily terminating the string there */
@@ -503,27 +531,45 @@ ex_sort(eap)
 	    *s2 = NUL;
 	    /* Sorting on number: Store the number itself. */
 	    p = s + start_col;
-	    if (sort_what & STR2NR_HEX)
-		s = skiptohex(p);
-	    else if (sort_what & STR2NR_BIN)
-		s = skiptobin(p);
+	    if (sort_nr)
+	    {
+		if (sort_what & STR2NR_HEX)
+		    s = skiptohex(p);
+		else if (sort_what & STR2NR_BIN)
+		    s = skiptobin(p);
+		else
+		    s = skiptodigit(p);
+		if (s > p && s[-1] == '-')
+		    --s;  /* include preceding negative sign */
+		if (*s == NUL)
+		    /* empty line should sort before any number */
+		    nrs[lnum - eap->line1].st_u.value = -MAXLNUM;
+		else
+		    vim_str2nr(s, NULL, NULL, sort_what,
+			       &nrs[lnum - eap->line1].st_u.value, NULL, 0);
+	    }
+#ifdef FEAT_FLOAT
 	    else
-		s = skiptodigit(p);
-	    if (s > p && s[-1] == '-')
-		--s;  /* include preceding negative sign */
-	    if (*s == NUL)
-		/* empty line should sort before any number */
-		nrs[lnum - eap->line1].start_col_nr = -MAXLNUM;
-	    else
-		vim_str2nr(s, NULL, NULL, sort_what,
-			       &nrs[lnum - eap->line1].start_col_nr, NULL, 0);
+	    {
+		s = skipwhite(p);
+		if (*s == '+')
+		    s = skipwhite(s + 1);
+
+		if (*s == NUL)
+		    /* empty line should sort before any number */
+		    nrs[lnum - eap->line1].st_u.value_flt = -DBL_MAX;
+		else
+		    nrs[lnum - eap->line1].st_u.value_flt =
+						      strtod((char *)s, NULL);
+	    }
+#endif
 	    *s2 = c;
 	}
 	else
 	{
 	    /* Store the column to sort at. */
-	    nrs[lnum - eap->line1].start_col_nr = start_col;
-	    nrs[lnum - eap->line1].end_col_nr = end_col;
+	    nrs[lnum - eap->line1].st_u.line.start_col_nr = start_col;
+	    nrs[lnum - eap->line1].st_u.line.end_col_nr = end_col;
 	}
 
 	nrs[lnum - eap->line1].lnum = lnum;
--- a/src/testdir/test57.in
+++ b/src/testdir/test57.in
@@ -32,6 +32,7 @@ STARTTEST
 :/^t27:/+1,/^t28/-1sort no
 :/^t28:/+1,/^t29/-1sort b
 :/^t29:/+1,/^t30/-1sort b
+:/^t30:/+1,/^t31/-1sort f
 :/^t01:/,$wq! test.out
 ENDTEST
 
@@ -496,9 +497,9 @@ c321d
 b322b
 b321
 b321b
-t28: binary
 
 
+t28: binary
 0b111000
 0b101100
 0b101001
@@ -513,9 +514,9 @@ 0b101010
 0b100010
 0b100100
 0b100010
-t29: binary with leading characters
 
 
+t29: binary with leading characters
 0b100010
 0b010000
  0b101001
@@ -530,4 +531,15 @@ ab0b100000
 0b101010
 0b000000
 b0b111000
-t30: done
+
+
+t30: float
+1.234
+0.88
+123.456
+1.15e-6
+-1.1e3
+-1.01e3
+
+
+t31: done
--- a/src/testdir/test57.ok
+++ b/src/testdir/test57.ok
@@ -453,6 +453,8 @@ c321d
 b322b
 b321
 b321b
+
+
 t28: binary
 
 
@@ -487,4 +489,13 @@ a0b101001
 0b101010
 b0b101100
 b0b111000
-t30: done
+t30: float
+
+
+-1.1e3
+-1.01e3
+1.15e-6
+0.88
+1.234
+123.456
+t31: done
--- a/src/testdir/test_sort.vim
+++ b/src/testdir/test_sort.vim
@@ -17,3 +17,7 @@ func Test_sort_numbers()
   call assert_equal([3, 13, 28], sort([13, 28, 3], 'N'))
   call assert_equal(['3', '13', '28'], sort(['13', '28', '3'], 'N'))
 endfunc
+
+func Test_sort_float()
+  call assert_equal([0.28, 3, 13.5], sort([13.5, 0.28, 3], 'f'))
+endfunc
--- 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 */
 /**/
+    1143,
+/**/
     1142,
 /**/
     1141,