sabiql 1.8.0

A fast, driver-less TUI for browsing and editing PostgreSQL databases
Documentation
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
use super::KeyBinding;
use super::types::{Key, KeyCombo};
use crate::app::action::Action;

// =============================================================================
// Global Keys (Normal mode)
// =============================================================================

pub const GLOBAL_KEYS: &[KeyBinding] = &[
    // idx 0: QUIT
    KeyBinding {
        key_short: "q",
        key: "q",
        desc_short: "Quit",
        description: "Quit application",
        action: Action::Quit,
        combos: &[KeyCombo::plain(Key::Char('q'))],
    },
    // idx 1: HELP
    KeyBinding {
        key_short: "?",
        key: "?",
        desc_short: "Help",
        description: "Toggle help",
        action: Action::OpenHelp,
        combos: &[KeyCombo::plain(Key::Char('?'))],
    },
    // idx 2: TABLE_PICKER
    KeyBinding {
        key_short: "^P",
        key: "Ctrl+P",
        desc_short: "Tables",
        description: "Open Table Picker",
        action: Action::OpenTablePicker,
        combos: &[KeyCombo::ctrl(Key::Char('p'))],
    },
    // idx 3: PALETTE
    KeyBinding {
        key_short: "^K",
        key: "Ctrl+K",
        desc_short: "Palette",
        description: "Open Command Palette",
        action: Action::OpenCommandPalette,
        combos: &[KeyCombo::ctrl(Key::Char('k'))],
    },
    // idx 4: COMMAND_LINE
    KeyBinding {
        key_short: ":",
        key: ":",
        desc_short: "Cmd",
        description: "Enter command line",
        action: Action::EnterCommandLine,
        combos: &[KeyCombo::plain(Key::Char(':'))],
    },
    // idx 5: FOCUS / idx 6: EXIT_FOCUS — intentionally duplicate combo ('f')
    // for the same Action::ToggleFocus. Two entries exist because the footer
    // shows different labels depending on whether focus mode is active.
    KeyBinding {
        key_short: "f",
        key: "f",
        desc_short: "Focus",
        description: "Toggle Focus mode",
        action: Action::ToggleFocus,
        combos: &[KeyCombo::plain(Key::Char('f'))],
    },
    KeyBinding {
        key_short: "f",
        key: "f",
        desc_short: "Exit Focus",
        description: "Exit Focus mode",
        action: Action::ToggleFocus,
        combos: &[KeyCombo::plain(Key::Char('f'))],
    },
    // idx 7: PANE_SWITCH
    KeyBinding {
        key_short: "1/2/3",
        key: "1/2/3",
        desc_short: "Pane",
        description: "Switch pane focus",
        action: Action::None,
        combos: &[],
    },
    // idx 8: INSPECTOR_TABS
    KeyBinding {
        key_short: "Tab/⇧Tab",
        key: "Tab/⇧Tab",
        desc_short: "InsTabs",
        description: "Inspector prev/next tab",
        action: Action::None,
        combos: &[],
    },
    // idx 9: RELOAD
    KeyBinding {
        key_short: "r",
        key: "r",
        desc_short: "Reload",
        description: "Reload metadata",
        action: Action::ReloadMetadata,
        combos: &[KeyCombo::plain(Key::Char('r'))],
    },
    // idx 10: SQL
    KeyBinding {
        key_short: "s",
        key: "s",
        desc_short: "SQL",
        description: "Open SQL Editor",
        action: Action::OpenSqlModal,
        combos: &[KeyCombo::plain(Key::Char('s'))],
    },
    // idx 11: ER_DIAGRAM
    KeyBinding {
        key_short: "e",
        key: "e",
        desc_short: "ER Diagram",
        description: "Open ER Diagram",
        action: Action::OpenErTablePicker,
        combos: &[KeyCombo::plain(Key::Char('e'))],
    },
    // idx 12: CONNECTIONS
    KeyBinding {
        key_short: "c",
        key: "c",
        desc_short: "Connections",
        description: "Open Connection Selector",
        action: Action::OpenConnectionSelector,
        combos: &[KeyCombo::plain(Key::Char('c'))],
    },
    // idx 13: CSV_EXPORT
    KeyBinding {
        key_short: "^E",
        key: "Ctrl+E",
        desc_short: "Export",
        description: "Export result to CSV",
        action: Action::RequestCsvExport,
        combos: &[KeyCombo::ctrl(Key::Char('e'))],
    },
    // idx 14: READ_ONLY / idx 15: EXIT_READ_ONLY — intentionally duplicate combo (Ctrl+R)
    // for the same Action::ToggleReadOnly. Two entries exist because the footer
    // shows different labels depending on whether read-only mode is active.
    KeyBinding {
        key_short: "^R",
        key: "Ctrl+R",
        desc_short: "Read-Only",
        description: "Enable Read-Only mode",
        action: Action::ToggleReadOnly,
        combos: &[KeyCombo::ctrl(Key::Char('r'))],
    },
    KeyBinding {
        key_short: "^R",
        key: "Ctrl+R",
        desc_short: "Read-Write",
        description: "Disable Read-Only mode",
        action: Action::ToggleReadOnly,
        combos: &[KeyCombo::ctrl(Key::Char('r'))],
    },
    // idx 16: QUERY_HISTORY
    KeyBinding {
        key_short: "^O",
        key: "Ctrl+O",
        desc_short: "History",
        description: "Open Query History",
        action: Action::OpenQueryHistoryPicker,
        combos: &[KeyCombo::ctrl(Key::Char('o'))],
    },
];

