| To: vim_dev@googlegroups.com |
| Subject: Patch 7.4.218 |
| Fcc: outbox |
| From: Bram Moolenaar <Bram@moolenaar.net> |
| Mime-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| |
| Patch 7.4.218 |
| Problem: It's not easy to remove duplicates from a list. |
| Solution: Add the uniq() function. (LCD) |
| Files: runtime/doc/change.txt, runtime/doc/eval.txt, |
| runtime/doc/usr_41.txt, runtime/doc/version7.txt, src/eval.c, |
| src/testdir/test55.in, src/testdir/test55.ok |
| |
| |
| |
| |
| |
| *** 1645,1651 **** |
| 7. Sorting text *sorting* |
| |
| Vim has a sorting function and a sorting command. The sorting function can be |
| ! found here: |sort()|. |
| |
| *:sor* *:sort* |
| :[range]sor[t][!] [i][u][r][n][x][o] [/{pattern}/] |
| --- 1650,1656 ---- |
| 7. Sorting text *sorting* |
| |
| 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] [/{pattern}/] |
| |
| |
| |
| *** 326,331 **** |
| --- 327,333 ---- |
| Changing the order of items in a list: > |
| :call sort(list) " sort a list alphabetically |
| :call reverse(list) " reverse the order of items |
| + :call uniq(sort(list)) " sort and remove duplicates |
| |
| |
| For loop ~ |
| |
| *** 1518,1523 **** |
| --- 1520,1526 ---- |
| startup. These are the files that Vim remembers marks for. |
| The length of the List is limited by the ' argument of the |
| 'viminfo' option (default is 100). |
| + When the |viminfo| file is not used the List is empty. |
| Also see |:oldfiles| and |c_#<|. |
| The List can be modified, but this has no effect on what is |
| stored in the |viminfo| file later. If you use values other |
| |
| *** 2003,2008 **** |
| --- 2006,2013 ---- |
| type( {name}) Number type of variable {name} |
| undofile( {name}) String undo file name for {name} |
| undotree() List undo file tree |
| + uniq( {list} [, {func} [, {dict}]]) |
| + List remove adjacent duplicates from a list |
| values( {dict}) List values in {dict} |
| virtcol( {expr}) Number screen column of cursor or mark |
| visualmode( [expr]) String last visual mode used |
| |
| *** 5474,5493 **** |
| |
| |
| sort({list} [, {func} [, {dict}]]) *sort()* *E702* |
| ! Sort the items in {list} in-place. Returns {list}. If you |
| ! want a list to remain unmodified make a copy first: > |
| :let sortedlist = sort(copy(mylist)) |
| < Uses the string representation of each item to sort on. |
| Numbers sort after Strings, |Lists| after Numbers. |
| For sorting text in the current buffer use |:sort|. |
| When {func} is given and it is one then case is ignored. |
| - {dict} is for functions with the "dict" attribute. It will be |
| - used to set the local variable "self". |Dictionary-function| |
| When {func} is a |Funcref| or a function name, this function |
| is called to compare items. The function is invoked with two |
| items as argument and must return zero if they are equal, 1 or |
| bigger if the first one sorts after the second one, -1 or |
| smaller if the first one sorts before the second one. |
| Example: > |
| func MyCompare(i1, i2) |
| return a:i1 == a:i2 ? 0 : a:i1 > a:i2 ? 1 : -1 |
| --- 5491,5516 ---- |
| |
| |
| sort({list} [, {func} [, {dict}]]) *sort()* *E702* |
| ! Sort the items in {list} in-place. Returns {list}. |
| ! |
| ! If you want a list to remain unmodified make a copy first: > |
| :let sortedlist = sort(copy(mylist)) |
| < Uses the string representation of each item to sort on. |
| Numbers sort after Strings, |Lists| after Numbers. |
| For sorting text in the current buffer use |:sort|. |
| + |
| When {func} is given and it is one then case is ignored. |
| When {func} is a |Funcref| or a function name, this function |
| is called to compare items. The function is invoked with two |
| items as argument and must return zero if they are equal, 1 or |
| bigger if the first one sorts after the second one, -1 or |
| smaller if the first one sorts before the second one. |
| + |
| + {dict} is for functions with the "dict" attribute. It will be |
| + used to set the local variable "self". |Dictionary-function| |
| + |
| + Also see |uniq()|. |
| + |
| Example: > |
| func MyCompare(i1, i2) |
| return a:i1 == a:i2 ? 0 : a:i1 > a:i2 ? 1 : -1 |
| |
| *** 6155,6160 **** |
| --- 6178,6191 ---- |
| blocks. Each item may again have an "alt" |
| item. |
| |
| + uniq({list} [, {func} [, {dict}]]) *uniq()* *E882* |
| + Remove second and succeeding copies of repeated adjacent |
| + {list} items in-place. Returns {list}. If you want a list |
| + to remain unmodified make a copy first: > |
| + :let newlist = uniq(copy(mylist)) |
| + < The default compare function uses the string representation of |
| + each item. For the use of {func} and {dict} see |sort()|. |
| + |
| values({dict}) *values()* |
| Return a |List| with all the values of {dict}. The |List| is |
| in arbitrary order. |
| |
| |
| |
| *** 1,4 **** |
| ! *usr_41.txt* For Vim version 7.4. Last change: 2013 Feb 20 |
| |
| VIM USER MANUAL - by Bram Moolenaar |
| |
| --- 1,4 ---- |
| ! *usr_41.txt* For Vim version 7.4. Last change: 2014 Jan 10 |
| |
| VIM USER MANUAL - by Bram Moolenaar |
| |
| |
| *** 595,607 **** |
| matchlist() like matchstr() and also return submatches |
| stridx() first index of a short string in a long string |
| strridx() last index of a short string in a long string |
| ! strlen() length of a string |
| substitute() substitute a pattern match with a string |
| submatch() get a specific match in ":s" and substitute() |
| strpart() get part of a string |
| expand() expand special keywords |
| iconv() convert text from one encoding to another |
| byteidx() byte index of a character in a string |
| repeat() repeat a string multiple times |
| eval() evaluate a string expression |
| |
| --- 595,611 ---- |
| matchlist() like matchstr() and also return submatches |
| stridx() first index of a short string in a long string |
| strridx() last index of a short string in a long string |
| ! strlen() length of a string in bytes |
| ! strchars() length of a string in characters |
| ! strwidth() size of string when displayed |
| ! strdisplaywidth() size of string when displayed, deals with tabs |
| substitute() substitute a pattern match with a string |
| submatch() get a specific match in ":s" and substitute() |
| strpart() get part of a string |
| expand() expand special keywords |
| iconv() convert text from one encoding to another |
| byteidx() byte index of a character in a string |
| + byteidxcomp() like byteidx() but count composing characters |
| repeat() repeat a string multiple times |
| eval() evaluate a string expression |
| |
| |
| *** 619,624 **** |
| --- 623,629 ---- |
| map() change each List item |
| sort() sort a List |
| reverse() reverse the order of a List |
| + uniq() remove copies of repeated adjacent items |
| split() split a String into a List |
| join() join List items into a String |
| range() return a List with a sequence of numbers |
| |
| *** 656,661 **** |
| --- 661,669 ---- |
| ceil() round up |
| floor() round down |
| trunc() remove value after decimal point |
| + fmod() remainder of division |
| + exp() exponential |
| + log() natural logarithm (logarithm to base e) |
| log10() logarithm to base 10 |
| pow() value of x to the exponent y |
| sqrt() square root |
| |
| *** 675,680 **** |
| --- 683,689 ---- |
| invert() bitwise invert |
| or() bitwise OR |
| xor() bitwise XOR |
| + sha256() SHA-256 hash |
| |
| Variables: *var-functions* |
| type() type of a variable |
| |
| *** 697,707 **** |
| --- 706,720 ---- |
| wincol() window column number of the cursor |
| winline() window line number of the cursor |
| cursor() position the cursor at a line/column |
| + screencol() get screen column of the cursor |
| + screenrow() get screen row of the cursor |
| getpos() get position of cursor, mark, etc. |
| setpos() set position of cursor, mark, etc. |
| byte2line() get line number at a specific byte count |
| line2byte() byte count at a specific line |
| diff_filler() get the number of filler lines above a line |
| + screenattr() get attribute at a screen line/row |
| + screenchar() get character code at a screen line/row |
| |
| Working with text in the current buffer: *text-functions* |
| getline() get a line or list of lines from the buffer |
| |
| *** 883,896 **** |
| --- 896,917 ---- |
| libcall() call a function in an external library |
| libcallnr() idem, returning a number |
| |
| + undofile() get the name of the undo file |
| + undotree() return the state of the undo tree |
| + |
| getreg() get contents of a register |
| getregtype() get type of a register |
| setreg() set contents and type of a register |
| |
| + shiftwidth() effective value of 'shiftwidth' |
| + |
| taglist() get list of matching tags |
| tagfiles() get a list of tags files |
| |
| + luaeval() evaluate Lua expression |
| mzeval() evaluate |MzScheme| expression |
| + py3eval() evaluate Python expression (|+python3|) |
| + pyeval() evaluate Python expression (|+python|) |
| |
| |
| *41.7* Defining a function |
| |
| |
| |
| *** 942,947 **** |
| --- 942,948 ---- |
| |tagfiles()| List with tags file names |
| |taglist()| get list of matching tags (Yegappan Lakshmanan) |
| |tr()| translate characters (Ron Aaron) |
| + |uniq()| remove copies of repeated adjacent list items |
| |values()| get List of Dictionary values |
| |winnr()| takes an argument: what window to use |
| |winrestview()| restore the view of the current window |
| |
| |
| |
| *** 744,749 **** |
| --- 744,750 ---- |
| static void f_type __ARGS((typval_T *argvars, typval_T *rettv)); |
| static void f_undofile __ARGS((typval_T *argvars, typval_T *rettv)); |
| static void f_undotree __ARGS((typval_T *argvars, typval_T *rettv)); |
| + static void f_uniq __ARGS((typval_T *argvars, typval_T *rettv)); |
| static void f_values __ARGS((typval_T *argvars, typval_T *rettv)); |
| static void f_virtcol __ARGS((typval_T *argvars, typval_T *rettv)); |
| static void f_visualmode __ARGS((typval_T *argvars, typval_T *rettv)); |
| |
| *** 8150,8155 **** |
| --- 8151,8157 ---- |
| {"type", 1, 1, f_type}, |
| {"undofile", 1, 1, f_undofile}, |
| {"undotree", 0, 0, f_undotree}, |
| + {"uniq", 1, 3, f_uniq}, |
| {"values", 1, 1, f_values}, |
| {"virtcol", 1, 1, f_virtcol}, |
| {"visualmode", 0, 1, f_visualmode}, |
| |
| *** 17023,17032 **** |
| static char_u *item_compare_func; |
| static dict_T *item_compare_selfdict; |
| static int item_compare_func_err; |
| #define ITEM_COMPARE_FAIL 999 |
| |
| /* |
| ! * Compare functions for f_sort() below. |
| */ |
| static int |
| #ifdef __BORLANDC__ |
| --- 17025,17035 ---- |
| static char_u *item_compare_func; |
| static dict_T *item_compare_selfdict; |
| static int item_compare_func_err; |
| + static void do_sort_uniq __ARGS((typval_T *argvars, typval_T *rettv, int sort)); |
| #define ITEM_COMPARE_FAIL 999 |
| |
| /* |
| ! * Compare functions for f_sort() and f_uniq() below. |
| */ |
| static int |
| #ifdef __BORLANDC__ |
| |
| *** 17100,17108 **** |
| * "sort({list})" function |
| */ |
| static void |
| ! f_sort(argvars, rettv) |
| typval_T *argvars; |
| typval_T *rettv; |
| { |
| list_T *l; |
| listitem_T *li; |
| --- 17103,17112 ---- |
| * "sort({list})" function |
| */ |
| static void |
| ! do_sort_uniq(argvars, rettv, sort) |
| typval_T *argvars; |
| typval_T *rettv; |
| + int sort; |
| { |
| list_T *l; |
| listitem_T *li; |
| |
| *** 17111,17122 **** |
| long i; |
| |
| if (argvars[0].v_type != VAR_LIST) |
| ! EMSG2(_(e_listarg), "sort()"); |
| else |
| { |
| l = argvars[0].vval.v_list; |
| if (l == NULL || tv_check_lock(l->lv_lock, |
| ! (char_u *)_("sort() argument"))) |
| return; |
| rettv->vval.v_list = l; |
| rettv->v_type = VAR_LIST; |
| --- 17115,17126 ---- |
| long i; |
| |
| if (argvars[0].v_type != VAR_LIST) |
| ! EMSG2(_(e_listarg), sort ? "sort()" : "uniq()"); |
| else |
| { |
| l = argvars[0].vval.v_list; |
| if (l == NULL || tv_check_lock(l->lv_lock, |
| ! (char_u *)(sort ? _("sort() argument") : _("uniq() argument")))) |
| return; |
| rettv->vval.v_list = l; |
| rettv->v_type = VAR_LIST; |
| |
| *** 17163,17191 **** |
| ptrs = (listitem_T **)alloc((int)(len * sizeof(listitem_T *))); |
| if (ptrs == NULL) |
| return; |
| - i = 0; |
| - for (li = l->lv_first; li != NULL; li = li->li_next) |
| - ptrs[i++] = li; |
| |
| ! item_compare_func_err = FALSE; |
| ! /* test the compare function */ |
| ! if (item_compare_func != NULL |
| ! && item_compare2((void *)&ptrs[0], (void *)&ptrs[1]) |
| == ITEM_COMPARE_FAIL) |
| ! EMSG(_("E702: Sort compare function failed")); |
| else |
| { |
| ! /* Sort the array with item pointers. */ |
| ! qsort((void *)ptrs, (size_t)len, sizeof(listitem_T *), |
| ! item_compare_func == NULL ? item_compare : item_compare2); |
| |
| if (!item_compare_func_err) |
| { |
| ! /* Clear the List and append the items in the sorted order. */ |
| ! l->lv_first = l->lv_last = l->lv_idx_item = NULL; |
| ! l->lv_len = 0; |
| ! for (i = 0; i < len; ++i) |
| ! list_append(l, ptrs[i]); |
| } |
| } |
| |
| --- 17167,17238 ---- |
| ptrs = (listitem_T **)alloc((int)(len * sizeof(listitem_T *))); |
| if (ptrs == NULL) |
| return; |
| |
| ! i = 0; |
| ! if (sort) |
| ! { |
| ! /* sort(): ptrs will be the list to sort */ |
| ! for (li = l->lv_first; li != NULL; li = li->li_next) |
| ! ptrs[i++] = li; |
| ! |
| ! item_compare_func_err = FALSE; |
| ! /* test the compare function */ |
| ! if (item_compare_func != NULL |
| ! && item_compare2((void *)&ptrs[0], (void *)&ptrs[1]) |
| == ITEM_COMPARE_FAIL) |
| ! EMSG(_("E702: Sort compare function failed")); |
| ! else |
| ! { |
| ! /* Sort the array with item pointers. */ |
| ! qsort((void *)ptrs, (size_t)len, sizeof(listitem_T *), |
| ! item_compare_func == NULL ? item_compare : item_compare2); |
| ! |
| ! if (!item_compare_func_err) |
| ! { |
| ! /* Clear the List and append the items in sorted order. */ |
| ! l->lv_first = l->lv_last = l->lv_idx_item = NULL; |
| ! l->lv_len = 0; |
| ! for (i = 0; i < len; ++i) |
| ! list_append(l, ptrs[i]); |
| ! } |
| ! } |
| ! } |
| else |
| { |
| ! int (*item_compare_func_ptr)__ARGS((const void *, const void *)); |
| ! |
| ! /* f_uniq(): ptrs will be a stack of items to remove */ |
| ! item_compare_func_err = FALSE; |
| ! item_compare_func_ptr = item_compare_func |
| ! ? item_compare2 : item_compare; |
| ! |
| ! for (li = l->lv_first; li != NULL && li->li_next != NULL; |
| ! li = li->li_next) |
| ! { |
| ! if (item_compare_func_ptr((void *)&li, (void *)&li->li_next) |
| ! == 0) |
| ! ptrs[i++] = li; |
| ! if (item_compare_func_err) |
| ! { |
| ! EMSG(_("E882: Uniq compare function failed")); |
| ! break; |
| ! } |
| ! } |
| |
| if (!item_compare_func_err) |
| { |
| ! while (--i >= 0) |
| ! { |
| ! li = ptrs[i]->li_next; |
| ! ptrs[i]->li_next = li->li_next; |
| ! if (li->li_next != NULL) |
| ! li->li_next->li_prev = ptrs[i]; |
| ! else |
| ! l->lv_last = ptrs[i]; |
| ! list_fix_watch(l, li); |
| ! listitem_free(li); |
| ! l->lv_len--; |
| ! } |
| } |
| } |
| |
| |
| *** 17194,17199 **** |
| --- 17241,17268 ---- |
| } |
| |
| /* |
| + * "sort({list})" function |
| + */ |
| + static void |
| + f_sort(argvars, rettv) |
| + typval_T *argvars; |
| + typval_T *rettv; |
| + { |
| + do_sort_uniq(argvars, rettv, TRUE); |
| + } |
| + |
| + /* |
| + * "uniq({list})" function |
| + */ |
| + static void |
| + f_uniq(argvars, rettv) |
| + typval_T *argvars; |
| + typval_T *rettv; |
| + { |
| + do_sort_uniq(argvars, rettv, FALSE); |
| + } |
| + |
| + /* |
| * "soundfold({word})" function |
| */ |
| static void |
| |
| |
| |
| *** 323,335 **** |
| : $put ='caught ' . v:exception |
| :endtry |
| :" |
| ! :" reverse() and sort() |
| ! :let l = ['-0', 'A11', 2, 'xaaa', 4, 'foo', 'foo6', [0, 1, 2], 'x8'] |
| :$put =string(reverse(l)) |
| :$put =string(reverse(reverse(l))) |
| :$put =string(sort(l)) |
| :$put =string(reverse(sort(l))) |
| :$put =string(sort(reverse(sort(l)))) |
| :" |
| :" splitting a string to a List |
| :$put =string(split(' aa bb ')) |
| --- 323,337 ---- |
| : $put ='caught ' . v:exception |
| :endtry |
| :" |
| ! :" reverse(), sort(), uniq() |
| ! :let l = ['-0', 'A11', 2, 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5] |
| ! :$put =string(uniq(copy(l))) |
| :$put =string(reverse(l)) |
| :$put =string(reverse(reverse(l))) |
| :$put =string(sort(l)) |
| :$put =string(reverse(sort(l))) |
| :$put =string(sort(reverse(sort(l)))) |
| + :$put =string(uniq(sort(l))) |
| :" |
| :" splitting a string to a List |
| :$put =string(split(' aa bb ')) |
| |
| |
| |
| *** 94,104 **** |
| caught a:000[2] |
| caught a:000[3] |
| [1, 2, [3, 9, 5, 6], {'a': 12, '5': 8}] |
| ! ['x8', [0, 1, 2], 'foo6', 'foo', 4, 'xaaa', 2, 'A11', '-0'] |
| ! ['x8', [0, 1, 2], 'foo6', 'foo', 4, 'xaaa', 2, 'A11', '-0'] |
| ! ['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 2, 4, [0, 1, 2]] |
| ! [[0, 1, 2], 4, 2, 'xaaa', 'x8', 'foo6', 'foo', 'A11', '-0'] |
| ! ['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 2, 4, [0, 1, 2]] |
| ['aa', 'bb'] |
| ['aa', 'bb'] |
| ['', 'aa', 'bb', ''] |
| --- 94,106 ---- |
| caught a:000[2] |
| caught a:000[3] |
| [1, 2, [3, 9, 5, 6], {'a': 12, '5': 8}] |
| ! ['-0', 'A11', 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5] |
| ! [1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0'] |
| ! [1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0'] |
| ! ['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]] |
| ! [[0, 1, 2], [0, 1, 2], 4, 2, 2, 1.5, 'xaaa', 'x8', 'foo6', 'foo', 'foo', 'A11', '-0'] |
| ! ['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]] |
| ! ['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 4, [0, 1, 2]] |
| ['aa', 'bb'] |
| ['aa', 'bb'] |
| ['', 'aa', 'bb', ''] |
| |
| |
| |
| *** 736,737 **** |
| --- 736,739 ---- |
| { /* Add new patch number below this line */ |
| + /**/ |
| + 218, |
| /**/ |
| |
| -- |
| Never under any circumstances take a sleeping pill |
| and a laxative on the same night. |
| |
| /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ |
| /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ |
| \\\ an exciting new programming language -- http://www.Zimbu.org /// |
| \\\ help me help AIDS victims -- http://ICCF-Holland.org /// |