Expand description
an unparsed sequence with its separator (which may be different from the one provided by local_separator())
Fields§
§raw: String
§separator: String
Implementations§
source§impl Sequence
impl Sequence
sourcepub fn local_separator() -> String
pub fn local_separator() -> String
return the separator to use to parse sequences.
sourcepub fn new<S: Into<String>>(raw: S, separator: Option<S>) -> Self
pub fn new<S: Into<String>>(raw: S, separator: Option<S>) -> Self
Examples found in repository?
src/net/message.rs (lines 42-45)
36 37 38 39 40 41 42 43 44 45 46 47 48
pub fn read<BR: BufRead>(r: &mut BR) -> Result<Self, NetError> {
// the first line gives the type of message
match read_line(r)?.as_ref() {
"CMD" => Ok(Self::Command(read_line(r)?)),
"GET_ROOT" => Ok(Self::GetRoot),
"ROOT" => Ok(Self::Root(read_line(r)?)),
"SEQ" => Ok(Self::Sequence(Sequence::new(
read_line(r)?,
Some(read_line(r)?),
))),
_ => Err(NetError::InvalidMessage),
}
}
More examples
src/conf/verb_conf.rs (line 118)
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)
}
sourcepub fn new_single(cmd: String) -> Self
pub fn new_single(cmd: String) -> Self
Examples found in repository?
src/net/server.rs (line 45)
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
pub fn new(
name: &str,
tx: Sender<Sequence>,
root: Arc<Mutex<PathBuf>>,
) -> Result<Self, NetError> {
let path = super::socket_file_path(name);
if fs::metadata(&path).is_ok() {
return Err(NetError::SocketNotAvailable { path });
}
let listener = UnixListener::bind(&path)?;
info!("listening on {}", &path);
// we use only one thread as we don't want to support long connections
thread::spawn(move || {
for stream in listener.incoming() {
match stream {
Ok(mut stream) => {
let mut br = BufReader::new(&stream);
if let Some(sequence) = match Message::read(&mut br) {
Ok(Message::Command(command)) => {
debug!("got single command {:?}", &command);
// we convert it to a sequence
Some(Sequence::new_single(command))
}
Ok(Message::GetRoot) => {
debug!("got get root query");
let root = root.lock().unwrap();
let answer = Message::Root(root.to_string_lossy().to_string());
match answer.write(&mut stream) {
Ok(()) => debug!("root path successfully returned"),
Err(e) => warn!("error while answering: {:?}", e),
}
None
}
Ok(Message::Sequence(sequence)) => {
debug!("got sequence {:?}", &sequence);
Some(sequence)
}
Ok(message) => {
debug!("got something not yet handled: {:?}", message);
None
}
Err(e) => {
warn!("Read error : {:?}", e);
None
}
} {
if let Err(e) = tx.send(sequence) {
warn!("error while sending {:?}", e);
return;
}
}
}
Err(e) => {
warn!("Stream error : {:?}", e);
}
}
}
});
Ok(Self { path })
}
sourcepub fn new_local(raw: String) -> Self
pub fn new_local(raw: String) -> Self
Examples found in repository?
src/cli/mod.rs (line 108)
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 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
pub fn run() -> Result<Option<Launchable>, ProgramError> {
// parse the launch arguments we got from cli
let args = Args::parse();
let mut must_quit = false;
if let Some(dir) = &args.write_default_conf {
write_default_conf_in(dir)?;
must_quit = true;
}
// read the install related arguments
let install_args = InstallLaunchArgs::from(&args)?;
// execute installation things required by launch args
if let Some(state) = install_args.set_install_state {
write_state(state)?;
must_quit = true;
}
if let Some(shell) = &install_args.print_shell_function {
ShellInstall::print(shell)?;
must_quit = true;
}
if must_quit {
return Ok(None);
}
// read the list of specific config files
let specific_conf: Option<Vec<PathBuf>> = args.conf
.as_ref()
.map(|s| s.split(';').map(PathBuf::from).collect());
// if we don't run on a specific config file, we check the
// configuration
if specific_conf.is_none() && install_args.install != Some(false) {
let mut shell_install = ShellInstall::new(install_args.install == Some(true));
shell_install.check()?;
if shell_install.should_quit {
return Ok(None);
}
}
// read the configuration file(s): either the standard one
// or the ones required by the launch args
let mut config = match &specific_conf {
Some(conf_paths) => {
let mut conf = Conf::default();
for path in conf_paths {
conf.read_file(path.to_path_buf())?;
}
conf
}
_ => time!(Conf::from_default_location())?,
};
debug!("config: {:#?}", &config);
// verb store is completed from the config file(s)
let verb_store = VerbStore::new(&mut config)?;
let mut context = AppContext::from(args, verb_store, &config)?;
#[cfg(unix)]
if let Some(server_name) = &context.launch_args.send {
use crate::{
command::Sequence,
net::{Client, Message},
};
let client = Client::new(server_name);
if let Some(seq) = &context.launch_args.cmd {
let message = Message::Sequence(Sequence::new_local(seq.to_string()));
client.send(&message)?;
} else if !context.launch_args.get_root {
let message = Message::Command(
format!(":focus {}", context.initial_root.to_string_lossy())
);
client.send(&message)?;
};
if context.launch_args.get_root {
client.send(&Message::GetRoot)?;
}
return Ok(None);
}
let mut w = display::writer();
let app = App::new(&context)?;
w.queue(EnterAlternateScreen)?;
w.queue(cursor::Hide)?;
if context.capture_mouse {
w.queue(EnableMouseCapture)?;
}
let r = app.run(&mut w, &mut context, &config);
if context.capture_mouse {
w.queue(DisableMouseCapture)?;
}
w.queue(cursor::Show)?;
w.queue(LeaveAlternateScreen)?;
w.flush()?;
r
}
More examples
src/app/app.rs (line 708)
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 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 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
pub fn run(
mut self,
w: &mut W,
con: &mut AppContext,
conf: &Conf,
) -> Result<Option<Launchable>, ProgramError> {
#[cfg(feature = "clipboard")]
{
// different systems have different clipboard capabilities
// and it may be useful to know which one we have
debug!("Clipboard backend: {:?}", terminal_clipboard::get_type());
}
// we listen for events in a separate thread so that we can go on listening
// when a long search is running, and interrupt it if needed
let event_source = EventSource::new()?;
let rx_events = event_source.receiver();
let mut dam = Dam::from(rx_events);
let skin = AppSkin::new(conf, con.launch_args.color == TriBool::No);
let mut app_state = AppState {
stage: Stage::default(),
root: con.initial_root.clone(),
other_panel_path: None,
};
self.screen.clear_bottom_right_char(w, &skin.focused)?;
if let Some(raw_sequence) = &con.launch_args.cmd {
self.tx_seqs
.send(Sequence::new_local(raw_sequence.to_string()))
.unwrap();
}
#[cfg(unix)]
let _server = con.launch_args.listen.as_ref()
.map(|server_name| {
let shared_root = Arc::new(Mutex::new(app_state.root.clone()));
let server = crate::net::Server::new(
server_name,
self.tx_seqs.clone(),
Arc::clone(&shared_root),
);
self.shared_root = Some(shared_root);
server
})
.transpose()?;
loop {
if !self.quitting {
self.display_panels(w, &skin, &app_state, con)?;
time!(
Info,
"pending_tasks",
self.do_pending_tasks(w, &skin, &mut dam, &mut app_state, con)?,
);
}
#[allow(unused_mut)]
match dam.next(&self.rx_seqs) {
Either::First(Some(event)) => {
info!("event: {:?}", &event);
let mut handled = false;
// app level handling
if let Some((x, y)) = event.as_click() {
if self.clicked_panel_index(x, y) != self.active_panel_idx {
// panel activation click
self.active_panel_idx = self.clicked_panel_index(x, y);
handled = true;
}
} else if let Event::Resize(mut width, mut height) = event.event {
// I don't know why but Crossterm seems to always report an
// understimated size on Windows
#[cfg(windows)]
{
width += 1;
height += 1;
}
self.screen.set_terminal_size(width, height, con);
Areas::resize_all(
self.panels.as_mut_slice(),
self.screen,
self.preview_panel.is_some(),
);
for panel in &mut self.panels {
panel.mut_state().refresh(self.screen, con);
}
handled = true;
}
// event handled by the panel
if !handled {
let cmd = self.mut_panel().add_event(w, event, &app_state, con)?;
debug!("command after add_event: {:?}", &cmd);
self.apply_command(w, cmd, &skin.focused, &mut app_state, con)?;
}
event_source.unblock(self.quitting);
}
Either::First(None) => {
// this is how we quit the application,
// when the input thread is properly closed
break;
}
Either::Second(Some(raw_sequence)) => {
debug!("got command sequence: {:?}", &raw_sequence);
for (input, arg_cmd) in raw_sequence.parse(con)? {
self.mut_panel().set_input_content(&input);
self.apply_command(w, arg_cmd, &skin.focused, &mut app_state, con)?;
if self.quitting {
// is that a 100% safe way of quitting ?
return Ok(self.launch_at_end.take());
} else {
self.display_panels(w, &skin, &app_state, con)?;
time!(
"sequence pending tasks",
self.do_pending_tasks(w, &skin, &mut dam, &mut app_state, con)?,
);
}
}
}
Either::Second(None) => {
warn!("I didn't expect a None to occur here");
}
}
}
Ok(self.launch_at_end.take())
}
sourcepub fn parse(
&self,
con: &AppContext
) -> Result<Vec<(String, Command)>, ProgramError>
pub fn parse(
&self,
con: &AppContext
) -> Result<Vec<(String, Command)>, ProgramError>
Examples found in repository?
src/app/app.rs (line 785)
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 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 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
pub fn run(
mut self,
w: &mut W,
con: &mut AppContext,
conf: &Conf,
) -> Result<Option<Launchable>, ProgramError> {
#[cfg(feature = "clipboard")]
{
// different systems have different clipboard capabilities
// and it may be useful to know which one we have
debug!("Clipboard backend: {:?}", terminal_clipboard::get_type());
}
// we listen for events in a separate thread so that we can go on listening
// when a long search is running, and interrupt it if needed
let event_source = EventSource::new()?;
let rx_events = event_source.receiver();
let mut dam = Dam::from(rx_events);
let skin = AppSkin::new(conf, con.launch_args.color == TriBool::No);
let mut app_state = AppState {
stage: Stage::default(),
root: con.initial_root.clone(),
other_panel_path: None,
};
self.screen.clear_bottom_right_char(w, &skin.focused)?;
if let Some(raw_sequence) = &con.launch_args.cmd {
self.tx_seqs
.send(Sequence::new_local(raw_sequence.to_string()))
.unwrap();
}
#[cfg(unix)]
let _server = con.launch_args.listen.as_ref()
.map(|server_name| {
let shared_root = Arc::new(Mutex::new(app_state.root.clone()));
let server = crate::net::Server::new(
server_name,
self.tx_seqs.clone(),
Arc::clone(&shared_root),
);
self.shared_root = Some(shared_root);
server
})
.transpose()?;
loop {
if !self.quitting {
self.display_panels(w, &skin, &app_state, con)?;
time!(
Info,
"pending_tasks",
self.do_pending_tasks(w, &skin, &mut dam, &mut app_state, con)?,
);
}
#[allow(unused_mut)]
match dam.next(&self.rx_seqs) {
Either::First(Some(event)) => {
info!("event: {:?}", &event);
let mut handled = false;
// app level handling
if let Some((x, y)) = event.as_click() {
if self.clicked_panel_index(x, y) != self.active_panel_idx {
// panel activation click
self.active_panel_idx = self.clicked_panel_index(x, y);
handled = true;
}
} else if let Event::Resize(mut width, mut height) = event.event {
// I don't know why but Crossterm seems to always report an
// understimated size on Windows
#[cfg(windows)]
{
width += 1;
height += 1;
}
self.screen.set_terminal_size(width, height, con);
Areas::resize_all(
self.panels.as_mut_slice(),
self.screen,
self.preview_panel.is_some(),
);
for panel in &mut self.panels {
panel.mut_state().refresh(self.screen, con);
}
handled = true;
}
// event handled by the panel
if !handled {
let cmd = self.mut_panel().add_event(w, event, &app_state, con)?;
debug!("command after add_event: {:?}", &cmd);
self.apply_command(w, cmd, &skin.focused, &mut app_state, con)?;
}
event_source.unblock(self.quitting);
}
Either::First(None) => {
// this is how we quit the application,
// when the input thread is properly closed
break;
}
Either::Second(Some(raw_sequence)) => {
debug!("got command sequence: {:?}", &raw_sequence);
for (input, arg_cmd) in raw_sequence.parse(con)? {
self.mut_panel().set_input_content(&input);
self.apply_command(w, arg_cmd, &skin.focused, &mut app_state, con)?;
if self.quitting {
// is that a 100% safe way of quitting ?
return Ok(self.launch_at_end.take());
} else {
self.display_panels(w, &skin, &app_state, con)?;
time!(
"sequence pending tasks",
self.do_pending_tasks(w, &skin, &mut dam, &mut app_state, con)?,
);
}
}
}
Either::Second(None) => {
warn!("I didn't expect a None to occur here");
}
}
}
Ok(self.launch_at_end.take())
}
sourcepub fn has_selection_group(&self) -> bool
pub fn has_selection_group(&self) -> bool
Examples found in repository?
src/verb/verb.rs (line 110)
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(),
})
}
sourcepub fn has_other_panel_group(&self) -> bool
pub fn has_other_panel_group(&self) -> bool
Examples found in repository?
src/verb/verb.rs (line 111)
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(),
})
}