Skip to content

Commit f7edf40

Browse files
committed
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().
1 parent b8060fe commit f7edf40

File tree

7 files changed

+185
-42
lines changed

7 files changed

+185
-42
lines changed

runtime/doc/change.txt

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*change.txt* For Vim version 7.4. Last change: 2016 Jan 02
1+
*change.txt* For Vim version 7.4. Last change: 2016 Jan 19
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1745,18 +1745,26 @@ Vim has a sorting function and a sorting command. The sorting function can be
17451745
found here: |sort()|, |uniq()|.
17461746

17471747
*:sor* *:sort*
1748-
:[range]sor[t][!] [i][u][r][n][x][o][b] [/{pattern}/]
1748+
:[range]sor[t][!] [b][f][i][n][o][r][u][x] [/{pattern}/]
17491749
Sort lines in [range]. When no range is given all
17501750
lines are sorted.
17511751

17521752
With [!] the order is reversed.
17531753

17541754
With [i] case is ignored.
17551755

1756+
Options [n][f][x][o][b] are mutually exclusive.
1757+
17561758
With [n] sorting is done on the first decimal number
17571759
in the line (after or inside a {pattern} match).
17581760
One leading '-' is included in the number.
17591761

1762+
With [f] sorting is done on the Float in the line.
1763+
The value of Float is determined similar to passing
1764+
the text (after or inside a {pattern} match) to
1765+
str2float() function. This option is available only
1766+
if Vim was compiled with Floating point support.
1767+
17601768
With [x] sorting is done on the first hexadecimal
17611769
number in the line (after or inside a {pattern}
17621770
match). A leading "0x" or "0X" is ignored.
@@ -1768,10 +1776,10 @@ found here: |sort()|, |uniq()|.
17681776
With [b] sorting is done on the first binary number in
17691777
the line (after or inside a {pattern} match).
17701778

1771-
With [u] only keep the first of a sequence of
1772-
identical lines (ignoring case when [i] is used).
1773-
Without this flag, a sequence of identical lines
1774-
will be kept in their original order.
1779+
With [u] (u stands for unique) only keep the first of
1780+
a sequence of identical lines (ignoring case when [i]
1781+
is used). Without this flag, a sequence of identical
1782+
lines will be kept in their original order.
17751783
Note that leading and trailing white space may cause
17761784
lines to be different.
17771785

src/eval.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,9 @@ static typval_T *alloc_tv __ARGS((void));
809809
static typval_T *alloc_string_tv __ARGS((char_u *string));
810810
static void init_tv __ARGS((typval_T *varp));
811811
static long get_tv_number __ARGS((typval_T *varp));
812+
#ifdef FEAT_FLOAT
813+
static float_T get_tv_float(typval_T *varp);
814+
#endif
812815
static linenr_T get_tv_lnum __ARGS((typval_T *argvars));
813816
static linenr_T get_tv_lnum_buf __ARGS((typval_T *argvars, buf_T *buf));
814817
static char_u *get_tv_string __ARGS((typval_T *varp));
@@ -18143,6 +18146,9 @@ typedef struct
1814318146
static int item_compare_ic;
1814418147
static int item_compare_numeric;
1814518148
static int item_compare_numbers;
18149+
#ifdef FEAT_FLOAT
18150+
static int item_compare_float;
18151+
#endif
1814618152
static char_u *item_compare_func;
1814718153
static dict_T *item_compare_selfdict;
1814818154
static int item_compare_func_err;
@@ -18182,6 +18188,16 @@ item_compare(s1, s2)
1818218188
return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
1818318189
}
1818418190

