Skip to content

Commit

Permalink
More keybindings (datafusion-contrib#243)
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewmturner authored Nov 10, 2024
1 parent 0060fb2 commit bea9998
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 2 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ Editor for executing SQL with local DataFusion `SessionContext`.
- Editable
- Character keys to write queries
- Backspace / tab / enter work same as normal
- `Shift` + Up/Down/Left/Right => Select text
- `Alt` + `Enter` => execute query
- `esc` to exit Edit mode and go back to Normal mode
- DDL mode
- Not editable
Expand All @@ -257,6 +259,8 @@ Editor for executing SQL with local DataFusion `SessionContext`.
- Editable
- Character keys to write queries
- Backspace / tab / enter work same as normal
- `Shift` + Up/Down/Left/Right => Select text
- `Alt` + `Enter` => execute query
- `esc` to exit Edit mode and go back to Normal mode
#### FlightSQL Tab
Expand All @@ -273,6 +277,8 @@ Same interface as SQL tab but sends SQL queries to FlightSQL server.
- Edit mode
- Character keys to write queries
- Backspace / tab / enter work same as normal
- `Shift` + Up/Down/Left/Right => Select text
- `Alt` + `Enter` => execute query
- `esc` to exit Edit mode and go back to Normal mode
#### History Tab
Expand Down
11 changes: 11 additions & 0 deletions src/tui/handlers/flightsql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ pub fn editable_handler(app: &mut App, key: KeyEvent) {
(KeyCode::Right, KeyModifiers::ALT) => app.state.flightsql_tab.next_word(),
(KeyCode::Backspace, KeyModifiers::ALT) => app.state.flightsql_tab.delete_word(),
(KeyCode::Esc, _) => app.state.flightsql_tab.exit_edit(),
(KeyCode::Enter, KeyModifiers::ALT) => {
// TODO: Encapsulate this logic
let sql = app.state.sql_tab.sql();
info!("Running query: {}", sql);
let _event_tx = app.event_tx().clone();
let execution = Arc::clone(&app.execution);
let sqls: Vec<String> = sql.split(';').map(|s| s.to_string()).collect();
let handle = tokio::spawn(execution.run_sqls(sqls, _event_tx));
app.state.sql_tab.set_execution_task(handle);
}

_ => app.state.flightsql_tab.update_editor_content(key),
}
}
Expand Down
23 changes: 23 additions & 0 deletions src/tui/handlers/sql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,29 @@ pub fn editable_handler(app: &mut App, key: KeyEvent) {
(KeyCode::Right, KeyModifiers::ALT) => app.state.sql_tab.next_word(),
(KeyCode::Backspace, KeyModifiers::ALT) => app.state.sql_tab.delete_word(),
(KeyCode::Esc, _) => app.state.sql_tab.exit_edit(),
(KeyCode::Enter, KeyModifiers::ALT) => {
match app.state.sql_tab.mode() {
// TODO: Encapsulate this logic
SQLTabMode::Normal => {
let sql = app.state.sql_tab.sql();
info!("Running query: {}", sql);
let _event_tx = app.event_tx().clone();
let execution = Arc::clone(&app.execution);
let sqls: Vec<String> = sql.split(';').map(|s| s.to_string()).collect();
let handle = tokio::spawn(execution.run_sqls(sqls, _event_tx));
app.state.sql_tab.set_execution_task(handle);
}
SQLTabMode::DDL => {
let _event_tx = app.event_tx().clone();
// TODO: Probably want this to load from Editor instead of the file so that
// it is the latest content.
let ddl = app.execution.load_ddl().unwrap_or_default();
if let Err(e) = _event_tx.send(AppEvent::ExecuteDDL(ddl)) {
error!("Error sending ExecuteDDL event: {:?}", e);
}
}
}
}
_ => app.state.sql_tab.update_editor_content(key),
}
}
Expand Down
32 changes: 31 additions & 1 deletion src/tui/state/tabs/flightsql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,38 @@ impl<'app> FlightSQLTabState<'app> {
}
}

/// Returns the SQL to be executed. If no text is selected it returns the entire buffer else
/// it returns the current selection.
pub fn sql(&self) -> String {
self.editor.lines().join("\n")
if let Some(((start_row, start_col), (end_row, end_col))) = self.editor.selection_range() {
if start_row == end_row {
let line = &self.editor.lines()[start_row];
line.chars()
.skip(start_col)
.take(end_col - start_col)
.collect()
} else {
let lines: Vec<String> = self
.editor
.lines()
.iter()
.enumerate()
.map(|(i, line)| {
let selected_chars: Vec<char> = if i == start_row {
line.chars().skip(start_col).collect()
} else if i == end_row {
line.chars().take(end_col).collect()
} else {
line.chars().collect()
};
selected_chars.into_iter().collect()
})
.collect();
lines.join("\n")
}
} else {
self.editor.lines().join("\n")
}
}
}

Expand Down
36 changes: 35 additions & 1 deletion src/tui/state/tabs/sql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,43 @@ impl<'app> SQLTabState<'app> {
self.mode = mode
}

/// Returns the SQL to be executed. If no text is selected it returns the entire buffer else
/// it returns the current selection. For DDL it returns the entire buffer.
pub fn sql(&self) -> String {
match self.mode {
SQLTabMode::Normal => self.editor.lines().join("\n"),
SQLTabMode::Normal => {
if let Some(((start_row, start_col), (end_row, end_col))) =
self.editor.selection_range()
{
if start_row == end_row {
let line = &self.editor.lines()[start_row];
line.chars()
.skip(start_col)
.take(end_col - start_col)
.collect()
} else {
let lines: Vec<String> = self
.editor
.lines()
.iter()
.enumerate()
.map(|(i, line)| {
let selected_chars: Vec<char> = if i == start_row {
line.chars().skip(start_col).collect()
} else if i == end_row {
line.chars().take(end_col).collect()
} else {
line.chars().collect()
};
selected_chars.into_iter().collect()
})
.collect();
lines.join("\n")
}
} else {
self.editor.lines().join("\n")
}
}
SQLTabMode::DDL => self.ddl_editor.lines().join("\n"),
}
}
Expand Down

0 comments on commit bea9998

Please sign in to comment.