Enum broot::verb::ExecPattern

source ·
pub enum ExecPattern {
    String(String),
    Array(Vec<String>),
}
Expand description

A pattern which can be expanded into an executable

Variants§

§

String(String)

§

Array(Vec<String>)

Implementations§

Examples found in repository?
src/conf/verb_conf.rs (line 73)
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
    pub fn make_verb(&self, previous_verbs: &[Verb]) -> Result<Verb, ConfError> {
        let vc = self;
        if vc.leave_broot == Some(false) && vc.from_shell == Some(true) {
            return Err(ConfError::InvalidVerbConf {
                details: "You can't simultaneously have leave_broot=false and from_shell=true".to_string(),
            });
        }
        let invocation = vc.invocation.clone().filter(|i| !i.is_empty());
        let internal = vc.internal.as_ref().filter(|i| !i.is_empty());
        let external = vc.external.as_ref().filter(|i| !i.is_empty());
        let cmd = vc.cmd.as_ref().filter(|i| !i.is_empty());
        let cmd_separator = vc.cmd_separator.as_ref().filter(|i| !i.is_empty());
        let execution = vc.execution.as_ref().filter(|i| !i.is_empty());
        let make_external_execution = |s| {
            let working_dir = match (vc.set_working_dir, &vc.working_dir) {
                (Some(false), _) => None,
                (_, Some(s)) => Some(s.clone()),
                (Some(true), None) => Some("{directory}".to_owned()),
                (None, None) => None,
            };
            ExternalExecution::new(
                s,
                ExternalExecutionMode::from_conf(vc.from_shell, vc.leave_broot),
            )
            .with_working_dir(working_dir)
        };
        let execution = match (execution, internal, external, cmd) {
            // old definition with "execution": we guess whether it's an internal or
            // an external
            (Some(ep), None, None, None) => {
                if let Some(internal_pattern) = ep.as_internal_pattern() {
                    if let Some(previous_verb) = previous_verbs.iter().find(|&v| v.has_name(internal_pattern)) {
                        previous_verb.execution.clone()
                    } else {
                        VerbExecution::Internal(InternalExecution::try_from(internal_pattern)?)
                    }
                } else {
                    VerbExecution::External(make_external_execution(ep.clone()))
                }
            }
            // "internal": the leading `:` or ` ` is optional
            (None, Some(s), None, None) => {
                VerbExecution::Internal(if s.starts_with(':') || s.starts_with(' ') {
                    InternalExecution::try_from(&s[1..])?
                } else {
                    InternalExecution::try_from(s)?
                })
            }
            // "external": it can be about any form
            (None, None, Some(ep), None) => {
                VerbExecution::External(make_external_execution(ep.clone()))
            }
            // "cmd": it's a sequence
            (None, None, None, Some(s)) => VerbExecution::Sequence(SequenceExecution {
                sequence: Sequence::new(s, cmd_separator),
            }),
            _ => {
                return Err(ConfError::InvalidVerbConf {
                    details: "You must define either internal, external or cmd".to_string(),
                });
            }
        };
        let description = vc
            .description
            .clone()
            .map(VerbDescription::from_text)
            .unwrap_or_else(|| VerbDescription::from_code(execution.to_string()));
        let mut verb = Verb::new(
            invocation.as_deref(),
            execution,
            description,
        )?;
        // we accept both key and keys. We merge both here
        let mut unchecked_keys = vc.keys.clone();
        if let Some(key) = &vc.key {
            unchecked_keys.push(key.clone());
        }
        let mut checked_keys = Vec::new();
        for key in &unchecked_keys {
            let key = crokey::parse(key)?;
            if keys::is_reserved(key) {
                return Err(ConfError::ReservedKey {
                    key: keys::KEY_FORMAT.to_string(key)
                });
            }
            checked_keys.push(key);
        }
        for extension in &self.extensions {
            verb.file_extensions.push(extension.clone());
        }
        if !checked_keys.is_empty() {
            verb.add_keys(checked_keys);
        }
        if let Some(shortcut) = &vc.shortcut {
            verb.names.push(shortcut.clone());
        }
        if vc.auto_exec == Some(false) {
            verb.auto_exec = false;
        }
        if !vc.panels.is_empty() {
            verb.panels = vc.panels.clone();
        }
        verb.selection_condition = match vc.apply_to.as_deref() {
            Some("file") => SelectionType::File,
            Some("directory") => SelectionType::Directory,
            Some("any") => SelectionType::Any,
            None => SelectionType::Any,
            Some(s) => {
                return Err(ConfError::InvalidVerbConf {
                    details: format!("{:?} isn't a valid value of apply_to", s),
                });
            }
        };
        Ok(verb)
    }
