diff --git a/frontend/components/CellInput/pluto_autocomplete.js b/frontend/components/CellInput/pluto_autocomplete.js index 0df4c5b6c4..3e9062bdb7 100644 --- a/frontend/components/CellInput/pluto_autocomplete.js +++ b/frontend/components/CellInput/pluto_autocomplete.js @@ -8,7 +8,7 @@ import { open_bottom_right_panel } from "../BottomRightPanel.js" import { ENABLE_CM_AUTOCOMPLETE_ON_TYPE } from "../CellInput.js" import { GlobalDefinitionsFacet } from "./go_to_definition_plugin.js" -let { autocompletion, completionKeymap, completionStatus, acceptCompletion } = autocomplete +let { autocompletion, completionKeymap, completionStatus, acceptCompletion, selectedCompletion } = autocomplete // These should be imported from @codemirror/autocomplete, but they are not exported. const completionState = autocompletion()[1] @@ -101,8 +101,11 @@ const pluto_autocomplete_keymap = [ */ let update_docs_from_autocomplete_selection = (on_update_doc_query) => { return EditorView.updateListener.of((update) => { - // Can't use this yet as it has not enough info to apply the change (source.from and source.to) - // let selected_completion = autocomplete.selectedCompletion(update.state) + // But we can use `selectedCompletion` to better check if the autocomplete is open + // (for some reason `autocompletion_state?.open != null` isn't enough anymore?) + // Sadly we still need `update.state.field(completionState, false)` as well because we can't + // apply the result from `selectedCompletion()` yet (has no .from and .to, for example) + if (selectedCompletion(update.state) == null) return let autocompletion_state = update.state.field(completionState, false) let open_autocomplete = autocompletion_state?.open @@ -123,6 +126,10 @@ let update_docs_from_autocomplete_selection = (on_update_doc_query) => { // Apply completion to state, which will yield us a `Transaction`. // The nice thing about this is that we can use the resulting state from the transaction, // without updating the actual state of the editor. + // NOTE This could bite someone who isn't familiar with this, but there isn't an easy way to fix it without a lot of console spam: + // .... THIS UPDATE WILL DO CONSOLE.LOG'S LIKE ANY UPDATE WOULD DO + // .... Which means you sometimes get double logs from codemirror extensions... + // .... Very disorienting 😵‍💫 let result_transaction = update.state.update({ changes: { from, @@ -183,9 +190,9 @@ const validFor = (text) => { /** Use the completion results from the Julia server to create CM completion objects. */ const julia_code_completions_to_cm = (/** @type {PlutoRequestAutocomplete} */ request_autocomplete) => async (/** @type {autocomplete.CompletionContext} */ ctx) => { - if (writing_variable_name_or_keyword(ctx)) return null if (match_special_symbol_complete(ctx)) return null - if (ctx.tokenBefore(["Number", "Comment", "String", "TripleString"]) != null) return null + if (!ctx.explicit && writing_variable_name_or_keyword(ctx)) return null + if (!ctx.explicit && ctx.tokenBefore(["Number", "Comment", "String", "TripleString"]) != null) return null let to_complete = /** @type {String} */ (ctx.state.sliceDoc(0, ctx.pos)) @@ -196,9 +203,6 @@ const julia_code_completions_to_cm = to_complete = to_complete.slice(0, is_symbol_completion.from + 1) + to_complete.slice(is_symbol_completion.from + 2) } - // no path autocompletions - if (ctx.tokenBefore(["String"]) != null) return null - const globals = ctx.state.facet(GlobalDefinitionsFacet) const is_already_a_global = (text) => text != null && Object.keys(globals).includes(text) @@ -284,9 +288,9 @@ const julia_code_completions_to_cm = } const complete_anyword = async (/** @type {autocomplete.CompletionContext} */ ctx) => { - if (writing_variable_name_or_keyword(ctx)) return null if (match_special_symbol_complete(ctx)) return null - if (ctx.tokenBefore(["Number", "Comment", "String", "TripleString"]) != null) return null + if (!ctx.explicit && writing_variable_name_or_keyword(ctx)) return null + if (!ctx.explicit && ctx.tokenBefore(["Number", "Comment", "String", "TripleString"]) != null) return null const results_from_cm = await autocomplete.completeAnyWord(ctx) if (results_from_cm === null) return null @@ -328,9 +332,9 @@ const writing_variable_name_or_keyword = (/** @type {autocomplete.CompletionCont /** @returns {Promise} */ const global_variables_completion = async (/** @type {autocomplete.CompletionContext} */ ctx) => { - if (writing_variable_name_or_keyword(ctx)) return null if (match_special_symbol_complete(ctx)) return null - if (ctx.tokenBefore(["Number", "Comment", "String", "TripleString"]) != null) return null + if (!ctx.explicit && writing_variable_name_or_keyword(ctx)) return null + if (!ctx.explicit && ctx.tokenBefore(["Number", "Comment", "String", "TripleString"]) != null) return null const globals = ctx.state.facet(GlobalDefinitionsFacet) @@ -417,9 +421,9 @@ const special_symbols_completion = (/** @type {() => Promise} * } return async (/** @type {autocomplete.CompletionContext} */ ctx) => { - if (writing_variable_name_or_keyword(ctx)) return null if (!match_special_symbol_complete(ctx)) return null - if (ctx.tokenBefore(["Number", "Comment"]) != null) return null + if (!ctx.explicit && writing_variable_name_or_keyword(ctx)) return null + if (!ctx.explicit && ctx.tokenBefore(["Number", "Comment"]) != null) return null const result = await get_special_symbols()