Skip to content
This repository was archived by the owner on Sep 19, 2025. It is now read-only.

Commit 22ab1fc

Browse files
committed
Split out codeAction mapper
1 parent d067edb commit 22ab1fc

File tree

1 file changed

+57
-46
lines changed

1 file changed

+57
-46
lines changed

src/autocomplete/deserializeCompletions.ts

Lines changed: 57 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import {
66
import { RawCompletion, RawCompletionItem } from "../types.js";
77
import { TransactionSpec } from "@codemirror/state";
88
import { renderDisplayParts } from "../hover/renderTooltip.js";
9+
import { EditorView } from "codemirror";
10+
import ts from "typescript";
911

1012
export function deserializeCompletions(raw: RawCompletion | null) {
1113
if (!raw) return raw;
@@ -21,56 +23,65 @@ function deserializeCompletion(raw: RawCompletionItem): Completion {
2123
return {
2224
label,
2325
type,
24-
// The default for CodeMirror completions is that when you hit Tab or the other trigger,
25-
// it will replace the current 'word' (partially-written text) with the label of the completion.
26-
// TypeScript provides codeActions that let you import new modules when you accept
27-
// a completion. This checks whether we have any codeActions, and if we do,
28-
// lets you import them automatically.
29-
apply: codeActions
30-
? (view, completion, from, to) => {
31-
const insTransaction: TransactionSpec = {
32-
...insertCompletionText(view.state, completion.label, from, to),
33-
annotations: pickedCompletion.of(completion),
34-
};
35-
36-
const actionTransactions: TransactionSpec[] = [];
37-
38-
// Complete, but also implement code actions.
39-
// https://github.com/codemirror/autocomplete/blob/30307656e85c9e5911a69fe2432de05be1580958/src/state.ts#L322
40-
for (const action of codeActions) {
41-
for (const change of action.changes) {
42-
for (const textChange of change.textChanges) {
43-
// Note that this may be dangerous! We've had many problems
44-
// with trying to dispatch transactions on CodeMirror when the length
45-
// of the document is different than what it expects or needs. I think
46-
// that this will be safe in that case because we're combining
47-
// and only declaring the length once.
48-
//
49-
// NOTE: this has less than ideal history behavior! ideal this would
50-
// be composed with `insTransaction` and produce one history event.
51-
// But that is tough because the two need to perfectly agree on the document that
52-
// they're editing, and the length of the document changes.
53-
actionTransactions.push({
54-
changes: [
55-
{
56-
from: textChange.span.start,
57-
to: textChange.span.start + textChange.span.length,
58-
insert: textChange.newText,
59-
},
60-
],
61-
annotations: pickedCompletion.of(completion),
62-
});
63-
}
64-
}
65-
}
66-
67-
view.dispatch(...[insTransaction, ...actionTransactions]);
68-
}
69-
: raw.label,
26+
apply: codeActions ? codeActionToApplyFunction(codeActions) : raw.label,
7027
info: () => {
7128
const elem = document.createElement("div");
7229
elem.appendChild(renderDisplayParts(raw.displayParts));
7330
return elem;
7431
},
7532
};
7633
}
34+
35+
/**
36+
* The default for CodeMirror completions is that when you hit Tab or the other trigger,
37+
* it will replace the current 'word' (partially-written text) with the label of the completion.
38+
* TypeScript provides codeActions that let you import new modules when you accept
39+
* a completion. This checks whether we have any codeActions, and if we do,
40+
* lets you import them automatically.
41+
*/
42+
export function codeActionToApplyFunction(codeActions: ts.CodeAction[]) {
43+
return (
44+
view: EditorView,
45+
completion: Completion,
46+
from: number,
47+
to: number,
48+
) => {
49+
const insTransaction: TransactionSpec = {
50+
...insertCompletionText(view.state, completion.label, from, to),
51+
annotations: pickedCompletion.of(completion),
52+
};
53+
54+
const actionTransactions: TransactionSpec[] = [];
55+
56+
// Complete, but also implement code actions.
57+
// https://github.com/codemirror/autocomplete/blob/30307656e85c9e5911a69fe2432de05be1580958/src/state.ts#L322
58+
for (const action of codeActions) {
59+
for (const change of action.changes) {
60+
for (const textChange of change.textChanges) {
61+
// Note that this may be dangerous! We've had many problems
62+
// with trying to dispatch transactions on CodeMirror when the length
63+
// of the document is different than what it expects or needs. I think
64+
// that this will be safe in that case because we're combining
65+
// and only declaring the length once.
66+
//
67+
// NOTE: this has less than ideal history behavior! ideal this would
68+
// be composed with `insTransaction` and produce one history event.
69+
// But that is tough because the two need to perfectly agree on the document that
70+
// they're editing, and the length of the document changes.
71+
actionTransactions.push({
72+
changes: [
73+
{
74+
from: textChange.span.start,
75+
to: textChange.span.start + textChange.span.length,
76+
insert: textChange.newText,
77+
},
78+
],
79+
annotations: pickedCompletion.of(completion),
80+
});
81+
}
82+
}
83+
}
84+
85+
view.dispatch(...[insTransaction, ...actionTransactions]);
86+
};
87+
}

0 commit comments

Comments
 (0)