Skip to content

Commit 206d882

Browse files
committed
Implemented head tail modifier that works on multiple scope types
1 parent 2ee7ca1 commit 206d882

14 files changed

+124
-22
lines changed
Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,40 @@
1-
import { Position, Range, TextEditor } from "vscode";
1+
import { Range, TextEditor } from "vscode";
22
import { Target } from "../../typings/target.types";
33
import {
44
HeadModifier,
55
TailModifier,
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 PlainTarget from "../targets/PlainTarget";
10+
import { toLineTarget } from "./scopeTypeStages/LineStage";
1011

1112
abstract class HeadTailStage implements ModifierStage {
12-
abstract update(editor: TextEditor, range: Range): Range;
13+
abstract update(
14+
editor: TextEditor,
15+
previousRange: Range,
16+
nextRange: Range
17+
): Range;
1318

1419
constructor(private isReversed: boolean) {}
1520

1621
run(context: ProcessedTargetsContext, target: Target): Target[] {
17-
const contentRange = this.update(target.editor, target.contentRange);
22+
const { previousRange, nextRange } = (() => {
23+
if (target.previousTarget != null) {
24+
return {
25+
previousRange: target.previousTarget.contentRange,
26+
nextRange: target.contentRange,
27+
};
28+
}
29+
return {
30+
previousRange: target.contentRange,
31+
nextRange: toLineTarget(target).contentRange,
32+
};
33+
})();
34+
35+
const contentRange = this.update(target.editor, previousRange, nextRange);
1836
return [
19-
new TokenTarget({
37+
new PlainTarget({
2038
editor: target.editor,
2139
isReversed: this.isReversed,
2240
contentRange,
@@ -30,8 +48,8 @@ export class HeadStage extends HeadTailStage {
3048
super(true);
3149
}
3250

33-
update(editor: TextEditor, range: Range) {
34-
return new Range(new Position(range.start.line, 0), range.end);
51+
update(editor: TextEditor, previousRange: Range, nextRange: Range) {
52+
return new Range(nextRange.start, previousRange.end);
3553
}
3654
}
3755

@@ -40,7 +58,7 @@ export class TailStage extends HeadTailStage {
4058
super(false);
4159
}
4260

43-
update(editor: TextEditor, range: Range) {
44-
return new Range(range.start, editor.document.lineAt(range.end).range.end);
61+
update(editor: TextEditor, previousRange: Range, nextRange: Range) {
62+
return new Range(previousRange.start, nextRange.end);
4563
}
4664
}

src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ export default class OrdinalRangeSubTokenStage implements ModifierStage {
130130
insertionDelimiter,
131131
leadingDelimiterRange,
132132
trailingDelimiterRange,
133+
previousTarget: target,
133134
}),
134135
];
135136
}

src/processTargets/modifiers/SurroundingPairStage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ function processedSurroundingPairTarget(
5050
...pairInfo,
5151
editor: target.editor,
5252
isReversed: target.isReversed,
53+
previousTarget: target,
5354
}),
5455
];
5556
}

src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ export default class implements ModifierStage {
3232
) {}
3333

3434
run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget[] {
35+
const isEveryScope = this.modifier.type === "everyScope";
36+
3537
const nodeMatcher = getNodeMatcher(
3638
target.editor.document.languageId,
3739
this.modifier.scopeType.type,
38-
this.modifier.type === "everyScope"
40+
isEveryScope
3941
);
4042

4143
const node: SyntaxNode | null = context.getNodeAtLocation(
@@ -82,6 +84,7 @@ export default class implements ModifierStage {
8284
delimiter: containingListDelimiter,
8385
leadingDelimiterRange,
8486
trailingDelimiterRange,
87+
previousTarget: isEveryScope ? undefined : target,
8588
});
8689
});
8790
}

src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export default class implements ModifierStage {
1717
editor: target.editor,
1818
isReversed: target.isReversed,
1919
contentRange: getDocumentRange(target.editor),
20+
previousTarget: target,
2021
}),
2122
];
2223
}

src/processTargets/modifiers/scopeTypeStages/LineStage.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,12 @@ export default class implements ModifierStage {
4747
}
4848

4949
export function toLineTarget(target: Target): LineTarget {
50-
return createLineTarget(
51-
target.editor,
52-
target.contentRange,
53-
target.isReversed
54-
);
50+
return new LineTarget({
51+
editor: target.editor,
52+
isReversed: target.isReversed,
53+
contentRange: fitRangeToLineContent(target.editor, target.contentRange),
54+
previousTarget: target,
55+
});
5556
}
5657

