Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 2 additions & 2 deletions denops/ddc/base/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {
Previewer,
SourceOptions,
} from "../types.ts";
import { convertKeywordPattern } from "../utils.ts";
import { convertKeywordPattern, getKeywordRegExp } from "../utils.ts";

import type { Denops } from "@denops/std";

Expand Down Expand Up @@ -106,7 +106,7 @@ export abstract class BaseSource<
);

const completePos = args.context.input.search(
new RegExp("(?:" + keywordPattern + ")$"),
getKeywordRegExp("(?:" + keywordPattern + ")$"),
);
return completePos;
}
Expand Down
11 changes: 7 additions & 4 deletions denops/ddc/ddc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import type { Denops } from "@denops/std";
import * as autocmd from "@denops/std/autocmd";
import * as op from "@denops/std/option";
import * as fn from "@denops/std/function";
import { batch } from "@denops/std/batch";
import { batch, collect } from "@denops/std/batch";

import { assertEquals } from "@std/assert/equals";

Expand Down Expand Up @@ -622,9 +622,12 @@ export class Ddc {
return;
}

const input = denops.call("ddc#util#get_input", context.event);
const mode = fn.mode(denops);
if (context.input !== await input || context.mode !== await mode) {
const [currentInput, currentMode] = await collect(denops, (denops) => [
// ddc#util#get_input always returns a string; cast for type inference.
denops.call("ddc#util#get_input", context.event) as Promise<string>,
fn.mode(denops),
]);
if (context.input !== currentInput || context.mode !== currentMode) {
// Input is changed. Skip invalid completion.
await this.hide(denops, context, options);
return;
Expand Down
11 changes: 4 additions & 7 deletions denops/ddc/ext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,14 +237,11 @@ export async function filterItems(
userFilters: UserFilter[],
items: Item[],
): Promise<Item[]> {
const resolvedList = await Promise.all(
userFilters.map((uf) => getFilter(denops, loader, options, uf)),
);
const resolved: ResolvedFilter[] = [];
for (const userFilter of userFilters) {
const [filter, filterOptions, filterParams] = await getFilter(
denops,
loader,
options,
userFilter,
);
for (const [filter, filterOptions, filterParams] of resolvedList) {
if (!filter) {
return [];
}
Expand Down
30 changes: 30 additions & 0 deletions denops/ddc/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
import { join } from "@std/path/join";
import { dirname } from "@std/path/dirname";

// Cache size limit: in practice only a handful of distinct keywordPattern /
// iskeyword combinations appear, so 64 entries is more than enough.
const KEYWORD_CACHE_MAX = 64;
const convertKeywordPatternCache = new Map<string, string>();
const keywordRegExpCache = new Map<string, RegExp>();

export async function convertKeywordPattern(
denops: Denops,
keywordPattern: string,
Expand All @@ -23,13 +29,37 @@
const iskeyword = bufnr === undefined
? await op.iskeyword.getLocal(denops)
: await op.iskeyword.getBuffer(denops, bufnr);
// Neither iskeyword nor keywordPattern contain NUL bytes, so this
// composite key is unambiguous.
const cacheKey = keywordPattern + "\0" + iskeyword;
const cached = convertKeywordPatternCache.get(cacheKey);
if (cached !== undefined) {
return cached;
}
const keyword = vimoption2ts(iskeyword);
const replaced = keywordPattern
.replaceAll("\\k", "[" + keyword + "]")
.replaceAll("[:keyword:]", keyword);
if (convertKeywordPatternCache.size >= KEYWORD_CACHE_MAX) {
convertKeywordPatternCache.clear();
}
convertKeywordPatternCache.set(cacheKey, replaced);
return replaced;
}

export function getKeywordRegExp(expandedPattern: string): RegExp {
const cached = keywordRegExpCache.get(expandedPattern);
if (cached !== undefined) {
return cached;
}
const re = new RegExp(expandedPattern);
if (keywordRegExpCache.size >= KEYWORD_CACHE_MAX) {
keywordRegExpCache.clear();
}
keywordRegExpCache.set(expandedPattern, re);
return re;
}

// See https://github.com/vim-denops/denops.vim/issues/358 for details
export function isDenoCacheIssueError(e: unknown): boolean {
const expects = [
Expand Down Expand Up @@ -251,7 +281,7 @@
}
return await importer.import(`${url}#${suffix}`);
} else {
return await import(`${url}#${suffix}`);

Check warning on line 284 in denops/ddc/utils.ts

View workflow job for this annotation

GitHub Actions / deno-test-publish

unable to analyze dynamic import
}
}

Expand Down
Loading