Sorting by floating point values in Vim

350 views
Skip to first unread message

Alex

unread,
Oct 30, 2010, 8:00:17 PM10/30/10
to vim_dev
Hi all,

I've extended :sort command in vim - now it can sort by floating point
values as well as dec/hex/oct. Submitting the change for review.

Kind regards,

Alex

>>>>>>>>>>>>>>>> BEGIN OF HG EXPORT
# HG changeset patch
# User Alex Jakushev <alex.j...@gmail.com>
# Date 1288482264 -3600
# Node ID a31735077986cf251235d6a007c6552acf5e77d6
# Parent b6ba81f1258fc53fcb030868229971e239d43aee
Help updated for "sort f"

diff -r b6ba81f1258f -r a31735077986 runtime/doc/change.txt
--- a/runtime/doc/change.txt Sun Oct 31 00:17:20 2010 +0100
+++ b/runtime/doc/change.txt Sun Oct 31 00:44:24 2010 +0100
@@ -1585,7 +1585,7 @@
found here: |sort()|.

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

@@ -1605,6 +1605,14 @@
With [o] sorting is done on the first octal number in
the line (after or inside a {pattern} match).

+ 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.
+
+ Options [n][x][o][f] are mutually exclusive.
+
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
# HG changeset patch
# User Alex Jakushev <alex.j...@gmail.com>
# Date 1288480640 -3600
# Node ID b6ba81f1258fc53fcb030868229971e239d43aee
# Parent df6b12c84b2359415cd987c016f5de135c680100
Support of sorting by floating point numbers

diff -r df6b12c84b23 -r b6ba81f1258f src/ex_cmds.c
--- a/src/ex_cmds.c Wed Oct 27 18:36:36 2010 +0200
+++ b/src/ex_cmds.c Sun Oct 31 00:17:20 2010 +0100
@@ -17,6 +17,9 @@

#include "vim.h"
#include "version.h"
+#ifdef FEAT_FLOAT
+#include <float.h>
+#endif

#ifdef FEAT_EX_EXTRA
static int linelen __ARGS((int *has_tab));
@@ -282,6 +285,9 @@
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 */

@@ -289,8 +295,17 @@
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 number (n/o/x)
+#ifdef FEAT_FLOAT
+ float_T value_flt; // value if sorting by float
+#endif
+ } st_u;
} sorti_T;

static int
@@ -320,22 +335,25 @@
if (got_int)
sort_abort = TRUE;

- /* 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);
@@ -371,6 +389,7 @@
colnr_T end_col;
int sort_oct; /* sort on octal number */
int sort_hex; /* sort on hex number */
+ int sort_special_all; /* sort on any possible numeric value */

/* Sorting one line is really quick! */
if (count <= 1)
@@ -386,6 +405,9 @@
goto sortend;

sort_abort = sort_ic = sort_rx = sort_nr = sort_oct = sort_hex =
0;
+#ifdef FEAT_FLOAT
+ sort_flt = 0;
+#endif

for (p = eap->arg; *p != NUL; ++p)
{
@@ -401,6 +423,10 @@
sort_oct = 2;
else if (*p == 'x')
sort_hex = 2;
+#ifdef FEAT_FLOAT
+ else if (*p == 'f')
+ sort_flt = 2;
+#endif
else if (*p == 'u')
unique = TRUE;
else if (*p == '"') /* comment start */
@@ -436,14 +462,19 @@
}
}

- /* Can only have one of 'n', 'o' and 'x'. */
- if (sort_nr + sort_oct + sort_hex > 2)
+ sort_special_all = sort_nr + sort_oct + sort_hex;
+#ifdef FEAT_FLOAT
+ sort_special_all += sort_flt;
+#endif
+
+ /* Can only have one of 'f', 'n', 'o' and 'x'. */
+ if (sort_special_all > 2)
{
EMSG(_(e_invarg));
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 *int* number
sorting. */
sort_nr += sort_oct + sort_hex;

/*
@@ -477,7 +508,7 @@
if (regmatch.regprog != NULL)
end_col = 0;

- if (sort_nr)
+ if (sort_special_all)
{
/* Make sure vim_str2nr doesn't read any digits past the end
* of the match, by temporarily terminating the string there */
@@ -486,25 +517,44 @@
*s2 = NUL;
/* Sorting on number: Store the number itself. */
p = s + start_col;
- if (sort_hex)
- s = skiptohex(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].start_col_nr = -MAXLNUM;
- else
- vim_str2nr(s, NULL, NULL, sort_oct, sort_hex,
- &nrs[lnum - eap->line1].start_col_nr, NULL);
+
+ if (sort_nr)
+ {
+ if (sort_hex)
+ s = skiptohex(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_oct, sort_hex,
+ &nrs[lnum - eap->line1].st_u.value, NULL);
+ }
+#ifdef FEAT_FLOAT
+ else if (sort_flt)
+ {
+ 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 = atof(s);
+ }
+#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;
>>>>>>>>>>>>>>>> END OF HG EXPORT

Bram Moolenaar

unread,
Oct 31, 2010, 8:59:04 AM10/31/10
to Alex, vim_dev

Alex Jakushev wrote:

> I've extended :sort command in vim - now it can sort by floating point
> values as well as dec/hex/oct. Submitting the change for review.

Looks OK.

It would be useful to have a test for :sort. Especially now that it
becomes more complicated.

--
MESKIMEN'S LAW
There's never time to do it right, but always time to do it over.

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ download, build and distribute -- http://www.A-A-P.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

Alex

unread,
Oct 31, 2010, 10:53:21 AM10/31/10
to vim_dev
I will post one later.

Alex

On Oct 31, 12:59 pm, Bram Moolenaar <B...@Moolenaar.net> wrote:
> Alex Jakushev wrote:
> > I've extended :sort command in vim - now it can sort by floating point
> > values as well as dec/hex/oct. Submitting the change for review.
>
> Looks OK.
>
> It would be useful to have a test for :sort.  Especially now that it
> becomes more complicated.
>
> --
> MESKIMEN'S LAW
>     There's never time to do it right, but always time to do it over.
>
>  /// Bram Moolenaar -- B...@Moolenaar.net --http://www.Moolenaar.net  \\\
> ///        sponsor Vim, vote for features --http://www.Vim.org/sponsor/\\\
> \\\        download, build and distribute --http://www.A-A-P.org       ///

Sebastian Gsänger

unread,
Dec 5, 2015, 12:38:06 PM12/5/15
to vim_dev
Hi,

this patch seems to have been forgotten, although it still seems to work.
Could it still be merged, or is a test needed? How would this test need to look like?

Thanks,
Sebastian
Reply all
Reply to author
Forward
0 new messages