Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow autocomplete in strings and comments with <TAB> #2892

Merged
merged 1 commit into from
Apr 11, 2024
Merged
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
32 changes: 18 additions & 14 deletions frontend/components/CellInput/pluto_autocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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))

Expand All @@ -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)

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -328,9 +332,9 @@ const writing_variable_name_or_keyword = (/** @type {autocomplete.CompletionCont

/** @returns {Promise<autocomplete.CompletionResult?>} */
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)

Expand Down Expand Up @@ -417,9 +421,9 @@ const special_symbols_completion = (/** @type {() => Promise<SpecialSymbols?>} *
}

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()

Expand Down
Loading