1+ use crate :: extension:: ExtensionSettings ;
12use serde:: { Deserialize , Serialize } ;
23use std:: collections:: HashMap ;
34use tauri:: AppHandle ;
@@ -30,17 +31,40 @@ pub struct EditorInfo {
3031 pub timestamp : Option < String > ,
3132}
3233
33- /// Defines the action that would be performed when a document gets opened.
34+ /// Defines the action that would be performed when a [document](Document) gets opened.
35+ ///
36+ /// "Document" is a uniform type that the backend uses to send the search results
37+ /// back to the frontend. Since Coco can search many sources, "Document" can
38+ /// represent different things, application, web page, local file, extensions, and
39+ /// so on. Each has its own specific open action.
3440#[ derive( Debug , Clone , Serialize , Deserialize ) ]
3541pub ( crate ) enum OnOpened {
3642 /// Launch the application
3743 Application { app_path : String } ,
3844 /// Open the URL.
3945 Document { url : String } ,
46+ /// The document is an extension.
47+ Extension ( ExtensionOnOpened ) ,
48+ }
49+
50+ #[ derive( Debug , Clone , Serialize , Deserialize ) ]
51+ pub ( crate ) struct ExtensionOnOpened {
52+ /// Different types of extensions have different open behaviors.
53+ pub ( crate ) ty : ExtensionOnOpenedType ,
54+ /// Extensions settings. Some could affect open action.
55+ ///
56+ /// Optional because not all extensions have their settings.
57+ pub ( crate ) settings : Option < ExtensionSettings > ,
58+ }
59+
60+ #[ derive( Debug , Clone , Serialize , Deserialize ) ]
61+ pub ( crate ) enum ExtensionOnOpenedType {
4062 /// Spawn a child process to run the `CommandAction`.
4163 Command {
4264 action : crate :: extension:: CommandAction ,
4365 } ,
66+ /// Open the `link`.
67+ //
4468 // NOTE that this variant has the same definition as `struct Quicklink`, but we
4569 // cannot use it directly, its `link` field should be deserialized/serialized
4670 // from/to a string, but we need a JSON object here.
@@ -57,20 +81,24 @@ impl OnOpened {
5781 match self {
5882 Self :: Application { app_path } => app_path. clone ( ) ,
5983 Self :: Document { url } => url. clone ( ) ,
60- Self :: Command { action } => {
61- const WHITESPACE : & str = " " ;
62- let mut ret = action. exec . clone ( ) ;
63- ret. push_str ( WHITESPACE ) ;
64- if let Some ( ref args) = action. args {
65- ret. push_str ( args. join ( WHITESPACE ) . as_str ( ) ) ;
84+ Self :: Extension ( ext_on_opened) => {
85+ match & ext_on_opened. ty {
86+ ExtensionOnOpenedType :: Command { action } => {
87+ const WHITESPACE : & str = " " ;
88+ let mut ret = action. exec . clone ( ) ;
89+ ret. push_str ( WHITESPACE ) ;
90+ if let Some ( ref args) = action. args {
91+ ret. push_str ( args. join ( WHITESPACE ) . as_str ( ) ) ;
92+ }
93+
94+ ret
95+ }
96+ // Currently, our URL is static and does not support dynamic parameters.
97+ // The URL of a quicklink is nearly useless without such dynamic user
98+ // inputs, so until we have dynamic URL support, we just use "N/A".
99+ ExtensionOnOpenedType :: Quicklink { .. } => String :: from ( "N/A" ) ,
66100 }
67-
68- ret
69101 }
70- // Currently, our URL is static and does not support dynamic parameters.
71- // The URL of a quicklink is nearly useless without such dynamic user
72- // inputs, so until we have dynamic URL support, we just use "N/A".
73- Self :: Quicklink { .. } => String :: from ( "N/A" ) ,
74102 }
75103 }
76104}
@@ -95,65 +123,78 @@ pub(crate) async fn open(
95123
96124 homemade_tauri_shell_open ( tauri_app_handle. clone ( ) , url) . await ?
97125 }
98- OnOpened :: Command { action } => {
99- log:: debug!( "open (execute) command [{:?}]" , action) ;
100-
101- let mut cmd = Command :: new ( action. exec ) ;
102- if let Some ( args) = action. args {
103- cmd. args ( args) ;
104- }
105- let output = cmd. output ( ) . map_err ( |e| e. to_string ( ) ) ?;
106- // Sometimes, we wanna see the result in logs even though it doesn't fail.
107- log:: debug!(
108- "executing open(Command) result, exit code: [{}], stdout: [{}], stderr: [{}]" ,
109- output. status,
110- String :: from_utf8_lossy( & output. stdout) ,
111- String :: from_utf8_lossy( & output. stderr)
112- ) ;
113- if !output. status . success ( ) {
114- log:: warn!(
115- "executing open(Command) failed, exit code: [{}], stdout: [{}], stderr: [{}]" ,
116- output. status,
117- String :: from_utf8_lossy( & output. stdout) ,
118- String :: from_utf8_lossy( & output. stderr)
119- ) ;
120-
121- return Err ( format ! (
122- "Command failed, stderr [{}]" ,
123- String :: from_utf8_lossy( & output. stderr)
124- ) ) ;
125- }
126- }
127- OnOpened :: Quicklink {
128- link,
129- open_with : opt_open_with,
130- } => {
131- let url = link. concatenate_url ( & extra_args) ;
132-
133- log:: debug!( "open quicklink [{}] with [{:?}]" , url, opt_open_with) ;
134-
135- cfg_if:: cfg_if! {
136- // The `open_with` functionality is only supported on macOS, provided
137- // by the `open -a` command.
138- if #[ cfg( target_os = "macos" ) ] {
139- let mut cmd = Command :: new( "open" ) ;
140- if let Some ( ref open_with) = opt_open_with {
141- cmd. arg( "-a" ) ;
142- cmd. arg( open_with. as_str( ) ) ;
126+ OnOpened :: Extension ( ext_on_opened) => {
127+ // Apply the settings that would affect open behavior
128+ if let Some ( settings) = ext_on_opened. settings {
129+ if let Some ( should_hide) = settings. hide_before_open {
130+ if should_hide {
131+ crate :: hide_coco ( tauri_app_handle. clone ( ) ) . await ;
143132 }
144- cmd. arg( & url) ;
133+ }
134+ }
145135
146- let output = cmd. output( ) . map_err( |e| format!( "failed to spawn [open] due to error [{}]" , e) ) ?;
136+ match ext_on_opened. ty {
137+ ExtensionOnOpenedType :: Command { action } => {
138+ log:: debug!( "open (execute) command [{:?}]" , action) ;
147139
148- if !output. status. success( ) {
149- return Err ( format!(
150- "failed to open with app {:?}: {}" ,
151- opt_open_with,
140+ let mut cmd = Command :: new ( action. exec ) ;
141+ if let Some ( args) = action. args {
142+ cmd. args ( args) ;
143+ }
144+ let output = cmd. output ( ) . map_err ( |e| e. to_string ( ) ) ?;
145+ // Sometimes, we wanna see the result in logs even though it doesn't fail.
146+ log:: debug!(
147+ "executing open(Command) result, exit code: [{}], stdout: [{}], stderr: [{}]" ,
148+ output. status,
149+ String :: from_utf8_lossy( & output. stdout) ,
152150 String :: from_utf8_lossy( & output. stderr)
153- ) ) ;
151+ ) ;
152+ if !output. status . success ( ) {
153+ log:: warn!(
154+ "executing open(Command) failed, exit code: [{}], stdout: [{}], stderr: [{}]" ,
155+ output. status,
156+ String :: from_utf8_lossy( & output. stdout) ,
157+ String :: from_utf8_lossy( & output. stderr)
158+ ) ;
159+
160+ return Err ( format ! (
161+ "Command failed, stderr [{}]" ,
162+ String :: from_utf8_lossy( & output. stderr)
163+ ) ) ;
164+ }
165+ }
166+ ExtensionOnOpenedType :: Quicklink {
167+ link,
168+ open_with : opt_open_with,
169+ } => {
170+ let url = link. concatenate_url ( & extra_args) ;
171+
172+ log:: debug!( "open quicklink [{}] with [{:?}]" , url, opt_open_with) ;
173+
174+ cfg_if:: cfg_if! {
175+ // The `open_with` functionality is only supported on macOS, provided
176+ // by the `open -a` command.
177+ if #[ cfg( target_os = "macos" ) ] {
178+ let mut cmd = Command :: new( "open" ) ;
179+ if let Some ( ref open_with) = opt_open_with {
180+ cmd. arg( "-a" ) ;
181+ cmd. arg( open_with. as_str( ) ) ;
182+ }
183+ cmd. arg( & url) ;
184+
185+ let output = cmd. output( ) . map_err( |e| format!( "failed to spawn [open] due to error [{}]" , e) ) ?;
186+
187+ if !output. status. success( ) {
188+ return Err ( format!(
189+ "failed to open with app {:?}: {}" ,
190+ opt_open_with,
191+ String :: from_utf8_lossy( & output. stderr)
192+ ) ) ;
193+ }
194+ } else {
195+ homemade_tauri_shell_open( tauri_app_handle. clone( ) , url) . await ?
196+ }
154197 }
155- } else {
156- homemade_tauri_shell_open( tauri_app_handle. clone( ) , url) . await ?
157198 }
158199 }
159200 }
0 commit comments