Skip to content

Commit

Permalink
First pass assigning registers
Browse files Browse the repository at this point in the history
  • Loading branch information
danielglasgow committed Oct 17, 2024
1 parent 4cf0360 commit 1a52280
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 39 deletions.
26 changes: 22 additions & 4 deletions src/cmd_line/commands/let.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// eslint-disable-next-line id-denylist
import { alt, optWhitespace, Parser, seq, string, whitespace } from 'parsimmon';
import { env } from 'process';
import { ErrorCode, VimError } from '../../error';
import { Register, RegisterMode } from '../../register/register';
import { VimState } from '../../state/vimState';
import { StatusBar } from '../../statusBar';
import { ExCommand } from '../../vimscript/exCommand';
Expand All @@ -13,23 +15,23 @@ import {
str,
subtract,
} from '../../vimscript/expression/build';
import { EvaluationContext } from '../../vimscript/expression/evaluate';
import { displayValue } from '../../vimscript/expression/displayValue';
import { EvaluationContext, toString } from '../../vimscript/expression/evaluate';
import {
envVariableParser,
expressionParser,
optionParser,
registerParser,
variableParser,
} from '../../vimscript/expression/parser';
import { stringToRegisterMode } from '../../vimscript/expression/registerUtils';
import {
EnvVariableExpression,
Expression,
OptionExpression,
RegisterExpression,
VariableExpression,
} from '../../vimscript/expression/types';
import { displayValue } from '../../vimscript/expression/displayValue';
import { ErrorCode, VimError } from '../../error';

