Skip to content

Implemented head tail modifier that works on multiple scope types #708

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

Merged
merged 23 commits into from
Jun 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
206d882
Implemented head tail modifier that works on multiple scope types
pokey Jun 7, 2022
e99e1c9
Merge branch 'main' into headTail
pokey Jun 7, 2022
6451364
Merge branch 'main' into headTail
AndreasArvidsson Jun 13, 2022
2d0fe2b
Fixed test that broke in merge
AndreasArvidsson Jun 13, 2022
148b435
Merge branch 'main' into headTail
AndreasArvidsson Jun 15, 2022
4c3d73f
Updated head tail modifier
AndreasArvidsson Jun 16, 2022
372952e
Cleanup
AndreasArvidsson Jun 16, 2022
fa30879
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 16, 2022
406c5f9
More cleanup
AndreasArvidsson Jun 16, 2022
2fbc676
Merge branch 'headTail' of github.com:pokey/cursorless-vscode into he…
AndreasArvidsson Jun 16, 2022
2aa8222
More cleanup
AndreasArvidsson Jun 16, 2022
00d0ed5
More cleanup
AndreasArvidsson Jun 16, 2022
9277be8
Fixed line endings
AndreasArvidsson Jun 16, 2022
aaf3f89
Updated tests
AndreasArvidsson Jun 16, 2022
9f8eac1
Updated tests
AndreasArvidsson Jun 16, 2022
0124280
Head and tail modifiers swallow all following modifiers
AndreasArvidsson Jun 17, 2022
db90689
Updated tests
AndreasArvidsson Jun 17, 2022
55d641e
Merge branch 'main' into headTail
AndreasArvidsson Jun 17, 2022
31a77b7
Cleanup
AndreasArvidsson Jun 18, 2022
a97be06
Cleanup
AndreasArvidsson Jun 18, 2022
2f04384
Switch head tail stage to use token target instead of plane target
pokey Jun 20, 2022
075db77
Cleanup head tail stage
pokey Jun 20, 2022
fc8550f
Reinstate doc string
pokey Jun 20, 2022
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
26 changes: 26 additions & 0 deletions cursorless-talon/src/modifiers/head_tail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from talon import Module

head_tail_modifiers = {
"head": "extendThroughStartOf",
"tail": "extendThroughEndOf",
}

mod = Module()

mod.list(
"cursorless_head_tail_modifier",
desc="Cursorless head and tail modifiers",
)


@mod.capture(rule="{user.cursorless_head_tail_modifier} <user.cursorless_modifier>*")
def cursorless_head_tail_modifier(m) -> dict[str, str]:
"""Cursorless head and tail modifier"""
result = {
"type": m.cursorless_head_tail_modifier,
}
try:
result["modifiers"] = m.cursorless_modifier_list
except AttributeError:
pass
return result
20 changes: 18 additions & 2 deletions cursorless-talon/src/modifiers/modifiers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from talon import Module, app

from ..csv_overrides import init_csv_and_watch_changes
from .head_tail import head_tail_modifiers
from .range_type import range_types

mod = Module()
Expand All @@ -11,8 +12,6 @@
"inside": "interiorOnly",
"bounds": "excludeInterior",
"just": "toRawSelection",
"head": "extendThroughStartOf",
"tail": "extendThroughEndOf",
"leading": "leading",
"trailing": "trailing",
}
Expand All @@ -31,11 +30,28 @@ def cursorless_simple_modifier(m) -> dict[str, str]:
}


modifiers = [
"<user.cursorless_position>", # before, end of
"<user.cursorless_simple_modifier>", # inside, bounds, just, leading, trailing
"<user.cursorless_head_tail_modifier>", # head, tail
"<user.cursorless_containing_scope>", # funk, state, class
"<user.cursorless_subtoken_scope>", # first past second word
"<user.cursorless_surrounding_pair>", # matching/pair [curly, round]
]


@mod.capture(rule="|".join(modifiers))
def cursorless_modifier(m) -> str:
"""Cursorless modifier"""
return m[0]


def on_ready():
init_csv_and_watch_changes(
"modifiers",
{
"simple_modifier": simple_modifiers,
"head_tail_modifier": head_tail_modifiers,
"range_type": range_types,
},
)
Expand Down
15 changes: 0 additions & 15 deletions cursorless-talon/src/primitive_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,6 @@
IMPLICIT_TARGET = {"type": "primitive", "isImplicit": True}


