Skip to content

Commit b771a6d

Browse files
authored
Merge pull request #20 from kyoto7250/add_mypullrequests
Add mypull requests
2 parents c2c6737 + d05017a commit b771a6d

21 files changed

+1119
-102
lines changed

.gitignore

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
1-
/target
2-
zhobo
3-
zhobo.yml
4-
zhobo.log
1+
# Generated by Cargo
2+
# will have compiled files and executables
3+
debug/
4+
target/
5+
6+
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
7+
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
8+
Cargo.lock
9+
10+
# These are backup files generated by rustfmt
11+
**/*.rs.bk
12+
13+
# MSVC Windows builds of rustc generate these, which store debugging information
14+
*.pdb
15+
.vscode/

Cargo.lock

+13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ clap = "4.5.7"
3434
structopt = "0.3.26"
3535
syntect = { version = "5.0", default-features = false, features = ["metadata", "default-fancy"]}
3636
unicode-segmentation = "1.11.0"
37+
ron = "0.8.1"
3738

3839
[target.'cfg(all(target_family="unix",not(target_os="macos")))'.dependencies]
3940
which = "6.0.1"

README.md

+18-36
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# dolce
1+
# zhobo
22

3-
`dolce` is the rebaked [gobang project](https://github.com/TaKO8Ki/gobang).
3+
`zhobo` is the rebaked [gobang project](https://github.com/TaKO8Ki/gobang).
44

55
## Features
66
- Cross-platform support (macOS, Windows, Linux)
@@ -26,7 +26,10 @@
2626
| <kbd>h</kbd>, <kbd>j</kbd>, <kbd>k</kbd>, <kbd>l</kbd> | Scroll left/down/up/right |
2727
| <kbd>Ctrl</kbd> + <kbd>u</kbd>, <kbd>Ctrl</kbd> + <kbd>d</kbd> | Scroll up/down multiple lines |
2828
| <kbd>g</kbd> , <kbd>G</kbd> | Scroll to top/bottom |
29+
| <kbd>^</kbd>, <kbd>$</kbd> | Move to head/tail of line |
30+
| <kbd>s</kbd> | Sort by selected column |
2931
| <kbd>H</kbd>, <kbd>J</kbd>, <kbd>K</kbd>, <kbd>L</kbd> | Extend selection by one cell left/down/up/right |
32+
| <kbd>V</kbd> | Extend selection by horizontal line |
3033
| <kbd>y</kbd> | Copy a cell value |
3134
| <kbd>←</kbd>, <kbd>→</kbd> | Move focus to left/right |
3235
| <kbd>c</kbd> | Move focus to connections |
@@ -42,43 +45,22 @@
4245

4346
The location of the file depends on your OS:
4447

45-
- macOS: `$HOME/.config/gobang/config.toml`
46-
- Linux: `$HOME/.config/gobang/config.toml`
47-
- Windows: `%APPDATA%/gobang/config.toml`
48-
49-
The following is a sample config.toml file:
50-
51-
```toml
52-
[[conn]]
53-
type = "mysql"
54-
user = "root"
55-
host = "localhost"
56-
port = 3306
57-
58-
[[conn]]
59-
type = "mysql"
60-
user = "root"
61-
host = "localhost"
62-
port = 3306
63-
password = "password"
64-
database = "foo"
65-
name = "mysql Foo DB"
66-
67-
[[conn]]
68-
type = "postgres"
69-
user = "root"
70-
host = "localhost"
71-
port = 5432
72-
database = "bar"
73-
name = "postgres Bar DB"
74-
75-
[[conn]]
76-
type = "sqlite"
77-
path = "/path/to/baz.db"
78-
```
48+
- macOS: `$HOME/.config/zhobo/config.toml`
49+
- Linux: `$HOME/.config/zhobo/config.toml`
50+
- Windows: `%APPDATA%/zhobo/config.toml`
51+
52+
Sample config.toml file is `examples/config.toml`:
7953

8054
### custom keymap
8155

56+
The location of the file depends on your OS:
57+
58+
- macOS: `$HOME/.config/zhobo/key_bind.ron`
59+
- Linux: `$HOME/.config/zhobo/key_bind.ron`
60+
- Windows: `%APPDATA%/zhobo/key_bind.ron`
61+
62+
Sample config.toml file is `examples/key_bind.ron`:
63+
8264
## contribution
8365

8466
Contributions are welcome.

examples/config.toml

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[[conn]]
2+
type = "mysql"
3+
user = "root"
4+
host = "localhost"
5+
port = 3306
6+
7+
[[conn]]
8+
type = "mysql"
9+
user = "root"
10+
host = "localhost"
11+
port = 3306
12+
password = "password"
13+
database = "foo"
14+
name = "mysql Foo DB"
15+
16+
[[conn]]
17+
type = "postgres"
18+
user = "root"
19+
host = "localhost"
20+
port = 5432
21+
database = "bar"
22+
name = "postgres Bar DB"
23+
24+
[[conn]]
25+
type = "sqlite"
26+
path = "/path/to/baz.db"

examples/key_bind.ron

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* This file is a custom key configuration file.
3+
* Place this file in `$HOME/.config/zhobo/key_bind.ron`.
4+
*/
5+
(
6+
scroll_up: Some(Char('k')),
7+
scroll_down: Some(Char('j')),
8+
scroll_right: Some(Char('l')),
9+
scroll_left: Some(Char('h')),
10+
sort_by_column: Some(Char('s')),
11+
move_up: Some(Up),
12+
move_down: Some(Down),
13+
copy: Some(Char('y')),
14+
enter: Some(Enter),
15+
exit: Some(Ctrl('c')),
16+
quit: Some(Char('q')),
17+
exit_popup: Some(Esc),
18+
focus_right: Some(Right),
19+
focus_left: Some(Left),
20+
focus_above: Some(Up),
21+
focus_connections: Some(Char('c')),
22+
open_help: Some(Char('?')),
23+
filter: Some(Char('/')),
24+
scroll_down_multiple_lines: Some(Ctrl('d')),
25+
scroll_up_multiple_lines: Some(Ctrl('u')),
26+
scroll_to_top: Some(Char('g')),
27+
scroll_to_bottom: Some(Char('G')),
28+
move_to_head_of_line: Some(Char('^')),
29+
move_to_tail_of_line: Some(Char('$')),
30+
extend_selection_by_one_cell_left: Some(Char('H')),
31+
extend_selection_by_one_cell_right: Some(Char('L')),
32+
extend_selection_by_one_cell_down: Some(Char('J')),
33+
extend_selection_by_horizontal_line: Some(Char('V')),
34+
extend_selection_by_one_cell_up: Some(Char('K')),
35+
tab_records: Some(Char('1')),
36+
tab_properties: Some(Char('2')),
37+
tab_sql_editor: Some(Char('3')),
38+
tab_columns: Some(Char('4')),
39+
tab_constraints: Some(Char('5')),
40+
tab_foreign_keys: Some(Char('6')),
41+
tab_indexes: Some(Char('7')),
42+
extend_or_shorten_widget_width_to_right: Some(Char('>')),
43+
extend_or_shorten_widget_width_to_left: Some(Char('<')),
44+
)

