Skip to content

Commit ac4c153

Browse files
AndreasArvidssonpokeypre-commit-ci[bot]
authored
Implemented head tail modifier that works on multiple scope types (#708)
* Implemented head tail modifier that works on multiple scope types * Fixed test that broke in merge * Cleanup * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * More cleanup * More cleanup * More cleanup * Fixed line endings * Updated tests * Updated tests * Head and tail modifiers swallow all following modifiers * Updated tests * Cleanup * Cleanup * Switch head tail stage to use token target instead of plane target * Cleanup head tail stage * Reinstate doc string Co-authored-by: Pokey Rule <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 9c6678c commit ac4c153

28 files changed

+434
-97
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from talon import Module
2+
3+
head_tail_modifiers = {
4+
"head": "extendThroughStartOf",
5+
"tail": "extendThroughEndOf",
6+
}
7+
8+
mod = Module()
9+
10+
mod.list(
11+
"cursorless_head_tail_modifier",
12+
desc="Cursorless head and tail modifiers",
13+
)
14+
15+
16+
@mod.capture(rule="{user.cursorless_head_tail_modifier} <user.cursorless_modifier>*")
17+
def cursorless_head_tail_modifier(m) -> dict[str, str]:
18+
"""Cursorless head and tail modifier"""
19+
result = {
20+
"type": m.cursorless_head_tail_modifier,
21+
}
22+
try:
23+
result["modifiers"] = m.cursorless_modifier_list
24+
except AttributeError:
25+
pass
26+
return result

cursorless-talon/src/modifiers/modifiers.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from talon import Module, app
22

33
from ..csv_overrides import init_csv_and_watch_changes
4+
from .head_tail import head_tail_modifiers
45
from .range_type import range_types
56

67
mod = Module()
@@ -11,8 +12,6 @@
1112
"inside": "interiorOnly",
1213
"bounds": "excludeInterior",
1314
"just": "toRawSelection",
14-
"head": "extendThroughStartOf",
15-
"tail": "extendThroughEndOf",
1615
"leading": "leading",
1716
"trailing": "trailing",
1817
}
@@ -31,11 +30,28 @@ def cursorless_simple_modifier(m) -> dict[str, str]:
3130
}
3231

3332

33+
modifiers = [
34+
"<user.cursorless_position>", # before, end of
35+
"<user.cursorless_simple_modifier>", # inside, bounds, just, leading, trailing
36+
"<user.cursorless_head_tail_modifier>", # head, tail
37+
"<user.cursorless_containing_scope>", # funk, state, class
38+
"<user.cursorless_subtoken_scope>", # first past second word
39+
"<user.cursorless_surrounding_pair>", # matching/pair [curly, round]
40+
]
41+
42+
43+
@mod.capture(rule="|".join(modifiers))
44+
def cursorless_modifier(m) -> str:
45+
"""Cursorless modifier"""
46+
return m[0]
47+
48+
3449
def on_ready():
3550
init_csv_and_watch_changes(
3651
"modifiers",
3752
{
3853
"simple_modifier": simple_modifiers,
54+
"head_tail_modifier": head_tail_modifiers,
3955
"range_type": range_types,
4056
},
4157
)

cursorless-talon/src/primitive_target.py

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,6 @@
88
IMPLICIT_TARGET = {"type": "primitive", "isImplicit": True}
99

1010

11-
modifiers = [
12-
"<user.cursorless_position>", # before, end of
13-
"<user.cursorless_simple_modifier>", # eg inside, bounds, just, head, tail, leading, trailing
14-
"<user.cursorless_containing_scope>", # funk, state, class
15-
"<user.cursorless_subtoken_scope>", # first past second word
16-
"<user.cursorless_surrounding_pair>", # matching/pair [curly, round]
17-
]
18-
19-
20-
@mod.capture(rule="|".join(modifiers))
21-
def cursorless_modifier(m) -> str:
22-
"""Cursorless modifier"""
23-
return m[0]
24-
25-
2611
@mod.capture(
2712
rule="<user.cursorless_modifier>+ [<user.cursorless_mark>] | <user.cursorless_mark>"
2813
)

