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:
parent
b8060fe862
commit
f7edf40448
@ -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.
|
||||||
|
|
||||||
|
60
src/eval.c
60
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 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.
|
||||||
|
110
src/ex_cmds.c
110
src/ex_cmds.c
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user