Skip to content

Commit df3f7d5

Browse files
committed
Implement :unl[et]
1 parent 7872fb1 commit df3f7d5

File tree

4 files changed

+49
-12
lines changed

4 files changed

+49
-12
lines changed

src/cmd_line/commands/let.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// eslint-disable-next-line id-denylist
2-
import { alt, optWhitespace, Parser, sepBy, seq, string, whitespace } from 'parsimmon';
2+
import { alt, optWhitespace, Parser, sepBy, seq, seqMap, string, whitespace } from 'parsimmon';
33
import { VimState } from '../../state/vimState';
44
import { StatusBar } from '../../statusBar';
55
import { ExCommand } from '../../vimscript/exCommand';
@@ -283,3 +283,35 @@ export class LetCommand extends ExCommand {
283283
}
284284
}
285285
}
286+
287+
export class UnletCommand extends ExCommand {
288+
public static readonly argParser = seqMap(
289+
string('!').fallback(undefined),
290+
whitespace.then(variableParser.sepBy(whitespace)),
291+
(bang, variables) => {
292+
if (variables.length === 0) {
293+
throw VimError.fromCode(ErrorCode.ArgumentRequired);
294+
}
295+
return new UnletCommand(variables, bang !== undefined);
296+
},
297+
);
298+
299+
private variables: VariableExpression[];
300+
private bang: boolean;
301+
public constructor(variables: VariableExpression[], bang: boolean) {
302+
super();
303+
this.variables = variables;
304+
this.bang = bang;
305+
}
306+
307+
async execute(vimState: VimState): Promise<void> {
308+
const ctx = new EvaluationContext();
309+
for (const variable of this.variables) {
310+
const store = ctx.getVariableStore(variable.namespace);
311+
const existed = store?.delete(variable.name);
312+
if (!existed && !this.bang) {
313+
throw VimError.fromCode(ErrorCode.NoSuchVariable, `"${variable.name}"`);
314+
}
315+
}
316+
}
317+
}

src/error.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export enum ErrorCode {
1616
NoWriteSinceLastChange = 37,
1717
MultipleMatches = 93,
1818
NoMatchingBuffer = 94,
19+
NoSuchVariable = 108,
1920
MissingQuote = 114,
2021
UnknownFunction_call = 117,
2122
TooManyArgs = 118,
@@ -104,6 +105,7 @@ export const ErrorMessage: IErrorMessage = {
104105
37: 'No write since last change (add ! to override)',
105106
93: 'More than one match',
106107
94: 'No matching buffer',
108+
108: 'No such variable',
107109
114: 'Missing quote',
108110
117: 'Unknown function',
109111
118: 'Too many arguments for function',

src/vimscript/exCommandParser.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ import { StatusBar } from '../statusBar';
5151
import { ExCommand } from './exCommand';
5252
import { LineRange } from './lineRange';
5353
import { nameAbbrevParser } from './parserUtils';
54-
import { LetCommand } from '../cmd_line/commands/let';
54+
import { LetCommand, UnletCommand } from '../cmd_line/commands/let';
5555
import { CallCommand, EvalCommand } from '../cmd_line/commands/eval';
5656
import { PwdCommand } from '../cmd_line/commands/pwd';
5757

@@ -566,7 +566,7 @@ export const builtinExCommands: ReadonlyArray<[[string, string], ArgParser | und
566566
[['undoj', 'oin'], undefined],
567567
[['undol', 'ist'], undefined],
568568
[['unh', 'ide'], undefined],
569-
[['unl', 'et'], undefined],
569+
[['unl', 'et'], UnletCommand.argParser],
570570
[['unlo', 'ckvar'], undefined],
571571
[['unm', 'ap'], undefined],
572572
[['unme', 'nu'], undefined],

src/vimscript/expression/evaluate.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export class Variable {
127127
}
128128
}
129129

130-
type VariableStore = Map<string, Variable>;
130+
export type VariableStore = Map<string, Variable>;
131131

132132
export class EvaluationContext {
133133
private static globalVariables: VariableStore = new Map();
@@ -266,14 +266,7 @@ export class EvaluationContext {
266266
throw VimError.fromCode(ErrorCode.FuncrefVariableNameMustStartWithACapital, varExpr.name);
267267
}
268268

269-
let store: VariableStore | undefined;
270-
if (this.localScopes.length > 0 && varExpr.namespace === undefined) {
271-
store = this.localScopes.at(-1);
272-
} else if (varExpr.namespace === 'g' || varExpr.namespace === undefined) {
273-
store = EvaluationContext.globalVariables;
274-
} else {
275-
// TODO
276-
}
269+
const store = this.getVariableStore(varExpr.namespace);
277270

278271
if (store) {
279272
const _var = store.get(varExpr.name);
@@ -364,6 +357,16 @@ export class EvaluationContext {
364357
);
365358
}
366359

360+
public getVariableStore(namespace: string | undefined): VariableStore | undefined {
361+
if (this.localScopes.length > 0 && namespace === undefined) {
362+
return this.localScopes.at(-1);
363+
} else if (namespace === 'g' || namespace === undefined) {
364+
return EvaluationContext.globalVariables;
365+
}
366+
// TODO
367+
return undefined;
368+
}
369+
367370
private evaluateIndex(sequence: Value, index: Value): Value {
368371
switch (sequence.type) {
369372
case 'string':

0 commit comments

Comments
 (0)