@rbxts/centurion-ui 1.0.0-dev-dd918ea → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/components/history/history-list.luau +16 -16
- package/out/components/terminal/command.luau +2 -2
- package/out/components/terminal/suggestion.luau +34 -21
- package/out/components/terminal/terminal-text-field/index.d.ts +1 -0
- package/out/components/terminal/terminal-text-field/init.luau +7 -0
- package/out/components/terminal/terminal-text-field/suggestion.d.ts +5 -0
- package/out/components/terminal/terminal-text-field/suggestion.luau +128 -0
- package/out/components/terminal/{terminal-text-field.luau → terminal-text-field/terminal-text-field.luau} +51 -172
- package/out/components/terminal/terminal.luau +37 -32
- package/out/store.luau +1 -1
- package/package.json +9 -10
- /package/out/components/terminal/{terminal-text-field.d.ts → terminal-text-field/terminal-text-field.d.ts} +0 -0
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
local TS = _G[script]
|
|
3
3
|
local _vide = TS.import(script, TS.getModule(script, "@rbxts", "vide").src)
|
|
4
4
|
local Vide = _vide
|
|
5
|
-
local
|
|
5
|
+
local derive = _vide.derive
|
|
6
6
|
local For = _vide.For
|
|
7
7
|
local read = _vide.read
|
|
8
|
-
local source = _vide.source
|
|
9
8
|
local useAtom = TS.import(script, script.Parent.Parent.Parent, "hooks", "use-atom").useAtom
|
|
10
9
|
local px = TS.import(script, script.Parent.Parent.Parent, "hooks", "use-px").px
|
|
11
10
|
local interfaceOptions = TS.import(script, script.Parent.Parent.Parent, "store").interfaceOptions
|
|
@@ -17,29 +16,30 @@ local function HistoryList(_param)
|
|
|
17
16
|
local position = _param.position
|
|
18
17
|
local maxHeight = _param.maxHeight
|
|
19
18
|
local options = useAtom(interfaceOptions)
|
|
20
|
-
local
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
canvasSize(UDim2.new(0, 0, 0, height))
|
|
26
|
-
canvasPos(Vector2.new(0, height))
|
|
27
|
-
if maxHeight ~= nil then
|
|
28
|
-
scrollingEnabled(height > read(maxHeight))
|
|
29
|
-
end
|
|
19
|
+
local height = derive(function()
|
|
20
|
+
return read(data).height - px(8)
|
|
21
|
+
end)
|
|
22
|
+
local exceedsMaxHeight = derive(function()
|
|
23
|
+
return maxHeight ~= nil and height() > read(maxHeight)
|
|
30
24
|
end)
|
|
31
25
|
return Vide.jsx(ScrollingFrame, {
|
|
32
26
|
size = size,
|
|
33
27
|
position = position,
|
|
34
|
-
canvasSize =
|
|
35
|
-
|
|
28
|
+
canvasSize = function()
|
|
29
|
+
return UDim2.fromOffset(0, height())
|
|
30
|
+
end,
|
|
31
|
+
canvasPosition = function()
|
|
32
|
+
return Vector2.new(0, height())
|
|
33
|
+
end,
|
|
36
34
|
scrollBarColor = function()
|
|
37
35
|
return options().palette.subtext
|
|
38
36
|
end,
|
|
39
37
|
scrollBarThickness = function()
|
|
40
|
-
return if
|
|
38
|
+
return if exceedsMaxHeight() then 10 else 0
|
|
39
|
+
end,
|
|
40
|
+
scrollingEnabled = function()
|
|
41
|
+
return exceedsMaxHeight()
|
|
41
42
|
end,
|
|
42
|
-
scrollingEnabled = scrollingEnabled,
|
|
43
43
|
}, Vide.jsx(For, {
|
|
44
44
|
each = function()
|
|
45
45
|
return read(data).lines
|
|
@@ -5,7 +5,7 @@ local ImmutableRegistryPath = _centurion.ImmutableRegistryPath
|
|
|
5
5
|
local RegistryPath = _centurion.RegistryPath
|
|
6
6
|
local IS_EDIT = TS.import(script, script.Parent.Parent.Parent, "constants", "util").IS_EDIT
|
|
7
7
|
local function formatPartsAsPath(parts)
|
|
8
|
-
return table.concat(parts, "/")
|
|
8
|
+
return string.lower(table.concat(parts, "/"))
|
|
9
9
|
end
|
|
10
10
|
local function getValidPath(registry, text)
|
|
11
11
|
if #text == 0 then
|
|
@@ -17,7 +17,7 @@ local function getValidPath(registry, text)
|
|
|
17
17
|
end
|
|
18
18
|
local path = RegistryPath:empty()
|
|
19
19
|
for _, part in text do
|
|
20
|
-
path:append(part)
|
|
20
|
+
path:append(string.lower(part))
|
|
21
21
|
if registry:getCommand(path) == nil and registry:getGroup(path) == nil and #registry:getChildPaths(path) == 0 then
|
|
22
22
|
path:remove(path:size() - 1)
|
|
23
23
|
break
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
local TS = _G[script]
|
|
3
3
|
local Players = TS.import(script, TS.getModule(script, "@rbxts", "services")).Players
|
|
4
4
|
local MAX_OTHER_SUGGESTIONS = 3
|
|
5
|
+
local function formatText(text)
|
|
6
|
+
return if #{ string.match(text, "%s") } == 0 then text else `"{text}"`
|
|
7
|
+
end
|
|
5
8
|
local function getMatches(strings, text)
|
|
6
9
|
if text == nil then
|
|
7
10
|
table.sort(strings)
|
|
@@ -41,51 +44,61 @@ local function getMatches(strings, text)
|
|
|
41
44
|
return _newValue
|
|
42
45
|
end
|
|
43
46
|
local function getArgumentSuggestion(arg, textPart)
|
|
44
|
-
local _array = {}
|
|
45
|
-
local _length = #_array
|
|
46
|
-
local _array_1 = (arg.options.suggestions or {})
|
|
47
|
-
table.move(_array_1, 1, #_array_1, _length + 1, _array)
|
|
48
|
-
local suggestions = _array
|
|
49
|
-
local singleArg = arg.kind == "single"
|
|
50
47
|
local _result
|
|
48
|
+
if arg.options.suggestions ~= nil then
|
|
49
|
+
local _exp = arg.options.suggestions
|
|
50
|
+
-- ▼ ReadonlyArray.map ▼
|
|
51
|
+
local _newValue = table.create(#_exp)
|
|
52
|
+
for _k, _v in _exp do
|
|
53
|
+
_newValue[_k] = formatText(_v, _k - 1, _exp)
|
|
54
|
+
end
|
|
55
|
+
-- ▲ ReadonlyArray.map ▲
|
|
56
|
+
_result = _newValue
|
|
57
|
+
else
|
|
58
|
+
_result = {}
|
|
59
|
+
end
|
|
60
|
+
local suggestions = _result
|
|
61
|
+
local singleArg = arg.kind == "single"
|
|
62
|
+
local _result_1
|
|
51
63
|
if singleArg then
|
|
52
|
-
local
|
|
53
|
-
if
|
|
64
|
+
local _result_2 = arg.type.suggestions
|
|
65
|
+
if _result_2 ~= nil then
|
|
54
66
|
local _condition = arg.input
|
|
55
67
|
if _condition == nil then
|
|
56
68
|
_condition = ""
|
|
57
69
|
end
|
|
58
|
-
|
|
70
|
+
_result_2 = _result_2(_condition, Players.LocalPlayer)
|
|
59
71
|
end
|
|
60
|
-
|
|
72
|
+
_result_1 = _result_2
|
|
61
73
|
else
|
|
62
|
-
local
|
|
63
|
-
if
|
|
64
|
-
|
|
74
|
+
local _result_2 = arg.type.suggestions
|
|
75
|
+
if _result_2 ~= nil then
|
|
76
|
+
_result_2 = _result_2(arg.input, Players.LocalPlayer)
|
|
65
77
|
end
|
|
66
|
-
|
|
78
|
+
_result_1 = _result_2
|
|
67
79
|
end
|
|
68
|
-
local typeSuggestions =
|
|
80
|
+
local typeSuggestions = _result_1
|
|
69
81
|
if typeSuggestions ~= nil then
|
|
70
82
|
for _, text in typeSuggestions do
|
|
71
|
-
|
|
83
|
+
local _arg0 = formatText(text)
|
|
84
|
+
table.insert(suggestions, _arg0)
|
|
72
85
|
end
|
|
73
86
|
end
|
|
74
87
|
local errorText
|
|
75
88
|
if not arg.type.expensive then
|
|
76
89
|
local success, err = pcall(function()
|
|
77
|
-
local
|
|
90
|
+
local _result_2
|
|
78
91
|
if singleArg then
|
|
79
92
|
local _type = arg.type
|
|
80
93
|
local _condition = arg.input
|
|
81
94
|
if _condition == nil then
|
|
82
95
|
_condition = ""
|
|
83
96
|
end
|
|
84
|
-
|
|
97
|
+
_result_2 = _type.transform(_condition, Players.LocalPlayer)
|
|
85
98
|
else
|
|
86
|
-
|
|
99
|
+
_result_2 = arg.type.transform(arg.input, Players.LocalPlayer)
|
|
87
100
|
end
|
|
88
|
-
local transformResult =
|
|
101
|
+
local transformResult = _result_2
|
|
89
102
|
if transformResult.ok then
|
|
90
103
|
return nil
|
|
91
104
|
end
|
|
@@ -170,7 +183,7 @@ local function getCommandSuggestion(registry, parentPath, text)
|
|
|
170
183
|
local _newValue_1 = table.create(#sortedPaths)
|
|
171
184
|
local _callback_1 = function(_param)
|
|
172
185
|
local str = _param[2]
|
|
173
|
-
return str
|
|
186
|
+
return formatText(str)
|
|
174
187
|
end
|
|
175
188
|
for _k, _v in sortedPaths do
|
|
176
189
|
_newValue_1[_k] = _callback_1(_v, _k - 1, sortedPaths)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./terminal-text-field";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { BaseRegistry } from "@rbxts/centurion";
|
|
2
|
+
import { Suggestion } from "../../../types";
|
|
3
|
+
export declare function completeCommand(registry: BaseRegistry, text: string, suggestion: string): string;
|
|
4
|
+
export declare function completeArgument(text: string, suggestion: string, commandArgCount: number): string;
|
|
5
|
+
export declare function getSuggestedText(registry: BaseRegistry, text: string, suggestion?: Suggestion): string;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local _store = TS.import(script, script.Parent.Parent.Parent.Parent, "store")
|
|
4
|
+
local commandArgIndex = _store.commandArgIndex
|
|
5
|
+
local currentCommandPath = _store.currentCommandPath
|
|
6
|
+
local currentTextPart = _store.currentTextPart
|
|
7
|
+
local terminalArgIndex = _store.terminalArgIndex
|
|
8
|
+
local terminalTextParts = _store.terminalTextParts
|
|
9
|
+
local _command = TS.import(script, script.Parent.Parent, "command")
|
|
10
|
+
local formatPartsAsPath = _command.formatPartsAsPath
|
|
11
|
+
local getArgumentNames = _command.getArgumentNames
|
|
12
|
+
local function replaceTextPart(text, ...)
|
|
13
|
+
local suggestions = { ... }
|
|
14
|
+
local currentPart = currentTextPart()
|
|
15
|
+
local _result = currentPart
|
|
16
|
+
if _result ~= nil then
|
|
17
|
+
_result = #_result
|
|
18
|
+
end
|
|
19
|
+
local _condition = _result
|
|
20
|
+
if _condition == nil then
|
|
21
|
+
_condition = 0
|
|
22
|
+
end
|
|
23
|
+
local currentPartSize = _condition
|
|
24
|
+
local _text = text
|
|
25
|
+
local _arg1 = #text - currentPartSize
|
|
26
|
+
local result = string.sub(_text, 0, _arg1)
|
|
27
|
+
result ..= table.concat(suggestions, " ")
|
|
28
|
+
return result
|
|
29
|
+
end
|
|
30
|
+
local function completeCommand(registry, text, suggestion)
|
|
31
|
+
local textParts = terminalTextParts()
|
|
32
|
+
local atNextPart = string.sub(text, -1) == " "
|
|
33
|
+
local _array = {}
|
|
34
|
+
local _length = #_array
|
|
35
|
+
table.move(textParts, 1, #textParts, _length + 1, _array)
|
|
36
|
+
local pathParts = _array
|
|
37
|
+
if not atNextPart then
|
|
38
|
+
local _arg0 = #textParts - 1
|
|
39
|
+
table.remove(pathParts, _arg0 + 1)
|
|
40
|
+
end
|
|
41
|
+
local _suggestion = suggestion
|
|
42
|
+
table.insert(pathParts, _suggestion)
|
|
43
|
+
local _command_1 = registry:getCommandByString(formatPartsAsPath(pathParts))
|
|
44
|
+
if _command_1 ~= nil then
|
|
45
|
+
_command_1 = _command_1.options
|
|
46
|
+
end
|
|
47
|
+
local command = _command_1
|
|
48
|
+
local result = replaceTextPart(text, suggestion)
|
|
49
|
+
-- Add a space if this path isn't a command (meaning it's a group) or is a command with arguments
|
|
50
|
+
local _condition = command == nil
|
|
51
|
+
if not _condition then
|
|
52
|
+
local _result = command.arguments
|
|
53
|
+
if _result ~= nil then
|
|
54
|
+
_result = #_result == 0
|
|
55
|
+
end
|
|
56
|
+
local _condition_1 = _result
|
|
57
|
+
if _condition_1 == nil then
|
|
58
|
+
_condition_1 = true
|
|
59
|
+
end
|
|
60
|
+
_condition = not _condition_1
|
|
61
|
+
end
|
|
62
|
+
if _condition then
|
|
63
|
+
result ..= " "
|
|
64
|
+
end
|
|
65
|
+
return result
|
|
66
|
+
end
|
|
67
|
+
local function completeArgument(text, suggestion, commandArgCount)
|
|
68
|
+
local argIndex = terminalArgIndex()
|
|
69
|
+
if argIndex == nil or commandArgCount == 0 then
|
|
70
|
+
return text
|
|
71
|
+
end
|
|
72
|
+
local result = replaceTextPart(text, suggestion)
|
|
73
|
+
if argIndex < commandArgCount - 1 then
|
|
74
|
+
result ..= " "
|
|
75
|
+
end
|
|
76
|
+
return result
|
|
77
|
+
end
|
|
78
|
+
local function getSuggestedText(registry, text, suggestion)
|
|
79
|
+
if suggestion == nil then
|
|
80
|
+
return text
|
|
81
|
+
end
|
|
82
|
+
local suggestionText
|
|
83
|
+
local parts = terminalTextParts()
|
|
84
|
+
if #parts == 0 or suggestion.type == "command" then
|
|
85
|
+
suggestionText = suggestion.title
|
|
86
|
+
else
|
|
87
|
+
local command = currentCommandPath()
|
|
88
|
+
local argIndex = terminalArgIndex()
|
|
89
|
+
if command == nil or argIndex == nil then
|
|
90
|
+
return text
|
|
91
|
+
end
|
|
92
|
+
local atNextPart = string.sub(text, -1) == " "
|
|
93
|
+
if atNextPart and argIndex == commandArgIndex() then
|
|
94
|
+
suggestionText = suggestion.title
|
|
95
|
+
elseif not (#suggestion.others == 0) then
|
|
96
|
+
suggestionText = suggestion.others[1]
|
|
97
|
+
else
|
|
98
|
+
local _condition = currentTextPart()
|
|
99
|
+
if _condition == nil then
|
|
100
|
+
_condition = ""
|
|
101
|
+
end
|
|
102
|
+
suggestionText = _condition
|
|
103
|
+
end
|
|
104
|
+
local argNames = getArgumentNames(registry, command)
|
|
105
|
+
for i = argIndex + 1, #argNames - 1 do
|
|
106
|
+
suggestionText ..= ` {argNames[i + 1]}`
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
local _result = currentTextPart()
|
|
110
|
+
if _result ~= nil then
|
|
111
|
+
_result = #_result
|
|
112
|
+
end
|
|
113
|
+
local _condition = _result
|
|
114
|
+
if _condition == nil then
|
|
115
|
+
_condition = 0
|
|
116
|
+
end
|
|
117
|
+
local partSize = _condition
|
|
118
|
+
local result = text
|
|
119
|
+
local _suggestionText = suggestionText
|
|
120
|
+
local _arg0 = partSize + 1
|
|
121
|
+
result ..= string.sub(_suggestionText, _arg0)
|
|
122
|
+
return result
|
|
123
|
+
end
|
|
124
|
+
return {
|
|
125
|
+
completeCommand = completeCommand,
|
|
126
|
+
completeArgument = completeArgument,
|
|
127
|
+
getSuggestedText = getSuggestedText,
|
|
128
|
+
}
|
|
@@ -5,30 +5,25 @@ local UserInputService = TS.import(script, TS.getModule(script, "@rbxts", "servi
|
|
|
5
5
|
local _vide = TS.import(script, TS.getModule(script, "@rbxts", "vide").src)
|
|
6
6
|
local Vide = _vide
|
|
7
7
|
local cleanup = _vide.cleanup
|
|
8
|
-
local effect = _vide.effect
|
|
9
8
|
local source = _vide.source
|
|
10
|
-
local useAtom = TS.import(script, script.Parent.Parent.Parent, "hooks", "use-atom").useAtom
|
|
11
|
-
local useClient = TS.import(script, script.Parent.Parent.Parent, "hooks", "use-client").useClient
|
|
12
|
-
local useEvent = TS.import(script, script.Parent.Parent.Parent, "hooks", "use-event").useEvent
|
|
13
|
-
local px = TS.import(script, script.Parent.Parent.Parent, "hooks", "use-px").px
|
|
14
|
-
local _store = TS.import(script, script.Parent.Parent.Parent, "store")
|
|
15
|
-
local commandArgIndex = _store.commandArgIndex
|
|
9
|
+
local useAtom = TS.import(script, script.Parent.Parent.Parent.Parent, "hooks", "use-atom").useAtom
|
|
10
|
+
local useClient = TS.import(script, script.Parent.Parent.Parent.Parent, "hooks", "use-client").useClient
|
|
11
|
+
local useEvent = TS.import(script, script.Parent.Parent.Parent.Parent, "hooks", "use-event").useEvent
|
|
12
|
+
local px = TS.import(script, script.Parent.Parent.Parent.Parent, "hooks", "use-px").px
|
|
13
|
+
local _store = TS.import(script, script.Parent.Parent.Parent.Parent, "store")
|
|
16
14
|
local currentCommandPath = _store.currentCommandPath
|
|
17
15
|
local currentSuggestion = _store.currentSuggestion
|
|
18
|
-
local currentTextPart = _store.currentTextPart
|
|
19
16
|
local interfaceOptions = _store.interfaceOptions
|
|
20
17
|
local interfaceVisible = _store.interfaceVisible
|
|
21
|
-
local terminalArgIndex = _store.terminalArgIndex
|
|
22
|
-
local terminalText = _store.terminalText
|
|
23
|
-
local terminalTextParts = _store.terminalTextParts
|
|
24
18
|
local terminalTextValid = _store.terminalTextValid
|
|
25
|
-
local Frame = TS.import(script, script.Parent.Parent, "ui", "frame").Frame
|
|
26
|
-
local Padding = TS.import(script, script.Parent.Parent, "ui", "padding").Padding
|
|
27
|
-
local Text = TS.import(script, script.Parent.Parent, "ui", "text").Text
|
|
28
|
-
local TextField = TS.import(script, script.Parent.Parent, "ui", "text-field").TextField
|
|
29
|
-
local
|
|
30
|
-
local
|
|
31
|
-
local
|
|
19
|
+
local Frame = TS.import(script, script.Parent.Parent.Parent, "ui", "frame").Frame
|
|
20
|
+
local Padding = TS.import(script, script.Parent.Parent.Parent, "ui", "padding").Padding
|
|
21
|
+
local Text = TS.import(script, script.Parent.Parent.Parent, "ui", "text").Text
|
|
22
|
+
local TextField = TS.import(script, script.Parent.Parent.Parent, "ui", "text-field").TextField
|
|
23
|
+
local _suggestion = TS.import(script, script.Parent, "suggestion")
|
|
24
|
+
local completeArgument = _suggestion.completeArgument
|
|
25
|
+
local completeCommand = _suggestion.completeCommand
|
|
26
|
+
local getSuggestedText = _suggestion.getSuggestedText
|
|
32
27
|
local TEXT_SIZE = 22
|
|
33
28
|
local function TerminalTextField(_param)
|
|
34
29
|
local anchor = _param.anchor
|
|
@@ -39,7 +34,6 @@ local function TerminalTextField(_param)
|
|
|
39
34
|
local onSubmit = _param.onSubmit
|
|
40
35
|
local client = useClient()
|
|
41
36
|
local options = useAtom(interfaceOptions)
|
|
42
|
-
local visible = useAtom(interfaceVisible)
|
|
43
37
|
local valid = useAtom(terminalTextValid)
|
|
44
38
|
local ref = source()
|
|
45
39
|
local commandHistory = source({})
|
|
@@ -47,8 +41,8 @@ local function TerminalTextField(_param)
|
|
|
47
41
|
local suggestionText = source("")
|
|
48
42
|
local currentTextValue = ""
|
|
49
43
|
-- Focus text field when terminal becomes visible
|
|
50
|
-
|
|
51
|
-
if visible
|
|
44
|
+
local visibleConnection = subscribe(interfaceVisible, function(visible)
|
|
45
|
+
if visible then
|
|
52
46
|
local _result = ref()
|
|
53
47
|
if _result ~= nil then
|
|
54
48
|
_result:CaptureFocus()
|
|
@@ -60,6 +54,16 @@ local function TerminalTextField(_param)
|
|
|
60
54
|
end
|
|
61
55
|
end
|
|
62
56
|
end)
|
|
57
|
+
cleanup(visibleConnection)
|
|
58
|
+
local setText = function(text)
|
|
59
|
+
local textBox = ref()
|
|
60
|
+
if textBox == nil then
|
|
61
|
+
return nil
|
|
62
|
+
end
|
|
63
|
+
textBox.Text = text
|
|
64
|
+
textBox.CursorPosition = #text + 1
|
|
65
|
+
suggestionText(text)
|
|
66
|
+
end
|
|
63
67
|
local traverseHistory = function(up)
|
|
64
68
|
local history = commandHistory()
|
|
65
69
|
if #history == 0 then
|
|
@@ -75,8 +79,7 @@ local function TerminalTextField(_param)
|
|
|
75
79
|
end
|
|
76
80
|
local lastIndex = #history - 1
|
|
77
81
|
if not up and historyIndex == lastIndex then
|
|
78
|
-
|
|
79
|
-
suggestionText("")
|
|
82
|
+
setText("")
|
|
80
83
|
commandHistoryIndex(nil)
|
|
81
84
|
return nil
|
|
82
85
|
end
|
|
@@ -85,63 +88,20 @@ local function TerminalTextField(_param)
|
|
|
85
88
|
_condition = #history
|
|
86
89
|
end
|
|
87
90
|
local newIndex = math.clamp(_condition + (if up then -1 else 1), 0, lastIndex)
|
|
88
|
-
|
|
89
|
-
textBox.Text = newText
|
|
90
|
-
textBox.CursorPosition = #newText + 1
|
|
91
|
-
suggestionText("")
|
|
91
|
+
setText(history[newIndex + 1])
|
|
92
92
|
commandHistoryIndex(newIndex)
|
|
93
93
|
end
|
|
94
94
|
local suggestionConnection = subscribe(currentSuggestion, function(suggestion)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
local atNextPart = string.sub(terminalText(), -1) == " "
|
|
100
|
-
local textParts = terminalTextParts()
|
|
101
|
-
if #textParts == 0 then
|
|
102
|
-
suggestionText(suggestion.title)
|
|
103
|
-
return nil
|
|
104
|
-
end
|
|
105
|
-
local _currentText = ref()
|
|
106
|
-
if _currentText ~= nil then
|
|
107
|
-
_currentText = _currentText.Text
|
|
108
|
-
end
|
|
109
|
-
local currentText = _currentText
|
|
110
|
-
if currentText == nil then
|
|
111
|
-
return nil
|
|
112
|
-
end
|
|
113
|
-
-- Command suggestions
|
|
114
|
-
if suggestion.type == "command" then
|
|
115
|
-
local suggestionStartIndex = (if not atNextPart then #textParts[#textParts] else 0) + 1
|
|
116
|
-
suggestionText(currentText .. string.sub(suggestion.title, suggestionStartIndex))
|
|
117
|
-
return nil
|
|
118
|
-
end
|
|
119
|
-
-- Argument suggestions
|
|
120
|
-
local command = currentCommandPath()
|
|
121
|
-
local argIndex = terminalArgIndex()
|
|
122
|
-
if suggestion.type ~= "argument" or command == nil or argIndex == nil then
|
|
123
|
-
return nil
|
|
124
|
-
end
|
|
125
|
-
local newText = currentText
|
|
126
|
-
if atNextPart and argIndex == commandArgIndex() then
|
|
127
|
-
newText ..= suggestion.title
|
|
128
|
-
elseif not (#suggestion.others == 0) then
|
|
129
|
-
local _exp = suggestion.others[1]
|
|
130
|
-
local _result = currentTextPart()
|
|
131
|
-
if _result ~= nil then
|
|
132
|
-
_result = #_result
|
|
133
|
-
end
|
|
134
|
-
local _condition = _result
|
|
135
|
-
if _condition == nil then
|
|
136
|
-
_condition = 0
|
|
137
|
-
end
|
|
138
|
-
newText ..= string.sub(_exp, _condition + 1)
|
|
95
|
+
local _exp = client.registry
|
|
96
|
+
local _result = ref()
|
|
97
|
+
if _result ~= nil then
|
|
98
|
+
_result = _result.Text
|
|
139
99
|
end
|
|
140
|
-
local
|
|
141
|
-
|
|
142
|
-
|
|
100
|
+
local _condition = _result
|
|
101
|
+
if _condition == nil then
|
|
102
|
+
_condition = ""
|
|
143
103
|
end
|
|
144
|
-
suggestionText(
|
|
104
|
+
suggestionText(getSuggestedText(_exp, _condition, suggestion))
|
|
145
105
|
end)
|
|
146
106
|
cleanup(suggestionConnection)
|
|
147
107
|
useEvent(UserInputService.InputBegan, function(input)
|
|
@@ -157,6 +117,7 @@ local function TerminalTextField(_param)
|
|
|
157
117
|
if _condition then
|
|
158
118
|
return nil
|
|
159
119
|
end
|
|
120
|
+
-- Handle history traversal
|
|
160
121
|
if input.KeyCode == Enum.KeyCode.Up then
|
|
161
122
|
traverseHistory(true)
|
|
162
123
|
elseif input.KeyCode == Enum.KeyCode.Down then
|
|
@@ -165,120 +126,38 @@ local function TerminalTextField(_param)
|
|
|
165
126
|
if input.KeyCode ~= Enum.KeyCode.Tab then
|
|
166
127
|
return nil
|
|
167
128
|
end
|
|
168
|
-
--
|
|
129
|
+
-- Handle autocompletion
|
|
169
130
|
local commandPath = currentCommandPath()
|
|
170
131
|
local suggestion = currentSuggestion()
|
|
171
132
|
if suggestion == nil then
|
|
172
133
|
return nil
|
|
173
134
|
end
|
|
174
135
|
local currentText = textBox.Text
|
|
175
|
-
local textParts = terminalTextParts()
|
|
176
|
-
local lastPart = textParts[#textParts]
|
|
177
|
-
local atNextPart = string.sub(currentText, -1) == " "
|
|
178
136
|
if commandPath == nil then
|
|
179
|
-
|
|
180
|
-
if #textParts == 0 then
|
|
181
|
-
return nil
|
|
182
|
-
end
|
|
183
|
-
local _array = {}
|
|
184
|
-
local _length = #_array
|
|
185
|
-
table.move(textParts, 1, #textParts, _length + 1, _array)
|
|
186
|
-
local pathParts = _array
|
|
187
|
-
local newText = currentText
|
|
188
|
-
if atNextPart then
|
|
189
|
-
newText ..= suggestionTitle
|
|
190
|
-
table.insert(pathParts, suggestionTitle)
|
|
191
|
-
elseif not (#textParts == 0) then
|
|
192
|
-
local _newText = newText
|
|
193
|
-
local _arg1 = #newText - #lastPart
|
|
194
|
-
newText = string.sub(_newText, 0, _arg1) .. suggestionTitle
|
|
195
|
-
local _arg0 = #textParts - 1
|
|
196
|
-
table.remove(pathParts, _arg0 + 1)
|
|
197
|
-
table.insert(pathParts, suggestionTitle)
|
|
198
|
-
end
|
|
199
|
-
local _nextCommand = client.registry:getCommandByString(formatPartsAsPath(pathParts))
|
|
200
|
-
if _nextCommand ~= nil then
|
|
201
|
-
_nextCommand = _nextCommand.options
|
|
202
|
-
end
|
|
203
|
-
local nextCommand = _nextCommand
|
|
204
|
-
local _condition_1 = nextCommand == nil
|
|
205
|
-
if not _condition_1 then
|
|
206
|
-
local _result = nextCommand.arguments
|
|
207
|
-
if _result ~= nil then
|
|
208
|
-
_result = #_result == 0
|
|
209
|
-
end
|
|
210
|
-
local _condition_2 = _result
|
|
211
|
-
if _condition_2 == nil then
|
|
212
|
-
_condition_2 = true
|
|
213
|
-
end
|
|
214
|
-
_condition_1 = not _condition_2
|
|
215
|
-
end
|
|
216
|
-
if _condition_1 then
|
|
217
|
-
newText ..= " "
|
|
218
|
-
end
|
|
219
|
-
suggestionText("")
|
|
220
|
-
textBox.Text = newText
|
|
221
|
-
textBox.CursorPosition = #newText + 1
|
|
137
|
+
setText(completeCommand(client.registry, textBox.Text, suggestion.title))
|
|
222
138
|
return nil
|
|
223
139
|
end
|
|
224
|
-
local
|
|
225
|
-
if
|
|
226
|
-
|
|
227
|
-
end
|
|
228
|
-
local commandArgs = _commandArgs
|
|
229
|
-
local _condition_1 = suggestion.type == "command" and not atNextPart
|
|
230
|
-
if _condition_1 then
|
|
231
|
-
local _result = commandArgs
|
|
140
|
+
local _result = client.registry:getCommand(commandPath)
|
|
141
|
+
if _result ~= nil then
|
|
142
|
+
_result = _result.options.arguments
|
|
232
143
|
if _result ~= nil then
|
|
233
|
-
_result = #_result
|
|
234
|
-
end
|
|
235
|
-
local _condition_2 = _result
|
|
236
|
-
if _condition_2 == nil then
|
|
237
|
-
_condition_2 = true
|
|
144
|
+
_result = #_result
|
|
238
145
|
end
|
|
239
|
-
_condition_1 = not _condition_2
|
|
240
146
|
end
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
textBox.Text = newText
|
|
245
|
-
textBox.CursorPosition = #newText + 1
|
|
246
|
-
return nil
|
|
147
|
+
local _condition_1 = _result
|
|
148
|
+
if _condition_1 == nil then
|
|
149
|
+
_condition_1 = 0
|
|
247
150
|
end
|
|
248
|
-
|
|
249
|
-
if
|
|
151
|
+
local argCount = _condition_1
|
|
152
|
+
if suggestion.type == "command" and argCount ~= 0 then
|
|
153
|
+
setText(`{currentText} `)
|
|
250
154
|
return nil
|
|
251
155
|
end
|
|
252
|
-
|
|
253
|
-
|
|
156
|
+
if #suggestion.others == 0 then
|
|
157
|
+
setText(currentText)
|
|
254
158
|
return nil
|
|
255
159
|
end
|
|
256
|
-
|
|
257
|
-
local otherSuggestion = suggestion.others[1]
|
|
258
|
-
local trailingSpaces = (string.match(newText, "(%s+)$"))
|
|
259
|
-
local _newText = newText
|
|
260
|
-
local _exp = #newText
|
|
261
|
-
local _condition_2 = #lastPart
|
|
262
|
-
if _condition_2 == nil then
|
|
263
|
-
_condition_2 = 0
|
|
264
|
-
end
|
|
265
|
-
local _exp_1 = _exp - _condition_2
|
|
266
|
-
local _result = trailingSpaces
|
|
267
|
-
if _result ~= nil then
|
|
268
|
-
_result = #_result
|
|
269
|
-
end
|
|
270
|
-
local _condition_3 = _result
|
|
271
|
-
if _condition_3 == nil then
|
|
272
|
-
_condition_3 = 0
|
|
273
|
-
end
|
|
274
|
-
newText = string.sub(_newText, 0, _exp_1 - _condition_3)
|
|
275
|
-
newText ..= if #{ string.match(otherSuggestion, "%s") } == 0 then otherSuggestion else `"{otherSuggestion}"`
|
|
276
|
-
if argIndex < #commandArgs - 1 then
|
|
277
|
-
newText ..= " "
|
|
278
|
-
end
|
|
279
|
-
suggestionText("")
|
|
280
|
-
textBox.Text = newText
|
|
281
|
-
textBox.CursorPosition = #newText + 1
|
|
160
|
+
setText(completeArgument(currentText, suggestion.others[1], argCount))
|
|
282
161
|
end)
|
|
283
162
|
return Vide.jsx(Frame, {
|
|
284
163
|
anchor = anchor,
|
|
@@ -36,6 +36,8 @@ local getCommandSuggestion = _suggestion.getCommandSuggestion
|
|
|
36
36
|
local TerminalTextField = TS.import(script, script.Parent, "terminal-text-field").TerminalTextField
|
|
37
37
|
local MAX_HEIGHT = HISTORY_TEXT_SIZE * 10
|
|
38
38
|
local TEXT_FIELD_HEIGHT = 40
|
|
39
|
+
local START_QUOTE_PATTERN = `^(['"])`
|
|
40
|
+
local TRAILING_SPACE_PATTERN = "(%s+)$"
|
|
39
41
|
local function Terminal()
|
|
40
42
|
local client = useClient()
|
|
41
43
|
local options = useAtom(interfaceOptions)
|
|
@@ -136,38 +138,41 @@ local function Terminal()
|
|
|
136
138
|
currentCommandPath(nil)
|
|
137
139
|
terminalTextValid(false)
|
|
138
140
|
end
|
|
139
|
-
local
|
|
140
|
-
local
|
|
141
|
-
if
|
|
142
|
-
|
|
143
|
-
elseif not atNextPart then
|
|
144
|
-
textPart = lastPart
|
|
141
|
+
local textPart = parts[#parts]
|
|
142
|
+
local _result = textPart
|
|
143
|
+
if _result ~= nil then
|
|
144
|
+
_result = string.match(_result, START_QUOTE_PATTERN)
|
|
145
145
|
end
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
146
|
+
local quoted = _result ~= nil
|
|
147
|
+
if atNextPart and not quoted then
|
|
148
|
+
textPart = nil
|
|
149
|
+
elseif textPart ~= nil then
|
|
150
|
+
local _condition = (string.match(text, TRAILING_SPACE_PATTERN))
|
|
151
|
+
if _condition == nil then
|
|
152
|
+
_condition = ""
|
|
150
153
|
end
|
|
154
|
+
local spaces = _condition
|
|
155
|
+
textPart ..= tostring(spaces)
|
|
151
156
|
end
|
|
152
157
|
local argIndex = if path ~= nil then #parts - path:size() - (if atNextPart then 0 else 1) else -1
|
|
153
158
|
terminalArgIndex(argIndex)
|
|
154
159
|
if command == nil or argIndex == -1 then
|
|
155
160
|
-- Get command suggestions
|
|
156
161
|
local parentPath = if not (#parts == 0) then RegistryPath.new(ArrayUtil.slice(parts, 0, #parts - (if atNextPart then 0 else 1))) else nil
|
|
162
|
+
currentTextPart(textPart)
|
|
157
163
|
local _exp = client.registry
|
|
158
|
-
local
|
|
159
|
-
if
|
|
160
|
-
|
|
164
|
+
local _result_1 = parentPath
|
|
165
|
+
if _result_1 ~= nil then
|
|
166
|
+
_result_1 = _result_1:isEmpty()
|
|
161
167
|
end
|
|
162
|
-
currentSuggestion(getCommandSuggestion(_exp, if not
|
|
163
|
-
currentTextPart(textPart)
|
|
168
|
+
currentSuggestion(getCommandSuggestion(_exp, if not _result_1 then parentPath else nil, textPart))
|
|
164
169
|
return nil
|
|
165
170
|
end
|
|
166
171
|
-- Handle arguments
|
|
167
172
|
local args = command.options.arguments
|
|
168
173
|
if args == nil then
|
|
169
|
-
currentSuggestion(nil)
|
|
170
174
|
currentTextPart(nil)
|
|
175
|
+
currentSuggestion(nil)
|
|
171
176
|
commandArgIndex(nil)
|
|
172
177
|
return nil
|
|
173
178
|
end
|
|
@@ -192,11 +197,11 @@ local function Terminal()
|
|
|
192
197
|
endIndex = if numArgs ~= "rest" then i + (numArgs - 1) else nil
|
|
193
198
|
end
|
|
194
199
|
local _registry = client.registry
|
|
195
|
-
local
|
|
196
|
-
if
|
|
197
|
-
|
|
200
|
+
local _result_1 = currentArg
|
|
201
|
+
if _result_1 ~= nil then
|
|
202
|
+
_result_1 = _result_1.type
|
|
198
203
|
end
|
|
199
|
-
local _condition =
|
|
204
|
+
local _condition = _result_1
|
|
200
205
|
if _condition == nil then
|
|
201
206
|
_condition = ""
|
|
202
207
|
end
|
|
@@ -217,20 +222,20 @@ local function Terminal()
|
|
|
217
222
|
kind = "single",
|
|
218
223
|
options = currentArg,
|
|
219
224
|
type = argType,
|
|
220
|
-
input =
|
|
221
|
-
},
|
|
225
|
+
input = argTextPart,
|
|
226
|
+
}, argTextPart)
|
|
222
227
|
else
|
|
223
228
|
local _condition_1 = textPart
|
|
224
229
|
if _condition_1 == nil then
|
|
225
230
|
_condition_1 = ""
|
|
226
231
|
end
|
|
227
|
-
local textParts = splitString(_condition_1, ",")
|
|
228
|
-
local
|
|
229
|
-
local
|
|
230
|
-
if
|
|
231
|
-
|
|
232
|
+
local textParts = splitString(_condition_1, ",", true)
|
|
233
|
+
local lastText = if not (#textParts == 0) then textParts[#textParts] else nil
|
|
234
|
+
local _result_2 = textPart
|
|
235
|
+
if _result_2 ~= nil then
|
|
236
|
+
_result_2 = string.sub(_result_2, -1)
|
|
232
237
|
end
|
|
233
|
-
argTextPart = if
|
|
238
|
+
argTextPart = if _result_2 ~= "," then lastText else nil
|
|
234
239
|
suggestion = getArgumentSuggestion({
|
|
235
240
|
kind = "list",
|
|
236
241
|
options = currentArg,
|
|
@@ -240,11 +245,11 @@ local function Terminal()
|
|
|
240
245
|
end
|
|
241
246
|
currentTextPart(argTextPart)
|
|
242
247
|
currentSuggestion(suggestion)
|
|
243
|
-
local
|
|
244
|
-
if
|
|
245
|
-
|
|
248
|
+
local _result_2 = suggestion
|
|
249
|
+
if _result_2 ~= nil then
|
|
250
|
+
_result_2 = _result_2.error
|
|
246
251
|
end
|
|
247
|
-
if
|
|
252
|
+
if _result_2 ~= nil then
|
|
248
253
|
terminalTextValid(false)
|
|
249
254
|
end
|
|
250
255
|
end,
|
package/out/store.luau
CHANGED
|
@@ -14,7 +14,7 @@ local terminalArgIndex = atom(nil)
|
|
|
14
14
|
local currentSuggestion = atom(nil)
|
|
15
15
|
local terminalText = atom("")
|
|
16
16
|
local terminalTextParts = computed(function()
|
|
17
|
-
return splitString(terminalText(), " ")
|
|
17
|
+
return splitString(terminalText(), " ", true)
|
|
18
18
|
end)
|
|
19
19
|
local terminalTextValid = atom(false)
|
|
20
20
|
local currentTextPart = atom(nil)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rbxts/centurion-ui",
|
|
3
3
|
"description": "Terminal UI for the Centurion command framework",
|
|
4
|
-
"version": "1.0.0
|
|
4
|
+
"version": "1.0.0",
|
|
5
5
|
"author": "paradoxuum",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "out/init.lua",
|
|
@@ -32,21 +32,20 @@
|
|
|
32
32
|
"dev": "shx rm -rf out && rbxtsc -w"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@rbxts/centurion": "^1.0.0
|
|
35
|
+
"@rbxts/centurion": "^1.0.0",
|
|
36
36
|
"@rbxts/compiler-types": "3.0.0-types.0",
|
|
37
|
-
"@rbxts/types": "^1.0.
|
|
37
|
+
"@rbxts/types": "^1.0.809",
|
|
38
38
|
"roblox-ts": "3.0.0",
|
|
39
39
|
"shx": "^0.3.4",
|
|
40
|
-
"typescript": "
|
|
40
|
+
"typescript": "=5.5.3"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@rbxts/charm": "^0.
|
|
44
|
-
"@rbxts/services": "^1.5.
|
|
43
|
+
"@rbxts/charm": "^0.7.5",
|
|
44
|
+
"@rbxts/services": "^1.5.5",
|
|
45
45
|
"@rbxts/set-timeout": "^1.1.2",
|
|
46
|
-
"@rbxts/vide": "^0.4.
|
|
46
|
+
"@rbxts/vide": "^0.4.6"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"@rbxts/centurion": "
|
|
50
|
-
}
|
|
51
|
-
"stableVersion": "1.0.0"
|
|
49
|
+
"@rbxts/centurion": "^1.0.0"
|
|
50
|
+
}
|
|
52
51
|
}
|
|
File without changes
|