18191+
#ifdef FEAT_FLOAT
18192+
if (item_compare_float)
18193+
{
18194+
float_T v1 = get_tv_float(tv1);
18195+
float_T v2 = get_tv_float(tv2);
18196+
18197+
return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
18198+
}
18199+
#endif
18200+
1818518201
/* tv2string() puts quotes around a string and allocates memory. Don't do
1818618202
* that for string variables. Use a single quote when comparing with a
1818718203
* non-string to do what the docs promise. */
@@ -18316,6 +18332,9 @@ do_sort_uniq(argvars, rettv, sort)
1831618332
item_compare_ic = FALSE;
1831718333
item_compare_numeric = FALSE;
1831818334
item_compare_numbers = FALSE;
18335+
#ifdef FEAT_FLOAT
18336+
item_compare_float = FALSE;
18337+
#endif
1831918338
item_compare_func = NULL;
1832018339
item_compare_selfdict = NULL;
1832118340
if (argvars[1].v_type != VAR_UNKNOWN)
@@ -18346,6 +18365,13 @@ do_sort_uniq(argvars, rettv, sort)
1834618365
item_compare_func = NULL;
1834718366
item_compare_numbers = TRUE;
1834818367
}
18368+
#ifdef FEAT_FLOAT
18369+
else if (STRCMP(item_compare_func, "f") == 0)
18370+
{
18371+
item_compare_func = NULL;
18372+
item_compare_float = TRUE;
18373+
}
18374+
#endif
1834918375
else if (STRCMP(item_compare_func, "i") == 0)
1835018376
{
1835118377
item_compare_func = NULL;
@@ -21613,6 +21639,40 @@ get_tv_number_chk(varp, denote)
2161321639
return n;
2161421640
}
2161521641

21642+
#ifdef FEAT_FLOAT
21643+
static float_T
21644+
get_tv_float(varp)
21645+
typval_T *varp;
21646+
{
21647+
switch (varp->v_type)
21648+
{
21649+
case VAR_NUMBER:
21650+
return (float_T)(varp->vval.v_number);
21651+
#ifdef FEAT_FLOAT
21652+
case VAR_FLOAT:
21653+
return varp->vval.v_float;
21654+
break;
21655+
#endif
21656+
case VAR_FUNC:
21657+
EMSG(_("E891: Using a Funcref as a Float"));
21658+
break;
21659+
case VAR_STRING:
21660+
EMSG(_("E892: Using a String as a Float"));
21661+
break;
21662+
case VAR_LIST:
21663+
EMSG(_("E893: Using a List as a Float"));
21664+
break;
21665+
case VAR_DICT:
21666+
EMSG(_("E894: Using a Dictionary as a Float"));
21667+
break;
21668+
default:
21669+
EMSG2(_(e_intern2), "get_tv_float()");
21670+
break;
21671+
}
21672+
return 0;
21673+
}
21674+
#endif
21675+
2161621676
/*
2161721677
* Get the lnum from the first argument.
2161821678
* Also accepts ".", "$", etc., but that only works for the current buffer.

src/ex_cmds.c

Lines changed: 78 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -275,18 +275,30 @@ linelen(has_tab)
275275
static char_u *sortbuf1;
276276
static char_u *sortbuf2;
277277

278-
static int sort_ic; /* ignore case */
279-
static int sort_nr; /* sort on number */
280-
static int sort_rx; /* sort on regex instead of skipping it */
278+
static int sort_ic; /* ignore case */
279+
static int sort_nr; /* sort on number */
280+
static int sort_rx; /* sort on regex instead of skipping it */
281+
#ifdef FEAT_FLOAT
282+
static int sort_flt; /* sort on floating number */
283+
#endif
281284

282-
static int sort_abort; /* flag to indicate if sorting has been interrupted */
285+
static int sort_abort; /* flag to indicate if sorting has been interrupted */
283286

284287
/* Struct to store info to be sorted. */
285288
typedef struct
286289
{
287290
linenr_T lnum; /* line number */
288-
long start_col_nr; /* starting column number or number */
289-
long end_col_nr; /* ending column number */
291+
union {
292+
struct
293+
{
294+
long start_col_nr; /* starting column number */
295+
long end_col_nr; /* ending column number */
296+
} line;
297+
long value; /* value if sorting by integer */
298+
#ifdef FEAT_FLOAT
299+
float_T value_flt; /* value if sorting by float */
300+
#endif
301+
} st_u;
290302
} sorti_T;
291303

