Skip to content

Commit

Permalink
Add support for commit characters
Browse files Browse the repository at this point in the history
FEATURE: Completions may now provide 'commit characters' that, when typed,
commit the completion before inserting the character.

Issue codemirror/dev#1346
  • Loading branch information
marijnh committed Feb 28, 2024
1 parent fb1c899 commit 3cc305c
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 2 deletions.
7 changes: 7 additions & 0 deletions src/completion.ts
Expand Up @@ -39,6 +39,9 @@ export interface Completion {
///
/// Multiple types can be provided by separating them with spaces.
type?: string
/// When this option is selected, and one of these characters is
/// typed, insert the completion before typing the character.
commitCharacters?: readonly string[],
/// When given, should be a number from -99 to 99 that adjusts how
/// this completion is ranked compared to other completions that
/// match the input as well as this one. A negative number moves it
Expand Down Expand Up @@ -229,6 +232,10 @@ 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
/// Set a default set of [commit
/// characters](#autocomplete.Completion.commitCharacters) for all
/// options in this result.
commitCharacters?: readonly string[]
}

export class Option {
Expand Down
4 changes: 3 additions & 1 deletion src/index.ts
Expand Up @@ -3,7 +3,8 @@ import {keymap, KeyBinding} from "@codemirror/view"
import {Completion, Option} from "./completion"
import {completionState, State, setSelectedEffect} from "./state"
import {CompletionConfig, completionConfig} from "./config"
import {completionPlugin, moveCompletionSelection, acceptCompletion, startCompletion, closeCompletion} from "./view"
import {completionPlugin, moveCompletionSelection, acceptCompletion,
startCompletion, closeCompletion, commitCharacters} from "./view"
import {baseTheme} from "./theme"

export {snippet, snippetCompletion, nextSnippetField, prevSnippetField,
Expand All @@ -17,6 +18,7 @@ export {CloseBracketConfig, closeBrackets, closeBracketsKeymap, deleteBracketPai
/// Returns an extension that enables autocompletion.
export function autocompletion(config: CompletionConfig = {}): Extension {
return [
commitCharacters,
completionState,
completionConfig.of(config),
completionPlugin,
Expand Down
19 changes: 18 additions & 1 deletion src/view.ts
@@ -1,6 +1,6 @@
import {EditorView, Command, ViewPlugin, PluginValue, ViewUpdate, logException,
getTooltip, TooltipView} from "@codemirror/view"
import {Transaction} from "@codemirror/state"
import {Transaction, Prec} from "@codemirror/state"
import {completionState, setSelectedEffect, setActiveEffect, State,
ActiveSource, ActiveResult, getUserEvent, applyCompletion} from "./state"
import {completionConfig} from "./config"
Expand Down Expand Up @@ -216,3 +216,20 @@ export const completionPlugin = ViewPlugin.fromClass(class implements PluginValu
}
}
})

const windows = typeof navigator == "object" && /Win/.test(navigator.platform)

export const commitCharacters = Prec.highest(EditorView.domEventHandlers({
keydown(event, view) {
let field = view.state.field(completionState, false)
if (!field || !field.open || field.open.disabled || field.open.selected < 0 ||
event.key.length > 1 || event.ctrlKey && !(windows && event.altKey) || event.metaKey)
return false
let option = field.open.options[field.open.selected]
let result = field.active.find(a => a.source == option.source) as ActiveResult
let commitChars = option.completion.commitCharacters || result.result.commitCharacters
if (commitChars && commitChars.indexOf(event.key) > -1)
applyCompletion(view, option)
return false
}
}))

0 comments on commit 3cc305c

Please sign in to comment.