Skip to content

Commit

Permalink
Add support for CompletionResult.map
Browse files Browse the repository at this point in the history
FEATURE: Completion results can now define a `map` method that can be used
to adjust position-dependent information for document changes.

Issue codemirror/dev#1347
  • Loading branch information
marijnh committed Mar 4, 2024
1 parent e29c830 commit ee22fa2
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 11 deletions.
8 changes: 7 additions & 1 deletion src/completion.ts
@@ -1,5 +1,5 @@
import {EditorView} from "@codemirror/view"
import {EditorState, StateEffect, Annotation, EditorSelection, TransactionSpec} from "@codemirror/state"
import {EditorState, StateEffect, Annotation, EditorSelection, TransactionSpec, ChangeDesc} from "@codemirror/state"
import {syntaxTree} from "@codemirror/language"
import {SyntaxNode} from "@lezer/common"

Expand Down Expand Up @@ -232,6 +232,12 @@ export interface CompletionResult {
/// [`validFor`](#autocomplete.CompletionResult.validFor)) that the
/// completion still applies in the new state.
update?: (current: CompletionResult, from: number, to: number, context: CompletionContext) => CompletionResult | null
/// When results contain position-dependent information in, for
/// example, `apply` methods, you can provide this method to update
/// the result for transactions that happen after the query. It is
/// not necessary to update `from` and `to`—those are tracked
/// automatically.
map?: (current: CompletionResult, changes: ChangeDesc) => CompletionResult | null
/// Set a default set of [commit
/// characters](#autocomplete.Completion.commitCharacters) for all
/// options in this result.
Expand Down
24 changes: 14 additions & 10 deletions src/state.ts
Expand Up @@ -240,18 +240,20 @@ export class ActiveResult extends ActiveSource {
hasResult(): this is ActiveResult { return true }

handleUserEvent(tr: Transaction, type: "input" | "delete", conf: Required<CompletionConfig>): ActiveSource {
let result = this.result as CompletionResult | null
if (result!.map && !tr.changes.empty) result = result!.map(result!, tr.changes)
let from = tr.changes.mapPos(this.from), to = tr.changes.mapPos(this.to, 1)
let pos = cur(tr.state)
if ((this.explicitPos < 0 ? pos <= from : pos < this.from) ||
pos > to ||
pos > to || !result ||
type == "delete" && cur(tr.startState) == this.from)
return new ActiveSource(this.source, type == "input" && conf.activateOnTyping ? State.Pending : State.Inactive)
let explicitPos = this.explicitPos < 0 ? -1 : tr.changes.mapPos(this.explicitPos), updated
if (checkValid(this.result.validFor, tr.state, from, to))
return new ActiveResult(this.source, explicitPos, this.result, from, to)
if (this.result.update &&
(updated = this.result.update(this.result, from, to, new CompletionContext(tr.state, pos, explicitPos >= 0))))
return new ActiveResult(this.source, explicitPos, updated, updated.from, updated.to ?? cur(tr.state))
let explicitPos = this.explicitPos < 0 ? -1 : tr.changes.mapPos(this.explicitPos)
if (checkValid(result.validFor, tr.state, from, to))
return new ActiveResult(this.source, explicitPos, result, from, to)
if (result.update &&
(result = result.update(result, from, to, new CompletionContext(tr.state, pos, explicitPos >= 0))))
return new ActiveResult(this.source, explicitPos, result, result.from, result.to ?? cur(tr.state))
return new ActiveSource(this.source, State.Pending, explicitPos)
}

Expand All @@ -260,9 +262,11 @@ export class ActiveResult extends ActiveSource {
}

map(mapping: ChangeDesc) {
return mapping.empty ? this :
new ActiveResult(this.source, this.explicitPos < 0 ? -1 : mapping.mapPos(this.explicitPos), this.result,
mapping.mapPos(this.from), mapping.mapPos(this.to, 1))
if (mapping.empty) return this
let result = this.result.map ? this.result.map(this.result, mapping) : this.result
if (!result) return new ActiveSource(this.source, State.Inactive)
return new ActiveResult(this.source, this.explicitPos < 0 ? -1 : mapping.mapPos(this.explicitPos), this.result,
mapping.mapPos(this.from), mapping.mapPos(this.to, 1))
}
}

Expand Down

0 comments on commit ee22fa2

Please sign in to comment.