Skip to content

Commit

Permalink
Make algorithm smarte r when handling lots of results.
Browse files Browse the repository at this point in the history
  • Loading branch information
Tacodiva committed Feb 11, 2024
1 parent a150657 commit 1c77b97
Showing 1 changed file with 46 additions and 32 deletions.
78 changes: 46 additions & 32 deletions addons/middle-click-popup/WorkspaceQuerier.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,13 @@ class TokenProvider {
* Return the tokens found by this token provider in `query` at character `idx`.
* @param {QueryInfo} query The query to search
* @param {number} idx The index to start the search at
* @param {number} depth The number of blocks this token is inside of.
* For the query 1 + 1, the `+` block token would have a depth of 0 and the `1` tokens would have a depth of 1.
* @yields {Token} All the tokens found
* @abstract
*/
// eslint-disable-next-line require-yield
*parseTokens(query, idx) {
*parseTokens(query, idx, depth) {
throw new Error("Sub-class must override abstract method.");
}
}
Expand All @@ -181,9 +183,9 @@ class TokenProviderOptional extends TokenProvider {
this.inner = inner;
}

*parseTokens(query, idx) {
*parseTokens(query, idx, depth) {
yield TokenTypeBlank.INSTANCE.createToken(idx);
yield* this.inner.parseTokens(query, idx);
yield* this.inner.parseTokens(query, idx, depth);
}
}

Expand All @@ -207,9 +209,9 @@ class TokenProviderSingleCache extends TokenProvider {
}
}