292304
static int
@@ -319,19 +331,24 @@ sort_compare(s1, s2)
319331
/* When sorting numbers "start_col_nr" is the number, not the column
320332
* number. */
321333
if (sort_nr)
322-
result = l1.start_col_nr == l2.start_col_nr ? 0
323-
: l1.start_col_nr > l2.start_col_nr ? 1 : -1;
334+
result = l1.st_u.value == l2.st_u.value ? 0
335+
: l1.st_u.value > l2.st_u.value ? 1 : -1;
336+
#ifdef FEAT_FLOAT
337+
else if (sort_flt)
338+
result = l1.st_u.value_flt == l2.st_u.value_flt ? 0
339+
: l1.st_u.value_flt > l2.st_u.value_flt ? 1 : -1;
340+
#endif
324341
else
325342
{
326343
/* We need to copy one line into "sortbuf1", because there is no
327344
* guarantee that the first pointer becomes invalid when obtaining the
328345
* second one. */
329-
STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.start_col_nr,
330-
l1.end_col_nr - l1.start_col_nr + 1);
331-
sortbuf1[l1.end_col_nr - l1.start_col_nr] = 0;
332-
STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.start_col_nr,
333-
l2.end_col_nr - l2.start_col_nr + 1);
334-
sortbuf2[l2.end_col_nr - l2.start_col_nr] = 0;
346+
STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.st_u.line.start_col_nr,
347+
l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr + 1);
348+
sortbuf1[l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr] = 0;
349+
STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.st_u.line.start_col_nr,
350+
l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr + 1);
351+
sortbuf2[l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr] = 0;
335352

336353
result = sort_ic ? STRICMP(sortbuf1, sortbuf2)
337354
: STRCMP(sortbuf1, sortbuf2);
@@ -382,6 +399,9 @@ ex_sort(eap)
382399
goto sortend;
383400

384401
sort_abort = sort_ic = sort_rx = sort_nr = 0;
402+
#ifdef FEAT_FLOAT
403+
sort_flt = 0;
404+
#endif
385405

