nu_command/path/
basename.rs1use super::PathSubcommandArguments;
2use nu_engine::command_prelude::*;
3use nu_protocol::engine::StateWorkingSet;
4use std::path::Path;
5
6struct Arguments {
7 replace: Option<Spanned<String>>,
8}
9
10impl PathSubcommandArguments for Arguments {}
11
12#[derive(Clone)]
13pub struct PathBasename;
14
15impl Command for PathBasename {
16 fn name(&self) -> &str {
17 "path basename"
18 }
19
20 fn signature(&self) -> Signature {
21 Signature::build("path basename")
22 .input_output_types(vec![
23 (Type::String, Type::String),
24 (
25 Type::List(Box::new(Type::String)),
26 Type::List(Box::new(Type::String)),
27 ),
28 ])
29 .named(
30 "replace",
31 SyntaxShape::String,
32 "Return original path with basename replaced by this string",
33 Some('r'),
34 )
35 .category(Category::Path)
36 }
37
38 fn description(&self) -> &str {
39 "Get the final component of a path."
40 }
41
42 fn is_const(&self) -> bool {
43 true
44 }
45
46 fn run(
47 &self,
48 engine_state: &EngineState,
49 stack: &mut Stack,
50 call: &Call,
51 input: PipelineData,
52 ) -> Result<PipelineData, ShellError> {
53 let head = call.head;
54 let args = Arguments {
55 replace: call.get_flag(engine_state, stack, "replace")?,
56 };
57
58 if matches!(input, PipelineData::Empty) {
60 return Err(ShellError::PipelineEmpty { dst_span: head });
61 }
62 input.map(
63 move |value| super::operate(&get_basename, &args, value, head),
64 engine_state.signals(),
65 )
66 }
67
68 fn run_const(
69 &self,
70 working_set: &StateWorkingSet,
71 call: &Call,
72 input: PipelineData,
73 ) -> Result<PipelineData, ShellError> {
74 let head = call.head;
75 let args = Arguments {
76 replace: call.get_flag_const(working_set, "replace")?,
77 };
78
79 if matches!(input, PipelineData::Empty) {
81 return Err(ShellError::PipelineEmpty { dst_span: head });
82 }
83 input.map(
84 move |value| super::operate(&get_basename, &args, value, head),
85 working_set.permanent().signals(),
86 )
87 }
88
89 #[cfg(windows)]
90 fn examples(&self) -> Vec<Example> {
91 vec![
92 Example {
93 description: "Get basename of a path",
94 example: "'C:\\Users\\joe\\test.txt' | path basename",
95 result: Some(Value::test_string("test.txt")),
96 },
97 Example {
98 description: "Get basename of a list of paths",
99 example: r"[ C:\Users\joe, C:\Users\doe ] | path basename",
100 result: Some(Value::test_list(vec![
101 Value::test_string("joe"),
102 Value::test_string("doe"),
103 ])),
104 },
105 Example {
106 description: "Replace basename of a path",
107 example: "'C:\\Users\\joe\\test.txt' | path basename --replace 'spam.png'",
108 result: Some(Value::test_string("C:\\Users\\joe\\spam.png")),
109 },
110 ]
111 }
112
113 #[cfg(not(windows))]
114 fn examples(&self) -> Vec<Example> {
115 vec![
116 Example {
117 description: "Get basename of a path",
118 example: "'/home/joe/test.txt' | path basename",
119 result: Some(Value::test_string("test.txt")),
120 },
121 Example {
122 description: "Get basename of a list of paths",
123 example: "[ /home/joe, /home/doe ] | path basename",
124 result: Some(Value::test_list(vec![
125 Value::test_string("joe"),
126 Value::test_string("doe"),
127 ])),
128 },
129 Example {
130 description: "Replace basename of a path",
131 example: "'/home/joe/test.txt' | path basename --replace 'spam.png'",
132 result: Some(Value::test_string("/home/joe/spam.png")),
133 },
134 ]
135 }
136}
137
138fn get_basename(path: &Path, span: Span, args: &Arguments) -> Value {
139 match &args.replace {
140 Some(r) => Value::string(path.with_file_name(r.item.clone()).to_string_lossy(), span),
141 None => Value::string(
142 match path.file_name() {
143 Some(n) => n.to_string_lossy(),
144 None => "".into(),
145 },
146 span,
147 ),
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn test_examples() {
157 use crate::test_examples;
158
159 test_examples(PathBasename {})
160 }
161}