Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

44 changes: 44 additions & 0 deletions data/fixtures/scopes/textual/surroundingPair4.scope
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
(a < b)
(c > d)
---

[#1 Content] =
[#1 Removal] =
[#1 Domain] = 0:0-0:7
>-------<
0| (a < b)

[#1 Interior] = 0:1-0:6
>-----<
0| (a < b)

[#1 Boundary L] = 0:0-0:1
>-<
0| (a < b)

[#1 Boundary R] = 0:6-0:7
>-<
0| (a < b)

[#1 Insertion delimiter] = " "


[#2 Content] =
[#2 Removal] =
[#2 Domain] = 1:0-1:7
>-------<
1| (c > d)

[#2 Interior] = 1:1-1:6
>-----<
1| (c > d)

[#2 Boundary L] = 1:0-1:1
>-<
1| (c > d)

[#2 Boundary R] = 1:6-1:7
>-<
1| (c > d)

[#2 Insertion delimiter] = " "
38 changes: 38 additions & 0 deletions data/fixtures/scopes/textual/surroundingPair5.scope
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
( [ ) ]
---

[Content] =
[Domain] = 0:0-0:7
>-------<
0| ( [ ) ]

[Removal] = 0:0-0:9
>---------<
0| ( [ ) ]

[Trailing delimiter] = 0:7-0:9
>--<
0| ( [ ) ]

[Interior: Content] = 0:3-0:4
>-<
0| ( [ ) ]
[Interior: Removal] = 0:1-0:6
>-----<
0| ( [ ) ]

[Boundary L: Content] = 0:0-0:1
>-<
0| ( [ ) ]
[Boundary L: Removal] = 0:0-0:3
>---<
0| ( [ ) ]

[Boundary R: Content] = 0:6-0:7
>-<
0| ( [ ) ]
[Boundary R: Removal] = 0:6-0:9
>---<
0| ( [ ) ]

[Insertion delimiter] = " "
22 changes: 22 additions & 0 deletions data/fixtures/scopes/textual/surroundingPair6.scope
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
([)]
---

[Content] =
[Removal] =
[Domain] = 0:0-0:3
>---<
0| ([)]

[Interior] = 0:1-0:2
>-<
0| ([)]

[Boundary L] = 0:0-0:1
>-<
0| ([)]

[Boundary R] = 0:2-0:3
>-<
0| ([)]

[Insertion delimiter] = " "
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { SimpleSurroundingPairName } from "@cursorless/common";
import { DefaultMap } from "@cursorless/common";
import type { Range } from "@cursorless/common";
import findLastIndex from "lodash-es/findLastIndex";
import type { DelimiterOccurrence, SurroundingPairOccurrence } from "./types";

/**
Expand All @@ -13,14 +13,7 @@ export function getSurroundingPairOccurrences(
delimiterOccurrences: DelimiterOccurrence[],
): SurroundingPairOccurrence[] {
const result: SurroundingPairOccurrence[] = [];

/**
* A map from delimiter names to occurrences of the opening delimiter
*/
const openingDelimiterOccurrences = new DefaultMap<
SimpleSurroundingPairName,
DelimiterOccurrence[]
>(() => []);
const openingDelimitersStack: DelimiterOccurrence[] = [];

for (const occurrence of delimiterOccurrences) {
const {
Expand All @@ -29,48 +22,29 @@ export function getSurroundingPairOccurrences(
range,
} = occurrence;

let openingDelimiters = openingDelimiterOccurrences.get(delimiterName);

if (isSingleLine) {
// If single line, remove all opening delimiters that are not on the same line
// as occurrence
openingDelimiters = openingDelimiters.filter(
(openingDelimiter) =>
openingDelimiter.range.start.line === range.start.line,
);
openingDelimiterOccurrences.set(delimiterName, openingDelimiters);
}

/**
* A list of opening delimiters that are relevant to the current occurrence.
* We exclude delimiters that are not in the same text fragment range as the
* current occurrence.
*/
const relevantOpeningDelimiters = openingDelimiters.filter(
(openingDelimiter) =>
(textFragmentRange == null &&
openingDelimiter.textFragmentRange == null) ||
(textFragmentRange != null &&
openingDelimiter.textFragmentRange != null &&
openingDelimiter.textFragmentRange.isRangeEqual(textFragmentRange)),
);

if (
side === "left" ||
(side === "unknown" && relevantOpeningDelimiters.length % 2 === 0)
) {
openingDelimiters.push(occurrence);
if (side === "left") {
openingDelimitersStack.push(occurrence);
} else {
const openingDelimiter = relevantOpeningDelimiters.at(-1);
const openingDelimiterIndex = findLastIndex(
openingDelimitersStack,
(o) =>
o.delimiterInfo.delimiterName === delimiterName &&
isSameTextFragment(o.textFragmentRange, textFragmentRange) &&
isValidLine(isSingleLine, o.range, range),
);

if (openingDelimiter == null) {
if (openingDelimiterIndex === -1) {
// When side is unknown and we can't find an opening delimiter, that means this is the opening delimiter.
if (side === "unknown") {
openingDelimitersStack.push(occurrence);
}
continue;
}

openingDelimiters.splice(
openingDelimiters.lastIndexOf(openingDelimiter),
1,
);
const openingDelimiter = openingDelimitersStack[openingDelimiterIndex];

// Pop stack up to and including the opening delimiter
openingDelimitersStack.length = openingDelimiterIndex;

result.push({
delimiterName: delimiterName,
Expand All @@ -82,3 +56,17 @@ export function getSurroundingPairOccurrences(

return result;
}

function isSameTextFragment(
a: Range | undefined,
b: Range | undefined,
): boolean {
if (a == null || b == null) {
return a === b;
}
return a.isRangeEqual(b);
}

function isValidLine(isSingleLine: boolean, a: Range, b: Range): boolean {
return !isSingleLine || a.start.line === b.start.line;
}
Loading