import { Callable, Callable1, InputEvent, LineEdit, Variant } from 'godot' import { export_, onready } from 'godot.annotations' import { Enumerable, IEnumerable } from '../enumerable-ts/src/index' import { Action } from './dev_console' export default class AutocompleteLine extends LineEdit { @export_(Variant.Type.TYPE_BOOL) private auto_suggest: boolean = true @onready("Suggestion") private suggestion!: LineEdit autocomplete_list: string[] = [] current_suggestions: string[] = [] suggestion_index: number = -1 suppress_focus_change: boolean = true _on_text_changed!: Callable1 _ready(): void { this._on_text_changed = Callable.create(this, this.suggest) if (this.auto_suggest) { this.text_changed.connect(this._on_text_changed) } } _input(event: InputEvent): void { if (this.has_focus() && this.suppress_focus_change) if (event.is_action_pressed(Action.FocusPrevious)) { this.accept_event() this.autocomplete(-1) } else if (event.is_action_pressed(Action.FocusNext)) { this.accept_event() this.autocomplete(1) } } suggest(value: string): boolean { this.reset() if (value == '') { return false } this.current_suggestions = this.fuzzy_find(value) if (this.current_suggestions.length > 0) { const suggestion = this.current_suggestions[0] if (suggestion != null) { // create the illusion that the text is autocompleting // by replacing the already typed characters with spaces const padded = suggestion.slice(value.length).padStart(suggestion.length, ' ') this.suggestion.text = padded return true } } this.suggestion.text = '' return false } set_caret_to_end() { this.caret_column = this.text.length + 1 } autocomplete(direction: (-1 | 1)) { if (this.current_suggestions.length > 0) { this.suggestion_index = (this.suggestion_index + direction) % this.current_suggestions.length this.text = this.current_suggestions.at(this.suggestion_index) || '' this.suggestion.clear() this.set_caret_to_end() } } fuzzy_find(value: string): string[] { return this.autocomplete_list.filter(text => text != null && text.startsWith(value)) } reset() { this.current_suggestions = [] this.suggestion_index = -1 this.suggestion.text = '' } }