Merge pull request #840 from zjp-CN/win

Fix multiple paths: define the platform-specific join separator
This commit is contained in:
Denis Isidoro 2023-12-10 06:20:08 -03:00 committed by GitHub
commit b560ba572e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 121 additions and 38 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
/target
**/*.rs.bk
navi.log

11
Cargo.lock generated
View file

@ -244,6 +244,12 @@ dependencies = [
"synstructure",
]
[[package]]
name = "dunce"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
[[package]]
name = "edit"
version = "0.1.4"
@ -412,9 +418,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.14"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
@ -455,6 +461,7 @@ dependencies = [
"crossterm",
"dns_common",
"dns_common_derive",
"dunce",
"edit",
"etcetera",
"lazy_static",

View file

@ -37,6 +37,9 @@ dns_common_derive = { version = "0.2.1" }
dns_common = { version = "0.2.1", default-features = false, features = ["yaml", "json"] }
unicode-width = "0.1.10"
[target.'cfg(windows)'.dependencies]
dunce = "1"
[lib]
name = "navi"
path = "src/lib.rs"

View file

@ -29,3 +29,9 @@ Run the following command to generate a config file with the default parameters:
```sh
navi info config-example > "$(navi info config-path)"
```
### Logging
The log file will be created under the same directory where the config locates.
And you can use the `RUST_LOG` env to set the log level, e.g. `RUST_LOG=debug navi`.

View file

@ -20,13 +20,16 @@ finder:
# cheats:
# paths:
# - /path/to/some/dir
# - /path/to/another/dir
# - /path/to/some/dir # on unix-like os
# - F:\\path\\to\\dir # on Windows
# path: /path/to/some/dir # (DEPRECATED) equivalent to the --path option
# search:
# tags: git,!checkout # equivalent to the --tag-rules option
shell:
command: bash # shell used for shell out. possible values: bash, zsh, dash, ...
# Shell used for shell out. Possible values: bash, zsh, dash, ...
# For Windows, use `cmd.exe` instead.
command: bash
# finder_command: bash # similar, but for fzf's internals

View file

@ -1,6 +1,6 @@
extern crate navi;
use std::fmt::Debug;
use dns_common::prelude::*;
use thiserror::Error;
#[derive(Error, Debug)]
@ -24,6 +24,36 @@ impl FileAnIssue {
}
}
fn main() -> Result<(), anyhow::Error> {
navi::handle().map_err(|e| FileAnIssue::new(e).into())
fn main() -> anyhow::Result<()> {
if let Err(err) = init_logger() {
// may need redir stderr to a file to show this log initialization error
eprintln!("failed to initialize logging: {err:?}");
}
navi::handle().map_err(|e| {
error!("{e:?}");
FileAnIssue::new(e).into()
})
}
fn init_logger() -> anyhow::Result<()> {
const FILE_NAME: &str = "navi.log";
let mut file = navi::default_config_pathbuf()?;
file.set_file_name(FILE_NAME);
// If config path doesn't exist, navi won't log.
if file.parent().map(|p| !p.exists()).unwrap_or(true) {
return Ok(());
}
let writer = std::fs::File::create(&file).with_context(|| format!("{file:?} is not created"))?;
tracing::subscriber::set_global_default(
tracing_subscriber::fmt()
.with_ansi(false)
.with_writer(writer)
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.finish(),
)?;
debug!("tracing initialized");
Ok(())
}

View file

@ -41,9 +41,10 @@ fn prompt_finder(
}
}
let child = shell::out()
.stdout(Stdio::piped())
.arg(suggestion_command)
let mut cmd = shell::out();
cmd.stdout(Stdio::piped()).arg(suggestion_command);
debug!(cmd = ?cmd);
let child = cmd
.spawn()
.map_err(|e| ShellSpawnError::new(suggestion_command, e))?;
@ -236,9 +237,10 @@ pub fn act(
clipboard::copy(interpolated_snippet)?;
}
_ => {
shell::out()
.arg(&interpolated_snippet[..])
.spawn()
let mut cmd = shell::out();
cmd.arg(&interpolated_snippet[..]);
debug!(cmd = ?cmd);
cmd.spawn()
.map_err(|e| ShellSpawnError::new(&interpolated_snippet[..], e))?
.wait()
.context("bash was not running")?;

View file

@ -13,6 +13,7 @@ use crate::welcome;
pub fn init(fetcher: Box<dyn Fetcher>) -> Result<()> {
let config = &CONFIG;
let opts = FinderOpts::snippet_default();
debug!("opts = {opts:#?}");
// let fetcher = config.fetcher();
let (raw_selection, (variables, files)) = config
@ -32,6 +33,7 @@ pub fn init(fetcher: Box<dyn Fetcher>) -> Result<()> {
})
.context("Failed getting selection and variables from finder")?;
debug!(raw_selection = ?raw_selection);
let extractions = deser::terminal::read(&raw_selection, config.best_match());
if extractions.is_err() {
@ -44,7 +46,9 @@ pub fn init(fetcher: Box<dyn Fetcher>) -> Result<()> {
}
pub fn get_fetcher() -> Result<Box<dyn Fetcher>> {
match CONFIG.source() {
let source = CONFIG.source();
debug!(source = ?source);
match source {
Source::Cheats(query) => {
let lines = cheatsh::call(&query)?;
let fetcher = Box::new(StaticFetcher::new(lines));

View file

@ -12,6 +12,7 @@ use crate::prelude::*;
pub fn handle() -> Result<()> {
use crate::config::Command::*;
debug!("CONFIG = {:#?}", &*CONFIG);
match CONFIG.cmd() {
None => commands::core::main(),

View file

@ -30,11 +30,10 @@ impl Runnable for Input {
if !extra.is_empty() {
print!("");
shell::out()
.arg(extra)
.spawn()
.map_err(|e| ShellSpawnError::new(extra, e))?
.wait()?;
let mut cmd = shell::out();
cmd.arg(extra);
debug!(?cmd);
cmd.spawn().map_err(|e| ShellSpawnError::new(extra, e))?.wait()?;
}
}

View file

@ -78,6 +78,11 @@ fn follow_symlink(pathbuf: PathBuf) -> Result<PathBuf> {
fn exe_pathbuf() -> Result<PathBuf> {
let pathbuf = std::env::current_exe().context("Unable to acquire executable's path")?;
#[cfg(target_family = "windows")]
let pathbuf = dunce::canonicalize(pathbuf)?;
debug!(current_exe = ?pathbuf);
follow_symlink(pathbuf)
}

View file

@ -117,6 +117,7 @@ pub enum Command {
Info(commands::info::Input),
}
#[derive(Debug)]
pub enum Source {
Filesystem(Option<String>),
Tldr(String),

View file

@ -2,6 +2,7 @@ use crate::env_var;
use crate::finder::FinderChoice;
use crate::prelude::*;
#[derive(Debug)]
pub struct EnvConfig {
pub config_yaml: Option<String>,
pub config_path: Option<String>,

View file

@ -12,6 +12,7 @@ use yaml::YamlConfig;
lazy_static! {
pub static ref CONFIG: Config = Config::new();
}
#[derive(Debug)]
pub struct Config {
yaml: YamlConfig,
clap: ClapConfig,
@ -69,7 +70,7 @@ impl Config {
if p.is_empty() {
None
} else {
Some(p.join(":"))
Some(p.join(crate::filesystem::JOIN_SEPARATOR))
}
})
.or_else(|| self.yaml.cheats.path.clone())

View file

@ -6,7 +6,7 @@ use crate::prelude::*;
use crossterm::style::Color as TerminalColor;
use serde::de;
#[derive(Deserialize)]
#[derive(Deserialize, Debug)]
pub struct Color(#[serde(deserialize_with = "color_deserialize")] TerminalColor);
impl Color {
@ -24,7 +24,7 @@ where
.map_err(|_| de::Error::custom(format!("Failed to deserialize color: {s}")))
}
#[derive(Deserialize)]
#[derive(Deserialize, Debug)]
#[serde(default)]
pub struct ColorWidth {
pub color: Color,
@ -32,7 +32,7 @@ pub struct ColorWidth {
pub min_width: u16,
}
#[derive(Deserialize)]
#[derive(Deserialize, Debug)]
#[serde(default)]
pub struct Style {
pub tag: ColorWidth,
@ -40,7 +40,7 @@ pub struct Style {
pub snippet: ColorWidth,
}
#[derive(Deserialize)]
#[derive(Deserialize, Debug)]
#[serde(default)]
pub struct Finder {
#[serde(deserialize_with = "finder_deserialize")]
@ -58,27 +58,27 @@ where
.map_err(|_| de::Error::custom(format!("Failed to deserialize finder: {s}")))
}
#[derive(Deserialize, Default)]
#[derive(Deserialize, Default, Debug)]
#[serde(default)]
pub struct Cheats {
pub path: Option<String>,
pub paths: Vec<String>,
}
#[derive(Deserialize, Default)]
#[derive(Deserialize, Default, Debug)]
#[serde(default)]
pub struct Search {
pub tags: Option<String>,
}
#[derive(Deserialize)]
#[derive(Deserialize, Debug)]
#[serde(default)]
pub struct Shell {
pub command: String,
pub finder_command: Option<String>,
}
#[derive(Deserialize, Default)]
#[derive(Deserialize, Default, Debug)]
#[serde(default)]
pub struct YamlConfig {
pub style: Style,

View file

@ -12,6 +12,13 @@ use std::path::MAIN_SEPARATOR;
use walkdir::WalkDir;
/// Multiple paths are joint by a platform-specific separator.
/// FIXME: it's actually incorrect to assume a path doesn't containing this separator
#[cfg(target_family = "windows")]
pub const JOIN_SEPARATOR: &str = ";";
#[cfg(not(target_family = "windows"))]
pub const JOIN_SEPARATOR: &str = ":";
pub fn all_cheat_files(path: &Path) -> Vec<String> {
WalkDir::new(path)
.follow_links(true)
@ -23,7 +30,7 @@ pub fn all_cheat_files(path: &Path) -> Vec<String> {
}
fn paths_from_path_param(env_var: &str) -> impl Iterator<Item = &str> {
env_var.split(':').filter(|folder| folder != &"")
env_var.split(JOIN_SEPARATOR).filter(|folder| folder != &"")
}
fn compiled_default_path(path: Option<&str>) -> Option<PathBuf> {
@ -125,6 +132,7 @@ fn interpolate_paths(paths: String) -> String {
newtext
}
#[derive(Debug)]
pub struct Fetcher {
path: Option<String>,
files: RefCell<Vec<String>>,
@ -165,7 +173,9 @@ impl fetcher::Fetcher for Fetcher {
None => folder.to_string(),
};
let folder_pathbuf = PathBuf::from(interpolated_folder);
for file in all_cheat_files(&folder_pathbuf) {
let cheat_files = all_cheat_files(&folder_pathbuf);
debug!("read cheat files in `{folder_pathbuf:?}`: {cheat_files:#?}");
for file in cheat_files {
self.files.borrow_mut().push(file.clone());
let index = self.files.borrow().len() - 1;
let read_file_result = {
@ -180,6 +190,7 @@ impl fetcher::Fetcher for Fetcher {
}
}
debug!("FilesystemFetcher = {self:#?}");
Ok(found_something)
}
@ -280,4 +291,12 @@ mod tests {
assert_eq!(expected, cheats.to_string_lossy().to_string())
}
#[test]
#[cfg(target_family = "windows")]
fn multiple_paths() {
let p = r#"C:\Users\Administrator\AppData\Roaming\navi\config.yaml"#;
let paths = &[p; 2].join(JOIN_SEPARATOR);
assert_eq!(paths_from_path_param(paths).collect::<Vec<_>>(), [p; 2]);
}
}

View file

@ -152,11 +152,13 @@ impl FinderChoice {
});
}
let child = command
command
.env("SHELL", CONFIG.finder_shell())
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn();
.stdout(Stdio::piped());
debug!(cmd = ?command);
let child = command.spawn();
let mut child = match child {
Ok(x) => x,

View file

@ -1,7 +1,5 @@
#[macro_use]
extern crate lazy_static;
// #[macro_use]
// extern crate anyhow;
mod clients;
mod commands;
@ -16,4 +14,4 @@ mod prelude;
mod structures;
mod welcome;
pub use commands::handle;
pub use {commands::handle, filesystem::default_config_pathbuf};