1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
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
|
use {
super::*,
crate::{
app::*,
browser::BrowserState,
command::TriggerType,
display::Screen,
path,
selection_type::SelectionType,
task_sync::Dam,
tree::TreeOptions,
},
std::path::{Path, PathBuf},
};
pub fn on_path(
path: PathBuf,
screen: &mut Screen,
tree_options: TreeOptions,
in_new_panel: bool,
con: &AppContext,
) -> AppStateCmdResult {
if in_new_panel {
new_panel_on_path(path, screen, tree_options, PanelPurpose::None, con, HDir::Right)
} else {
new_state_on_path(path, screen, tree_options, con)
}
}
pub fn new_state_on_path(
path: PathBuf,
screen: &mut Screen,
tree_options: TreeOptions,
con: &AppContext,
) -> AppStateCmdResult {
let path = path::closest_dir(&path);
AppStateCmdResult::from_optional_state(
BrowserState::new(path, tree_options, screen, con, &Dam::unlimited()),
false,
)
}
pub fn new_panel_on_path(
path: PathBuf,
screen: &mut Screen,
tree_options: TreeOptions,
purpose: PanelPurpose,
con: &AppContext,
direction: HDir,
) -> AppStateCmdResult {
let path = path::closest_dir(&path);
match BrowserState::new(path, tree_options, screen, con, &Dam::unlimited()) {
Ok(Some(os)) => {
AppStateCmdResult::NewPanel {
state: Box::new(os),
purpose,
direction,
}
}
Ok(None) => AppStateCmdResult::Keep, // this isn't supposed to happen
Err(e) => AppStateCmdResult::DisplayError(e.to_string()),
}
}
/// general implementation for verbs based on the :focus internal with optionally
/// a bang or an argument.
pub fn on_internal(
internal_exec: &InternalExecution,
input_invocation: Option<&VerbInvocation>,
trigger_type: TriggerType,
selected_path: &Path,
screen: &mut Screen,
con: &AppContext,
tree_options: TreeOptions,
) -> AppStateCmdResult {
if let Some(arg) = &internal_exec.arg {
// the internal_execution specifies the path to use
// (it may come from a configured verb whose execution is
// `:focus some/path`).
// The given path may be relative hence the need for the
// state's selection
let path = path::path_from(selected_path, arg);
let bang = input_invocation
.map(|inv| inv.bang)
.unwrap_or(internal_exec.bang);
return on_path(path, screen, tree_options, bang, con);
}
if let Some(input_invocation) = &input_invocation {
if let Some(input_arg) = &input_invocation.args {
// user typed a path in the input
match trigger_type {
TriggerType::Input => {
// the :focus internal execution was triggered from the
// input (which must be a kind of alias for :focus)
// so we do exactly what the input asks for
let path = path::path_from(selected_path, input_arg);
let bang = input_invocation.bang || internal_exec.bang;
return on_path(path, screen, tree_options, bang, con);
}
_ => {
// the :focus internal was triggered by a key, which
// means the user wants to explore the arg with purpose
// of selecting a path
let base_dir = selected_path.to_string_lossy();
let path = path::path_from(&*base_dir, input_arg);
let arg_type = SelectionType::Any; // We might do better later
let purpose = PanelPurpose::ArgEdition { arg_type };
return new_panel_on_path(path, screen, tree_options, purpose, con, HDir::Right);
}
}
}
}
// user only wants to open the selected path, either in the same panel or
// in a new one
let bang = input_invocation
.map(|inv| inv.bang)
.unwrap_or(internal_exec.bang);
on_path(selected_path.to_path_buf(), screen, tree_options, bang, con)
}
|