summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyohei Uto <im@kyoheiu.dev>2023-02-12 07:15:27 +0900
committerGitHub <noreply@github.com>2023-02-12 07:15:27 +0900
commit053c4dfcfb99f6cd723e9934d5a191ec47aef0ff (patch)
tree30725af83c770ca14672f92e1aacc58b0823e8a2
parent43923f20527e24533a07a3f86f5014943d2e8556 (diff)
parentbf06a8a12fa739c5a6b60595ba978b14d65cfda8 (diff)
Merge pull request #182 from kyoheiu/developv2.2.5
v2.2.5
-rw-r--r--CHANGELOG.md16
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rw-r--r--README.md25
-rw-r--r--config.yaml5
-rw-r--r--src/config.rs7
-rw-r--r--src/errors.rs4
-rw-r--r--src/functions.rs17
-rw-r--r--src/help.rs2
-rw-r--r--src/run.rs99
-rw-r--r--src/state.rs69
-rw-r--r--src/term.rs4
12 files changed, 155 insertions, 97 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9edad50..176b87e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,22 @@
## Unreleased
+## v2.2.5 (2023-02-12)
+
+### Added
+- Allow renaming even when item name contains non-ascii chars (i.e. wide chars).
+- Key command with arguments is now supported: For example,
+ ```
+ exec:
+ 'feh -.':
+ [jpg, jpeg, png, gif, svg, hdr]
+ ```
+ this configuration enables you to execute `feh -. <item path>` by `Enter | l | Right`, or `o`.
+- Check for out-of-boundary of the cursor at the top of loop.
+
+### Fixed
+- Display when using in kitty: Correctly show the cursor and preview.
+
## v2.2.4 (2023-02-01)
### Fixed
diff --git a/Cargo.lock b/Cargo.lock
index b8bbca7..b5dff0e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -371,7 +371,7 @@ checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "felix"
-version = "2.2.4"
+version = "2.2.5"
dependencies = [
"chrono",
"content_inspector",
diff --git a/Cargo.toml b/Cargo.toml
index af62d8b..cd3cf01 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "felix"
-version = "2.2.4"
+version = "2.2.5"
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 2252e61..536ddf4 100644
--- a/README.md
+++ b/README.md
@@ -23,22 +23,21 @@ For more detailed document, visit https://kyoheiu.dev/felix.
## New release
-## v2.2.4 (2023-02-01)
+## v2.2.5 (2023-02-12)
-### Fixed
-- Disable remove_and_yank in the trash dir.
-- Clear selection in the select mode if something fails.
-- Cursor move after deleting multiple items in select mode.
-
-## v2.2.3 (2023-01-20)
+### Added
+- Allow renaming even when item name contains non-ascii chars (i.e. wide chars).
+- Key command with arguments is now supported: For example,
+ ```
+ exec:
+ 'feh -.':
+ [jpg, jpeg, png, gif, svg, hdr]
+ ```
+ this configuration enables you to execute `feh -. <item path>` by `Enter | l | Right`, or `o`.
+- Check for out-of-boundary of the cursor at the top of loop.
### Fixed
-- Wide chars handling: Using unicode_width, now felix can properly split file name or previewed texts.
-- Preview space height: When horizontally split, image preview could break the layout. Fixed this by adjusting the height.
-
-### Added
-- `chafa`'s minimal supported version: >= v1.10.0
-- Add pacman installation.
+- Display when using in kitty: Correctly show the cursor and preview.
For more details, see `CHANGELOG.md`.
diff --git a/config.yaml b/config.yaml
index f55710c..36420fb 100644
--- a/config.yaml
+++ b/config.yaml
@@ -5,11 +5,12 @@
# (Optional)
# key (the command you want to use when opening file): [values] (extensions)
+# In the key, You can use arguments.
# exec:
-# feh:
-# [jpg, jpeg, png, gif, svg]
# zathura:
# [pdf]
+# 'feh -.':
+# [jpg, jpeg, png, gif, svg, hdr]
# (Optional)
# Whether to use syntax highlighting in the preview mode.
diff --git a/src/config.rs b/src/config.rs
index 25cf4b7..5e216c5 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -14,12 +14,13 @@ pub const CONFIG_EXAMPLE: &str = "# (Optional)
# default: nvim
# (Optional)
-# key (the command you want to use): [values] (extensions)
+# key (the command you want to use when opening files): [values] (extensions)
+# In the key, You can use arguments.
# exec:
-# feh:
-# [jpg, jpeg, png, gif, svg]
# zathura:
# [pdf]
+# 'feh -.':
+# [jpg, jpeg, png, gif, svg, hdr]
# (Optional)
# Whether to use syntax highlighting in the preview mode.
diff --git a/src/errors.rs b/src/errors.rs
index 54e6efd..bb49aa1 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -7,7 +7,7 @@ pub enum FxError {
Io(String),
Dirs(String),
GetItem,
- OpenItem,
+ OpenItem(String),
OpenNewWindow(String),
Yaml(String),
WalkDir(String),
@@ -33,7 +33,7 @@ impl std::fmt::Display for FxError {
FxError::Io(s) => s.to_owned(),
FxError::Dirs(s) => s.to_owned(),
FxError::GetItem => "Error: Cannot get item info".to_owned(),
- FxError::OpenItem => "Error: Cannot open item".to_owned(),
+ FxError::OpenItem(s) => s.to_owned(),
FxError::OpenNewWindow(s) => s.to_owned(),
FxError::Yaml(s) => s.to_owned(),
FxError::WalkDir(s) => s.to_owned(),
diff --git a/src/functions.rs b/src/functions.rs
index 42dc9bb..fb09451 100644
--- a/src/functions.rs
+++ b/src/functions.rs
@@ -229,11 +229,6 @@ pub fn print_help(v: &[String], skip_number: usize, row: u16) {
}
}
-/// Check if we can edit the file name safely.
-pub fn is_editable(s: &str) -> bool {
- s.is_ascii()
-}
-
/// Initialize the log if `-l` option is added.
pub fn init_log(data_local_path: &Path) -> Result<(), FxError> {
let mut log_name = chrono::Local::now().format("%F-%H-%M-%S").to_string();
@@ -368,18 +363,6 @@ mod tests {
}
#[test]
- fn test_is_editable() {
- let s1 = "Hello, world!";
- let s2 = "image.jpg";
- let s3 = "a̐éö̲\r\n";
- let s4 = "日本の首都は東京です";
- assert!(is_editable(s1));
- assert!(is_editable(s2));
- assert!(!is_editable(s3));
- assert!(!is_editable(s4));
- }
-
- #[test]
fn test_convert_to_permissions() {
let file = 33188;
let dir = 16877;
diff --git a/src/help.rs b/src/help.rs
index 4cb9c1e..5b0ce9a 100644
--- a/src/help.rs
+++ b/src/help.rs
@@ -1,5 +1,5 @@
/// Help text.
-pub const HELP: &str = "# felix v2.2.4
+pub const HELP: &str = "# felix v2.2.5
A simple TUI file manager with vim-like keymapping.
## Usage
diff --git a/src/run.rs b/src/run.rs
index b003347..c78891d 100644
--- a/src/run.rs
+++ b/src/run.rs
@@ -24,7 +24,6 @@ pub const TRASH: &str = "Trash";
/// Where the item list starts to scroll.
const SCROLL_POINT: u16 = 3;
const CLRSCR: &str = "\x1B[2J";
-const INITIAL_POS_RENAME: u16 = 12;
const INITIAL_POS_SEARCH: usize = 3;
const INITIAL_POS_SHELL: u16 = 3;
@@ -149,6 +148,10 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> {
screen.flush()?;
'main: loop {
+ if state.is_out_of_bounds() {
+ state.layout.nums.reset();
+ state.redraw(BEGINNING_ROW);
+ }
screen.flush()?;
let len = state.list.len();
@@ -987,14 +990,6 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> {
continue;
}
let item = state.get_item()?.clone();
- if !is_editable(&item.file_name) {
- print_warning(
- "Item name cannot be renamed due to the character type.",
- state.layout.y,
- );
- continue;
- }
-
show_cursor();
let mut rename = item.file_name.chars().collect::<Vec<char>>();
to_info_line();
@@ -1002,7 +997,8 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> {
print!("New name: {}", &rename.iter().collect::<String>(),);
screen.flush()?;
- let mut current_pos: u16 = 12 + item.file_name.len() as u16;
+ let (mut current_pos, _) = cursor_pos()?;
+ let mut current_char_pos = rename.len();
loop {
if let Event::Key(KeyEvent { code, .. }) = event::read()? {
match code {
@@ -1040,55 +1036,73 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> {
}
KeyCode::Left => {
- if current_pos == INITIAL_POS_RENAME {
+ if current_char_pos == 0 {
continue;
};
- current_pos -= 1;
- move_left(1);
+ if let Some(to_be_skipped) =
+ unicode_width::UnicodeWidthChar::width(
+ rename[current_char_pos - 1],
+ )
+ {
+ current_char_pos -= 1;
+ current_pos -= to_be_skipped as u16;
+ move_left(to_be_skipped as u16);
+ }
}
KeyCode::Right => {
- if current_pos as usize
- == rename.len() + INITIAL_POS_RENAME as usize
- {
+ if current_char_pos as usize == rename.len() {
continue;
};
- current_pos += 1;
- move_right(1);
+ if let Some(to_be_skipped) =
+ unicode_width::UnicodeWidthChar::width(
+ rename[current_char_pos],
+ )
+ {
+ current_char_pos += 1;
+ current_pos += to_be_skipped as u16;
+ move_right(to_be_skipped as u16);
+ }
}
KeyCode::Char(c) => {
- rename.insert(
- (current_pos - INITIAL_POS_RENAME).into(),
- c,
- );
- current_pos += 1;
+ if let Some(to_be_added) =
+ unicode_width::UnicodeWidthChar::width(c)
+ {
+ rename.insert((current_char_pos).into(), c);
+ current_char_pos += 1;
+ current_pos += to_be_added as u16;
- to_info_line();
- clear_current_line();
- print!(
- "New name: {}",
- &rename.iter().collect::<String>(),
- );
- move_to(current_pos, 2);
+ to_info_line();
+ clear_current_line();
+ print!(
+ "New name: {}",
+ &rename.iter().collect::<String>(),
+ );
+ move_to(current_pos + 1, 2);
+ }
}
KeyCode::Backspace => {
- if current_pos == INITIAL_POS_RENAME {
+ if current_char_pos == 0 {
continue;
};
- rename.remove(
- (current_pos - INITIAL_POS_RENAME - 1).into(),
- );
- current_pos -= 1;
+ let removed =
+ rename.remove((current_char_pos - 1).into());
+ if let Some(to_be_removed) =
+ unicode_width::UnicodeWidthChar::width(removed)
+ {
+ current_char_pos -= 1;
+ current_pos -= to_be_removed as u16;
- to_info_line();
- clear_current_line();
- print!(
- "New name: {}",
- &rename.iter().collect::<String>(),
- );
- move_to(current_pos, 2);
+ to_info_line();
+ clear_current_line();
+ print!(
+ "New name: {}",
+ &rename.iter().collect::<String>(),
+ );
+ move_to(current_pos + 1, 2);
+ }
}
_ => continue,
@@ -1618,6 +1632,7 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> {
print!("{}", CLRSCR);
state.clear_and_show_headline();
state.list_up();
+ state.move_cursor(state.layout.y);
screen.flush()?;
}
}
diff --git a/src/state.rs b/src/state.rs
index d3f29d1..a1c61e7 100644
--- a/src/state.rs
+++ b/src/state.rs
@@ -200,15 +200,38 @@ impl State {
info!("OPEN: {:?}", path);
match map {
- None => default.arg(path).status().or(Err(FxError::OpenItem)),
+ None => default
+ .arg(path)
+ .status()
+ .map_err(|e| FxError::OpenItem(e.to_string())),
Some(map) => match extension {
- None => default.arg(path).status().or(Err(FxError::OpenItem)),
+ None => default
+ .arg(path)
+ .status()
+ .map_err(|e| FxError::OpenItem(e.to_string())),
Some(extension) => match map.get(extension) {
Some(command) => {
- let mut ex = Command::new(command);
- ex.arg(path).status().or(Err(FxError::OpenItem))
+ let command: Vec<&str> = command.split_ascii_whitespace().collect();
+ //If the key has no arguments
+ if command.len() == 1 {
+ let mut ex = Command::new(command[0]);
+ ex.arg(path)
+ .status()
+ .map_err(|e| FxError::OpenItem(e.to_string()))
+ } else {
+ let mut args: Vec<&OsStr> =
+ command[1..].iter().map(|x| x.as_ref()).collect();
+ args.push(path.as_ref());
+ let mut ex = Command::new(command[0]);
+ ex.args(args)
+ .status()
+ .map_err(|e| FxError::OpenItem(e.to_string()))
+ }
}
- None => default.arg(path).status().or(Err(FxError::OpenItem)),
+ None => default
+ .arg(path)
+ .status()
+ .map_err(|e| FxError::OpenItem(e.to_string())),
},
},
}
@@ -236,15 +259,31 @@ impl State {
}
nix::unistd::ForkResult::Child => {
nix::unistd::setsid()?;
- let mut ex = Command::new(command);
- ex.arg(path)
- .stdout(Stdio::null())
- .stdin(Stdio::null())
- .spawn()
- .and(Ok(()))
- .map_err(|_| FxError::OpenItem)?;
- drop(ex);
- std::process::exit(0);
+ let command: Vec<&str> = command.split_ascii_whitespace().collect();
+ if command.len() == 1 {
+ let mut ex = Command::new(command[0]);
+ ex.arg(path)
+ .stdout(Stdio::null())
+ .stdin(Stdio::null())
+ .spawn()
+ .and(Ok(()))
+ .map_err(|e| FxError::OpenItem(e.to_string()))?;
+ drop(ex);
+ std::process::exit(0);
+ } else {
+ let mut args: Vec<&OsStr> =
+ command[1..].iter().map(|x| x.as_ref()).collect();
+ args.push(path.as_ref());
+ let mut ex = Command::new(command[0]);
+ ex.args(args)
+ .stdout(Stdio::null())
+ .stdin(Stdio::null())
+ .spawn()
+ .and(Ok(()))
+ .map_err(|e| FxError::OpenItem(e.to_string()))?;
+ drop(ex);
+ std::process::exit(0);
+ }
}
},
Err(e) => Err(FxError::Nix(e.to_string())),
@@ -282,7 +321,7 @@ impl State {
.stdin(Stdio::null())
.spawn()
.and(Ok(()))
- .or(Err(FxError::OpenItem))
+ .map_err(|e| (FxError::OpenItem(e.to_string())))
}
None => Err(FxError::OpenNewWindow(
"Cannot open this type of item in new window".to_owned(),
diff --git a/src/term.rs b/src/term.rs
index 0c25c4a..812e780 100644
--- a/src/term.rs
+++ b/src/term.rs
@@ -32,6 +32,10 @@ pub fn terminal_size() -> Result<(u16, u16), FxError> {
crossterm::terminal::size().map_err(|_| FxError::TerminalSizeDetection)
}
+pub fn cursor_pos() -> Result<(u16, u16), FxError> {
+ Ok(crossterm::cursor::position()?)
+}
+
pub fn move_to(x: u16, y: u16) {
print!("{}", MoveTo(x - 1, y - 1));
}