Skip to content

Commit

Permalink
Add methods to write text without erasing the prompt
Browse files Browse the repository at this point in the history
* Renames `Interface::lock_writer` to `lock_writer_erase` and
  `Prompter::writer` to `writer_erase`
* Adds `Interface::lock_writer_append` and `Prompter::writer_append`,
  which move the cursor to a new line before writing
* Retain `Interface::write_fmt` as shortcut to an erasing write,
  with a note about its behavior
  • Loading branch information
murarth committed May 31, 2018
1 parent 87ec9bb commit 442ce8d
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 17 deletions.
4 changes: 3 additions & 1 deletion examples/demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ fn main() -> io::Result<()> {
thread_id += 1;
}
"history" => {
for (i, entry) in interface.lock_writer()?.history().enumerate() {
let w = interface.lock_writer_erase()?;

for (i, entry) in w.history().enumerate() {
println!("{}: {}", i, entry);
}
}
Expand Down
2 changes: 1 addition & 1 deletion examples/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct DemoFunction;
impl<Term: Terminal> Function<Term> for DemoFunction {
fn execute(&self, prompter: &mut Prompter<Term>, _count: i32, _ch: char) -> io::Result<()> {
assert_eq!(prompter.sequence(), DEMO_FN_SEQ);
let mut writer = prompter.writer()?;
let mut writer = prompter.writer_erase()?;

writeln!(writer, "demo function executed")
}
Expand Down
27 changes: 24 additions & 3 deletions src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,31 @@ impl<Term: Terminal> Interface<Term> {
Reader::new(self, self.lock_read())
}

/// Acquires the write lock and returns a `Writer` instance.
///
/// If a `read_line` call is in progress, this method will move the cursor
/// to a new line after the prompt, allowing output to be written without
/// corrupting the prompt text. The prompt will be redrawn when the `Writer`
/// instance is dropped.
///
/// To instead erase the prompt and write text, use [`lock_writer_erase`].
///
/// [`lock_writer_erase`]: #method.lock_writer_erase
pub fn lock_writer_append(&self) -> io::Result<Writer<Term>> {
Writer::with_lock(self.lock_write(), false)
}

/// Acquires the write lock and returns a `Writer` instance.
///
/// If a `read_line` call is in progress, this method will erase the prompt,
/// allowing output to be written without corrupting the prompt text.
/// The prompt will be redrawn when the `Writer` instance is dropped.
pub fn lock_writer(&self) -> io::Result<Writer<Term>> {
Writer::with_mutex(self.lock_write())
///
/// To instead write text after the prompt, use [`lock_writer_append`].
///
/// [`lock_writer_append`]: #method.lock_writer_append
pub fn lock_writer_erase(&self) -> io::Result<Writer<Term>> {
Writer::with_lock(self.lock_write(), true)
}

fn lock_read(&self) -> ReadLock<Term> {
Expand Down Expand Up @@ -340,15 +358,18 @@ impl<Term: Terminal> Interface<Term> {
/// Therefore, the written text should end with a newline. If the `writeln!`
/// macro is used, a newline is automatically added to the end of the text.
///
/// To instead write text after the prompt, use [`lock_writer_append`].
///
/// [`read_line`]: #method.read_line
/// [`writeln!`]: https://doc.rust-lang.org/std/macro.writeln.html
/// [`lock_writer_append`]: #method.lock_writer_append
pub fn write_fmt(&self, args: fmt::Arguments) -> io::Result<()> {
let s = args.to_string();
self.write_str(&s)
}

fn write_str(&self, line: &str) -> io::Result<()> {
self.lock_writer()?.write_str(line)
self.lock_writer_erase()?.write_str(line)
}
}

Expand Down
21 changes: 19 additions & 2 deletions src/prompter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,30 @@ impl<'a, 'b: 'a, Term: 'b + Terminal> Prompter<'a, 'b, Term> {
Prompter{read, write}
}

/// Returns a `Writer` instance using the currently held write lock.
///
/// This method will move the cursor to a new line after the prompt,
/// allowing output to be written without corrupting the prompt text.
/// The prompt will be redrawn when the `Writer` instance is dropped.
///
/// To instead erase the prompt and write text, use [`writer_erase`].
///
/// [`writer_erase`]: #method.writer_erase
pub fn writer_append<'c>(&'c mut self) -> io::Result<Writer<'c, 'b, Term>> {
Writer::with_ref(&mut self.write, false)
}

/// Returns a `Writer` instance using the currently held write lock.
///
/// This method will erase the prompt, allowing output to be written
/// without corrupting the prompt text. The prompt will be redrawn
/// when the `Writer` instance is dropped.
pub fn writer<'c>(&'c mut self) -> io::Result<Writer<'c, 'b, Term>> {
Writer::with_ref(&mut self.write)
///
/// To instead write text after the prompt, use [`writer_append`].
///
/// [`writer_append`]: #method.writer_append
pub fn writer_erase<'c>(&'c mut self) -> io::Result<Writer<'c, 'b, Term>> {
Writer::with_ref(&mut self.write, true)
}

/// Resets input state at the start of `read_line`
Expand Down
26 changes: 16 additions & 10 deletions src/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@ const PROMPT_SEARCH_SUFFIX: usize = 3;
/// Holds a lock on terminal write operations.
/// See [`Interface`] for more information about concurrent operations.
///
/// An instance of this type can be constructed using the
/// [`Interface::lock_writer`] method.
/// An instance of this type can be constructed using either the
/// [`Interface::lock_writer_append`] or the [`Interface::lock_writer_erase`]
/// method.
///
/// [`Interface`]: ../interface/struct.Interface.html
/// [`Interface::lock_writer`]: ../interface/struct.Interface.html#method.lock_writer
/// [`Interface::lock_writer_append`]: ../interface/struct.Interface.html#method.lock_writer_append
/// [`Interface::lock_writer_erase`]: ../interface/struct.Interface.html#method.lock_writer_erase
pub struct Writer<'a, 'b: 'a, Term: 'b + Terminal> {
write: WriterImpl<'a, 'b, Term>,
}
Expand Down Expand Up @@ -927,24 +929,28 @@ impl<'a, Term: Terminal> WriteLock<'a, Term> {
self.input_arg = digit;
self.explicit_arg = true;
}

}

impl<'a, 'b: 'a, Term: 'b + Terminal> Writer<'a, 'b, Term> {
fn new(mut write: WriterImpl<'a, 'b, Term>) -> io::Result<Self> {
fn new(mut write: WriterImpl<'a, 'b, Term>, clear: bool) -> io::Result<Self> {
if write.is_prompt_drawn {
write.clear_full_prompt()?;
if clear {
write.clear_full_prompt()?;
} else {
write.move_to_end()?;
write.write_str("\n")?;
}
}

Ok(Writer{write})
}

pub(crate) fn with_mutex(write: WriteLock<'b, Term>) -> io::Result<Self> {
Writer::new(WriterImpl::Mutex(write))
pub(crate) fn with_lock(write: WriteLock<'b, Term>, clear: bool) -> io::Result<Self> {
Writer::new(WriterImpl::Mutex(write), clear)
}

pub(crate) fn with_ref(write: &'a mut WriteLock<'b, Term>) -> io::Result<Self> {
Writer::new(WriterImpl::MutRef(write))
pub(crate) fn with_ref(write: &'a mut WriteLock<'b, Term>, clear: bool) -> io::Result<Self> {
Writer::new(WriterImpl::MutRef(write), clear)
}

/// Returns an iterator over history entries.
Expand Down

0 comments on commit 442ce8d

Please sign in to comment.