Skip to content

Commit 3a21025

Browse files
committed
getpos(), line(), and col()
1 parent c907bf1 commit 3a21025

File tree

6 files changed

+60
-10
lines changed

6 files changed

+60
-10
lines changed

src/cmd_line/commands/echo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class EchoCommand extends ExCommand {
2929
}
3030

3131
public async execute(vimState: VimState): Promise<void> {
32-
const ctx = new EvaluationContext();
32+
const ctx = new EvaluationContext(vimState);
3333
const values = this.expressions.map((x) => ctx.evaluate(x));
3434
const message = values.map((v) => displayValue(v)).join(this.sep);
3535
StatusBar.setText(vimState, message, this.error);

src/cmd_line/commands/eval.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export class EvalCommand extends ExCommand {
1717
}
1818

1919
public async execute(vimState: VimState): Promise<void> {
20-
const ctx = new EvaluationContext();
20+
const ctx = new EvaluationContext(vimState);
2121
ctx.evaluate(this.expression);
2222
}
2323
}
@@ -34,7 +34,7 @@ export class CallCommand extends ExCommand {
3434
}
3535

3636
public async execute(vimState: VimState): Promise<void> {
37-
const ctx = new EvaluationContext();
37+
const ctx = new EvaluationContext(vimState);
3838
ctx.evaluate(this.expression);
3939
}
4040
}

src/cmd_line/commands/let.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ export class LetCommand extends ExCommand {
154154
}
155155

