@tooee/shell 0.1.9 → 0.1.12
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/dist/command-palette-provider.d.ts +5 -0
- package/dist/command-palette-provider.d.ts.map +1 -0
- package/dist/command-palette-provider.js +28 -0
- package/dist/command-palette-provider.js.map +1 -0
- package/dist/commands.d.ts +9 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +61 -11
- package/dist/commands.js.map +1 -1
- package/dist/copy-hook.d.ts +12 -0
- package/dist/copy-hook.d.ts.map +1 -0
- package/dist/copy-hook.js +35 -0
- package/dist/copy-hook.js.map +1 -0
- package/dist/copy-on-select.d.ts.map +1 -1
- package/dist/copy-on-select.js +1 -3
- package/dist/copy-on-select.js.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/navigation.d.ts +24 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/navigation.js +239 -0
- package/dist/navigation.js.map +1 -0
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +4 -1
- package/dist/provider.js.map +1 -1
- package/dist/search-hook.d.ts +14 -0
- package/dist/search-hook.d.ts.map +1 -0
- package/dist/search-hook.js +120 -0
- package/dist/search-hook.js.map +1 -0
- package/dist/theme-picker.js +1 -1
- package/dist/theme-picker.js.map +1 -1
- package/package.json +20 -20
- package/src/command-palette-provider.tsx +39 -0
- package/src/commands.ts +64 -11
- package/src/copy-hook.ts +45 -0
- package/src/copy-on-select.ts +1 -4
- package/src/index.ts +15 -5
- package/src/navigation.ts +297 -0
- package/src/provider.tsx +6 -1
- package/src/search-hook.ts +147 -0
- package/src/theme-picker.ts +1 -1
- package/dist/command-palette.d.ts +0 -9
- package/dist/command-palette.d.ts.map +0 -1
- package/dist/command-palette.js +0 -51
- package/dist/command-palette.js.map +0 -1
- package/dist/modal.d.ts +0 -33
- package/dist/modal.d.ts.map +0 -1
- package/dist/modal.js +0 -394
- package/dist/modal.js.map +0 -1
- package/src/command-palette.ts +0 -73
- package/src/modal.ts +0 -449
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { useCallback, useMemo, useRef, useState } from "react"
|
|
2
|
+
import { useTerminalDimensions } from "@opentui/react"
|
|
3
|
+
import { useCommand, useMode, useSetMode, type Mode } from "@tooee/commands"
|
|
4
|
+
|
|
5
|
+
export interface Position {
|
|
6
|
+
line: number
|
|
7
|
+
col: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const CURSOR_MODES: Mode[] = ["cursor"]
|
|
11
|
+
const SELECT_MODES: Mode[] = ["select"]
|
|
12
|
+
|
|
13
|
+
export interface UseNavigationOptions {
|
|
14
|
+
rowCount: number
|
|
15
|
+
isSelectable?: (index: number) => boolean
|
|
16
|
+
viewportHeight?: number
|
|
17
|
+
multiSelect?: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface NavigationState {
|
|
21
|
+
mode: Mode
|
|
22
|
+
setMode: (mode: Mode) => void
|
|
23
|
+
cursor: Position | null
|
|
24
|
+
setCursor: (line: number) => void
|
|
25
|
+
selection: { start: Position; end: Position } | null
|
|
26
|
+
toggledIndices: Set<number>
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function defaultIsSelectable(): boolean {
|
|
30
|
+
return true
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function useNavigation({
|
|
34
|
+
rowCount,
|
|
35
|
+
isSelectable = defaultIsSelectable,
|
|
36
|
+
viewportHeight,
|
|
37
|
+
multiSelect = false,
|
|
38
|
+
}: UseNavigationOptions): NavigationState {
|
|
39
|
+
const { height: terminalHeight } = useTerminalDimensions()
|
|
40
|
+
const effectiveViewportHeight = viewportHeight ?? Math.max(1, terminalHeight - 2)
|
|
41
|
+
const mode = useMode()
|
|
42
|
+
const setMode = useSetMode()
|
|
43
|
+
|
|
44
|
+
const maxIndex = Math.max(0, rowCount - 1)
|
|
45
|
+
|
|
46
|
+
const clampIndex = useCallback(
|
|
47
|
+
(index: number) => Math.max(0, Math.min(index, maxIndex)),
|
|
48
|
+
[maxIndex],
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
const findSelectable = useCallback(
|
|
52
|
+
(start: number, direction: 1 | -1) => {
|
|
53
|
+
if (rowCount <= 0) return null
|
|
54
|
+
const initial = Math.max(0, Math.min(start, maxIndex))
|
|
55
|
+
for (
|
|
56
|
+
let index = initial;
|
|
57
|
+
direction === 1 ? index <= maxIndex : index >= 0;
|
|
58
|
+
index += direction
|
|
59
|
+
) {
|
|
60
|
+
if (isSelectable(index)) return index
|
|
61
|
+
}
|
|
62
|
+
return null
|
|
63
|
+
},
|
|
64
|
+
[rowCount, maxIndex, isSelectable],
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
const resolveSelectable = useCallback(
|
|
68
|
+
(target: number, preferredDirection: 1 | -1 = 1) => {
|
|
69
|
+
if (rowCount <= 0) return null
|
|
70
|
+
const clamped = Math.max(0, Math.min(target, maxIndex))
|
|
71
|
+
if (isSelectable(clamped)) return clamped
|
|
72
|
+
return preferredDirection === 1
|
|
73
|
+
? findSelectable(clamped, 1) ?? findSelectable(clamped, -1)
|
|
74
|
+
: findSelectable(clamped, -1) ?? findSelectable(clamped, 1)
|
|
75
|
+
},
|
|
76
|
+
[rowCount, maxIndex, isSelectable, findSelectable],
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
const [rawCursor, setRawCursor] = useState<Position | null>(() => {
|
|
80
|
+
const line = resolveSelectable(0, 1)
|
|
81
|
+
return line == null ? null : { line, col: 0 }
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
// Derive valid cursor from raw cursor + constraints
|
|
85
|
+
const cursor = useMemo(() => {
|
|
86
|
+
if (rowCount <= 0) return null
|
|
87
|
+
if (!rawCursor) {
|
|
88
|
+
if (mode !== "cursor") return null
|
|
89
|
+
const line = resolveSelectable(0, 1)
|
|
90
|
+
return line == null ? null : { line, col: 0 }
|
|
91
|
+
}
|
|
92
|
+
const preferredDirection: 1 | -1 = rawCursor.line > maxIndex ? -1 : 1
|
|
93
|
+
const resolved = resolveSelectable(rawCursor.line, preferredDirection)
|
|
94
|
+
if (resolved == null) return null
|
|
95
|
+
if (resolved === rawCursor.line) return rawCursor
|
|
96
|
+
return { line: resolved, col: 0 }
|
|
97
|
+
}, [rawCursor, rowCount, maxIndex, mode, resolveSelectable])
|
|
98
|
+
|
|
99
|
+
const cursorRef = useRef(cursor)
|
|
100
|
+
cursorRef.current = cursor
|
|
101
|
+
const [selectionAnchor, setSelectionAnchor] = useState<Position | null>(null)
|
|
102
|
+
const [rawToggledIndices, setRawToggledIndices] = useState<Set<number>>(new Set())
|
|
103
|
+
|
|
104
|
+
// Derive valid toggled indices (filter out-of-bounds)
|
|
105
|
+
const toggledIndices = useMemo(() => {
|
|
106
|
+
if (rowCount <= 0) return new Set<number>()
|
|
107
|
+
let needsFilter = false
|
|
108
|
+
for (const i of rawToggledIndices) {
|
|
109
|
+
if (i >= rowCount) { needsFilter = true; break }
|
|
110
|
+
}
|
|
111
|
+
if (!needsFilter) return rawToggledIndices
|
|
112
|
+
return new Set(Array.from(rawToggledIndices).filter(i => i < rowCount))
|
|
113
|
+
}, [rawToggledIndices, rowCount])
|
|
114
|
+
|
|
115
|
+
const setCursor = useCallback(
|
|
116
|
+
(line: number) => {
|
|
117
|
+
setRawCursor((current) => {
|
|
118
|
+
const preferredDirection: 1 | -1 = current && line < current.line ? -1 : 1
|
|
119
|
+
const nextLine = resolveSelectable(line, preferredDirection)
|
|
120
|
+
if (nextLine == null) return null
|
|
121
|
+
if (current && nextLine === current.line) return current
|
|
122
|
+
return { line: nextLine, col: 0 }
|
|
123
|
+
})
|
|
124
|
+
},
|
|
125
|
+
[resolveSelectable],
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
const moveCursor = useCallback(
|
|
129
|
+
(delta: number) => {
|
|
130
|
+
setRawCursor((current) => {
|
|
131
|
+
if (!current) return current
|
|
132
|
+
const target = clampIndex(current.line + delta)
|
|
133
|
+
const preferredDirection: 1 | -1 = delta < 0 ? -1 : 1
|
|
134
|
+
const nextLine = resolveSelectable(target, preferredDirection)
|
|
135
|
+
if (nextLine == null) return current
|
|
136
|
+
if (nextLine === current.line) return current
|
|
137
|
+
return { line: nextLine, col: 0 }
|
|
138
|
+
})
|
|
139
|
+
},
|
|
140
|
+
[clampIndex, resolveSelectable],
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
const jumpCursor = useCallback(
|
|
144
|
+
(target: number, preferredDirection: 1 | -1) => {
|
|
145
|
+
const nextLine = resolveSelectable(target, preferredDirection)
|
|
146
|
+
setRawCursor(nextLine == null ? null : { line: nextLine, col: 0 })
|
|
147
|
+
},
|
|
148
|
+
[resolveSelectable],
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
const toggleCurrent = useCallback(() => {
|
|
152
|
+
const cur = cursorRef.current
|
|
153
|
+
if (!cur) return
|
|
154
|
+
setRawToggledIndices((prev) => {
|
|
155
|
+
const next = new Set(prev)
|
|
156
|
+
if (next.has(cur.line)) {
|
|
157
|
+
next.delete(cur.line)
|
|
158
|
+
} else {
|
|
159
|
+
next.add(cur.line)
|
|
160
|
+
}
|
|
161
|
+
return next
|
|
162
|
+
})
|
|
163
|
+
}, [])
|
|
164
|
+
|
|
165
|
+
useCommand({
|
|
166
|
+
id: "cursor-down",
|
|
167
|
+
title: "Cursor down",
|
|
168
|
+
hotkey: "j",
|
|
169
|
+
modes: CURSOR_MODES,
|
|
170
|
+
handler: () => moveCursor(1),
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
useCommand({
|
|
174
|
+
id: "cursor-up",
|
|
175
|
+
title: "Cursor up",
|
|
176
|
+
hotkey: "k",
|
|
177
|
+
modes: CURSOR_MODES,
|
|
178
|
+
handler: () => moveCursor(-1),
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
useCommand({
|
|
182
|
+
id: "cursor-half-down",
|
|
183
|
+
title: "Cursor half page down",
|
|
184
|
+
hotkey: "ctrl+d",
|
|
185
|
+
modes: CURSOR_MODES,
|
|
186
|
+
handler: () => moveCursor(Math.floor(effectiveViewportHeight / 2) || 1),
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
useCommand({
|
|
190
|
+
id: "cursor-half-up",
|
|
191
|
+
title: "Cursor half page up",
|
|
192
|
+
hotkey: "ctrl+u",
|
|
193
|
+
modes: CURSOR_MODES,
|
|
194
|
+
handler: () => moveCursor(-(Math.floor(effectiveViewportHeight / 2) || 1)),
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
useCommand({
|
|
198
|
+
id: "cursor-top",
|
|
199
|
+
title: "Cursor to top",
|
|
200
|
+
hotkey: "g g",
|
|
201
|
+
modes: CURSOR_MODES,
|
|
202
|
+
handler: () => jumpCursor(0, 1),
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
useCommand({
|
|
206
|
+
id: "cursor-bottom",
|
|
207
|
+
title: "Cursor to bottom",
|
|
208
|
+
hotkey: "shift+g",
|
|
209
|
+
modes: CURSOR_MODES,
|
|
210
|
+
handler: () => jumpCursor(maxIndex, -1),
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
useCommand({
|
|
214
|
+
id: "enter-select",
|
|
215
|
+
title: "Enter select mode",
|
|
216
|
+
hotkey: "v",
|
|
217
|
+
modes: CURSOR_MODES,
|
|
218
|
+
handler: () => {
|
|
219
|
+
setSelectionAnchor(cursorRef.current ? { ...cursorRef.current } : null)
|
|
220
|
+
setMode("select")
|
|
221
|
+
},
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
useCommand({
|
|
225
|
+
id: "cursor-toggle",
|
|
226
|
+
title: "Toggle selection",
|
|
227
|
+
hotkey: "tab",
|
|
228
|
+
modes: CURSOR_MODES,
|
|
229
|
+
when: () => multiSelect,
|
|
230
|
+
handler: toggleCurrent,
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
useCommand({
|
|
234
|
+
id: "cursor-toggle-up",
|
|
235
|
+
title: "Toggle and move up",
|
|
236
|
+
hotkey: "shift+tab",
|
|
237
|
+
modes: CURSOR_MODES,
|
|
238
|
+
when: () => multiSelect,
|
|
239
|
+
handler: () => {
|
|
240
|
+
toggleCurrent()
|
|
241
|
+
moveCursor(-1)
|
|
242
|
+
},
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
useCommand({
|
|
246
|
+
id: "select-down",
|
|
247
|
+
title: "Extend selection down",
|
|
248
|
+
hotkey: "j",
|
|
249
|
+
modes: SELECT_MODES,
|
|
250
|
+
handler: () => moveCursor(1),
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
useCommand({
|
|
254
|
+
id: "select-up",
|
|
255
|
+
title: "Extend selection up",
|
|
256
|
+
hotkey: "k",
|
|
257
|
+
modes: SELECT_MODES,
|
|
258
|
+
handler: () => moveCursor(-1),
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
useCommand({
|
|
262
|
+
id: "select-toggle",
|
|
263
|
+
title: "Toggle selection",
|
|
264
|
+
hotkey: "tab",
|
|
265
|
+
modes: SELECT_MODES,
|
|
266
|
+
when: () => multiSelect,
|
|
267
|
+
handler: toggleCurrent,
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
useCommand({
|
|
271
|
+
id: "select-cancel",
|
|
272
|
+
title: "Cancel selection",
|
|
273
|
+
hotkey: "escape",
|
|
274
|
+
modes: SELECT_MODES,
|
|
275
|
+
handler: () => {
|
|
276
|
+
setSelectionAnchor(null)
|
|
277
|
+
setMode("cursor")
|
|
278
|
+
},
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
const selection =
|
|
282
|
+
mode === "select" && selectionAnchor && cursor
|
|
283
|
+
? {
|
|
284
|
+
start: selectionAnchor.line <= cursor.line ? selectionAnchor : cursor,
|
|
285
|
+
end: selectionAnchor.line <= cursor.line ? cursor : selectionAnchor,
|
|
286
|
+
}
|
|
287
|
+
: null
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
mode,
|
|
291
|
+
setMode,
|
|
292
|
+
cursor,
|
|
293
|
+
setCursor,
|
|
294
|
+
selection,
|
|
295
|
+
toggledIndices,
|
|
296
|
+
}
|
|
297
|
+
}
|
package/src/provider.tsx
CHANGED
|
@@ -4,7 +4,9 @@ import { ThemeSwitcherProvider } from "@tooee/themes"
|
|
|
4
4
|
import { CommandProvider, useProvideCommandContext, type Mode } from "@tooee/commands"
|
|
5
5
|
import { ToastProvider, useToast, type ToastController } from "@tooee/toasts"
|
|
6
6
|
import { OverlayProvider } from "./overlay.js"
|
|
7
|
+
import { CommandPaletteProvider } from "./command-palette-provider.js"
|
|
7
8
|
import { useCopyOnSelect } from "./copy-on-select.js"
|
|
9
|
+
import { useDebugConsoleCommand } from "./commands.js"
|
|
8
10
|
|
|
9
11
|
declare module "@tooee/commands" {
|
|
10
12
|
interface CommandContext {
|
|
@@ -49,7 +51,9 @@ function TooeeProviderInner({
|
|
|
49
51
|
<CommandProvider leader={leader} keymap={config.keys} initialMode={initialMode}>
|
|
50
52
|
<ToastProvider>
|
|
51
53
|
<ToastContextBridge>
|
|
52
|
-
<OverlayProvider>
|
|
54
|
+
<OverlayProvider>
|
|
55
|
+
<CommandPaletteProvider>{children}</CommandPaletteProvider>
|
|
56
|
+
</OverlayProvider>
|
|
53
57
|
</ToastContextBridge>
|
|
54
58
|
</ToastProvider>
|
|
55
59
|
</CommandProvider>
|
|
@@ -65,6 +69,7 @@ function ToastContextBridge({ children }: { children: ReactNode }) {
|
|
|
65
69
|
}))
|
|
66
70
|
|
|
67
71
|
useCopyOnSelect()
|
|
72
|
+
useDebugConsoleCommand()
|
|
68
73
|
|
|
69
74
|
return <>{children}</>
|
|
70
75
|
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { useCallback, useMemo, useRef, useState } from "react"
|
|
2
|
+
import { useCommand, useMode, useSetMode, type Mode } from "@tooee/commands"
|
|
3
|
+
|
|
4
|
+
export interface UseSearchOptions {
|
|
5
|
+
match: (query: string) => number[]
|
|
6
|
+
onJump: (index: number) => void
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface SearchState {
|
|
10
|
+
searchQuery: string
|
|
11
|
+
searchActive: boolean
|
|
12
|
+
setSearchQuery: (query: string) => void
|
|
13
|
+
matchingLines: number[]
|
|
14
|
+
currentMatchIndex: number
|
|
15
|
+
submitSearch: () => void
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const EMPTY: number[] = []
|
|
19
|
+
const CURSOR_MODES: Mode[] = ["cursor"]
|
|
20
|
+
const ALL_MODES: Mode[] = ["cursor", "select", "insert"]
|
|
21
|
+
|
|
22
|
+
export function useSearch({ match, onJump }: UseSearchOptions): SearchState {
|
|
23
|
+
const mode = useMode()
|
|
24
|
+
const setMode = useSetMode()
|
|
25
|
+
|
|
26
|
+
const [searchQuery, setSearchQuery] = useState("")
|
|
27
|
+
const [searchActive, setSearchActive] = useState(false)
|
|
28
|
+
const [currentMatchIndex, setCurrentMatchIndex] = useState(0)
|
|
29
|
+
const [committedQuery, setCommittedQuery] = useState("")
|
|
30
|
+
const preSearchModeRef = useRef<Mode>("cursor")
|
|
31
|
+
|
|
32
|
+
const matchRef = useRef(match)
|
|
33
|
+
matchRef.current = match
|
|
34
|
+
|
|
35
|
+
const onJumpRef = useRef(onJump)
|
|
36
|
+
onJumpRef.current = onJump
|
|
37
|
+
|
|
38
|
+
const activeQuery = searchActive ? searchQuery : committedQuery
|
|
39
|
+
|
|
40
|
+
const matchingLines = useMemo(() => {
|
|
41
|
+
if (!activeQuery) return EMPTY
|
|
42
|
+
return matchRef.current(activeQuery)
|
|
43
|
+
}, [activeQuery])
|
|
44
|
+
|
|
45
|
+
const matchingLinesRef = useRef(matchingLines)
|
|
46
|
+
matchingLinesRef.current = matchingLines
|
|
47
|
+
|
|
48
|
+
// Imperatively set search query, reset match index, and jump to first match.
|
|
49
|
+
const updateSearchQuery = useCallback((query: string) => {
|
|
50
|
+
setSearchQuery(query)
|
|
51
|
+
setCurrentMatchIndex(0)
|
|
52
|
+
const matches = query ? matchRef.current(query) : []
|
|
53
|
+
if (matches[0] != null) {
|
|
54
|
+
onJumpRef.current(matches[0])
|
|
55
|
+
}
|
|
56
|
+
}, [])
|
|
57
|
+
|
|
58
|
+
useCommand({
|
|
59
|
+
id: "cursor-search-start",
|
|
60
|
+
title: "Search",
|
|
61
|
+
hotkey: "/",
|
|
62
|
+
modes: CURSOR_MODES,
|
|
63
|
+
handler: () => {
|
|
64
|
+
preSearchModeRef.current = mode
|
|
65
|
+
setSearchActive(true)
|
|
66
|
+
setSearchQuery("")
|
|
67
|
+
setMode("insert")
|
|
68
|
+
},
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
useCommand({
|
|
72
|
+
id: "cursor-search-next",
|
|
73
|
+
title: "Next match",
|
|
74
|
+
hotkey: "n",
|
|
75
|
+
modes: CURSOR_MODES,
|
|
76
|
+
when: () => !searchActive,
|
|
77
|
+
handler: () => {
|
|
78
|
+
const matches = matchingLinesRef.current
|
|
79
|
+
if (matches.length === 0) return
|
|
80
|
+
|
|
81
|
+
setCurrentMatchIndex((index) => {
|
|
82
|
+
const nextIndex = (index + 1) % matches.length
|
|
83
|
+
const nextMatch = matches[nextIndex]
|
|
84
|
+
if (nextMatch != null) {
|
|
85
|
+
onJumpRef.current(nextMatch)
|
|
86
|
+
}
|
|
87
|
+
return nextIndex
|
|
88
|
+
})
|
|
89
|
+
},
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
useCommand({
|
|
93
|
+
id: "cursor-search-prev",
|
|
94
|
+
title: "Previous match",
|
|
95
|
+
hotkey: "shift+n",
|
|
96
|
+
modes: CURSOR_MODES,
|
|
97
|
+
when: () => !searchActive,
|
|
98
|
+
handler: () => {
|
|
99
|
+
const matches = matchingLinesRef.current
|
|
100
|
+
if (matches.length === 0) return
|
|
101
|
+
|
|
102
|
+
setCurrentMatchIndex((index) => {
|
|
103
|
+
const nextIndex = (index - 1 + matches.length) % matches.length
|
|
104
|
+
const nextMatch = matches[nextIndex]
|
|
105
|
+
if (nextMatch != null) {
|
|
106
|
+
onJumpRef.current(nextMatch)
|
|
107
|
+
}
|
|
108
|
+
return nextIndex
|
|
109
|
+
})
|
|
110
|
+
},
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
useCommand({
|
|
114
|
+
id: "search-cancel",
|
|
115
|
+
title: "Cancel search",
|
|
116
|
+
hotkey: "escape",
|
|
117
|
+
modes: ALL_MODES,
|
|
118
|
+
when: () => searchActive,
|
|
119
|
+
handler: () => {
|
|
120
|
+
setSearchActive(false)
|
|
121
|
+
setSearchQuery("")
|
|
122
|
+
setCommittedQuery("")
|
|
123
|
+
setCurrentMatchIndex(0)
|
|
124
|
+
setMode(preSearchModeRef.current)
|
|
125
|
+
},
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
const submitSearch = useCallback(() => {
|
|
129
|
+
setCommittedQuery(searchQuery)
|
|
130
|
+
setSearchActive(false)
|
|
131
|
+
setCurrentMatchIndex(0)
|
|
132
|
+
const matches = searchQuery ? matchRef.current(searchQuery) : []
|
|
133
|
+
if (matches[0] != null) {
|
|
134
|
+
onJumpRef.current(matches[0])
|
|
135
|
+
}
|
|
136
|
+
setMode(preSearchModeRef.current)
|
|
137
|
+
}, [searchQuery, setMode])
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
searchQuery,
|
|
141
|
+
searchActive,
|
|
142
|
+
setSearchQuery: updateSearchQuery,
|
|
143
|
+
matchingLines,
|
|
144
|
+
currentMatchIndex,
|
|
145
|
+
submitSearch,
|
|
146
|
+
}
|
|
147
|
+
}
|
package/src/theme-picker.ts
CHANGED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { CommandPaletteEntry } from "@tooee/renderers";
|
|
2
|
-
export interface CommandPaletteState {
|
|
3
|
-
isOpen: boolean;
|
|
4
|
-
open: () => void;
|
|
5
|
-
close: () => void;
|
|
6
|
-
entries: CommandPaletteEntry[];
|
|
7
|
-
}
|
|
8
|
-
export declare function useCommandPalette(): CommandPaletteState;
|
|
9
|
-
//# sourceMappingURL=command-palette.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"command-palette.d.ts","sourceRoot":"","sources":["../src/command-palette.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAM3D,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,OAAO,EAAE,mBAAmB,EAAE,CAAA;CAC/B;AAED,wBAAgB,iBAAiB,IAAI,mBAAmB,CAqDvD"}
|
package/dist/command-palette.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { useCallback, useMemo, useRef, useState } from "react";
|
|
2
|
-
import { createElement } from "react";
|
|
3
|
-
import { useCommandContext, useCommand, useMode } from "@tooee/commands";
|
|
4
|
-
import { useOverlay } from "@tooee/overlays";
|
|
5
|
-
import { CommandPaletteOverlay } from "./CommandPaletteOverlay.js";
|
|
6
|
-
const DEFAULT_MODES = ["cursor"];
|
|
7
|
-
const OVERLAY_ID = "command-palette";
|
|
8
|
-
export function useCommandPalette() {
|
|
9
|
-
const { commands } = useCommandContext();
|
|
10
|
-
const mode = useMode();
|
|
11
|
-
const overlay = useOverlay();
|
|
12
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
13
|
-
const launchModeRef = useRef(mode);
|
|
14
|
-
const launchMode = launchModeRef.current;
|
|
15
|
-
const entries = useMemo(() => {
|
|
16
|
-
return commands
|
|
17
|
-
.filter((cmd) => !cmd.hidden)
|
|
18
|
-
.filter((cmd) => {
|
|
19
|
-
const cmdModes = cmd.modes ?? DEFAULT_MODES;
|
|
20
|
-
return cmdModes.includes(launchMode);
|
|
21
|
-
})
|
|
22
|
-
.map((cmd) => ({
|
|
23
|
-
id: cmd.id,
|
|
24
|
-
title: cmd.title,
|
|
25
|
-
hotkey: cmd.defaultHotkey,
|
|
26
|
-
category: cmd.category,
|
|
27
|
-
icon: cmd.icon,
|
|
28
|
-
}));
|
|
29
|
-
}, [commands, launchMode]);
|
|
30
|
-
const close = useCallback(() => {
|
|
31
|
-
setIsOpen(false);
|
|
32
|
-
overlay.hide(OVERLAY_ID);
|
|
33
|
-
}, [overlay]);
|
|
34
|
-
const open = useCallback(() => {
|
|
35
|
-
launchModeRef.current = mode;
|
|
36
|
-
setIsOpen(true);
|
|
37
|
-
overlay.open(OVERLAY_ID, ({ close }) => createElement(CommandPaletteOverlay, {
|
|
38
|
-
launchMode: mode,
|
|
39
|
-
close: () => close(),
|
|
40
|
-
}), null, { mode: "insert", dismissOnEscape: true, onClose: () => setIsOpen(false) });
|
|
41
|
-
}, [overlay, mode]);
|
|
42
|
-
useCommand({
|
|
43
|
-
id: "command-palette",
|
|
44
|
-
title: "Command Palette",
|
|
45
|
-
hotkey: ":",
|
|
46
|
-
modes: ["cursor"],
|
|
47
|
-
handler: open,
|
|
48
|
-
});
|
|
49
|
-
return { isOpen, open, close, entries };
|
|
50
|
-
}
|
|
51
|
-
//# sourceMappingURL=command-palette.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"command-palette.js","sourceRoot":"","sources":["../src/command-palette.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AACrC,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAExE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAG5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAElE,MAAM,aAAa,GAAW,CAAC,QAAQ,CAAC,CAAA;AACxC,MAAM,UAAU,GAAG,iBAAiB,CAAA;AASpC,MAAM,UAAU,iBAAiB;IAC/B,MAAM,EAAE,QAAQ,EAAE,GAAG,iBAAiB,EAAE,CAAA;IACxC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAA;IACtB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAC5B,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,aAAa,GAAG,MAAM,CAAO,IAAI,CAAC,CAAA;IAExC,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAA;IACxC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE;QAC3B,OAAO,QAAQ;aACZ,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;aAC5B,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE;YACd,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,IAAI,aAAa,CAAA;YAC3C,OAAO,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAA;QACtC,CAAC,CAAC;aACD,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACb,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,MAAM,EAAE,GAAG,CAAC,aAAa;YACzB,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,IAAI,EAAE,GAAG,CAAC,IAAI;SACf,CAAC,CAAC,CAAA;IACP,CAAC,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAA;IAE1B,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;QAC7B,SAAS,CAAC,KAAK,CAAC,CAAA;QAChB,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IAC1B,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IAEb,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE;QAC5B,aAAa,CAAC,OAAO,GAAG,IAAI,CAAA;QAC5B,SAAS,CAAC,IAAI,CAAC,CAAA;QACf,OAAO,CAAC,IAAI,CACV,UAAU,EACV,CAAC,EAAE,KAAK,EAAoD,EAAE,EAAE,CAC9D,aAAa,CAAC,qBAAqB,EAAE;YACnC,UAAU,EAAE,IAAI;YAChB,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE;SACrB,CAAC,EACJ,IAAI,EACJ,EAAE,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAC3E,CAAA;IACH,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAA;IAEnB,UAAU,CAAC;QACT,EAAE,EAAE,iBAAiB;QACrB,KAAK,EAAE,iBAAiB;QACxB,MAAM,EAAE,GAAG;QACX,KAAK,EAAE,CAAC,QAAQ,CAAC;QACjB,OAAO,EAAE,IAAI;KACd,CAAC,CAAA;IAEF,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;AACzC,CAAC"}
|
package/dist/modal.d.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { type Mode } from "@tooee/commands";
|
|
2
|
-
export interface Position {
|
|
3
|
-
line: number;
|
|
4
|
-
col: number;
|
|
5
|
-
}
|
|
6
|
-
export interface ModalNavigationState {
|
|
7
|
-
mode: Mode;
|
|
8
|
-
setMode: (mode: Mode) => void;
|
|
9
|
-
cursor: Position | null;
|
|
10
|
-
selection: {
|
|
11
|
-
start: Position;
|
|
12
|
-
end: Position;
|
|
13
|
-
} | null;
|
|
14
|
-
toggledIndices: Set<number>;
|
|
15
|
-
searchQuery: string;
|
|
16
|
-
searchActive: boolean;
|
|
17
|
-
setSearchQuery: (query: string) => void;
|
|
18
|
-
matchingLines: number[];
|
|
19
|
-
currentMatchIndex: number;
|
|
20
|
-
submitSearch: () => void;
|
|
21
|
-
}
|
|
22
|
-
export interface ModalNavigationOptions {
|
|
23
|
-
totalLines: number;
|
|
24
|
-
viewportHeight?: number;
|
|
25
|
-
getText?: () => string | undefined;
|
|
26
|
-
blockCount?: number;
|
|
27
|
-
blockLineMap?: number[];
|
|
28
|
-
/** Offset to subtract from search line numbers to get block indices (for when getText has different line structure than visual) */
|
|
29
|
-
searchLineOffset?: number;
|
|
30
|
-
multiSelect?: boolean;
|
|
31
|
-
}
|
|
32
|
-
export declare function useModalNavigationCommands(opts: ModalNavigationOptions): ModalNavigationState;
|
|
33
|
-
//# sourceMappingURL=modal.d.ts.map
|
package/dist/modal.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["../src/modal.ts"],"names":[],"mappings":"AACA,OAAO,EAAmC,KAAK,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAK5E,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,IAAI,CAAA;IACV,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAC7B,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAA;IACvB,SAAS,EAAE;QAAE,KAAK,EAAE,QAAQ,CAAC;QAAC,GAAG,EAAE,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAA;IACpD,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC3B,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,OAAO,CAAA;IACrB,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,iBAAiB,EAAE,MAAM,CAAA;IACzB,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,OAAO,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAA;IAClC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,mIAAmI;IACnI,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,sBAAsB,GAAG,oBAAoB,CA4Z7F"}
|