mirror of
https://github.com/denisidoro/navi
synced 2024-11-24 20:43:06 +00:00
Merge pull request #840 from zjp-CN/win
Fix multiple paths: define the platform-specific join separator
This commit is contained in:
commit
b560ba572e
18 changed files with 121 additions and 38 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
/target
|
||||
**/*.rs.bk
|
||||
navi.log
|
||||
|
|
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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")?;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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(),
|
||||
|
||||
|
|
|
@ -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()?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -117,6 +117,7 @@ pub enum Command {
|
|||
Info(commands::info::Input),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Source {
|
||||
Filesystem(Option<String>),
|
||||
Tldr(String),
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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};
|
||||
|
|
Loading…
Reference in a new issue