Skip to content

Added action insert #234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
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
62 changes: 62 additions & 0 deletions src/actions/Insert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import {
Action,
ActionPreferences,
ActionReturnValue,
Graph,
TextGenerator,
TypedSelection,
} from "../typings/Types";
import { displayPendingEditDecorationsForSelection } from "../util/editDisplayUtils";
import { runForEachEditor } from "../util/targetUtils";
import { flatten, zip } from "lodash";
import { maybeAddDelimiter } from "../util/getTextWithPossibleDelimiter";
import { performEditsAndUpdateSelections } from "../util/updateSelections";
import generateText from "../generateText";

export default class implements Action {
targetPreferences: ActionPreferences[] = [{ insideOutsideType: null }];

constructor(private graph: Graph) {
this.run = this.run.bind(this);
}

async run(
[targets]: [TypedSelection[]],
generator: TextGenerator
): Promise<ActionReturnValue> {
const texts = generateText(generator, targets.length);

const edits = zip(targets, texts).map(([target, text]) => ({
editor: target!.selection.editor,
range: target!.selection.selection,
text: maybeAddDelimiter(text!, target!),
extendOnEqualEmptyRange: true,
}));

const thatMark = flatten(
await runForEachEditor(
edits,
(edit) => edit.editor,
async (editor, edits) => {
const [updatedSelections] = await performEditsAndUpdateSelections(
editor,
edits,
[targets.map((target) => target.selection.selection)]
);

return updatedSelections.map((selection) => ({
editor,
selection,
}));
}
)
);

await displayPendingEditDecorationsForSelection(
thatMark,
this.graph.editStyles.justAdded.token
);

return { thatMark };
}
}
14 changes: 5 additions & 9 deletions src/actions/Replace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import {
ActionPreferences,
ActionReturnValue,
Graph,
TextGenerator,
TypedSelection,
} from "../typings/Types";
import displayPendingEditDecorations from "../util/editDisplayUtils";
import { runForEachEditor } from "../util/targetUtils";
import { flatten, zip } from "lodash";
import { maybeAddDelimiter } from "../util/getTextWithPossibleDelimiter";
import { performEditsAndUpdateSelections } from "../util/updateSelections";

type RangeGenerator = { start: number };
import generateText from "../generateText";

