xsivgnazlixs/addons/dev_console/autocomplete_line.ts
2025-05-02 19:10:14 -05:00

84 lines
2.3 KiB
TypeScript

import { Callable, Callable1, InputEvent, LineEdit, Variant } from 'godot'
import { export_, onready } from 'godot.annotations'
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<string>
_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 = ''
}
}