1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
|
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
*** ../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 ///
|