Examples found in repository?
src/verb/verb.rs (line 106)
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
    pub fn new(
        invocation_str: Option<&str>,
        execution: VerbExecution,
        description: VerbDescription,
    ) -> Result<Self, ConfError> {
        let invocation_parser = invocation_str.map(InvocationParser::new).transpose()?;
        let mut names = Vec::new();
        if let Some(ref invocation_parser) = invocation_parser {
            names.push(invocation_parser.name().to_string());
        }
        let (
            needs_selection,
            needs_another_panel,
        ) = match &execution {
            VerbExecution::Internal(ie) => (
                ie.needs_selection(),
                false,
            ),
            VerbExecution::External(ee) => (
                ee.exec_pattern.has_selection_group(),
                ee.exec_pattern.has_other_panel_group(),
            ),
            VerbExecution::Sequence(se) => (
                se.sequence.has_selection_group(),
                se.sequence.has_other_panel_group(),
            )
        };
        Ok(Self {
            names,
            keys: Vec::new(),
            keys_desc: "".to_string(),
            invocation_parser,
            execution,
            description,
            selection_condition: SelectionType::Any,
            file_extensions: Vec::new(),
            needs_selection,
            needs_another_panel,
            auto_exec: true,
            show_in_doc: true,
            panels: Vec::new(),
        })
    }
Examples found in repository?
src/verb/verb.rs (line 107)
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
    pub fn new(
        invocation_str: Option<&str>,
        execution: VerbExecution,
        description: VerbDescription,
    ) -> Result<Self, ConfError> {
        let invocation_parser = invocation_str.map(InvocationParser::new).transpose()?;
        let mut names = Vec::new();
        if let Some(ref invocation_parser) = invocation_parser {
            names.push(invocation_parser.name().to_string());
        }
        let (
            needs_selection,
            needs_another_panel,
        ) = match &execution {
            VerbExecution::Internal(ie) => (
                ie.needs_selection(),
                false,
            ),
            VerbExecution::External(ee) => (
                ee.exec_pattern.has_selection_group(),
                ee.exec_pattern.has_other_panel_group(),
            ),
            VerbExecution::Sequence(se) => (
                se.sequence.has_selection_group(),
                se.sequence.has_other_panel_group(),
            )
        };
        Ok(Self {
            names,
            keys: Vec::new(),
            keys_desc: "".to_string(),
            invocation_parser,
            execution,
            description,
            selection_condition: SelectionType::Any,
            file_extensions: Vec::new(),
            needs_selection,
            needs_another_panel,
            auto_exec: true,
            show_in_doc: true,
            panels: Vec::new(),
        })
    }
