mirror of
https://github.com/nushell/nushell.git
synced 2024-11-07 17:14:23 +01:00
Try again with math-like externals (#4629)
* Try again with math-like externals * clippy 1.59 * clippy 1.59 * clippy 1.59
This commit is contained in:
parent
2c9d8c4818
commit
3c62d27c28
@ -26,8 +26,7 @@ impl NuCompleter {
|
|||||||
fn external_command_completion(&self, prefix: &str) -> Vec<String> {
|
fn external_command_completion(&self, prefix: &str) -> Vec<String> {
|
||||||
let mut executables = vec![];
|
let mut executables = vec![];
|
||||||
|
|
||||||
let paths;
|
let paths = self.engine_state.env_vars.get("PATH");
|
||||||
paths = self.engine_state.env_vars.get("PATH");
|
|
||||||
|
|
||||||
if let Some(paths) = paths {
|
if let Some(paths) = paths {
|
||||||
if let Ok(paths) = paths.as_list() {
|
if let Ok(paths) = paths.as_list() {
|
||||||
@ -470,7 +469,7 @@ fn file_path_completion(
|
|||||||
) -> Vec<(nu_protocol::Span, String)> {
|
) -> Vec<(nu_protocol::Span, String)> {
|
||||||
use std::path::{is_separator, Path};
|
use std::path::{is_separator, Path};
|
||||||
|
|
||||||
let partial = partial.replace("\"", "");
|
let partial = partial.replace('\"', "");
|
||||||
|
|
||||||
let (base_dir_name, partial) = {
|
let (base_dir_name, partial) = {
|
||||||
// If partial is only a word we want to search in the current dir
|
// If partial is only a word we want to search in the current dir
|
||||||
|
@ -86,26 +86,26 @@ impl NushellPrompt {
|
|||||||
impl Prompt for NushellPrompt {
|
impl Prompt for NushellPrompt {
|
||||||
fn render_prompt_left(&self) -> Cow<str> {
|
fn render_prompt_left(&self) -> Cow<str> {
|
||||||
if let Some(prompt_string) = &self.left_prompt_string {
|
if let Some(prompt_string) = &self.left_prompt_string {
|
||||||
prompt_string.replace("\n", "\r\n").into()
|
prompt_string.replace('\n', "\r\n").into()
|
||||||
} else {
|
} else {
|
||||||
let default = DefaultPrompt::new();
|
let default = DefaultPrompt::new();
|
||||||
default
|
default
|
||||||
.render_prompt_left()
|
.render_prompt_left()
|
||||||
.to_string()
|
.to_string()
|
||||||
.replace("\n", "\r\n")
|
.replace('\n', "\r\n")
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_prompt_right(&self) -> Cow<str> {
|
fn render_prompt_right(&self) -> Cow<str> {
|
||||||
if let Some(prompt_string) = &self.right_prompt_string {
|
if let Some(prompt_string) = &self.right_prompt_string {
|
||||||
prompt_string.replace("\n", "\r\n").into()
|
prompt_string.replace('\n', "\r\n").into()
|
||||||
} else {
|
} else {
|
||||||
let default = DefaultPrompt::new();
|
let default = DefaultPrompt::new();
|
||||||
default
|
default
|
||||||
.render_prompt_right()
|
.render_prompt_right()
|
||||||
.to_string()
|
.to_string()
|
||||||
.replace("\n", "\r\n")
|
.replace('\n', "\r\n")
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,7 @@ fn convert_int(input: &Value, head: Span, radix: u32) -> Value {
|
|||||||
Value::Int { val, .. } => val.to_string(),
|
Value::Int { val, .. } => val.to_string(),
|
||||||
Value::String { val, .. } => {
|
Value::String { val, .. } => {
|
||||||
if val.starts_with("0x") || val.starts_with("0b") {
|
if val.starts_with("0x") || val.starts_with("0b") {
|
||||||
match int_from_string(&val.to_string(), head) {
|
match int_from_string(val, head) {
|
||||||
Ok(x) => return Value::Int { val: x, span: head },
|
Ok(x) => return Value::Int { val: x, span: head },
|
||||||
Err(e) => return Value::Error { error: e },
|
Err(e) => return Value::Error { error: e },
|
||||||
}
|
}
|
||||||
|
@ -451,7 +451,7 @@ fn html_value(value: Value, config: &Config) -> String {
|
|||||||
}
|
}
|
||||||
other => output_string.push_str(
|
other => output_string.push_str(
|
||||||
&htmlescape::encode_minimal(&other.into_abbreviated_string(config))
|
&htmlescape::encode_minimal(&other.into_abbreviated_string(config))
|
||||||
.replace("\n", "<br>"),
|
.replace('\n', "<br>"),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
output_string
|
output_string
|
||||||
|
@ -248,7 +248,7 @@ pub fn run_seq(
|
|||||||
};
|
};
|
||||||
let last = {
|
let last = {
|
||||||
let slice = &free[free.len() - 1][..];
|
let slice = &free[free.len() - 1][..];
|
||||||
padding = cmp::max(padding, slice.find('.').unwrap_or_else(|| slice.len()));
|
padding = cmp::max(padding, slice.find('.').unwrap_or(slice.len()));
|
||||||
match parse_float(slice) {
|
match parse_float(slice) {
|
||||||
Ok(n) => n,
|
Ok(n) => n,
|
||||||
Err(s) => {
|
Err(s) => {
|
||||||
|
@ -423,7 +423,7 @@ fn generate_ansi_code_list(
|
|||||||
let cols = vec!["name".into(), "short name".into(), "code".into()];
|
let cols = vec!["name".into(), "short name".into(), "code".into()];
|
||||||
let name: Value = Value::string(String::from(ansi_code.long_name), call_span);
|
let name: Value = Value::string(String::from(ansi_code.long_name), call_span);
|
||||||
let short_name = Value::string(ansi_code.short_name.unwrap_or(""), call_span);
|
let short_name = Value::string(ansi_code.short_name.unwrap_or(""), call_span);
|
||||||
let code_string = String::from(&ansi_code.code.replace("\u{1b}", ""));
|
let code_string = String::from(&ansi_code.code.replace('\u{1b}', ""));
|
||||||
let code = Value::string(code_string, call_span);
|
let code = Value::string(code_string, call_span);
|
||||||
let vals = vec![name, short_name, code];
|
let vals = vec![name, short_name, code];
|
||||||
Value::Record {
|
Value::Record {
|
||||||
|
@ -397,7 +397,7 @@ impl ExternalCommand {
|
|||||||
// Clean the args before we use them:
|
// Clean the args before we use them:
|
||||||
// https://stackoverflow.com/questions/1200235/how-to-pass-a-quoted-pipe-character-to-cmd-exe
|
// https://stackoverflow.com/questions/1200235/how-to-pass-a-quoted-pipe-character-to-cmd-exe
|
||||||
// cmd.exe needs to have a caret to escape a pipe
|
// cmd.exe needs to have a caret to escape a pipe
|
||||||
let arg = arg.item.replace("|", "^|");
|
let arg = arg.item.replace('|', "^|");
|
||||||
process.arg(&arg);
|
process.arg(&arg);
|
||||||
}
|
}
|
||||||
process
|
process
|
||||||
|
@ -928,7 +928,7 @@ where
|
|||||||
if f1.len() <= f2.len() + 1 {
|
if f1.len() <= f2.len() + 1 {
|
||||||
f1
|
f1
|
||||||
} else if !f2.contains("e-") {
|
} else if !f2.contains("e-") {
|
||||||
f2.replace("e", "e+")
|
f2.replace('e', "e+")
|
||||||
} else {
|
} else {
|
||||||
f2
|
f2
|
||||||
}
|
}
|
||||||
|
@ -2956,9 +2956,8 @@ pub fn parse_table_expression(
|
|||||||
{
|
{
|
||||||
match values.len().cmp(&table_headers.len()) {
|
match values.len().cmp(&table_headers.len()) {
|
||||||
std::cmp::Ordering::Less => {
|
std::cmp::Ordering::Less => {
|
||||||
error = error.or_else(|| {
|
error = error
|
||||||
Some(ParseError::MissingColumns(table_headers.len(), span))
|
.or(Some(ParseError::MissingColumns(table_headers.len(), span)))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
std::cmp::Ordering::Equal => {}
|
std::cmp::Ordering::Equal => {}
|
||||||
std::cmp::Ordering::Greater => {
|
std::cmp::Ordering::Greater => {
|
||||||
|
@ -259,7 +259,7 @@ impl PipelineData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Simplified flatmapper. For full iterator support use `.into_iter()` instead
|
/// Simplified flatmapper. For full iterator support use `.into_iter()` instead
|
||||||
pub fn flat_map<U, F>(
|
pub fn flat_map<U: 'static, F>(
|
||||||
self,
|
self,
|
||||||
mut f: F,
|
mut f: F,
|
||||||
ctrlc: Option<Arc<AtomicBool>>,
|
ctrlc: Option<Arc<AtomicBool>>,
|
||||||
@ -272,10 +272,10 @@ impl PipelineData {
|
|||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
PipelineData::Value(Value::List { vals, .. }, ..) => {
|
PipelineData::Value(Value::List { vals, .. }, ..) => {
|
||||||
Ok(vals.into_iter().map(f).flatten().into_pipeline_data(ctrlc))
|
Ok(vals.into_iter().flat_map(f).into_pipeline_data(ctrlc))
|
||||||
}
|
}
|
||||||
PipelineData::ListStream(stream, ..) => {
|
PipelineData::ListStream(stream, ..) => {
|
||||||
Ok(stream.map(f).flatten().into_pipeline_data(ctrlc))
|
Ok(stream.flat_map(f).into_pipeline_data(ctrlc))
|
||||||
}
|
}
|
||||||
PipelineData::RawStream(stream, ..) => {
|
PipelineData::RawStream(stream, ..) => {
|
||||||
let collected = stream.into_bytes()?;
|
let collected = stream.into_bytes()?;
|
||||||
@ -297,7 +297,7 @@ impl PipelineData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
PipelineData::Value(Value::Range { val, .. }, ..) => match val.into_range_iter() {
|
PipelineData::Value(Value::Range { val, .. }, ..) => match val.into_range_iter() {
|
||||||
Ok(iter) => Ok(iter.map(f).flatten().into_pipeline_data(ctrlc)),
|
Ok(iter) => Ok(iter.flat_map(f).into_pipeline_data(ctrlc)),
|
||||||
Err(error) => Err(error),
|
Err(error) => Err(error),
|
||||||
},
|
},
|
||||||
PipelineData::Value(v, ..) => Ok(f(v).into_iter().into_pipeline_data(ctrlc)),
|
PipelineData::Value(v, ..) => Ok(f(v).into_iter().into_pipeline_data(ctrlc)),
|
||||||
|
@ -2120,7 +2120,7 @@ fn format_filesize(num_bytes: i64, config: &Config) -> String {
|
|||||||
// Since get_locale() and Locale::from_name() don't always return the same items
|
// Since get_locale() and Locale::from_name() don't always return the same items
|
||||||
// we need to try and parse it to match. For instance, a valid locale is de_DE
|
// we need to try and parse it to match. For instance, a valid locale is de_DE
|
||||||
// however Locale::from_name() wants only de so we split and parse it out.
|
// however Locale::from_name() wants only de so we split and parse it out.
|
||||||
let locale_string = locale_string.replace("_", "-"); // en_AU -> en-AU
|
let locale_string = locale_string.replace('_', "-"); // en_AU -> en-AU
|
||||||
let locale = match Locale::from_name(&locale_string) {
|
let locale = match Locale::from_name(&locale_string) {
|
||||||
Ok(loc) => loc,
|
Ok(loc) => loc,
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -194,7 +194,7 @@ impl ProcessInfo {
|
|||||||
pub fn command(&self) -> String {
|
pub fn command(&self) -> String {
|
||||||
if let Ok(cmd) = &self.curr_proc.cmdline() {
|
if let Ok(cmd) = &self.curr_proc.cmdline() {
|
||||||
if !cmd.is_empty() {
|
if !cmd.is_empty() {
|
||||||
cmd.join(" ").replace("\n", " ").replace("\t", " ")
|
cmd.join(" ").replace('\n', " ").replace('\t', " ")
|
||||||
} else {
|
} else {
|
||||||
self.curr_proc.stat().comm.clone()
|
self.curr_proc.stat().comm.clone()
|
||||||
}
|
}
|
||||||
|
@ -324,12 +324,12 @@ impl ProcessInfo {
|
|||||||
pub fn command(&self) -> String {
|
pub fn command(&self) -> String {
|
||||||
if let Some(path) = &self.curr_path {
|
if let Some(path) = &self.curr_path {
|
||||||
if !path.cmd.is_empty() {
|
if !path.cmd.is_empty() {
|
||||||
path.cmd.join(" ").replace("\n", " ").replace("\t", " ")
|
path.cmd.join(" ").replace('\n', " ").replace('\t', " ")
|
||||||
} else {
|
} else {
|
||||||
String::from("")
|
String::new()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String::from("")
|
String::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +209,7 @@ pub fn collect_proc(interval: Duration, _with_thread: bool) -> Vec<ProcessInfo>
|
|||||||
name: None,
|
name: None,
|
||||||
domainname: None,
|
domainname: None,
|
||||||
});
|
});
|
||||||
let groups = groups.unwrap_or_else(Vec::new);
|
let groups = groups.unwrap_or_default();
|
||||||
let thread = thread.unwrap_or_default();
|
let thread = thread.unwrap_or_default();
|
||||||
|
|
||||||
let proc = ProcessInfo {
|
let proc = ProcessInfo {
|
||||||
|
@ -168,5 +168,5 @@ pub fn read_std(std: &[u8]) -> String {
|
|||||||
let out = String::from_utf8_lossy(std);
|
let out = String::from_utf8_lossy(std);
|
||||||
let out = out.lines().collect::<Vec<_>>().join("\n");
|
let out = out.lines().collect::<Vec<_>>().join("\n");
|
||||||
let out = out.replace("\r\n", "");
|
let out = out.replace("\r\n", "");
|
||||||
out.replace("\n", "")
|
out.replace('\n', "")
|
||||||
}
|
}
|
||||||
|
@ -157,5 +157,5 @@ fn read_std(std: &[u8]) -> Vec<u8> {
|
|||||||
let out = String::from_utf8_lossy(std);
|
let out = String::from_utf8_lossy(std);
|
||||||
let out = out.lines().collect::<Vec<_>>().join("\n");
|
let out = out.lines().collect::<Vec<_>>().join("\n");
|
||||||
let out = out.replace("\r\n", "");
|
let out = out.replace("\r\n", "");
|
||||||
out.replace("\n", "").into_bytes()
|
out.replace('\n', "").into_bytes()
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,6 @@ pub(crate) fn evaluate(
|
|||||||
// First, set up env vars as strings only
|
// First, set up env vars as strings only
|
||||||
gather_parent_env_vars(engine_state);
|
gather_parent_env_vars(engine_state);
|
||||||
|
|
||||||
// Make a note of the exceptions we see for externals that look like math expressions
|
|
||||||
let exceptions = crate::utils::external_exceptions();
|
|
||||||
engine_state.external_exceptions = exceptions;
|
|
||||||
|
|
||||||
// Run a command (or commands) given to us by the user
|
// Run a command (or commands) given to us by the user
|
||||||
let (block, delta) = {
|
let (block, delta) = {
|
||||||
let mut working_set = StateWorkingSet::new(engine_state);
|
let mut working_set = StateWorkingSet::new(engine_state);
|
||||||
@ -78,6 +74,10 @@ pub(crate) fn evaluate(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Make a note of the exceptions we see for externals that look like math expressions
|
||||||
|
let exceptions = crate::utils::external_exceptions(engine_state, &stack);
|
||||||
|
engine_state.external_exceptions = exceptions;
|
||||||
|
|
||||||
// Merge the delta in case env vars changed in the config
|
// Merge the delta in case env vars changed in the config
|
||||||
match nu_engine::env::current_dir(engine_state, &stack) {
|
match nu_engine::env::current_dir(engine_state, &stack) {
|
||||||
Ok(cwd) => {
|
Ok(cwd) => {
|
||||||
|
@ -22,10 +22,6 @@ pub(crate) fn evaluate(
|
|||||||
// First, set up env vars as strings only
|
// First, set up env vars as strings only
|
||||||
gather_parent_env_vars(engine_state);
|
gather_parent_env_vars(engine_state);
|
||||||
|
|
||||||
// Make a note of the exceptions we see for externals that look like math expressions
|
|
||||||
let exceptions = crate::utils::external_exceptions();
|
|
||||||
engine_state.external_exceptions = exceptions;
|
|
||||||
|
|
||||||
let mut stack = nu_protocol::engine::Stack::new();
|
let mut stack = nu_protocol::engine::Stack::new();
|
||||||
|
|
||||||
// Set up our initial config to start from
|
// Set up our initial config to start from
|
||||||
@ -45,6 +41,10 @@ pub(crate) fn evaluate(
|
|||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make a note of the exceptions we see for externals that look like math expressions
|
||||||
|
let exceptions = crate::utils::external_exceptions(engine_state, &stack);
|
||||||
|
engine_state.external_exceptions = exceptions;
|
||||||
|
|
||||||
let file = std::fs::read(&path).into_diagnostic()?;
|
let file = std::fs::read(&path).into_diagnostic()?;
|
||||||
|
|
||||||
let mut working_set = StateWorkingSet::new(engine_state);
|
let mut working_set = StateWorkingSet::new(engine_state);
|
||||||
|
10
src/repl.rs
10
src/repl.rs
@ -35,10 +35,6 @@ pub(crate) fn evaluate(
|
|||||||
// First, set up env vars as strings only
|
// First, set up env vars as strings only
|
||||||
gather_parent_env_vars(engine_state);
|
gather_parent_env_vars(engine_state);
|
||||||
|
|
||||||
// Make a note of the exceptions we see for externals that look like math expressions
|
|
||||||
let exceptions = crate::utils::external_exceptions();
|
|
||||||
engine_state.external_exceptions = exceptions;
|
|
||||||
|
|
||||||
// Set up our initial config to start from
|
// Set up our initial config to start from
|
||||||
stack.vars.insert(
|
stack.vars.insert(
|
||||||
CONFIG_VARIABLE_ID,
|
CONFIG_VARIABLE_ID,
|
||||||
@ -86,6 +82,10 @@ pub(crate) fn evaluate(
|
|||||||
report_error(&working_set, &e);
|
report_error(&working_set, &e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make a note of the exceptions we see for externals that look like math expressions
|
||||||
|
let exceptions = crate::utils::external_exceptions(engine_state, &stack);
|
||||||
|
engine_state.external_exceptions = exceptions;
|
||||||
|
|
||||||
// seed the cmd_duration_ms env var
|
// seed the cmd_duration_ms env var
|
||||||
stack.add_env_var(
|
stack.add_env_var(
|
||||||
"CMD_DURATION_MS".into(),
|
"CMD_DURATION_MS".into(),
|
||||||
@ -322,7 +322,7 @@ pub(crate) fn evaluate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make a note of the exceptions we see for externals that look like math expressions
|
// Make a note of the exceptions we see for externals that look like math expressions
|
||||||
let exceptions = crate::utils::external_exceptions();
|
let exceptions = crate::utils::external_exceptions(engine_state, &stack);
|
||||||
engine_state.external_exceptions = exceptions;
|
engine_state.external_exceptions = exceptions;
|
||||||
}
|
}
|
||||||
Ok(Signal::CtrlC) => {
|
Ok(Signal::CtrlC) => {
|
||||||
|
@ -102,7 +102,7 @@ fn did_chop_arguments() -> bool {
|
|||||||
|
|
||||||
for arg in arguments {
|
for arg in arguments {
|
||||||
let chopped = if arg.is_empty() {
|
let chopped = if arg.is_empty() {
|
||||||
&arg
|
arg
|
||||||
} else {
|
} else {
|
||||||
let to = arg.len() - 1;
|
let to = arg.len() - 1;
|
||||||
&arg[..to]
|
&arg[..to]
|
||||||
|
49
src/utils.rs
49
src/utils.rs
@ -255,25 +255,50 @@ pub(crate) fn eval_source(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Finds externals that have names that look like math expressions
|
/// Finds externals that have names that look like math expressions
|
||||||
pub fn external_exceptions() -> Vec<Vec<u8>> {
|
pub fn external_exceptions(engine_state: &EngineState, stack: &Stack) -> Vec<Vec<u8>> {
|
||||||
let mut executables = vec![];
|
let mut executables = vec![];
|
||||||
|
|
||||||
if let Ok(path) = std::env::var("PATH") {
|
if let Some(path) = stack.get_env_var(engine_state, "PATH") {
|
||||||
for path in std::env::split_paths(&path) {
|
match path {
|
||||||
let path = path.to_string_lossy().to_string();
|
Value::List { vals, .. } => {
|
||||||
|
for val in vals {
|
||||||
|
let path = val.as_string();
|
||||||
|
|
||||||
if let Ok(mut contents) = std::fs::read_dir(path) {
|
if let Ok(path) = path {
|
||||||
while let Some(Ok(item)) = contents.next() {
|
if let Ok(mut contents) = std::fs::read_dir(path) {
|
||||||
if is_executable::is_executable(&item.path()) {
|
while let Some(Ok(item)) = contents.next() {
|
||||||
if let Ok(name) = item.file_name().into_string() {
|
if is_executable::is_executable(&item.path()) {
|
||||||
let name = name.as_bytes().to_vec();
|
if let Ok(name) = item.file_name().into_string() {
|
||||||
if nu_parser::is_math_expression_like(&name) {
|
let name = name.as_bytes().to_vec();
|
||||||
executables.push(name);
|
if nu_parser::is_math_expression_like(&name) {
|
||||||
|
executables.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Value::String { val, .. } => {
|
||||||
|
for path in std::env::split_paths(&val) {
|
||||||
|
let path = path.to_string_lossy().to_string();
|
||||||
|
|
||||||
|
if let Ok(mut contents) = std::fs::read_dir(path) {
|
||||||
|
while let Some(Ok(item)) = contents.next() {
|
||||||
|
if is_executable::is_executable(&item.path()) {
|
||||||
|
if let Ok(name) = item.file_name().into_string() {
|
||||||
|
let name = name.as_bytes().to_vec();
|
||||||
|
if nu_parser::is_math_expression_like(&name) {
|
||||||
|
executables.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +343,7 @@ pub fn report_error(
|
|||||||
pub(crate) fn get_init_cwd() -> PathBuf {
|
pub(crate) fn get_init_cwd() -> PathBuf {
|
||||||
match std::env::current_dir() {
|
match std::env::current_dir() {
|
||||||
Ok(cwd) => cwd,
|
Ok(cwd) => cwd,
|
||||||
Err(_) => match std::env::var("PWD".to_string()) {
|
Err(_) => match std::env::var("PWD") {
|
||||||
Ok(cwd) => PathBuf::from(cwd),
|
Ok(cwd) => PathBuf::from(cwd),
|
||||||
Err(_) => match nu_path::home_dir() {
|
Err(_) => match nu_path::home_dir() {
|
||||||
Some(cwd) => cwd,
|
Some(cwd) => cwd,
|
||||||
|
Loading…
Reference in New Issue
Block a user