55//!
66//! Selecting the hit copies the calculated value to the system's clipboard.
77
8- use arboard :: Clipboard ;
8+ use abi_stable :: reexports :: SelfOps ;
99use gravel_ffi:: prelude:: * ;
1010use mexprp:: Answer ;
1111use serde:: Deserialize ;
12- use std:: cell:: OnceCell ;
13- use std:: sync:: { Arc , Mutex } ;
1412
1513const DEFAULT_CONFIG : & str = include_str ! ( concat!( env!( "CARGO_MANIFEST_DIR" ) , "/config.yml" ) ) ;
1614
1715struct CalculatorProvider {
1816 config : Config ,
19- clipboard : OnceCell < Option < Arc < Mutex < Clipboard > > > > ,
20- }
21-
22- impl CalculatorProvider {
23- fn get_clipboard ( & self ) -> Option < Arc < Mutex < Clipboard > > > {
24- self . clipboard . get_or_init ( create_clipboard) . clone ( )
25- }
2617}
2718
2819#[ gravel_provider( "calculator" ) ]
2920impl Provider for CalculatorProvider {
3021 fn new ( config : & PluginConfigAdapter < ' _ > ) -> Self {
3122 Self {
3223 config : config. get ( DEFAULT_CONFIG ) ,
33- clipboard : OnceCell :: new ( ) ,
3424 }
3525 }
3626
3727 fn query ( & self , query : & str ) -> ProviderResult {
3828 let query = query. trim ( ) ;
39- let result = eval ( query) ;
40-
41- let Some ( result) = result else {
42- return ProviderResult :: empty ( ) ;
43- } ;
4429
45- if query == result || matches ! ( query, "e" | "pi" | "i" ) {
46- return ProviderResult :: empty ( ) ;
47- }
48-
49- let clipboard = self . get_clipboard ( ) ;
30+ eval ( query)
31+ . filter ( |r| !query_was_const ( query, r) )
32+ . map ( |r| self . get_hit ( r) )
33+ . piped ( ProviderResult :: from_option)
34+ }
35+ }
5036
51- let hit = SimpleHit :: new ( result, self . config . subtitle . clone ( ) , move |hit, ctx| {
52- do_copy ( clipboard. clone ( ) , hit. title ( ) . as_str ( ) , ctx) ;
37+ impl CalculatorProvider {
38+ fn get_hit ( & self , result : String ) -> SimpleHit {
39+ SimpleHit :: new ( result, self . config . subtitle . clone ( ) , move |hit, ctx| {
40+ ctx. set_clipboard_text ( hit. title ( ) . to_string ( ) . into_c ( ) ) ;
41+ ctx. hide_frontend ( ) ;
5342 } )
5443 . with_secondary ( |hit, ctx| {
55- ctx. set_query ( hit. title ( ) . into_rust ( ) . to_owned ( ) . into_c ( ) ) ;
44+ ctx. set_query ( hit. title ( ) . as_str ( ) . to_owned ( ) . into_c ( ) ) ;
5645 } )
57- . with_score ( MAX_SCORE ) ;
58-
59- ProviderResult :: single ( hit)
46+ . with_score ( MAX_SCORE )
6047 }
6148}
6249
63- fn create_clipboard ( ) -> Option < Arc < Mutex < Clipboard > > > {
64- log:: trace!( "spawning clipboard instance" ) ;
65-
66- Clipboard :: new ( )
67- . inspect_err ( |e| log:: error!( "unable to initialize clipboard: {e}" ) )
68- . ok ( )
69- . map ( |c| Arc :: new ( Mutex :: new ( c) ) )
50+ // queries that do not require any calculation should be ignored
51+ fn query_was_const ( query : & str , result : & str ) -> bool {
52+ query == result || matches ! ( query, "e" | "pi" | "i" )
7053}
7154
7255fn eval ( expression : & str ) -> Option < String > {
@@ -78,22 +61,6 @@ fn eval(expression: &str) -> Option<String> {
7861 . map ( |r| round ( r, 10 ) . to_string ( ) )
7962}
8063
81- fn do_copy ( clipboard : Option < Arc < Mutex < Clipboard > > > , result : & str , context : RefDynHitActionContext < ' _ > ) {
82- let Some ( clipboard_mutex) = clipboard else {
83- return ;
84- } ;
85-
86- log:: debug!( "copying value to clipboard: {result}" ) ;
87-
88- let mut guard = clipboard_mutex. lock ( ) . expect ( "thread holding the mutex can't panic" ) ;
89- guard
90- . set_text ( result)
91- . inspect_err ( |e| log:: error!( "unable to set clipboard: {e}" ) )
92- . ok ( ) ;
93-
94- context. hide_frontend ( ) ;
95- }
96-
9764fn round ( number : f64 , precision : u32 ) -> f64 {
9865 let factor = 10_u64 . pow ( precision) as f64 ;
9966 ( number * factor) . round ( ) / factor
0 commit comments