5758
export function createLineTarget(

src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,16 @@ export default class implements ModifierStage {
7272
}
7373

7474
getSingleTarget(target: Target): ParagraphTarget {
75-
return this.getTargetFromRange(target);
75+
const range = calculateRange(target);
76+
return new ParagraphTarget({
77+
editor: target.editor,
78+
isReversed: target.isReversed,
79+
contentRange: fitRangeToLineContent(target.editor, range),
80+
previousTarget: target,
81+
});
7682
}
7783

78-
getTargetFromRange(target: Target, range?: Range): ParagraphTarget {
79-
if (range == null) {
80-
range = calculateRange(target);
81-
}
82-
84+
getTargetFromRange(target: Target, range: Range): ParagraphTarget {
8385
return new ParagraphTarget({
8486
editor: target.editor,
8587
isReversed: target.isReversed,

src/processTargets/modifiers/scopeTypeStages/RegexStage.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,13 @@ class RegexStage implements ModifierStage {
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);
63-
return this.getTargetFromRange(target, contentRange);
63+
return new ScopeTypeTarget({
64+
scopeTypeType: this.modifier.scopeType.type,
65+
editor: target.editor,
66+
isReversed: target.isReversed,
67+
contentRange,
68+
previousTarget: target,
69+
});
6470
}
6571

6672
getTargetFromRange(target: Target, range: Range): ScopeTypeTarget {

src/processTargets/targets/BaseTarget.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export interface CommonTargetParameters {
1515
readonly isReversed: boolean;
1616
readonly contentRange: Range;
1717
readonly thatTarget?: Target;
18+
readonly previousTarget?: Target;
1819
}
1920

2021
export interface CloneWithParameters {
@@ -35,6 +36,7 @@ export default abstract class BaseTarget implements Target {
3536
isReversed: parameters.isReversed,
3637
contentRange: parameters.contentRange,
3738
thatTarget: parameters.thatTarget,
39+
previousTarget: parameters.previousTarget,
3840
};
3941
}
4042

@@ -51,6 +53,10 @@ export default abstract class BaseTarget implements Target {
5153
: this;
5254
}
5355

56+
get previousTarget(): Target | undefined {
57+
return this.state.previousTarget;
58+
}
59+
5460
get contentText(): string {
5561
return this.editor.document.getText(this.contentRange);
5662
}

src/processTargets/targets/SurroundingPairTarget.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export default class SurroundingPairTarget extends BaseTarget {
5252
editor: this.editor,
5353
isReversed: this.isReversed,
5454
contentRange: this.interiorRange_,
55+
previousTarget: this.previousTarget,
5556
}),
5657
];
5758
}

src/test/suite/fixtures/recorded/compoundTargets/takeLineVestAndAir.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,6 @@ finalState:
3131
thatMark:
3232
- anchor: {line: 0, character: 4}
3333
active: {line: 0, character: 17}
34+
- anchor: {line: 0, character: 4}
35+
active: {line: 0, character: 17}
3436
fullTargets: [{type: list, elements: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, selectionType: line, position: contents, insideOutsideType: inside, modifier: {type: identity}}, {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: a}, selectionType: line, position: contents, insideOutsideType: inside, modifier: {type: identity}}]}]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
languageId: plaintext
2+
command:
3+
spokenForm: clear head core
4+
version: 2
5+
targets:
6+
- type: primitive
7+
modifiers:
8+
- {type: head}
9+
- {type: interiorOnly}
10+
usePrePhraseSnapshot: true
11+
action: {name: clearAndSetSelection}
12+
initialState:
13+
documentContents: foo(bar baz)
14+
selections:
15+
- anchor: {line: 0, character: 10}
16+
active: {line: 0, character: 10}
17+
marks: {}
18+
finalState:
19+
documentContents: foo(z)
20+
selections:
21+
- anchor: {line: 0, character: 4}
22+
active: {line: 0, character: 4}
23+
thatMark:
24+
- anchor: {line: 0, character: 4}
25+
active: {line: 0, character: 4}
26+
fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: head}, {type: interiorOnly}]}]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
languageId: typescript
2+
command:
3+
spokenForm: clear head funk
4+
version: 2
5+
targets:
6+
- type: primitive
7+
modifiers:
8+
- {type: head}
9+
- type: containingScope
10+
scopeType: {type: namedFunction}
11+
usePrePhraseSnapshot: true
12+
action: {name: clearAndSetSelection}
13+
initialState:
14+
documentContents: |-
15+
function whatever() {
16+
17+
}
18+
selections:
19+
- anchor: {line: 1, character: 4}
20+
active: {line: 1, character: 4}
21+
marks: {}
22+
finalState:
23+
documentContents: |-
24+
25+
}
26+
selections:
27+
- anchor: {line: 0, character: 0}
28+
active: {line: 0, character: 0}
29+
thatMark:
30+
- anchor: {line: 0, character: 0}
31+
active: {line: 0, character: 0}
32+
fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: head}, {type: containingScope, scopeType: {type: namedFunction}}]}]

src/typings/target.types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ export interface Target {
4646
/** Internal target that should be used for the that mark */
4747
readonly thatTarget: Target;
4848

49+
readonly previousTarget: Target | undefined;
50+
4951
getInteriorStrict(): Target[];
5052
getBoundaryStrict(): Target[];
5153
/** The range of the delimiter before the content selection */

0 commit comments

Comments
 (0)