386406
for (p = eap->arg; *p != NUL; ++p)
387407
{
@@ -393,9 +413,16 @@ ex_sort(eap)
393413
sort_rx = TRUE;
394414
else if (*p == 'n')
395415
{
396-
sort_nr = 2;
416+
sort_nr = 1;
397417
++format_found;
398418
}
419+
#ifdef FEAT_FLOAT
420+
else if (*p == 'f')
421+
{
422+
sort_flt = 1;
423+
++format_found;
424+
}
425+
#endif
399426
else if (*p == 'b')
400427
{
401428
sort_what = STR2NR_BIN + STR2NR_FORCE;
@@ -460,7 +487,8 @@ ex_sort(eap)
460487
goto sortend;
461488
}
462489

463-
/* From here on "sort_nr" is used as a flag for any number sorting. */
490+
/* From here on "sort_nr" is used as a flag for any integer number
491+
* sorting. */
464492
sort_nr += sort_what;
465493

466494
/*
@@ -494,7 +522,7 @@ ex_sort(eap)
494522
if (regmatch.regprog != NULL)
495523
end_col = 0;
496524

497-
if (sort_nr)
525+
if (sort_nr || sort_flt)
498526
{
499527
/* Make sure vim_str2nr doesn't read any digits past the end
500528
* of the match, by temporarily terminating the string there */
@@ -503,27 +531,45 @@ ex_sort(eap)
503531
*s2 = NUL;
504532
/* Sorting on number: Store the number itself. */
505533
p = s + start_col;
506-
if (sort_what & STR2NR_HEX)
507-
s = skiptohex(p);
508-
else if (sort_what & STR2NR_BIN)
509-
s = skiptobin(p);
510-
else
511-
s = skiptodigit(p);
512-
if (s > p && s[-1] == '-')
513-
--s; /* include preceding negative sign */
514-
if (*s == NUL)
515-
/* empty line should sort before any number */
516-
nrs[lnum - eap->line1].start_col_nr = -MAXLNUM;
534+
if (sort_nr)
535+
{
536+
if (sort_what & STR2NR_HEX)
537+
s = skiptohex(p);
538+
else if (sort_what & STR2NR_BIN)
539+
s = skiptobin(p);
540+
else
541+
s = skiptodigit(p);
542+
if (s > p && s[-1] == '-')
543+
--s; /* include preceding negative sign */
544+
if (*s == NUL)
545+
/* empty line should sort before any number */
546+
nrs[lnum - eap->line1].st_u.value = -MAXLNUM;
547+
else
548+
vim_str2nr(s, NULL, NULL, sort_what,
549+
&nrs[lnum - eap->line1].st_u.value, NULL, 0);
550+
}
551+
#ifdef FEAT_FLOAT
517552
else
518-
vim_str2nr(s, NULL, NULL, sort_what,
519-
&nrs[lnum - eap->line1].start_col_nr, NULL, 0);
553+
{
554+
s = skipwhite(p);
555+
if (*s == '+')
556+
s = skipwhite(s + 1);
557+
558+
if (*s == NUL)
559+
/* empty line should sort before any number */
560+
nrs[lnum - eap->line1].st_u.value_flt = -DBL_MAX;
561+
else
562+
nrs[lnum - eap->line1].st_u.value_flt =
563+
strtod((char *)s, NULL);
564+
}
565+
#endif
520566
*s2 = c;
521567
}
522568
else
523569
{
524570
/* Store the column to sort at. */
525-
nrs[lnum - eap->line1].start_col_nr = start_col;
526-
nrs[lnum - eap->line1].end_col_nr = end_col;
571+
nrs[lnum - eap->line1].st_u.line.start_col_nr = start_col;
572+
nrs[lnum - eap->line1].st_u.line.end_col_nr = end_col;
527573
}
528574

529575
nrs[lnum - eap->line1].lnum = lnum;

src/testdir/test57.in

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ STARTTEST
3232
:/^t27:/+1,/^t28/-1sort no
3333
:/^t28:/+1,/^t29/-1sort b
3434
:/^t29:/+1,/^t30/-1sort b
35+
:/^t30:/+1,/^t31/-1sort f
3536
:/^t01:/,$wq! test.out
3637
ENDTEST
3738

@@ -496,9 +497,9 @@ c321d
496497
b322b
497498
b321
498499
b321b
499-
t28: binary
500500

501501

502+
t28: binary
502503
0b111000
503504
0b101100
504505
0b101001
@@ -513,9 +514,9 @@ t28: binary
513514
0b100010
514515
0b100100
515516
0b100010
516-
t29: binary with leading characters
517517

518518

519+
t29: binary with leading characters
519520
0b100010
520521
0b010000
521522
0b101001
@@ -530,4 +531,15 @@ ab0b100000
530531
0b101010
531532
0b000000
532533
b0b111000
533-
t30: done
534+
535+
536+
t30: float
537+
1.234
538+
0.88
539+
123.456
540+
1.15e-6
541+
-1.1e3
542+
-1.01e3
543+
544+
545+
t31: done

src/testdir/test57.ok

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,8 @@ c321d
453453
b322b
454454
b321
455455
b321b
456+
457+
456458
t28: binary
457459

458460

@@ -487,4 +489,13 @@ a0b101001
487489
0b101010
488490
b0b101100
489491
b0b111000
490-
t30: done
492+
t30: float
493+
494+
495+
-1.1e3
496+
-1.01e3
497+
1.15e-6
498+
0.88
499+
1.234
500+
123.456
501+
t31: done

0 commit comments

Comments
 (0)