Merge 69c7728240
into 813aac89bd
This commit is contained in:
commit
64e395d4e3
|
@ -18,6 +18,7 @@ pub fn add_cli_context(mut engine_state: EngineState) -> EngineState {
|
||||||
CommandlineSetCursor,
|
CommandlineSetCursor,
|
||||||
History,
|
History,
|
||||||
HistorySession,
|
HistorySession,
|
||||||
|
HistoryImport,
|
||||||
Keybindings,
|
Keybindings,
|
||||||
KeybindingsDefault,
|
KeybindingsDefault,
|
||||||
KeybindingsList,
|
KeybindingsList,
|
||||||
|
|
10
crates/nu-cli/src/commands/history/fields.rs
Normal file
10
crates/nu-cli/src/commands/history/fields.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// Each const is named after a HistoryItem field, and the value is the field name to be displayed to
|
||||||
|
// the user (or accept during import).
|
||||||
|
pub const COMMAND_LINE: &str = "command";
|
||||||
|
pub const ID: &str = "item_id";
|
||||||
|
pub const START_TIMESTAMP: &str = "start_timestamp";
|
||||||
|
pub const HOSTNAME: &str = "hostname";
|
||||||
|
pub const CWD: &str = "cwd";
|
||||||
|
pub const EXIT_STATUS: &str = "exist_status";
|
||||||
|
pub const DURATION: &str = "duration";
|
||||||
|
pub const SESSION_ID: &str = "session_id";
|
|
@ -5,6 +5,8 @@ use reedline::{
|
||||||
SqliteBackedHistory,
|
SqliteBackedHistory,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::{commands::history::fields, config_files::get_history_path};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct History;
|
pub struct History;
|
||||||
|
|
||||||
|
@ -44,89 +46,78 @@ impl Command for History {
|
||||||
};
|
};
|
||||||
|
|
||||||
// todo for sqlite history this command should be an alias to `open ~/.config/nushell/history.sqlite3 | get history`
|
// todo for sqlite history this command should be an alias to `open ~/.config/nushell/history.sqlite3 | get history`
|
||||||
if let Some(config_path) = nu_path::config_dir() {
|
let Some(history_path) = get_history_path(history.file_format) else {
|
||||||
let clear = call.has_flag(engine_state, stack, "clear")?;
|
return Err(ShellError::ConfigDirNotFound { span: Some(head) });
|
||||||
let long = call.has_flag(engine_state, stack, "long")?;
|
};
|
||||||
let signals = engine_state.signals().clone();
|
let clear = call.has_flag(engine_state, stack, "clear")?;
|
||||||
|
let long = call.has_flag(engine_state, stack, "long")?;
|
||||||
|
let signals = engine_state.signals().clone();
|
||||||
|
|
||||||
let mut history_path = config_path;
|
if clear {
|
||||||
history_path.push("nushell");
|
let _ = std::fs::remove_file(history_path);
|
||||||
match history.file_format {
|
// TODO: FIXME also clear the auxiliary files when using sqlite
|
||||||
HistoryFileFormat::Sqlite => {
|
Ok(PipelineData::empty())
|
||||||
history_path.push("history.sqlite3");
|
|
||||||
}
|
|
||||||
HistoryFileFormat::PlainText => {
|
|
||||||
history_path.push("history.txt");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if clear {
|
|
||||||
let _ = std::fs::remove_file(history_path);
|
|
||||||
// TODO: FIXME also clear the auxiliary files when using sqlite
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
} else {
|
|
||||||
let history_reader: Option<Box<dyn ReedlineHistory>> = match history.file_format {
|
|
||||||
HistoryFileFormat::Sqlite => {
|
|
||||||
SqliteBackedHistory::with_file(history_path.clone(), None, None)
|
|
||||||
.map(|inner| {
|
|
||||||
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
|
|
||||||
boxed
|
|
||||||
})
|
|
||||||
.ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryFileFormat::PlainText => FileBackedHistory::with_file(
|
|
||||||
history.max_size as usize,
|
|
||||||
history_path.clone(),
|
|
||||||
)
|
|
||||||
.map(|inner| {
|
|
||||||
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
|
|
||||||
boxed
|
|
||||||
})
|
|
||||||
.ok(),
|
|
||||||
};
|
|
||||||
|
|
||||||
match history.file_format {
|
|
||||||
HistoryFileFormat::PlainText => Ok(history_reader
|
|
||||||
.and_then(|h| {
|
|
||||||
h.search(SearchQuery::everything(SearchDirection::Forward, None))
|
|
||||||
.ok()
|
|
||||||
})
|
|
||||||
.map(move |entries| {
|
|
||||||
entries.into_iter().enumerate().map(move |(idx, entry)| {
|
|
||||||
Value::record(
|
|
||||||
record! {
|
|
||||||
"command" => Value::string(entry.command_line, head),
|
|
||||||
"index" => Value::int(idx as i64, head),
|
|
||||||
},
|
|
||||||
head,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.ok_or(ShellError::FileNotFound {
|
|
||||||
file: history_path.display().to_string(),
|
|
||||||
span: head,
|
|
||||||
})?
|
|
||||||
.into_pipeline_data(head, signals)),
|
|
||||||
HistoryFileFormat::Sqlite => Ok(history_reader
|
|
||||||
.and_then(|h| {
|
|
||||||
h.search(SearchQuery::everything(SearchDirection::Forward, None))
|
|
||||||
.ok()
|
|
||||||
})
|
|
||||||
.map(move |entries| {
|
|
||||||
entries.into_iter().enumerate().map(move |(idx, entry)| {
|
|
||||||
create_history_record(idx, entry, long, head)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.ok_or(ShellError::FileNotFound {
|
|
||||||
file: history_path.display().to_string(),
|
|
||||||
span: head,
|
|
||||||
})?
|
|
||||||
.into_pipeline_data(head, signals)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Err(ShellError::ConfigDirNotFound { span: Some(head) })
|
let history_reader: Option<Box<dyn ReedlineHistory>> = match history.file_format {
|
||||||
|
HistoryFileFormat::Sqlite => {
|
||||||
|
SqliteBackedHistory::with_file(history_path.clone(), None, None)
|
||||||
|
.map(|inner| {
|
||||||
|
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
|
||||||
|
boxed
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryFileFormat::PlainText => {
|
||||||
|
FileBackedHistory::with_file(history.max_size as usize, history_path.clone())
|
||||||
|
.map(|inner| {
|
||||||
|
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
|
||||||
|
boxed
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match history.file_format {
|
||||||
|
HistoryFileFormat::PlainText => Ok(history_reader
|
||||||
|
.and_then(|h| {
|
||||||
|
h.search(SearchQuery::everything(SearchDirection::Forward, None))
|
||||||
|
.ok()
|
||||||
|
})
|
||||||
|
.map(move |entries| {
|
||||||
|
entries.into_iter().enumerate().map(move |(idx, entry)| {
|
||||||
|
Value::record(
|
||||||
|
record! {
|
||||||
|
fields::COMMAND_LINE => Value::string(entry.command_line, head),
|
||||||
|
// TODO: This name is inconsistent with create_history_record.
|
||||||
|
"index" => Value::int(idx as i64, head),
|
||||||
|
},
|
||||||
|
head,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.ok_or(ShellError::FileNotFound {
|
||||||
|
file: history_path.display().to_string(),
|
||||||
|
span: head,
|
||||||
|
})?
|
||||||
|
.into_pipeline_data(head, signals)),
|
||||||
|
HistoryFileFormat::Sqlite => Ok(history_reader
|
||||||
|
.and_then(|h| {
|
||||||
|
h.search(SearchQuery::everything(SearchDirection::Forward, None))
|
||||||
|
.ok()
|
||||||
|
})
|
||||||
|
.map(move |entries| {
|
||||||
|
entries
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(move |(idx, entry)| create_history_record(idx, entry, long, head))
|
||||||
|
})
|
||||||
|
.ok_or(ShellError::FileNotFound {
|
||||||
|
file: history_path.display().to_string(),
|
||||||
|
span: head,
|
||||||
|
})?
|
||||||
|
.into_pipeline_data(head, signals)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,14 +206,14 @@ fn create_history_record(idx: usize, entry: HistoryItem, long: bool, head: Span)
|
||||||
if long {
|
if long {
|
||||||
Value::record(
|
Value::record(
|
||||||
record! {
|
record! {
|
||||||
"item_id" => item_id_value,
|
fields::ID => item_id_value,
|
||||||
"start_timestamp" => start_timestamp_value,
|
fields::START_TIMESTAMP => start_timestamp_value,
|
||||||
"command" => command_value,
|
fields::COMMAND_LINE => command_value,
|
||||||
"session_id" => session_id_value,
|
fields::SESSION_ID => session_id_value,
|
||||||
"hostname" => hostname_value,
|
fields::HOSTNAME => hostname_value,
|
||||||
"cwd" => cwd_value,
|
fields::CWD => cwd_value,
|
||||||
"duration" => duration_value,
|
fields::DURATION => duration_value,
|
||||||
"exit_status" => exit_status_value,
|
fields::EXIT_STATUS => exit_status_value,
|
||||||
"idx" => index_value,
|
"idx" => index_value,
|
||||||
},
|
},
|
||||||
head,
|
head,
|
||||||
|
@ -230,11 +221,11 @@ fn create_history_record(idx: usize, entry: HistoryItem, long: bool, head: Span)
|
||||||
} else {
|
} else {
|
||||||
Value::record(
|
Value::record(
|
||||||
record! {
|
record! {
|
||||||
"start_timestamp" => start_timestamp_value,
|
fields::START_TIMESTAMP => start_timestamp_value,
|
||||||
"command" => command_value,
|
fields::COMMAND_LINE => command_value,
|
||||||
"cwd" => cwd_value,
|
fields::CWD => cwd_value,
|
||||||
"duration" => duration_value,
|
fields::DURATION => duration_value,
|
||||||
"exit_status" => exit_status_value,
|
fields::EXIT_STATUS => exit_status_value,
|
||||||
},
|
},
|
||||||
head,
|
head,
|
||||||
)
|
)
|
||||||
|
|
318
crates/nu-cli/src/commands/history/history_import.rs
Normal file
318
crates/nu-cli/src/commands/history/history_import.rs
Normal file
|
@ -0,0 +1,318 @@
|
||||||
|
use nu_engine::command_prelude::*;
|
||||||
|
use nu_protocol::HistoryFileFormat;
|
||||||
|
|
||||||
|
use reedline::{
|
||||||
|
FileBackedHistory, History, HistoryItem, HistoryItemId, ReedlineError, SearchQuery,
|
||||||
|
SqliteBackedHistory,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
commands::history::fields,
|
||||||
|
config_files::{HISTORY_FILE_SQLITE, HISTORY_FILE_TXT},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct HistoryImport;
|
||||||
|
|
||||||
|
impl Command for HistoryImport {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"history import"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Import command line history"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
r#"Can import history from input, either successive command lines or more detailed records. If providing records, available fields are:
|
||||||
|
command_line, id, start_timestamp, hostname, cwd, duration, exit_status.
|
||||||
|
|
||||||
|
If no input is provided, will import all history items from existing history in the other format: if current history is stored in sqlite, it will store it in plain text and vice versa."#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
|
Signature::build("history import")
|
||||||
|
.category(Category::History)
|
||||||
|
.input_output_types(vec![
|
||||||
|
(Type::Nothing, Type::Nothing),
|
||||||
|
(Type::List(Box::new(Type::String)), Type::Nothing),
|
||||||
|
(Type::table(), Type::Nothing),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
example: "history import",
|
||||||
|
description:
|
||||||
|
"Append all items from history in the other format to the current history",
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
example: "echo foo | history import",
|
||||||
|
description: "Append `foo` to the current history",
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
example: "[[ command_line cwd ]; [ foo /home ]] | history import",
|
||||||
|
description: "Append `foo` ran from `/home` to the current history",
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
_stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let ok = Ok(Value::nothing(call.head).into_pipeline_data());
|
||||||
|
|
||||||
|
let Some(history) = engine_state.history_config() else {
|
||||||
|
return ok;
|
||||||
|
};
|
||||||
|
let Some(config_path) = nu_path::nu_config_dir() else {
|
||||||
|
return Err(ShellError::ConfigDirNotFound {
|
||||||
|
span: Some(call.head),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_sqlite_backend = || {
|
||||||
|
SqliteBackedHistory::with_file(config_path.join(HISTORY_FILE_SQLITE), None, None)
|
||||||
|
.map_err(error_from_reedline)
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_file_backend = || {
|
||||||
|
FileBackedHistory::with_file(
|
||||||
|
history.max_size as usize,
|
||||||
|
config_path.join(HISTORY_FILE_TXT),
|
||||||
|
)
|
||||||
|
.map_err(error_from_reedline)
|
||||||
|
};
|
||||||
|
|
||||||
|
match input {
|
||||||
|
PipelineData::Empty => {
|
||||||
|
let mut sqlite = new_sqlite_backend()?;
|
||||||
|
let mut plaintext = new_file_backend()?;
|
||||||
|
let (src, dst): (&dyn History, &mut dyn History) = match history.file_format {
|
||||||
|
HistoryFileFormat::Sqlite => (&plaintext, &mut sqlite),
|
||||||
|
HistoryFileFormat::PlainText => (&sqlite, &mut plaintext),
|
||||||
|
};
|
||||||
|
|
||||||
|
let items = src
|
||||||
|
.search(SearchQuery::everything(
|
||||||
|
reedline::SearchDirection::Forward,
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
.map_err(error_from_reedline)?
|
||||||
|
.into_iter()
|
||||||
|
.map(Ok);
|
||||||
|
import(dst, items)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let input = input.into_iter().map(item_from_value);
|
||||||
|
match history.file_format {
|
||||||
|
HistoryFileFormat::Sqlite => import(&mut new_sqlite_backend()?, input),
|
||||||
|
HistoryFileFormat::PlainText => import(&mut new_file_backend()?, input),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}?;
|
||||||
|
|
||||||
|
ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn import(
|
||||||
|
dst: &mut dyn History,
|
||||||
|
src: impl Iterator<Item = Result<HistoryItem, ShellError>>,
|
||||||
|
) -> Result<(), ShellError> {
|
||||||
|
for item in src {
|
||||||
|
dst.save(item?).map_err(error_from_reedline)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error_from_reedline(e: ReedlineError) -> ShellError {
|
||||||
|
// TODO: Should we add a new ShellError variant?
|
||||||
|
ShellError::IOError {
|
||||||
|
msg: format!("reedline error: {e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn item_from_value(v: Value) -> Result<HistoryItem, ShellError> {
|
||||||
|
let span = v.span();
|
||||||
|
match v {
|
||||||
|
Value::Record { val, .. } => item_from_record(val.into_owned(), span),
|
||||||
|
Value::String { val, .. } => Ok(HistoryItem {
|
||||||
|
command_line: val,
|
||||||
|
id: None,
|
||||||
|
start_timestamp: None,
|
||||||
|
session_id: None,
|
||||||
|
hostname: None,
|
||||||
|
cwd: None,
|
||||||
|
duration: None,
|
||||||
|
exit_status: None,
|
||||||
|
more_info: None,
|
||||||
|
}),
|
||||||
|
_ => Err(ShellError::UnsupportedInput {
|
||||||
|
msg: "Only list and record inputs are supported".to_owned(),
|
||||||
|
input: v.get_type().to_string(),
|
||||||
|
msg_span: span,
|
||||||
|
input_span: span,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn item_from_record(mut rec: Record, span: Span) -> Result<HistoryItem, ShellError> {
|
||||||
|
let cmd = match rec.remove(fields::COMMAND_LINE) {
|
||||||
|
Some(v) => v.as_str()?.to_owned(),
|
||||||
|
None => {
|
||||||
|
return Err(ShellError::NotFound {
|
||||||
|
span: Span::unknown(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn get<T>(
|
||||||
|
rec: &mut Record,
|
||||||
|
field: &'static str,
|
||||||
|
f: impl FnOnce(Value) -> Result<T, ShellError>,
|
||||||
|
) -> Result<Option<T>, ShellError> {
|
||||||
|
rec.remove(field).map(f).transpose()
|
||||||
|
}
|
||||||
|
|
||||||
|
let item = HistoryItem {
|
||||||
|
command_line: cmd,
|
||||||
|
id: get(&mut rec, fields::ID, |v| {
|
||||||
|
Ok(HistoryItemId::new(v.as_int()?))
|
||||||
|
})?,
|
||||||
|
start_timestamp: get(&mut rec, fields::START_TIMESTAMP, |v| {
|
||||||
|
Ok(v.as_date()?.to_utc())
|
||||||
|
})?,
|
||||||
|
hostname: get(&mut rec, fields::HOSTNAME, |v| Ok(v.as_str()?.to_owned()))?,
|
||||||
|
cwd: get(&mut rec, fields::CWD, |v| Ok(v.as_str()?.to_owned()))?,
|
||||||
|
exit_status: get(&mut rec, fields::EXIT_STATUS, |v| v.as_i64())?,
|
||||||
|
duration: get(&mut rec, fields::DURATION, duration_from_value)?,
|
||||||
|
more_info: None,
|
||||||
|
// TODO: Currently reedline doesn't let you create session IDs.
|
||||||
|
session_id: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if !rec.is_empty() {
|
||||||
|
let cols = rec.columns().map(|s| s.as_str()).collect::<Vec<_>>();
|
||||||
|
return Err(ShellError::TypeMismatch {
|
||||||
|
err_message: format!("unsupported column names: {}", cols.join(", ")),
|
||||||
|
span,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn duration_from_value(v: Value) -> Result<std::time::Duration, ShellError> {
|
||||||
|
chrono::Duration::nanoseconds(v.as_duration()?)
|
||||||
|
.to_std()
|
||||||
|
.map_err(|_| ShellError::IOError {
|
||||||
|
msg: "negative duration not supported".to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use chrono::DateTime;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_item_from_value_string() -> Result<(), ShellError> {
|
||||||
|
let item = item_from_value(Value::string("foo", Span::unknown()))?;
|
||||||
|
assert_eq!(
|
||||||
|
item,
|
||||||
|
HistoryItem {
|
||||||
|
command_line: "foo".to_string(),
|
||||||
|
id: None,
|
||||||
|
start_timestamp: None,
|
||||||
|
session_id: None,
|
||||||
|
hostname: None,
|
||||||
|
cwd: None,
|
||||||
|
duration: None,
|
||||||
|
exit_status: None,
|
||||||
|
more_info: None
|
||||||
|
}
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_item_from_value_record() {
|
||||||
|
let span = Span::unknown();
|
||||||
|
let rec = new_record(&[
|
||||||
|
("command_line", Value::string("foo", span)),
|
||||||
|
("id", Value::int(1, span)),
|
||||||
|
(
|
||||||
|
"start_timestamp",
|
||||||
|
Value::date(
|
||||||
|
DateTime::parse_from_rfc3339("1996-12-19T16:39:57-08:00").unwrap(),
|
||||||
|
span,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("hostname", Value::string("localhost", span)),
|
||||||
|
("cwd", Value::string("/home/test", span)),
|
||||||
|
("duration", Value::duration(100_000_000, span)),
|
||||||
|
("exit_status", Value::int(42, span)),
|
||||||
|
]);
|
||||||
|
let item = item_from_value(rec).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
item,
|
||||||
|
HistoryItem {
|
||||||
|
command_line: "foo".to_string(),
|
||||||
|
id: Some(HistoryItemId::new(1)),
|
||||||
|
start_timestamp: Some(
|
||||||
|
DateTime::parse_from_rfc3339("1996-12-19T16:39:57-08:00")
|
||||||
|
.unwrap()
|
||||||
|
.to_utc()
|
||||||
|
),
|
||||||
|
hostname: Some("localhost".to_string()),
|
||||||
|
cwd: Some("/home/test".to_string()),
|
||||||
|
duration: Some(std::time::Duration::from_nanos(100_000_000)),
|
||||||
|
exit_status: Some(42),
|
||||||
|
|
||||||
|
session_id: None,
|
||||||
|
more_info: None
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_item_from_value_record_extra_field() {
|
||||||
|
let span = Span::unknown();
|
||||||
|
let rec = new_record(&[
|
||||||
|
("command_line", Value::string("foo", span)),
|
||||||
|
("id_nonexistent", Value::int(1, span)),
|
||||||
|
]);
|
||||||
|
assert!(item_from_value(rec).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_item_from_value_record_bad_type() {
|
||||||
|
let span = Span::unknown();
|
||||||
|
let rec = new_record(&[
|
||||||
|
("command_line", Value::string("foo", span)),
|
||||||
|
("id", Value::string("one".to_string(), span)),
|
||||||
|
]);
|
||||||
|
assert!(item_from_value(rec).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_record(rec: &[(&'static str, Value)]) -> Value {
|
||||||
|
let span = Span::unknown();
|
||||||
|
let rec = Record::from_raw_cols_vals(
|
||||||
|
rec.iter().map(|(col, _)| col.to_string()).collect(),
|
||||||
|
rec.iter().map(|(_, val)| val.clone()).collect(),
|
||||||
|
span,
|
||||||
|
span,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
Value::record(rec, span)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,8 @@
|
||||||
|
mod fields;
|
||||||
mod history_;
|
mod history_;
|
||||||
|
mod history_import;
|
||||||
mod history_session;
|
mod history_session;
|
||||||
|
|
||||||
pub use history_::History;
|
pub use history_::History;
|
||||||
|
pub use history_import::HistoryImport;
|
||||||
pub use history_session::HistorySession;
|
pub use history_session::HistorySession;
|
||||||
|
|
|
@ -7,7 +7,7 @@ mod keybindings_list;
|
||||||
mod keybindings_listen;
|
mod keybindings_listen;
|
||||||
|
|
||||||
pub use commandline::{Commandline, CommandlineEdit, CommandlineGetCursor, CommandlineSetCursor};
|
pub use commandline::{Commandline, CommandlineEdit, CommandlineGetCursor, CommandlineSetCursor};
|
||||||
pub use history::{History, HistorySession};
|
pub use history::{History, HistoryImport, HistorySession};
|
||||||
pub use keybindings::Keybindings;
|
pub use keybindings::Keybindings;
|
||||||
pub use keybindings_default::KeybindingsDefault;
|
pub use keybindings_default::KeybindingsDefault;
|
||||||
pub use keybindings_list::KeybindingsList;
|
pub use keybindings_list::KeybindingsList;
|
||||||
|
|
|
@ -16,8 +16,8 @@ const PLUGIN_FILE: &str = "plugin.msgpackz";
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
const OLD_PLUGIN_FILE: &str = "plugin.nu";
|
const OLD_PLUGIN_FILE: &str = "plugin.nu";
|
||||||
|
|
||||||
const HISTORY_FILE_TXT: &str = "history.txt";
|
pub const HISTORY_FILE_TXT: &str = "history.txt";
|
||||||
const HISTORY_FILE_SQLITE: &str = "history.sqlite3";
|
pub const HISTORY_FILE_SQLITE: &str = "history.sqlite3";
|
||||||
|
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
pub fn read_plugin_file(
|
pub fn read_plugin_file(
|
||||||
|
@ -240,9 +240,8 @@ pub fn eval_config_contents(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_history_path(storage_path: &str, mode: HistoryFileFormat) -> Option<PathBuf> {
|
pub(crate) fn get_history_path(mode: HistoryFileFormat) -> Option<PathBuf> {
|
||||||
nu_path::config_dir().map(|mut history_path| {
|
nu_path::nu_config_dir().map(|mut history_path| {
|
||||||
history_path.push(storage_path);
|
|
||||||
history_path.push(match mode {
|
history_path.push(match mode {
|
||||||
HistoryFileFormat::PlainText => HISTORY_FILE_TXT,
|
HistoryFileFormat::PlainText => HISTORY_FILE_TXT,
|
||||||
HistoryFileFormat::Sqlite => HISTORY_FILE_SQLITE,
|
HistoryFileFormat::Sqlite => HISTORY_FILE_SQLITE,
|
||||||
|
|
|
@ -52,7 +52,6 @@ use sysinfo::System;
|
||||||
pub fn evaluate_repl(
|
pub fn evaluate_repl(
|
||||||
engine_state: &mut EngineState,
|
engine_state: &mut EngineState,
|
||||||
stack: Stack,
|
stack: Stack,
|
||||||
nushell_path: &str,
|
|
||||||
prerun_command: Option<Spanned<String>>,
|
prerun_command: Option<Spanned<String>>,
|
||||||
load_std_lib: Option<Spanned<String>>,
|
load_std_lib: Option<Spanned<String>>,
|
||||||
entire_start_time: Instant,
|
entire_start_time: Instant,
|
||||||
|
@ -99,7 +98,7 @@ pub fn evaluate_repl(
|
||||||
|
|
||||||
unique_stack.add_env_var("LAST_EXIT_CODE".into(), Value::int(0, Span::unknown()));
|
unique_stack.add_env_var("LAST_EXIT_CODE".into(), Value::int(0, Span::unknown()));
|
||||||
|
|
||||||
let mut line_editor = get_line_editor(engine_state, nushell_path, use_color)?;
|
let mut line_editor = get_line_editor(engine_state, use_color)?;
|
||||||
let temp_file = temp_dir().join(format!("{}.nu", uuid::Uuid::new_v4()));
|
let temp_file = temp_dir().join(format!("{}.nu", uuid::Uuid::new_v4()));
|
||||||
|
|
||||||
if let Some(s) = prerun_command {
|
if let Some(s) = prerun_command {
|
||||||
|
@ -200,7 +199,7 @@ pub fn evaluate_repl(
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// line_editor is lost in the error case so reconstruct a new one
|
// line_editor is lost in the error case so reconstruct a new one
|
||||||
line_editor = get_line_editor(engine_state, nushell_path, use_color)?;
|
line_editor = get_line_editor(engine_state, use_color)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,11 +207,7 @@ pub fn evaluate_repl(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_line_editor(
|
fn get_line_editor(engine_state: &mut EngineState, use_color: bool) -> Result<Reedline> {
|
||||||
engine_state: &mut EngineState,
|
|
||||||
nushell_path: &str,
|
|
||||||
use_color: bool,
|
|
||||||
) -> Result<Reedline> {
|
|
||||||
let mut start_time = std::time::Instant::now();
|
let mut start_time = std::time::Instant::now();
|
||||||
let mut line_editor = Reedline::create();
|
let mut line_editor = Reedline::create();
|
||||||
|
|
||||||
|
@ -223,7 +218,7 @@ fn get_line_editor(
|
||||||
if let Some(history) = engine_state.history_config() {
|
if let Some(history) = engine_state.history_config() {
|
||||||
start_time = std::time::Instant::now();
|
start_time = std::time::Instant::now();
|
||||||
|
|
||||||
line_editor = setup_history(nushell_path, engine_state, line_editor, history)?;
|
line_editor = setup_history(engine_state, line_editor, history)?;
|
||||||
|
|
||||||
perf!("setup history", start_time, use_color);
|
perf!("setup history", start_time, use_color);
|
||||||
}
|
}
|
||||||
|
@ -1037,7 +1032,6 @@ fn flush_engine_state_repl_buffer(engine_state: &mut EngineState, line_editor: &
|
||||||
/// Setup history management for Reedline
|
/// Setup history management for Reedline
|
||||||
///
|
///
|
||||||
fn setup_history(
|
fn setup_history(
|
||||||
nushell_path: &str,
|
|
||||||
engine_state: &mut EngineState,
|
engine_state: &mut EngineState,
|
||||||
line_editor: Reedline,
|
line_editor: Reedline,
|
||||||
history: HistoryConfig,
|
history: HistoryConfig,
|
||||||
|
@ -1049,7 +1043,7 @@ fn setup_history(
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(path) = crate::config_files::get_history_path(nushell_path, history.file_format) {
|
if let Some(path) = crate::config_files::get_history_path(history.file_format) {
|
||||||
return update_line_editor_history(
|
return update_line_editor_history(
|
||||||
engine_state,
|
engine_state,
|
||||||
path,
|
path,
|
||||||
|
@ -1317,8 +1311,7 @@ fn trailing_slash_looks_like_path() {
|
||||||
fn are_session_ids_in_sync() {
|
fn are_session_ids_in_sync() {
|
||||||
let engine_state = &mut EngineState::new();
|
let engine_state = &mut EngineState::new();
|
||||||
let history = engine_state.history_config().unwrap();
|
let history = engine_state.history_config().unwrap();
|
||||||
let history_path =
|
let history_path = crate::config_files::get_history_path(history.file_format).unwrap();
|
||||||
crate::config_files::get_history_path("nushell", history.file_format).unwrap();
|
|
||||||
let line_editor = reedline::Reedline::create();
|
let line_editor = reedline::Reedline::create();
|
||||||
let history_session_id = reedline::Reedline::create_history_session_id();
|
let history_session_id = reedline::Reedline::create_history_session_id();
|
||||||
let line_editor = update_line_editor_history(
|
let line_editor = update_line_editor_history(
|
||||||
|
|
161
crates/nu-cli/tests/commands/history_import.rs
Normal file
161
crates/nu-cli/tests/commands/history_import.rs
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
use nu_test_support::{nu, Outcome};
|
||||||
|
use reedline::{
|
||||||
|
FileBackedHistory, History, HistoryItem, HistoryItemId, ReedlineError, SearchQuery,
|
||||||
|
SqliteBackedHistory,
|
||||||
|
};
|
||||||
|
use tempfile::TempDir;
|
||||||
|
|
||||||
|
struct Test {
|
||||||
|
cfg_dir: TempDir,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Test {
|
||||||
|
fn new(history_format: &'static str) -> Self {
|
||||||
|
let cfg_dir = tempfile::Builder::new()
|
||||||
|
.prefix("history_import_test")
|
||||||
|
.tempdir()
|
||||||
|
.unwrap();
|
||||||
|
std::fs::create_dir(&cfg_dir).unwrap();
|
||||||
|
// Assigning to $env.config.history.file_format seems to work only in startup
|
||||||
|
// configuration.
|
||||||
|
std::fs::write(
|
||||||
|
cfg_dir.path().join("env.nu"),
|
||||||
|
format!("$env.config.history.file_format = {history_format}"),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
Self { cfg_dir }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nu(&self, cmd: &'static str) -> Outcome {
|
||||||
|
let env = [(
|
||||||
|
"XDG_CONFIG_HOME".to_string(),
|
||||||
|
self.cfg_dir.path().to_str().unwrap().to_string(),
|
||||||
|
)];
|
||||||
|
let env_config = self.cfg_dir.path().join("env.nu");
|
||||||
|
nu!(envs: env, env_config: env_config, cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_plaintext(&self) -> Result<FileBackedHistory, ReedlineError> {
|
||||||
|
FileBackedHistory::with_file(100, self.cfg_dir.path().join("nushell").join("history.txt"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_sqlite(&self) -> Result<SqliteBackedHistory, ReedlineError> {
|
||||||
|
SqliteBackedHistory::with_file(
|
||||||
|
self.cfg_dir.path().join("nushell").join("history.sqlite3"),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn query_all(history: impl History) -> Result<Vec<HistoryItem>, ReedlineError> {
|
||||||
|
history.search(SearchQuery::everything(
|
||||||
|
reedline::SearchDirection::Forward,
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save_all(mut history: impl History, items: Vec<HistoryItem>) -> Result<(), ReedlineError> {
|
||||||
|
for item in items {
|
||||||
|
history.save(item)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
const EMPTY_ITEM: HistoryItem = HistoryItem {
|
||||||
|
command_line: String::new(),
|
||||||
|
id: None,
|
||||||
|
start_timestamp: None,
|
||||||
|
session_id: None,
|
||||||
|
hostname: None,
|
||||||
|
cwd: None,
|
||||||
|
duration: None,
|
||||||
|
exit_status: None,
|
||||||
|
more_info: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn history_import_pipe() {
|
||||||
|
let test = Test::new("plaintext");
|
||||||
|
let outcome = test.nu("echo bar | history import");
|
||||||
|
assert!(outcome.status.success());
|
||||||
|
assert_eq!(
|
||||||
|
query_all(test.open_plaintext().unwrap()).unwrap(),
|
||||||
|
vec![HistoryItem {
|
||||||
|
id: Some(HistoryItemId::new(0)),
|
||||||
|
command_line: "bar".to_string(),
|
||||||
|
..EMPTY_ITEM
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn history_import_plain_to_sqlite() {
|
||||||
|
let test = Test::new("sqlite");
|
||||||
|
save_all(
|
||||||
|
test.open_plaintext().unwrap(),
|
||||||
|
vec![
|
||||||
|
HistoryItem {
|
||||||
|
id: Some(HistoryItemId::new(0)),
|
||||||
|
command_line: "foo".to_string(),
|
||||||
|
..EMPTY_ITEM
|
||||||
|
},
|
||||||
|
HistoryItem {
|
||||||
|
id: Some(HistoryItemId::new(1)),
|
||||||
|
command_line: "bar".to_string(),
|
||||||
|
..EMPTY_ITEM
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let outcome = test.nu("history import");
|
||||||
|
assert!(outcome.status.success());
|
||||||
|
assert_eq!(
|
||||||
|
query_all(test.open_sqlite().unwrap()).unwrap(),
|
||||||
|
vec![HistoryItem {
|
||||||
|
id: Some(HistoryItemId::new(0)),
|
||||||
|
command_line: "bar".to_string(),
|
||||||
|
..EMPTY_ITEM
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn history_import_sqlite_to_plain() {
|
||||||
|
let test = Test::new("plaintext");
|
||||||
|
save_all(
|
||||||
|
test.open_sqlite().unwrap(),
|
||||||
|
vec![
|
||||||
|
HistoryItem {
|
||||||
|
id: Some(HistoryItemId::new(0)),
|
||||||
|
command_line: "foo".to_string(),
|
||||||
|
hostname: Some("host".to_string()),
|
||||||
|
..EMPTY_ITEM
|
||||||
|
},
|
||||||
|
HistoryItem {
|
||||||
|
id: Some(HistoryItemId::new(1)),
|
||||||
|
command_line: "bar".to_string(),
|
||||||
|
cwd: Some("/home/test".to_string()),
|
||||||
|
..EMPTY_ITEM
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let outcome = test.nu("history import");
|
||||||
|
assert!(outcome.status.success());
|
||||||
|
assert_eq!(
|
||||||
|
query_all(test.open_plaintext().unwrap()).unwrap(),
|
||||||
|
vec![
|
||||||
|
HistoryItem {
|
||||||
|
id: Some(HistoryItemId::new(0)),
|
||||||
|
command_line: "foo".to_string(),
|
||||||
|
..EMPTY_ITEM
|
||||||
|
},
|
||||||
|
HistoryItem {
|
||||||
|
id: Some(HistoryItemId::new(1)),
|
||||||
|
command_line: "bar".to_string(),
|
||||||
|
..EMPTY_ITEM
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,2 +1,3 @@
|
||||||
|
mod history_import;
|
||||||
mod keybindings_list;
|
mod keybindings_list;
|
||||||
mod nu_highlight;
|
mod nu_highlight;
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
use omnipath::WinPathExt;
|
use omnipath::WinPathExt;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[deprecated(
|
||||||
|
note = "prefer using nu_config_dir() instead of config_dir() joined with NUSHELL_FOLDER"
|
||||||
|
)]
|
||||||
|
pub const NUSHELL_FOLDER: &str = "nushell";
|
||||||
|
|
||||||
pub fn home_dir() -> Option<PathBuf> {
|
pub fn home_dir() -> Option<PathBuf> {
|
||||||
dirs::home_dir()
|
dirs::home_dir()
|
||||||
}
|
}
|
||||||
|
@ -34,6 +39,15 @@ pub fn config_dir() -> Option<PathBuf> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the nushell config directory.
|
||||||
|
pub fn nu_config_dir() -> Option<PathBuf> {
|
||||||
|
config_dir().map(|mut p| {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
p.push(NUSHELL_FOLDER);
|
||||||
|
p
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_canonicalized_path(path: Option<PathBuf>) -> Option<PathBuf> {
|
pub fn get_canonicalized_path(path: Option<PathBuf>) -> Option<PathBuf> {
|
||||||
let path = path?;
|
let path = path?;
|
||||||
Some(canonicalize(&path).unwrap_or(path))
|
Some(canonicalize(&path).unwrap_or(path))
|
||||||
|
|
|
@ -11,7 +11,12 @@ mod trailing_slash;
|
||||||
|
|
||||||
pub use components::components;
|
pub use components::components;
|
||||||
pub use expansions::{canonicalize_with, expand_path_with, expand_to_real_path, locate_in_dirs};
|
pub use expansions::{canonicalize_with, expand_path_with, expand_to_real_path, locate_in_dirs};
|
||||||
pub use helpers::{cache_dir, config_dir, data_dir, get_canonicalized_path, home_dir};
|
pub use helpers::{
|
||||||
|
cache_dir, config_dir, data_dir, get_canonicalized_path, home_dir, nu_config_dir,
|
||||||
|
};
|
||||||
pub use path::*;
|
pub use path::*;
|
||||||
pub use tilde::expand_tilde;
|
pub use tilde::expand_tilde;
|
||||||
pub use trailing_slash::{has_trailing_slash, strip_trailing_slash};
|
pub use trailing_slash::{has_trailing_slash, strip_trailing_slash};
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
|
pub use helpers::NUSHELL_FOLDER;
|
||||||
|
|
|
@ -234,7 +234,7 @@ macro_rules! nu_with_plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::{Outcome, NATIVE_PATH_ENV_VAR};
|
use crate::{Outcome, NATIVE_PATH_ENV_VAR};
|
||||||
use nu_path::{AbsolutePath, AbsolutePathBuf, Path};
|
use nu_path::{AbsolutePath, AbsolutePathBuf, Path, PathBuf};
|
||||||
use std::{
|
use std::{
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
process::{Command, Stdio},
|
process::{Command, Stdio},
|
||||||
|
@ -248,6 +248,10 @@ pub struct NuOpts {
|
||||||
pub envs: Option<Vec<(String, String)>>,
|
pub envs: Option<Vec<(String, String)>>,
|
||||||
pub collapse_output: Option<bool>,
|
pub collapse_output: Option<bool>,
|
||||||
pub use_ir: Option<bool>,
|
pub use_ir: Option<bool>,
|
||||||
|
// Note: At the time this was added, passing in a file path was more convenient. However,
|
||||||
|
// passing in file contents seems like a better API - consider this when adding new uses of
|
||||||
|
// this field.
|
||||||
|
pub env_config: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nu_run_test(opts: NuOpts, commands: impl AsRef<str>, with_std: bool) -> Outcome {
|
pub fn nu_run_test(opts: NuOpts, commands: impl AsRef<str>, with_std: bool) -> Outcome {
|
||||||
|
@ -278,8 +282,14 @@ pub fn nu_run_test(opts: NuOpts, commands: impl AsRef<str>, with_std: bool) -> O
|
||||||
command.envs(envs);
|
command.envs(envs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the user's config doesn't interfere with the tests
|
match opts.env_config {
|
||||||
command.arg("--no-config-file");
|
Some(path) => command.arg("--env-config").arg(path),
|
||||||
|
// TODO: This seems unnecessary: the code that runs for integration tests
|
||||||
|
// (run_commands) loads startup configs only if they are specified via flags explicitly or
|
||||||
|
// the shell is started as logging shell (which it is not in this case).
|
||||||
|
None => command.arg("--no-config-file"),
|
||||||
|
};
|
||||||
|
|
||||||
if !with_std {
|
if !with_std {
|
||||||
command.arg("--no-std-lib");
|
command.arg("--no-std-lib");
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ use log::warn;
|
||||||
use nu_cli::read_plugin_file;
|
use nu_cli::read_plugin_file;
|
||||||
use nu_cli::{eval_config_contents, eval_source};
|
use nu_cli::{eval_config_contents, eval_source};
|
||||||
use nu_path::canonicalize_with;
|
use nu_path::canonicalize_with;
|
||||||
|
#[allow(deprecated)]
|
||||||
|
use nu_path::NUSHELL_FOLDER;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
report_error, report_error_new, Config, ParseError, PipelineData, Spanned,
|
report_error, report_error_new, Config, ParseError, PipelineData, Spanned,
|
||||||
|
@ -17,7 +19,6 @@ use std::{
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) const NUSHELL_FOLDER: &str = "nushell";
|
|
||||||
const CONFIG_FILE: &str = "config.nu";
|
const CONFIG_FILE: &str = "config.nu";
|
||||||
const ENV_FILE: &str = "env.nu";
|
const ENV_FILE: &str = "env.nu";
|
||||||
const LOGINSHELL_FILE: &str = "login.nu";
|
const LOGINSHELL_FILE: &str = "login.nu";
|
||||||
|
@ -50,6 +51,7 @@ pub(crate) fn read_config_file(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let Some(mut config_path) = nu_path::config_dir() {
|
} else if let Some(mut config_path) = nu_path::config_dir() {
|
||||||
|
#[allow(deprecated)]
|
||||||
config_path.push(NUSHELL_FOLDER);
|
config_path.push(NUSHELL_FOLDER);
|
||||||
|
|
||||||
// Create config directory if it does not exist
|
// Create config directory if it does not exist
|
||||||
|
@ -135,6 +137,7 @@ pub(crate) fn read_loginshell_file(engine_state: &mut EngineState, stack: &mut S
|
||||||
|
|
||||||
// read and execute loginshell file if exists
|
// read and execute loginshell file if exists
|
||||||
if let Some(mut config_path) = nu_path::config_dir() {
|
if let Some(mut config_path) = nu_path::config_dir() {
|
||||||
|
#[allow(deprecated)]
|
||||||
config_path.push(NUSHELL_FOLDER);
|
config_path.push(NUSHELL_FOLDER);
|
||||||
config_path.push(LOGINSHELL_FILE);
|
config_path.push(LOGINSHELL_FILE);
|
||||||
|
|
||||||
|
@ -268,6 +271,7 @@ pub(crate) fn setup_config(
|
||||||
);
|
);
|
||||||
let result = catch_unwind(AssertUnwindSafe(|| {
|
let result = catch_unwind(AssertUnwindSafe(|| {
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
|
#[allow(deprecated)]
|
||||||
read_plugin_file(engine_state, plugin_file, NUSHELL_FOLDER);
|
read_plugin_file(engine_state, plugin_file, NUSHELL_FOLDER);
|
||||||
|
|
||||||
read_config_file(engine_state, stack, env_file, true);
|
read_config_file(engine_state, stack, env_file, true);
|
||||||
|
@ -301,6 +305,7 @@ pub(crate) fn set_config_path(
|
||||||
let config_path = match config_file {
|
let config_path = match config_file {
|
||||||
Some(s) => canonicalize_with(&s.item, cwd).ok(),
|
Some(s) => canonicalize_with(&s.item, cwd).ok(),
|
||||||
None => nu_path::config_dir().map(|mut p| {
|
None => nu_path::config_dir().map(|mut p| {
|
||||||
|
#[allow(deprecated)]
|
||||||
p.push(NUSHELL_FOLDER);
|
p.push(NUSHELL_FOLDER);
|
||||||
let mut p = canonicalize_with(&p, cwd).unwrap_or(p);
|
let mut p = canonicalize_with(&p, cwd).unwrap_or(p);
|
||||||
p.push(default_config_name);
|
p.push(default_config_name);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
use crate::config_files::NUSHELL_FOLDER;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
command,
|
command,
|
||||||
config_files::{self, setup_config},
|
config_files::{self, setup_config},
|
||||||
|
@ -8,6 +7,8 @@ use log::trace;
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
use nu_cli::read_plugin_file;
|
use nu_cli::read_plugin_file;
|
||||||
use nu_cli::{evaluate_commands, evaluate_file, evaluate_repl, EvaluateCommandsOpts};
|
use nu_cli::{evaluate_commands, evaluate_file, evaluate_repl, EvaluateCommandsOpts};
|
||||||
|
#[allow(deprecated)]
|
||||||
|
use nu_path::NUSHELL_FOLDER;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{EngineState, Stack},
|
engine::{EngineState, Stack},
|
||||||
report_error_new, PipelineData, Spanned,
|
report_error_new, PipelineData, Spanned,
|
||||||
|
@ -37,6 +38,7 @@ pub(crate) fn run_commands(
|
||||||
// if the --no-config-file(-n) flag is passed, do not load plugin, env, or config files
|
// if the --no-config-file(-n) flag is passed, do not load plugin, env, or config files
|
||||||
if parsed_nu_cli_args.no_config_file.is_none() {
|
if parsed_nu_cli_args.no_config_file.is_none() {
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
|
#[allow(deprecated)]
|
||||||
read_plugin_file(engine_state, parsed_nu_cli_args.plugin_file, NUSHELL_FOLDER);
|
read_plugin_file(engine_state, parsed_nu_cli_args.plugin_file, NUSHELL_FOLDER);
|
||||||
|
|
||||||
perf!("read plugins", start_time, use_color);
|
perf!("read plugins", start_time, use_color);
|
||||||
|
@ -125,6 +127,7 @@ pub(crate) fn run_file(
|
||||||
if parsed_nu_cli_args.no_config_file.is_none() {
|
if parsed_nu_cli_args.no_config_file.is_none() {
|
||||||
let start_time = std::time::Instant::now();
|
let start_time = std::time::Instant::now();
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
|
#[allow(deprecated)]
|
||||||
read_plugin_file(engine_state, parsed_nu_cli_args.plugin_file, NUSHELL_FOLDER);
|
read_plugin_file(engine_state, parsed_nu_cli_args.plugin_file, NUSHELL_FOLDER);
|
||||||
perf!("read plugins", start_time, use_color);
|
perf!("read plugins", start_time, use_color);
|
||||||
|
|
||||||
|
@ -216,7 +219,6 @@ pub(crate) fn run_repl(
|
||||||
let ret_val = evaluate_repl(
|
let ret_val = evaluate_repl(
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
config_files::NUSHELL_FOLDER,
|
|
||||||
parsed_nu_cli_args.execute,
|
parsed_nu_cli_args.execute,
|
||||||
parsed_nu_cli_args.no_std_lib,
|
parsed_nu_cli_args.no_std_lib,
|
||||||
entire_start_time,
|
entire_start_time,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user