forked from limbonaut/limbo_console
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcommand_entry.gd
More file actions
130 lines (102 loc) · 3.69 KB
/
command_entry.gd
File metadata and controls
130 lines (102 loc) · 3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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