Skip to content

Commit

Permalink
Merge pull request #176 from kyoheiu/develop
Browse files Browse the repository at this point in the history
v2.2.3
  • Loading branch information
kyoheiu authored Jan 19, 2023
2 parents 40c5cd5 + bf83428 commit 33dcda4
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 36 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

## Unreleased

## v2.2.3 (2023-01-20)

### 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.
Expand Down
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "felix"
version = "2.2.2"
version = "2.2.3"
authors = ["Kyohei Uto <[email protected]>"]
edition = "2021"
description = "tui file manager with vim-like key mapping"
Expand Down Expand Up @@ -31,6 +31,7 @@ tar = "0.4.38"
flate2 = "1.0.24"
lzma-rs = "0.2.0"
zstd = "0.11.2"
unicode-width = "0.1.10"

[dev-dependencies]
devtimer = "4.0.0"
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ For more detailed document, visit https://kyoheiu.dev/felix.

## New release

## v2.2.3 (2023-01-20)

### 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.

## v2.2.2 (2022-12-19)

### Fixed
Expand Down
86 changes: 57 additions & 29 deletions src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::collections::{BTreeMap, BTreeSet};
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use std::time::Duration;
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};

pub const PROCESS_INDICATOR_LENGTH: u16 = 7;
const KB: u64 = 1000;
Expand Down Expand Up @@ -77,7 +78,7 @@ pub fn print_info<T: std::fmt::Display>(message: T, then: u16) {
info!("{}", message);

let (width, _) = terminal_size().unwrap();
let trimmed = split_str(&message.to_string(), (width - 1).into());
let trimmed = shorten_str_including_wide_char(&message.to_string(), (width - 1).into());
print!("{}", trimmed);

hide_cursor();
Expand All @@ -93,7 +94,7 @@ pub fn print_warning<T: std::fmt::Display>(message: T, then: u16) {
warn!("{}", message);

let (width, _) = terminal_size().unwrap();
let trimmed = split_str(&message.to_string(), (width - 1).into());
let trimmed = shorten_str_including_wide_char(&message.to_string(), (width - 1).into());
set_color(&TermColor::ForeGround(&Colorname::White));
set_color(&TermColor::BackGround(&Colorname::LightRed));
print!("{}", trimmed);
Expand Down Expand Up @@ -189,7 +190,7 @@ pub fn list_up_contents(path: &Path, width: u16) -> Result<String, FxError> {
if i == len - 1 {
let mut line = "└ ".to_string();
line.push_str(item);
line = split_str(&line, width.into());
line = shorten_str_including_wide_char(&line, width.into());
result.push_str(&line);
} else {
let mut line = "├ ".to_string();
Expand All @@ -203,20 +204,7 @@ pub fn list_up_contents(path: &Path, width: u16) -> Result<String, FxError> {

/// Format texts to print. Used when printing help or text preview.
pub fn format_txt(txt: &str, width: u16, is_help: bool) -> Vec<String> {
let mut v = Vec::new();
for line in txt.lines() {
let mut line = line;
while line.bytes().len() > width as usize {
let mut i = width as usize;
while !line.is_char_boundary(i) {
i -= 1;
}
let (first, second) = line.split_at(i);
v.push(first.to_owned());
line = second;
}
v.push(line.to_owned());
}
let mut v = split_lines_includng_wide_char(txt, width.into());
if is_help {
v.push("Press Enter to go back.".to_owned());
}
Expand Down Expand Up @@ -300,19 +288,42 @@ pub fn convert_to_permissions(permissions: u32) -> String {
permissions.chars().rev().collect()
}

///The length of the file name is counted by bytes(), not chars(),
/// because it is possible that if the name contains multibyte characters
/// (sometimes they are wide chars such as CJK),
/// it may exceed the file-name space i.e. header, item list space or preview header.
/// To avoid this, the file name is split by the nearest character boundary (round-off),
/// even if extra space between the name and the modified time may appear.
pub fn split_str(s: &str, i: usize) -> String {
let mut i = i;
while !s.is_char_boundary(i) {
i -= 1;
/// Shorten &str to specific width. With unicode_width, even if the string includes wide chars, it's properly split, using full width of the terminal.
pub fn shorten_str_including_wide_char(s: &str, i: usize) -> String {
let mut result = "".to_owned();
for c in s.chars() {
let result_length = UnicodeWidthStr::width(result.as_str());
if let Some(c_width) = UnicodeWidthChar::width(c) {
if result_length + c_width > i {
return result;
}
result.push(c);
continue;
}
}
let (result, _) = s.split_at(i);
result.to_owned()
result
}

fn split_lines_includng_wide_char(s: &str, width: usize) -> Vec<String> {
let mut result = vec![];
let mut new_line = "".to_owned();
for c in s.chars() {
let new_line_length = UnicodeWidthStr::width(new_line.as_str());
if c == '\n' {
result.push(new_line);
new_line = "".to_owned();
}
if let Some(c_width) = UnicodeWidthChar::width(c) {
if new_line_length + c_width > width {
result.push(new_line);
new_line = "".to_owned();
}
new_line.push(c);
}
}
result.push(new_line);

result
}

//cargo test -- --nocapture
Expand Down Expand Up @@ -375,4 +386,21 @@ mod tests {
assert_eq!(&convert_to_permissions(file), "644");
assert_eq!(&convert_to_permissions(dir), "755");
}

#[test]
fn test_split_str_including_wide_char() {
let teststr = "Hello, world!";
assert_eq!(
"Hello, worl".to_owned(),
shorten_str_including_wide_char(teststr, 20)
);
assert_eq!(
"Hello".to_owned(),
shorten_str_including_wide_char(teststr, 10)
);
assert_eq!(
"Hello, w".to_owned(),
shorten_str_including_wide_char(teststr, 15)
);
}
}
2 changes: 1 addition & 1 deletion src/help.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// Help text.
pub const HELP: &str = "# felix v2.2.2
pub const HELP: &str = "# felix v2.2.3
A simple TUI file manager with vim-like keymapping.
## Usage
Expand Down
2 changes: 1 addition & 1 deletion src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ impl Layout {
move_right(1);
let mut file_name = format!("[{}]", item.file_name);
if file_name.bytes().len() > self.preview_space.0 as usize {
file_name = split_str(&file_name, self.preview_space.0 as usize);
file_name = shorten_str_including_wide_char(&file_name, self.preview_space.0 as usize);
}
print!("{}", file_name);
}
Expand Down
6 changes: 3 additions & 3 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ impl State {
self.layout.terminal_column = column;
self.layout.preview_start = match self.layout.split {
Split::Vertical => (column + 2, BEGINNING_ROW),
Split::Horizontal => (1, row + 2),
Split::Horizontal => (1, row + 1),
};
self.layout.preview_space = match self.layout.preview {
true => match self.layout.split {
Expand Down Expand Up @@ -800,7 +800,7 @@ impl State {
//current directory does not have any text attribute for now.
let current_dir = self.current_dir.display().to_string();
if current_dir.bytes().len() >= header_space {
let current_dir = split_str(&current_dir, header_space);
let current_dir = shorten_str_including_wide_char(&current_dir, header_space);
set_color(&TermColor::ForeGround(&Colorname::Cyan));
print!(" {}", current_dir);
reset_color();
Expand Down Expand Up @@ -837,7 +837,7 @@ impl State {
item.file_name.clone()
} else {
let i = self.layout.name_max_len - 2;
let mut file_name = split_str(&item.file_name, i);
let mut file_name = shorten_str_including_wide_char(&item.file_name, i);
file_name.push_str("..");
file_name
};
Expand Down

0 comments on commit 33dcda4

Please sign in to comment.