Skip to content

Commit

Permalink
Add activateOnCompletion option
Browse files Browse the repository at this point in the history
FEATURE: The new `activateOnCompletion` option allows autocompletion to be configured
to chain completion activation for some types of completions.

Issue https://discuss.codemirror.net/t/how-to-invoke-autocomplete-immediately-after-a-completion-is-selected/8040
  • Loading branch information
marijnh committed Apr 11, 2024
1 parent 5ad2ebc commit 4f944fc
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 5 deletions.
4 changes: 4 additions & 0 deletions src/config.ts
Expand Up @@ -7,6 +7,9 @@ export interface CompletionConfig {
/// When enabled (defaults to true), autocompletion will start
/// whenever the user types something that can be completed.
activateOnTyping?: boolean
/// When given, if a completion that matches the predicate is
/// picked, reactivate completion again as if it was typed normally.
activateOnCompletion?: (completion: Completion) => boolean
/// The amount of time to wait for further typing before querying
/// completion sources via
/// [`activateOnTyping`](#autocomplete.autocompletion^config.activateOnTyping).
Expand Down Expand Up @@ -93,6 +96,7 @@ export const completionConfig = Facet.define<CompletionConfig, Required<Completi
combine(configs) {
return combineConfig<Required<CompletionConfig>>(configs, {
activateOnTyping: true,
activateOnCompletion: () => false,
activateOnTypingDelay: 100,
selectOnOpen: true,
override: null,
Expand Down
8 changes: 6 additions & 2 deletions src/state.ts
Expand Up @@ -186,7 +186,11 @@ const none: readonly any[] = []

export const enum State { Inactive = 0, Pending = 1, Result = 2 }

export function getUserEvent(tr: Transaction): "input" | "delete" | null {
export function getUserEvent(tr: Transaction, conf: Required<CompletionConfig>): "input" | "delete" | null {
if (tr.isUserEvent("input.complete")) {
let completion = tr.annotation(pickedCompletion)
if (completion && conf.activateOnCompletion(completion)) return "input"
}
return tr.isUserEvent("input.type") ? "input" : tr.isUserEvent("delete.backward") ? "delete" : null
}

Expand All @@ -198,7 +202,7 @@ export class ActiveSource {
hasResult(): this is ActiveResult { return false }

update(tr: Transaction, conf: Required<CompletionConfig>): ActiveSource {
let event = getUserEvent(tr), value: ActiveSource = this
let event = getUserEvent(tr, conf), value: ActiveSource = this
if (event)
value = value.handleUserEvent(tr, event, conf)
else if (tr.docChanged)
Expand Down
7 changes: 4 additions & 3 deletions src/view.ts
Expand Up @@ -82,10 +82,11 @@ export const completionPlugin = ViewPlugin.fromClass(class implements PluginValu

update(update: ViewUpdate) {
let cState = update.state.field(completionState)
let conf = update.state.facet(completionConfig)
if (!update.selectionSet && !update.docChanged && update.startState.field(completionState) == cState) return

let doesReset = update.transactions.some(tr => {
return (tr.selection || tr.docChanged) && !getUserEvent(tr)
return (tr.selection || tr.docChanged) && !getUserEvent(tr, conf)
})
for (let i = 0; i < this.running.length; i++) {
let query = this.running[i]
Expand All @@ -104,12 +105,12 @@ export const completionPlugin = ViewPlugin.fromClass(class implements PluginValu

if (this.debounceUpdate > -1) clearTimeout(this.debounceUpdate)
if (update.transactions.some(tr => tr.effects.some(e => e.is(startCompletionEffect)))) this.pendingStart = true
let delay = this.pendingStart ? 50 : update.state.facet(completionConfig).activateOnTypingDelay
let delay = this.pendingStart ? 50 : conf.activateOnTypingDelay
this.debounceUpdate = cState.active.some(a => a.state == State.Pending && !this.running.some(q => q.active.source == a.source))
? setTimeout(() => this.startUpdate(), delay) : -1

if (this.composing != CompositionState.None) for (let tr of update.transactions) {
if (getUserEvent(tr) == "input")
if (getUserEvent(tr, conf) == "input")
this.composing = CompositionState.Changed
else if (this.composing == CompositionState.Changed && tr.selection)
this.composing = CompositionState.ChangedAndMoved
Expand Down

0 comments on commit 4f944fc

Please sign in to comment.