Skip to content

Commit 6b8cea8

Browse files
Changed getRemovalHighlightRange to return a GeneralizedRange (#2784)
Fixes #1657 ## Checklist - [/] I have added [tests](https://www.cursorless.org/docs/contributing/test-case-recorder/) - [/] I have updated the [docs](https://github.com/cursorless-dev/cursorless/tree/main/docs) and [cheatsheet](https://github.com/cursorless-dev/cursorless/tree/main/cursorless-talon/src/cheatsheet) - [/] I have not broken the cheatsheet
1 parent a1eca3d commit 6b8cea8

File tree

12 files changed

+120
-115
lines changed

12 files changed

+120
-115
lines changed

packages/cursorless-engine/src/actions/BringMoveSwap.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import type { Range, Selection, TextEditor } from "@cursorless/common";
1+
import type {
2+
GeneralizedRange,
3+
Range,
4+
Selection,
5+
TextEditor,
6+
} from "@cursorless/common";
27
import { FlashStyle, RangeExpansionBehavior } from "@cursorless/common";
38
import { flatten } from "lodash-es";
49
import type { RangeUpdater } from "../core/updateSelections/RangeUpdater";
@@ -8,8 +13,8 @@ import type { EditWithRangeUpdater } from "../typings/Types";
813
import type { Destination, Target } from "../typings/target.types";
914
import {
1015
flashTargets,
11-
getContentRange,
1216
runForEachEditor,
17+
toGeneralizedRange,
1318
} from "../util/targetUtils";
1419
import { unifyRemovalTargets } from "../util/unifyRanges";
1520
import type { ActionReturnValue } from "./actions.types";
@@ -34,7 +39,7 @@ abstract class BringMoveSwap {
3439
protected abstract decoration: {
3540
sourceStyle: FlashStyle;
3641
destinationStyle: FlashStyle;
37-
getSourceRangeCallback: (target: Target) => Range;
42+
getSourceRangeCallback?: (target: Target) => GeneralizedRange;
3843
};
3944

4045
constructor(
@@ -209,8 +214,12 @@ abstract class BringMoveSwap {
209214
}
210215

211216
protected async decorateThatMark(thatMark: MarkEntry[]) {
212-
const getRange = (target: Target) =>
213-
thatMark.find((t) => t.target === target)!.selection;
217+
const getRange = (target: Target) => {
218+
return toGeneralizedRange(
219+
target,
220+
thatMark.find((t) => t.target === target)!.selection,
221+
);
222+
};
214223
return Promise.all([
215224
flashTargets(
216225
ide(),
@@ -250,7 +259,6 @@ export class Bring extends BringMoveSwap {
250259
decoration = {
251260
sourceStyle: FlashStyle.referenced,
252261
destinationStyle: FlashStyle.pendingModification0,
253-
getSourceRangeCallback: getContentRange,
254262
};
255263

256264
constructor(rangeUpdater: RangeUpdater) {
@@ -320,7 +328,6 @@ export class Swap extends BringMoveSwap {
320328
decoration = {
321329
sourceStyle: FlashStyle.pendingModification1,
322330
destinationStyle: FlashStyle.pendingModification0,
323-
getSourceRangeCallback: getContentRange,
324331
};
325332

326333
constructor(rangeUpdater: RangeUpdater) {

packages/cursorless-engine/src/actions/CopyToClipboard.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,7 @@ export class CopyToClipboard implements SimpleAction {
2929
}
3030

3131
if (options.showDecorations) {
32-
await flashTargets(
33-
ide(),
34-
targets,
35-
FlashStyle.referenced,
36-
(target) => target.contentRange,
37-
);
32+
await flashTargets(ide(), targets, FlashStyle.referenced);
3833
}
3934

4035
// FIXME: We should really keep track of the number of targets from the

packages/cursorless-engine/src/actions/CutToClipboard.ts

Lines changed: 41 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,17 @@
1-
import type { FlashDescriptor } from "@cursorless/common";
2-
import {
3-
FlashStyle,
4-
Range,
5-
toCharacterRange,
6-
toLineRange,
7-
} from "@cursorless/common";
1+
import type { CharacterRange, FlashDescriptor } from "@cursorless/common";
2+
import { FlashStyle, Range, toCharacterRange } from "@cursorless/common";
83
import { ide } from "../singletons/ide.singleton";
94
import type { Target } from "../typings/target.types";
105
import type { Actions } from "./Actions";
11-
import type { SimpleAction, ActionReturnValue } from "./actions.types";
6+
import type { ActionReturnValue, SimpleAction } from "./actions.types";
127

138
export class CutToClipboard implements SimpleAction {
149
constructor(private actions: Actions) {
1510
this.run = this.run.bind(this);
1611
}
1712

1813
async run(targets: Target[]): Promise<ActionReturnValue> {
19-
await ide().flashRanges(
20-
targets.flatMap((target) => {
21-
const { editor, contentRange } = target;
22-
const removalHighlightRange = target.getRemovalHighlightRange();
23-
24-
if (target.isLine) {
25-
return [
26-
{
27-
editor,
28-
range: toCharacterRange(contentRange),
29-
style: FlashStyle.referenced,
30-
},
31-
{
32-
editor,
33-
range: toLineRange(removalHighlightRange),
34-
style: FlashStyle.pendingDelete,
35-
},
36-
];
37-
}
38-
39-
return [
40-
{
41-
editor,
42-
range: toCharacterRange(contentRange),
43-
style: FlashStyle.referenced,
44-
},
45-
...getOutsideOverflow(contentRange, removalHighlightRange).map(
46-
(overflow): FlashDescriptor => ({
47-
editor,
48-
range: toCharacterRange(overflow),
49-
style: FlashStyle.pendingDelete,
50-
}),
51-
),
52-
];
53-
}),
54-
);
14+
await ide().flashRanges(targets.flatMap(getFlashDescriptors));
5515

5616
const options = { showDecorations: false };
5717

@@ -63,8 +23,44 @@ export class CutToClipboard implements SimpleAction {
6323
}
6424
}
6525

26+
function getFlashDescriptors(target: Target): FlashDescriptor[] {
27+
const { editor, contentRange } = target;
28+
const removalHighlightRange = target.getRemovalHighlightRange();
29+
30+
const flashDescriptors: FlashDescriptor[] = [
31+
{
32+
editor,
33+
range: toCharacterRange(contentRange),
34+
style: FlashStyle.referenced,
35+
},
36+
];
37+
38+
if (removalHighlightRange.type === "line") {
39+
flashDescriptors.push({
40+
editor,
41+
range: removalHighlightRange,
42+
style: FlashStyle.pendingDelete,
43+
});
44+
} else {
45+
flashDescriptors.push(
46+
...getOutsideOverflow(contentRange, removalHighlightRange).map(
47+
(overflow): FlashDescriptor => ({
48+
editor,
49+
range: toCharacterRange(overflow),
50+
style: FlashStyle.pendingDelete,
51+
}),
52+
),
53+
);
54+
}
55+
56+
return flashDescriptors;
57+
}
58+
6659
/** Get the possible leading and trailing overflow ranges of the outside range compared to the inside range */
67-
function getOutsideOverflow(insideRange: Range, outsideRange: Range): Range[] {
60+
function getOutsideOverflow(
61+
insideRange: Range,
62+
outsideRange: CharacterRange,
63+
): Range[] {
6864
const { start: insideStart, end: insideEnd } = insideRange;
6965
const { start: outsideStart, end: outsideEnd } = outsideRange;
7066
const result = [];

packages/cursorless-engine/src/actions/Highlight.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ export default class Highlight {
3333
ide().setHighlightRanges(
3434
highlightId,
3535
editor,
36-
targets.map(toGeneralizedRange),
36+
targets.map((target) =>
37+
toGeneralizedRange(target, target.contentRange),
38+
),
3739
),
3840
);
3941
}

packages/cursorless-engine/src/actions/ToggleBreakpoint.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ export default class ToggleBreakpoint implements SimpleAction {
2525
await flashTargets(ide(), thatTargets, FlashStyle.referenced);
2626

2727
await runOnTargetsForEachEditor(targets, async (editor, targets) => {
28-
const generalizedRanges = targets.map(toGeneralizedRange);
28+
const generalizedRanges = targets.map((target) =>
29+
toGeneralizedRange(target, target.contentRange),
30+
);
2931

3032
await ide()
3133
.getEditableTextEditor(editor)

packages/cursorless-engine/src/processTargets/targets/BaseTarget.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type {
22
EnforceUndefined,
3+
GeneralizedRange,
34
InsertionMode,
45
Range,
56
Selection,
@@ -14,6 +15,7 @@ import type {
1415
JoinAsType,
1516
Target,
1617
} from "../../typings/target.types";
18+
import { toGeneralizedRange } from "../../util/targetUtils";
1719
import { DestinationImpl } from "./DestinationImpl";
1820
import { createContinuousRange } from "./util/createContinuousRange";
1921

@@ -97,8 +99,8 @@ export abstract class BaseTarget<
9799
};
98100
}
99101

100-
getRemovalHighlightRange(): Range {
101-
return this.getRemovalRange();
102+
getRemovalHighlightRange(): GeneralizedRange {
103+
return toGeneralizedRange(this, this.getRemovalRange());
102104
}
103105

104106
withThatTarget(thatTarget: Target): Target {

packages/cursorless-engine/src/processTargets/targets/BoundedParagraphTarget.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import type { Range } from "@cursorless/common";
1+
import { toLineRange, type Range } from "@cursorless/common";
2+
import type { InteriorTarget, ParagraphTarget } from ".";
3+
import { expandToFullLine } from "../../util/rangeUtils";
24
import type { MinimumTargetParameters } from "./BaseTarget";
35
import { BaseTarget } from "./BaseTarget";
46
import { LineTarget } from "./LineTarget";
5-
import { expandToFullLine } from "../../util/rangeUtils";
6-
import type { InteriorTarget, ParagraphTarget } from ".";
77

88
interface BoundedParagraphTargetParameters extends MinimumTargetParameters {
99
readonly paragraphTarget: ParagraphTarget;
@@ -86,16 +86,20 @@ export class BoundedParagraphTarget extends BaseTarget<BoundedParagraphTargetPar
8686
}
8787

8888
getRemovalHighlightRange() {
89-
if (this.startLineGap < 1 || this.endLineGap < 1) {
90-
return this.getRemovalRange();
91-
}
89+
const range = (() => {
90+
if (this.startLineGap < 1 || this.endLineGap < 1) {
91+
return this.getRemovalRange();
92+
}
9293

93-
const delimiterTarget =
94-
this.getTrailingDelimiterTarget() ?? this.getLeadingDelimiterTarget();
94+
const delimiterTarget =
95+
this.getTrailingDelimiterTarget() ?? this.getLeadingDelimiterTarget();
96+
97+
return delimiterTarget != null
98+
? this.fullLineContentRange.union(delimiterTarget.contentRange)
99+
: this.fullLineContentRange;
100+
})();
95101

96-
return delimiterTarget != null
97-
? this.fullLineContentRange.union(delimiterTarget.contentRange)
98-
: this.fullLineContentRange;
102+
return toLineRange(range);
99103
}
100104

101105
maybeCreateRichRangeTarget(

packages/cursorless-engine/src/processTargets/targets/LineTarget.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import type { TextEditor } from "@cursorless/common";
2-
import { Position, Range } from "@cursorless/common";
2+
import { Position, Range, toLineRange } from "@cursorless/common";
3+
import { expandToFullLine } from "../../util/rangeUtils";
4+
import { tryConstructTarget } from "../../util/tryConstructTarget";
35
import type { CommonTargetParameters } from "./BaseTarget";
46
import { BaseTarget } from "./BaseTarget";
5-
import { expandToFullLine } from "../../util/rangeUtils";
67
import { tryConstructPlainTarget } from "./PlainTarget";
78
import { createContinuousLineRange } from "./util/createContinuousRange";
8-
import { tryConstructTarget } from "../../util/tryConstructTarget";
99

1010
export class LineTarget extends BaseTarget<CommonTargetParameters> {
1111
type = "LineTarget";
@@ -42,7 +42,9 @@ export class LineTarget extends BaseTarget<CommonTargetParameters> {
4242
: contentRemovalRange.union(delimiterTarget.contentRange);
4343
}
4444

45-
getRemovalHighlightRange = () => this.fullLineContentRange;
45+
getRemovalHighlightRange = () => {
46+
return toLineRange(this.fullLineContentRange);
47+
};
4648

4749
maybeCreateRichRangeTarget(
4850
isReversed: boolean,

packages/cursorless-engine/src/processTargets/targets/ParagraphTarget.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
import type { TextDocument, TextEditor, TextLine } from "@cursorless/common";
2-
import { Position, Range } from "@cursorless/common";
1+
import type {
2+
GeneralizedRange,
3+
TextDocument,
4+
TextEditor,
5+
TextLine,
6+
} from "@cursorless/common";
7+
import { Position, Range, toLineRange } from "@cursorless/common";
8+
import { expandToFullLine } from "../../util/rangeUtils";
39
import type { CommonTargetParameters } from "./BaseTarget";
410
import { BaseTarget } from "./BaseTarget";
5-
import { LineTarget } from "./LineTarget";
6-
import { expandToFullLine } from "../../util/rangeUtils";
7-
import { constructLineTarget } from "./LineTarget";
11+
import { constructLineTarget, LineTarget } from "./LineTarget";
812
import { createContinuousLineRange } from "./util/createContinuousRange";
913

1014
export class ParagraphTarget extends BaseTarget<CommonTargetParameters> {
@@ -59,13 +63,16 @@ export class ParagraphTarget extends BaseTarget<CommonTargetParameters> {
5963
return expandToFullLine(this.editor, this.contentRange);
6064
}
6165

62-
getRemovalHighlightRange() {
66+
getRemovalHighlightRange(): GeneralizedRange {
6367
const delimiterTarget =
6468
this.getTrailingDelimiterTarget() ?? this.getLeadingDelimiterTarget();
6569

66-
return delimiterTarget != null
67-
? this.fullLineContentRange.union(delimiterTarget.contentRange)
68-
: this.fullLineContentRange;
70+
const range =
71+
delimiterTarget != null
72+
? this.fullLineContentRange.union(delimiterTarget.contentRange)
73+
: this.fullLineContentRange;
74+
75+
return toLineRange(range);
6976
}
7077

7178
maybeCreateRichRangeTarget(

packages/cursorless-engine/src/scopeProviders/getTargetRanges.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
import type { TargetRanges } from "@cursorless/common";
2-
import { toCharacterRange, toLineRange } from "@cursorless/common";
32
import type { Target } from "../typings/target.types";
43

54
export function getTargetRanges(target: Target): TargetRanges {
65
return {
76
contentRange: target.contentRange,
87
removalRange: target.getRemovalRange(),
9-
removalHighlightRange: target.isLine
10-
? toLineRange(target.getRemovalHighlightRange())
11-
: toCharacterRange(target.getRemovalHighlightRange()),
8+
removalHighlightRange: target.getRemovalHighlightRange(),
129
leadingDelimiter: getOptionalTarget(target.getLeadingDelimiterTarget()),
1310
trailingDelimiter: getOptionalTarget(target.getTrailingDelimiterTarget()),
1411
interior: target.getInterior()?.map(getTargetRanges),

0 commit comments

Comments
 (0)