To: vim_dev@googlegroups.com Subject: Patch 7.4.218 Fcc: outbox From: Bram Moolenaar 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 *** ../vim-7.4.217/runtime/doc/change.txt 2013-09-22 15:23:38.000000000 +0200 --- runtime/doc/change.txt 2014-03-25 17:32:29.510040841 +0100 *************** *** 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}/] *** ../vim-7.4.217/runtime/doc/eval.txt 2014-02-23 23:38:58.820760280 +0100 --- runtime/doc/eval.txt 2014-03-25 17:47:18.750054467 +0100 *************** *** 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. *** ../vim-7.4.217/runtime/doc/usr_41.txt 2013-08-10 13:25:05.000000000 +0200 --- runtime/doc/usr_41.txt 2014-03-25 17:32:29.518040841 +0100 *************** *** 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 *** ../vim-7.4.217/runtime/doc/version7.txt 2013-08-10 14:23:06.000000000 +0200 --- runtime/doc/version7.txt 2014-03-25 17:32:29.518040841 +0100 *************** *** 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 *** ../vim-7.4.217/src/eval.c 2014-03-23 15:12:29.915264336 +0100 --- src/eval.c 2014-03-25 17:52:09.554058923 +0100 *************** *** 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 *** ../vim-7.4.217/src/testdir/test55.in 2014-01-14 15:24:24.000000000 +0100 --- src/testdir/test55.in 2014-03-25 17:32:29.522040841 +0100 *************** *** 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 ')) *** ../vim-7.4.217/src/testdir/test55.ok 2014-01-14 15:24:24.000000000 +0100 --- src/testdir/test55.ok 2014-03-25 17:32:29.522040841 +0100 *************** *** 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', ''] *** ../vim-7.4.217/src/version.c 2014-03-25 18:05:45.242071421 +0100 --- src/version.c 2014-03-25 17:34:51.918043023 +0100 *************** *** 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 ///