From b8060fe862f684b591f9ac679eac5b2594d6c5a0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 19 Jan 2016 22:29:28 +0100 Subject: [PATCH 1/2] patch 7.4.1142 Problem: Cannot define keyword characters for a syntax file. Solution: Add the ":syn iskeyword" command. (Christian Brabandt) --- runtime/doc/options.txt | 4 +- runtime/doc/syntax.txt | 29 ++++++++++- src/buffer.c | 1 + src/option.c | 2 + src/structs.h | 2 + src/syntax.c | 97 ++++++++++++++++++++++++++++++++++++- src/testdir/Make_all.mak | 1 + src/testdir/test_syntax.vim | 67 +++++++++++++++++++++++++ src/version.c | 2 + 9 files changed, 202 insertions(+), 3 deletions(-) create mode 100644 src/testdir/test_syntax.vim diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 8cf2aa7bd4..a5e6fff457 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 7.4. Last change: 2016 Jan 09 +*options.txt* For Vim version 7.4. Last change: 2016 Jan 19 VIM REFERENCE MANUAL by Bram Moolenaar @@ -4489,6 +4489,8 @@ A jump table for the options with a short description can be found at |Q_op|. '*', '"' and '|' (so that CTRL-] on a command finds the help for that command). When the 'lisp' option is on the '-' character is always included. + This option also influences syntax highlighting, unless the syntax + uses |:syn-iskeyword|. NOTE: This option is set to the Vi default value when 'compatible' is set and to the Vim default value when 'compatible' is reset. diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index 6886422cea..cf91e88bd5 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -1,4 +1,4 @@ -*syntax.txt* For Vim version 7.4. Last change: 2015 Dec 19 +*syntax.txt* For Vim version 7.4. Last change: 2016 Jan 19 VIM REFERENCE MANUAL by Bram Moolenaar @@ -3438,6 +3438,32 @@ SPELL CHECKING *:syn-spell* To activate spell checking the 'spell' option must be set. +SYNTAX ISKEYWORD SETTING *:syn-iskeyword* + +:sy[ntax] iskeyword [clear | {option}] + This defines the keyword characters. It's like the 'iskeyword' option + for but only applies to syntax highlighting. + + clear: Syntax specific iskeyword setting is disabled and the + buffer-local 'iskeyword' setting is used. + {option} Set the syntax 'iskeyword' option to a new value. + + Example: > + :syntax iskeyword @,48-57,192-255,$,_ +< + This would set the syntax specific iskeyword option to include all + alphabetic characters, plus the numeric characters, all accented + characters and also includes the "_" and the "$". + + If no argument is given, the current value will be output. + + Setting this option influences what |/\k| matches in syntax patterns + and also determines where |:syn-keywords| will be checked for a new + match. + + It is recommended when writing syntax files, to use this command + to the correct value for the specific syntax language and not change + the 'iskeyword' option. DEFINING KEYWORDS *:syn-keyword* @@ -3469,6 +3495,7 @@ DEFINING KEYWORDS *:syn-keyword* isn't, the keyword will never be recognized. Multi-byte characters can also be used. These do not have to be in 'iskeyword'. + See |:syn-iskeyword| for defining syntax specific iskeyword settings. A keyword always has higher priority than a match or region, the keyword is used if more than one item matches. Keywords do not nest diff --git a/src/buffer.c b/src/buffer.c index fd94a27449..8986ac4e22 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1955,6 +1955,7 @@ free_buf_options(buf, free_p_ff) clear_string_option(&buf->b_p_nf); #ifdef FEAT_SYN_HL clear_string_option(&buf->b_p_syn); + clear_string_option(&buf->b_s.b_syn_isk); #endif #ifdef FEAT_SPELL clear_string_option(&buf->b_s.b_p_spc); diff --git a/src/option.c b/src/option.c index bc88d45547..cd7064c4f1 100644 --- a/src/option.c +++ b/src/option.c @@ -5494,6 +5494,7 @@ check_buf_options(buf) #endif #ifdef FEAT_SYN_HL check_string_option(&buf->b_p_syn); + check_string_option(&buf->b_s.b_syn_isk); #endif #ifdef FEAT_SPELL check_string_option(&buf->b_s.b_p_spc); @@ -10821,6 +10822,7 @@ buf_copy_options(buf, flags) /* Don't copy 'syntax', it must be set */ buf->b_p_syn = empty_option; buf->b_p_smc = p_smc; + buf->b_s.b_syn_isk = empty_option; #endif #ifdef FEAT_SPELL buf->b_s.b_p_spc = vim_strsave(p_spc); diff --git a/src/structs.h b/src/structs.h index 5c65cc65a4..143d46dfa9 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1362,6 +1362,8 @@ typedef struct { #if !defined(FEAT_SYN_HL) && !defined(FEAT_SPELL) int dummy; #endif + char_u b_syn_chartab[32]; /* syntax iskeyword option */ + char_u *b_syn_isk; /* iskeyword option */ } synblock_T; diff --git a/src/syntax.c b/src/syntax.c index 6e1a5e24a1..d9f0ffc9f1 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -376,6 +376,8 @@ static int current_line_id = 0; /* unique number for current line */ #define CUR_STATE(idx) ((stateitem_T *)(current_state.ga_data))[idx] static void syn_sync __ARGS((win_T *wp, linenr_T lnum, synstate_T *last_valid)); +static void save_chartab(char_u *chartab); +static void restore_chartab(char_u *chartab); static int syn_match_linecont __ARGS((linenr_T lnum)); static void syn_start_line __ARGS((void)); static void syn_update_ends __ARGS((int startofline)); @@ -458,6 +460,7 @@ static void add_keyword __ARGS((char_u *name, int id, int flags, short *cont_in_ static char_u *get_group_name __ARGS((char_u *arg, char_u **name_end)); static char_u *get_syn_options __ARGS((char_u *arg, syn_opt_arg_T *opt, int *conceal_char)); static void syn_cmd_include __ARGS((exarg_T *eap, int syncing)); +static void syn_cmd_iskeyword __ARGS((exarg_T *eap, int syncing)); static void syn_cmd_keyword __ARGS((exarg_T *eap, int syncing)); static void syn_cmd_match __ARGS((exarg_T *eap, int syncing)); static void syn_cmd_region __ARGS((exarg_T *eap, int syncing)); @@ -984,6 +987,24 @@ syn_sync(wp, start_lnum, last_valid) validate_current_state(); } + static void +save_chartab(char_u *chartab) +{ + if (syn_block->b_syn_isk != empty_option) + { + mch_memmove(chartab, syn_buf->b_chartab, (size_t)32); + mch_memmove(syn_buf->b_chartab, syn_win->w_s->b_syn_chartab, + (size_t)32); + } +} + + static void +restore_chartab(char_u *chartab) +{ + if (syn_win->w_s->b_syn_isk != empty_option) + mch_memmove(syn_buf->b_chartab, chartab, (size_t)32); +} + /* * Return TRUE if the line-continuation pattern matches in line "lnum". */ @@ -993,14 +1014,18 @@ syn_match_linecont(lnum) { regmmatch_T regmatch; int r; + char_u buf_chartab[32]; /* chartab array for syn iskyeyword */ if (syn_block->b_syn_linecont_prog != NULL) { + /* use syntax iskeyword option */ + save_chartab(buf_chartab); regmatch.rmm_ic = syn_block->b_syn_linecont_ic; regmatch.regprog = syn_block->b_syn_linecont_prog; r = syn_regexec(®match, lnum, (colnr_T)0, IF_SYN_TIME(&syn_block->b_syn_linecont_time)); syn_block->b_syn_linecont_prog = regmatch.regprog; + restore_chartab(buf_chartab); return r; } return FALSE; @@ -1891,6 +1916,7 @@ syn_current_attr(syncing, displaying, can_spell, keep_state) lpos_T pos; int lc_col; reg_extmatch_T *cur_extmatch = NULL; + char_u buf_chartab[32]; /* chartab array for syn iskyeyword */ char_u *line; /* current line. NOTE: becomes invalid after looking for a pattern match! */ @@ -1945,6 +1971,9 @@ syn_current_attr(syncing, displaying, can_spell, keep_state) * avoid matching the same item in the same position twice. */ ga_init2(&zero_width_next_ga, (int)sizeof(int), 10); + /* use syntax iskeyword option */ + save_chartab(buf_chartab); + /* * Repeat matching keywords and patterns, to find contained items at the * same column. This stops when there are no extra matches at the current @@ -1956,6 +1985,7 @@ syn_current_attr(syncing, displaying, can_spell, keep_state) keep_next_list = FALSE; syn_id = 0; + /* * 1. Check for a current state. * Only when there is no current state, or if the current state may @@ -2309,6 +2339,8 @@ syn_current_attr(syncing, displaying, can_spell, keep_state) } while (found_match); + restore_chartab(buf_chartab); + /* * Use attributes from the current state, if within its highlighting. * If not, use attributes from the current-but-one state, etc. @@ -2915,6 +2947,7 @@ find_endpos(idx, startpos, m_endpos, hl_endpos, flagsp, end_endpos, lpos_T pos; char_u *line; int had_match = FALSE; + char_u buf_chartab[32]; /* chartab array for syn option iskyeyword */ /* just in case we are invoked for a keyword */ if (idx < 0) @@ -2961,6 +2994,10 @@ find_endpos(idx, startpos, m_endpos, hl_endpos, flagsp, end_endpos, matchcol = startpos->col; /* start looking for a match at sstart */ start_idx = idx; /* remember the first END pattern. */ best_regmatch.startpos[0].col = 0; /* avoid compiler warning */ + + /* use syntax iskeyword option */ + save_chartab(buf_chartab); + for (;;) { /* @@ -3117,6 +3154,8 @@ find_endpos(idx, startpos, m_endpos, hl_endpos, flagsp, end_endpos, if (!had_match) m_endpos->lnum = 0; + restore_chartab(buf_chartab); + /* Remove external matches. */ unref_extmatch(re_extmatch_in); re_extmatch_in = NULL; @@ -3481,6 +3520,57 @@ syn_cmd_spell(eap, syncing) redraw_win_later(curwin, NOT_VALID); } +/* + * Handle ":syntax iskeyword" command. + */ + static void +syn_cmd_iskeyword(eap, syncing) + exarg_T *eap; + int syncing UNUSED; +{ + char_u *arg = eap->arg; + char_u save_chartab[32]; + char_u *save_isk; + + if (eap->skip) + return; + + arg = skipwhite(arg); + if (*arg == NUL) + { + MSG_PUTS("\n"); + MSG_PUTS(_("syntax iskeyword ")); + if (curwin->w_s->b_syn_isk != empty_option) + msg_outtrans(curwin->w_s->b_syn_isk); + else + msg_outtrans((char_u *)"not set"); + } + else + { + if (STRNICMP(arg, "clear", 5) == 0) + { + mch_memmove(curwin->w_s->b_syn_chartab, curbuf->b_chartab, + (size_t)32); + clear_string_option(&curwin->w_s->b_syn_isk); + } + else + { + mch_memmove(save_chartab, curbuf->b_chartab, (size_t)32); + save_isk = curbuf->b_p_isk; + curbuf->b_p_isk = vim_strsave(arg); + + buf_init_chartab(curbuf, FALSE); + mch_memmove(curwin->w_s->b_syn_chartab, curbuf->b_chartab, + (size_t)32); + mch_memmove(curbuf->b_chartab, save_chartab, (size_t)32); + clear_string_option(&curwin->w_s->b_syn_isk); + curwin->w_s->b_syn_isk = curbuf->b_p_isk; + curbuf->b_p_isk = save_isk; + } + } + redraw_win_later(curwin, NOT_VALID); +} + /* * Clear all syntax info for one buffer. */ @@ -3523,6 +3613,7 @@ syntax_clear(block) #ifdef FEAT_FOLDING block->b_syn_folditems = 0; #endif + clear_string_option(&block->b_syn_isk); /* free the stored states */ syn_stack_free_all(block); @@ -3569,8 +3660,9 @@ syntax_sync_clear() curwin->w_s->b_syn_linecont_prog = NULL; vim_free(curwin->w_s->b_syn_linecont_pat); curwin->w_s->b_syn_linecont_pat = NULL; + clear_string_option(&curwin->w_s->b_syn_isk); - syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */ + syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */ } /* @@ -3777,6 +3869,7 @@ syn_cmd_reset(eap, syncing) eap->nextcmd = check_nextcmd(eap->arg); if (!eap->skip) { + clear_string_option(&curwin->w_s->b_syn_isk); set_internal_string_var((char_u *)"syntax_cmd", (char_u *)"reset"); do_cmdline_cmd((char_u *)"runtime! syntax/syncolor.vim"); do_unlet((char_u *)"g:syntax_cmd", TRUE); @@ -6253,6 +6346,7 @@ static struct subcommand subcommands[] = {"conceal", syn_cmd_conceal}, {"enable", syn_cmd_enable}, {"include", syn_cmd_include}, + {"iskeyword", syn_cmd_iskeyword}, {"keyword", syn_cmd_keyword}, {"list", syn_cmd_list}, {"manual", syn_cmd_manual}, @@ -6331,6 +6425,7 @@ ex_ownsyntax(eap) clear_string_option(&curwin->w_s->b_p_spf); clear_string_option(&curwin->w_s->b_p_spl); #endif + clear_string_option(&curwin->w_s->b_syn_isk); } /* save value of b:current_syntax */ diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index 526a43534b..d02e8d2b40 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -175,6 +175,7 @@ NEW_TESTS = test_arglist.res \ test_increment.res \ test_perl.res \ test_quickfix.res \ + test_syntax.res \ test_viminfo.res \ test_viml.res \ test_alot.res diff --git a/src/testdir/test_syntax.vim b/src/testdir/test_syntax.vim new file mode 100644 index 0000000000..297e8359a3 --- /dev/null +++ b/src/testdir/test_syntax.vim @@ -0,0 +1,67 @@ +" Test for syntax and syntax iskeyword option + +if !has("syntax") + finish +endif + +func GetSyntaxItem(pat) + let c = '' + let a = ['a', getreg('a'), getregtype('a')] + 0 + redraw! + call search(a:pat, 'W') + let synid = synID(line('.'), col('.'), 1) + while synid == synID(line('.'), col('.'), 1) + norm! v"ay + " stop at whitespace + if @a =~# '\s' + break + endif + let c .= @a + norm! l + endw + call call('setreg', a) + 0 + return c +endfunc + +func Test_syn_iskeyword() + new + call setline(1, [ + \ 'CREATE TABLE FOOBAR(', + \ ' DLTD_BY VARCHAR2(100)', + \ ');', + \ '']) + + syntax on + set ft=sql + syn match SYN /C\k\+\>/ + hi link SYN ErrorMsg + call assert_equal('DLTD_BY', GetSyntaxItem('DLTD')) + /\/:norm! ygn + call assert_equal('DLTD_BY', @0) + redir @c + syn iskeyword + redir END + call assert_equal("\nsyntax iskeyword not set", @c) + + syn iskeyword @,48-57,_,192-255 + redir @c + syn iskeyword + redir END + call assert_equal("\nsyntax iskeyword @,48-57,_,192-255", @c) + + setlocal isk-=_ + call assert_equal('DLTD_BY', GetSyntaxItem('DLTD')) + /\/:norm! ygn + let b2=@0 + call assert_equal('DLTD', @0) + + syn iskeyword clear + redir @c + syn iskeyword + redir END + call assert_equal("\nsyntax iskeyword not set", @c) + + quit! +endfunc diff --git a/src/version.c b/src/version.c index 3ea9a1557b..20305c8144 100644 --- a/src/version.c +++ b/src/version.c @@ -741,6 +741,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1142, /**/ 1141, /**/ From f7edf40448a09e04eec3bd05e043f7fea93b07c9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 19 Jan 2016 23:36:15 +0100 Subject: [PATCH 2/2] 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(). --- runtime/doc/change.txt | 20 ++++--- src/eval.c | 60 +++++++++++++++++++++ src/ex_cmds.c | 110 +++++++++++++++++++++++++++----------- src/testdir/test57.in | 22 ++++++-- src/testdir/test57.ok | 13 ++++- src/testdir/test_sort.vim | 4 ++ src/version.c | 2 + 7 files changed, 187 insertions(+), 44 deletions(-) diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index 6dd20ad8b2..ac1b8b6862 100644 --- 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 command. The sorting function can be 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. diff --git a/src/eval.c b/src/eval.c index b42ecc78f1..de30f712ee 100644 --- 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. diff --git a/src/ex_cmds.c b/src/ex_cmds.c index bb6daa8ca0..11c3cf48ba 100644 --- 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_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 */ +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; diff --git a/src/testdir/test57.in b/src/testdir/test57.in index 0bb95adc34..5f235358b8 100644 --- 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 - - 0b111000 0b101100 0b101001 @@ -513,9 +514,9 @@ t28: binary 0b100010 0b100100 0b100010 + + 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 diff --git a/src/testdir/test57.ok b/src/testdir/test57.ok index 2ac5e59e27..452acf1fc4 100644 --- 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 diff --git a/src/testdir/test_sort.vim b/src/testdir/test_sort.vim index 30dd167cd6..32ad7f8ad5 100644 --- 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 diff --git a/src/version.c b/src/version.c index 20305c8144..bd2c8f6ac1 100644 --- a/src/version.c +++ b/src/version.c @@ -741,6 +741,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1143, /**/ 1142, /**/