export default class implements Action {
targetPreferences: ActionPreferences[] = [{ insideOutsideType: null }];
Expand All @@ -22,7 +22,7 @@ export default class implements Action {

private getTexts(
targets: TypedSelection[],
replaceWith: string[] | RangeGenerator
replaceWith: string[] | TextGenerator
): string[] {
if (Array.isArray(replaceWith)) {
// Broadcast single text to each target
Expand All @@ -31,16 +31,12 @@ export default class implements Action {
}
return replaceWith;
}
const numbers = [];
for (let i = 0; i < targets.length; ++i) {
numbers[i] = (replaceWith.start + i).toString();
}
return numbers;
return generateText(replaceWith, targets.length);
}

async run(
[targets]: [TypedSelection[]],
replaceWith: string[] | RangeGenerator
replaceWith: string[] | TextGenerator
): Promise<ActionReturnValue> {
await displayPendingEditDecorations(
targets,
Expand Down
14 changes: 7 additions & 7 deletions src/actions/Wrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import {
TypedSelection,
} from "../typings/Types";
import { runOnTargetsForEachEditor } from "../util/targetUtils";
import { decorationSleep } from "../util/editDisplayUtils";
import { performEditsAndUpdateSelections } from "../util/updateSelections";
import { selectionWithEditorFromPositions } from "../util/selectionUtils";
import { displayPendingEditDecorationsForSelection } from "../util/editDisplayUtils";

export default class Wrap implements Action {
targetPreferences: ActionPreferences[] = [{ insideOutsideType: "inside" }];
Expand Down Expand Up @@ -68,13 +68,13 @@ export default class Wrap implements Action {
]
);

editor.setDecorations(
this.graph.editStyles.justAdded.token,
updatedSelections
await displayPendingEditDecorationsForSelection(
updatedSelections.map((selection) => ({
editor,
selection,
})),
this.graph.editStyles.justAdded.token
);
await decorationSleep();

editor.setDecorations(this.graph.editStyles.justAdded.token, []);

return targets.map((target, index) => {
const start = updatedSelections[index * 2].start;
Expand Down
2 changes: 2 additions & 0 deletions src/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { CopyLinesUp, CopyLinesDown } from "./CopyLines";
import SetBreakpoint from "./SetBreakpoint";
import { Sort, Reverse } from "./Sort";
import Call from "./Call";
import Insert from "./Insert";

class Actions implements ActionRecord {
constructor(private graph: Graph) {}
Expand All @@ -42,6 +43,7 @@ class Actions implements ActionRecord {
foldRegion = new Fold(this.graph);
getText = new GetText(this.graph);
indentLine = new IndentLines(this.graph);
insert = new Insert(this.graph);
insertCopyAfter = new CopyLinesDown(this.graph);
insertCopyBefore = new CopyLinesUp(this.graph);
insertEmptyLineAfter = new InsertEmptyLineBelow(this.graph);
Expand Down
21 changes: 21 additions & 0 deletions src/generateText.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { range } from "lodash";
import { pairDelimiterToText } from "./pairDelimiters";
import { TextGenerator } from "./typings/Types";

export default function (generator: TextGenerator, numTargets: number) {
switch (generator.type) {
case "range":
const { start } = generator;

return range(start, start + numTargets).map((num) => num.toString());

case "pair":
if (numTargets % 2 !== 0) {
throw new Error("Number of targets is not divisible by two");
}

const pairTexts = pairDelimiterToText[generator.pair];

return range(numTargets / 2).flatMap(() => pairTexts);
}
}
24 changes: 5 additions & 19 deletions src/languages/surroundingPair.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { maxBy, zip } from "lodash";
import { Position, Selection } from "vscode";
import { Point, SyntaxNode } from "web-tree-sitter";
import { PairDelimiter, pairDelimiterToText } from "../pairDelimiters";
import {
Delimiter,
NodeMatcher,
NodeMatcherValue,
SelectionWithEditor,
Expand All @@ -12,36 +11,23 @@ function positionFromPoint(point: Point): Position {
return new Position(point.row, point.column);
}

const delimiterToText: Record<Delimiter, string[]> = {
squareBrackets: ["[", "]"],
curlyBrackets: ["{", "}"],
angleBrackets: ["<", ">"],
parentheses: ["(", ")"],
singleQuotes: ["'", "'"],
doubleQuotes: ['"', '"'],
backtickQuotes: ["`", "`"],
whitespace: [" ", " "], // TODO: Fix this to handle tabs / newlines
escapedSingleQuotes: ["\\'", "\\'"],
escapedDoubleQuotes: ['\\"', '\\"'],
};

const leftToRightMap: Record<string, string> = Object.fromEntries(
Object.values(delimiterToText)
Object.values(pairDelimiterToText)
);

export function createSurroundingPairMatcher(
delimiter: Delimiter | null,
delimiter: PairDelimiter | null,
delimitersOnly: boolean
): NodeMatcher {
return function nodeMatcher(
selection: SelectionWithEditor,
node: SyntaxNode
) {
const delimitersToCheck =
delimiter == null ? Object.keys(delimiterToText) : [delimiter];
delimiter == null ? Object.keys(pairDelimiterToText) : [delimiter];

const leftDelimiterTypes = delimitersToCheck.map(
(delimiter) => delimiterToText[delimiter][0]
(delimiter) => pairDelimiterToText[delimiter][0]
);

const leftDelimiterNodes = node.children.filter(
Expand Down
24 changes: 24 additions & 0 deletions src/pairDelimiters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export type PairDelimiter =
| "angleBrackets"
| "backtickQuotes"
| "curlyBrackets"
| "doubleQuotes"
| "escapedSingleQuotes"
| "escapedDoubleQuotes"
| "parentheses"
| "singleQuotes"
| "squareBrackets"
| "whitespace";

export const pairDelimiterToText: Record<PairDelimiter, string[]> = {
angleBrackets: ["<", ">"],
backtickQuotes: ["`", "`"],
curlyBrackets: ["{", "}"],
doubleQuotes: ['"', '"'],
escapedDoubleQuotes: ['\\"', '\\"'],
escapedSingleQuotes: ["\\'", "\\'"],
parentheses: ["(", ")"],
singleQuotes: ["'", "'"],
squareBrackets: ["[", "]"],
whitespace: [" ", " "], // TODO: Fix this to handle tabs / newlines
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ command:
- type: primitive
mark: {type: decoratedSymbol, symbolColor: default, character: c}
extraArgs:
- {start: 0}
- {type: "range", start: 0}
marks:
default.a:
start: {line: 1, character: 0}
Expand Down
27 changes: 15 additions & 12 deletions src/typings/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Location } from "vscode";
import { HatStyleName } from "../core/constants";
import { EditStyles } from "../core/editStyles";
import NavigationMap from "../core/NavigationMap";
import { PairDelimiter } from "../pairDelimiters";

/**
* A token within a text editor, including the current display line of the token
Expand Down Expand Up @@ -61,17 +62,6 @@ export type Mark =
// | LastCursorPosition Not implemented yet
| DecoratedSymbol
| LineNumber;
export type Delimiter =
| "angleBrackets"
| "backtickQuotes"
| "curlyBrackets"
| "doubleQuotes"
| "escapedSingleQuotes"
| "escapedDoubleQuotes"
| "parentheses"
| "singleQuotes"
| "squareBrackets"
| "whitespace";

export type ScopeType =
| "argumentOrParameter"
Expand Down Expand Up @@ -102,7 +92,7 @@ export type SubTokenType = "word" | "character";

export interface SurroundingPairModifier {
type: "surroundingPair";
delimiter: Delimiter | null;
delimiter: PairDelimiter | null;
delimitersOnly: boolean;
}
export interface ContainingScopeModifier {
Expand Down Expand Up @@ -288,6 +278,7 @@ export type ActionType =
| "foldRegion"
| "getText"
| "indentLine"
| "insert"
| "insertCopyAfter"
| "insertCopyBefore"
| "insertEmptyLineAfter"
Expand Down Expand Up @@ -361,3 +352,15 @@ export interface Edit {
dontMoveOnEqualStart?: boolean;
extendOnEqualEmptyRange?: boolean;
}

export interface RangeGenerator {
type: "range";
start: number;
}

export interface PairGenerator {
type: "pair";
pair: PairDelimiter;
}

export type TextGenerator = RangeGenerator | PairGenerator;