156156
async execute(vimState: VimState): Promise<void> {
157-
const context = new EvaluationContext();
157+
const context = new EvaluationContext(vimState);
158158
if (this.args.operation === 'print') {
159159
if (this.args.variables.length === 0) {
160160
// TODO
@@ -306,7 +306,7 @@ export class UnletCommand extends ExCommand {
306306
}
307307

308308
async execute(vimState: VimState): Promise<void> {
309-
const ctx = new EvaluationContext();
309+
const ctx = new EvaluationContext(vimState);
310310
for (const variable of this.variables) {
311311
const store = ctx.getVariableStore(variable.namespace);
312312
const existed = store?.delete(variable.name);

src/cmd_line/commands/put.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export class PutExCommand extends ExCommand {
6767

6868
this.arguments.register = '=';
6969

70-
const value = new EvaluationContext().evaluate(this.arguments.fromExpression);
70+
const value = new EvaluationContext(vimState).evaluate(this.arguments.fromExpression);
7171
const stringified =
7272
value.type === 'list' ? value.items.map(toString).join('\n') : toString(value);
7373
Register.overwriteRegister(vimState, this.arguments.register, stringified, 0);

src/vimscript/expression/evaluate.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ import {
3232
} from './types';
3333
import { Pattern, SearchDirection } from '../pattern';
3434
import { escapeRegExp, isInteger } from 'lodash';
35-
import { integerParser } from '../parserUtils';
35+
import { VimState } from '../../state/vimState';
36+
import { Position } from 'vscode';
37+
import { isVisualMode } from '../../mode/mode';
3638

3739
// ID of next lambda; incremented each time one is created
3840
let lambdaNumber = 1;
@@ -146,9 +148,14 @@ export type VariableStore = Map<string, Variable>;
146148
export class EvaluationContext {
147149
private static globalVariables: VariableStore = new Map();
148150

151+
private vimState: VimState | undefined;
149152
private localScopes: VariableStore[] = [];
150153
private errors: string[] = [];
151154

155+
constructor(vimState: VimState | undefined) {
156+
this.vimState = vimState;
157+
}
158+
152159
/**
153160
* Fully evaluates the given expression and returns the resulting value.
154161
* May throw a variety of VimErrors if the expression is semantically invalid.
@@ -677,6 +684,33 @@ export class EvaluationContext {
677684
this.errors.push(msg);
678685
return int(1);
679686
};
687+
688+
const getpos = (arg: string) => {
689+
const pos: Position | undefined = (() => {
690+
if (arg === '.') {
691+
return this.vimState!.cursorStopPosition;
692+
} else if (arg === '$') {
693+
return new Position(this.vimState!.document.lineCount, 0);
694+
} else if (arg.startsWith("'") && arg.length === 2) {
695+
const mark = this.vimState!.historyTracker.getMark(arg[1]);
696+
return mark?.position;
697+
} else if (arg === 'w0') {
698+
return new Position(this.vimState!.editor.visibleRanges[0].start.line, 0);
699+
} else if (arg === 'w$') {
700+
return new Position(this.vimState!.editor.visibleRanges[0].end.line, 0);
701+
} else if (arg === 'v') {
702+
return this.vimState!.cursorStartPosition;
703+
}
704+
return undefined;
705+
})();
706+
return {
707+
bufnum: 0, // TODO
708+
lnum: (pos?.line ?? -1) + 1,
709+
col: (pos?.character ?? -1) + 1,
710+
off: 0,
711+
};
712+
};
713+
680714
const getArgs = (min: number, max?: number) => {
681715
if (max === undefined) {
682716
max = min;
@@ -830,6 +864,10 @@ export class EvaluationContext {
830864
const [x] = getArgs(1);
831865
return float(Math.ceil(toFloat(x!)));
832866
}
867+
case 'col': {
868+
const [s] = getArgs(1);
869+
return int(getpos(toString(s!)).col);
870+
}
833871
case 'copy': {
834872
const [x] = getArgs(1);
835873
switch (x?.type) {
@@ -891,6 +929,7 @@ export class EvaluationContext {
891929
}
892930
return int(count);
893931
}
932+
// TODO: cursor()
894933
case 'deepcopy': {
895934
// TODO: real deep copy once references are implemented
896935
const [x] = getArgs(1);
@@ -1028,6 +1067,11 @@ export class EvaluationContext {
10281067
}
10291068
// TODO: getcurpos()
10301069
// TODO: getline()
1070+
case 'getpos': {
1071+
const [s] = getArgs(1);
1072+
const { bufnum, lnum, col, off } = getpos(toString(s!));
1073+
return list([int(bufnum), int(lnum), int(col), int(off)]);
1074+
}
10311075
// TODO: getreg()
10321076
// TODO: getreginfo()
10331077
// TODO: getregtype()
@@ -1199,6 +1243,10 @@ export class EvaluationContext {
11991243
throw VimError.fromCode(ErrorCode.InvalidTypeForLen);
12001244
}
12011245
}
1246+
case 'line': {
1247+
const [s, winid] = getArgs(1, 2);
1248+
return int(getpos(toString(s!)).lnum);
1249+
}
12021250
case 'localtime': {
12031251
return int(Date.now() / 1000);
12041252
}
@@ -1354,6 +1402,7 @@ export class EvaluationContext {
13541402
// Halfway between integers, Math.round() rounds toward infinity while Vim's round() rounds away from 0.
13551403
return float(_x < 0 ? -Math.round(-_x) : Math.round(_x));
13561404
}
1405+
// TODO: setpos()
13571406
// TODO: setreg()
13581407
case 'sin': {
13591408
const [x] = getArgs(1);
@@ -1476,6 +1525,7 @@ export class EvaluationContext {
14761525
const [x] = getArgs(1);
14771526
return float(Math.tanh(toFloat(x!)));
14781527
}
1528+
// TODO: timer*()
14791529
case 'tolower': {
14801530
const [s] = getArgs(1);
14811531
return str(toString(s!).toLowerCase());

test/vimscript/expression.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ function exprTest(
3232
assert.deepStrictEqual(expression, asserts.expr);
3333
}
3434
if ('error' in asserts) {
35-
const ctx = new EvaluationContext();
35+
const ctx = new EvaluationContext(undefined);
3636
ctx.evaluate(expression);
3737
} else {
3838
if (asserts.value !== undefined) {
39-
const ctx = new EvaluationContext();
39+
const ctx = new EvaluationContext(undefined);
4040
assert.deepStrictEqual(ctx.evaluate(expression), asserts.value);
4141
}
4242
if (asserts.display !== undefined) {
43-
const ctx = new EvaluationContext();
43+
const ctx = new EvaluationContext(undefined);
4444
assert.deepStrictEqual(displayValue(ctx.evaluate(expression)), asserts.display);
4545
}
4646
}

0 commit comments

Comments
 (0)