summaryrefslogtreecommitdiffstats
path: root/src/buffer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/buffer.rs')
-rw-r--r--src/buffer.rs113
1 files changed, 62 insertions, 51 deletions
diff --git a/src/buffer.rs b/src/buffer.rs
index 5771668..a9d925b 100644
--- a/src/buffer.rs
+++ b/src/buffer.rs
@@ -77,6 +77,50 @@ macro_rules! char {
};
}
+/// This bit of code is annoying, but it appears that the unicode_width library is (incorrectly)
+/// computing some character's width to be 0. So, we need to loop through each character from
+/// the last path, and if unicode_width says its width is 0, add 1 to it.
+///
+/// The string I have been testing with is: "01\ エレクトリック・パブリック.flac".
+/// There are some unicode characters with a width of zero
+/// (https://unicode-explorer.com/articles/space-characters), however, I have analyzed the raw
+/// byte sequence of all the characters in the string above, and I do not believe that any of
+/// them are zero width chars.
+///
+/// In theory, this workaround may mess up completion for strings that DO have real zero width
+/// characters. However, as those characters seem to be mostly for typesetting, I am not going
+/// to worry about it, unless I run into it myself, or someone complains to me about it.
+///
+/// Here is a simple ruby script that might help anyone looking to do their own analysis:
+/// #!/usr/bin/env ruby
+/// # frozen_string_literal: true
+///
+/// str = '01\ エレクトリック・パブリック.flac'
+/// puts "len: #{str.length}"
+///
+/// str.bytes do |b|
+/// # puts b
+/// puts b if b == 191
+/// end
+///
+/// puts
+/// # oth = "hi\u200chi"
+/// oth = "hi\ufeffhi"
+/// puts oth
+/// puts oth.bytes do |b|
+/// puts b
+/// end
+macro_rules! width {
+ ($c:expr) => {{
+ let w = UnicodeWidthChar::width($c).unwrap_or(1);
+ if w == 0 {
+ 1
+ } else {
+ w
+ }
+ }};
+}
+
/// Retrieve the next character from STDIN
///
/// A UTF-8 compatible function used to get the next character from STDIN. A UTF-8 character may be
@@ -165,47 +209,10 @@ fn comp(
*bpos -= *len;
}
- // This bit of code is annoying, but it appears that the unicode_width library is (incorrectly)
- // computing some character's width to be 0. So, we need to loop through each character from
- // the last path, and if unicode_width says its width is 0, add 1 to it.
- //
- // The string I have been testing with is: "01\ エレクトリック・パブリック.flac".
- // There are some unicode characters with a width of zero
- // (https://unicode-explorer.com/articles/space-characters), however, I have analyzed the raw
- // byte sequence of all the characters in the string above, and I do not believe that any of
- // them are zero width chars.
- //
- // In theory, this workaround may mess up completion for strings that DO have real zero width
- // characters. However, as those characters seem to be mostly for typesetting, I am not going
- // to worry about it, unless I run into it myself, or someone complains to me about it.
- //
- // Here is a simple ruby script that might help anyone looking to do their own analysis:
- // #!/usr/bin/env ruby
- // # frozen_string_literal: true
- //
- // str = '01\ エレクトリック・パブリック.flac'
- // puts "len: #{str.length}"
- //
- // str.bytes do |b|
- // # puts b
- // puts b if b == 191
- // end
- //
- // puts
- // # oth = "hi\u200chi"
- // oth = "hi\ufeffhi"
- // puts oth
- // puts oth.bytes do |b|
- // puts b
- // end
let ori_path = buffer[*bpos..].into_iter().collect::<Vec<_>>();
let mut width = 0;
for c in ori_path.clone() {
- let mut w = UnicodeWidthChar::width(*c).unwrap_or(1);
- if w == 0 {
- w += 1;
- }
- width += w;
+ width += width!(*c);
}
// Remove the last autocomplete value from the buffer
@@ -451,27 +458,33 @@ pub fn getline(
}
*pos.lock().unwrap() -= 1;
- let trunc = &buffer.lock().unwrap()[*pos.lock().unwrap()..]
- .iter()
- .collect::<String>();
- let trunc_width = UnicodeWidthStr::width(trunc.as_str());
- let c = buffer.lock().unwrap().remove(*pos.lock().unwrap());
- let width = UnicodeWidthChar::width(c).unwrap_or(1);
+ let mut buffer = buffer.lock().unwrap();
+ let trunc = &buffer[*pos.lock().unwrap()..].iter().collect::<Vec<_>>();
- if *pos.lock().unwrap() == buffer.lock().unwrap().len() {
+ let mut trunc_width = 0;
+ for c in trunc {
+ trunc_width += width!(**c);
+ }
+
+ let c = buffer.remove(*pos.lock().unwrap());
+ let mut width = UnicodeWidthChar::width(c).unwrap_or(1);
+ if width == 0 {
+ width += 1;
+ }
+
+ if *pos.lock().unwrap() == buffer.len() {
(0..width).for_each(|_| print!("\u{8}"));
print!(" \u{8}");
} else {
(0..trunc_width).for_each(|_| print!(" "));
(0..trunc_width + width).for_each(|_| print!("\u{8}"));
- buffer.lock().unwrap()[*pos.lock().unwrap()..]
+ buffer[*pos.lock().unwrap()..]
.iter()
.for_each(|c| print!("{}", c));
(0..trunc_width - width).for_each(|_| print!("\u{8}"));
}
// Update directory for autocomplete
- let buffer = buffer.lock().unwrap();
let comp_path = match buffer.last() {
Some(c) if *c == ' ' => String::new(),
None => String::new(),
@@ -529,8 +542,7 @@ pub fn getline(
continue;
}
- let width = UnicodeWidthChar::width(buffer.lock().unwrap()[*pos.lock().unwrap()])
- .unwrap_or(1);
+ let width = width!(buffer.lock().unwrap()[*pos.lock().unwrap()]);
for _ in 0..width {
print!("\x1b[1C");
}
@@ -543,8 +555,7 @@ pub fn getline(
}
*pos.lock().unwrap() -= 1;
- let width = UnicodeWidthChar::width(buffer.lock().unwrap()[*pos.lock().unwrap()])
- .unwrap_or(1);
+ let width = width!(buffer.lock().unwrap()[*pos.lock().unwrap()]);
for _ in 0..width {
print!("\u{8}");
}