Examples found in repository?
src/conf/verb_conf.rs (line 94)
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
    pub fn make_verb(&self, previous_verbs: &[Verb]) -> Result<Verb, ConfError> {
        let vc = self;
        if vc.leave_broot == Some(false) && vc.from_shell == Some(true) {
            return Err(ConfError::InvalidVerbConf {
                details: "You can't simultaneously have leave_broot=false and from_shell=true".to_string(),
            });
        }
        let invocation = vc.invocation.clone().filter(|i| !i.is_empty());
        let internal = vc.internal.as_ref().filter(|i| !i.is_empty());
        let external = vc.external.as_ref().filter(|i| !i.is_empty());
        let cmd = vc.cmd.as_ref().filter(|i| !i.is_empty());
        let cmd_separator = vc.cmd_separator.as_ref().filter(|i| !i.is_empty());
        let execution = vc.execution.as_ref().filter(|i| !i.is_empty());
        let make_external_execution = |s| {
            let working_dir = match (vc.set_working_dir, &vc.working_dir) {
                (Some(false), _) => None,
                (_, Some(s)) => Some(s.clone()),
                (Some(true), None) => Some("{directory}".to_owned()),
                (None, None) => None,
            };
            ExternalExecution::new(
                s,
                ExternalExecutionMode::from_conf(vc.from_shell, vc.leave_broot),
            )
            .with_working_dir(working_dir)
        };
        let execution = match (execution, internal, external, cmd) {
            // old definition with "execution": we guess whether it's an internal or
            // an external
            (Some(ep), None, None, None) => {
                if let Some(internal_pattern) = ep.as_internal_pattern() {
                    if let Some(previous_verb) = previous_verbs.iter().find(|&v| v.has_name(internal_pattern)) {
                        previous_verb.execution.clone()
                    } else {
                        VerbExecution::Internal(InternalExecution::try_from(internal_pattern)?)
                    }
                } else {
                    VerbExecution::External(make_external_execution(ep.clone()))
                }
            }
            // "internal": the leading `:` or ` ` is optional
            (None, Some(s), None, None) => {
                VerbExecution::Internal(if s.starts_with(':') || s.starts_with(' ') {
                    InternalExecution::try_from(&s[1..])?
                } else {
                    InternalExecution::try_from(s)?
                })
            }
            // "external": it can be about any form
            (None, None, Some(ep), None) => {
                VerbExecution::External(make_external_execution(ep.clone()))
            }
            // "cmd": it's a sequence
            (None, None, None, Some(s)) => VerbExecution::Sequence(SequenceExecution {
                sequence: Sequence::new(s, cmd_separator),
            }),
            _ => {
                return Err(ConfError::InvalidVerbConf {
                    details: "You must define either internal, external or cmd".to_string(),
                });
            }
        };
        let description = vc
            .description
            .clone()
            .map(VerbDescription::from_text)
            .unwrap_or_else(|| VerbDescription::from_code(execution.to_string()));
        let mut verb = Verb::new(
            invocation.as_deref(),
            execution,
            description,
        )?;
        // we accept both key and keys. We merge both here
        let mut unchecked_keys = vc.keys.clone();
        if let Some(key) = &vc.key {
            unchecked_keys.push(key.clone());
        }
        let mut checked_keys = Vec::new();
        for key in &unchecked_keys {
            let key = crokey::parse(key)?;
            if keys::is_reserved(key) {
                return Err(ConfError::ReservedKey {
                    key: keys::KEY_FORMAT.to_string(key)
                });
            }
            checked_keys.push(key);
        }
        for extension in &self.extensions {
            verb.file_extensions.push(extension.clone());
        }
        if !checked_keys.is_empty() {
            verb.add_keys(checked_keys);
        }
        if let Some(shortcut) = &vc.shortcut {
            verb.names.push(shortcut.clone());
        }
        if vc.auto_exec == Some(false) {
            verb.auto_exec = false;
        }
        if !vc.panels.is_empty() {
            verb.panels = vc.panels.clone();
        }
        verb.selection_condition = match vc.apply_to.as_deref() {
            Some("file") => SelectionType::File,
            Some("directory") => SelectionType::Directory,
            Some("any") => SelectionType::Any,
            None => SelectionType::Any,
            Some(s) => {
                return Err(ConfError::InvalidVerbConf {
                    details: format!("{:?} isn't a valid value of apply_to", s),
                });
            }
        };
        Ok(verb)
    }
Examples found in repository?
src/verb/exec_pattern.rs (line 69)
68
69
70
    pub fn tokenize(self) -> Self {
        Self::Array(self.into_array())
    }
