66import { RawCompletion , RawCompletionItem } from "../types.js" ;
77import { TransactionSpec } from "@codemirror/state" ;
88import { renderDisplayParts } from "../hover/renderTooltip.js" ;
9+ import { EditorView } from "codemirror" ;
10+ import ts from "typescript" ;
911
1012export 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