diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-11-01 13:57:44 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-11-01 13:57:44 +0100 |
commit | 55e29611d20bca14fa5efc61385bc8a6b7acd9e2 (patch) | |
tree | ab93029caf0fe68c139d7b7d02c67fe11abf02b7 /src | |
parent | 963734e316bd17dd7290abcac28b875435d06381 (diff) | |
download | vim-git-55e29611d20bca14fa5efc61385bc8a6b7acd9e2.tar.gz |
patch 8.2.1933: cannot sort using locale orderingv8.2.1933
Problem: Cannot sort using locale ordering.
Solution: Add a flag for :sort and sort() to use the locale. (Dominique
Pellé, closes #7237)
Diffstat (limited to 'src')
-rw-r--r-- | src/ex_cmds.c | 19 | ||||
-rw-r--r-- | src/list.c | 13 | ||||
-rw-r--r-- | src/testdir/test_sort.vim | 70 | ||||
-rw-r--r-- | src/version.c | 2 |
4 files changed, 95 insertions, 9 deletions
diff --git a/src/ex_cmds.c b/src/ex_cmds.c index 8ddf238d3..de4b806b2 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -277,6 +277,7 @@ linelen(int *has_tab) static char_u *sortbuf1; static char_u *sortbuf2; +static int sort_lc; // sort using locale static int sort_ic; // ignore case static int sort_nr; // sort on number static int sort_rx; // sort on regex instead of skipping it @@ -307,7 +308,13 @@ typedef struct } st_u; } sorti_T; -static int sort_compare(const void *s1, const void *s2); + static int +string_compare(const void *s1, const void *s2) +{ + if (sort_lc) + return strcoll((char *)s1, (char *)s2); + return sort_ic ? STRICMP(s1, s2) : STRCMP(s1, s2); +} static int sort_compare(const void *s1, const void *s2) @@ -350,8 +357,7 @@ sort_compare(const void *s1, const void *s2) 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); + result = string_compare(sortbuf1, sortbuf2); } // If two lines have the same value, preserve the original line order. @@ -398,7 +404,7 @@ ex_sort(exarg_T *eap) if (nrs == NULL) goto sortend; - sort_abort = sort_ic = sort_rx = sort_nr = 0; + sort_abort = sort_ic = sort_lc = sort_rx = sort_nr = 0; #ifdef FEAT_FLOAT sort_flt = 0; #endif @@ -409,6 +415,8 @@ ex_sort(exarg_T *eap) ; else if (*p == 'i') sort_ic = TRUE; + else if (*p == 'l') + sort_lc = TRUE; else if (*p == 'r') sort_rx = TRUE; else if (*p == 'n') @@ -614,8 +622,7 @@ ex_sort(exarg_T *eap) change_occurred = TRUE; s = ml_get(get_lnum); - if (!unique || i == 0 - || (sort_ic ? STRICMP(s, sortbuf1) : STRCMP(s, sortbuf1)) != 0) + if (!unique || i == 0 || string_compare(s, sortbuf1) != 0) { // Copy the line into a buffer, it may become invalid in // ml_append(). And it's needed for "unique". diff --git a/src/list.c b/src/list.c index 62c571c71..1da4f3d0c 100644 --- a/src/list.c +++ b/src/list.c @@ -1516,6 +1516,7 @@ typedef struct typedef struct { int item_compare_ic; + int item_compare_lc; int item_compare_numeric; int item_compare_numbers; #ifdef FEAT_FLOAT @@ -1594,10 +1595,10 @@ item_compare(const void *s1, const void *s2) p2 = (char_u *)""; if (!sortinfo->item_compare_numeric) { - if (sortinfo->item_compare_ic) - res = STRICMP(p1, p2); + if (sortinfo->item_compare_lc) + res = strcoll((char *)p1, (char *)p2); else - res = STRCMP(p1, p2); + res = sortinfo->item_compare_ic ? STRICMP(p1, p2): STRCMP(p1, p2); } else { @@ -1706,6 +1707,7 @@ do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort) goto theend; // short list sorts pretty quickly info.item_compare_ic = FALSE; + info.item_compare_lc = FALSE; info.item_compare_numeric = FALSE; info.item_compare_numbers = FALSE; #ifdef FEAT_FLOAT @@ -1773,6 +1775,11 @@ do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort) info.item_compare_func = NULL; info.item_compare_ic = TRUE; } + else if (STRCMP(info.item_compare_func, "l") == 0) + { + info.item_compare_func = NULL; + info.item_compare_lc = TRUE; + } } } diff --git a/src/testdir/test_sort.vim b/src/testdir/test_sort.vim index d76132ee5..93190a940 100644 --- a/src/testdir/test_sort.vim +++ b/src/testdir/test_sort.vim @@ -15,6 +15,25 @@ func Test_sort_strings() " numbers compared as strings call assert_equal([1, 2, 3], sort([3, 2, 1])) call assert_equal([13, 28, 3], sort([3, 28, 13])) + + call assert_equal(['A', 'O', 'P', 'a', 'o', 'p', 'Ä', 'Ô', 'ä', 'ô', 'œ', 'œ'], + \ sort(['A', 'O', 'P', 'a', 'o', 'p', 'Ä', 'Ô', 'ä', 'ô', 'œ', 'œ'])) + + call assert_equal(['A', 'a', 'o', 'O', 'p', 'P', 'Ä', 'Ô', 'ä', 'ô', 'œ', 'œ'], + \ sort(['A', 'a', 'o', 'O', 'œ', 'œ', 'p', 'P', 'Ä', 'ä', 'ô', 'Ô'], 'i')) + + let lc = execute('language collate') + " With the following locales, the accentuated letters are ordered + " similarly to the non-accentuated letters... + if lc =~? '"\(en\|es\|de\|fr\|it\|nl\).*\.utf-\?8"' + call assert_equal(['a', 'A', 'ä', 'Ä', 'o', 'O', 'ô', 'Ô', 'œ', 'œ', 'p', 'P'], + \ sort(['A', 'a', 'o', 'O', 'œ', 'œ', 'p', 'P', 'Ä', 'ä', 'ô', 'Ô'], 'l')) + " ... whereas with a Swedish locale, the accentuated letters are ordered + " after Z. + elseif lc =~? '"sv.*utf-\?8"' + call assert_equal(['a', 'A', 'o', 'O', 'p', 'P', 'ä', 'Ä', 'œ', 'œ', 'ô', 'Ô'], + \ sort(['A', 'a', 'o', 'O', 'œ', 'œ', 'p', 'P', 'Ä', 'ä', 'ô', 'Ô'], 'l')) + endif endfunc func Test_sort_numeric() @@ -1204,6 +1223,57 @@ func Test_sort_cmd() \ }, \ ] + " With the following locales, the accentuated letters are ordered + " similarly to the non-accentuated letters... + let lc = execute('language collate') + if lc =~? '"\(en\|es\|de\|fr\|it\|nl\).*\.utf-\?8"' + let tests += [ + \ { + \ 'name' : 'sort with locale', + \ 'cmd' : '%sort l', + \ 'input' : [ + \ 'A', + \ 'E', + \ 'O', + \ 'À', + \ 'È', + \ 'É', + \ 'Ô', + \ 'Œ', + \ 'Z', + \ 'a', + \ 'e', + \ 'o', + \ 'à', + \ 'è', + \ 'é', + \ 'ô', + \ 'œ', + \ 'z' + \ ], + \ 'expected' : [ + \ 'a', + \ 'A', + \ 'à', + \ 'À', + \ 'e', + \ 'E', + \ 'é', + \ 'É', + \ 'è', + \ 'È', + \ 'o', + \ 'O', + \ 'ô', + \ 'Ô', + \ 'œ', + \ 'Œ', + \ 'z', + \ 'Z' + \ ] + \ }, + \ ] + endif if has('float') let tests += [ \ { diff --git a/src/version.c b/src/version.c index 11d45607f..ca98d241c 100644 --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1933, +/**/ 1932, /**/ 1931, |