modifiers = [
"<user.cursorless_position>", # before, end of
"<user.cursorless_simple_modifier>", # eg inside, bounds, just, head, tail, leading, trailing
"<user.cursorless_containing_scope>", # funk, state, class
"<user.cursorless_subtoken_scope>", # first past second word
"<user.cursorless_surrounding_pair>", # matching/pair [curly, round]
]


@mod.capture(rule="|".join(modifiers))
def cursorless_modifier(m) -> str:
"""Cursorless modifier"""
return m[0]


@mod.capture(
rule="<user.cursorless_modifier>+ [<user.cursorless_mark>] | <user.cursorless_mark>"
)
Expand Down
2 changes: 1 addition & 1 deletion src/processTargets/marks/LineNumberStage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default class implements MarkStage {
const activeRange = editor.document.lineAt(activeLine).range;
const contentRange = anchorRange.union(activeRange);
const isReversed = this.modifier.anchor < this.modifier.active;
return [createLineTarget(editor, contentRange, isReversed)];
return [createLineTarget(editor, isReversed, contentRange)];
}
}

Expand Down
63 changes: 43 additions & 20 deletions src/processTargets/modifiers/HeadTailStage.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,69 @@
import { Position, Range, TextEditor } from "vscode";
import { Range, TextEditor } from "vscode";
import { Target } from "../../typings/target.types";
import {
HeadModifier,
TailModifier,
HeadTailModifier,
Modifier,
} from "../../typings/targetDescriptor.types";
import { ProcessedTargetsContext } from "../../typings/Types";
import { ModifierStage } from "../PipelineStages.types";
import TokenTarget from "../targets/TokenTarget";
import {
getModifierStagesFromTargetModifiers,
processModifierStages,
} from "../processTargets";
import { TokenTarget } from "../targets";

abstract class HeadTailStage implements ModifierStage {
abstract update(editor: TextEditor, range: Range): Range;

constructor(private isReversed: boolean) {}
constructor(private isReversed: boolean, private modifiers?: Modifier[]) {}

run(context: ProcessedTargetsContext, target: Target): Target[] {
const contentRange = this.update(target.editor, target.contentRange);
return [
new TokenTarget({
const modifiers = this.modifiers ?? [
{
type: "containingScope",
scopeType: { type: "line" },
},
];

const modifierStages = getModifierStagesFromTargetModifiers(modifiers);
const modifiedTargets = processModifierStages(context, modifierStages, [
target,
]);

return modifiedTargets.map((modifiedTarget) => {
const contentRange = this.constructContentRange(
target.contentRange,
modifiedTarget.contentRange
);

return new TokenTarget({
editor: target.editor,
isReversed: this.isReversed,
contentRange,
}),
];
});
});
}

protected abstract constructContentRange(
originalRange: Range,
modifiedRange: Range
): Range;
}