pub const NAVIGATION_KEYS: &[KeyBinding] = &[
    KeyBinding {
        key_short: "j",
        key: "j / ↓",
        desc_short: "Down",
        description: "Move down / scroll",
        action: Action::None,
        combos: &[],
    },
    KeyBinding {
        key_short: "k",
        key: "k / ↑",
        desc_short: "Up",
        description: "Move up / scroll",
        action: Action::None,
        combos: &[],
    },
    KeyBinding {
        key_short: "g",
        key: "g / Home",
        desc_short: "Top",
        description: "First item / top",
        action: Action::None,
        combos: &[],
    },
    KeyBinding {
        key_short: "G",
        key: "G / End",
        desc_short: "Bottom",
        description: "Last item / bottom",
        action: Action::None,
        combos: &[],
    },
    KeyBinding {
        key_short: "M",
        key: "M",
        desc_short: "Middle",
        description: "Middle of viewport",
        action: Action::None,
        combos: &[],
    },
    KeyBinding {
        key_short: "^D/^U",
        key: "Ctrl+D / Ctrl+U",
        desc_short: "Half Page",
        description: "Scroll half page down/up",
        action: Action::None,
        combos: &[],
    },
    KeyBinding {
        key_short: "^F/^B",
        key: "Ctrl+F/B / PgDn/Up",
        desc_short: "Full Page",
        description: "Scroll full page down/up",
        action: Action::None,
        combos: &[],
    },
    KeyBinding {
        key_short: "h/l / ←→",
        key: "h / l",
        desc_short: "H-Scroll",
        description: "Scroll left/right",
        action: Action::None,
        combos: &[],
    },
    KeyBinding {
        key_short: "]",
        key: "]",
        desc_short: "Next Page",
        description: "Next page (Preview)",
        action: Action::ResultNextPage,
        combos: &[KeyCombo::plain(Key::Char(']'))],
    },
    KeyBinding {
        key_short: "[",
        key: "[",
        desc_short: "Prev Page",
        description: "Previous page (Preview)",
        action: Action::ResultPrevPage,
        combos: &[KeyCombo::plain(Key::Char('['))],
    },
];

pub const FOOTER_NAV_KEYS: &[KeyBinding] = &[
    // idx 0: SCROLL
    KeyBinding {
        key_short: "j/k / ↑↓",
        key: "j / k / ↑ / ↓",
        desc_short: "Scroll",
        description: "Move down/up",
        action: Action::None,
        combos: &[],
    },
    // idx 1: SCROLL_SHORT (same as SCROLL for now)
    KeyBinding {
        key_short: "j/k / ↑↓",
        key: "j / k / ↑ / ↓",
        desc_short: "Scroll",
        description: "Move down/up",
        action: Action::None,
        combos: &[],
    },
    // idx 2: TOP_MID_BOTTOM
    KeyBinding {
        key_short: "g/M/G",
        key: "g / M / G",
        desc_short: "Top/Mid/Bot",
        description: "First/Middle/Last item",
        action: Action::None,
        combos: &[],
    },
    // idx 3: H_SCROLL
    KeyBinding {
        key_short: "h/l / ←→",
        key: "h / l / ← / →",
        desc_short: "H-Scroll",
        description: "Scroll left/right",
        action: Action::None,
        combos: &[],
    },
    // idx 4: PAGE_NAV
    KeyBinding {
        key_short: "]/[",
        key: "] / [",
        desc_short: "Page",
        description: "Next/Previous page",
        action: Action::None,
        combos: &[],
    },
];

