cm-tarnation
Version:
An alternative parser for CodeMirror 6
94 lines • 3.22 kB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import { pointsMatch, toPoints } from "../../util";
/**
* Matcher that takes in a list of strings, and matches each one against an
* input to see if any match.
*/
export class LookupMatcher {
/**
* @param src - The source list of strings.
* @param ignoreCase - If `true`, matches will be case-insensitive.
* @param variables - A variable table to use when expanding variables.
*/
constructor(src, ignoreCase, variables) {
// longest first
const sorted = [...src].sort((a, b) => b.length - a.length);
this.max = sorted[0].length;
this.ignoreCase = Boolean(ignoreCase);
this.lengths = new Map();
this.entries = sorted.map(entry => {
if (variables)
entry = expandVariables(entry, variables);
if (ignoreCase)
entry = entry.toLowerCase();
const points = toPoints(entry);
this.lengths.set(points, entry.length);
return points;
});
}
/**
* Internal method which returns the length of a match against a string,
* if one was found.
*
* @param str - The string to match.
* @param pos - The position to start matching at.
*/
exec(str, pos) {
const slice = str.slice(pos, pos + this.max);
const against = toPoints(this.ignoreCase ? slice.toLowerCase() : slice);
for (let i = 0; i < this.entries.length; i++) {
const points = this.entries[i];
if (pointsMatch(points, against, 0))
return this.lengths.get(points);
}
return null;
}
/**
* Tests to see if a string is in this list.
*
* @param str - The string to match.
* @param pos - The position to start matching at.
*/
test(str, pos) {
return this.exec(str, pos) !== null;
}
/**
* Returns the results of attempting to match a string against this list.
*
* @param str - The string to match.
* @param pos - The position to start matching at.
*/
match(str, pos) {
const result = this.exec(str, pos);
if (!result)
return null;
return {
total: str.slice(pos, pos + result),
captures: null,
length: result
};
}
}
/**
* Expands the variables in a pattern source using a variable table.
*
* @param src - The source to expand.
* @param variables - The variable table to use.
*/
function expandVariables(src, variables) {
let depth = 0;
while (/@\w/.test(src) && depth < 5) {
depth++;
src = src.replace(/@(\w+)/g, (_, ident) => {
const value = variables[ident];
if (typeof value !== "string") {
throw new Error(`Variable ${ident} is not a string`);
}
return value;
});
}
return src;
}
//# sourceMappingURL=lookup.js.map