mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-08 17:02:17 +00:00
fix(editor): List identical completion items once
kotlin-language-server repeats a class once per classpath entry declaring it, so `String()` and `String` were listed three times each.
This commit is contained in:
1 parent
b9f8a0b4bd
commit
7c09a13afc
3 files changed
+44
-5
No files matched your search
@@ -4,7 +4,14 @@ import { EditorView } from "@codemirror/view";
|
||||
import type { CompletionItem } from "@/bindings";
|
||||
import type { EditorDocContext } from "@/editor/api";
|
||||
import { lspDoc } from "./lsp";
|
||||
import { completionSymbolKind, identifierEnd, toCmCompletion, triggerCharacter, typeColumnText } from "./completionItems";
|
||||
import {
|
||||
completionSymbolKind,
|
||||
identifierEnd,
|
||||
toCmCompletion,
|
||||
triggerCharacter,
|
||||
typeColumnText,
|
||||
withoutDuplicates,
|
||||
} from "./completionItems";
|
||||
import {
|
||||
applyLspCompletion,
|
||||
callParens,
|
||||
@@ -75,6 +82,13 @@ describe("toCmCompletion", () => {
|
||||
expect(toCmCompletion(item({ label: "foo", filterText: "foo_bar" })).label).toBe("foo_bar");
|
||||
});
|
||||
|
||||
it("lists identical items once", () => {
|
||||
const ctor = item({ label: "String()", kind: "constructor", data: "1" });
|
||||
const overload = item({ label: "String()", kind: "constructor", labelDetail: "(bytes: ByteArray)" });
|
||||
const out = withoutDuplicates([ctor, { ...ctor, data: "2" }, overload, { ...ctor, server: 2 }]);
|
||||
expect(out).toEqual([ctor, overload, { ...ctor, server: 2 }]);
|
||||
});
|
||||
|
||||
it("boosts preselected and demotes deprecated items", () => {
|
||||
expect(toCmCompletion(item({ preselect: true })).boost).toBe(99);
|
||||
expect(toCmCompletion(item({ deprecated: true })).boost).toBeLessThan(0);
|
||||
|
||||
@@ -35,7 +35,14 @@ import {
|
||||
type RequestId,
|
||||
} from "@/platform/ipc";
|
||||
import { useProject } from "@/platform/project";
|
||||
import { completionSymbolKind, identifierEnd, toCmCompletion, triggerCharacter, typeColumnText } from "./completionItems";
|
||||
import {
|
||||
completionSymbolKind,
|
||||
identifierEnd,
|
||||
toCmCompletion,
|
||||
triggerCharacter,
|
||||
typeColumnText,
|
||||
withoutDuplicates,
|
||||
} from "./completionItems";
|
||||
import { lspSnippetToCm, snippetVariables } from "./snippet";
|
||||
import { docOf, isUnavailable, lspDoc, lspRequest, reportLspError } from "./lsp";
|
||||
import { offsetToPos, posToOffset, textEditsToChanges } from "./positions";
|
||||
@@ -437,9 +444,11 @@ async function lspCompletionSource(ctx: CompletionContext): Promise<CompletionRe
|
||||
const req: RequestContext = { doc: doc.doc, path: doc.path, language: doc.uiMode, pos: ctx.pos, text: ctx.state.doc };
|
||||
const prefs = editorPrefs().completion;
|
||||
const typed = word?.text ?? "";
|
||||
let items = prefs.matchCase
|
||||
? list.items.filter((it) => matchesCase(it.filterText ?? it.label, typed, prefs.caseSensitivity))
|
||||
: list.items;
|
||||
let items = withoutDuplicates(
|
||||
prefs.matchCase
|
||||
? list.items.filter((it) => matchesCase(it.filterText ?? it.label, typed, prefs.caseSensitivity))
|
||||
: list.items,
|
||||
);
|
||||
// A server snippet named like a live template (jdtls `sout`, `fori`) would be listed twice; the template wins.
|
||||
if (items.some((it) => it.kind === "snippet")) {
|
||||
const own = await contributedSource(ctx);
|
||||
|
||||
@@ -65,6 +65,22 @@ function extendsLabel(item: CompletionItem): boolean {
|
||||
return item.filterText!.startsWith(item.label) && /^[^\p{L}\p{N}_$]/u.test(rest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Items that look and insert the same, listed once. kotlin-language-server
|
||||
* repeats a class once per classpath entry declaring it (`String()` ×3);
|
||||
* these all have their own `apply` (see `makeCompletion`), so CodeMirror
|
||||
* wouldn't merge them.
|
||||
*/
|
||||
export function withoutDuplicates(items: readonly CompletionItem[]): CompletionItem[] {
|
||||
const seen = new Set<string>();
|
||||
return items.filter((it) => {
|
||||
const key = JSON.stringify([it.server, it.label, it.labelDetail, it.detail, it.kind, it.insertText, it.additionalEdits]);
|
||||
if (seen.has(key)) return false;
|
||||
seen.add(key);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
const IMPORT_SOURCE = [
|
||||
/^\s*from\s+([\w.]+)\s+import\b/m, // Python
|
||||
/^\s*import\s+(?:static\s+)?([\w.]+?)\.\w+;?\s*$/m, // Java, Kotlin
|
||||
|
||||
Reference in new issue
Block a user