pub const RESULT_ACTIVE_KEYS: &[KeyBinding] = &[
    // idx 0: ENTER_DEEPEN
    KeyBinding {
        key_short: "Enter",
        key: "Enter",
        desc_short: "Select",
        description: "Enter row / cell selection",
        action: Action::ResultEnterRowActive,
        combos: &[KeyCombo::plain(Key::Enter)],
    },
    // idx 1: YANK
    KeyBinding {
        key_short: "y",
        key: "y",
        desc_short: "Yank",
        description: "Copy cell value to clipboard",
        action: Action::ResultCellYank,
        combos: &[KeyCombo::plain(Key::Char('y'))],
    },
    // idx 2: STAGE_DELETE
    KeyBinding {
        key_short: "dd",
        key: "d, d",
        desc_short: "Stage Del",
        description: "Stage row for deletion (red highlight; :w to commit)",
        action: Action::StageRowForDelete,
        combos: &[], // dd is a two-key sequence, not a single combo
    },
    // idx 3: UNSTAGE_DELETE
    KeyBinding {
        key_short: "u",
        key: "u",
        desc_short: "Unstage",
        description: "Unstage last staged row",
        action: Action::UnstageLastStagedRow,
        combos: &[KeyCombo::plain(Key::Char('u'))],
    },
    // idx 4: CELL_NAV (display-only)
    KeyBinding {
        key_short: "h/l",
        key: "h / l",
        desc_short: "Cell",
        description: "Move cell left/right",
        action: Action::None,
        combos: &[],
    },
    // idx 5: ROW_NAV (display-only)
    KeyBinding {
        key_short: "j/k",
        key: "j / k",
        desc_short: "Row",
        description: "Move row up/down",
        action: Action::None,
        combos: &[],
    },
    // idx 6: TOP_MID_BOTTOM (display-only)
    KeyBinding {
        key_short: "g/M/G",
        key: "g / M / G",
        desc_short: "Top/Mid/Bot",
        description: "First/Middle/Last row",
        action: Action::None,
        combos: &[],
    },
    // idx 7: ESC_BACK
    KeyBinding {
        key_short: "Esc",
        key: "Esc",
        desc_short: "Back",
        description: "Exit to previous mode",
        action: Action::ResultExitToScroll,
        combos: &[KeyCombo::plain(Key::Esc)],
    },
    // idx 8: EDIT
    KeyBinding {
        key_short: "i",
        key: "i",
        desc_short: "Edit",
        description: "Edit active cell",
        action: Action::ResultEnterCellEdit,
        combos: &[KeyCombo::plain(Key::Char('i'))],
    },
    // idx 9: DRAFT_DISCARD
    KeyBinding {
        key_short: "Esc",
        key: "Esc",
        desc_short: "Discard",
        description: "Discard pending draft and exit to Row Active",
        action: Action::ResultDiscardCellEdit,
        combos: &[KeyCombo::plain(Key::Esc)],
    },
    // idx 10: ROW_YANK
    KeyBinding {
        key_short: "yy",
        key: "y, y",
        desc_short: "Yank Row",
        description: "Copy row values to clipboard (TSV)",
        action: Action::ResultRowYank,
        combos: &[],
    },
];

pub const HISTORY_KEYS: &[KeyBinding] = &[
    // idx 0: OPEN
    KeyBinding {
        key_short: "^H",
        key: "Ctrl+H",
        desc_short: "History",
        description: "Toggle Result History",
        action: Action::OpenResultHistory,
        combos: &[KeyCombo::ctrl(Key::Char('h'))],
    },
    // idx 1: NAV (display-only)
    KeyBinding {
        key_short: "]/[",
        key: "] / [",
        desc_short: "History",
        description: "Navigate history newer/older",
        action: Action::None,
        combos: &[],
    },
    // idx 2: EXIT (display-only)
    KeyBinding {
        key_short: "^H",
        key: "Ctrl+H",
        desc_short: "Back",
        description: "Exit history (back to latest)",
        action: Action::None,
        combos: &[],
    },
];

pub const INSPECTOR_DDL_KEYS: &[KeyBinding] = &[
    // idx 0: YANK
    KeyBinding {
        key_short: "y",
        key: "y",
        desc_short: "Yank",
        description: "Copy DDL to clipboard",
        action: Action::DdlYank,
        combos: &[KeyCombo::plain(Key::Char('y'))],
    },
];