Skip to content

Commit db0e6b4

Browse files
authored
feat: configurable key bindings (#255)
* test(config): add more fields to the config file to test the new behavior * feat(command): add more option fields to the commands struct to config the navigation key bindings * feat(config): add more fields to the config object to read the navigation keybindings from the config file * feat(tui): add a way to read the navigation keybindings rather than the constant values from tcell * feat(root): add default keybindings to keep backward compatibility * docs(readme): add documentation for the key bindings configuration * chore(form): ignore key bindings field so dblab can enter in form mode * fix: fix typo * refactor: move non-navigation key bindings a level above on the KeyBinding structs * docs(mkdocs): add key binding config documentation to the mkdocs
1 parent 919d753 commit db0e6b4

File tree

11 files changed

+357
-109
lines changed

11 files changed

+357
-109
lines changed

.dblab.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,14 @@ database:
3535
password: "5@klkbN#ABC"
3636
user: "SA"
3737
limit: 50
38+
keybindings:
39+
run-query: 'Ctrl-Space'
40+
structure: 'Ctrl-S'
41+
indexes: 'Ctrl-I'
42+
constraints: 'Ctrl-T'
43+
clear-editor: 'Ctrl-D'
44+
navigation:
45+
up: 'Ctrl-K'
46+
down: 'Ctrl-J'
47+
left: 'Ctrl-H'
48+
right: 'Ctrl-L'

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ __Interactive client for PostgreSQL, MySQL, SQLite3, Oracle and SQL Server.__
2727
- [Usage](#usage)
2828
- [SSH Tunnel](#ssh-tunnel)
2929
- [Configuration](#configuration)
30+
- [Key bindings configuration](#key-bindings-configuration)
3031
- [Navigation](#navigation)
3132
- [Key Bindings](#key-bindings)
3233
- [Contribute](#contribute)
@@ -253,7 +254,11 @@ $ dblab --config
253254
$ dblab --config --cfg-name "prod"
254255
```
255256

256-
`.dblab.yaml` example:
257+
#### Key bindings configuration
258+
259+
Key bindings can be configured through the `.dblab.yaml` file. There is a field called `keybindings` where key bindings can be modified. See the example to see the full list of the key bindings subject to change. The file shows the default values. The list of the available key bindings belongs to the [tcell](https://github.com/gdamore/tcell) library. Specifically, see the [KeyNames map](https://github.com/gdamore/tcell/blob/781586687ddb57c9d44727dc9320340c4d049b11/key.go#L83), for an accurate reference.
260+
261+
#### .dblab.yaml example
257262

258263
```yaml
259264
database:
@@ -310,6 +315,17 @@ database:
310315
ssh-pass: "password"
311316
# should be greater than 0, otherwise the app will error out
312317
limit: 50
318+
keybindings:
319+
run-query: 'Ctrl-Space'
320+
structure: 'Ctrl-S'
321+
indexes: 'Ctrl-I'
322+
constraints: 'Ctrl-T'
323+
clear-editor: 'Ctrl-D'
324+
navigation:
325+
up: 'Ctrl-K'
326+
down: 'Ctrl-J'
327+
left: 'Ctrl-H'
328+
right: 'Ctrl-L'
313329
```
314330
315331
Or for sqlite:
@@ -325,6 +341,8 @@ Only the `host` and `ssl` fields are optionals. `127.0.0.1` and `disable`, respe
325341

326342
## Navigation
327343

344+
The key bindings are now configurable, see [Key bindings configuration](#key-bindings-configuration) to learn how to replace existing key bindings. It's worth noting that key bindings are only configurable through the configuration file, there is no flags to do so. If you don't replace them through the configuration file, the information below remains the same, otherwise, just replace the new key binding with the existing information for the default one.
345+
328346
If the query panel is active, type the desired query and press <kbd>Ctrl+Space</kbd> to see the results on the rows panel below.
329347
Otherwise, you might me located at the tables panel, then you can navigate by using the arrows <kbd>Up</kbd> and <kbd>Down</kbd> (or the keys <kbd>k</kbd> and <kbd>j</kbd> respectively). If you want to see the rows of a table, press <kbd>Enter</kbd>. To see the the schema of a table, locate yourself on the `rows` panel and press <kbd>Ctrl+S</kbd> to switch to the `structure` panel, then switch <kbd>Ctrl+S</kbd> to switch back.
330348
The same can be achieved for the `constraints` view by pressing <kbd>Ctrl+F</kbd> to go back and forth between the `rows` and the `constraints` panels.

cmd/root.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cmd
22

33
import (
4+
"github.com/gdamore/tcell/v2"
45
"github.com/spf13/cobra"
56

67
"github.com/danvergara/dblab/pkg/app"
@@ -29,17 +30,20 @@ var (
2930
sslkey string
3031
sslpassword string
3132
sslrootcert string
33+
3234
// SSH Tunnel.
3335
sshHost string
3436
sshPort string
3537
sshUser string
3638
sshPass string
3739
sshKey string
3840
sshKeyPassphrase string
41+
3942
// oracle specific.
4043
traceFile string
4144
sslVerify string
4245
wallet string
46+
4347
// sql server.
4448
encrypt string
4549
trustServerCertificate string
@@ -90,6 +94,19 @@ func NewRootCmd() *cobra.Command {
9094
SSHPass: sshPass,
9195
SSHKeyFile: sshKey,
9296
SSHKeyPassphrase: sshKeyPassphrase,
97+
TUIKeyBindings: command.TUIKeyBindings{
98+
RunQuery: tcell.KeyCtrlSpace,
99+
Structure: tcell.KeyCtrlS,
100+
Indexes: tcell.KeyCtrlI,
101+
Constraints: tcell.KeyCtrlT,
102+
ClearEditor: tcell.KeyCtrlD,
103+
Navigation: command.TUINavigationBindgins{
104+
Up: tcell.KeyCtrlK,
105+
Down: tcell.KeyCtrlJ,
106+
Left: tcell.KeyCtrlH,
107+
Right: tcell.KeyCtrlL,
108+
},
109+
},
93110
}
94111

95112
if form.IsEmpty(opts) {

docs/usage.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,12 @@ dbladb --config
265265
dblab --config --cfg-name "prod"
266266
```
267267

268-
`.dblab.yaml` example:
268+
#### Key bindings configuration
269+
270+
Key bindings can be configured through the `.dblab.yaml` file. There is a field called `keybindings` where key bindings can be modified. See the example to see the full list of the key bindings subject to change. The file shows the default values. The list of the available key bindings belongs to the [tcell](https://github.com/gdamore/tcell) library. Specifically, see the [KeyNames map](https://github.com/gdamore/tcell/blob/781586687ddb57c9d44727dc9320340c4d049b11/key.go#L83), for an accurate reference.
271+
272+
273+
#### .dblab.yaml example
269274

270275
```{ .yaml .copy }
271276
database:
@@ -322,6 +327,17 @@ database:
322327
ssh-pass: "password"
323328
# should be greater than 0, otherwise the app will error out
324329
limit: 50
330+
keybindings:
331+
run-query: 'Ctrl-Space'
332+
structure: 'Ctrl-S'
333+
indexes: 'Ctrl-I'
334+
constraints: 'Ctrl-T'
335+
clear-editor: 'Ctrl-D'
336+
navigation:
337+
up: 'Ctrl-K'
338+
down: 'Ctrl-J'
339+
left: 'Ctrl-H'
340+
right: 'Ctrl-L'
325341
```
326342

327343
Or for sqlite:

pkg/app/app.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func New(opts command.Options) (*App, error) {
4040
return nil, err
4141
}
4242

43-
t, err := tui.New(c)
43+
t, err := tui.New(tui.WithClient(c), tui.WithKeyBinding(&opts.TUIKeyBindings))
4444
if err != nil {
4545
return nil, err
4646
}

pkg/command/command.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package command
22

3-
import "os"
3+
import (
4+
"os"
5+
6+
"github.com/gdamore/tcell/v2"
7+
)
48

59
// Options is a struct that stores the provided commands by the user.
610
type Options struct {
@@ -36,6 +40,24 @@ type Options struct {
3640
Encrypt string
3741
TrustServerCertificate string
3842
ConnectionTimeout string
43+
// TUI keybidings.
44+
TUIKeyBindings TUIKeyBindings
45+
}
46+
47+
type TUIKeyBindings struct {
48+
RunQuery tcell.Key
49+
Structure tcell.Key
50+
Indexes tcell.Key
51+
Constraints tcell.Key
52+
ClearEditor tcell.Key
53+
Navigation TUINavigationBindgins
54+
}
55+
56+
type TUINavigationBindgins struct {
57+
Up tcell.Key
58+
Down tcell.Key
59+
Left tcell.Key
60+
Right tcell.Key
3961
}
4062

4163
// SetDefault returns a Options struct and fills the empty

pkg/config/.dblab.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,14 @@ database:
4949
ssh-user: "ssh-user"
5050
ssh-pass: "password"
5151
limit: 50
52+
keybindings:
53+
run-query: 'Ctrl-Space'
54+
structure: 'Ctrl-S'
55+
indexes: 'Ctrl-I'
56+
constraints: 'Ctrl-T'
57+
clear-editor: 'Ctrl-D'
58+
navigation:
59+
up: 'Ctrl-K'
60+
down: 'Ctrl-J'
61+
left: 'Ctrl-H'
62+
right: 'Ctrl-L'

pkg/config/config.go

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"os"
99

10+
"github.com/gdamore/tcell/v2"
1011
"github.com/golang-migrate/migrate/v4"
1112
"github.com/golang-migrate/migrate/v4/database/sqlite3"
1213
"github.com/golang-migrate/migrate/v4/source/file"
@@ -19,14 +20,15 @@ import (
1920

2021
// Config struct is used to store the db connection data.
2122
type Config struct {
22-
Database []Database
23-
User string
24-
Pswd string
25-
Host string
26-
Port string
27-
DBName string
28-
Driver string
29-
Limit uint `fig:"limit" default:"100"`
23+
Database []Database
24+
User string
25+
Pswd string
26+
Host string
27+
Port string
28+
DBName string
29+
Driver string
30+
Limit uint `fig:"limit" default:"100"`
31+
KeyBindings KeyBindings
3032
}
3133

3234
type Database struct {
@@ -67,6 +69,33 @@ type Database struct {
6769
ConnectionTimeout string `fig:"connection-timeout"`
6870
}
6971

72+
type KeyBindings struct {
73+
RunQuery string `fig:"run-query" default:"Ctrl-Space"`
74+
Structure string `fig:"structure" default:"Ctrl-S"`
75+
Indexes string `fig:"indexes" default:"Ctrl-I"`
76+
Constraints string `fig:"constraints" default:"Ctrl-T"`
77+
ClearEditor string `fig:"clear-editor" default:"Ctrl-D"`
78+
Navigation NavigationBindgins
79+
}
80+
81+
type NavigationBindgins struct {
82+
Up string `fig:"up" default:"Ctrl-K"`
83+
Down string `fig:"down" default:"Ctrl-J"`
84+
Left string `fig:"left" default:"Ctrl-H"`
85+
Right string `fig:"right" default:"Ctrl-L"`
86+
}
87+
88+
// swapKeyNames swap keys and values of the tcell.KeyNames map.
89+
func swapKeyNames[K comparable, V comparable](m map[K]V) map[V]K {
90+
reversed := make(map[V]K, len(m))
91+
92+
for k, v := range m {
93+
reversed[v] = k
94+
}
95+
96+
return reversed
97+
}
98+
7099
// New returns a config instance the with db connection data inplace based on the flags of a cobra command.
71100
func New(cmd *cobra.Command) *Config {
72101
conf := &Config{}
@@ -116,6 +145,11 @@ func Init(configName string) (command.Options, error) {
116145
db = cfg.Database[0]
117146
}
118147

148+
swapedKeyNames := swapKeyNames(tcell.KeyNames)
149+
// This entry is missing in the tcell.KeyNames.
150+
swapedKeyNames["Ctrl-H"] = tcell.KeyCtrlH
151+
swapedKeyNames["Ctrl-I"] = tcell.KeyCtrlI
152+
119153
opts = command.Options{
120154
Driver: db.Driver,
121155
Host: db.Host,
@@ -142,6 +176,19 @@ func Init(configName string) (command.Options, error) {
142176
SSHPass: db.SSHPass,
143177
SSHKeyFile: db.SSHKeyFile,
144178
SSHKeyPassphrase: db.SSHKeyPassphrase,
179+
TUIKeyBindings: command.TUIKeyBindings{
180+
RunQuery: tcell.Key(swapedKeyNames[cfg.KeyBindings.RunQuery]),
181+
Structure: tcell.Key(swapedKeyNames[cfg.KeyBindings.Structure]),
182+
Constraints: tcell.Key(swapedKeyNames[cfg.KeyBindings.Constraints]),
183+
Indexes: tcell.Key(swapedKeyNames[cfg.KeyBindings.Indexes]),
184+
ClearEditor: tcell.Key(swapedKeyNames[cfg.KeyBindings.ClearEditor]),
185+
Navigation: command.TUINavigationBindgins{
186+
Up: tcell.Key(swapedKeyNames[cfg.KeyBindings.Navigation.Up]),
187+
Down: tcell.Key(swapedKeyNames[cfg.KeyBindings.Navigation.Down]),
188+
Left: tcell.Key(swapedKeyNames[cfg.KeyBindings.Navigation.Left]),
189+
Right: tcell.Key(swapedKeyNames[cfg.KeyBindings.Navigation.Right]),
190+
},
191+
},
145192
}
146193

147194
return opts, nil

0 commit comments

Comments
 (0)