More examples
Hide additional examples
src/verb/execution_builder.rs (line 293)
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
    pub fn exec_token(
        &self,
        exec_pattern: &ExecPattern,
    ) -> Vec<String> {
        exec_pattern
            .apply(&|s| {
                GROUP.replace_all(
                    s,
                    |ec: &Captures<'_>| self.get_capture_replacement(ec),
                ).to_string()
            })
            .fix_paths()
            .into_array()
    }
    /// build a vec of tokens which can be passed to Command to
    /// launch an executable
    pub fn sel_exec_token(
        &self,
        exec_pattern: &ExecPattern,
        sel: Option<Selection<'_>>,
    ) -> Vec<String> {
        exec_pattern
            .apply(&|s| {
                GROUP.replace_all(
                    s,
                    |ec: &Captures<'_>| self.get_sel_capture_replacement(ec, sel),
                ).to_string()
            })
            .fix_paths()
            .into_array()
    }
Examples found in repository?
src/verb/builtin.rs (line 39)
33
34
35
36
37
38
39
40
41
42
43
44
45
46
fn external(
    invocation_str: &str,
    execution_str: &str,
    exec_mode: ExternalExecutionMode,
) -> Verb {
    let execution = VerbExecution::External(
        ExternalExecution::new(ExecPattern::from_string(execution_str), exec_mode)
    );
    Verb::new(
        Some(invocation_str),
        execution,
        VerbDescription::from_code(execution_str.to_string()),
    ).unwrap()
}
More examples
Hide additional examples
src/app/panel_state.rs (line 726)
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
    fn execute_sequence(
        &mut self,
        _w: &mut W,
        verb: &Verb,
        seq_ex: &SequenceExecution,
        invocation: Option<&VerbInvocation>,
        app_state: &mut AppState,
        _cc: &CmdContext,
    ) -> Result<CmdResult, ProgramError> {
        let sel_info = self.sel_info(app_state);
        if matches!(sel_info, SelInfo::More(_)) {
            // sequences would be hard to execute as the execution on a file can change the
            // state in too many ways (changing selection, focused panel, parent, unstage or
            // stage files, removing the staged paths, etc.)
            return Ok(CmdResult::error("sequences can't be executed on multiple selections"));
        }
        let exec_builder = ExecutionStringBuilder::with_invocation(
            &verb.invocation_parser,
            sel_info,
            app_state,
            if let Some(inv) = invocation {
                inv.args.as_ref()
            } else {
                None
            },
        );
        // TODO what follows is dangerous: if an inserted group value contains the separator,
        // the parsing will cut on this separator
        let sequence = Sequence {
            raw: exec_builder.shell_exec_string(&ExecPattern::from_string(&seq_ex.sequence.raw)),
            separator: seq_ex.sequence.separator.clone(),
        };
        Ok(CmdResult::ExecuteSequence { sequence })
    }
src/verb/verb.rs (line 260)
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
    pub fn get_status_markdown(
        &self,
        sel_info: SelInfo<'_>,
        app_state: &AppState,
        invocation: &VerbInvocation,
    ) -> String {
        let name = self.names.get(0).unwrap_or(&invocation.name);

        // there's one special case: the ̀ :focus` internal. As long
        // as no other internal takes args, and no other verb can
        // have an optional argument, I don't try to build a
        // generic behavior for internal optionally taking args and
        // thus I hardcode the test here.
        if let VerbExecution::Internal(internal_exec) = &self.execution {
            if internal_exec.internal == Internal::focus {
                return internal_focus::get_status_markdown(
                    self,
                    internal_exec,
                    sel_info,
                    invocation,
                    app_state,
                );
            }
        }

        let builder = || {
            ExecutionStringBuilder::with_invocation(
                &self.invocation_parser,
                sel_info,
                app_state,
                invocation.args.as_ref(),
            )
        };
        if let VerbExecution::Sequence(seq_ex) = &self.execution {
            let exec_desc = builder().shell_exec_string(
                &ExecPattern::from_string(&seq_ex.sequence.raw)
            );
            format!("Hit *enter* to **{}**: `{}`", name, &exec_desc)
        } else if let VerbExecution::External(external_exec) = &self.execution {
            let exec_desc = builder().shell_exec_string(&external_exec.exec_pattern);
            format!("Hit *enter* to **{}**: `{}`", name, &exec_desc)
        } else if self.description.code {
            format!("Hit *enter* to **{}**: `{}`", name, &self.description.content)
        } else {
            format!("Hit *enter* to **{}**: {}", name, &self.description.content)
        }
    }
