1
1
// eslint-disable-next-line id-denylist
2
2
import { alt , optWhitespace , Parser , sepBy , seq , string , whitespace } from 'parsimmon' ;
3
- import { env } from 'process' ;
4
3
import { VimState } from '../../state/vimState' ;
5
4
import { StatusBar } from '../../statusBar' ;
6
5
import { ExCommand } from '../../vimscript/exCommand' ;
@@ -11,7 +10,6 @@ import {
11
10
int ,
12
11
modulo ,
13
12
multiply ,
14
- str ,
15
13
subtract ,
16
14
} from '../../vimscript/expression/build' ;
17
15
import { EvaluationContext , toInt , toString } from '../../vimscript/expression/evaluate' ;
@@ -42,6 +40,12 @@ type Index = {
42
40
variable : VariableExpression ;
43
41
index : Expression ;
44
42
} ;
43
+ type Slice = {
44
+ type : 'slice' ;
45
+ variable : VariableExpression ;
46
+ start : Expression | undefined ;
47
+ end : Expression | undefined ;
48
+ } ;
45
49
46
50
export type LetCommandOperation = '=' | '+=' | '-=' | '*=' | '/=' | '%=' | '.=' | '..=' ;
47
51
export type LetCommandVariable =
@@ -52,7 +56,7 @@ export type LetCommandVariable =
52
56
export type LetCommandArgs =
53
57
| {
54
58
operation : LetCommandOperation ;
55
- variable : LetCommandVariable | Unpack | Index ;
59
+ variable : LetCommandVariable | Unpack | Index | Slice ;
56
60
expression : Expression ;
57
61
lock : boolean ;
58
62
}
@@ -95,8 +99,19 @@ const indexParser: Parser<Index> = seq(
95
99
index,
96
100
} ) ) ;
97
101
102
+ const sliceParser : Parser < Slice > = seq (
103
+ variableParser ,
104
+ string ( '[' ) . then ( optWhitespace ) . then ( expressionParser ) . fallback ( undefined ) ,
105
+ string ( ':' ) . trim ( optWhitespace ) ,
106
+ expressionParser . fallback ( undefined ) . skip ( optWhitespace . then ( string ( ']' ) ) ) ,
107
+ ) . map ( ( [ variable , start , _ , end ] ) => ( {
108
+ type : 'slice' ,
109
+ variable,
110
+ start,
111
+ end,
112
+ } ) ) ;
113
+
98
114
export class LetCommand extends ExCommand {
99
- // TODO: Support slicing
100
115
public static readonly argParser = ( lock : boolean ) =>
101
116
alt < LetCommand > (
102
117
// `:let {var} = {expr}`
@@ -105,7 +120,12 @@ export class LetCommand extends ExCommand {
105
120
// `:let {var} .= {expr}`
106
121
whitespace . then (
107
122
seq (
108
- alt < LetCommandVariable | Unpack | Index > ( unpackParser , indexParser , letVarParser ) ,
123
+ alt < LetCommandVariable | Unpack | Index | Slice > (
124
+ unpackParser ,
125
+ sliceParser ,
126
+ indexParser ,
127
+ letVarParser ,
128
+ ) ,
109
129
operationParser . trim ( optWhitespace ) ,
110
130
expressionParser ,
111
131
) . map (
@@ -221,6 +241,37 @@ export class LetCommand extends ExCommand {
221
241
// TODO: Support blobs
222
242
throw VimError . fromCode ( ErrorCode . CanOnlyIndexAListDictionaryOrBlob ) ;
223
243
}
244
+ } else if ( variable . type === 'slice' ) {
245
+ // TODO: Operations other than `=`?
246
+ // TODO: Support blobs
247
+ const varValue = context . evaluate ( variable . variable ) ;
248
+ if ( varValue . type !== 'list' || value . type !== 'list' ) {
249
+ throw VimError . fromCode ( ErrorCode . CanOnlyIndexAListDictionaryOrBlob ) ;
250
+ }
251
+ if ( value . type !== 'list' ) {
252
+ throw VimError . fromCode ( ErrorCode . SliceRequiresAListOrBlobValue ) ;
253
+ }
254
+ const start = variable . start ? toInt ( context . evaluate ( variable . start ) ) : 0 ;
255
+ if ( start > varValue . items . length - 1 ) {
256
+ throw VimError . fromCode ( ErrorCode . ListIndexOutOfRange , start . toString ( ) ) ;
257
+ }
258
+ // NOTE: end is inclusive, unlike in JS
259
+ const end = variable . end
260
+ ? toInt ( context . evaluate ( variable . end ) )
261
+ : varValue . items . length - 1 ;
262
+ const slots = end - start + 1 ;
263
+ if ( slots > value . items . length ) {
264
+ throw VimError . fromCode ( ErrorCode . ListValueHasNotEnoughItems ) ;
265
+ } else if ( slots < value . items . length ) {
266
+ // TODO: Allow this when going past end of list and end === undefined
267
+ throw VimError . fromCode ( ErrorCode . ListValueHasMoreItemsThanTarget ) ;
268
+ }
269
+ let i = start ;
270
+ for ( const item of value . items ) {
271
+ varValue . items [ i ] = item ;
272
+ ++ i ;
273
+ }
274
+ context . setVariable ( variable . variable , varValue , this . args . lock ) ;
224
275
}
225
276
}
226
277
}
0 commit comments