export type LetCommandOperation = '=' | '+=' | '-=' | '*=' | '/=' | '%=' | '.=' | '..=';
export type LetCommandVariable =
Expand Down Expand Up @@ -143,7 +145,23 @@ export class LetCommand extends ExCommand {
}
context.setVariable(variable, value, this.args.lock);
} else if (variable.type === 'register') {
// TODO
if (this.args.operation !== '=') {
throw VimError.fromCode(ErrorCode.InvalidOperationForRegister, this.args.operation);
}
let registerIndex = 0;
const items = value.type === 'list' ? value.items : [value];
for (const item of items) {
const registerMode =
item.type === 'register_val'
? stringToRegisterMode(item.registerMode)
: RegisterMode.CharacterWise;
Register.put(vimState, toString(value), registerIndex, /* copyToUnamed */ false, {
registerName: variable.name,
registerMode,
forceOverwrite: true,
});
registerIndex++;
}
} else if (variable.type === 'option') {
// TODO
} else if (variable.type === 'env_variable') {
Expand Down
8 changes: 8 additions & 0 deletions src/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ export enum ErrorCode {
UsingABlobAsANumber = 974,
CannotModifyExistingVariable = 995,
CannotLockARegister = 996,
CannotAccessClipboardRegister = 997,
UsingARegisterAsANumber = 998,
CannotAccessRecordedStateRegister = 999,
InvalidOperationForRegister = 1000,
}

export const ErrorMessage: IErrorMessage = {
Expand Down Expand Up @@ -162,6 +166,10 @@ export const ErrorMessage: IErrorMessage = {
974: 'Using a Blob as a Number',
995: 'Cannot modify existing variable',
996: 'Cannot lock a register',
997: 'Cannot access clipboard register',
998: 'Using a register as a Number',
999: 'Cannot access recorded state register',
1000: 'Invalid operation for register',
};

export class VimError extends Error {
Expand Down
60 changes: 41 additions & 19 deletions src/register/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,10 @@ export class Register {
vimState: VimState,
content: RegisterContent,
multicursorIndex?: number,
copyToUnnamed?: boolean,
copyToUnnamed?: boolean, // TODO: This should be a part of the options object
options: { registerName?: string; registerMode?: RegisterMode; forceOverwrite?: boolean } = {},
): void {
const register = vimState.recordedState.registerName;
const register = options.registerName || vimState.recordedState.registerName;

if (!Register.isValidRegister(register)) {
throw new Error(`Invalid register ${register}`);
Expand All @@ -67,17 +68,33 @@ export class Register {
return;
}

if (Register.isValidUppercaseRegister(register)) {
Register.appendToRegister(vimState, register.toLowerCase(), content, multicursorIndex ?? 0);
if (Register.isValidUppercaseRegister(register) && !options.forceOverwrite) {
Register.appendToRegister(
vimState,
Register.decapitalize(register),
content,
multicursorIndex ?? 0,
options.registerMode,
);
} else {
Register.overwriteRegister(vimState, register, content, multicursorIndex ?? 0);
Register.overwriteRegister(
vimState,
Register.decapitalize(register),
content,
multicursorIndex ?? 0,
options.registerMode,
);
}

if (copyToUnnamed && register !== '"') {
Register.registers.set('"', Register.registers.get(register)!);
}
}

private static decapitalize(register: string): string {
return Register.isValidUppercaseRegister(register) ? register.toLowerCase() : register;
}

public static isValidRegister(register: string): boolean {
return (
Register.isValidLowercaseRegister(register) ||
Expand All @@ -95,7 +112,7 @@ export class Register {
return registerName === '_';
}

private static isClipboardRegister(registerName: string): boolean {
public static isClipboardRegister(registerName: string): boolean {
return registerName === '*' || registerName === '+';
}

Expand All @@ -120,13 +137,14 @@ export class Register {
register: string,
content: RegisterContent,
multicursorIndex: number,
registerMode?: RegisterMode,
): void {
if (multicursorIndex === 0 || !Register.registers.has(register)) {
Register.registers.set(register, []);
}

Register.registers.get(register)![multicursorIndex] = {
registerMode: vimState.currentRegisterMode,
registerMode: registerMode || vimState.currentRegisterMode,
text: content,
};

Expand All @@ -149,6 +167,7 @@ export class Register {
register: string,
content: RegisterContent,
multicursorIndex: number,
registerMode?: RegisterMode,
): void {
if (!Register.registers.has(register)) {
Register.registers.set(register, []);
Expand All @@ -162,11 +181,13 @@ export class Register {
text: content,
};
} else {
// Line-wise trumps other RegisterModes
const registerMode =
vimState.currentRegisterMode === RegisterMode.LineWise
? RegisterMode.LineWise
: oldContent.registerMode;
if (!registerMode) {
// Line-wise trumps other RegisterModes
registerMode =
vimState.currentRegisterMode === RegisterMode.LineWise
? RegisterMode.LineWise
: oldContent.registerMode;
}
let newText: RegisterContent;
if (oldContent.text instanceof RecordedState || content instanceof RecordedState) {
newText = oldContent.text;
Expand Down Expand Up @@ -271,13 +292,7 @@ export class Register {
register: string,
multicursorIndex = 0,
): Promise<IRegisterContent | undefined> {
if (!Register.isValidRegister(register)) {
throw new Error(`Invalid register ${register}`);
}

register = register.toLowerCase();

const contentByCursor = Register.registers.get(register);
const contentByCursor = Register.getRegisterArray(register);

if (Register.isClipboardRegister(register)) {
const clipboardContent = (await Clipboard.Paste()).replace(/\r\n/g, '\n');
Expand All @@ -302,6 +317,13 @@ export class Register {
return contentByCursor?.[multicursorIndex];
}

public static getRegisterArray(register: string): IRegisterContent[] | undefined {
if (!Register.isValidRegister(register)) {
throw new Error(`Invalid register ${register}`);
}
return Register.registers.get(register.toLowerCase());
}

public static has(register: string): boolean {
return Register.registers.has(register);
}
Expand Down
36 changes: 24 additions & 12 deletions src/vimscript/expression/build.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import {
NumberValue,
Expression,
ListExpression,
UnaryExpression,
BinaryOp,
BinaryExpression,
FunctionCallExpression,
StringValue,
LambdaExpression,
VariableExpression,
Namespace,
BinaryOp,
BlobValue,
DictionaryValue,
Expression,
FloatValue,
FuncRefValue,
FunctionCallExpression,
LambdaExpression,
ListExpression,
ListValue,
DictionaryValue,
Namespace,
NumberValue,
RegisterValue,
StringValue,
UnaryExpression,
Value,
BlobValue,
VariableExpression,
} from './types';

export function int(value: number): NumberValue {
Expand Down Expand Up @@ -66,6 +67,17 @@ export function blob(data: ArrayBuffer): BlobValue {
};
}

export function register(
content: string,
registerMode: 'character' | 'line' | 'block',
): RegisterValue {
return {
type: 'register_val',
content,
registerMode,
};
}

export function listExpr(items: Expression[]): ListExpression {
return {
type: 'list',
Expand Down
2 changes: 2 additions & 0 deletions src/vimscript/expression/displayValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,7 @@ export function displayValue(value: Value, topLevel = true): string {
.join('')
.toUpperCase()
);
case 'register_val':
return `register('${value.content}', ${value.registerMode})`;
}
}
23 changes: 20 additions & 3 deletions src/vimscript/expression/evaluate.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { all } from 'parsimmon';
import { displayValue } from './displayValue';
import { configuration } from '../../configuration/configuration';
import { ErrorCode, VimError } from '../../error';
import { globalState } from '../../state/globalState';
import { bool, float, funcref, listExpr, int, str, list, funcCall, blob } from './build';
import { blob, bool, float, funcCall, funcref, int, list, listExpr, str } from './build';
import { displayValue } from './displayValue';
import { expressionParser, numberParser } from './parser';
import { lookupRegister } from './registerUtils';
import {
BinaryOp,
ComparisonOp,
Expand Down Expand Up @@ -43,6 +44,8 @@ function toInt(value: Value): number {
throw VimError.fromCode(ErrorCode.UsingAFuncrefAsANumber);
case 'blob':
throw VimError.fromCode(ErrorCode.UsingABlobAsANumber);
case 'register_val':
throw VimError.fromCode(ErrorCode.UsingARegisterAsANumber);
}
}

Expand All @@ -57,6 +60,7 @@ function toFloat(value: Value): number {
case 'dict_val':
case 'funcref':
case 'blob':
case 'register_val':
throw VimError.fromCode(ErrorCode.NumberOrFloatRequired);
}
}
Expand All @@ -77,6 +81,8 @@ export function toString(value: Value): string {
throw VimError.fromCode(ErrorCode.UsingFuncrefAsAString);
case 'blob':
return displayValue(value);
case 'register_val':
return value.content;
}
}

Expand All @@ -88,6 +94,7 @@ function toList(value: Value): ListValue {
case 'funcref':
case 'dict_val':
case 'blob':
case 'register_val':
throw VimError.fromCode(ErrorCode.ListRequired);
case 'list':
return value;
Expand All @@ -102,6 +109,7 @@ function toDict(value: Value): DictionaryValue {
case 'list':
case 'funcref':
case 'blob':
case 'register_val':
throw VimError.fromCode(ErrorCode.DictionaryRequired);
case 'dict_val':
return value;
Expand Down Expand Up @@ -147,6 +155,7 @@ export class EvaluationContext {
case 'dict_val':
case 'funcref':
case 'blob':
case 'register_val':
return expression;
case 'list':
return list(expression.items.map((x) => this.evaluate(x)));
Expand All @@ -168,7 +177,7 @@ export class EvaluationContext {
case 'variable':
return this.evaluateVariable(expression);
case 'register':
return str(''); // TODO
return lookupRegister(expression.name);
case 'option':
return str(''); // TODO
case 'env_variable':
Expand Down Expand Up @@ -395,6 +404,9 @@ export class EvaluationContext {
const bytes = new Uint8Array(sequence.data);
return int(bytes[toInt(index)]);
}
case 'register_val': {
return this.evaluateIndex(str(toString(sequence)), index);
}
}
}

Expand Down Expand Up @@ -438,6 +450,9 @@ export class EvaluationContext {
case 'blob': {
return blob(new Uint8Array(sequence.data).slice(_start, _end + 1));
}
case 'register_val': {
return this.evaluateSlice(str(toString(sequence)), start, end);
}
}
}

Expand Down Expand Up @@ -1281,6 +1296,8 @@ export class EvaluationContext {
// return int(7);
case 'blob':
return int(8);
case 'register_val':
return int(9);
default:
const guard: never = x;
throw new Error('type() got unexpected type');
Expand Down
Loading

0 comments on commit 1a52280

Please sign in to comment.