src/processTargets/marks/LineNumberStage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export default class implements MarkStage {
2222
const activeRange = editor.document.lineAt(activeLine).range;
2323
const contentRange = anchorRange.union(activeRange);
2424
const isReversed = this.modifier.anchor < this.modifier.active;
25-
return [createLineTarget(editor, contentRange, isReversed)];
25+
return [createLineTarget(editor, isReversed, contentRange)];
2626
}
2727
}
2828

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,69 @@
1-
import { Position, Range, TextEditor } from "vscode";
1+
import { Range, TextEditor } from "vscode";
22
import { Target } from "../../typings/target.types";
33
import {
4-
HeadModifier,
5-
TailModifier,
4+
HeadTailModifier,
5+
Modifier,
66
} from "../../typings/targetDescriptor.types";
77
import { ProcessedTargetsContext } from "../../typings/Types";
88
import { ModifierStage } from "../PipelineStages.types";
9-
import TokenTarget from "../targets/TokenTarget";
9+
import {
10+
getModifierStagesFromTargetModifiers,
11+
processModifierStages,
12+
} from "../processTargets";
13+
import { TokenTarget } from "../targets";
1014

1115
abstract class HeadTailStage implements ModifierStage {
12-
abstract update(editor: TextEditor, range: Range): Range;
13-
14-
constructor(private isReversed: boolean) {}
16+
constructor(private isReversed: boolean, private modifiers?: Modifier[]) {}
1517

1618
run(context: ProcessedTargetsContext, target: Target): Target[] {
17-
const contentRange = this.update(target.editor, target.contentRange);
18-
return [
19-
new TokenTarget({
19+
const modifiers = this.modifiers ?? [
20+
{
21+
type: "containingScope",
22+
scopeType: { type: "line" },
23+
},
24+
];
25+
26+
const modifierStages = getModifierStagesFromTargetModifiers(modifiers);
27+
const modifiedTargets = processModifierStages(context, modifierStages, [
28+
target,
29+
]);
30+
31+
return modifiedTargets.map((modifiedTarget) => {
32+
const contentRange = this.constructContentRange(
33+
target.contentRange,
34+
modifiedTarget.contentRange
35+
);
36+
37+
return new TokenTarget({
2038
editor: target.editor,
2139
isReversed: this.isReversed,
2240
contentRange,
23-
}),
24-
];
41+
});
42+
});
2543
}
44+
45+
protected abstract constructContentRange(
46+
originalRange: Range,
47+
modifiedRange: Range
48+
): Range;
2649
}
2750

