Files
parasitic-god/addons/limbo_console/command_entry.gd

131 lines
3.7 KiB
GDScript

extends TextEdit
## CommandEntry
signal text_submitted(command_line: String)
signal autocomplete_requested()
var autocomplete_hint: String:
set(value):
if autocomplete_hint != value:
autocomplete_hint = value
queue_redraw()
var _font: Font
var _font_size: int
var _hint_color: Color
var _sb_normal: StyleBox
func _init() -> void:
syntax_highlighter = CommandEntryHighlighter.new()
func _ready() -> void:
caret_multiple = false
autowrap_mode = TextServer.AUTOWRAP_OFF
scroll_fit_content_height = true
# placeholder_text = ""
get_v_scroll_bar().visibility_changed.connect(_hide_scrollbars)
get_h_scroll_bar().visibility_changed.connect(_hide_scrollbars)
_hide_scrollbars()
_font = get_theme_font("font")
_font_size = get_theme_font_size("font_size")
_hint_color = get_theme_color("hint_color")
_sb_normal = get_theme_stylebox("normal")
func _notification(what: int) -> void:
match what:
NOTIFICATION_FOCUS_ENTER:
set_process_input(true)
NOTIFICATION_FOCUS_EXIT:
set_process_input(false)
func _input(event: InputEvent) -> void:
if not has_focus():
return
if event is InputEventKey:
if event.keycode == KEY_ENTER or event.keycode == KEY_KP_ENTER:
if event.is_pressed():
submit_text()
get_viewport().set_input_as_handled()
elif event.keycode == KEY_C and event.get_modifiers_mask() == KEY_MASK_CTRL and get_selected_text().is_empty():
# Clear input on Ctrl+C if no text selected.
if event.is_pressed():
text = ""
text_changed.emit()
get_viewport().set_input_as_handled()
elif event.keycode in [KEY_RIGHT, KEY_END] and get_caret_column() == text.length():
# Request autocomplete on RIGHT & END.
if event.is_pressed() and not autocomplete_hint.is_empty():
autocomplete_requested.emit()
get_viewport().set_input_as_handled()
func _draw() -> void:
var offset_x: int = 0
offset_x += _sb_normal.get_offset().x * 0.5
offset_x += get_line_width(0)
var offset_y: int = 0
offset_y += _sb_normal.get_offset().y * 0.5
offset_y += get_line_height() + 0.5 # + line_spacing
offset_y -= _font.get_descent(_font_size)
draw_string(_font, Vector2(offset_x, offset_y), autocomplete_hint, 0, -1, _font_size, _hint_color)
func submit_text() -> void:
text_submitted.emit(text)
func _hide_scrollbars() -> void:
get_v_scroll_bar().hide()
get_h_scroll_bar().hide()
class CommandEntryHighlighter extends SyntaxHighlighter:
var command_found_color: Color
var subcommand_color: Color
var command_not_found_color: Color
var text_color: Color
func _get_line_syntax_highlighting(line: int) -> Dictionary:
var text: String = get_text_edit().text
var command_end_idx: int = -1 # index where last recognized command ends (with subcommands)
var argv: PackedStringArray = [] # argument vector (aka tokens)
var argi: PackedInt32Array = [] # argument starting indices in text
var start: int = 0
var cur: int = 0
for char in text + ' ':
if char == ' ':
if cur > start:
argv.append(text.substr(start, cur - start))
argi.append(start)
var maybe_command: String = ' '.join(argv)
if LimboConsole.has_command(maybe_command) or LimboConsole.has_alias(maybe_command):
command_end_idx = cur
start = cur + 1
cur += 1
var command_color: Color
var arg_start_idx: int = 0 # index where arguments start
if command_end_idx > -1:
command_color = command_found_color
arg_start_idx = command_end_idx + 1
else:
command_color = command_not_found_color
arg_start_idx = argi[1] if argi.size() > 1 else text.length()
var result: Dictionary
result[0] = { "color": command_color }
if command_end_idx > -1 and argi.size() > 1:
result[argi[1]] = { "color": subcommand_color }
result[arg_start_idx] = { "color": text_color }
return result