patch 9.1.1232: Vim script is missing the tuple data type
Problem: Vim script is missing the tuple data type
Solution: Add support for the tuple data type
(Yegappan Lakshmanan)
closes: #16776
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 48bdc43..d7c9740 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -1,4 +1,4 @@
-*builtin.txt* For Vim version 9.1. Last change: 2025 Mar 22
+*builtin.txt* For Vim version 9.1. Last change: 2025 Mar 23
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -207,7 +207,7 @@
foldlevel({lnum}) Number fold level at {lnum}
foldtext() String line displayed for closed fold
foldtextresult({lnum}) String text for closed fold at {lnum}
-foreach({expr1}, {expr2}) List/Dict/Blob/String
+foreach({expr1}, {expr2}) List/Tuple/Dict/Blob/String
for each item in {expr1} call {expr2}
foreground() Number bring the Vim window to the foreground
fullcommand({name} [, {vim9}]) String get full command from {name}
@@ -348,7 +348,7 @@
Job start a job
job_status({job}) String get the status of {job}
job_stop({job} [, {how}]) Number stop {job}
-join({list} [, {sep}]) String join {list} items into one String
+join({expr} [, {sep}]) String join items in {expr} into one String
js_decode({string}) any decode JS style JSON
js_encode({expr}) String encode JS style JSON
json_decode({string}) any decode JSON
@@ -364,6 +364,7 @@
lispindent({lnum}) Number Lisp indent for line {lnum}
list2blob({list}) Blob turn {list} of numbers into a Blob
list2str({list} [, {utf8}]) String turn {list} of numbers into a String
+list2tuple({list}) Tuple turn {list} of items into a tuple
listener_add({callback} [, {buf}])
Number add a callback to listen to changes
listener_flush([{buf}]) none invoke listener callbacks
@@ -511,10 +512,10 @@
remove bytes {idx}-{end} from {blob}
remove({dict}, {key}) any remove entry {key} from {dict}
rename({from}, {to}) Number rename (move) file from {from} to {to}
-repeat({expr}, {count}) List/Blob/String
+repeat({expr}, {count}) List/Tuple/Blob/String
repeat {expr} {count} times
resolve({filename}) String get filename a shortcut points to
-reverse({obj}) List/Blob/String
+reverse({obj}) List/Tuple/Blob/String
reverse {obj}
round({expr}) Float round off {expr}
rubyeval({expr}) any evaluate |Ruby| expression
@@ -713,6 +714,7 @@
test_null_list() List null value for testing
test_null_partial() Funcref null value for testing
test_null_string() String null value for testing
+test_null_tuple() Tuple null value for testing
test_option_not_set({name}) none reset flag indicating option was set
test_override({expr}, {val}) none test with Vim internal overrides
test_refcount({expr}) Number get the reference count of {expr}
@@ -734,6 +736,7 @@
trim({text} [, {mask} [, {dir}]])
String trim characters in {mask} from {text}
trunc({expr}) Float truncate Float {expr}
+tuple2list({tuple}) List turn {tuple} of items into a list
type({expr}) Number type of value {expr}
typename({expr}) String representation of the type of {expr}
undofile({name}) String undo file name for {name}
@@ -2073,7 +2076,8 @@
that the original |List| can be changed without changing the
copy, and vice versa. But the items are identical, thus
changing an item changes the contents of both |Lists|.
- A |Dictionary| is copied in a similar way as a |List|.
+ A |Tuple| or |Dictionary| is copied in a similar way as a
+ |List|.
Also see |deepcopy()|.
Can also be used as a |method|: >
mylist->copy()
@@ -2116,10 +2120,10 @@
count({comp}, {expr} [, {ic} [, {start}]]) *count()* *E706*
Return the number of times an item with value {expr} appears
- in |String|, |List| or |Dictionary| {comp}.
+ in |String|, |List|, |Tuple| or |Dictionary| {comp}.
If {start} is given then start with the item with this index.
- {start} can only be used with a |List|.
+ {start} can only be used with a |List| or a |Tuple|.
When {ic} is given and it's |TRUE| then case is ignored.
@@ -2239,7 +2243,8 @@
|Dictionary|, a copy for it is made, recursively. Thus
changing an item in the copy does not change the contents of
the original |List|.
- A |Dictionary| is copied in a similar way as a |List|.
+ A |Tuple| or |Dictionary| is copied in a similar way as a
+ |List|.
When {noref} is omitted or zero a contained |List| or
|Dictionary| is only copied once. All references point to
@@ -2547,8 +2552,8 @@
empty({expr}) *empty()*
Return the Number 1 if {expr} is empty, zero otherwise.
- - A |List| or |Dictionary| is empty when it does not have any
- items.
+ - A |List|, |Tuple| or |Dictionary| is empty when it does
+ not have any items.
- A |String| is empty when its length is zero.
- A |Number| and |Float| are empty when their value is zero.
- |v:false|, |v:none| and |v:null| are empty, |v:true| is not.
@@ -3475,8 +3480,9 @@
Return type: |String|
-foreach({expr1}, {expr2}) *foreach()*
- {expr1} must be a |List|, |String|, |Blob| or |Dictionary|.
+foreach({expr1}, {expr2}) *foreach()* *E1525*
+ {expr1} must be a |List|, |Tuple|, |String|, |Blob| or
+ |Dictionary|.
For each item in {expr1} execute {expr2}. {expr1} is not
modified; its values may be, as with |:lockvar| 1. |E741|
See |map()| and |filter()| to modify {expr1}.
@@ -3485,10 +3491,10 @@
If {expr2} is a |string|, inside {expr2} |v:val| has the value
of the current item. For a |Dictionary| |v:key| has the key
- of the current item and for a |List| |v:key| has the index of
- the current item. For a |Blob| |v:key| has the index of the
- current byte. For a |String| |v:key| has the index of the
- current character.
+ of the current item and for a |List| or a |Tuple| |v:key| has
+ the index of the current item. For a |Blob| |v:key| has the
+ index of the current byte. For a |String| |v:key| has the
+ index of the current character.
Examples: >
call foreach(mylist, 'used[v:val] = true')
< This records the items that are in the {expr1} list.
@@ -3514,8 +3520,8 @@
Can also be used as a |method|: >
mylist->foreach(expr2)
<
- Return type: |String|, |Blob| list<{type}> or dict<{type}>
- depending on {expr1}
+ Return type: |String|, |Blob|, list<{type}>, tuple<{type}> or
+ dict<{type}> depending on {expr1}
*foreground()*
foreground() Move the Vim window to the foreground. Useful when sent from
@@ -3688,6 +3694,15 @@
<
Return type: any, depending on {list}
+get({tuple}, {idx} [, {default}]) *get()-tuple*
+ Get item {idx} from |Tuple| {tuple}. When this item is not
+ available return {default}. Return zero when {default} is
+ omitted.
+ Preferably used as a |method|: >
+ mytuple->get(idx)
+<
+ Return type: any, depending on {tuple}
+
get({blob}, {idx} [, {default}]) *get()-blob*
Get byte {idx} from |Blob| {blob}. When this byte is not
available return {default}. Return -1 when {default} is
@@ -5821,8 +5836,8 @@
< prevents {item} from being garbage collected and provides a
way to get the {item} from the `id`.
- {item} may be a List, Dictionary, Object, Job, Channel or
- Blob. If the item is not a permitted type, or it is a null
+ {item} may be a List, Tuple, Dictionary, Object, Job, Channel
+ or Blob. If the item is not a permitted type, or it is a null
value, then an empty String is returned.
Can also be used as a |method|: >
@@ -5849,12 +5864,12 @@
Find {expr} in {object} and return its index. See
|indexof()| for using a lambda to select the item.
- If {object} is a |List| return the lowest index where the item
- has a value equal to {expr}. There is no automatic
- conversion, so the String "4" is different from the Number 4.
- And the number 4 is different from the Float 4.0. The value
- of 'ignorecase' is not used here, case matters as indicated by
- the {ic} argument.
+ If {object} is a |List| or a |Tuple| return the lowest index
+ where the item has a value equal to {expr}. There is no
+ automatic conversion, so the String "4" is different from the
+ Number 4. And the number 4 is different from the Float 4.0.
+ The value of 'ignorecase' is not used here, case matters as
+ indicated by the {ic} argument.
If {object} is |Blob| return the lowest index where the byte
value is equal to {expr}.
@@ -5878,11 +5893,11 @@
indexof({object}, {expr} [, {opts}]) *indexof()*
Returns the index of an item in {object} where {expr} is
- v:true. {object} must be a |List| or a |Blob|.
+ v:true. {object} must be a |List|, a |Tuple| or a |Blob|.
- If {object} is a |List|, evaluate {expr} for each item in the
- List until the expression is v:true and return the index of
- this item.
+ If {object} is a |List| or a |Tuple|, evaluate {expr} for each
+ item in the List until the expression is v:true and return the
+ index of this item.
If {object} is a |Blob| evaluate {expr} for each byte in the
Blob until the expression is v:true and return the index of
@@ -5890,11 +5905,11 @@
{expr} must be a |string| or |Funcref|.
- If {expr} is a |string|: If {object} is a |List|, inside
- {expr} |v:key| has the index of the current List item and
- |v:val| has the value of the item. If {object} is a |Blob|,
- inside {expr} |v:key| has the index of the current byte and
- |v:val| has the byte value.
+ If {expr} is a |string|: If {object} is a |List| or a |Tuple|,
+ inside {expr} |v:key| has the index of the current List or
+ Tuple item and |v:val| has the value of the item. If {object}
+ is a |Blob|, inside {expr} |v:key| has the index of the
+ current byte and |v:val| has the byte value.
If {expr} is a |Funcref| it must take two arguments:
1. the key or the index of the current item.
@@ -6204,9 +6219,9 @@
echo key .. ': ' .. value
endfor
<
- A List or a String argument is also supported. In these
- cases, items() returns a List with the index and the value at
- the index.
+ A |List|, a |Tuple| or a |String| argument is also supported.
+ In these cases, items() returns a List with the index and the
+ value at the index.
Can also be used as a |method|: >
mydict->items()
@@ -6217,16 +6232,17 @@
job_ functions are documented here: |job-functions-details|
-join({list} [, {sep}]) *join()*
- Join the items in {list} together into one String.
+join({expr} [, {sep}]) *join()*
+ Join the items in {expr} together into one String. {expr} can
+ be a |List| or a |Tuple|.
When {sep} is specified it is put in between the items. If
{sep} is omitted a single space is used.
Note that {sep} is not added at the end. You might want to
add it there too: >
let lines = join(mylist, "\n") .. "\n"
-< String items are used as-is. |Lists| and |Dictionaries| are
- converted into a string like with |string()|.
- The opposite function is |split()|.
+< String items are used as-is. |Lists|, |Tuples| and
+ |Dictionaries| are converted into a string like with
+ |string()|. The opposite function is |split()|.
Can also be used as a |method|: >
mylist->join()
@@ -6320,6 +6336,8 @@
|Funcref| not possible, error
|List| as an array (possibly null); when
used recursively: []
+ |Tuple| as an array (possibly null); when
+ used recursively: []
|Dict| as an object (possibly null); when
used recursively: {}
|Blob| as an array of the individual bytes
@@ -6368,6 +6386,8 @@
used, as with |strlen()|.
When {expr} is a |List| the number of items in the |List| is
returned.
+ When {expr} is a |Tuple| the number of items in the |Tuple| is
+ returned.
When {expr} is a |Blob| the number of bytes is returned.
When {expr} is a |Dictionary| the number of entries in the
|Dictionary| is returned.
@@ -6549,6 +6569,25 @@
Return type: |String|
+list2tuple({list}) *list2tuple()*
+ Create a Tuple from a shallow copy of the list items.
+ Examples: >
+ list2tuple([1, 2, 3]) returns (1, 2, 3)
+< |tuple2list()| does the opposite.
+
+ This function doesn't recursively convert all the List items
+ in {list} to a Tuple. Note that the items are identical
+ between the list and the tuple, changing an item changes the
+ contents of both the tuple and the list.
+
+ Returns an empty tuple on error.
+
+ Can also be used as a |method|: >
+ GetList()->list2tuple()
+<
+ Return type: tuple<{type}> (depending on the given |List|)
+
+
listener_add({callback} [, {buf}]) *listener_add()*
Add a callback function that will be invoked when changes have
been made to buffer {buf}.
@@ -7464,11 +7503,12 @@
Return the maximum value of all items in {expr}. Example: >
echo max([apples, pears, oranges])
-< {expr} can be a |List| or a |Dictionary|. For a Dictionary,
- it returns the maximum of all values in the Dictionary.
- If {expr} is neither a List nor a Dictionary, or one of the
- items in {expr} cannot be used as a Number this results in
- an error. An empty |List| or |Dictionary| results in zero.
+< {expr} can be a |List|, a |Tuple| or a |Dictionary|. For a
+ Dictionary, it returns the maximum of all values in the
+ Dictionary. If {expr} is neither a List nor a Tuple nor a
+ Dictionary, or one of the items in {expr} cannot be used as a
+ Number this results in an error. An empty |List|, |Tuple|
+ or |Dictionary| results in zero.
Can also be used as a |method|: >
mylist->max()
@@ -7555,11 +7595,12 @@
Return the minimum value of all items in {expr}. Example: >
echo min([apples, pears, oranges])
-< {expr} can be a |List| or a |Dictionary|. For a Dictionary,
- it returns the minimum of all values in the Dictionary.
- If {expr} is neither a List nor a Dictionary, or one of the
- items in {expr} cannot be used as a Number this results in
- an error. An empty |List| or |Dictionary| results in zero.
+< {expr} can be a |List|, a |Tuple| or a |Dictionary|. For a
+ Dictionary, it returns the minimum of all values in the
+ Dictionary. If {expr} is neither a List nor a Tuple nor a
+ Dictionary, or one of the items in {expr} cannot be used as a
+ Number this results in an error. An empty |List|, |Tuple| or
+ |Dictionary| results in zero.
Can also be used as a |method|: >
mylist->min()
@@ -8582,8 +8623,8 @@
reduce({object}, {func} [, {initial}]) *reduce()* *E998*
{func} is called for every item in {object}, which can be a
- |String|, |List| or a |Blob|. {func} is called with two
- arguments: the result so far and current item. After
+ |String|, |List|, |Tuple| or a |Blob|. {func} is called with
+ two arguments: the result so far and current item. After
processing all items the result is returned. *E1132*
{initial} is the initial result. When omitted, the first item
@@ -8904,16 +8945,16 @@
result. Example: >
:let separator = repeat('-', 80)
< When {count} is zero or negative the result is empty.
- When {expr} is a |List| or a |Blob| the result is {expr}
- concatenated {count} times. Example: >
+ When {expr} is a |List|, a |Tuple| or a |Blob| the result is
+ {expr} concatenated {count} times. Example: >
:let longlist = repeat(['a', 'b'], 3)
< Results in ['a', 'b', 'a', 'b', 'a', 'b'].
Can also be used as a |method|: >
mylist->repeat(count)
<
- Return type: |String|, |Blob| or list<{type}> depending on
- {expr}
+ Return type: |String|, |Blob|, list<{type}> or tuple<{type}>
+ depending on {expr}
resolve({filename}) *resolve()* *E655*
@@ -8940,18 +8981,19 @@
reverse({object}) *reverse()*
Reverse the order of items in {object}. {object} can be a
- |List|, a |Blob| or a |String|. For a List and a Blob the
- items are reversed in-place and {object} is returned.
+ |List|, a |Tuple|, a |Blob| or a |String|. For a List and a
+ Blob the items are reversed in-place and {object} is returned.
+ For a Tuple, a new Tuple is returned.
For a String a new String is returned.
- Returns zero if {object} is not a List, Blob or a String.
- If you want a List or Blob to remain unmodified make a copy
- first: >
+ Returns zero if {object} is not a List, Tuple, Blob or a
+ String. If you want a List or Blob to remain unmodified make
+ a copy first: >
:let revlist = reverse(copy(mylist))
< Can also be used as a |method|: >
mylist->reverse()
<
- Return type: |String|, |Blob| or list<{type}> depending on
- {object}
+ Return type: |String|, |Blob|, list<{type}> or tuple<{type}>
+ depending on {object}
round({expr}) *round()*
@@ -10304,7 +10346,7 @@
Can also be used as a |method|: >
GetList()->slice(offset)
<
- Return type: list<{type}>
+ Return type: list<{type}> or tuple<{type}>
sort({list} [, {how} [, {dict}]]) *sort()* *E702*
@@ -10916,15 +10958,16 @@
Funcref function('name')
Blob 0z00112233.44556677.8899
List [item, item]
+ Tuple (item, item)
Dictionary {key: value, key: value}
Class class SomeName
Object object of SomeName {lnum: 1, col: 3}
Enum enum EnumName
EnumValue enum name.value {name: str, ordinal: nr}
- When a |List| or |Dictionary| has a recursive reference it is
- replaced by "[...]" or "{...}". Using eval() on the result
- will then fail.
+ When a |List|, |Tuple| or |Dictionary| has a recursive
+ reference it is replaced by "[...]" or "(...)" or "{...}".
+ Using eval() on the result will then fail.
For an object, invokes the string() method to get a textual
representation of the object. If the method is not present,
@@ -11878,6 +11921,25 @@
Return type: |Float|
+tuple2list({list}) *tuple2list()*
+ Create a List from a shallow copy of the tuple items.
+ Examples: >
+ tuple2list((1, 2, 3)) returns [1, 2, 3]
+< |list2tuple()| does the opposite.
+
+ This function doesn't recursively convert all the Tuple items
+ in {tuple} to a List. Note that the items are identical
+ between the list and the tuple, changing an item changes the
+ contents of both the tuple and the list.
+
+ Returns an empty list on error.
+
+ Can also be used as a |method|: >
+ GetTuple()->tuple2list()
+<
+ Return type: list<{type}> (depending on the given |Tuple|)
+
+
*type()*
type({expr}) The result is a Number representing the type of {expr}.
Instead of using the number directly, it is better to use the
@@ -11898,6 +11960,7 @@
Typealias: 14 |v:t_typealias|
Enum: 15 |v:t_enum|
EnumValue: 16 |v:t_enumvalue|
+ Tuple: 17 |v:t_tuple|
For backward compatibility, this method can be used: >
:if type(myvar) == type(0)
:if type(myvar) == type("")
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 0ada1b2..bcd64e3 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1,4 +1,4 @@
-*eval.txt* For Vim version 9.1. Last change: 2025 Feb 23
+*eval.txt* For Vim version 9.1. Last change: 2025 Mar 23
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -21,9 +21,10 @@
1.1 Variable types
1.2 Function references |Funcref|
1.3 Lists |Lists|
- 1.4 Dictionaries |Dictionaries|
- 1.5 Blobs |Blobs|
- 1.6 More about variables |more-variables|
+ 1.4 Tuples |Tuples|
+ 1.5 Dictionaries |Dictionaries|
+ 1.6 Blobs |Blobs|
+ 1.7 More about variables |more-variables|
2. Expression syntax |expression-syntax|
3. Internal variable |internal-variables|
4. Builtin Functions |functions|
@@ -46,8 +47,8 @@
1.1 Variable types ~
*E712* *E896* *E897* *E899* *E1098*
- *E1107* *E1135* *E1138*
-There are ten types of variables:
+ *E1107* *E1135* *E1138* *E1523*
+There are eleven types of variables:
*Number* *Integer*
Number A 32 or 64 bit signed number. |expr-number|
@@ -63,6 +64,10 @@
List An ordered sequence of items, see |List| for details.
Example: [1, 2, ['a', 'b']]
+Tuple An ordered immutable sequence of items, see |Tuple| for
+ details.
+ Example: (1, 2, ('a', 'b'))
+
Dictionary An associative, unordered array: Each entry has a key and a
value. |Dictionary|
Examples:
@@ -165,16 +170,17 @@
*E611* *E745* *E728* *E703* *E729* *E730* *E731* *E908* *E910*
*E913* *E974* *E975* *E976* *E1319* *E1320* *E1321* *E1322*
- *E1323* *E1324*
-|List|, |Dictionary|, |Funcref|, |Job|, |Channel|, |Blob|, |Class| and
-|object| types are not automatically converted.
+ *E1323* *E1324* *E1520* *E1522*
+|List|, |Tuple|, |Dictionary|, |Funcref|, |Job|, |Channel|, |Blob|, |Class|
+and |object| types are not automatically converted.
*E805* *E806* *E808*
When mixing Number and Float the Number is converted to Float. Otherwise
there is no automatic conversion of Float. You can use str2float() for String
to Float, printf() for Float to String and float2nr() for Float to Number.
- *E362* *E891* *E892* *E893* *E894* *E907* *E911* *E914*
+ *E362* *E891* *E892* *E893* *E894*
+ *E907* *E911* *E914* *E1521*
When expecting a Float a Number can also be used, but nothing else.
*no-type-checking*
@@ -267,9 +273,9 @@
List creation ~
*E696* *E697*
-A List is created with a comma-separated list of items in square brackets.
+A List is created with a comma-separated sequence of items in square brackets.
Examples: >
- :let mylist = [1, two, 3, "four"]
+ :let mylist = [1, "two", 3, "four"]
:let emptylist = []
An item can be any expression. Using a List for an item creates a
@@ -327,13 +333,13 @@
:let otherlist = mylist[:] " make a copy of the List
Notice that the last index is inclusive. If you prefer using an exclusive
-index use the |slice()| method.
+index use the |slice()| function.
-If the first index is beyond the last item of the List or the second item is
+If the first index is beyond the last item of the List or the last index is
before the first item, the result is an empty list. There is no error
message.
-If the second index is equal to or greater than the length of the list the
+If the last index is equal to or greater than the length of the list the
length minus one is used: >
:let mylist = [0, 1, 2, 3]
:echo mylist[2:8] " result: [2, 3]
@@ -463,8 +469,8 @@
For loop ~
-The |:for| loop executes commands for each item in a List, String or Blob.
-A variable is set to each item in sequence. Example with a List: >
+The |:for| loop executes commands for each item in a List, Tuple, String or
+Blob. A variable is set to each item in sequence. Example with a List: >
:for item in mylist
: call Doit(item)
:endfor
@@ -497,6 +503,8 @@
: endif
:endfor
+For a Tuple one tuple item at a time is used.
+
For a Blob one byte at a time is used.
For a String one character, including any composing characters, is used as a
@@ -527,8 +535,206 @@
example, to add up all the numbers in a list: >
:exe 'let sum = ' .. join(nrlist, '+')
+1.4 Tuples ~
+ *tuple* *Tuple* *Tuples*
+ *E1532* *E1533*
+A Tuple is an ordered sequence of items. An item can be of any type. Items
+can be accessed by their index number. A Tuple is immutable.
-1.4 Dictionaries ~
+A Tuple uses less memory compared to a List and provides O(1) lookup time.
+
+Tuple creation ~
+ *E1526* *E1527*
+A Tuple is created with a comma-separated sequence of items in parentheses.
+Examples: >
+ :let mytuple = (1, "two", 3, "four")
+ :let tuple = (5,)
+ :let emptytuple = ()
+
+An item can be any expression. If there is only one item in the tuple, then
+the item must be followed by a comma.
+
+Using a Tuple for an item creates a Tuple of Tuples: >
+ :let nesttuple = ((11, 12), (21, 22), (31, 32))
+
+
+Tuple index ~
+ *tuple-index* *E1519*
+An item in the Tuple can be accessed by putting the index in square brackets
+after the Tuple. Indexes are zero-based, thus the first item has index zero.
+>
+ :let item = mytuple[0] " get the first item: 1
+ :let item = mytuple[2] " get the third item: 3
+
+When the resulting item is a tuple this can be repeated: >
+ :let item = nesttuple[0][1] " get the first tuple, second item: 12
+<
+A negative index is counted from the end. Index -1 refers to the last item in
+the Tuple, -2 to the last but one item, etc. >
+ :let last = mytuple[-1] " get the last item: "four"
+
+To avoid an error for an invalid index use the |get()| function. When an item
+is not available it returns zero or the default value you specify: >
+ :echo get(mytuple, idx)
+ :echo get(mytuple, idx, "NONE")
+
+
+Tuple concatenation ~
+ *tuple-concatenation*
+Two tuples can be concatenated with the "+" operator: >
+ :let longtuple = mytuple + (5, 6)
+ :let longtuple = (5, 6) + mytuple
+To prepend or append an item, turn it into a tuple by putting () around it.
+The item must be followed by a comma.
+
+ *E1540*
+Two variadic tuples with same item type can be concatenated but with different
+item types cannot be concatenated. Examples: >
+ var a: tuple<...list<number>> = (1, 2)
+ var b: tuple<...list<string>> = ('a', 'b')
+ echo a + b # not allowed
+
+ var a: tuple<number, number> = (1, 2)
+ var b: tuple<...list<string>> = ('a', 'b')
+ echo a + b # allowed
+
+ var a: tuple<...list<number>> = (1, 2)
+ var b: tuple<number, number> = (3, 4)
+ echo a + b # not allowed
+
+ var a: tuple<...list<number>> = (1, 2)
+ var b: tuple<number, ...list<number>> = (3, 4)
+ echo a + b # not allowed
+<
+Note that a tuple is immutable and items cannot be added or removed from a
+tuple.
+
+
+Subtuple ~
+ *subtuple*
+A part of the Tuple can be obtained by specifying the first and last index,
+separated by a colon in square brackets: >
+ :let shorttuple = mytuple[2:-1] " get Tuple (3, "four")
+
+Omitting the first index is similar to zero. Omitting the last index is
+similar to -1. >
+ :let endtuple = mytuple[2:] " from item 2 to the end: (3, "four")
+ :let shorttuple = mytuple[2:2] " Tuple with one item: (3,)
+ :let othertuple = mytuple[:] " make a copy of the Tuple
+
+Notice that the last index is inclusive. If you prefer using an exclusive
+index, use the |slice()| function.
+
+If the first index is beyond the last item of the Tuple or the last index is
+before the first item, the result is an empty tuple. There is no error
+message.
+
+If the last index is equal to or greater than the length of the tuple, the
+length minus one is used: >
+ :let mytuple = (0, 1, 2, 3)
+ :echo mytuple[2:8] " result: (2, 3)
+
+NOTE: mytuple[s:e] means using the variable "s:e" as index. Watch out for
+using a single letter variable before the ":". Insert a space when needed:
+mytuple[s : e].
+
+
+Tuple identity ~
+ *tuple-identity*
+When variable "aa" is a tuple and you assign it to another variable "bb", both
+variables refer to the same tuple: >
+ :let aa = (1, 2, 3)
+ :let bb = aa
+<
+
+Making a copy of a tuple is done with the |copy()| function. Using [:] also
+works, as explained above. This creates a shallow copy of the tuple: For
+example, changing a list item in the tuple will also change the item in the
+copied tuple: >
+ :let aa = ([1, 'a'], 2, 3)
+ :let bb = copy(aa)
+ :let aa[0][1] = 'aaa'
+ :echo aa
+< ([1, aaa], 2, 3) >
+ :echo bb
+< ([1, aaa], 2, 3)
+
+To make a completely independent tuple, use |deepcopy()|. This also makes a
+copy of the values in the tuple, recursively. Up to a hundred levels deep.
+
+The operator "is" can be used to check if two variables refer to the same
+Tuple. "isnot" does the opposite. In contrast, "==" compares if two tuples
+have the same value. >
+ :let atuple = (1, 2, 3)
+ :let btuple = (1, 2, 3)
+ :echo atuple is btuple
+< 0 >
+ :echo atuple == btuple
+< 1
+
+Note about comparing tuples: Two tuples are considered equal if they have the
+same length and all items compare equal, as with using "==". There is one
+exception: When comparing a number with a string they are considered
+different. There is no automatic type conversion, as with using "==" on
+variables. Example: >
+ echo 4 == "4"
+< 1 >
+ echo (4,) == ("4",)
+< 0
+
+Thus comparing Tuples is more strict than comparing numbers and strings. You
+can compare simple values this way too by putting them in a tuple: >
+
+ :let a = 5
+ :let b = "5"
+ :echo a == b
+< 1 >
+ :echo (a,) == (b,)
+< 0
+
+
+Tuple unpack ~
+
+To unpack the items in a tuple to individual variables, put the variables in
+square brackets, like list items: >
+ :let [var1, var2] = mytuple
+
+When the number of variables does not match the number of items in the tuple
+this produces an error. To handle any extra items from the tuple, append ";"
+and a variable name (which will then be of type tuple): >
+ :let [var1, var2; rest] = mytuple
+
+This works like: >
+ :let var1 = mytuple[0]
+ :let var2 = mytuple[1]
+ :let rest = mytuple[2:]
+
+Except that there is no error if there are only two items. "rest" will be an
+empty tuple then.
+
+
+Tuple functions ~
+ *E1536*
+Functions that are useful with a Tuple: >
+ :let xs = count(tuple, 'x') " count number of 'x's in tuple
+ :if empty(tuple) " check if tuple is empty
+ :let i = index(tuple, 'x') " index of first 'x' in tuple
+ :let l = items(tuple) " list of items in a tuple
+ :let string = join(tuple, ', ') " create string from tuple items
+ :let l = len(tuple) " number of items in tuple
+ :let big = max(tuple) " maximum value in tuple
+ :let small = min(tuple) " minimum value in tuple
+ :let r = repeat(tuple, n) " repeat a tuple n times
+ :let r = reverse(tuple) " reverse a tuple
+ :let s = slice(tuple, n1, n2) " slice a tuple
+ :let s = string(tuple) " String representation of tuple
+ :let l = tuple2list(tuple) " convert a tuple to list
+ :let t = list2tuple(list) " convert a list to tuple
+<
+ *E1524*
+A tuple cannot be used with the |map()|, |mapnew()| and |filter()| functions.
+
+1.5 Dictionaries ~
*dict* *Dict* *Dictionaries* *Dictionary*
A Dictionary is an associative array: Each entry has a key and a value. The
entry can be located with the key. The entries are stored without a specific
@@ -537,10 +743,10 @@
Dictionary creation ~
*E720* *E721* *E722* *E723*
-A Dictionary is created with a comma-separated list of entries in curly
+A Dictionary is created with a comma-separated sequence of entries in curly
braces. Each entry has a key and a value, separated by a colon. Each key can
only appear once. Examples: >
- :let mydict = {1: 'one', 2: 'two', 3: 'three'}
+ :let mydict = {'one': 1, 'two': 2, 'three': 3}
:let emptydict = {}
< *E713* *E716* *E717*
A key is always a String. You can use a Number, it will be converted to a
@@ -570,8 +776,11 @@
Accessing entries ~
The normal way to access an entry is by putting the key in square brackets: >
+ :let mydict = {'one': 1, 'two': 2, 'three': 3}
:let val = mydict["one"]
:let mydict["four"] = 4
+ :let val = mydict.one
+ :let mydict.four = 4
You can add new entries to an existing Dictionary this way, unlike Lists.
@@ -709,7 +918,7 @@
:call map(dict, '">> " .. v:val') " prepend ">> " to each item
-1.5 Blobs ~
+1.6 Blobs ~
*blob* *Blob* *Blobs* *E978*
A Blob is a binary object. It can be used to read an image from a file and
send it over a channel, for example.
@@ -856,7 +1065,7 @@
works, as explained above.
-1.6 More about variables ~
+1.7 More about variables ~
*more-variables*
If you need to know the type of a variable or expression, use the |type()|
function.
@@ -907,16 +1116,18 @@
etc. As above, append ? for ignoring case, # for
matching case
- expr5 is expr5 same |List|, |Dictionary| or |Blob| instance
- expr5 isnot expr5 different |List|, |Dictionary| or |Blob|
+ expr5 is expr5 same |List|, |Tuple|, |Dictionary| or |Blob|
instance
+ expr5 isnot expr5 different |List|, |Tuple|, |Dictionary| or
+ |Blob| instance
|expr5| expr6
expr6 << expr6 bitwise left shift
expr6 >> expr6 bitwise right shift
|expr6| expr7
- expr7 + expr7 ... number addition, list or blob concatenation
+ expr7 + expr7 ... number addition, list or tuple or blob
+ concatenation
expr7 - expr7 ... number subtraction
expr7 . expr7 ... string concatenation
expr7 .. expr7 ... string concatenation
@@ -935,8 +1146,10 @@
+ expr9 unary plus
|expr10| expr11
- expr10[expr1] byte of a String or item of a |List|
+ expr10[expr1] byte of a String or item of a |List| or
+ |Tuple|
expr10[expr1 : expr1] substring of a String or sublist of a |List|
+ or a slice of a |Tuple|
expr10.name entry in a |Dictionary|
expr10(expr1, ...) function call with |Funcref| variable
expr10->name(expr1, ...) |method| call
@@ -945,6 +1158,7 @@
"string" string constant, backslash is special
'string' string constant, ' is doubled
[expr1, ...] |List|
+ (expr1, ...) |Tuple|
{expr1: expr1, ...} |Dictionary|
#{key: expr1, ...} legacy |Dictionary|
&option option value
@@ -1101,10 +1315,11 @@
"abc" == "Abc" evaluates to 1 if 'ignorecase' is set, 0 otherwise
NOTE: In |Vim9| script 'ignorecase' is not used.
- *E691* *E692*
+ *E691* *E692* *E1517* *E1518*
A |List| can only be compared with a |List| and only "equal", "not equal",
"is" and "isnot" can be used. This compares the values of the list,
recursively. Ignoring case means case is ignored when comparing item values.
+Same applies for a |Tuple|.
*E735* *E736*
A |Dictionary| can only be compared with a |Dictionary| and only "equal", "not
@@ -1124,12 +1339,13 @@
if get(Part1, 'name') == get(Part2, 'name')
" Part1 and Part2 refer to the same function
< *E1037*
-Using "is" or "isnot" with a |List|, |Dictionary| or |Blob| checks whether
-the expressions are referring to the same |List|, |Dictionary| or |Blob|
-instance. A copy of a |List| is different from the original |List|. When
-using "is" without a |List|, |Dictionary| or |Blob|, it is equivalent to
-using "equal", using "isnot" equivalent to using "not equal". Except that
-a different type means the values are different: >
+Using "is" or "isnot" with a |List|, |Tuple|, |Dictionary| or |Blob| checks
+whether the expressions are referring to the same |List|, |Tuple|,
+|Dictionary| or |Blob| instance. A copy of a |List| or |Tuple| is different
+from the original |List| or |Tuple|. When using "is" without a |List|,
+|Tuple|, |Dictionary| or |Blob|, it is equivalent to using "equal", using
+"isnot" is equivalent to using "not equal". Except that a different type
+means the values are different: >
echo 4 == '4'
1
echo 4 is '4'
@@ -1147,7 +1363,7 @@
because 'x' converted to a Number is zero. However: >
echo [0] == ['x']
0
-Inside a List or Dictionary this conversion is not used.
+Inside a List or Tuple or Dictionary this conversion is not used.
In |Vim9| script the types must match.
@@ -1191,13 +1407,14 @@
expr6 and expr7 *expr6* *expr7* *E1036* *E1051*
---------------
-expr7 + expr7 Number addition, |List| or |Blob| concatenation *expr-+*
+ *expr-+*
+expr7 + expr7 Number addition, |List| or |Tuple| or |Blob| concatenation
expr7 - expr7 Number subtraction *expr--*
expr7 . expr7 String concatenation *expr-.*
expr7 .. expr7 String concatenation *expr-..*
For |Lists| only "+" is possible and then both expr7 must be a list. The
-result is a new list with the two lists Concatenated.
+result is a new list with the two lists concatenated. Same for a |Tuple|.
For String concatenation ".." is preferred, since "." is ambiguous, it is also
used for |Dict| member access and floating point numbers.
@@ -1295,7 +1512,8 @@
expr10->(expr1, ...)[expr1]
Evaluation is always from left to right.
-expr10[expr1] item of String or |List| *expr-[]* *E111*
+ *expr-[]* *E111*
+expr10[expr1] item of String or |List| or |Tuple|
*E909* *subscript* *E1062*
In legacy Vim script:
If expr10 is a Number or String this results in a String that contains the
@@ -1328,6 +1546,8 @@
|List|, or more negative than the length of the |List|, this results in an
error.
+A |Tuple| index is similar to a |List| index as explained above.
+
expr10[expr1a : expr1b] substring or |sublist| *expr-[:]* *substring*
@@ -1369,6 +1589,7 @@
:let l = mylist[:3] " first four items
:let l = mylist[4:4] " List with one item
:let l = mylist[:] " shallow copy of a List
+A |Tuple| slice is similar to a |List| slice.
If expr10 is a |Blob| this results in a new |Blob| with the bytes in the
indexes expr1a and expr1b, inclusive. Examples: >
@@ -2615,6 +2836,8 @@
v:t_enum Value of |enum| type. Read-only. See: |type()|
*v:t_enumvalue* *t_enumvalue-variable*
v:t_enumvalue Value of |enumvalue| type. Read-only. See: |type()|
+ *v:t_tuple* *t_tuple-variable*
+v:t_tuple Value of |Tuple| type. Read-only. See: |type()|
*v:termresponse* *termresponse-variable*
v:termresponse The escape sequence returned by the terminal for the |t_RV|
@@ -2934,13 +3157,13 @@
:let &g:{option-name} -= {expr1}
Like above, but only set the global value of an option
(if there is one). Works like |:setglobal|.
- *E1093*
+ *E1093* *E1537* *E1538* *E1535*
:let [{name1}, {name2}, ...] = {expr1} *:let-unpack* *E687* *E688*
- {expr1} must evaluate to a |List|. The first item in
- the list is assigned to {name1}, the second item to
- {name2}, etc.
+ {expr1} must evaluate to a |List| or a |Tuple|. The
+ first item in the list or tuple is assigned to
+ {name1}, the second item to {name2}, etc.
The number of names must match the number of items in
- the |List|.
+ the |List| or |Tuple|.
Each name can be one of the items of the ":let"
command as mentioned above.
Example: >
@@ -2957,16 +3180,22 @@
:let [{name1}, {name2}, ...] .= {expr1}
:let [{name1}, {name2}, ...] += {expr1}
:let [{name1}, {name2}, ...] -= {expr1}
- Like above, but append/add/subtract the value for each
- |List| item.
+:let [{name1}, {name2}, ...] *= {expr1}
+:let [{name1}, {name2}, ...] /= {expr1}
+:let [{name1}, {name2}, ...] %= {expr1}
+ Like above, but append, add, subtract, multiply,
+ divide, or modulo the value for each |List| or |Tuple|
+ item.
:let [{name}, ..., ; {lastname}] = {expr1} *E452*
- Like |:let-unpack| above, but the |List| may have more
- items than there are names. A list of the remaining
- items is assigned to {lastname}. If there are no
- remaining items {lastname} is set to an empty list.
+ Like |:let-unpack| above, but the |List| or |Tuple|
+ may have more items than there are names. A list or a
+ tuple of the remaining items is assigned to
+ {lastname}. If there are no remaining items,
+ {lastname} is set to an empty list or tuple.
Example: >
:let [a, b; rest] = ["aval", "bval", 3, 4]
+ :let [a, b; rest] = ("aval", "bval", 3, 4)
<
:let [{name}, ..., ; {lastname}] .= {expr1}
:let [{name}, ..., ; {lastname}] += {expr1}
@@ -3161,23 +3390,26 @@
get an error message: "E940: Cannot lock or unlock
variable {name}".
- [depth] is relevant when locking a |List| or
- |Dictionary|. It specifies how deep the locking goes:
+ [depth] is relevant when locking a |List|, a |Tuple|
+ or a |Dictionary|. It specifies how deep the locking
+ goes:
0 Lock the variable {name} but not its
value.
- 1 Lock the |List| or |Dictionary| itself,
- cannot add or remove items, but can
- still change their values.
+ 1 Lock the |List| or |Tuple| or
+ |Dictionary| itself, cannot add or
+ remove items, but can still change
+ their values.
2 Also lock the values, cannot change
the items. If an item is a |List| or
- |Dictionary|, cannot add or remove
- items, but can still change the
+ |Tuple| or |Dictionary|, cannot add or
+ remove items, but can still change the
values.
- 3 Like 2 but for the |List| /
- |Dictionary| in the |List| /
+ 3 Like 2 but for the |List| / |Tuple| /
+ |Dictionary| in the |List| / |Tuple| /
|Dictionary|, one level deeper.
- The default [depth] is 2, thus when {name} is a |List|
- or |Dictionary| the values cannot be changed.
+ The default [depth] is 2, thus when {name} is a
+ |List|, a |Tuple| or a |Dictionary| the values cannot
+ be changed.
Example with [depth] 0: >
let mylist = [1, 2, 3]
@@ -3282,7 +3514,7 @@
:endfo[r] *:endfo* *:endfor*
Repeat the commands between `:for` and `:endfor` for
each item in {object}. {object} can be a |List|,
- a |Blob| or a |String|. *E1177*
+ a |Tuple|, a |Blob| or a |String|. *E1177*
Variable {var} is set to the value of each item.
In |Vim9| script the loop variable must not have been
diff --git a/runtime/doc/tags b/runtime/doc/tags
index 1eebe14..52c3678 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -4592,9 +4592,33 @@
E1514 options.txt /*E1514*
E1515 builtin.txt /*E1515*
E1516 builtin.txt /*E1516*
+E1517 eval.txt /*E1517*
+E1518 eval.txt /*E1518*
+E1519 eval.txt /*E1519*
E152 helphelp.txt /*E152*
+E1520 eval.txt /*E1520*
+E1521 eval.txt /*E1521*
+E1522 eval.txt /*E1522*
+E1523 eval.txt /*E1523*
+E1524 eval.txt /*E1524*
+E1525 builtin.txt /*E1525*
+E1526 eval.txt /*E1526*
+E1527 eval.txt /*E1527*
+E1528 vim9.txt /*E1528*
+E1529 vim9.txt /*E1529*
E153 helphelp.txt /*E153*
+E1530 vim9.txt /*E1530*
+E1531 vim9.txt /*E1531*
+E1532 eval.txt /*E1532*
+E1533 eval.txt /*E1533*
+E1534 vim9.txt /*E1534*
+E1535 eval.txt /*E1535*
+E1536 eval.txt /*E1536*
+E1537 eval.txt /*E1537*
+E1538 eval.txt /*E1538*
+E1539 vim9.txt /*E1539*
E154 helphelp.txt /*E154*
+E1540 eval.txt /*E1540*
E155 sign.txt /*E155*
E156 sign.txt /*E156*
E157 sign.txt /*E157*
@@ -5785,6 +5809,8 @@
TextChangedT autocmd.txt /*TextChangedT*
TextYankPost autocmd.txt /*TextYankPost*
Transact-SQL ft_sql.txt /*Transact-SQL*
+Tuple eval.txt /*Tuple*
+Tuples eval.txt /*Tuples*
U undo.txt /*U*
UTF-8 mbyte.txt /*UTF-8*
UTF8-xterm mbyte.txt /*UTF8-xterm*
@@ -7872,6 +7898,7 @@
get()-dict builtin.txt /*get()-dict*
get()-func builtin.txt /*get()-func*
get()-list builtin.txt /*get()-list*
+get()-tuple builtin.txt /*get()-tuple*
get-ms-debuggers debug.txt /*get-ms-debuggers*
getbufinfo() builtin.txt /*getbufinfo()*
getbufline() builtin.txt /*getbufline()*
@@ -8652,6 +8679,7 @@
list-repeat windows.txt /*list-repeat*
list2blob() builtin.txt /*list2blob()*
list2str() builtin.txt /*list2str()*
+list2tuple() builtin.txt /*list2tuple()*
listener_add() builtin.txt /*listener_add()*
listener_flush() builtin.txt /*listener_flush()*
listener_remove() builtin.txt /*listener_remove()*
@@ -10325,6 +10353,7 @@
substitute() builtin.txt /*substitute()*
substitute-CR version6.txt /*substitute-CR*
substring eval.txt /*substring*
+subtuple eval.txt /*subtuple*
suffixes cmdline.txt /*suffixes*
suspend starting.txt /*suspend*
swap-exists-choices usr_11.txt /*swap-exists-choices*
@@ -10574,6 +10603,7 @@
t_tp version4.txt /*t_tp*
t_ts term.txt /*t_ts*
t_ts_old version4.txt /*t_ts_old*
+t_tuple-variable eval.txt /*t_tuple-variable*
t_typealias-variable eval.txt /*t_typealias-variable*
t_u7 term.txt /*t_u7*
t_ue term.txt /*t_ue*
@@ -10810,6 +10840,7 @@
test_null_list() testing.txt /*test_null_list()*
test_null_partial() testing.txt /*test_null_partial()*
test_null_string() testing.txt /*test_null_string()*
+test_null_tuple() testing.txt /*test_null_tuple()*
test_option_not_set() testing.txt /*test_option_not_set()*
test_override() testing.txt /*test_override()*
test_refcount() testing.txt /*test_refcount()*
@@ -10895,6 +10926,13 @@
try-finally eval.txt /*try-finally*
try-nested eval.txt /*try-nested*
try-nesting eval.txt /*try-nesting*
+tuple eval.txt /*tuple*
+tuple-concatenation eval.txt /*tuple-concatenation*
+tuple-functions usr_41.txt /*tuple-functions*
+tuple-identity eval.txt /*tuple-identity*
+tuple-index eval.txt /*tuple-index*
+tuple-type vim9.txt /*tuple-type*
+tuple2list() builtin.txt /*tuple2list()*
tutor usr_01.txt /*tutor*
two-engines pattern.txt /*two-engines*
type() builtin.txt /*type()*
@@ -11091,6 +11129,7 @@
v:t_number eval.txt /*v:t_number*
v:t_object eval.txt /*v:t_object*
v:t_string eval.txt /*v:t_string*
+v:t_tuple eval.txt /*v:t_tuple*
v:t_typealias eval.txt /*v:t_typealias*
v:termblinkresp eval.txt /*v:termblinkresp*
v:termrbgresp eval.txt /*v:termrbgresp*
@@ -11230,6 +11269,7 @@
variable-scope eval.txt /*variable-scope*
variable-types vim9.txt /*variable-types*
variables eval.txt /*variables*
+variadic-tuple vim9.txt /*variadic-tuple*
various various.txt /*various*
various-cmds various.txt /*various-cmds*
various-functions usr_41.txt /*various-functions*
diff --git a/runtime/doc/testing.txt b/runtime/doc/testing.txt
index 7d0402c..01e98cb 100644
--- a/runtime/doc/testing.txt
+++ b/runtime/doc/testing.txt
@@ -1,4 +1,4 @@
-*testing.txt* For Vim version 9.1. Last change: 2024 Jul 18
+*testing.txt* For Vim version 9.1. Last change: 2025 Mar 23
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -364,6 +364,11 @@
Return type: |String|
+test_null_tuple() *test_null_tuple()*
+ Return a |Tuple| that is null. Only useful for testing.
+
+ Return type: |Tuple|
+
test_option_not_set({name}) *test_option_not_set()*
Reset the flag that indicates option {name} was set. Thus it
looks like it still has the default value. Use like this: >
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index 0d09fc9..4c5e5ef 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -1,4 +1,4 @@
-*usr_41.txt* For Vim version 9.1. Last change: 2025 Feb 01
+*usr_41.txt* For Vim version 9.1. Last change: 2025 Mar 23
VIM USER MANUAL - by Bram Moolenaar
@@ -839,6 +839,30 @@
repeat() repeat a List multiple times
flatten() flatten a List
flattennew() flatten a copy of a List
+ items() get List of List index-value pairs
+
+Tuple manipulation: *tuple-functions*
+ copy() make a shallow copy of a Tuple
+ count() count number of times a value appears in a
+ Tuple
+ deepcopy() make a full copy of a Tuple
+ empty() check if Tuple is empty
+ foreach() apply function to Tuple items
+ get() get an item without error for wrong index
+ index() index of a value in a Tuple
+ indexof() index in a Tuple where an expression is true
+ items() get List of Tuple index-value pairs
+ join() join Tuple items into a String
+ len() number of items in a Tuple
+ list2tuple() convert a list of items into a Tuple
+ max() maximum value in a Tuple
+ min() minimum value in a Tuple
+ reduce() reduce a Tuple to a value
+ repeat() repeat a Tuple multiple times
+ reverse() reverse the order of items in a Tuple
+ slice() take a slice of a Tuple
+ string() string representation of a Tuple
+ tuple2list() convert a Tuple of items into a list
Dictionary manipulation: *dict-functions*
get() get an entry without an error for a wrong key
@@ -1234,6 +1258,7 @@
test_null_list() return a null List
test_null_partial() return a null Partial function
test_null_string() return a null String
+ test_null_tuple() return a null Tuple
test_settime() set the time Vim uses internally
test_setmouse() set the mouse position
test_feedinput() add key sequence to input buffer
@@ -1649,8 +1674,8 @@
==============================================================================
*41.8* Lists and Dictionaries
-So far we have used the basic types String and Number. Vim also supports two
-composite types: List and Dictionary.
+So far we have used the basic types String and Number. Vim also supports
+three composite types: List, Tuple and Dictionary.
A List is an ordered sequence of items. The items can be any kind of value,
thus you can make a List of numbers, a List of Lists and even a List of mixed
@@ -1751,6 +1776,23 @@
For further reading see |Lists|.
+TUPLE
+
+A Tuple is an immutable ordered sequence of items. An item can be of any
+type. Items can be accessed by their index number. To create a Tuple with
+three strings: >
+
+ var atuple = ('one', 'two', 'three')
+
+The Tuple items are enclosed in parenthesis and separated by commas. To
+create an empty Tuple: >
+
+ var atuple = ()
+
+The |:for| loop can be used to iterate over the items in a Tuple similar to a
+List.
+
+For further reading see |Tuples|.
DICTIONARIES
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index 377ab2a..4f0da43 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -1,4 +1,4 @@
-*version9.txt* For Vim version 9.1. Last change: 2025 Mar 21
+*version9.txt* For Vim version 9.1. Last change: 2025 Mar 23
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -41574,6 +41574,8 @@
changes between buffers on similar lines improving the diff highlighting in
Vim
+Support for the |Tuple| data type in Vim script and Vim9 script.
+
*changed-9.2*
Changed~
-------
@@ -41677,11 +41679,14 @@
|getstacktrace()| get current stack trace of Vim scripts
|id()| get unique identifier for a Dict, List, Object,
Channel or Blob variable
+|list2tuple()| turn a List of items into a Tuple
|matchbufline()| all the matches of a pattern in a buffer
|matchstrlist()| all the matches of a pattern in a List of strings
|ngettext()| lookup single/plural message translation
|popup_setbuf()| switch to a different buffer in a popup
|str2blob()| convert a List of strings into a blob
+|test_null_tuple()| return a null tuple
+|tuple2list()| turn a Tuple of items into a List
Autocommands: ~
diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt
index bf50094..d06c250 100644
--- a/runtime/doc/vim9.txt
+++ b/runtime/doc/vim9.txt
@@ -1,4 +1,4 @@
-*vim9.txt* For Vim version 9.1. Last change: 2025 Mar 06
+*vim9.txt* For Vim version 9.1. Last change: 2025 Mar 23
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1001,6 +1001,7 @@
string non-empty
blob non-empty
list non-empty (different from JavaScript)
+ tuple non-empty (different from JavaScript)
dictionary non-empty (different from JavaScript)
func when there is a function name
special true or v:true
@@ -1048,6 +1049,7 @@
null_function
null_job
null_list
+ null_tuple
null_object
null_partial
null_string
@@ -1467,15 +1469,16 @@
dict<{type}>
job
channel
+ tuple<{type}>
+ tuple<{type}, {type}, ...>
+ tuple<...list<{type}>>
+ tuple<{type}, ...list<{type}>>
func
func: {type}
func({type}, ...)
func({type}, ...): {type}
void
-Not supported yet:
- tuple<a: {type}, b: {type}, ...>
-
These types can be used in declarations, but no simple value will actually
have the "void" type. Trying to use a void (e.g. a function without a
return value) results in error *E1031* *E1186* .
@@ -1483,6 +1486,32 @@
There is no array type, use list<{type}> instead. For a list constant an
efficient implementation is used that avoids allocating a lot of small pieces
of memory.
+ *tuple-type*
+A tuple type can be declared in more or less specific ways:
+tuple<number> a tuple with a single item of type |Number|
+tuple<number, string> a tuple with two items of type |Number| and
+ |String|
+tuple<number, float, bool> a tuple with three items of type |Number|,
+ |Float| and |Boolean|.
+tuple<...list<number>> a variadic tuple with zero or more items of
+ type |Number|.
+tuple<number, ...list<string>> a tuple with an item of type |Number| followed
+ by zero or more items of type |String|.
+
+Examples: >
+ var myTuple: tuple<number> = (20,)
+ var myTuple: tuple<number, string> = (30, 'vim')
+ var myTuple: tuple<number, float, bool> = (40, 1.1, true)
+ var myTuple: tuple<...list<string>> = ('a', 'b', 'c')
+ var myTuple: tuple<number, ...list<string>> = (3, 'a', 'b', 'c')
+<
+ *variadic-tuple* *E1539*
+A variadic tuple has zero or more items of the same type. The type of a
+variadic tuple must end with a list type. Examples: >
+ var myTuple: tuple<...list<number>> = (1, 2, 3)
+ var myTuple: tuple<...list<string>> = ('a', 'b', 'c')
+ var myTuple: tuple<...list<bool>> = ()
+<
*vim9-func-declaration* *E1005* *E1007*
A partial and function can be declared in more or less specific ways:
func any kind of function reference, no type
@@ -1707,7 +1736,8 @@
*E1211* *E1217* *E1218* *E1219* *E1220* *E1221*
*E1222* *E1223* *E1224* *E1225* *E1226* *E1227*
*E1228* *E1238* *E1250* *E1251* *E1252* *E1256*
- *E1297* *E1298* *E1301*
+ *E1297* *E1298* *E1301* *E1528* *E1529* *E1530*
+ *E1531* *E1534*
Types are checked for most builtin functions to make it easier to spot
mistakes.
@@ -1715,7 +1745,7 @@
*variable-categories* *null-variables*
There are categories of variables:
primitive number, float, boolean
- container string, blob, list, dict
+ container string, blob, list, tuple, dict
specialized function, job, channel, user-defined-object
When declaring a variable without an initializer, an explicit type must be
@@ -1845,6 +1875,7 @@
var s: string s == null
var b: blob b != null ***
var l: list<any> l != null ***
+ var t: tuple<any> t != null ***
var d: dict<any> d != null ***
var f: func f == null
var j: job j == null
@@ -1855,6 +1886,7 @@
var s2: string = "" == null_string != null
var b2: blob = 0z == null_blob != null
var l2: list<any> = [] == null_list != null
+ var t2: tuple<any> = () == null_tuple != null
var d2: dict<any> = {} == null_dict != null
NOTE: the specialized variables, like job, default to null value and have no