profile
viewpoint
Alexandre Bury gyscos @argoai California, USA

gyscos/cursive 1936

A Text User Interface library for the Rust programming language

BonsaiDen/cursive_table_view 29

A basc table view compnent for cursive.

BonsaiDen/cursive_tree_view 26

A tree view implementation for cursive.

BonsaiDen/cursive_calendar_view 14

A basic calendar view implementation for cursive.

gyscos/coinched 3

A coinche server written in Rust

gyscos/cursive_calendar_view 2

A basic calendar view implementation for cursive.

gyscos/cursive_table_view 2

A basc table view compnent for cursive.

gyscos/CMANes 1

CMA-ES applied to neural network optimisation.

gyscos/colors 1

Lovely programatic images

gyscos/cursive_hexview 1

A simple hexview for cursive

issue commentgyscos/cursive

Unable to get Ctrl-Z working on ncspot

Hi, and thanks for the report!

First, regarding Ctrl-Z: as you noticed, it doesn't send a signal to the application but just regular input. Though you can totally raise the signal yourself in response:

fn main() {
    let mut siv = cursive::default();

    siv.add_layer(cursive::views::Dialog::text("foo"));

    siv.add_global_callback(cursive::event::Event::CtrlChar('z'), |_s| {
        unsafe { libc::raise(libc::SIGTSTP) };
    });

    siv.run();
}

Running with the ncurses backend, this will actually act like you'd expect, and you can then run fg to bring back the app, and it will keep working as expected. This is actually mostly thanks to ncurses: when initialized, it sets a signal handler for SIGTSP, which resets back the terminal to default values before actually hanging. It also sets a signal handler for SIGCONT which brings back the ncurses interface. This is what we want: we don't want to leave the terminal in a weird state when hanging, and similarly we don't know in what state it'll be when we resume. For this to work on other backends, we'll need to apply the same logic in the backend initialization code.

ChaboCode

comment created time in 2 days

pull request commentgyscos/cursive

Really minor fix

Thanks again for the work! :)

ChaboCode

comment created time in 2 days

push eventgyscos/cursive

Saul Chavez Sanchez

commit sha b3ada6be20fc0c04d5b4ad6dcb36de53fb2cbbf6

