Skip to content

Commit

Permalink
Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreasArvidsson committed Dec 26, 2024
1 parent 71b7b6c commit db385da
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 47 deletions.
14 changes: 9 additions & 5 deletions packages/common/src/util/regex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,20 @@ function makeCache<T, U>(func: (arg: T) => U) {
export const rightAnchored = makeCache(_rightAnchored);
export const leftAnchored = makeCache(_leftAnchored);

export function matchAllIterator(text: string, regex: RegExp) {
// Reset the regex to start at the beginning of string, in case the regex has
// been used before.
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec#finding_successive_matches
regex.lastIndex = 0;
return text.matchAll(regex);
}

export function matchAll<T>(
text: string,
regex: RegExp,
mapfn: (v: RegExpMatchArray, k: number) => T,
) {
// Reset the regex to start at the beginning of string, in case the regex has
// been used before.
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec#finding_successive_matches
regex.lastIndex = 0;
return Array.from(text.matchAll(regex), mapfn);
return Array.from(matchAllIterator(text, regex), mapfn);
}

export function testRegex(regex: RegExp, text: string): boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,26 @@ import type { Range } from "@cursorless/common";

/**
* An iterator that allows for efficient lookup of ranges that contain a search item.
* The items must be sorted in document order.
*/
export class RangeIterator<T extends { range: Range }> {
private index = 0;

constructor(
public items: T[],
sortItems = false,
) {
if (sortItems) {
this.items.sort((a, b) => a.range.start.compareTo(b.range.start));
}
}
/**
* @param items The items to iterate over. Must be sorted in document order.
*/
constructor(public items: T[]) {}

contains(searchItem: Range): boolean {
return this.advance(searchItem);
}

getContaining(searchItem: Range): T | undefined {
if (!this.advance(searchItem)) {
return undefined;
if (this.advance(searchItem)) {
return this.items[this.index];
}

return this.items[this.index];
return undefined;
}

private advance(searchItem: Range): boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { matchAll, Range, type TextDocument } from "@cursorless/common";
import { matchAllIterator, Range, type TextDocument } from "@cursorless/common";
import type { LanguageDefinition } from "../../../../languages/LanguageDefinition";
import type { QueryCapture } from "../../../../languages/TreeSitterQuery/QueryCapture";
import { getDelimiterRegex } from "./getDelimiterRegex";
import { RangeIterator } from "./RangeIterator";
import type { DelimiterOccurrence, IndividualDelimiter } from "./types";
Expand All @@ -21,20 +22,14 @@ export function getDelimiterOccurrences(
return [];
}

const delimiterRegex = getDelimiterRegex(individualDelimiters);

const captures = languageDefinition?.getMultipleCaptures(document, [
"disqualifyDelimiter",
"textFragment",
]);
const disqualifyDelimitersIterator = new RangeIterator(
captures?.disqualifyDelimiter ?? [],
true, // Sort items
);
const textFragmentsIterator = new RangeIterator(
captures?.textFragment ?? [],
true,
const disqualifyDelimitersIterator = createRangeIterator(
captures?.disqualifyDelimiter,
);
const textFragmentsIterator = createRangeIterator(captures?.textFragment);

const delimiterTextToDelimiterInfoMap = Object.fromEntries(
individualDelimiters.map((individualDelimiter) => [
Expand All @@ -52,20 +47,36 @@ export function getDelimiterOccurrences(
return textFragmentsIterator.getContaining(range)?.range;
};

const text = document.getText();
const matchIterator = matchAllIterator(
document.getText(),
getDelimiterRegex(individualDelimiters),
);

const results: DelimiterOccurrence[] = [];

return matchAll(text, delimiterRegex, (match): DelimiterOccurrence => {
for (const match of matchIterator) {
const text = match[0];
const range = new Range(
document.positionAt(match.index!),
document.positionAt(match.index! + text.length),
);

return {
delimiterInfo: delimiterTextToDelimiterInfoMap[text],
isDisqualified: isDisqualified(range),
textFragmentRange: getTextFragmentRange(range),
range,
};
});
if (!isDisqualified(range)) {
results.push({
delimiterInfo: delimiterTextToDelimiterInfoMap[text],
textFragmentRange: getTextFragmentRange(range),
range,
});
}
}

return results;
}

function createRangeIterator(
captures: QueryCapture[] | undefined,
): RangeIterator<QueryCapture> {
const items = captures ?? [];
items.sort((a, b) => a.range.start.compareTo(b.range.start));
return new RangeIterator(items);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,10 @@ export function getSurroundingPairOccurrences(
for (const occurrence of delimiterOccurrences) {
const {
delimiterInfo: { delimiterName, side, isSingleLine },
isDisqualified,
textFragmentRange,
range,
} = occurrence;

if (isDisqualified) {
continue;
}

let openingDelimiters = openingDelimiterOccurrences.get(delimiterName);

if (isSingleLine) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,6 @@ export interface DelimiterOccurrence {
*/
range: Range;

/**
* If `true`, this delimiter is disqualified from being considered as a
* surrounding pair delimiter, because it has been tagged as such based on a
* parse tree query.
*/
isDisqualified: boolean;

/**
* If the delimiter is part of a text fragment, eg a string or comment, this
* will be the range of the text fragment.
Expand Down

0 comments on commit db385da

Please sign in to comment.