Closed janstarke closed 2 months ago
Can confirm this happens with cursive
0.20
and with cursive
's latest git commit 0a95c82c88c8a791d7fd983e7fb9f568b77551a8 (HEAD, origin/main, origin/HEAD, main)
However the exit(101) apparently happens due to ncurses-rs
(a dep of cursive
), or a dep of , because, if I just tell ncurses-rs
that got updated(unlikely)cursive
to use version 6 of ncurses-rs
and apply some compilation error patches (this and this for ncurses-rs
, and this for cursive
) which have nothing to do with the issue at hand(ie. they're not the ones fixing it), it will then compile and show no text, but definitely not exit. However to show any text, applying the cursive patch from here is enough.
Further more I now see, running it like:
$ RUST_BACKTRACE=1 cargo run >& /tmp/foo.log
cat /tmp/foo.log
shows:
[1m[32m Finished[0m dev [unoptimized + debuginfo] target(s) in 0.03s
[1m[32m Running[0m `target/debug/stuff`
thread 'main' panicked at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ncurses-5.101.0/src/lib.rs:65:29:
called `Result::unwrap()` on an `Err` value: NulError(16, [72, 101, 108, 108, 111, 32, 78, 117, 108, 108, 98, 121, 116, 101, 58, 32, 0])
stack backtrace:
0: rust_begin_unwind
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:645:5
1: core::panicking::panic_fmt
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:72:14
2: core::result::unwrap_failed
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/result.rs:1649:5
3: core::result::Result<T,E>::unwrap
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/result.rs:1073:23
4: <&str as ncurses::ToCStr>::to_c_str
at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ncurses-5.101.0/src/lib.rs:65:9
5: ncurses::addstr
at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ncurses-5.101.0/src/lib.rs:99:23
6: ncurses::mvaddstr
at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ncurses-5.101.0/src/lib.rs:736:3
7: <cursive::backends::curses::n::Backend as cursive_core::backend::Backend>::print_at
at /tmp/cursive/cursive/src/backends/curses/n.rs:397:9
8: cursive_core::printer::Printer::print_with_width
at /tmp/cursive/cursive-core/src/printer.rs:239:9
9: cursive_core::printer::Printer::print
at /tmp/cursive/cursive-core/src/printer.rs:159:9
10: <cursive_core::views::text_view::TextView as cursive_core::view::view_trait::View>::draw::{{closure}}::{{closure}}
at /tmp/cursive/cursive-core/src/views/text_view.rs:402:25
11: cursive_core::printer::Printer::with_effects
at /tmp/cursive/cursive-core/src/printer.rs:414:21
12: cursive_core::printer::Printer::with_style::{{closure}}
at /tmp/cursive/cursive-core/src/printer.rs:372:13
13: cursive_core::printer::Printer::with_color
at /tmp/cursive/cursive-core/src/printer.rs:339:9
14: cursive_core::printer::Printer::with_style
at /tmp/cursive/cursive-core/src/printer.rs:371:9
15: <cursive_core::views::text_view::TextView as cursive_core::view::view_trait::View>::draw::{{closure}}
at /tmp/cursive/cursive-core/src/views/text_view.rs:401:21
16: cursive_core::printer::Printer::with_effects
at /tmp/cursive/cursive-core/src/printer.rs:414:21
17: cursive_core::printer::Printer::with_style::{{closure}}
at /tmp/cursive/cursive-core/src/printer.rs:372:13
18: cursive_core::printer::Printer::with_color
at /tmp/cursive/cursive-core/src/printer.rs:339:9
19: cursive_core::printer::Printer::with_style
at /tmp/cursive/cursive-core/src/printer.rs:371:9
20: <cursive_core::views::text_view::TextView as cursive_core::view::view_trait::View>::draw
at /tmp/cursive/cursive-core/src/views/text_view.rs:389:9
21: cursive_core::view::view_wrapper::ViewWrapper::wrap_draw::{{closure}}
at /tmp/cursive/cursive-core/src/view/view_wrapper.rs:54:28
22: <cursive_core::views::boxed_view::BoxedView as cursive_core::view::view_wrapper::ViewWrapper>::with_view
at /tmp/cursive/cursive-core/src/views/boxed_view.rs:66:14
23: cursive_core::view::view_wrapper::ViewWrapper::wrap_draw
at /tmp/cursive/cursive-core/src/view/view_wrapper.rs:54:9
24: cursive_core::view::view_wrapper::<impl cursive_core::view::view_trait::View for T>::draw
at /tmp/cursive/cursive-core/src/view/view_wrapper.rs:106:9
25: <cursive_core::views::layer::Layer<T> as cursive_core::view::view_wrapper::ViewWrapper>::wrap_draw::{{closure}}
at /tmp/cursive/cursive-core/src/views/layer.rs:50:13
26: cursive_core::printer::Printer::with_color
at /tmp/cursive/cursive-core/src/printer.rs:339:9
27: <cursive_core::views::layer::Layer<T> as cursive_core::view::view_wrapper::ViewWrapper>::wrap_draw
at /tmp/cursive/cursive-core/src/views/layer.rs:46:9
28: cursive_core::view::view_wrapper::<impl cursive_core::view::view_trait::View for T>::draw
at /tmp/cursive/cursive-core/src/view/view_wrapper.rs:106:9
29: <cursive_core::views::shadow_view::ShadowView<T> as cursive_core::view::view_wrapper::ViewWrapper>::wrap_draw
at /tmp/cursive/cursive-core/src/views/shadow_view.rs:107:9
30: cursive_core::view::view_wrapper::<impl cursive_core::view::view_trait::View for T>::draw
at /tmp/cursive/cursive-core/src/view/view_wrapper.rs:106:9
31: <cursive_core::views::stack_view::ChildWrapper<T> as cursive_core::view::view_trait::View>::draw
at /tmp/cursive/cursive-core/src/views/stack_view.rs:237:44
32: cursive_core::view::view_wrapper::ViewWrapper::wrap_draw::{{closure}}
at /tmp/cursive/cursive-core/src/view/view_wrapper.rs:54:28
33: <cursive_core::views::circular_focus::CircularFocus<T> as cursive_core::view::view_wrapper::ViewWrapper>::with_view
at /tmp/cursive/cursive-core/src/view/view_wrapper.rs:171:41
34: cursive_core::view::view_wrapper::ViewWrapper::wrap_draw
at /tmp/cursive/cursive-core/src/view/view_wrapper.rs:54:9
35: cursive_core::view::view_wrapper::<impl cursive_core::view::view_trait::View for T>::draw
at /tmp/cursive/cursive-core/src/view/view_wrapper.rs:106:9
36: cursive_core::views::stack_view::StackView::draw_fg::{{closure}}
at /tmp/cursive/cursive-core/src/views/stack_view.rs:669:17
37: cursive_core::printer::Printer::with_effects
at /tmp/cursive/cursive-core/src/printer.rs:414:21
38: cursive_core::printer::Printer::with_style::{{closure}}
at /tmp/cursive/cursive-core/src/printer.rs:372:13
39: cursive_core::printer::Printer::with_color
at /tmp/cursive/cursive-core/src/printer.rs:339:9
40: cursive_core::printer::Printer::with_style
at /tmp/cursive/cursive-core/src/printer.rs:371:9
41: cursive_core::views::stack_view::StackView::draw_fg
at /tmp/cursive/cursive-core/src/views/stack_view.rs:665:9
42: cursive_core::views::screens_view::ScreensView<cursive_core::views::stack_view::StackView>::draw_fg
at /tmp/cursive/cursive-core/src/views/screens_view.rs:98:13
43: cursive_core::cursive_root::Cursive::draw
at /tmp/cursive/cursive-core/src/cursive_root.rs:148:9
44: cursive_core::cursive_run::CursiveRunner<C>::draw
at /tmp/cursive/cursive-core/src/cursive_run.rs:99:9
45: cursive_core::cursive_run::CursiveRunner<C>::refresh
at /tmp/cursive/cursive-core/src/cursive_run.rs:194:9
46: cursive_core::cursive_run::CursiveRunner<C>::run
at /tmp/cursive/cursive-core/src/cursive_run.rs:234:9
47: cursive_core::cursive_root::Cursive::try_run_with
at /tmp/cursive/cursive-core/src/cursive_root.rs:890:9
48: <cursive_core::cursive_root::Cursive as cursive::cursive_ext::CursiveExt>::run_ncurses
at /tmp/cursive/cursive/src/cursive_ext.rs:87:9
49: <cursive_core::cursive_root::Cursive as cursive::cursive_ext::CursiveExt>::run
at /tmp/cursive/cursive/src/cursive_ext.rs:76:17
50: stuff::main
at ./src/main.rs:7:5
51: core::ops::function::FnOnce::call_once
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
which means it got fixed by this commit: https://github.com/jeaye/ncurses-rs/commit/1be70212788a946446602d8d2c62ef8c8f48b708 (thanks @ThomasHabets btw!)
(thus it's only in ncurses-rs
v6, which for cursive
has a PR for that here but it's waiting for the ncurses-rs
one first which is here)
just making a note that this issue got fixed by a commit https://github.com/gyscos/cursive/commit/760999d300a83adfe2a24dcdfae21525818f27f3#diff-5ab05e635edf74924d76fd94ec7bd7712e5193641e3b12b77cc47662f6d33b64R186
The following no longer applies due to recent commits: nevermind, it still applies (i just forgot something)
ok but because of this https://github.com/unicode-rs/unicode-width/commit/4efb1803faa054f1bea3c0457275ad3c8610170b#diff-2ad10836ccce5ac2056d5679cc92449d9ff9094d4ff5c5803f65b5dd1d52ef19R224
and because it's no longer pinned to 0.1.12 as I thought it was the width of \0
is 1 instead of 0 now, so it will not "delete" \0
-es, so it still happens, for example for:
$ cargo run --example select >& /tmp/foo.log || cat /tmp/foo.log
Finished dev [unoptimized + debuginfo] target(s) in 0.04s
Running `target/debug/examples/select`
thread 'main' panicked at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ncurses-5.101.0/src/lib.rs:65:29:
called `Result::unwrap()` on an `Err` value: NulError(0, [0])
stack backtrace:
0: rust_begin_unwind
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:645:5
1: core::panicking::panic_fmt
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:72:14
2: core::result::unwrap_failed
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/result.rs:1649:5
3: core::result::Result<T,E>::unwrap
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/result.rs:1073:23
4: <&str as ncurses::ToCStr>::to_c_str
at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ncurses-5.101.0/src/lib.rs:65:9
5: ncurses::addstr
at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ncurses-5.101.0/src/lib.rs:99:23
6: <cursive::backends::curses::n::Backend as cursive_core::backend::Backend>::print
at ./cursive/src/backends/curses/n.rs:401:9
7: cursive_core::buffer::PrintBuffer::flush
at ./cursive-core/src/buffer.rs:291:13
8: cursive_core::cursive_run::CursiveRunner<C>::draw
at ./cursive-core/src/cursive_run.rs:98:9
9: cursive_core::cursive_run::CursiveRunner<C>::refresh
at ./cursive-core/src/cursive_run.rs:193:9
10: cursive_core::cursive_run::CursiveRunner<C>::run
at ./cursive-core/src/cursive_run.rs:233:9
11: cursive_core::cursive_root::Cursive::try_run_with
at ./cursive-core/src/cursive_root.rs:898:9
12: cursive::cursive_runnable::CursiveRunnable::try_run
at ./cursive/src/cursive_runnable.rs:93:9
13: cursive::cursive_runnable::CursiveRunnable::run
at ./cursive/src/cursive_runnable.rs:88:9
14: select::main
at ./cursive/examples/select.rs:46:5
15: core::ops::function::FnOnce::call_once
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
oh I forgot to say here that I put a \0
in Adamstown
in cities.txt
Was trying to find out how to make a test that would ensure no \0
exists in the strings in the view, by looking at this:
$ cargo test --example select_test -- --nocapture
Finished test [unoptimized + debuginfo] target(s) in 0.04s
Running unittests examples/select_test.rs (target/debug/examples/select_test-61955c01bf129bf6)
running 2 tests
captured piece:
x01234567890123456789012345678901234567890123456789012345678901234567890123456789x
0 |
1 |
2 ┌┤ Where are you from? ├┐ |
3 │ Abidjan ▒ │ |
4 │ Abu Dhabi | │ |
5 │ Abuja | │ |
6 │ Accra | │ |
7 │ Adamstown | │ |
8 │ Addis Ababa | │ |
9 │ Algiers | │ |
0 │ Alofi | │ |
1 │ Amman | │ |
2 │ Amsterdam | │ |
3 └───────────────────────┘ |
4 |
5 |
x--------------------------------------------------------------------------------x
test tests::displays ... ok
captured piece:
x01234567890123456789012345678901234567890123456789012345678901234567890123456789x
0................................................................................|
1................................................................................|
2........................... ............................|
3........................... ...........................|
4........................... ...........................|
5.........................┌────────────────────────────┐.........................|
6.........................│ Abu.Dhabi is a.great.city! │ ........................|
7.........................│ ..... ..... .. │ ........................|
8.........................│ .... . ....<Quit> │ ........................|
9.........................└────────────────────────────┘ ........................|
0.......................... . ........................|
1........................... ...........................|
2........................... ...........................|
3........................... ...........................|
4............................ ...........................|
5................................................................................|
x--------------------------------------------------------------------------------x
test tests::interacts ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
(not actually)Fixed with:
diff --git a/cursive-core/src/buffer.rs b/cursive-core/src/buffer.rs
index ad35432..86f5c5c 100644
--- a/cursive-core/src/buffer.rs
+++ b/cursive-core/src/buffer.rs
@@ -183,7 +183,7 @@ impl PrintBuffer {
// TODO: Use some WithWidth(&str, usize) to not re-compute width a thousand times
for g in text.graphemes(true) {
let width = g.width();
- if width == 0 {
+ if (width == 0) || ("\0" == g) {
continue;
}
self.set_cell(pos, g, CellWidth::from_usize(width), style);
(see next comment)
@gyscos should I make a PR with the above patch for \0
-es and add a test too? it might take me hours to figure out, but you could do it in minutes xD (frankly, I'd prefer the latter)
EDIT: Just realized that patch isn't good enough, something else also counts those \0
-es, and ends up truncating the string from view. So the test must test for this case as well. For example:
captured piece:
x01234567890123456789012345678901234567890123456789012345678901234567890123456789x
0................................................................................|
1................................................................................|
2................................................................................|
3............................. Wellington .|...............................|
4................................West.Island.....................................|
5.................................Willemstad.....................................|
6..................................Windhoek......................................|
7................................Yamoussoukro....................................|
8................................ Yaoundé .....................................|
9.................................. Yar.n .......................................|
0..................................Yerevan.......................................|
1...................................Zagreb.......................................|
2.............................short nul s ......▒...............................|
3................................................................................|
4................................................................................|
5................................................................................|
x--------------------------------------------------------------------------------x
for this string:
select.add_item_str("\0\0\0\0\0short \0nul\0 str\0\0\0\0\0\0\0");
EDIT: Here's what I have so far:
diff --git a/cursive-core/src/buffer.rs b/cursive-core/src/buffer.rs
index fb772b9..68f86ca 100644
--- a/cursive-core/src/buffer.rs
+++ b/cursive-core/src/buffer.rs
@@ -183,7 +183,7 @@ impl PrintBuffer {
// TODO: Use some WithWidth(&str, usize) to not re-compute width a thousand times
for g in text.graphemes(true) {
let width = g.width();
- if width == 0 {
+ if (width == 0) || ("\0" == g) {
continue;
}
self.set_cell(pos, g, CellWidth::from_usize(width), style);
diff --git a/cursive/examples/select_test.rs b/cursive/examples/select_test.rs
index 4848f18..04f8c1e 100644
--- a/cursive/examples/select_test.rs
+++ b/cursive/examples/select_test.rs
@@ -40,6 +40,8 @@ pub mod tests {
// (We include the file at compile-time to avoid runtime read errors.)
let content = include_str!("assets/cities.txt");
select.add_all_str(content.lines());
+ select.add_item_str("short \0nul\0 1str");
+ select.add_item_str("\0\0\0\0\0short \0nul\0 2str\0\0\0\0\0\0\0");
// Sets the callback for when "Enter" is pressed.
select.set_on_submit(show_next_window);
@@ -114,6 +116,24 @@ pub mod tests {
assert_eq!(screen.find_occurences("Some random string").len(), 0);
}
+ #[test]
+ fn no_inner_nuls() {
+ let mut s = BasicSetup::new();
+ s.hit_keystroke(Key::End);
+ let screen = s.last_screen().unwrap();
+ s.dump_debug();
+ assert_eq!(screen.find_occurences("short nul 1str").len(), 1, "nuls aka \\0 in strings are supposed to be deleted");
+ }
+
+ #[test]
+ fn dont_count_the_nuls() {
+ let mut s = BasicSetup::new();
+ s.hit_keystroke(Key::End);
+ let screen = s.last_screen().unwrap();
+ s.dump_debug();
+ assert_eq!(screen.find_occurences("short nul 2str").len(), 1, "nuls aka \\0 in strings are supposed to be disregarded when computing size of string");
+ }
+
#[test]
fn interacts() {
let mut s = BasicSetup::new();
It only fails with unicode-width 0.1.13 but not with 0.1.12 because the former has 1 instead of 0 as the width of \0
.
Because of this, seems more complicated than I initially thought, I think I'll leave this up to you, as I've no idea how you'd want this handled now that \0
-es have width 1. Well, technically you did mention how.
If we converted \0
to replacement char (\u{fffd}
which had width 1) to work with 0.1.13
unicode-width crate(where \0
is of width 1), then it will fail with 0.1.12 crate, but I've something like this:
diff --git a/cursive-core/src/buffer.rs b/cursive-core/src/buffer.rs
index fb772b9..6cb374b 100644
--- a/cursive-core/src/buffer.rs
+++ b/cursive-core/src/buffer.rs
@@ -183,10 +183,16 @@ impl PrintBuffer {
// TODO: Use some WithWidth(&str, usize) to not re-compute width a thousand times
for g in text.graphemes(true) {
let width = g.width();
+ //if (width == 0) || ("\0" == g) {
if width == 0 {
continue;
}
- self.set_cell(pos, g, CellWidth::from_usize(width), style);
+ if "\0" == g {
+ assert_eq!(1,width,"\\0 should've had a width of 1");
+ self.set_cell(pos, "\u{fffd}", CellWidth::from_usize(width), style);
+ } else {
+ self.set_cell(pos, g, CellWidth::from_usize(width), style);
+ }
pos.x += width;
}
}
diff --git a/cursive/examples/select_test.rs b/cursive/examples/select_test.rs
index 4848f18..9a97b7e 100644
--- a/cursive/examples/select_test.rs
+++ b/cursive/examples/select_test.rs
@@ -40,6 +40,7 @@ pub mod tests {
// (We include the file at compile-time to avoid runtime read errors.)
let content = include_str!("assets/cities.txt");
select.add_all_str(content.lines());
+ select.add_item_str("short \0nul\0 1str");
// Sets the callback for when "Enter" is pressed.
select.set_on_submit(show_next_window);
@@ -114,6 +115,15 @@ pub mod tests {
assert_eq!(screen.find_occurences("Some random string").len(), 0);
}
+ #[test]
+ fn nuls_become_replacement_char() {
+ let mut s = BasicSetup::new();
+ s.hit_keystroke(Key::End);
+ let screen = s.last_screen().unwrap();
+ s.dump_debug();
+ assert_eq!(screen.find_occurences("short \u{fffd}nul\u{FFFD} 1str").len(), 1, "nuls aka \\0 in strings are supposed to be deleted");
+ }
+
#[test]
fn interacts() {
let mut s = BasicSetup::new();
diff --git a/cursive-core/src/utils/lines/spans/tests.rs b/cursive-core/src/utils/lines/spans/tests.rs
index 73d2aa2..fb7ea5a 100644
--- a/cursive-core/src/utils/lines/spans/tests.rs
+++ b/cursive-core/src/utils/lines/spans/tests.rs
@@ -16,6 +16,12 @@ fn input() -> StyledString {
text
}
+#[test]
+fn test_nuls_have_width_1() {
+ use unicode_width::UnicodeWidthStr;
+ assert_eq!("\0".width(), 1, "nul chars should have width 1 since unicode-width 0.1.13, seen here: https://github.com/unicode-rs/unicode-width/commit/4efb1803faa054f1bea3c0457275ad3c8610170b#diff-2ad10836ccce5ac2056d5679cc92449d9ff9094d4ff5c5803f65b5dd1d52ef19R224");
+}
+
#[test]
fn test_next_line_char() {
use unicode_width::UnicodeWidthStr;
I personally like this one with the replacement char, because the \0
becomes visible now. EDIT the quote at top of this https://github.com/unicode-rs/unicode-width/pull/45 suggests they(the nuls and more control chars) should be rendered(with fallback glyph if not interpreted), so this replacement char idea seems like a good one, but the implementation may be not be up to par here.
The crash should now be fixed with the latest commit, which ignores \0
(when using unicode-width < 0.1.13), or replaces it with �
(when using unicode-width >= 0.1.13).
Note that on my terminal, the handling of �
is a bit buggy: it is treated as a single-width character, but is rendered as a double-width one: this is on Alacritty 0.13.2:
The same happens on gnone-terminal. Might depend on the font used. This happens both with monospace
and with Source code pro
. Ah - with Ubuntu Mono
it looks good! On a macOS terminal with the default font, it also looks properly single-width. :shrug:
Fix has now be released. I'll close this, but feel free to re-open if you think you're still having this issue.
Describe the bug
cursive programs exit immediately when asked to display a string with a null byte. No error message is shown, and there doesn't seem to be a
panic
To Reproduce
MWE: This program should display a
TextView
, but instead it exists without any complaint.Expected behavior This program should display a
TextView
, or at least panic with an error message, so that users ofcursive
know that null bytes are not allowedScreenshots no screenshot available
Environment
Additional context I found this while fixing janstarke/regview#8