From c2471260eca4b1c57cbefcce7583d24e03efc07f Mon Sep 17 00:00:00 2001 From: Paul Berg Date: Mon, 15 Jul 2024 14:41:36 +0200 Subject: [PATCH] enable paths autocompletions (#2949) Co-authored-by: Fons van der Plas --- .../CellInput/pluto_autocomplete.js | 50 +++++-------------- src/runner/PlutoRunner/src/PlutoRunner.jl | 20 +++++--- 2 files changed, 25 insertions(+), 45 deletions(-) diff --git a/frontend/components/CellInput/pluto_autocomplete.js b/frontend/components/CellInput/pluto_autocomplete.js index 5fdbf9400c..edca7a4aee 100644 --- a/frontend/components/CellInput/pluto_autocomplete.js +++ b/frontend/components/CellInput/pluto_autocomplete.js @@ -13,34 +13,6 @@ let { autocompletion, completionKeymap, completionStatus, acceptCompletion, sele // These should be imported from @codemirror/autocomplete, but they are not exported. const completionState = autocompletion()[1] -/** @type {any} */ -const TabCompletionEffect = StateEffect.define() -const tabCompletionState = StateField.define({ - create() { - return false - }, - - update(value, /** @type {Transaction} */ tr) { - // Tab was pressed - for (let effect of tr.effects) { - if (effect.is(TabCompletionEffect)) return true - } - if (!value) return false - - let previous_selected = autocomplete.selectedCompletion(tr.startState) - let current_selected = autocomplete.selectedCompletion(tr.state) - - // Autocomplete window was closed - if (previous_selected != null && current_selected == null) { - return false - } - if (previous_selected != null && previous_selected !== current_selected) { - return false - } - return value - }, -}) - /** @param {EditorView} cm */ const tab_completion_command = (cm) => { // This will return true if the autocomplete select popup is open @@ -66,9 +38,6 @@ const tab_completion_command = (cm) => { // ?([1,2], 3) should trigger autocomplete if (last_char === ")" && !last_line.includes("?")) return false - cm.dispatch({ - effects: TabCompletionEffect.of(10), - }) return autocomplete.startCompletion(cm) } @@ -224,9 +193,11 @@ const julia_code_completions_to_cm = // console.debug({ definitions }) // const proposed = new Set() - let to_complete_onto = to_complete.slice(0, start) - let is_field_expression = to_complete_onto.endsWith(".") - let is_listing_all_fields_of_a_module = is_field_expression && start === stop + const to_complete_onto = to_complete.slice(0, start) + const is_field_expression = to_complete_onto.endsWith(".") + + // skip autocomplete's filter if we are completing a ~ path (userexpand) + const skip_filter = ctx.matchBefore(/\~[^\s\"]*/) != null return { from: start, @@ -239,10 +210,14 @@ const julia_code_completions_to_cm = validFor, commitCharacters: julia_commit_characters, + filter: !skip_filter, options: [ ...results - .filter(([text, _1, _2, is_from_notebook]) => !(is_from_notebook && is_already_a_global(text))) + .filter( + ([text, _1, _2, is_from_notebook, completion_type]) => + (ctx.explicit || completion_type != "path") && !(is_from_notebook && is_already_a_global(text)) + ) .map(([text, value_type, is_exported, is_from_notebook, completion_type, _ignored], i) => { // (quick) fix for identifiers that need to be escaped // Ideally this is done with Meta.isoperator on the julia side @@ -420,7 +395,7 @@ const special_emoji_examples = ["🐶", "🐱", "🐭", "🐰", "🐼", "🐨", const apply_completion = (view, completion, from, to) => { const currentComp = view.state.sliceDoc(from, to) - let insert = completion.detail ?? completion.label; + let insert = completion.detail ?? completion.label const is_emoji = completion.label.startsWith("\\:") if (!is_emoji && currentComp !== completion.label) { const is_inside_string = match_string_complete(view.state, to) @@ -429,7 +404,7 @@ const apply_completion = (view, completion, from, to) => { } } - view.dispatch({ changes: {from, to, insert}, annotations: autocomplete.pickedCompletion.of(completion), }) + view.dispatch({ changes: { from, to, insert }, annotations: autocomplete.pickedCompletion.of(completion) }) } const special_symbols_completion = (/** @type {() => Promise} */ request_special_symbols) => { @@ -535,7 +510,6 @@ export let pluto_autocomplete = ({ request_autocomplete, request_special_symbols } return [ - tabCompletionState, autocompletion({ activateOnTyping: ENABLE_CM_AUTOCOMPLETE_ON_TYPE, override: [ diff --git a/src/runner/PlutoRunner/src/PlutoRunner.jl b/src/runner/PlutoRunner/src/PlutoRunner.jl index 0435a4ec5c..2a8cf72690 100644 --- a/src/runner/PlutoRunner/src/PlutoRunner.jl +++ b/src/runner/PlutoRunner/src/PlutoRunner.jl @@ -2025,8 +2025,8 @@ function completion_fetcher(query, pos, workspace::Module) results, loc, found = FuzzyCompletions.completions( query, pos, workspace; enable_questionmark_methods=false, - enable_expanduser=false, - enable_path=false, + enable_expanduser=true, + enable_path=true, enable_methods=false, enable_packages=false, ) @@ -2034,16 +2034,22 @@ function completion_fetcher(query, pos, workspace::Module) if endswith(partial, '.') filter!(is_dot_completion, results) # we are autocompleting a module, and we want to see its fields alphabetically - sort!(results; by=(r -> completion_text(r))) + sort!(results; by=completion_text) elseif endswith(partial, '/') filter!(is_path_completion, results) - sort!(results; by=(r -> completion_text(r))) + sort!(results; by=completion_text) elseif endswith(partial, '[') filter!(is_dict_completion, results) - sort!(results; by=(r -> completion_text(r))) + sort!(results; by=completion_text) else - isenough(x) = x ≥ 0 - filter!(r -> is_kwarg_completion(r) || isenough(score(r)) && !is_path_completion(r), results) # too many candiates otherwise + contains_slash = '/' ∈ partial + if !contains_slash + filter!(!is_path_completion, results) + end + filter!( + r -> is_kwarg_completion(r) || score(r) >= 0, + results + ) # too many candidates otherwise end exported = completions_exported(results)