summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyohei Uto <im@kyoheiu.dev>2023-11-02 04:48:03 +0900
committerGitHub <noreply@github.com>2023-11-02 04:48:03 +0900
commitefa494ba36521da858e9d9032574ce6152e09ec6 (patch)
treebc571c648dcaa7e71f49d5d51c7cabe1dd4b74a0
parentd12f8c66cfba3fb87c009bc86b8ffe2a29983ad6 (diff)
parent9b846bd9b03fbe4d43108666462ac78553d8e5fa (diff)
Merge pull request #250 from kyoheiu/developv2.10.0
v2.10.0
-rw-r--r--CHANGELOG.md7
-rw-r--r--Cargo.lock30
-rw-r--r--Cargo.toml2
-rw-r--r--README.md10
-rw-r--r--src/errors.rs4
-rw-r--r--src/layout.rs75
-rw-r--r--src/state.rs10
7 files changed, 85 insertions, 53 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c08aaf2..0f07bc7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,13 @@
## Unreleased
+## v2.10.0 (2023-11-01)
+
+### Added
+- `bat` integration: If `bat` installed, felix automatically adds syntax highlighting to the text preview.
+ - Add `has_bat` field to `State`.
+ - Add `FxError::InvalidPath` to handle invalid unicode in file path.
+
## v2.9.0 (2023-10-22)
### Added
diff --git a/Cargo.lock b/Cargo.lock
index ece23fe..003ffd4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -170,9 +170,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
[[package]]
name = "cpufeatures"
-version = "0.2.10"
+version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fbc60abd742b35f2492f808e1abbb83d45f72db402e14c55057edc9c7b1e9e4"
+checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
dependencies = [
"libc",
]
@@ -188,9 +188,9 @@ dependencies = [
[[package]]
name = "crc-catalog"
-version = "2.2.0"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484"
+checksum = "4939f9ed1444bd8c896d37f3090012fa6e7834fe84ef8c9daa166109515732f9"
[[package]]
name = "crc32fast"
@@ -330,7 +330,7 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "felix"
-version = "2.9.0"
+version = "2.10.0"
dependencies = [
"bwrap",
"chrono",
@@ -470,9 +470,9 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "2.0.2"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897"
+checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
dependencies = [
"equivalent",
"hashbrown",
@@ -602,9 +602,9 @@ dependencies = [
[[package]]
name = "mio"
-version = "0.8.8"
+version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
+checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0"
dependencies = [
"libc",
"log",
@@ -836,18 +836,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
-version = "1.0.189"
+version = "1.0.190"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537"
+checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.189"
+version = "1.0.190"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5"
+checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
dependencies = [
"proc-macro2",
"quote",
@@ -856,9 +856,9 @@ dependencies = [
[[package]]
name = "serde_yaml"
-version = "0.9.25"
+version = "0.9.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574"
+checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c"
dependencies = [
"indexmap",
"itoa",
diff --git a/Cargo.toml b/Cargo.toml
index c9c9272..24e3eb4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "felix"
-version = "2.9.0"
+version = "2.10.0"
authors = ["Kyohei Uto <im@kyoheiu.dev>"]
edition = "2021"
description = "tui file manager with vim-like key mapping"
diff --git a/README.md b/README.md
index 7c99793..0c56d33 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,13 @@ For more detailed document, visit https://kyoheiu.dev/felix.
## New release
+## v2.10.0 (2023-11-01)
+
+### Added
+- `bat` integration: If `bat` installed, felix automatically adds syntax highlighting to the text preview.
+ - Add `has_bat` field to `State`.
+ - Add `FxError::InvalidPath` to handle invalid unicode in file path.
+
## v2.9.0 (2023-10-22)
### Added
@@ -115,13 +122,14 @@ source <(command fx --init)
*If this is not set, exiting to LWD will fail and show the error message.*
### Others
-In addition, you can use felix more conveniently by installing these two apps:
+In addition, you can use felix more conveniently by installing these apps:
- [zoxide](https://github.com/ajeetdsouza/zoxide): A smarter `cd` command, which
enables you to jump to a directory that matches the keyword in felix.
- [chafa](https://hpjansson.org/chafa/): Terminal graphics for the 21st century,
by which you can preview images in felix. _**chafa must be v1.10.0 or
later.**_
+- [bat](https://github.com/sharkdp/bat): A *cat(1)* clone. Add syntax highlighting to the text preview with bat.
These apps do not need any configuration to use with felix!
diff --git a/src/errors.rs b/src/errors.rs
index 112f2bd..fa58e79 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -18,6 +18,7 @@ pub enum FxError {
TooSmallWindowSize,
Log(String),
Unpack(String),
+ InvalidPath,
Panic,
#[cfg(any(target_os = "linux", target_os = "netbsd"))]
Nix(String),
@@ -29,7 +30,7 @@ impl std::fmt::Display for FxError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let printable = match self {
FxError::Arg(s) => s.to_owned(),
- FxError::TerminalSizeDetection => "Error: Cannot detect terminal size.".to_owned(),
+ FxError::TerminalSizeDetection => "Error: Cannot detect terminal size".to_owned(),
FxError::Io(s) => s.to_owned(),
FxError::Dirs(s) => s.to_owned(),
FxError::GetItem => "Error: Cannot get item info".to_owned(),
@@ -46,6 +47,7 @@ impl std::fmt::Display for FxError {
FxError::TooSmallWindowSize => "Error: Too small window size".to_owned(),
FxError::Log(s) => s.to_owned(),
FxError::Unpack(s) => s.to_owned(),
+ FxError::InvalidPath => "Error: Path may contain invalid unicode".to_owned(),
FxError::Panic => "Error: felix panicked".to_owned(),
#[cfg(any(target_os = "linux", target_os = "netbsd"))]
FxError::Nix(s) => s.to_owned(),
diff --git a/src/layout.rs b/src/layout.rs
index 25c2921..56e92b5 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -32,6 +32,7 @@ pub struct Layout {
pub preview_start: (u16, u16),
pub preview_space: (u16, u16),
pub has_chafa: bool,
+ pub has_bat: bool,
pub is_kitty: bool,
}
@@ -145,7 +146,7 @@ impl Layout {
}
Some(PreviewType::Image) => {
if self.has_chafa {
- if let Err(e) = self.preview_image(item, y) {
+ if let Err(e) = self.preview_image(item) {
print_warning(e, y);
}
} else {
@@ -160,7 +161,9 @@ impl Layout {
}
}
Some(PreviewType::Text) => {
- self.preview_text(item);
+ if let Err(e) = self.preview_text(item) {
+ print_warning(e, y);
+ }
}
Some(PreviewType::Binary) => {
print!("(Binary file)");
@@ -184,14 +187,35 @@ impl Layout {
print!("{}", file_name);
}
- fn preview_text(&self, item: &ItemInfo) {
+ fn preview_text(&self, item: &ItemInfo) -> Result<(), FxError> {
if let Some(content) = &item.content {
- self.print_txt_in_preview_area(
- item,
- &format_txt(content, self.preview_space.0, false),
- false,
- );
+ if !self.has_bat {
+ self.print_txt_in_preview_area(
+ item,
+ &format_txt(content, self.preview_space.0, false),
+ );
+ } else {
+ let path = item.file_path.to_str().ok_or(FxError::InvalidPath)?;
+ let output = std::process::Command::new("bat")
+ .args([
+ path,
+ "-fpP",
+ "--wrap",
+ "character",
+ "--terminal-width",
+ &format!("{}", self.preview_space.0),
+ ])
+ .output()?
+ .stdout;
+ let content = String::from_utf8(output)?;
+ let content = content
+ .split('\n')
+ .map(|x| x.to_owned())
+ .collect::<Vec<String>>();
+ self.print_txt_in_preview_area(item, &content);
+ }
}
+ Ok(())
}
fn preview_directory(&self, item: &ItemInfo) {
@@ -203,17 +227,11 @@ impl Layout {
self.print_txt_in_preview_area(
item,
&format_txt(&contents, self.preview_space.0, false),
- false,
);
}
}
- fn print_txt_in_preview_area(
- &self,
- item: &ItemInfo,
- content: &[String],
- syntex_highlight: bool,
- ) {
+ fn print_txt_in_preview_area(&self, item: &ItemInfo, content: &[String]) {
match self.split {
Split::Vertical => {
for (i, line) in content.iter().enumerate() {
@@ -223,12 +241,8 @@ impl Layout {
let sum = (i - item.preview_scroll) as u16;
let row = self.preview_start.1 + sum;
move_to(self.preview_start.0, row);
- if syntex_highlight {
- print!("{}", line);
- } else {
- set_color(&TermColor::ForeGround(&Colorname::LightBlack));
- print!("{}", line);
- }
+ set_color(&TermColor::ForeGround(&Colorname::LightBlack));
+ print!("{}", line);
if sum == self.preview_space.1 - 1 {
break;
}
@@ -242,12 +256,8 @@ impl Layout {
let sum = (i - item.preview_scroll) as u16;
let row = self.preview_start.1 + sum;
move_to(1, row);
- if syntex_highlight {
- print!("{}", line);
- } else {
- set_color(&TermColor::ForeGround(&Colorname::LightBlack));
- print!("{}", line);
- }
+ set_color(&TermColor::ForeGround(&Colorname::LightBlack));
+ print!("{}", line);
if row == self.terminal_row + self.preview_space.1 {
break;
}
@@ -258,7 +268,7 @@ impl Layout {
}
/// Print text preview on the right half of the terminal (Experimental).
- fn preview_image(&self, item: &ItemInfo, y: u16) -> Result<(), FxError> {
+ fn preview_image(&self, item: &ItemInfo) -> Result<(), FxError> {
let wxh = match self.split {
Split::Vertical => {
format!("--size={}x{}", self.preview_space.0, self.preview_space.1)
@@ -272,14 +282,9 @@ impl Layout {
}
};
- let file_path = item.file_path.to_str();
- if file_path.is_none() {
- print_warning("Cannot read the file path correctly.", y);
- return Ok(());
- }
-
+ let file_path = item.file_path.to_str().ok_or(FxError::InvalidPath)?;
let output = std::process::Command::new("chafa")
- .args(["--animate=false", &wxh, file_path.unwrap()])
+ .args(["--animate=false", &wxh, file_path])
.output()?
.stdout;
let output = String::from_utf8(output)?;
diff --git a/src/state.rs b/src/state.rs
index e7c757b..bbfd149 100644
--- a/src/state.rs
+++ b/src/state.rs
@@ -262,6 +262,7 @@ impl State {
let split = session.split.unwrap_or(Split::Vertical);
+ let has_bat = check_bat();
let has_chafa = check_chafa();
let has_zoxide = check_zoxide();
let is_kitty = check_kitty_support();
@@ -316,6 +317,7 @@ impl State {
Split::Vertical => (0, 0),
Split::Horizontal => (0, 0),
},
+ has_bat,
has_chafa,
is_kitty,
},
@@ -1941,6 +1943,14 @@ fn read_item(entry: fs::DirEntry) -> ItemInfo {
// Ok(result)
// }
+/// Check if bat is installed.
+fn check_bat() -> bool {
+ std::process::Command::new("bat")
+ .arg("--help")
+ .output()
+ .is_ok()
+}
+
/// Check if chafa is installed.
fn check_chafa() -> bool {
std::process::Command::new("chafa")