Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified codeflea-2.1.1.vsix
Binary file not shown.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

127 changes: 66 additions & 61 deletions package.json

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions src/CodeFleaManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,11 @@ export default class CodeFleaManager {
this.setUI();
}

async fastSkip(direction: common.Direction) {
await this.mode.fastSkip(direction);
this.setUI();
}

async skipOver(direction: common.Direction) {
await this.mode.skipOver(direction);
this.setUI();
Expand Down
6 changes: 6 additions & 0 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,12 @@ export const registeredCommands: ExtensionCommand[] = [
await manager.skip(Direction.forwards);
},
},
{
id: "codeFlea.fastSkip",
execute: async (manager) => {
await manager.fastSkip(Direction.forwards);
},
},
{
id: "codeFlea.skipBackwards",
execute: async (manager) => {
Expand Down
43 changes: 43 additions & 0 deletions src/modes/CommandMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import SubjectBase from "../subjects/SubjectBase";
import { SubjectAction } from "../subjects/SubjectActions";
import JumpInterface from "../handlers/JumpInterface";
import { SubjectName } from "../subjects/SubjectName";
import { InlineInput } from '../utils/inlineInput';

export default class CommandMode extends modes.EditorMode {
private lastSkip: common.Skip | undefined = undefined;
Expand Down Expand Up @@ -183,6 +184,7 @@ export default class CommandMode extends modes.EditorMode {
await this.subject.fixSelection(half);
}


async skip(direction: common.Direction): Promise<void> {
const skipChar = await editor.inputBoxChar(
`Skip ${direction} to a ${this.subject.name} by its first character`
Expand All @@ -197,6 +199,47 @@ export default class CommandMode extends modes.EditorMode {
await this.subject.skip(direction, this.lastSkip);
}

async fastSkip(direction: common.Direction): Promise<void> {
await new Promise<void>((resolve) => {
const handleInput = async (_: string, char: common.Char) => {
if (this.subject.name === "WORD" && !/[a-zA-Z0-9_]/.test(char)) {
const newMode = await this.changeTo({ kind: "COMMAND", subjectName: "CHAR" });
if (newMode instanceof CommandMode) {
const skip: common.Skip = {
kind: "SkipTo",
char,
};
this.lastSkip = { kind: "SkipOver", char: char };
await newMode.subject.skip(direction, skip);
}
} else {
const skip: common.Skip = {
kind: "SkipTo",
char,

};
this.lastSkip = { kind: "SkipOver", char: char };
await this.subject.skip(direction, skip);
}

resolve();
};

const inlineInput = new InlineInput({
textEditor: this.context.editor,
onInput: handleInput,
onCancel: async () => {
resolve();
}
});

inlineInput.updateStatusBar(
`Skip ${direction} to ${this.subject.displayName} by first character`,
0
);
});
}

async skipOver(direction: common.Direction): Promise<void> {
const skipChar = await editor.inputBoxChar(
`Skip ${direction} over the given character to the next ${this.subject.name}`,
Expand Down
4 changes: 4 additions & 0 deletions src/modes/ExtendMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ export default class ExtendMode extends EditorMode {
await this.extendSelections(() => this.wrappedMode.skip(direction));
}

async fastSkip(direction: common.Direction) {
await this.extendSelections(() => this.wrappedMode.skip(direction)); // just use normal skip
}

async skipOver(direction: common.Direction) {
await this.extendSelections(() => this.wrappedMode.skipOver(direction));
}
Expand Down
1 change: 1 addition & 0 deletions src/modes/InsertMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export default class InsertMode extends EditorMode {
async executeSubjectCommand() {}
async repeatLastSkip() {}
async skip() {}
async fastSkip() {}
async skipOver() {}
async jump() {}
async jumpToSubject() { return undefined; }
Expand Down
1 change: 1 addition & 0 deletions src/modes/NullMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export default class NullMode extends EditorMode {

async executeSubjectCommand() {}
async skip() {}
async fastSkip() {}
async skipOver() {}
async repeatLastSkip() {}
async jump() {}
Expand Down
1 change: 1 addition & 0 deletions src/modes/modes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export abstract class EditorMode implements vscode.Disposable {
abstract executeSubjectCommand(command: SubjectAction): Promise<void>;

abstract skip(direction: Direction): Promise<void>;
abstract fastSkip(direction: Direction): Promise<void>;
abstract skipOver(direction: string): Promise<void>;
abstract repeatLastSkip(direction: Direction): Promise<void>;
abstract jump(): Promise<void>;
Expand Down
68 changes: 68 additions & 0 deletions src/utils/inlineInput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Mostly from https://github.com/usernamehw/vscode-find-jump/blob/master/src/inlineInput.ts

import { commands, Disposable, StatusBarAlignment, StatusBarItem, TextEditor, window } from 'vscode';
import { Char } from '../common';
import * as vscode from "vscode";

const cancellationChars = new Set('\n');
const subscriptions: Disposable[] = [];

export class InlineInput {
private statusBarItem: StatusBarItem;
private input = '';

constructor(private readonly props: {
textEditor: TextEditor;
onInput(input: string, char: Char): void;
onCancel(...args: any[]): void;
}) {
subscriptions.push(
commands.registerCommand('type', this._onInput),
window.onDidChangeTextEditorSelection(this._onCancel),
);

vscode.commands.executeCommand('setContext', 'codeFlea.waitingForChar', true);
this.statusBarItem = window.createStatusBarItem(
StatusBarAlignment.Right,
1000
);
}

public updateStatusBar = (text: string, numberOfMatches: number, activityIndicatorState?: boolean): void => {
if (activityIndicatorState !== undefined) {
const indicator = activityIndicatorState ? '⚪' : '🔴';
this.statusBarItem.text = `${numberOfMatches} ░ ${text} ░ ${indicator}`;
} else {
this.statusBarItem.text = `$(search) ${text}`;
}
this.statusBarItem.show();
};

public destroy = (): void => {
this.statusBarItem.dispose();
subscriptions.forEach(subscription => subscription.dispose());
vscode.commands.executeCommand('setContext', 'codeFlea.waitingForChar', false);
};

public deleteLastCharacter = (): string => {
this.input = this.input.slice(0, -1);
return this.input;
};

private readonly _onInput = ({ text }: { text: string }) => {
if (text.length !== 1) return;
const char = text as Char; // Now we know it's length 1
this.input += char;

if (cancellationChars.has(char)) {
this._onCancel();
} else {
return this.props.onInput(this.input, char);
}
};

private readonly _onCancel = (...args: any[]) => {
this.destroy();
return this.props.onCancel(args);
};
}