2851
export class HeadStage extends HeadTailStage {
29-
constructor(private modifier: HeadModifier) {
30-
super(true);
52+
constructor(modifier: HeadTailModifier) {
53+
super(true, modifier.modifiers);
3154
}
3255

33-
update(editor: TextEditor, range: Range) {
34-
return new Range(new Position(range.start.line, 0), range.end);
56+
protected constructContentRange(originalRange: Range, modifiedRange: Range) {
57+
return new Range(modifiedRange.start, originalRange.end);
3558
}
3659
}
3760

3861
export class TailStage extends HeadTailStage {
39-
constructor(private modifier: TailModifier) {
40-
super(false);
62+
constructor(modifier: HeadTailModifier) {
63+
super(false, modifier.modifiers);
4164
}
4265

43-
update(editor: TextEditor, range: Range) {
44-
return new Range(range.start, editor.document.lineAt(range.end).range.end);
66+
protected constructContentRange(originalRange: Range, modifiedRange: Range) {
67+
return new Range(originalRange.start, modifiedRange.end);
4568
}
4669
}

src/processTargets/modifiers/scopeTypeStages/LineStage.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export default class implements ModifierStage {
1818
return [toLineTarget(target)];
1919
}
2020

21-
getEveryTarget(target: Target): LineTarget[] {
21+
private getEveryTarget(target: Target): LineTarget[] {
2222
const { contentRange, editor } = target;
2323
const { isEmpty } = contentRange;
2424
const startLine = isEmpty ? 0 : contentRange.start.line;
@@ -31,7 +31,7 @@ export default class implements ModifierStage {
3131
const line = editor.document.lineAt(i);
3232
if (!line.isEmptyOrWhitespace) {
3333
targets.push(
34-
createLineTarget(target.editor, line.range, target.isReversed)
34+
createLineTarget(target.editor, target.isReversed, line.range)
3535
);
3636
}
3737
}
@@ -46,18 +46,18 @@ export default class implements ModifierStage {
4646
}
4747
}
4848

49-
export function toLineTarget(target: Target): LineTarget {
49+
function toLineTarget(target: Target): LineTarget {
5050
return createLineTarget(
5151
target.editor,
52-
target.contentRange,
53-
target.isReversed
52+
target.isReversed,
53+
target.contentRange
5454
);
5555
}
5656

5757
export function createLineTarget(
5858
editor: TextEditor,
59-
range: Range,
60-
isReversed: boolean
59+
isReversed: boolean,
60+
range: Range
6161
) {
6262
return new LineTarget({
6363
editor,

src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export default class implements ModifierStage {
1919
return [this.getSingleTarget(target)];
2020
}
2121

22-
getEveryTarget(target: Target): ParagraphTarget[] {
22+
private getEveryTarget(target: Target): ParagraphTarget[] {
2323
const { contentRange, editor } = target;
2424
const { isEmpty } = contentRange;
2525
const { lineCount } = editor.document;
@@ -71,15 +71,11 @@ export default class implements ModifierStage {
7171
return targets;
7272
}
7373

74-
getSingleTarget(target: Target): ParagraphTarget {
75-
return this.getTargetFromRange(target);
74+
private getSingleTarget(target: Target): ParagraphTarget {
75+
return this.getTargetFromRange(target, calculateRange(target));
7676
}
7777

78-
getTargetFromRange(target: Target, range?: Range): ParagraphTarget {
79-
if (range == null) {
80-
range = calculateRange(target);
81-
}
82-
78+
private getTargetFromRange(target: Target, range: Range): ParagraphTarget {
8379
return new ParagraphTarget({
8480
editor: target.editor,
8581
isReversed: target.isReversed,

src/processTargets/modifiers/scopeTypeStages/RegexStage.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class RegexStage implements ModifierStage {
2424
return [this.getSingleTarget(target)];
2525
}
2626

27-
getEveryTarget(target: Target): ScopeTypeTarget[] {
27+
private getEveryTarget(target: Target): ScopeTypeTarget[] {
2828
const { contentRange, editor } = target;
2929
const { isEmpty } = contentRange;
3030
const start = isEmpty
@@ -55,24 +55,27 @@ class RegexStage implements ModifierStage {
5555
return targets;
5656
}
5757

58-
getSingleTarget(target: Target): ScopeTypeTarget {
58+
private getSingleTarget(target: Target): ScopeTypeTarget {
5959
const { editor } = target;
6060
const start = this.getMatchForPos(editor, target.contentRange.start).start;
6161
const end = this.getMatchForPos(editor, target.contentRange.end).end;
6262
const contentRange = new Range(start, end);
6363
return this.getTargetFromRange(target, contentRange);
6464
}
6565

66-
getTargetFromRange(target: Target, range: Range): ScopeTypeTarget {
66+
private getTargetFromRange(
67+
target: Target,
68+
contentRange: Range
69+
): ScopeTypeTarget {
6770
return new ScopeTypeTarget({
6871
scopeTypeType: this.modifier.scopeType.type,
6972
editor: target.editor,
7073
isReversed: target.isReversed,
71-
contentRange: range,
74+
contentRange,
7275
});
7376
}
7477

75-
getMatchForPos(editor: TextEditor, position: Position) {
78+
private getMatchForPos(editor: TextEditor, position: Position) {
7679
const match = this.getMatchesForLine(editor, position.line).find((range) =>
7780
range.contains(position)
7881
);
@@ -86,7 +89,7 @@ class RegexStage implements ModifierStage {
8689
return match;
8790
}
8891

89-
getMatchesForLine(editor: TextEditor, lineNum: number) {
92+
private getMatchesForLine(editor: TextEditor, lineNum: number) {
9093
const line = editor.document.lineAt(lineNum);
9194
const result = [...line.text.matchAll(this.regex)].map(
9295
(match) =>

src/processTargets/modifiers/scopeTypeStages/TokenStage.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export default class implements ModifierStage {
1919
return [this.getSingleTarget(target)];
2020
}
2121

22-
getEveryTarget(
22+
private getEveryTarget(
2323
context: ProcessedTargetsContext,
2424
target: Target
2525
): TokenTarget[] {
@@ -46,11 +46,11 @@ export default class implements ModifierStage {
4646
return targets;
4747
}
4848

49-
getSingleTarget(target: Target): TokenTarget {
49+
private getSingleTarget(target: Target): TokenTarget {
5050
return this.getTargetFromRange(target, target.contentRange);
5151
}
5252

53-
getTargetFromRange(target: Target, range: Range): TokenTarget {
53+
private getTargetFromRange(target: Target, range: Range): TokenTarget {
5454
const contentRange = getTokenRangeForSelection(target.editor, range);
5555
return new TokenTarget({
5656
editor: target.editor,

0 commit comments

Comments
 (0)