export class HeadStage extends HeadTailStage {
constructor(private modifier: HeadModifier) {
super(true);
constructor(modifier: HeadTailModifier) {
super(true, modifier.modifiers);
}

update(editor: TextEditor, range: Range) {
return new Range(new Position(range.start.line, 0), range.end);
protected constructContentRange(originalRange: Range, modifiedRange: Range) {
return new Range(modifiedRange.start, originalRange.end);
}
}

export class TailStage extends HeadTailStage {
constructor(private modifier: TailModifier) {
super(false);
constructor(modifier: HeadTailModifier) {
super(false, modifier.modifiers);
}

update(editor: TextEditor, range: Range) {
return new Range(range.start, editor.document.lineAt(range.end).range.end);
protected constructContentRange(originalRange: Range, modifiedRange: Range) {
return new Range(originalRange.start, modifiedRange.end);
}
}
14 changes: 7 additions & 7 deletions src/processTargets/modifiers/scopeTypeStages/LineStage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default class implements ModifierStage {
return [toLineTarget(target)];
}

getEveryTarget(target: Target): LineTarget[] {
private getEveryTarget(target: Target): LineTarget[] {
const { contentRange, editor } = target;
const { isEmpty } = contentRange;
const startLine = isEmpty ? 0 : contentRange.start.line;
Expand All @@ -31,7 +31,7 @@ export default class implements ModifierStage {
const line = editor.document.lineAt(i);
if (!line.isEmptyOrWhitespace) {
targets.push(
createLineTarget(target.editor, line.range, target.isReversed)
createLineTarget(target.editor, target.isReversed, line.range)
);
}
}
Expand All @@ -46,18 +46,18 @@ export default class implements ModifierStage {
}
}

export function toLineTarget(target: Target): LineTarget {
function toLineTarget(target: Target): LineTarget {
return createLineTarget(
target.editor,
target.contentRange,
target.isReversed
target.isReversed,
target.contentRange
);
}

export function createLineTarget(
editor: TextEditor,
range: Range,
isReversed: boolean
isReversed: boolean,
range: Range
) {
return new LineTarget({
editor,
Expand Down
12 changes: 4 additions & 8 deletions src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default class implements ModifierStage {
return [this.getSingleTarget(target)];
}

getEveryTarget(target: Target): ParagraphTarget[] {
private getEveryTarget(target: Target): ParagraphTarget[] {
const { contentRange, editor } = target;
const { isEmpty } = contentRange;
const { lineCount } = editor.document;
Expand Down Expand Up @@ -71,15 +71,11 @@ export default class implements ModifierStage {
return targets;
}

getSingleTarget(target: Target): ParagraphTarget {
return this.getTargetFromRange(target);
private getSingleTarget(target: Target): ParagraphTarget {
return this.getTargetFromRange(target, calculateRange(target));
}

getTargetFromRange(target: Target, range?: Range): ParagraphTarget {
if (range == null) {
range = calculateRange(target);
}

private getTargetFromRange(target: Target, range: Range): ParagraphTarget {
return new ParagraphTarget({
editor: target.editor,
isReversed: target.isReversed,
Expand Down
15 changes: 9 additions & 6 deletions src/processTargets/modifiers/scopeTypeStages/RegexStage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class RegexStage implements ModifierStage {
return [this.getSingleTarget(target)];
}

getEveryTarget(target: Target): ScopeTypeTarget[] {
private getEveryTarget(target: Target): ScopeTypeTarget[] {
const { contentRange, editor } = target;
const { isEmpty } = contentRange;
const start = isEmpty
Expand Down Expand Up @@ -55,24 +55,27 @@ class RegexStage implements ModifierStage {
return targets;
}

getSingleTarget(target: Target): ScopeTypeTarget {
private getSingleTarget(target: Target): ScopeTypeTarget {
const { editor } = target;
const start = this.getMatchForPos(editor, target.contentRange.start).start;
const end = this.getMatchForPos(editor, target.contentRange.end).end;
const contentRange = new Range(start, end);
return this.getTargetFromRange(target, contentRange);
}

getTargetFromRange(target: Target, range: Range): ScopeTypeTarget {
private getTargetFromRange(
target: Target,
contentRange: Range
): ScopeTypeTarget {
return new ScopeTypeTarget({
scopeTypeType: this.modifier.scopeType.type,
editor: target.editor,
isReversed: target.isReversed,
contentRange: range,
contentRange,
});
}

getMatchForPos(editor: TextEditor, position: Position) {
private getMatchForPos(editor: TextEditor, position: Position) {
const match = this.getMatchesForLine(editor, position.line).find((range) =>
range.contains(position)
);
Expand All @@ -86,7 +89,7 @@ class RegexStage implements ModifierStage {
return match;
}

getMatchesForLine(editor: TextEditor, lineNum: number) {
private getMatchesForLine(editor: TextEditor, lineNum: number) {
const line = editor.document.lineAt(lineNum);
const result = [...line.text.matchAll(this.regex)].map(
(match) =>
Expand Down
6 changes: 3 additions & 3 deletions src/processTargets/modifiers/scopeTypeStages/TokenStage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default class implements ModifierStage {
return [this.getSingleTarget(target)];
}

getEveryTarget(
private getEveryTarget(
context: ProcessedTargetsContext,
target: Target
): TokenTarget[] {
Expand All @@ -46,11 +46,11 @@ export default class implements ModifierStage {
return targets;
}

getSingleTarget(target: Target): TokenTarget {
private getSingleTarget(target: Target): TokenTarget {
return this.getTargetFromRange(target, target.contentRange);
}

getTargetFromRange(target: Target, range: Range): TokenTarget {
private getTargetFromRange(target: Target, range: Range): TokenTarget {
const contentRange = getTokenRangeForSelection(target.editor, range);
return new TokenTarget({
editor: target.editor,
Expand Down
Loading