-
Notifications
You must be signed in to change notification settings - Fork 280
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Command API experiment #175
Conversation
Hi. As someone looking to use this library, I'd be quite saddened if macros were introduced into the public API for this. In my humble opinion, macros should be used specifically to extend Rust's syntax, not for something as trivial as variadic functions. May I suggest using a builder pattern instead? write_chain(stdout)
.and(Goto(x, y))
.and(Output(String::from("#")))
.finish(); In my opinion, this is far more intuitive and doesn't undermine the rich semantics and visual guarantees that make Rust such a pleasant language to work with. |
Thanks for your input. Indeed macro's should be used for cases where they are meant for. Although macros are also super powerful in rust, and it is a feature a lot of people use. Also in public API. So we either do:
Or
I have several problems with the builder idea
write_chain(stdout)
.and(Goto(x, y));
// some code
write_chain(stdout)
.and(Goto(x, y));
// some code
write_chain(stdout)
.and(Goto(x, y))
finishe(); This would work way better with the macro where we do: schedule!(stdout, Goto(x, y);
// some code
schedule!(stdout, Goto(x, y);
// some code
schedule!(stdout, Goto(x, y);
stdout.flush()
default_write_chain(stdout)
.and(Goto(x, y)); And with macro's we can just leave a way that argument: schedule!(Goto(x, y); So all with all, I still prefer the macro functions,
|
To address your concerns:
A trait implemented for all stdout
.queue(Goto(x, y))
.queue('!')
.queue(Goto(a, b))
.flush(); In the single case, it's just a matter of doing
|
I'll take your concern into consideration, I will make a test that works with the type system as well. |
I currently implemented via the function as well: We have two traits: pub trait QueueableCommand<T: Display> {
fn queue(mut self, command: impl Command<AnsiType = T>) -> Self;
}
pub trait ExecutableCommand<T: Display> {
fn execute(mut self, command: impl Command<AnsiType = T>) -> Self;
} I implement those traits for all types implementing impl<T, A> QueueableCommand<A> for T
where
A: Display,
T: Write,
{
fn queue(mut self, command: impl Command<AnsiType = A>) -> Self {
schedule!(self, command);
self
}
}
impl<T, A> ExecutableCommand<A> for T
where
A: Display,
T: Write,
{
fn execute(mut self, command: impl Command<AnsiType = A>) -> Self {
execute!(self, command);
self
}
} Now I am able to call the queue and executing functionality on Stdout: let mut stdout = ::std::io::stdout();
stdout
.queue(Goto(5, 5))
.queue(Output("#".to_string()))
.flush();
stdout.execute(Goto(4,5)); And it works also :) |
We have two options:
macros // writing on default stdout
schedule!(Goto(x, y), Output("#"));
::std::io::flush();
// writing on a custom type that implements `Write`
schedule!(my_type, Goto(x, y), Output("#")); Builder: // writing on default stdout
::std::io::stdout()
.queue(Goto(5, 5))
.queue(Output("#".to_string()))
.flush();
// writing on a custom type that implements `Write`
my_type
.queue(Goto(5, 5))
.queue(Output("#".to_string()))
.flush(); |
Nice job! I much prefer this design, thanks for working on it. |
Will be merged now, documentation, examples, and comments are all finished. I implemented this branch for both TUI and cursive, to test the functionality. Will be released soon under version 10 |
This pull request is an experiment with issue: #171, it introduces a macro which writes commands onto the given
Write
type. The use can manually callflush
to clear the buffer. By using this API, we can improve the performance bottleneck we are currently experimenting because there is a lot of flushing going on.