diff options
| author | littleblack111 <littleblack11111@gmail.com> | 2026-07-27 14:46:32 +0800 |
|---|---|---|
| committer | littleblack111 <littleblack11111@gmail.com> | 2026-07-27 14:57:41 +0800 |
| commit | 90df3a1a8738d61f747c50f26359ccabf0c7b229 (patch) | |
| tree | 8df5a8ce0bef4f7cb831ba517ac54969c46fbe19 | |
| parent | 1f9873b40fee2d33c5b7103a25077ec61a387063 (diff) | |
new: more advanced math via kalk
refactor(components): optimizations and simplify
| -rw-r--r-- | config/Launcher.qml | 12 | ||||
| -rw-r--r-- | popups/launcher/components/App.qml | 13 | ||||
| -rw-r--r-- | popups/launcher/components/Calc.qml | 16 | ||||
| -rw-r--r-- | popups/launcher/components/DateTime.qml (renamed from popups/launcher/components/Date.qml) | 0 | ||||
| -rw-r--r-- | popups/launcher/components/ISmartCalc.qml | 14 | ||||
| -rw-r--r-- | popups/launcher/components/SelectionState.qml | 2 | ||||
| -rw-r--r-- | qml_plugin/Cargo.lock | 45 | ||||
| -rw-r--r-- | qml_plugin/Cargo.toml | 1 | ||||
| -rw-r--r-- | qml_plugin/build.rs | 7 | ||||
| -rw-r--r-- | qml_plugin/src/launcher.rs | 1 | ||||
| -rw-r--r-- | qml_plugin/src/launcher/mathcalc.rs | 111 |
11 files changed, 196 insertions, 26 deletions
diff --git a/config/Launcher.qml b/config/Launcher.qml index a1cb193..11a2b6e 100644 --- a/config/Launcher.qml +++ b/config/Launcher.qml @@ -31,6 +31,10 @@ Singleton { readonly property int predictiveCompletionRadius: 6 readonly property list<Component> widgets: [ + // recommanded order: + // 1. components with .startswith + // 2. utils + // 3. app launcher Component { Emoji {} }, @@ -41,16 +45,16 @@ Singleton { Spell {} }, Component { - App {} - }, - Component { Calc {} }, Component { - Date {} + DateTime {} }, Component { Unit {} }, + Component { + App {} + }, ] } diff --git a/popups/launcher/components/App.qml b/popups/launcher/components/App.qml index e90bea1..f9c63e3 100644 --- a/popups/launcher/components/App.qml +++ b/popups/launcher/components/App.qml @@ -10,7 +10,7 @@ import qs.config IComponent { id: root - property list<DesktopEntry> entries: active ? AppSearch.query(inputCleaned) : [] + property list<DesktopEntry> entries: AppSearch.query(inputCleaned) property int selectedIndex: -1 name: "Applications" @@ -25,14 +25,15 @@ IComponent { } } - property string predictiveCompletion: valid ? entries[selectedIndex]?.name.slice(input.length) || "" : "" + property string predictiveCompletion: entries[selectedIndex]?.name.slice(input.length) || "" process: function () { - const isValid = entries.length > 0; - const selected = isValid ? entries[selectedIndex] : ""; + const valid = entries.length > 0; + // TODO: consider removing the valid check + const selected = valid ? entries[selectedIndex] : ""; return { - valid: isValid, - priority: isValid, + valid, + priority: valid, answer: selected?.icon || "" }; } diff --git a/popups/launcher/components/Calc.qml b/popups/launcher/components/Calc.qml index c6cdbc1..4cc45a7 100644 --- a/popups/launcher/components/Calc.qml +++ b/popups/launcher/components/Calc.qml @@ -6,6 +6,8 @@ import qs.components import qs.services import qs.config +import core + IComponent { property int cursorPosition: SelectionState.cursorPosition @@ -17,17 +19,19 @@ IComponent { } process: function () { - const isValid = /^(?=.*\d)(?=.*[+\-*\/\^])[0-9+\-*\/\^().\s]+$/.test(input); - const answer = isValid ? String(eval(input.replace(/\^/g, '**').replace(/([\d)])\(/g, '$1*(').replace(/\)([\d])/g, ')*$1'))) : null; + MathCalc.query(input); + const valid = MathCalc.result && MathCalc.result.length > 0; + const answer = MathCalc.result; return { - valid: isValid, - priority: isValid, - answer: answer, - predictiveCompletion: isValid ? ' = ' + answer : '' + valid, + priority: valid, + answer, + predictiveCompletion: valid ? ' = ' + answer : '' }; } exec: function () { Clip.copy(answer); + MathCalc.reset_ctx(); } IInnerComponent { diff --git a/popups/launcher/components/Date.qml b/popups/launcher/components/DateTime.qml index 0929b75..0929b75 100644 --- a/popups/launcher/components/Date.qml +++ b/popups/launcher/components/DateTime.qml diff --git a/popups/launcher/components/ISmartCalc.qml b/popups/launcher/components/ISmartCalc.qml index 6e6381c..5474cc5 100644 --- a/popups/launcher/components/ISmartCalc.qml +++ b/popups/launcher/components/ISmartCalc.qml @@ -14,7 +14,6 @@ IComponent { required property string predictiveText property int cursorPosition: SelectionState.cursorPosition - property string answer: active && valid ? SmartCalc.result : "" preview: Component { Icon { @@ -24,13 +23,14 @@ IComponent { process: function () { SmartCalc.query(input); - const isValid = active && SmartCalc.result && SmartCalc.result.length > 0 && category; - const answer = isValid ? SmartCalc.result : ""; + const answer = SmartCalc.result; + // TODO: use answer property rn its circular dependent since it has to be valid which is the line below + const valid = SmartCalc.result && SmartCalc.result.length > 0 && category; return { - valid: isValid, - priority: isValid, - answer: answer, - predictiveCompletion: isValid ? ` ${predictiveText} ` + answer : '' + valid, + priority: valid, + answer, + predictiveCompletion: ` ${predictiveText} ` + answer }; } exec: function () { diff --git a/popups/launcher/components/SelectionState.qml b/popups/launcher/components/SelectionState.qml index 1ab577a..212bd1d 100644 --- a/popups/launcher/components/SelectionState.qml +++ b/popups/launcher/components/SelectionState.qml @@ -2,6 +2,8 @@ pragma Singleton import Quickshell import QtQuick +// FIXME: fix some selection not show/updated when deselected i.e. "pi" from app back to calc wont visually show deselection of last app +// FIXME: icon/answer not updated when changed to non first priority Singleton { id: root diff --git a/qml_plugin/Cargo.lock b/qml_plugin/Cargo.lock index b740b04..ee9fb39 100644 --- a/qml_plugin/Cargo.lock +++ b/qml_plugin/Cargo.lock @@ -79,6 +79,12 @@ dependencies = [ ] [[package]] +name = "az" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be5eb007b7cacc6c660343e96f650fedf4b5a77512399eb952ca6642cf8d13f7" + +[[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -462,9 +468,9 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "either" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" +checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" [[package]] name = "encoding_rs" @@ -593,6 +599,16 @@ dependencies = [ ] [[package]] +name = "gmp-mpfr-sys" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7db155b537cb791b133341f99f68371d86ee7fa4c79aacfbc376d72d23c70531" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] name = "h2" version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1289,6 +1305,18 @@ dependencies = [ ] [[package]] +name = "kalk" +version = "3.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6be3b5fe1fc1b007b90dbb151aa48d480efece8f813f975d53597aaa4df67003" +dependencies = [ + "gmp-mpfr-sys", + "lazy_static", + "rug", + "wasm-bindgen", +] + +[[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1481,6 +1509,7 @@ dependencies = [ "cxx-qt", "cxx-qt-build", "cxx-qt-lib", + "kalk", "smart-calculator", "tokio", ] @@ -1681,6 +1710,18 @@ dependencies = [ ] [[package]] +name = "rug" +version = "1.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07a8857882aec59d27254b02481c709327c13de6fad1da60bfc4f9783eaaa61e" +dependencies = [ + "az", + "gmp-mpfr-sys", + "libc", + "libm", +] + +[[package]] name = "rustc-hash" version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/qml_plugin/Cargo.toml b/qml_plugin/Cargo.toml index 9f9fa88..5ae6a1c 100644 --- a/qml_plugin/Cargo.toml +++ b/qml_plugin/Cargo.toml @@ -10,6 +10,7 @@ crate-type = ["cdylib"] cxx = "1.0.198" cxx-qt = "0.9.1" cxx-qt-lib = "0.9.1" +kalk = "3.2.3" smart-calculator = "1.0.3" tokio = { version = "1.53.1", features = ["rt-multi-thread", "macros"] } diff --git a/qml_plugin/build.rs b/qml_plugin/build.rs index 8a02b92..2c73418 100644 --- a/qml_plugin/build.rs +++ b/qml_plugin/build.rs @@ -13,6 +13,11 @@ fn main() { CxxQtBuilder::new_qml_module(QmlModule::new(NAME).plugin_type(PluginType::Dynamic)) .qt_module("Qml") - .files(["src/launcher/smartcalc.rs"]) + .files( + [ + "src/launcher/smartcalc.rs", + "src/launcher/mathcalc.rs", + ], + ) .build(); } diff --git a/qml_plugin/src/launcher.rs b/qml_plugin/src/launcher.rs index 8cb8676..4274840 100644 --- a/qml_plugin/src/launcher.rs +++ b/qml_plugin/src/launcher.rs @@ -1 +1,2 @@ +pub mod mathcalc; pub mod smartcalc; diff --git a/qml_plugin/src/launcher/mathcalc.rs b/qml_plugin/src/launcher/mathcalc.rs new file mode 100644 index 0000000..fd39ed1 --- /dev/null +++ b/qml_plugin/src/launcher/mathcalc.rs @@ -0,0 +1,111 @@ +use cxx_qt::{CxxQtType, Threading}; +use cxx_qt_lib::{QString, QVariant}; +use kalk::parser; +use std::{pin::Pin, sync::Arc}; +use tokio::sync::Mutex; + +use crate::RUNTIME; + +#[cxx_qt::bridge] +mod qobject { + extern "C++" { + include!("cxx-qt-lib/qstring.h"); + include!("cxx-qt-lib/qvariant.h"); + type QString = cxx_qt_lib::QString; + type QVariant = cxx_qt_lib::QVariant; + } + + extern "RustQt" { + #[qobject] + #[qml_element] + #[qml_singleton] + #[qproperty( + QVariant, result + )] + type MathCalc = super::MathCalcRs; + + #[qinvokable] + fn query(self: Pin<&mut MathCalc>, input: QString); + + #[qinvokable] + fn reset(self: Pin<&mut MathCalc>); + + #[qinvokable] + fn reset_ctx(self: Pin<&mut MathCalc>); + } + + impl cxx_qt::Threading for MathCalc {} +} + +#[derive(Default)] +pub struct MathCalcRs { + result: QVariant, + + ctx: Arc<Mutex<parser::Context>>, +} + +impl qobject::MathCalc { + fn query(self: Pin<&mut Self>, input: QString) { + let qt_thread = self.qt_thread(); + let ctx = Arc::clone( + &self + .rust_mut() + .ctx, + ); + // TODO: consider moving to spawn_blocking + RUNTIME.spawn( + async move { + let result = parser::eval( + &mut *ctx + .lock() + .await, + &input.to_string(), + // TODO: move to const/config + 53, + ); + qt_thread.queue( + |mut qo| { + qo.as_mut() + .set_result( + result.map_or_default( + |r| { + r.map_or_default( + |r| { + let result: QString = r + .to_string_big() + .into(); + QVariant::from(&result) + }, + ) + }, + ), /* match result { + * Ok(value) => { + * let result: QString = value + * .to_string() + * .into(); + * QVariant::from(&result) + * } + * // TODO: add some logging + * Err(_) => QVariant::default(), + * }, */ + ) + }, + ) + }, + ); + } + + fn reset(mut self: Pin<&mut Self>) { + self.as_mut() + .set_result(QVariant::default()); + self.as_mut() + .rust_mut() + .ctx = Arc::new(Mutex::new(parser::Context::default())); + } + + fn reset_ctx(mut self: Pin<&mut Self>) { + self.as_mut() + .rust_mut() + .ctx = Arc::new(Mutex::new(parser::Context::default())); + } +} |
