mirror of
https://github.com/nushell/nushell
synced 2025-01-12 13:19:01 +00:00
Add config.history.path
This was originally brought up in #11962, but closed in favour of the more general #10100. However this commit doesn't address the broader theme of using alternate XDG vars for the default history path. Here is the updated `sample_config.nu` documentation for the field: > # When this config doesn't exist or is set to null, then a default path is used > # based on the OS and ENV. > # > # You will likely want to match the file extension to the `file_format` setting, > # therefore ".txt" or ".sqlite". > # > # Nushell will create the file if it doesn't exist. However it won't create the > # directory path, and will error if it doesn't exist. > $env.config.history.path = null
This commit is contained in:
parent
4d3283e235
commit
85772e0407
7 changed files with 82 additions and 13 deletions
|
@ -45,8 +45,10 @@ impl Command for History {
|
||||||
return Ok(PipelineData::empty());
|
return Ok(PipelineData::empty());
|
||||||
};
|
};
|
||||||
// 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`
|
||||||
let Some(history_path) = history.file_path() else {
|
let result = history.file_path(Some(call.head));
|
||||||
return Err(ShellError::ConfigDirNotFound { span: Some(head) });
|
let history_path = match result {
|
||||||
|
Ok(path) => path,
|
||||||
|
Err(err) => return Err(err),
|
||||||
};
|
};
|
||||||
|
|
||||||
if call.has_flag(engine_state, stack, "clear")? {
|
if call.has_flag(engine_state, stack, "clear")? {
|
||||||
|
|
|
@ -73,10 +73,10 @@ Note that history item IDs are ignored when importing from file."#
|
||||||
let Some(history) = engine_state.history_config() else {
|
let Some(history) = engine_state.history_config() else {
|
||||||
return ok;
|
return ok;
|
||||||
};
|
};
|
||||||
let Some(current_history_path) = history.file_path() else {
|
let result = history.file_path(Some(call.head));
|
||||||
return Err(ShellError::ConfigDirNotFound {
|
let current_history_path = match result {
|
||||||
span: Some(call.head),
|
Ok(path) => path,
|
||||||
});
|
Err(err) => return Err(err),
|
||||||
};
|
};
|
||||||
if let Some(bak_path) = backup(¤t_history_path)? {
|
if let Some(bak_path) = backup(¤t_history_path)? {
|
||||||
println!("Backed history to {}", bak_path.display());
|
println!("Backed history to {}", bak_path.display());
|
||||||
|
|
|
@ -1126,7 +1126,7 @@ fn setup_history(
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(path) = history.file_path() {
|
if let Ok(path) = history.file_path(None) {
|
||||||
return update_line_editor_history(
|
return update_line_editor_history(
|
||||||
engine_state,
|
engine_state,
|
||||||
path,
|
path,
|
||||||
|
@ -1401,7 +1401,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 = history.file_path().unwrap();
|
let history_path = history.file_path(None).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(
|
||||||
|
|
|
@ -37,20 +37,54 @@ impl UpdateFromValue for HistoryFileFormat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct HistoryConfig {
|
pub struct HistoryConfig {
|
||||||
pub max_size: i64,
|
pub max_size: i64,
|
||||||
pub sync_on_enter: bool,
|
pub sync_on_enter: bool,
|
||||||
pub file_format: HistoryFileFormat,
|
pub file_format: HistoryFileFormat,
|
||||||
pub isolation: bool,
|
pub isolation: bool,
|
||||||
|
pub path: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HistoryConfig {
|
impl HistoryConfig {
|
||||||
pub fn file_path(&self) -> Option<std::path::PathBuf> {
|
pub fn file_path(&self, call_head: Option<Span>) -> Result<std::path::PathBuf, ShellError> {
|
||||||
nu_path::nu_config_dir().map(|mut history_path| {
|
match self.path.clone() {
|
||||||
|
None => self.system_defined_file_path(call_head),
|
||||||
|
Some(path) => self.user_defined_file_path(path, call_head),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn system_defined_file_path(
|
||||||
|
&self,
|
||||||
|
call_head: Option<Span>,
|
||||||
|
) -> Result<std::path::PathBuf, ShellError> {
|
||||||
|
let system_path = nu_path::nu_config_dir().map(|mut history_path| {
|
||||||
history_path.push(self.file_format.default_file_name());
|
history_path.push(self.file_format.default_file_name());
|
||||||
history_path.into()
|
history_path.into()
|
||||||
})
|
});
|
||||||
|
match system_path {
|
||||||
|
Some(path) => Ok(path),
|
||||||
|
None => Err(ShellError::ConfigDirNotFound { span: call_head }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn user_defined_file_path(
|
||||||
|
&self,
|
||||||
|
path_from_config: String,
|
||||||
|
call_head: Option<Span>,
|
||||||
|
) -> Result<std::path::PathBuf, ShellError> {
|
||||||
|
let error = Err(ShellError::HistoryDirNotFound { span: call_head });
|
||||||
|
|
||||||
|
let user_path = std::path::Path::new(&path_from_config);
|
||||||
|
let dir_path = match user_path.parent() {
|
||||||
|
Some(path) => path,
|
||||||
|
None => return error,
|
||||||
|
};
|
||||||
|
|
||||||
|
match dir_path.exists() {
|
||||||
|
true => Ok(user_path.into()),
|
||||||
|
false => error,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +95,7 @@ impl Default for HistoryConfig {
|
||||||
sync_on_enter: true,
|
sync_on_enter: true,
|
||||||
file_format: HistoryFileFormat::Plaintext,
|
file_format: HistoryFileFormat::Plaintext,
|
||||||
isolation: false,
|
isolation: false,
|
||||||
|
path: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,6 +119,11 @@ impl UpdateFromValue for HistoryConfig {
|
||||||
"sync_on_enter" => self.sync_on_enter.update(val, path, errors),
|
"sync_on_enter" => self.sync_on_enter.update(val, path, errors),
|
||||||
"max_size" => self.max_size.update(val, path, errors),
|
"max_size" => self.max_size.update(val, path, errors),
|
||||||
"file_format" => self.file_format.update(val, path, errors),
|
"file_format" => self.file_format.update(val, path, errors),
|
||||||
|
"path" => match val {
|
||||||
|
Value::Nothing { .. } => self.path = None,
|
||||||
|
Value::String { val, .. } => self.path = Some(val.clone()),
|
||||||
|
_ => errors.type_mismatch(path, Type::custom("path or nothing"), val),
|
||||||
|
},
|
||||||
_ => errors.unknown_option(path, val),
|
_ => errors.unknown_option(path, val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -762,7 +762,7 @@ impl EngineState {
|
||||||
|
|
||||||
/// Returns the configuration settings for command history or `None` if history is disabled
|
/// Returns the configuration settings for command history or `None` if history is disabled
|
||||||
pub fn history_config(&self) -> Option<HistoryConfig> {
|
pub fn history_config(&self) -> Option<HistoryConfig> {
|
||||||
self.history_enabled.then(|| self.config.history)
|
self.history_enabled.then(|| self.config.history.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_var(&self, var_id: VarId) -> &Variable {
|
pub fn get_var(&self, var_id: VarId) -> &Variable {
|
||||||
|
|
|
@ -1434,6 +1434,20 @@ On Windows, this would be %USERPROFILE%\AppData\Roaming"#
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// The config directory could not be found
|
||||||
|
#[error("The base directory for the history file could not be found")]
|
||||||
|
#[diagnostic(
|
||||||
|
code(nu::shell::history_dir_not_found),
|
||||||
|
help(
|
||||||
|
r#"A user-defined path for the history file was given in the config, but the base directory for the path does not exist.
|
||||||
|
Please create it."#
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
HistoryDirNotFound {
|
||||||
|
#[label = "Could not find history directory"]
|
||||||
|
span: Option<Span>,
|
||||||
|
},
|
||||||
|
|
||||||
/// XDG_CONFIG_HOME was set to an invalid path
|
/// XDG_CONFIG_HOME was set to an invalid path
|
||||||
#[error("$env.XDG_CONFIG_HOME ({xdg}) is invalid, using default config directory instead: {default}")]
|
#[error("$env.XDG_CONFIG_HOME ({xdg}) is invalid, using default config directory instead: {default}")]
|
||||||
#[diagnostic(
|
#[diagnostic(
|
||||||
|
|
|
@ -63,6 +63,19 @@ $env.config.history.sync_on_enter = true
|
||||||
# This setting only applies to SQLite-backed history
|
# This setting only applies to SQLite-backed history
|
||||||
$env.config.history.isolation = true
|
$env.config.history.isolation = true
|
||||||
|
|
||||||
|
# path (string):
|
||||||
|
# The absolute path to the history file.
|
||||||
|
#
|
||||||
|
# When this config doesn't exist or is set to null, then a default path is used
|
||||||
|
# based on the OS and ENV.
|
||||||
|
#
|
||||||
|
# You will likely want to match the file extension to the `file_format` setting,
|
||||||
|
# therefore ".txt" or ".sqlite".
|
||||||
|
#
|
||||||
|
# Nushell will create the file if it doesn't exist. However it won't create the
|
||||||
|
# directory path, and will error if it doesn't exist.
|
||||||
|
$env.config.history.path = null
|
||||||
|
|
||||||
# ----------------------
|
# ----------------------
|
||||||
# Miscellaneous Settings
|
# Miscellaneous Settings
|
||||||
# ----------------------
|
# ----------------------
|
||||||
|
|
Loading…
Reference in a new issue