mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-22 18:24:21 +01:00
feat(TUI): add autocomplete readline style keybinds (#3717)
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
This commit is contained in:
@@ -22,15 +22,16 @@ export type CommandOption = DialogSelectOption & {
|
|||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
const [registrations, setRegistrations] = createSignal<Accessor<CommandOption[]>[]>([])
|
const [registrations, setRegistrations] = createSignal<Accessor<CommandOption[]>[]>([])
|
||||||
|
const [suspendCount, setSuspendCount] = createSignal(0)
|
||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
const keybind = useKeybind()
|
const keybind = useKeybind()
|
||||||
const options = createMemo(() => {
|
const options = createMemo(() => {
|
||||||
return registrations().flatMap((x) => x())
|
return registrations().flatMap((x) => x())
|
||||||
})
|
})
|
||||||
|
const suspended = () => suspendCount() > 0
|
||||||
|
|
||||||
let keybinds = true
|
|
||||||
useKeyboard((evt) => {
|
useKeyboard((evt) => {
|
||||||
if (!keybinds) return
|
if (suspended()) return
|
||||||
for (const option of options()) {
|
for (const option of options()) {
|
||||||
if (option.keybind && keybind.match(option.keybind, evt)) {
|
if (option.keybind && keybind.match(option.keybind, evt)) {
|
||||||
evt.preventDefault()
|
evt.preventDefault()
|
||||||
@@ -50,8 +51,9 @@ function init() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
keybinds(enabled: boolean) {
|
keybinds(enabled: boolean) {
|
||||||
keybinds = enabled
|
setSuspendCount((count) => count + (enabled ? -1 : 1))
|
||||||
},
|
},
|
||||||
|
suspended,
|
||||||
show() {
|
show() {
|
||||||
dialog.replace(() => <DialogCommand options={options()} />)
|
dialog.replace(() => <DialogCommand options={options()} />)
|
||||||
},
|
},
|
||||||
@@ -83,7 +85,10 @@ export function CommandProvider(props: ParentProps) {
|
|||||||
const keybind = useKeybind()
|
const keybind = useKeybind()
|
||||||
|
|
||||||
useKeyboard((evt) => {
|
useKeyboard((evt) => {
|
||||||
if (keybind.match("command_list", evt) && dialog.stack.length === 0) {
|
if (value.suspended()) return
|
||||||
|
if (dialog.stack.length > 0) return
|
||||||
|
if (evt.defaultPrevented) return
|
||||||
|
if (keybind.match("command_list", evt)) {
|
||||||
evt.preventDefault()
|
evt.preventDefault()
|
||||||
dialog.replace(() => <DialogCommand options={value.options} />)
|
dialog.replace(() => <DialogCommand options={value.options} />)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -393,11 +393,31 @@ export function Autocomplete(props: {
|
|||||||
},
|
},
|
||||||
onKeyDown(e: KeyEvent) {
|
onKeyDown(e: KeyEvent) {
|
||||||
if (store.visible) {
|
if (store.visible) {
|
||||||
if (e.name === "up") move(-1)
|
const name = e.name?.toLowerCase()
|
||||||
if (e.name === "down") move(1)
|
const ctrlOnly = e.ctrl && !e.meta && !e.shift
|
||||||
if (e.name === "escape") hide()
|
const isNavUp = name === "up" || (ctrlOnly && name === "p")
|
||||||
if (e.name === "return" || e.name === "tab") select()
|
const isNavDown = name === "down" || (ctrlOnly && name === "n")
|
||||||
if (["up", "down", "return", "tab", "escape"].includes(e.name)) e.preventDefault()
|
|
||||||
|
if (isNavUp) {
|
||||||
|
move(-1)
|
||||||
|
e.preventDefault()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (isNavDown) {
|
||||||
|
move(1)
|
||||||
|
e.preventDefault()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (name === "escape") {
|
||||||
|
hide()
|
||||||
|
e.preventDefault()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (name === "return" || name === "tab") {
|
||||||
|
select()
|
||||||
|
e.preventDefault()
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!store.visible) {
|
if (!store.visible) {
|
||||||
if (e.name === "@") {
|
if (e.name === "@") {
|
||||||
|
|||||||
Reference in New Issue
Block a user