From da927eadb4435a651d358a5934c151fa23216b43 Mon Sep 17 00:00:00 2001 From: Spxg Date: Wed, 28 May 2025 23:22:28 +0800 Subject: [PATCH] Add embed query result tool --- crates/aceditor/src/lib.rs | 75 +++++++++++++++++ src/app/advanced_options_menu.rs | 14 ++-- src/app/header.rs | 135 ++++++++++++++++++------------- src/app/output/execute.rs | 54 +++++++------ src/app/output/share.rs | 46 ----------- src/app/playground.rs | 60 +++++++++++++- src/app/pop_button.rs | 5 +- src/app/state.rs | 8 +- src/app/tools_menu.rs | 41 +++------- src/bin/worker.rs | 8 +- src/lib.rs | 38 ++++----- src/worker/mod.rs | 126 +++++------------------------ src/worker/sqlitend.rs | 10 +-- 13 files changed, 308 insertions(+), 312 deletions(-) diff --git a/crates/aceditor/src/lib.rs b/crates/aceditor/src/lib.rs index 608ded1..638535e 100644 --- a/crates/aceditor/src/lib.rs +++ b/crates/aceditor/src/lib.rs @@ -28,11 +28,49 @@ mod bindgen { #[wasm_bindgen(method, js_name = getValue)] pub fn get_value(this: &Editor) -> String; + #[wasm_bindgen(method, js_name = clearSelection)] + pub fn clear_selection(this: &Editor); + #[wasm_bindgen(method, js_name = setValue)] pub fn set_value(this: &Editor, value: String); + #[wasm_bindgen(method, js_name = getSession)] + pub fn get_session(this: &Editor) -> EditSession; + + #[wasm_bindgen(method, js_name = getSelection)] + pub fn get_selection(this: &Editor) -> Selection; + #[wasm_bindgen(method, js_name = getSelectedText)] pub fn get_selected_text(this: &Editor) -> String; + + #[wasm_bindgen(method, js_name = setReadOnly)] + pub fn set_read_only(this: &Editor, value: bool); + } + + #[wasm_bindgen] + extern "C" { + pub type Selection; + + #[wasm_bindgen(method, js_name = getRange)] + pub fn get_range(this: &Selection) -> JsValue; + } + + #[wasm_bindgen] + extern "C" { + pub type EditSession; + + #[wasm_bindgen(method, js_name = setValue)] + pub fn set_value(this: &EditSession, value: String); + + #[wasm_bindgen(method, js_name = getLength)] + pub fn get_length(this: &EditSession) -> usize; + + #[wasm_bindgen(method, js_name = getTextRange)] + pub fn get_text_range(this: &EditSession, range: JsValue) -> String; + + #[wasm_bindgen(method, js_name = getLine)] + pub fn get_line(this: &EditSession, row: usize) -> String; + } #[wasm_bindgen] @@ -81,6 +119,20 @@ impl EditorOptionsBuilder { } } +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Range { + pub start: Point, + pub end: Point, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Point { + pub row: usize, + pub column: usize, +} + #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct EditorOptions { @@ -206,9 +258,32 @@ impl Editor { pub fn set_value(&self, value: String) { self.js.set_value(value); + self.js.clear_selection(); + } + + pub fn get_range(&self) -> Range { + serde_wasm_bindgen::from_value(self.js.get_selection().get_range()).unwrap() } pub fn get_selected_value(&self) -> String { self.js.get_selected_text() } + + pub fn set_read_only(&self, value: bool) { + self.js.set_read_only(value); + } + + pub fn get_length(&self) -> usize { + self.js.get_session().get_length() + } + + pub fn get_line(&self, row: usize) -> String { + self.js.get_session().get_line(row) + } + + pub fn get_text_range(&self, range: Range) -> String { + self.js + .get_session() + .get_text_range(serde_wasm_bindgen::to_value(&range).unwrap()) + } } diff --git a/src/app/advanced_options_menu.rs b/src/app/advanced_options_menu.rs index e83a20c..67d30f9 100644 --- a/src/app/advanced_options_menu.rs +++ b/src/app/advanced_options_menu.rs @@ -9,12 +9,6 @@ use crate::app::{ pub fn AdvancedOptionsMenu() -> impl IntoView { let state = expect_context::>(); - let value = move || *state.run_selected_sql().read(); - let is_default = move || !*state.run_selected_sql().read(); - let on_change = move |value: &bool| { - state.run_selected_sql().set(*value); - }; - view! { <> @@ -25,9 +19,11 @@ pub fn AdvancedOptionsMenu() -> impl IntoView { b=false a_label=Some("On".to_string()) b_label=Some("Off".to_string()) - value=value - is_default=Box::new(is_default) - on_change=on_change + value=move || *state.run_selected_sql().read() + is_default=Box::new(move || !*state.run_selected_sql().read()) + on_change=move |value: &bool| { + state.run_selected_sql().set(*value); + } /> diff --git a/src/app/header.rs b/src/app/header.rs index fdfc900..0c61bc0 100644 --- a/src/app/header.rs +++ b/src/app/header.rs @@ -1,13 +1,12 @@ use istyles::istyles; use leptos::{html::Input, prelude::*, tachys::html}; -use prettytable::{Cell, Row, Table}; use reactive_stores::Store; +use sqlformat::{FormatOptions, QueryParams}; use wasm_bindgen::{JsCast, prelude::Closure}; use web_sys::{Blob, Event, FileReader, HtmlInputElement, MouseEvent, Url, UrlSearchParams}; use crate::{ - FragileComfirmed, LoadDbOptions, PrepareOptions, SQLightError, SQLiteStatementResult, - WorkerRequest, + FragileComfirmed, LoadDbOptions, RunOptions, SQLightError, WorkerRequest, app::{ ImportProgress, advanced_options_menu::AdvancedOptionsMenu, @@ -76,31 +75,31 @@ pub fn Header() -> impl IntoView { pub fn execute(state: Store) -> Box { Box::new(move || { - let Some((code, selected_code)) = state - .editor() - .read_untracked() - .as_ref() - .map(|editor| (editor.get_value(), editor.get_selected_value())) - else { + let editor_guard = state.editor().read_untracked(); + let Some(editor) = editor_guard.as_ref() else { return; }; - let run_selected_code = state.run_selected_sql().get(); + let (code, selected_code) = (editor.get_value(), editor.get_selected_value()); + + drop(editor_guard); state.sql().set(code.clone()); change_focus(state, Some(Focus::Execute)); - std::mem::take(&mut *state.output().write()); + + let run_selected_code = + !selected_code.is_empty() && state.run_selected_sql().get_untracked(); if let Some(worker) = &*state.worker().read_untracked() { - worker.send_task(WorkerRequest::Prepare(PrepareOptions { - sql: if !selected_code.is_empty() && run_selected_code { + worker.send_task(WorkerRequest::Run(RunOptions { + embed: false, + sql: if run_selected_code { selected_code } else { code }, clear_on_prepare: !*state.keep_ctx().read_untracked(), })); - worker.send_task(WorkerRequest::Continue); } }) } @@ -209,6 +208,8 @@ fn AdvancedOptionsMenuButton(menu_container: NodeRef) -> imp #[component] fn ToolsButton(menu_container: NodeRef) -> impl IntoView { + let state = expect_context::>(); + let button = |toggle, node_ref| { view! {