Really minor fix (#520) * Really minor fix Now it looks a little bit prettier

view details

push time in 2 days

PR merged gyscos/cursive

Really minor fix

Now it looks a little bit prettier

+2 -2

1 comment

1 changed file

ChaboCode

pr closed time in 2 days

pull request commentgyscos/cursive

Really minor fix

Thanks for the PR! I think you need to update the link as well, a bit further in the file.

ChaboCode

comment created time in 3 days

issue commentgyscos/cursive

A few ideas from developing a non-trivial application with cursive

Latest commit should bring back Cursive::screen_size() based on the last layout phase. Note that in general, changing the layout based on available size is exactly what View::layout() is supposed to do: you'd have a root view which checks the size available during layout, and possibly re-organize its children. Though I understand that in some case it's easier to just check the size of the screen without having to build an isolated view.

Re: refresh, I'm curious if you do see a change. If you still see the screen failing to refresh after any event, then it's most likely a bug that we'll need to fix.

htejun

comment created time in 4 days

push eventgyscos/cursive

Alexandre Bury

commit sha fb23445e1d86337c0434231e4221e1cf43ce5c48

Add Cursive::screen_size based on last layout phase

view details

push time in 5 days

issue commentgyscos/cursive

A few ideas from developing a non-trivial application with cursive

Ah yes these are changes since the last published version.

The Cursive object no longer relies on the backend being alived the entire time, so some actions likes screen_size() may not always be available.

  • Cursive::refresh() rarely needs to be manually called, especially from callbacks; it's already called after processing callbacks, as a matter of fact a no-op callback can be used to trigger a refresh.
  • Cursive::screen_size() is rarely needed, since usually views only need to know the size they have, not the size of the full screen. Though for this we can add something like Cursive::last_size() to get the size used in the last layout phase.
htejun

comment created time in 9 days

issue commentgyscos/cursive

A few ideas from developing a non-trivial application with cursive

So on the latest main branch, there is now:

  • Cursive::call_on_all_named, which will call a closure on all views with the same name and type.
  • SpannedString::remove_spans to remove a range of spans
  • SpannedString::{trim, trim_start, trim_end, shrink_to_fit} which update the "source" string of a spanned string to remove the prefix, suffix or both not covered by any span. These also apply to StyledString. There's also SpannedString::compact which will re-allocate the source by compacting all spans content, getting rid of potential unused segments in the middle.
  • TextContent::with_content which lets you access the &mut StyledString of a TextView.

This should let you remove content from a TextView without having to re-set the whole thing.

htejun

comment created time in 15 days

push eventgyscos/cursive

Alexandre Bury

commit sha 382557f713ad2362d80ee3afa1f7386f26229096

Add mutable attribute access to SpannedStrings

view details

Alexandre Bury

commit sha 58bbae5ec87259c04df41fc464a71fece12b8519

Rename SpannedString::shrink_to_fit -> trim

view details

push time in 16 days

push eventgyscos/cursive

Alexandre Bury

commit sha b03eafaabb26d938cd21dc132508c77ab7feb041

Add methods to remove from a SpannedString and shrink it

view details

Alexandre Bury

commit sha 60fcbba54a82902efc5f7cbddd374589d36d5c80

Add public TextContent::with_content

view details

push time in 16 days

push eventgyscos/cursive

Alexandre Bury

commit sha 7f25dd71d3965093ef63e8c66d137d86586b4a83

Add Finder::call_on_all and Cursive::call_on_all_named

view details

push time in 16 days

issue commentValveSoftware/Proton

Final Fantasy XV (637650)

I don't know if it did this when it did work, but I enabled "show framerate" in the options, it reports that I have 24Gb of Ram yet I only have 16. It reports not using any VRAM at all, and it reports that it I am using over 14Gb ram just sitting at the title screen

In system memory it includes swap, which may account for the difference. Vram reporting is broken but it shouldn't prevent the game from working.

I finally got it working just using proton GE 5.9-8. The 5.11 branch still doesn't work, neither does the main proton bundled with steam.

Since that I only had 1 crash after loading, but running the game again worked just fine.

DistantThunder

comment created time in 16 days

startedfacebookexperimental/resctl-demo

started time in 17 days

issue commentgyscos/cursive

A few ideas from developing a non-trivial application with cursive

Hi, and thanks for the very detailed report! This kind of insight is super valuable to help improve Cursive.

Colors

I suppose you're using the default ncurses backend? This backend tries to be smart and detects the colors supported by the terminal. It relies on the $TERM variable for that, and on an accurate terminfo database. The problem is that:

  • $TERM is often incorrectly overriden, either by shell scripts or terminal multiplexer configuration
  • The terminfo database is often incomplete, and may not accurately report the actual color support of a terminal. Especially for terminal multiplexers, where the actual support end up depending on the multiplexer and the parent terminal.

You can try other backends like crossterm or termion - these are much simpler and do not try to read the terminal capabilities, they just always output full "true color" and hope the terminal is fine with that.

Focus and scrolling

Yeah it may not be perfect yet. The current logic is:

  • Arrow keys change focus, and scrolling is then adjusted to the focus. This means the focus controls the scrolling, and not the other way around.
  • To still be able to see things out of focus, some actions can let the focus leave the current viewport. This includes scrolling with the mousewheel, and (currently) using <kbd>Ctrl</kbd> + the arrow keys.
  • Something not currently supported is "keeping the focus in view", which means that when we scroll until the focus gets out of view, we try to find another item in view to focus instead. If that's what you're interested in, I can try to look into that.

Focus management / key-binding

That's a good point! Right now arrows and tabs have a relatively similar behaviour, so making them access different items is not trivial. That being said, they do currently have a different "focus source", so maybe we could use that to control what gets focused? Will need to think about it for a bit.

Borderless Panel

Well, a Panel is really only useful for its border, and maybe its title. What are you trying to achieve? Maybe just using the graphview without wrapping it in a Panel? Note that in addition to borders, by default layers have shadows around them. If the style removes shadows, there is still a 1-cell invisible border around layers - that is, unless you use add_fullscreen_layer, which skips the shadow wrapper. I understand it's terrible to discover, and not super convenient to use if you want the view to not be fullscreen.

call_on_name() on multiple targets

Interesting! I could start looking into that.

Trimming TextView

Yeaaah right now it's partly caused by the same limitation on StyledString, but:

  • We could probably enable trimming a StyledString
  • We might work on a dedicated LogView or something which doesn't have the same restrictions.
htejun

comment created time in 17 days

push eventgyscos/cursive

Alexandre Bury

commit sha 47d8d231982ad3aad5e5d6873766bbaaa16d2b28

Fix clippy lints

view details

push time in 22 days

push eventgyscos/cursive

Robin Krahl

commit sha 994a3cf54514b4001d10e4150aa616c828d1bfcc

List rusty-man in readme (#518) This patch adds rusty-man, a rustdoc documentation viewer for the terminal, to the list of cursive applications in the readme.

view details

push time in 22 days

PR merged gyscos/cursive

List rusty-man in readme

This patch adds rusty-man, a rustdoc documentation viewer for the terminal, to the list of cursive applications in the readme.

+1 -0

0 comment

1 changed file

robinkrahl

pr closed time in 22 days

push eventgyscos/cursive

Alexandre Bury

commit sha 801fa8e54bbb85424d4b156eab00046dd959e265

Deprecate ScrollBase

view details

Alexandre Bury

commit sha 03cd0d41da0a55235fd9bdb0683e7be7dc5a8983

Fix cursive_run doc

view details

push time in 22 days

push eventgyscos/cursive

Tianyi Shi

commit sha c7c5f7955f2d7364d24807552d887a3d109b03d8

add new example: stopwatch (#503) Co-authored-by: Mckol <mckol363@gmail.com>

view details

push time in 22 days

PR merged gyscos/cursive

add new example: stopwatch

A stopwatch is implemented in this example.

This example is not complete. I managed to make the textbox update the elapsed time every second, but haven't figured out how I can pause or stop the stopwatch. @gyscos any suggestions?

+92 -0

12 comments

2 changed files

TianyiShi2001

pr closed time in 22 days

pull request commentgyscos/cursive

add new example: stopwatch

Great! I think you just need to rebase to resolve the readme conflict.

TianyiShi2001

comment created time in 22 days

pull request commentgyscos/cursive

add new example: stopwatch

I think we can simplify a bit further the example - let's focus on one feature (a stopwatch) and look for the minimal example demonstrating this.

For example: https://gist.github.com/gyscos/67910f22e304214eaef00157faecb2ce

TianyiShi2001

comment created time in 23 days

issue commentgyscos/cursive

Event::CtrlShift(char)?

Hi, and thanks for the PR!

Unfortunately I don't think terminal application can tell the difference between C-z and C-Z: in both cases the same input code is sent by the terminal emulator (this is why there is no Event::CtrlShift(char), to prevent the confusion from this never happening). One of the limitations of terminals... :(

TianyiShi2001

comment created time in 23 days

issue commentgyscos/cursive

Setting a style for a TextView

Hi again!

I think there are two separate potential improvements:

  • Being able to write views that "pre-process" the given text, for example apply styles to it.
  • Being able to easily add/remove styles to an existing StyledString ("make this text bold", then "undo that" without losing previously-bold text for example).

There's also the more conceptual question "is style attached to the text content, or to the view itself?".

Some of this point to hierarchy of applied styles, maybe closer to CSS. I don't have a very clear idea of how to get there though, so for now having a dedicated style for the TextView itself which is merged with the content is perfectly fine.

robinkrahl

comment created time in 23 days

push eventgyscos/cursive

Tianyi Shi

commit sha ac06b3ac3a388d62c03c3ecda80df19a0a906de9

add sudoku-tui to showcase (#514)

view details

push time in 23 days

PR merged gyscos/cursive

add sudoku-tui to showcase

I implemented the sudoku game with Cursive. Would you mind adding it to the showcase?

+1 -0

0 comment

1 changed file

TianyiShi2001

pr closed time in 23 days

push eventgyscos/cursive

Robin Krahl

commit sha c5ccacf30e9550f2b5dc89deb7527a7957332937

Add cursive-markup to readme (#513) * Add cursive-markup to readme The cursive-markup crate provides a view that can render HTML or other markup. This patch adds it to the list of third-party views in the readme.

view details

push time in 24 days

PR merged gyscos/cursive

Add cursive-markup to readme

The cursive-markup crate provides a view that can render HTML or other markup. This patch adds it to the list of third-party views in the readme.

+1 -0

1 comment

1 changed file

robinkrahl

pr closed time in 24 days

pull request commentgyscos/cursive

Add cursive-markup to readme

Looks great! Just a small typo and it'll be good to go

robinkrahl

comment created time in 24 days

PullRequestReviewEvent

Pull request review commentgyscos/cursive

Add cursive-markup to readme

 Here are a few crates implementing new views for you to use: * [cursive-aligned-view](https://github.com/deinstapel/cursive-aligned-view): A view wrapper for gyscos/cursive views which aligns child views. * [cursive-async-view](https://github.com/deinstapel/cursive-async-view): A loading-screen wrapper. * [cursive-flexi-logger-view](https://github.com/deinstapel/cursive-flexi-logger-view): An alternative debug view using `emabee/flexi_logger`.+* [cursive-markup](https://sr.ht/~ireas/cursive-markup-rs): A view that renderes HTML or other markup.
* [cursive-markup](https://sr.ht/~ireas/cursive-markup-rs): A view that renders HTML or other markup.
robinkrahl

comment created time in 24 days

issue commentgyscos/cursive

Dead links for source code in documentation

You can fetch the repo and open the doc locally?

git clone https://github.com/gyscos/cursive && cd cursive && cargo doc --open

I don't know of a service like docs.rs that builds doc from git repos, but if there's one I'd love to learn about it!

robinwils

comment created time in 24 days

pull request commentgyscos/cursive

Implement FromIterator for SpannedString

Thanks again!

robinkrahl

comment created time in 24 days

push eventgyscos/cursive

Robin Krahl

commit sha 28c64958ca02ac028c8e4bdd1fe24ae6400dace7

Implement FromIterator for SpannedString (#512) This patch implements FromIterator<SpannedString<T>> for SpannedString<T> to make it easier to create strings programatically. We could also use fold directly without extracting the first element, but that would require an additional allocation.

view details

push time in 24 days

PR merged gyscos/cursive

Implement FromIterator for SpannedString

This patch implements FromIterator<SpannedString<T>> for SpannedString<T> to make it easier to create strings programatically. We could also use fold directly without extracting the first element, but that would require an additional allocation.


This should be the last PR for today. Thanks for the reviews and merges!

+17 -0

0 comment

1 changed file

robinkrahl

pr closed time in 24 days

push eventgyscos/cursive

Robin Krahl

commit sha 0e2a111f59ac2fa7abde3c17328684548291737f

Mark XY::stack_{horizontal, vertical} as must_use (#511) The method names stack_horizontal and stack_vertical don’t make it clear whether the methods modify self or return the modified version. Therefore, it is easy to use them wrong if you don’t look at the documentation. This patch adds the must_use attribute to both methods to make it easier to spot such mistakes.

view details

push time in 25 days

PR merged gyscos/cursive

Mark XY::stack_{horizontal, vertical} as must_use

The method names stack_horizontal and stack_vertical don’t make it clear whether the methods modify self or return the modified version. Therefore, it is easy to use them wrong if you don’t look at the documentation. This patch adds the must_use attribute to both methods to make it easier to spot such mistakes.

+2 -0

1 comment

1 changed file

robinkrahl

pr closed time in 25 days

pull request commentgyscos/cursive

Mark XY::stack_{horizontal, vertical} as must_use

Good idea!

robinkrahl

comment created time in 25 days

pull request commentgyscos/cursive

Implement FromIterator for Style

Looking good, thanks for the work!

robinkrahl

comment created time in 25 days

push eventgyscos/cursive

Robin Krahl

commit sha 3f60d383aa78d7f1e8588075b826cfb931709527

Implement FromIterator for Style (#510) This patch implements FromIterator<&Style> and FromIterator<T: Into<Style>> for Style to make it easier to programatically create styles. Style already has a merge method, but it takes a slice instead of an iterator.

view details

push time in 25 days

PR merged gyscos/cursive

Implement FromIterator for Style

This patch implements FromIterator<&Style> and FromIterator<T: Into<Style>> for Style to make it easier to programatically create styles. Style already has a merge method, but it takes a slice instead of an iterator.

+32 -12

0 comment

1 changed file

robinkrahl

pr closed time in 25 days

push eventgyscos/cursive

Robin Krahl

commit sha 02ce9f8a35cde7dab475d99267fa8b0bb7f21424

Derive Default for XY (#509) This patch derives Default for XY<T>. This makes it easier to deal with types like XY<usize>.

view details

push time in 25 days

PR merged gyscos/cursive

Implement Default for XY

This patch implements Default for XY<T> if T implements Default. This makes it easier to deal with types like XY<usize>.

+1 -1

3 comments

1 changed file

robinkrahl

pr closed time in 25 days

pull request commentgyscos/cursive

Implement Default for XY

These derives automatically carry the trait bound to any generic type. It's not always accurate (sometime you don't really depend on the generic type implementing the trait, see a playground example), but in many cases (including ours) it's actually what we want.

robinkrahl

comment created time in 25 days

pull request commentgyscos/cursive

Implement Default for XY

Thanks for the PR!

I think in our case we can just add Default to the derived implementations of XY (along with Debug, Clone, ...).

robinkrahl

comment created time in 25 days

push eventgyscos/cursive

Robin Krahl

commit sha f694e2ae25fdbe58f3f911e3895276f11f0f61b7

Remove outdated comment from button.rs (#508) Before commit f9c9e565189a32a30ff2b2d1fad594e07e78961b, this match interpreted the key code 10 as the Enter key. Since it now uses the Key::Enter variant instead, the comment explaining the magic number is no longer needed.

view details

push time in 25 days

PR merged gyscos/cursive

Remove outdated comment from button.rs

Before commit f9c9e565189a32a30ff2b2d1fad594e07e78961b, this match interpreted the key code 10 as the Enter key. Since it now uses the Key::Enter variant instead, the comment explaining the magic number is no longer needed.

+0 -1

1 comment

1 changed file

robinkrahl

pr closed time in 25 days

pull request commentgyscos/cursive

Remove outdated comment from button.rs

Whoops, good catch! Thanks for the PR!

robinkrahl

comment created time in 25 days

issue commentgyscos/cursive

Dead links for source code in documentation

Hi, and thanks for the report!

I messed up the doc links for that release; it's fixed on master, so the next release shouldn't have this problem. Just got to release something...

robinwils

comment created time in 25 days

issue commentgyscos/cursive

Styling individual words in a textview

Hi, and thanks for the report!

Right now unless you just want to append, there's no way to just "mutate" the content of a TextView; you need to set it again with set_content. This means you'll need to:

  • Fetch the existing text content.
  • Create a new content based on the existing one (and modify it in the process).
  • Set the new content.

To build the new content (a StyledString, which is just an alias for SpannedString<Style>), we can iterate on the existing "spans" of the existing content, and either add it as-is to our new content, or change it. Here's a working example:

use cursive::{
    theme::{BaseColor, Color, Effect, Style},
    traits::*,
    utils::markup::StyledString,
    views,
};

fn main() {
    let mut siv = cursive::default();

    let mut styled = StyledString::plain("Isn't ");
    styled.append(StyledString::styled("that ", Color::Dark(BaseColor::Red)));
    styled.append(StyledString::styled(
        "cool?",
        Style::from(Color::Light(BaseColor::Blue)).combine(Effect::Bold),
    ));

    siv.add_layer(views::Dialog::around(
        views::LinearLayout::vertical()
            .child(views::TextView::new(styled).with_name("text"))
            .child(views::EditView::new().on_edit(on_edit)),
    ));

    siv.run();
}

fn on_edit(s: &mut cursive::Cursive, edit_text: &str, _cursor: usize) {
    s.call_on_name("text", |t: &mut views::TextView| {
        let mut new_content = StyledString::new();
        for span in t.get_content().spans() {
            let new_style = if edit_text == span.content {
                Style::from(Effect::Bold)
            } else {
                *span.attr
            };
            new_content.append_styled(span.content, new_style);
        }
        t.set_content(new_content);
    });
}

In this example every time you type an exact span, it becomes bold instead. Though it's very primitive and only works at the span level. You'll probably want something smarter where you can match subsets of a span, or across spans, or something else entirely.

Exodus76

comment created time in a month

issue commentgyscos/cursive

quitting takes long

You can "send" the parameters out of the closure in a few ways:

  • Share a Rc<Cell<T>> (or Rc<Cell<Option<T>>) with the outside code and store the value there. Can also be a channel.
  • Store the values you want to keep in cursive's user_data field and fetch it back afterwards.
alx365

comment created time in a month

issue commentgyscos/cursive

quitting takes long

Hi, and thanks for the report! As you noticed, calling Cursive::quit does not quit instantly, but merely signals that the event loop should stop. If you want to run code after Cursive has cleaned up, you'll want to run the actual thing after Cursive::run.

Actually, I think on the crates.io version, you'll also need to drop the cursive instance (that is what will clean the terminal). On the latest master it should clean up the terminal when returning from Cursive::run.

alx365

comment created time in a month

startedrtic-rs/cortex-m-rtic

started time in a month

pull request commentgyscos/cursive

add new example: stopwatch

Thanks! A dedicated crate for more features sounds like a great idea. This way we can simplify the example to the minimum, and it'll be a teaser for your library :p

TianyiShi2001

comment created time in a month

Pull request review commentgyscos/cursive

add new example: stopwatch

+use chrono::Duration;+use cursive::{traits::*, views::Dialog, Cursive};+use stopwatch::{StopWatch, StopWatchView};++// A simple stopwatch without 'lap time' function is implemented in this example.+// Press "Space" to start/pause/resume the stopwatch. Press "Enter" to stop and+// get all data: moments at which the stopwatch is started/resumed, moments at which+// the stopwatch is paused/stopped; elapsed time.++fn main() {+    let mut siv = cursive::default();+    let stopwatch = StopWatchView::new();+    siv.add_layer(+        stopwatch+            // On stop, get all data and summarize them in an info box.+            .on_stop(|s: &mut Cursive, stopwatch| {+                s.add_layer(Dialog::info(summarize(stopwatch)))+            }),+    );+    siv.add_layer(Dialog::info(+        "Press 'Space' to start/pause/resume the stopwatch\nPress 'Enter' to stop",+    ));+    // the stopwatch is redrawn 15 times per second+    siv.set_fps(15);+    siv.run();+}++fn summarize(stopwatch: &StopWatch) -> String {+    let elapsed = stopwatch.elapsed;+    let n = stopwatch.pause_moments.len();+    let total_elapsed =+        stopwatch.pause_moments[n - 1] - stopwatch.start_moments[0];+    format!(+        "Elapsed time: {}\nTotal elapsed: {}\nPaused {} times",+        elapsed.pretty(),+        total_elapsed.pretty(),+        n - 1,+    )+}++pub trait PrettyDuration {+    fn pretty(&self) -> String;+}+impl PrettyDuration for Duration {+    /// Pretty-prints a chrono::Duration in the form `HH:MM:SS.xxx`+    /// A custom trait is used because `std::fmt::Diaplay` cannot be implemented+    /// for a struct coming from another external crate, due to the orphan rule+    fn pretty(&self) -> String {+        let s = self.num_seconds();+        let ms = self.num_milliseconds() - 1000 * s;+        let (h, s) = (s / 3600, s % 3600);+        let (m, s) = (s / 60, s % 60);+        format!("{:02}:{:02}:{:02}.{:03}", h, m, s, ms)+    }+}++mod stopwatch {+    use super::PrettyDuration;+    use chrono::{DateTime, Duration, Local};+    use cursive::{+        event::{Event, EventResult, Key},+        view::View,+        Cursive, Printer, Vec2, With,+    };+    use std::rc::Rc;++    #[derive(Clone, Debug)]+    pub struct StopWatch {+        // These data might be useful to the user+        pub elapsed: Duration, // total elapsed time+        pub pause_moments: Vec<DateTime<Local>>, // moments at which the stopwatch is paused+        pub start_moments: Vec<DateTime<Local>>, // moments at which the stopwatch resumes+        paused: bool,+    }++    impl StopWatch {+        /// Returns a stopwatch that is reset to zero+        pub fn new() -> Self {+            Self {+                elapsed: Duration::zero(),+                start_moments: Vec::new(),+                pause_moments: Vec::new(),+                paused: true, // stopped by default; start by explicitly calling `.resume()`+            }+        }++        fn last_start(&self) -> DateTime<Local> {+            self.start_moments[self.start_moments.len() - 1]+        }+        fn pause(&mut self) {+            assert!(self.paused == false, "Already paused!");+            let moment = Local::now();+            self.pause_moments.push(moment);+            self.elapsed = self.elapsed + (moment - self.last_start());+            self.paused = true;+        }+        fn resume(&mut self) {+            assert!(self.paused == true, "Already running!");+            self.start_moments.push(Local::now());+            self.paused = false;+        }+        fn pause_or_resume(&mut self) {+            if self.paused {+                self.resume();+            } else {+                self.pause();+            }+        }+        /// Read the total time elapsed+        fn read(&self) -> Duration {+            if self.paused {+                self.elapsed+            } else {+                self.elapsed + (Local::now() - self.last_start())+            }+        }+    }++    /// Separating the `StopWatch` 'core' and the `StopWatchView` improves reusability+    /// and flexibility. The user may implement their own `View`s, i.e. layouts, based+    /// on the same `StopWatch` logic.+    pub struct StopWatchView {+        stopwatch: StopWatch,+        on_stop: Option<Rc<dyn Fn(&mut Cursive, &StopWatch)>>,+    }++    impl StopWatchView {+        pub fn new() -> Self {+            Self {+                stopwatch: StopWatch::new(),+                on_stop: None,+            }+        }++        /// Sets a callback to be used when `<Enter>` is pressed.+        ///+        /// The elapsed time will be given to the callback.+        ///+        /// See also cursive::views::select_view::SelectView::set_on_submit+        pub fn set_on_stop<F, R>(&mut self, cb: F)+        where+            F: 'static + Fn(&mut Cursive, &StopWatch) -> R,+        {+            self.on_stop = Some(Rc::new(move |s, t| {+                cb(s, t);+            }));+        }++        pub fn on_stop<F, R>(self, cb: F) -> Self+        where+            F: 'static + Fn(&mut Cursive, &StopWatch) -> R,+        {+            self.with(|s| s.set_on_stop(cb))+        }++        fn stop(&mut self) -> EventResult {+            let stopwatch = &mut self.stopwatch;+            if !stopwatch.paused {+                stopwatch.pause();+            }+            let result = if self.on_stop.is_some() {+                let cb = self.on_stop.clone().unwrap();+                let stopwatch_data = self.stopwatch.clone(); // TODO: remove clone

You can use std::mem::take which does this automatically for "default" types.

TianyiShi2001

comment created time in a month

PullRequestReviewEvent

Pull request review commentgyscos/cursive

add new example: stopwatch

+use chrono::Duration;+use cursive::{traits::*, views::Dialog, Cursive};+use stopwatch::{StopWatch, StopWatchView};++// A simple stopwatch without 'lap time' function is implemented in this example.+// Press "Space" to start/pause/resume the stopwatch. Press "Enter" to stop and+// get all data: moments at which the stopwatch is started/resumed, moments at which+// the stopwatch is paused/stopped; elapsed time.++fn main() {+    let mut siv = cursive::default();+    let stopwatch = StopWatchView::new();+    siv.add_layer(+        stopwatch+            // On stop, get all data and summarize them in an info box.+            .on_stop(|s: &mut Cursive, stopwatch| {+                s.add_layer(Dialog::info(summarize(stopwatch)))+            }),+    );+    siv.add_layer(Dialog::info(+        "Press 'Space' to start/pause/resume the stopwatch\nPress 'Enter' to stop",+    ));+    // the stopwatch is redrawn 15 times per second+    siv.set_fps(15);+    siv.run();+}++fn summarize(stopwatch: &StopWatch) -> String {+    let elapsed = stopwatch.elapsed;+    let n = stopwatch.pause_moments.len();+    let total_elapsed =+        stopwatch.pause_moments[n - 1] - stopwatch.start_moments[0];+    format!(+        "Elapsed time: {}\nTotal elapsed: {}\nPaused {} times",+        elapsed.pretty(),+        total_elapsed.pretty(),+        n - 1,+    )+}++pub trait PrettyDuration {+    fn pretty(&self) -> String;+}+impl PrettyDuration for Duration {+    /// Pretty-prints a chrono::Duration in the form `HH:MM:SS.xxx`+    /// A custom trait is used because `std::fmt::Diaplay` cannot be implemented+    /// for a struct coming from another external crate, due to the orphan rule+    fn pretty(&self) -> String {+        let s = self.num_seconds();+        let ms = self.num_milliseconds() - 1000 * s;+        let (h, s) = (s / 3600, s % 3600);+        let (m, s) = (s / 60, s % 60);+        format!("{:02}:{:02}:{:02}.{:03}", h, m, s, ms)+    }+}++mod stopwatch {+    use super::PrettyDuration;+    use chrono::{DateTime, Duration, Local};+    use cursive::{+        event::{Event, EventResult, Key},+        view::View,+        Cursive, Printer, Vec2, With,+    };+    use std::rc::Rc;++    #[derive(Clone, Debug)]+    pub struct StopWatch {+        // These data might be useful to the user+        pub elapsed: Duration, // total elapsed time+        pub pause_moments: Vec<DateTime<Local>>, // moments at which the stopwatch is paused+        pub start_moments: Vec<DateTime<Local>>, // moments at which the stopwatch resumes+        paused: bool,+    }++    impl StopWatch {+        /// Returns a stopwatch that is reset to zero+        pub fn new() -> Self {+            Self {+                elapsed: Duration::zero(),+                start_moments: Vec::new(),+                pause_moments: Vec::new(),+                paused: true, // stopped by default; start by explicitly calling `.resume()`+            }+        }++        fn last_start(&self) -> DateTime<Local> {+            self.start_moments[self.start_moments.len() - 1]+        }+        fn pause(&mut self) {+            assert!(self.paused == false, "Already paused!");+            let moment = Local::now();+            self.pause_moments.push(moment);+            self.elapsed = self.elapsed + (moment - self.last_start());+            self.paused = true;+        }+        fn resume(&mut self) {+            assert!(self.paused == true, "Already running!");+            self.start_moments.push(Local::now());+            self.paused = false;+        }+        fn pause_or_resume(&mut self) {+            if self.paused {+                self.resume();+            } else {+                self.pause();+            }+        }+        /// Read the total time elapsed+        fn read(&self) -> Duration {+            if self.paused {+                self.elapsed+            } else {+                self.elapsed + (Local::now() - self.last_start())+            }+        }+    }++    /// Separating the `StopWatch` 'core' and the `StopWatchView` improves reusability+    /// and flexibility. The user may implement their own `View`s, i.e. layouts, based+    /// on the same `StopWatch` logic.+    pub struct StopWatchView {+        stopwatch: StopWatch,+        on_stop: Option<Rc<dyn Fn(&mut Cursive, &StopWatch)>>,+    }++    impl StopWatchView {+        pub fn new() -> Self {+            Self {+                stopwatch: StopWatch::new(),+                on_stop: None,+            }+        }++        /// Sets a callback to be used when `<Enter>` is pressed.+        ///+        /// The elapsed time will be given to the callback.+        ///+        /// See also cursive::views::select_view::SelectView::set_on_submit+        pub fn set_on_stop<F, R>(&mut self, cb: F)+        where+            F: 'static + Fn(&mut Cursive, &StopWatch) -> R,+        {+            self.on_stop = Some(Rc::new(move |s, t| {+                cb(s, t);+            }));+        }++        pub fn on_stop<F, R>(self, cb: F) -> Self+        where+            F: 'static + Fn(&mut Cursive, &StopWatch) -> R,+        {+            self.with(|s| s.set_on_stop(cb))+        }++        fn stop(&mut self) -> EventResult {+            let stopwatch = &mut self.stopwatch;+            if !stopwatch.paused {+                stopwatch.pause();+            }+            let result = if self.on_stop.is_some() {+                let cb = self.on_stop.clone().unwrap();+                let stopwatch_data = self.stopwatch.clone(); // TODO: remove clone

Yeaah... the issue is that the callback will be called later, possibly after removing this view. So we can't depend on any data in the view itself; the callback must be self-supported. The solution is to either clone the data as you are doing (making it standalone), or wrap it in a Rc shared by both the view and the callback.

TianyiShi2001

comment created time in a month

PullRequestReviewEvent

issue commentgyscos/cursive

Missing text with LinearLayout combos

This is what the required_size methods from the View trait does. You can call it on the currently active screen siv.screen_mut().required_size(constraings).

The value of constraint can be used to control how the view will strecth, if any:

  • Giving a very small value (like Vec2::zero()) will try to get the smallest possible size. If any view is scrollable, it will try to shrink to the minimum size.
  • Given a large value, it will expand to this value if necessary.

So ideally you would give as constraint either the maximum terminal size you can accept.

ph0llux

comment created time in a month

issue commentgyscos/cursive

Missing text with LinearLayout combos

But it's kind of strange that only on the last round is something cut off, isn't it?

It depends on how much space is missing to show everything. If you shrink the terminal a bit more, you will see more and more text being cut off.

Here are examples with different terminal heights:

Screenshot from 2020-09-22 12-14-16 Screenshot from 2020-09-22 12-14-19 Screenshot from 2020-09-22 12-14-28

ph0llux

comment created time in a month

issue commentgyscos/cursive

[feature request] support PaletteColor::Border

Hi, and thanks for the report!

Indeed, controlling border color independently from the primary color is something we want to support. I'm still thinking about a refactor of the theme module, to allow more control while still being convenient and easy to use.

s97712

comment created time in a month

issue commentgyscos/cursive

Publish newest version of cursive & cursive-core to crates.io to fix scrollable select view bug

Hi, and thanks for the report!

The past few weeks have been pretty crazy, but I should finally be able to find some free time and push a new version soon~ish...

JoshMcguigan

comment created time in a month

issue commentgyscos/cursive

Disable MenuItem

Hi, and thanks for the report!

Looks like it's not possible right now, but that's certainly something we want to support!

MTCoster

comment created time in a month

issue commentgyscos/cursive

Suggestion: Template on user data type

Hi, and thanks for the report!

Unfortunately making Cursive generic on the stored user data type would bring a few issues. Callback types would need to be generic on this too, and so would the View trait. It would show up everywhere, adding a generic type to almost any type/functions throughout the library. It may also complicate type inference for closures taking a &mut Cursive<T>.

This would be much faster than dealing with memory allocation

While storing a new data would be faster, accessing it would not be very different. We can also add methods to let users re-use the existing Box allocation, so they don't have to keep re-allocating.

Overall I suspect it would be a lot of changes and a non-negligible impact on user experience, for little gains. It's always possible to ignore this user data entirely and build your own highly-efficient single-type shared storage, for cases where the current situation is not appropriate.

nothien

comment created time in a month

issue commentgyscos/cursive

Missing BufferView scrollable()

Hi, and thanks for the report!

The BufferView from the example may not have been implemented super carefully, especially if it's going to be embedded in a ScrollView. It doesn't really define its required size, or its "important area", which ScrollView relies on.

I probably should update the example to correctly implement that, making the BufferView there a bit more re-usable.

mikart143

comment created time in a month

issue commentgyscos/cursive

Missing text with LinearLayout combos

Hi! This is interesting - testing this code locally, I get the full test visible (as long as the terminal window is tall enough).

Screenshot from 2020-09-22 09-28-56

Could the terminal window be just too short? By default it will always try to keep 1 row on top and 1 row on the bottom - if that's a problem, we can find a way to skip that.

ph0llux

comment created time in a month

Pull request review commentgyscos/cursive

add new example: stopwatch

+use cursive::traits::*;++fn main() {+    let mut siv = cursive::default();+    let timer = Timer::TimerView::new();+    siv.add_layer(timer.fixed_width(8).with_name("timer"));+    siv.add_layer(cursive::views::Dialog::info(+        "Press 'Space' to start/pause/resume the timer!",+    ));+    siv.set_fps(5);+    siv.run();+}++mod Timer {+    use chrono::{DateTime, Duration, Local};+    use cursive::{+        event::{Callback, Event, EventResult, Key},+        view::View,+        Cursive, Printer,+    };+    use std::rc::Rc;++    pub struct TimerView {+        elapsed: Duration,+        last_update: DateTime<Local>,+        paused: bool,+        on_stop: Option<Rc<dyn Fn(&mut Cursive, Duration)>>,+    }++    impl TimerView {+        pub fn new() -> Self {+            Self {+                elapsed: Duration::zero(),+                last_update: Local::now(),+                on_stop: None,+                paused: true,+            }+        }+        pub fn pause(&mut self) {+            assert!(self.paused == false, "Already paused!");+            self.elapsed = self.read();+            self.paused = true;+        }+        pub fn resume(&mut self) {+            assert!(self.paused == true, "Already running!");+            self.last_update = Local::now();+            self.paused = false;+        }+        pub fn pause_or_resume(&mut self) {+            if self.paused {+                self.resume();+            } else {+                self.pause();+            }+        }+        pub fn read(&self) -> Duration {+            if self.paused {+                self.elapsed+            } else {+                self.elapsed + (Local::now() - self.last_update)+            }+        }++        /// Sets a callback to be used when `<Enter>` is pressed.+        ///+        /// Also happens if the user clicks an item.+        ///+        /// The elapsed time will be given to the callback.+        ///+        /// See also cursive::views::select_view::SelectView::on_submit+        pub fn on_stop<F, R>(&mut self, cb: F)+        where+            F: 'static + Fn(&mut Cursive, Duration) -> R,+        {+            self.on_stop = Some(Rc::new(move |s, t| {+                cb(s, t);+            }));+        }++        fn stop(&mut self) -> EventResult {+            self.pause();+            let cb = self.on_stop.clone().unwrap();+            // We return a Callback Rc<|s| cb(s, &*v)>+            EventResult::Consumed(Some(Callback::from_fn(move |s| {+                cb(s, self.elapsed)+            })))+        }+    }+    impl View for TimerView {+        fn draw(&self, printer: &Printer) {+            printer.print((0, 0), &pretty(self.read()));+        }++        fn on_event(&mut self, event: Event) -> EventResult {+            match event {+                // pause/resume the timer when pressing "Space"+                Event::Char(' ') => {+                    self.pause_or_resume();+                }+                Event::Key(Key::Enter) if self.on_stop.is_some() => {

Does that mean Enter does not stop the timer if no on_stop callback was given?

TianyiShi2001

comment created time in a month

PullRequestReviewEvent

Pull request review commentgyscos/cursive

add new example: stopwatch

+use cursive::traits::*;++fn main() {+    let mut siv = cursive::default();+    let timer = Timer::TimerView::new();+    siv.add_layer(timer.fixed_width(8).with_name("timer"));+    siv.add_layer(cursive::views::Dialog::info(+        "Press 'Space' to start/pause/resume the timer!",+    ));+    siv.set_fps(5);+    siv.run();+}++mod Timer {+    use chrono::{DateTime, Duration, Local};+    use cursive::{+        event::{Callback, Event, EventResult, Key},+        view::View,+        Cursive, Printer,+    };+    use std::rc::Rc;++    pub struct TimerView {+        elapsed: Duration,+        last_update: DateTime<Local>,+        paused: bool,+        on_stop: Option<Rc<dyn Fn(&mut Cursive, Duration)>>,+    }++    impl TimerView {+        pub fn new() -> Self {+            Self {+                elapsed: Duration::zero(),+                last_update: Local::now(),+                on_stop: None,+                paused: true,+            }+        }+        pub fn pause(&mut self) {+            assert!(self.paused == false, "Already paused!");+            self.elapsed = self.read();+            self.paused = true;+        }+        pub fn resume(&mut self) {+            assert!(self.paused == true, "Already running!");+            self.last_update = Local::now();+            self.paused = false;+        }+        pub fn pause_or_resume(&mut self) {+            if self.paused {+                self.resume();+            } else {+                self.pause();+            }+        }+        pub fn read(&self) -> Duration {+            if self.paused {+                self.elapsed+            } else {+                self.elapsed + (Local::now() - self.last_update)+            }+        }++        /// Sets a callback to be used when `<Enter>` is pressed.+        ///+        /// Also happens if the user clicks an item.+        ///+        /// The elapsed time will be given to the callback.+        ///+        /// See also cursive::views::select_view::SelectView::on_submit+        pub fn on_stop<F, R>(&mut self, cb: F)

The usual convention for views would be to have fn set_on_stop(&mut self, ...), and a chainable fn on_stop(self, ...) -> Self.

TianyiShi2001

comment created time in a month

PullRequestReviewEvent

pull request commentgyscos/cursive

add new example: stopwatch

I think when you write self.elapsed in the move closure, it tries to move self. Instead, define let elapsed = self.elapsed; before, since it's Copy it should let the closure move just the elapsed time, leaving self alone.

TianyiShi2001

comment created time in a month

pull request commentgyscos/cursive

new example: autocomplete search box

Thanks again for all the work! :)

TianyiShi2001

comment created time in a month

push eventgyscos/cursive

Tianyi Shi

commit sha 3ab4f9b0f749a19379540e56aa0c9253229e35dc

new example: autocomplete search box (#502) new example: autocomplete search box

view details

push time in a month

PR merged gyscos/cursive

new example: autocomplete search box

Thank you so much for making this crate that saved my life!

I'm making an app in which Google-like autocomplete search boxes are used often. While entering the query on the top of such a search box, filtered results should be generated below on the fly.

It seems that there isn't a ready-to-use View for this, so I made one by assembling existing Views. I guess it might be helpful to add this to examples.

+95 -0

4 comments

2 changed files

TianyiShi2001

pr closed time in a month

pull request commentgyscos/cursive

add new example: stopwatch

One solution is not to use a thread at all; instead, a structure will hold:

  • The current status (paused or running)
  • The current elapsed time
  • The time of last_update.

Then:

  • To read the time: if status is paused, return elapsed. Otherwise, return elapsed + now - last_update.
  • To pause the timer, update elapsed with the formula above, then change the status.
  • To resume the timer, just update the status.
TianyiShi2001

comment created time in a month

pull request commentgyscos/cursive

new example: autocomplete search box

Note re: the non-public status of submit: you can also call .on_event() with a return key to the view.

TianyiShi2001

comment created time in a month

Pull request review commentgyscos/cursive

new example: autocomplete search box

+use cursive::align::HAlign;+use cursive::traits::Scrollable;+use cursive::view::{Boxable, Identifiable};+use cursive::views::{Dialog, EditView, LinearLayout, SelectView, TextView};+use cursive::Cursive;+use lazy_static::lazy_static;++// This example shows a way to implement a (Google-like) autocomplete search box.+// Try entering "tok"!++lazy_static! {+    static ref CITIES: &'static str = include_str!("../../assets/cities.txt");+}++fn main() {+    let mut siv = cursive::default();++    siv.add_layer(+        Dialog::around(+            LinearLayout::vertical()+                // the query box is on the top+                .child(+                    EditView::new()+                        // update results every time the query changes+                        .on_edit(on_edit)+                        // submit the focused (first) item of the matches+                        .on_submit(on_submit)+                        .with_name("query"),+                )+                // search results below the input+                .child(+                    SelectView::new()+                        // shows all cities by default+                        .with_all_str(CITIES.lines())+                        // Sets the callback for when "Enter" is pressed.+                        .on_submit(show_next_window)+                        // Center the text horizontally+                        .h_align(HAlign::Center)+                        .with_name("matches")+                        .scrollable()+                        .fixed_size((20, 10)),

Do we actually care about the width? We could probably just fixed_height(10)?

TianyiShi2001

comment created time in a month

PullRequestReviewEvent

Pull request review commentgyscos/cursive

new example: autocomplete search box

+use cursive::align::HAlign;+use cursive::event::EventResult;+use cursive::traits::*;+use cursive::view::{Boxable, Identifiable};+use cursive::views::{+    Dialog, EditView, LinearLayout, OnEventView, SelectView, TextView,+};+use cursive::Cursive;+use lazy_static::lazy_static;++// This example shows a way to implement a (Google-like) autocomplete search box.+// Try entering "Tok"!++lazy_static! {+    static ref CITIES: &'static str = include_str!("../../assets/cities.txt");+}++fn main() {+    let mut siv = cursive::default();++    siv.add_layer(+        Dialog::around(+            LinearLayout::vertical()+                // the input is on the top+                .child(EditView::new().on_edit(on_edit).with_name("query"))+                // search results below the input+                .child(+                    SelectView::new()+                        // shows all cities by default+                        .with_all_str(CITIES.lines())+                        // Sets the callback for when "Enter" is pressed.+                        .on_submit(show_next_window)+                        // Center the text horizontally+                        .h_align(HAlign::Center)+                        .with_name("matches"),+                )+                .fixed_width(25),+        )+        .button("Quit", Cursive::quit),+    );++    siv.run();+}++// Update results according to the query+fn on_edit(siv: &mut Cursive, _content: &str, _cursor: usize) {+    // Get the query+    let query = siv.find_name::<EditView>("query").unwrap().get_content();+    // Filter cities with names that starts with the query string+    let matches = CITIES+        .lines()+        .filter(|&city| query.chars().zip(city.chars()).all(|(c, d)| c == d));

Also, maybe accepting more than just prefixes (using contains() instead) could help too?

TianyiShi2001

comment created time in a month

PullRequestReviewEvent

pull request commentgyscos/cursive

new example: autocomplete search box

Looks great! Just a detail regarding the string prefix check, but it looks pretty good!

TianyiShi2001

comment created time in a month

Pull request review commentgyscos/cursive

new example: autocomplete search box

+use cursive::align::HAlign;+use cursive::event::EventResult;+use cursive::traits::*;+use cursive::view::{Boxable, Identifiable};+use cursive::views::{+    Dialog, EditView, LinearLayout, OnEventView, SelectView, TextView,+};+use cursive::Cursive;+use lazy_static::lazy_static;++// This example shows a way to implement a (Google-like) autocomplete search box.+// Try entering "Tok"!++lazy_static! {+    static ref CITIES: &'static str = include_str!("../../assets/cities.txt");+}++fn main() {+    let mut siv = cursive::default();++    siv.add_layer(+        Dialog::around(+            LinearLayout::vertical()+                // the input is on the top+                .child(EditView::new().on_edit(on_edit).with_name("query"))+                // search results below the input+                .child(+                    SelectView::new()+                        // shows all cities by default+                        .with_all_str(CITIES.lines())+                        // Sets the callback for when "Enter" is pressed.+                        .on_submit(show_next_window)+                        // Center the text horizontally+                        .h_align(HAlign::Center)+                        .with_name("matches"),+                )+                .fixed_width(25),+        )+        .button("Quit", Cursive::quit),+    );++    siv.run();+}++// Update results according to the query+fn on_edit(siv: &mut Cursive, _content: &str, _cursor: usize) {+    // Get the query+    let query = siv.find_name::<EditView>("query").unwrap().get_content();+    // Filter cities with names that starts with the query string+    let matches = CITIES+        .lines()+        .filter(|&city| query.chars().zip(city.chars()).all(|(c, d)| c == d));

Maybe str::starts_with could help here?

TianyiShi2001

comment created time in a month

PullRequestReviewEvent

push eventgyscos/cursive

Mckol

commit sha 7b579a7d54daa891082ca396c2bf02b4eeec8826

Improved the `select` example. (#501) Now the `OnEventView.on_pre_event_inner()` calls return `Some(EventResult::Consumed(Some(Callback)))` instead of `Some(EventResult::Consumed(None))`. This follows the guidelines from documentation of methods returning a `Callback`, which say that it should be ran on the `Cursive`. While in this example this doesn't make a difference, the previous version created confusion for new users who might not realize you can pass the `Callback`s to the `Cursive` this way.

view details

push time in a month

PR merged gyscos/cursive

Improved the `select` example.

Introduction

This PR is an effect of my initial confusion with the intended way of handling Callbacks, and aims to help prevent that from happening to others in future.

Story time!

I wanted to add custom keybindings to a SelectView, so I looked through the examples and found the select example which looked like exactly what I needed. After replicating the OnEventView wrapper part of the code, the keybindings worked as far as navigating the SelectView went, but I noticed all the callbacks set with SelectView.on_select() were ignored with the custom keybindings but worked with the default arrow ones.
I started reading into the documentation, and noticed the SelectView.select_up() method returned a Callback, and the documentation said it should be ran on the Cursive. I couldn't figure out how to get a reference to Cursive inside the closure in OnEventView.on_event_inner() to run it like the documentation example has shown (something along the lines of callback(&mut siv) ), so I tried using OnEventView.on_event(), then getting a referece to the SelectView by name, and using Cursive.cb_sink() to send the Callbacks but apparently they weren't Sync so that didn't work out.

Not until having found #433 and this comment in particular did I realize that I should look at the documentation of EventResult, which, in turn, made me realize that I can just pass the Callback inside the EventResult.

Summary

I thought it would be a good idea to create this small PR to hopefully help other Cursive beginners be less confused :) It effectively doesn't change anything in this example as far as functionality goes, but it helps bring attention to this important way of handling Callbacks.

+4 -4

1 comment

1 changed file

Mckol

pr closed time in a month

pull request commentgyscos/cursive

Improved the `select` example.

Hi, and thanks for the PR! Indeed, it's probably best practice to always forward the event result here, even if the example itself does not make use of it.

Mckol

comment created time in a month

Pull request review commentrust-lang/rust

Update RELEASES.md for 1.47.0

+Version 1.47.0 (2020-10-08)+==========================++Language+--------++Compiler+--------+- [Stabilized the `-C control-flow-guard` codegen option.][73893] Which enables+  [Control Flow Guard][1.47.0-cfg] for Windows platforms, and is ignored on other+  platforms.+- [Upgraded to LLVM 11.][73526]+- [Added tier 3\* support for the `thumbv4t-none-eabi` target.][74419]+- [Upgrade the FreeBSD toolchain to version 11.4][75204]++Libraries+---------+- [`CStr` now implements `Index<RangeFrom<usize>>`.][74021]+- [Traits in `std`/`core` are now implemented for arrays of any length, not just+  those of length less than 33.][74060]+- [`ops::RangeFull`, and `ops::Range` now implement Default.][73197]+- [`panic::Location` now implements `Copy`, `Clone`, `Eq`, `Hash`, `Ord`,+  `PartialEq`, and `PartialOrd`.][73583]++Stabilized APIs+---------------+- [`Ident::new_raw`]+- [`Range::is_empty`]+- [`RangeInclusive::is_empty`]+- [`Result::as_deref`]+- [`Result::as_deref_mut`]+- [`Vec::leak`]+- [`pointer::offset_from`]+- [`f32::TAU`]+- [`f64::TAU`]++The following previously stable APIs have now been made const.++- [`TypeId::of`]+- [The `new` method for all `NonZero` integers.][73858]+- [The `checked_add`,`checked_sub`,`checked_mul`,`checked_neg`, `checked_shl`,+  `checked_shr`, `saturating_add`, `saturating_sub`, and `saturating_mul`+  methods for all integers.][73858]+- [The `checked_abs`, `saturating_abs`, `saturating_neg`, and `signum`  for all+  signed integers.][73858]+- [The `is_ascii_alphabetic`, `is_ascii_uppercase`, `is_ascii_lowercase`,+  `is_ascii_alphanumeric`, `is_ascii_digit`, `is_ascii_hexdigit`,+  `is_ascii_punctuation`, `is_ascii_graphic`, `is_ascii_whitespace`, and+  `is_ascii_control` methods for `char` and `u8`.][73858]++Cargo+-----+- [`build-dependencies` are now built with opt-level 0 by default.][cargo/8500]+  You can override this by setting the following in your `Cargo.toml`.+  ```toml+  [profile.release.build-override]+  opt-level = 3+  ```+- [`cargo-help` will now display man pages for commands rather just the+  `--help` text.][cargo/8456]+- [`cargo-metadata` now emits a `test` field indicating if a target has+  tests enabled.][cargo/8478]+- [`workspace.default-members` now respects `workspace.exclude`.][cargo/8485]+- [`cargo-publish` will now use an alternative registry by default if it's the+  only registry specified in `package.publish`.][cargo/8571]++Misc+----+- [Added the `rustc-docs` component.][75560] This allows you to install+  and read the documentation for the compiler internal APIs. (Currently only+  available for `x86_64-unknown-linux-gnu`.)+- [Added a help button beside Rustdoc's searchbar that explains rustdoc's+  type based search.][75366]++Compatibility Notes+-------------------+- [The `missing_fragment_specifier` lint has been converted to a hard error.][75516]+  This lint had been set to `deny` by default since 2017.+- [Bumped the minimum supported Emscripten version to 1.39.20.][75716]+- [Bumped the minimum supported LLVM version to 10.0.0.][75908]+- [Fixed a regression parsing `{} && false` in tail expressions.][74650]+- [Added changes to how proc-macros are expanded in `macro_rules!` that should+  help to preserve more span information.][73084] These changes may cause+  compiliation errors if your macro was unhygenic or didn't correctly handle+  some delimiter information.+- [Moved support for the CloudABI target to tier 3.][75568]++Internal Only+--------+- [Improved default stages of the compiler to use for each of the commands+  in `x.py`.][73964]++[1.47.0-cfg]: https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard+[73858]: https://github.com/rust-lang/rust/pull/73858/+[75716]: https://github.com/rust-lang/rust/pull/75716/+[75908]: https://github.com/rust-lang/rust/pull/75908/+[75516]: https://github.com/rust-lang/rust/pull/75516/+[75560]: https://github.com/rust-lang/rust/pull/75560/+[75568]: https://github.com/rust-lang/rust/pull/75568/+[75366]: https://github.com/rust-lang/rust/pull/75366/+[75204]: https://github.com/rust-lang/rust/pull/75204/+[74650]: https://github.com/rust-lang/rust/pull/74650/+[74419]: https://github.com/rust-lang/rust/pull/74419/+[73964]: https://github.com/rust-lang/rust/pull/73964/+[74021]: https://github.com/rust-lang/rust/pull/74021/+[74060]: https://github.com/rust-lang/rust/pull/74060/+[73893]: https://github.com/rust-lang/rust/pull/73893/+[73526]: https://github.com/rust-lang/rust/pull/73526/+[73583]: https://github.com/rust-lang/rust/pull/73583/+[73084]: https://github.com/rust-lang/rust/pull/73084/+[73197]: https://github.com/rust-lang/rust/pull/73197/+[72488]: https://github.com/rust-lang/rust/pull/72488/+[cargo/8456]: https://github.com/rust-lang/cargo/pull/8456/+[cargo/8478]: https://github.com/rust-lang/cargo/pull/8478/+[cargo/8485]: https://github.com/rust-lang/cargo/pull/8485/+[cargo/8500]: https://github.com/rust-lang/cargo/pull/8500/+[cargo/8571]: https://github.com/rust-lang/cargo/pull/8571/+[`Ident::new_raw`]:  https://doc.rust-lang.org/nightly/proc_macro/struct.Ident.html#method.new_raw+[`Range::is_empty`]: https://doc.rust-lang.org/nightly/std/ops/struct.Range.html#method.is_empty+[`RangeInclusive::is_empty`]: https://doc.rust-lang.org/nightly/std/ops/struct.Range.html#method.is_empty
[`RangeInclusive::is_empty`]: https://doc.rust-lang.org/nightly/std/ops/struct.RangeInclusive.html#method.is_empty
XAMPPRocky

comment created time in 2 months

PullRequestReviewEvent

issue commentgraphql-python/gql

Run multiple mutations in one request

Looks good to me, thanks!

Felix-N

comment created time in 2 months

push eventgyscos/cursive

Alexandre Bury

commit sha b5651e3ac4a5e1802a467231433b309991ae5555

Add test for empty span after hard-stop

view details

Alexandre Bury

commit sha e7a813b3837323335b96c0f83d328a135ae85a68

Fix chunk_iterator with empty spans after hard-stop

view details

push time in 2 months

issue commentgyscos/cursive

crash on showing specially crafted string

Ah yeah we totally assume that any line-breaking character is 1-byte in utf-8... smart...

I pushed a tentative fix (and added this as a text case). Though now I see a new problem: ncurses behaves differently from other backends like termion/crossterm when attempting to print control characters like \u{7f} or \u{1d}:

Ncurses tries to print something: Screenshot from 2020-08-26 15-20-59

Crossterm just ignores it: Screenshot from 2020-08-26 15-20-49

UnicodeWidth returns a 0-width for these control characters, so the correct behaviour would be not to print them.

But rather than patching ncurses to not print them, it may be easier to sanitize the user input and remove these characters from any provided string?

On the other hand, there is a longer-term plan to bring something like agavrilov/cursive_buffered_backend in cursive itself, keeping an internal character grid before flushing to the backend. If we had that, it would be easy to ignore any zero-width grapheme.

alexanderkjall

comment created time in 2 months

push eventgyscos/cursive

Alexandre Bury

commit sha f13914a272e31b1a6b6f76e03e0d97a36b0ad92f

Add test

view details

Alexandre Bury

commit sha 7e32e0649e7fd4ab79b585fb3021760be021e31f

Fix handling of multi-bytes newlines

view details

push time in 2 months

push eventgyscos/cursive

Alexandre Bury

commit sha eec4dd8e68dccddd61b2c1cc70b3aafa11a53021

Fix unimported CString

view details

push time in 2 months

issue commentgyscos/cursive

Borders are printed as garbage

Well, until pancurses merges https://github.com/ihalila/pancurses/pull/78, I updated the backend here to call setlocale. Does it fix your issue?

krytarowski

comment created time in 2 months

push eventgyscos/cursive

Alexandre Bury

commit sha e2f79776a41a2acd2daffea3af130c6396b2a289

Manuall call setlocale for pancurses backend Once (if?) pancurses merges the corresponding PR[1], we can revert that. [1]: https://github.com/ihalila/pancurses/pull/78

view details

push time in 2 months

PR opened jeaye/ncurses-rs

Use libc::setlocale

This removes the setlocale binding, instead relying on the one from libc. It also re-exports the LC_ALL & cie constants from libc, rather than re-defining them here.

This is more portable: libc goes to great length to support many platforms (with platform-dependents constants and links), no need to re-invent the wheel here.

Concretely, this fixes an issue with NetBSD where setlocale should actually link to __setlocale50. libc does it correctly, so let's just take that.

+6 -14

0 comment

3 changed files

pr created time in 2 months

push eventgyscos/ncurses-rs

Kornel

commit sha 54aaca63115649092ce44f4796175d8a4444a50f

Upgrade cc crate

view details

Jeaye Wilkerson

commit sha ab4165eccb3f75bdb55baca59098eea298e303e7

Merge pull request #167 from kornelski/master Upgrade cc crate

view details

jeaye

commit sha 6568749e7bb31e36d1bcd8e14aaace64cb0a542e

Bump version

view details

Jeaye Wilkerson

commit sha fd131617e64a69773ae05fc70301197cdb0c3538

Merge pull request #165 from gyscos/master Add mouse_v1 feature and detection

view details

jeaye

commit sha 836d8bd5b8b32bbb45394f4ec3a7267adc8d6684

Bumpb version

view details

Alexandre Bury

commit sha 840c9ccae704cd792a08505432e62641be22ea8d

Add NCURSES_MOUSE_VERSION constant Among other uses, it allows dependent libraries to trigger their own `mouse_v1` feature based on this constant without the need for the same C-program-compilation trick.

view details

Jeaye Wilkerson

commit sha eb420abab0a4a12aed764609ea4c3be77419f144

Merge pull request #170 from gyscos/patch-1 Add NCURSES_MOUSE_VERSION constant

view details

jeaye

commit sha 6112e078624a28342ec95a30363ce54cbe77d1a0

Bump version

view details

jeaye

commit sha 0fc09b1ac17a8600f799fca48fe062d55def5155

Fix syntax issue with mouse constants

view details

Alexandre Bury

commit sha cca69835232d6619207fcadb761621ea77f65d3a

Update constants.rs Let's keep these variables defined even in legacy mouse mode. They will overlap with `BUTTON_CTRL` and others, but at least it'll maintain build compatibility with existing dependent libraries. In addition, this simplifies these constants definition by only using `mouse_v1` to define some shift values, which are then used more uniformly.

view details

Jeaye Wilkerson

commit sha b8a2405fd22231cc878064925bc34c75ddcd461c

Merge pull request #171 from gyscos/patch-4 Update constants.rs

view details

jeaye

commit sha 29661df42c3db0a3b1cc3bbe75f8116d93ac9fe4

Bump version

view details

Dominik Werder

commit sha b0a9d649501798b0d2a51274d67f3b8823a33e05

Use environment variables NCURSES_RS_RUSTC_LINK_LIB used for cargo:rustc-link-lib NCURSES_RS_RUSTC_FLAGS used for cargo:rustc-flags NCURSES_RS_CFLAGS used for compilation of test program in `check_chtype_size`

view details

Dominik Werder

commit sha 6846a39b939c8ca9bd65383e17edef7a1b86a891

Update README.md

view details

Czipperz

commit sha 572d1f6015a173f1c18e3fe62f257d142edb377f

`wmouse_trafo` should take a `WINDOW` not a `*mut WINDOW`

view details

Jeaye Wilkerson

commit sha 328502a100cd71fcea875c686ceed15931b048fd

Merge pull request #175 from czipperz/master `wmouse_trafo` should take a `WINDOW` not a `*mut WINDOW`

view details

jeaye

commit sha 55be2ec2f9e69f2b3870547be75cff93d27ebc7c

Bump version

view details

Maciej Augustyniak

commit sha e093c2b7b6ecbf34f8afbd87ee111df256957e41

Marked printw function as deprecated

view details

Maciej Augustyniak

commit sha a9165de8065bab6ee6969a1b31ddac549f634c15

Removed unsafe

view details

Maciej Augustyniak

commit sha 7fcee591341b3d37c25676cbac868bd27b4b2087

Added unsafe inside function

view details

push time in 2 months

pull request commenttime-rs/time

On NetBSD, link tzset to __tzset50.

Yeah what void tzset(void) __RENAME(__tzset50); does is, at the source level, redirrect calls to tzset to __tzset50. But it only works for actual C code that imports time.h; the true tzset symbol is part of the compatibility layer and doesn't really work.

I agree it'd be nice to have a NetBSD-test that we can show fails before this patch, and passes after. I'm not really a NetBSD user so I'm not 100% sure how to go about that; maybe some CI service offer NetBSD builds?

In https://github.com/hrkfdn/ncspot/pull/256 @krytarowski mentioned building this crate (albeit for an older version) resulted in the following warning:

          ld: /tmp/ncspot/target/debug/deps/libtime-166e0e30576a5331.rlib(time-166e0e30576a5331.time.ey6x0hik-cgu.1.rcgu.o): in function `time::tzset':
          /home/kamil/.cargo/registry/src/github.com-1ecc6299db9ec823/time-0.1.43/src/lib.rs:287: warning: warning: reference to compatibility tzset(); include <time.h> for correct reference
gyscos

comment created time in 2 months

pull request commenthrkfdn/ncspot

Use libc for setlocale() to fix non-ASCII

If no rust binding currently exist to this library, then you would have to create such a netbsd-curses-sys crate (and possibly a "safe" wrapper on top?). Once this is done and rust can call functions from this library, a new backend for Cursive would have to be written. If the API is similar to ncurses then I assume a lot of code could be shared with the current pan/ncurses backends.

voidpin

comment created time in 2 months

more