src/app.rs

+80-7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::components::{
1212
use crate::config::Config;
1313
use crate::database::{MySqlPool, Pool, PostgresPool, SqlitePool, RECORDS_LIMIT_PER_PAGE};
1414
use crate::event::Key;
15+
use ratatui::layout::Flex;
1516
use ratatui::{
1617
layout::{Constraint, Direction, Layout, Rect},
1718
Frame,
@@ -82,6 +83,7 @@ impl App {
8283

8384
let right_chunks = Layout::default()
8485
.direction(Direction::Vertical)
86+
.flex(Flex::Legacy)
8587
.constraints([Constraint::Length(3), Constraint::Length(5)].as_ref())
8688
.split(main_chunks[1]);
8789

@@ -139,6 +141,7 @@ impl App {
139141
if let Some(pool) = self.pool.as_ref() {
140142
pool.close().await;
141143
}
144+
142145
self.pool = if conn.is_mysql() {
143146
Some(Box::new(
144147
MySqlPool::new(conn.database_url()?.as_str()).await?,
@@ -162,7 +165,12 @@ impl App {
162165
Ok(())
163166
}
164167

165-
async fn update_record_table(&mut self) -> anyhow::Result<()> {
168+
async fn update_record_table(
169+
&mut self,
170+
orders: Option<String>,
171+
header_icons: Option<Vec<String>>,
172+
hold_cursor_position: bool,
173+
) -> anyhow::Result<()> {
166174
if let Some((database, table)) = self.databases.tree().selected_table() {
167175
let (headers, records) = self
168176
.pool
@@ -177,10 +185,16 @@ impl App {
177185
} else {
178186
Some(self.record_table.filter.input_str())
179187
},
188+
orders,
180189
)
181190
.await?;
182-
self.record_table
183-
.update(records, headers, database.clone(), table.clone());
191+
self.record_table.update(
192+
records,
193+
self.concat_headers(headers, header_icons),
194+
database.clone(),
195+
table.clone(),
196+
hold_cursor_position,
197+
);
184198
}
185199
Ok(())
186200
}
@@ -230,10 +244,15 @@ impl App {
230244
.pool
231245
.as_ref()
232246
.unwrap()
233-
.get_records(&database, &table, 0, None)
247+
.get_records(&database, &table, 0, None, None)
234248
.await?;
235-
self.record_table
236-
.update(records, headers, database.clone(), table.clone());
249+
self.record_table.update(
250+
records,
251+
headers,
252+
database.clone(),
253+
table.clone(),
254+
false,
255+
);
237256
self.properties
238257
.update(database.clone(), table.clone(), self.pool.as_ref().unwrap())
239258
.await?;
@@ -249,6 +268,17 @@ impl App {
249268
return Ok(EventState::Consumed);
250269
};
251270

271+
if key == self.config.key_config.sort_by_column
272+
&& !self.record_table.table.headers.is_empty()
273+
{
274+
self.record_table.table.add_order();
275+
let order_query = self.record_table.table.generate_order_query();
276+
let header_icons = self.record_table.table.generate_header_icons();
277+
self.update_record_table(order_query, Some(header_icons), true)
278+
.await?;
279+
return Ok(EventState::Consumed);
280+
};
281+
252282
if key == self.config.key_config.copy {
253283
if let Some(text) = self.record_table.table.selected_cells() {
254284
copy_to_clipboard(text.as_str())?
@@ -258,7 +288,10 @@ impl App {
258288
if key == self.config.key_config.enter && self.record_table.filter_focused()
259289
{
260290
self.record_table.focus = crate::components::record_table::Focus::Table;
261-
self.update_record_table().await?;
291+
let order_query = self.record_table.table.generate_order_query();
292+
let header_icons = self.record_table.table.generate_header_icons();
293+
self.update_record_table(order_query, Some(header_icons), false)
294+
.await?;
262295
}
263296

264297
if self.record_table.table.eod {
@@ -283,6 +316,7 @@ impl App {
283316
} else {
284317
Some(self.record_table.filter.input_str())
285318
},
319+
None,
286320
)
287321
.await?;
288322
if !records.is_empty() {
@@ -321,6 +355,24 @@ impl App {
321355
Ok(EventState::NotConsumed)
322356
}
323357

358+
fn concat_headers(
359+
&self,
360+
headers: Vec<String>,
361+
header_icons: Option<Vec<String>>,
362+
) -> Vec<String> {
363+
if let Some(header_icons) = &header_icons {
364+
let mut new_headers = vec![String::new(); headers.len()];
365+
for (index, header) in headers.iter().enumerate() {
366+
new_headers[index] = format!("{} {}", header, header_icons[index])
367+
.trim()
368+
.to_string();
369+
}
370+
return new_headers;
371+
}
372+
373+
headers
374+
}
375+
324376
fn extend_or_shorten_widget_width(&mut self, key: Key) -> anyhow::Result<EventState> {
325377
if key
326378
== self
@@ -408,4 +460,25 @@ mod test {
408460
);
409461
assert_eq!(app.left_main_chunk_percentage, 15);
410462
}
463+
464+
#[test]
465+
fn test_concat_headers() {
466+
let app = App::new(Config::default());
467+
let headers = vec![
468+
"ID".to_string(),
469+
"NAME".to_string(),
470+
"TIMESTAMP".to_string(),
471+
];
472+
let header_icons = vec!["".to_string(), "↑1".to_string(), "↓2".to_string()];
473+
let concat_headers: Vec<String> = app.concat_headers(headers, Some(header_icons));
474+
475+
assert_eq!(
476+
concat_headers,
477+
vec![
478+
"ID".to_string(),
479+
"NAME ↑1".to_string(),
480+
"TIMESTAMP ↓2".to_string()
481+
]
482+
)
483+
}
411484
}

0 commit comments

Comments
 (0)