Examples found in repository?
src/verb/execution_builder.rs (lines 252-257)
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
    pub fn shell_exec_string(
        &self,
        exec_pattern: &ExecPattern,
    ) -> String {
        exec_pattern
            .apply(&|s| {
                GROUP.replace_all(
                    s,
                    |ec: &Captures<'_>| self.get_capture_replacement(ec),
                ).to_string()
            })
            .fix_paths()
            .to_string()
    }
    /// build a shell compatible command, with escapings, for a specific
    /// selection (this is intended for execution on all selections of a
    /// stage)
    pub fn sel_shell_exec_string(
        &self,
        exec_pattern: &ExecPattern,
        sel: Option<Selection<'_>>,
    ) -> String {
        exec_pattern
            .apply(&|s| {
                GROUP.replace_all(
                    s,
                    |ec: &Captures<'_>| self.get_sel_capture_replacement(ec, sel),
                ).to_string()
            })
            .fix_paths()
            .to_string()
    }
    /// build a vec of tokens which can be passed to Command to
    /// launch an executable
    pub fn exec_token(
        &self,
        exec_pattern: &ExecPattern,
    ) -> Vec<String> {
        exec_pattern
            .apply(&|s| {
                GROUP.replace_all(
                    s,
                    |ec: &Captures<'_>| self.get_capture_replacement(ec),
                ).to_string()
            })
            .fix_paths()
            .into_array()
    }
    /// build a vec of tokens which can be passed to Command to
    /// launch an executable
    pub fn sel_exec_token(
        &self,
        exec_pattern: &ExecPattern,
        sel: Option<Selection<'_>>,
    ) -> Vec<String> {
        exec_pattern
            .apply(&|s| {
                GROUP.replace_all(
                    s,
                    |ec: &Captures<'_>| self.get_sel_capture_replacement(ec, sel),
                ).to_string()
            })
            .fix_paths()
            .into_array()
    }
Examples found in repository?
src/verb/execution_builder.rs (line 258)
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
    pub fn shell_exec_string(
        &self,
        exec_pattern: &ExecPattern,
    ) -> String {
        exec_pattern
            .apply(&|s| {
                GROUP.replace_all(
                    s,
                    |ec: &Captures<'_>| self.get_capture_replacement(ec),
                ).to_string()
            })
            .fix_paths()
            .to_string()
    }
    /// build a shell compatible command, with escapings, for a specific
    /// selection (this is intended for execution on all selections of a
    /// stage)
    pub fn sel_shell_exec_string(
        &self,
        exec_pattern: &ExecPattern,
        sel: Option<Selection<'_>>,
    ) -> String {
        exec_pattern
            .apply(&|s| {
                GROUP.replace_all(
                    s,
                    |ec: &Captures<'_>| self.get_sel_capture_replacement(ec, sel),
                ).to_string()
            })
            .fix_paths()
            .to_string()
    }
    /// build a vec of tokens which can be passed to Command to
    /// launch an executable
    pub fn exec_token(
        &self,
        exec_pattern: &ExecPattern,
    ) -> Vec<String> {
        exec_pattern
            .apply(&|s| {
                GROUP.replace_all(
                    s,
                    |ec: &Captures<'_>| self.get_capture_replacement(ec),
                ).to_string()
            })
            .fix_paths()
            .into_array()
    }
    /// build a vec of tokens which can be passed to Command to
    /// launch an executable
    pub fn sel_exec_token(
        &self,
        exec_pattern: &ExecPattern,
        sel: Option<Selection<'_>>,
    ) -> Vec<String> {
        exec_pattern
            .apply(&|s| {
                GROUP.replace_all(
                    s,
                    |ec: &Captures<'_>| self.get_sel_capture_replacement(ec, sel),
                ).to_string()
            })
            .fix_paths()
            .into_array()
    }

Trait Implementations§

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Deserialize this value from the given Serde deserializer. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Converts the given value to a String. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.