0
0
mirror of https://github.com/vim/vim.git synced 2025-07-25 10:54:51 -04:00

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().
This commit is contained in:
Bram Moolenaar 2016-01-19 23:36:15 +01:00
parent b8060fe862
commit f7edf40448
7 changed files with 187 additions and 44 deletions

View File

@ -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 VIM REFERENCE MANUAL by Bram Moolenaar
@ -1745,7 +1745,7 @@ Vim has a sorting function and a sorting command. The sorting function can be
found here: |sort()|, |uniq()|. found here: |sort()|, |uniq()|.
*:sor* *:sort* *: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 Sort lines in [range]. When no range is given all
lines are sorted. lines are sorted.
@ -1753,10 +1753,18 @@ found here: |sort()|, |uniq()|.
With [i] case is ignored. With [i] case is ignored.
Options [n][f][x][o][b] are mutually exclusive.
With [n] sorting is done on the first decimal number With [n] sorting is done on the first decimal number
in the line (after or inside a {pattern} match). in the line (after or inside a {pattern} match).
One leading '-' is included in the number. 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 With [x] sorting is done on the first hexadecimal
number in the line (after or inside a {pattern} number in the line (after or inside a {pattern}
match). A leading "0x" or "0X" is ignored. 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 With [b] sorting is done on the first binary number in
the line (after or inside a {pattern} match). the line (after or inside a {pattern} match).
With [u] only keep the first of a sequence of With [u] (u stands for unique) only keep the first of
identical lines (ignoring case when [i] is used). a sequence of identical lines (ignoring case when [i]
Without this flag, a sequence of identical lines is used). Without this flag, a sequence of identical
will be kept in their original order. lines will be kept in their original order.
Note that leading and trailing white space may cause Note that leading and trailing white space may cause
lines to be different. lines to be different.

View File

@ -809,6 +809,9 @@ static typval_T *alloc_tv __ARGS((void));
static typval_T *alloc_string_tv __ARGS((char_u *string)); static typval_T *alloc_string_tv __ARGS((char_u *string));
static void init_tv __ARGS((typval_T *varp)); static void init_tv __ARGS((typval_T *varp));
static long get_tv_number __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 __ARGS((typval_T *argvars));
static linenr_T get_tv_lnum_buf __ARGS((typval_T *argvars, buf_T *buf)); static linenr_T get_tv_lnum_buf __ARGS((typval_T *argvars, buf_T *buf));
static char_u *get_tv_string __ARGS((typval_T *varp)); 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_ic;
static int item_compare_numeric; static int item_compare_numeric;
static int item_compare_numbers; static int item_compare_numbers;
#ifdef FEAT_FLOAT
static int item_compare_float;
#endif
static char_u *item_compare_func; static char_u *item_compare_func;
static dict_T *item_compare_selfdict; static dict_T *item_compare_selfdict;
static int item_compare_func_err; static int item_compare_func_err;
@ -18182,6 +18188,16 @@ item_compare(s1, s2)
return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; 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 /* tv2string() puts quotes around a string and allocates memory. Don't do
* that for string variables. Use a single quote when comparing with a * that for string variables. Use a single quote when comparing with a
* non-string to do what the docs promise. */ * non-string to do what the docs promise. */
@ -18316,6 +18332,9 @@ do_sort_uniq(argvars, rettv, sort)
item_compare_ic = FALSE; item_compare_ic = FALSE;
item_compare_numeric = FALSE; item_compare_numeric = FALSE;
item_compare_numbers = FALSE; item_compare_numbers = FALSE;
#ifdef FEAT_FLOAT
item_compare_float = FALSE;
#endif
item_compare_func = NULL; item_compare_func = NULL;
item_compare_selfdict = NULL; item_compare_selfdict = NULL;
if (argvars[1].v_type != VAR_UNKNOWN) if (argvars[1].v_type != VAR_UNKNOWN)
@ -18346,6 +18365,13 @@ do_sort_uniq(argvars, rettv, sort)
item_compare_func = NULL; item_compare_func = NULL;
item_compare_numbers = TRUE; 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) else if (STRCMP(item_compare_func, "i") == 0)
{ {
item_compare_func = NULL; item_compare_func = NULL;
@ -21613,6 +21639,40 @@ get_tv_number_chk(varp, denote)
return n; 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. * Get the lnum from the first argument.
* Also accepts ".", "$", etc., but that only works for the current buffer. * Also accepts ".", "$", etc., but that only works for the current buffer.

View File

@ -275,18 +275,30 @@ linelen(has_tab)
static char_u *sortbuf1; static char_u *sortbuf1;
static char_u *sortbuf2; static char_u *sortbuf2;
static int sort_ic; /* ignore case */ static int sort_ic; /* ignore case */
static int sort_nr; /* sort on number */ static int sort_nr; /* sort on number */
static int sort_rx; /* sort on regex instead of skipping it */ 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 */ static int sort_abort; /* flag to indicate if sorting has been interrupted */
/* Struct to store info to be sorted. */ /* Struct to store info to be sorted. */
typedef struct typedef struct
{ {
linenr_T lnum; /* line number */ linenr_T lnum; /* line number */
long start_col_nr; /* starting column number or number */ union {
long end_col_nr; /* ending column number */ 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; } sorti_T;
static int static int
@ -319,19 +331,24 @@ sort_compare(s1, s2)
/* When sorting numbers "start_col_nr" is the number, not the column /* When sorting numbers "start_col_nr" is the number, not the column
* number. */ * number. */
if (sort_nr) if (sort_nr)
result = l1.start_col_nr == l2.start_col_nr ? 0 result = l1.st_u.value == l2.st_u.value ? 0
: l1.start_col_nr > l2.start_col_nr ? 1 : -1; : 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 else
{ {
/* We need to copy one line into "sortbuf1", because there is no /* We need to copy one line into "sortbuf1", because there is no
* guarantee that the first pointer becomes invalid when obtaining the * guarantee that the first pointer becomes invalid when obtaining the
* second one. */ * second one. */
STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.start_col_nr, STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.st_u.line.start_col_nr,
l1.end_col_nr - l1.start_col_nr + 1); l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr + 1);
sortbuf1[l1.end_col_nr - l1.start_col_nr] = 0; sortbuf1[l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr] = 0;
STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.start_col_nr, STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.st_u.line.start_col_nr,
l2.end_col_nr - l2.start_col_nr + 1); l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr + 1);
sortbuf2[l2.end_col_nr - l2.start_col_nr] = 0; sortbuf2[l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr] = 0;
result = sort_ic ? STRICMP(sortbuf1, sortbuf2) result = sort_ic ? STRICMP(sortbuf1, sortbuf2)
: STRCMP(sortbuf1, sortbuf2); : STRCMP(sortbuf1, sortbuf2);
@ -382,6 +399,9 @@ ex_sort(eap)
goto sortend; goto sortend;
sort_abort = sort_ic = sort_rx = sort_nr = 0; sort_abort = sort_ic = sort_rx = sort_nr = 0;
#ifdef FEAT_FLOAT
sort_flt = 0;
#endif
for (p = eap->arg; *p != NUL; ++p) for (p = eap->arg; *p != NUL; ++p)
{ {
@ -393,9 +413,16 @@ ex_sort(eap)
sort_rx = TRUE; sort_rx = TRUE;
else if (*p == 'n') else if (*p == 'n')
{ {
sort_nr = 2; sort_nr = 1;
++format_found; ++format_found;
} }
#ifdef FEAT_FLOAT
else if (*p == 'f')
{
sort_flt = 1;
++format_found;
}
#endif
else if (*p == 'b') else if (*p == 'b')
{ {
sort_what = STR2NR_BIN + STR2NR_FORCE; sort_what = STR2NR_BIN + STR2NR_FORCE;
@ -460,7 +487,8 @@ ex_sort(eap)
goto sortend; 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; sort_nr += sort_what;
/* /*
@ -494,7 +522,7 @@ ex_sort(eap)
if (regmatch.regprog != NULL) if (regmatch.regprog != NULL)
end_col = 0; end_col = 0;
if (sort_nr) if (sort_nr || sort_flt)
{ {
/* Make sure vim_str2nr doesn't read any digits past the end /* Make sure vim_str2nr doesn't read any digits past the end
* of the match, by temporarily terminating the string there */ * of the match, by temporarily terminating the string there */
@ -503,27 +531,45 @@ ex_sort(eap)
*s2 = NUL; *s2 = NUL;
/* Sorting on number: Store the number itself. */ /* Sorting on number: Store the number itself. */
p = s + start_col; p = s + start_col;
if (sort_what & STR2NR_HEX) if (sort_nr)
s = skiptohex(p); {
else if (sort_what & STR2NR_BIN) if (sort_what & STR2NR_HEX)
s = skiptobin(p); 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 else
s = skiptodigit(p); {
if (s > p && s[-1] == '-') s = skipwhite(p);
--s; /* include preceding negative sign */ if (*s == '+')
if (*s == NUL) s = skipwhite(s + 1);
/* empty line should sort before any number */
nrs[lnum - eap->line1].start_col_nr = -MAXLNUM; if (*s == NUL)
else /* empty line should sort before any number */
vim_str2nr(s, NULL, NULL, sort_what, nrs[lnum - eap->line1].st_u.value_flt = -DBL_MAX;
&nrs[lnum - eap->line1].start_col_nr, NULL, 0); else
nrs[lnum - eap->line1].st_u.value_flt =
strtod((char *)s, NULL);
}
#endif
*s2 = c; *s2 = c;
} }
else else
{ {
/* Store the column to sort at. */ /* Store the column to sort at. */
nrs[lnum - eap->line1].start_col_nr = start_col; nrs[lnum - eap->line1].st_u.line.start_col_nr = start_col;
nrs[lnum - eap->line1].end_col_nr = end_col; nrs[lnum - eap->line1].st_u.line.end_col_nr = end_col;
} }
nrs[lnum - eap->line1].lnum = lnum; nrs[lnum - eap->line1].lnum = lnum;

View File

@ -32,6 +32,7 @@ STARTTEST
:/^t27:/+1,/^t28/-1sort no :/^t27:/+1,/^t28/-1sort no
:/^t28:/+1,/^t29/-1sort b :/^t28:/+1,/^t29/-1sort b
:/^t29:/+1,/^t30/-1sort b :/^t29:/+1,/^t30/-1sort b
:/^t30:/+1,/^t31/-1sort f
:/^t01:/,$wq! test.out :/^t01:/,$wq! test.out
ENDTEST ENDTEST
@ -496,9 +497,9 @@ c321d
b322b b322b
b321 b321
b321b b321b
t28: binary t28: binary
0b111000 0b111000
0b101100 0b101100
0b101001 0b101001
@ -513,9 +514,9 @@ t28: binary
0b100010 0b100010
0b100100 0b100100
0b100010 0b100010
t29: binary with leading characters t29: binary with leading characters
0b100010 0b100010
0b010000 0b010000
0b101001 0b101001
@ -530,4 +531,15 @@ ab0b100000
0b101010 0b101010
0b000000 0b000000
b0b111000 b0b111000
t30: done
t30: float
1.234
0.88
123.456
1.15e-6
-1.1e3
-1.01e3
t31: done

View File

@ -453,6 +453,8 @@ c321d
b322b b322b
b321 b321
b321b b321b
t28: binary t28: binary
@ -487,4 +489,13 @@ a0b101001
0b101010 0b101010
b0b101100 b0b101100
b0b111000 b0b111000
t30: done t30: float
-1.1e3
-1.01e3
1.15e-6
0.88
1.234
123.456
t31: done

View File

@ -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'))
call assert_equal(['3', '13', '28'], sort(['13', '28', '3'], 'N')) call assert_equal(['3', '13', '28'], sort(['13', '28', '3'], 'N'))
endfunc endfunc
func Test_sort_float()
call assert_equal([0.28, 3, 13.5], sort([13.5, 0.28, 3], 'f'))
endfunc

View File

@ -741,6 +741,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1143,
/**/ /**/
1142, 1142,
/**/ /**/