*parseTokens(query, idx) {
*parseTokens(query, idx, depth) {
if (!this.inner.shouldCache) {
yield* this.inner.parseTokens();
yield* this.inner.parseTokens(query, idx, depth);
return;
}
if (this.cacheQueryID !== query.id) {
Expand All @@ -222,7 +224,7 @@ class TokenProviderSingleCache extends TokenProvider {
return;
}
this.cache[idx] = cacheEntry = [];
for (const token of this.inner.parseTokens(query, idx)) {
for (const token of this.inner.parseTokens(query, idx, depth)) {
cacheEntry.push(token);
yield token;
}
Expand Down Expand Up @@ -272,10 +274,10 @@ class TokenProviderGroup extends TokenProvider {
else this.illegalProviders.push(...providers);
}

*parseTokens(query, idx) {
*parseTokens(query, idx, depth) {
// If none of our providers are cacheable, just parse all the tokens again
if (!this.hasCacheable) {
for (const provider of this.providers) yield* provider.parseTokens(query, idx, false);
for (const provider of this.providers) yield* provider.parseTokens(query, idx, depth);
return;
}

Expand All @@ -293,7 +295,7 @@ class TokenProviderGroup extends TokenProvider {
for (let i = 0; i < tokenCaches.length; i++) {
const tokenCache = tokenCaches[i];
const providerCache = providerCaches[i];
for (const provider of providerCache) yield* provider.parseTokens(query, idx, false);
for (const provider of providerCache) yield* provider.parseTokens(query, idx, depth);
yield* tokenCache;
}
return;
Expand All @@ -312,7 +314,7 @@ class TokenProviderGroup extends TokenProvider {

for (const provider of this.providers) {
if (provider.shouldCache) {
for (const token of provider.parseTokens(query, idx, false)) {
for (const token of provider.parseTokens(query, idx, depth)) {
tokenCache.push(token);
yield token;
}
Expand All @@ -324,11 +326,11 @@ class TokenProviderGroup extends TokenProvider {
providerCaches.push(providerCache);
}
providerCache.push(provider);
yield* provider.parseTokens(query, idx, false);
yield* provider.parseTokens(query, idx, depth);
}
}
for (const provider of this.illegalProviders) {
for (let token of provider.parseTokens(query, idx, false)) {
for (let token of provider.parseTokens(query, idx, depth)) {
token = { ...token, isLegal: false };
tokenCache.push(token);
yield token;
Expand Down Expand Up @@ -403,7 +405,7 @@ class TokenTypeBlank extends TokenType {
this.isConstant = true;
}

*parseTokens(query, idx) {
*parseTokens(query, idx, depth) {
yield this.createToken(idx);
}

Expand Down Expand Up @@ -464,7 +466,7 @@ class TokenTypeStringEnum extends TokenType {
}
}

*parseTokens(query, idx) {
*parseTokens(query, idx, depth) {
for (let valueIdx = 0; valueIdx < this.values.length; valueIdx++) {
const valueInfo = this.values[valueIdx];
let yieldedToken = false;
Expand Down Expand Up @@ -520,7 +522,7 @@ class TokenTypeStringLiteral extends TokenType {
* Hello World for 10 seconds', but that's just the price we pay for trying to enumerate every
* interpretation.
*/
*parseTokens(query, idx) {
*parseTokens(query, idx, depth) {
// First, look for strings in quotes
let quoteEnd = -1;
if (query.str[idx] === '"' || query.str[idx] === "'") {
Expand Down Expand Up @@ -568,7 +570,7 @@ class TokenTypeNumberLiteral extends TokenType {
return !isNaN(+str) || !isNaN(parseFloat(+str));
}

*parseTokens(query, idx) {
*parseTokens(query, idx, depth) {
for (let i = idx; i <= query.length; i++) {
if (TokenTypeStringLiteral.isTerminator(query.str[i]) && i !== idx) {
const value = query.str.substring(idx, i);
Expand All @@ -592,7 +594,7 @@ class TokenTypeColor extends TokenType {
static INSTANCE = new TokenProviderOptional(new TokenTypeColor());
static HEX_CHARS = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"];

*parseTokens(query, idx) {
*parseTokens(query, idx, depth) {
if (!query.str.startsWith("#", idx)) return;
for (let i = 0; i < 6; i++) {
if (TokenTypeColor.HEX_CHARS.indexOf(query.lowercase[idx + i + 1]) === -1) return;
Expand All @@ -618,11 +620,11 @@ class TokenTypeBrackets extends TokenType {
this.tokenProvider = tokenProvider;
}

*parseTokens(query, idx) {
*parseTokens(query, idx, depth) {
const start = idx;
if (query.str[idx++] !== "(") return;
idx = query.skipIgnorable(idx);
for (const token of this.tokenProvider.parseTokens(query, idx)) {
for (const token of this.tokenProvider.parseTokens(query, idx, depth)) {
if (token.type instanceof TokenTypeBlank) continue; // Do not allow empty brackets like '()'
var tokenEnd = query.skipIgnorable(token.end);
let isTruncated = token.isTruncated;
Expand Down Expand Up @@ -750,12 +752,14 @@ class TokenTypeBlock extends TokenType {
}

/**
*
* @param {QueryInfo} query
* @param {*} idx
* @param {number} idx
* @param {number} depth
* @returns
*/
*parseTokens(query, idx) {
*parseTokens(query, idx, depth) {
if (depth !== 0 && !query.canCreateMoreNestedBlocks()) return;

let yieldedTokens = false;

for (const subtokens of this._parseSubtokens(query, idx, this.fullTokenProviders)) {
Expand Down Expand Up @@ -849,17 +853,20 @@ class TokenTypeBlock extends TokenType {
* @param {QueryInfo} query
* @param {number} idx
* @param {TokenProvider[]} subtokenProviders
* @param {number} depth
* @param {number} tokenProviderIdx
* @param {boolean} parseSubSubTokens
* @param {boolean} parseNextToken
* @yields {Token[]}
*/
*_parseSubtokens(query, idx, subtokenProviders, tokenProviderIdx = 0, parseSubSubTokens = true) {
*_parseSubtokens(query, idx, subtokenProviders, depth, tokenProviderIdx = 0, parseNextToken = true) {
idx = query.skipIgnorable(idx);
let tokenProvider = subtokenProviders[tokenProviderIdx];

for (const token of tokenProvider.parseTokens(query, idx)) {
for (const token of tokenProvider.parseTokens(query, idx, depth + 1)) {
++query.tokenCount;

if (!query.canCreateMoreTokens()) break;
if (depth !== 0 && !query.canCreateMoreNestedBlocks()) break;

if (this.block.precedence !== -1) {
if (
Expand All @@ -883,13 +890,14 @@ class TokenTypeBlock extends TokenType {
}
}

if (!parseSubSubTokens || !token.isLegal || tokenProviderIdx === subtokenProviders.length - 1) {
if (!parseNextToken || !token.isLegal || tokenProviderIdx === subtokenProviders.length - 1) {
yield [token];
} else {
for (const subTokenArr of this._parseSubtokens(
query,
token.end,
subtokenProviders,
depth,
tokenProviderIdx + 1,
!token.isTruncated
)) {
Expand Down Expand Up @@ -1069,8 +1077,10 @@ class QueryInfo {
this.lowercase = this.str.toLowerCase();
/** @type {number} A unique identifier for this query */
this.id = id;
/** @type{number} The number of tokens we've found so far */
/** @type {number} The number of tokens we've found so far */
this.tokenCount = 0;
/** @type {number} The number of query results we've found so far */
this.resultCount = 0;
}

/**
Expand Down Expand Up @@ -1117,6 +1127,10 @@ class QueryInfo {
canCreateMoreTokens() {
return this.tokenCount < WorkspaceQuerier.MAX_TOKENS;
}

canCreateMoreNestedBlocks() {
return this.canCreateMoreTokens() && this.resultCount < WorkspaceQuerier.MAX_RESULTS;
}
}

/**
Expand All @@ -1143,7 +1157,7 @@ export default class WorkspaceQuerier {
];

/**
* The maximum number of results to find before giving up.
* The maximum number of results to find before we give up searching sub-blocks.
*/
static MAX_RESULTS = 1000;

Expand Down Expand Up @@ -1180,7 +1194,7 @@ export default class WorkspaceQuerier {
let bestIllegalResult = null;
let bestIllegalResultText = "";

for (const option of this.tokenGroupBlocks.parseTokens(query, 0)) {
for (const option of this.tokenGroupBlocks.parseTokens(query, 0, 0)) {
if (option.end >= queryStr.length) {
if (option.isLegal) {
results.push(new QueryResult(query, option));
Expand All @@ -1192,12 +1206,12 @@ export default class WorkspaceQuerier {
}
}
}
++foundTokenCount;
if (foundTokenCount > WorkspaceQuerier.MAX_RESULTS) {
++query.resultCount;
if (!limited && query.resultCount >= WorkspaceQuerier.MAX_RESULTS) {
console.log("Warning: Workspace query exceeded maximum result count.");
limited = true;
break;
}

if (!query.canCreateMoreTokens()) {
console.log("Warning: Workspace query exceeded maximum token count.");
limited = true;
Expand Down

0 comments on commit 1c77b97

Please sign in to comment.