Mercurial > public > mercurial-scm > hg-stable
view rust/rhg/src/ui.rs @ 48550:47f2a82ae3e4
rhg: Fall back to Python if verbose status is requested by config
Differential Revision: https://phab.mercurial-scm.org/D11943
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Sat, 18 Dec 2021 11:47:03 +0100 |
parents | 38deb65d4441 |
children | 99b1dfc06571 |
line wrap: on
line source
use format_bytes::format_bytes; use std::borrow::Cow; use std::env; use std::io; use std::io::{ErrorKind, Write}; #[derive(Debug)] pub struct Ui { stdout: std::io::Stdout, stderr: std::io::Stderr, } /// The kind of user interface error pub enum UiError { /// The standard output stream cannot be written to StdoutError(io::Error), /// The standard error stream cannot be written to StderrError(io::Error), } /// The commandline user interface impl Ui { pub fn new() -> Self { Ui { stdout: std::io::stdout(), stderr: std::io::stderr(), } } /// Returns a buffered handle on stdout for faster batch printing /// operations. pub fn stdout_buffer(&self) -> StdoutBuffer<std::io::StdoutLock> { StdoutBuffer::new(self.stdout.lock()) } /// Write bytes to stdout pub fn write_stdout(&self, bytes: &[u8]) -> Result<(), UiError> { let mut stdout = self.stdout.lock(); stdout.write_all(bytes).or_else(handle_stdout_error)?; stdout.flush().or_else(handle_stdout_error) } /// Write bytes to stderr pub fn write_stderr(&self, bytes: &[u8]) -> Result<(), UiError> { let mut stderr = self.stderr.lock(); stderr.write_all(bytes).or_else(handle_stderr_error)?; stderr.flush().or_else(handle_stderr_error) } /// Return whether plain mode is active. /// /// Plain mode means that all configuration variables which affect /// the behavior and output of Mercurial should be /// ignored. Additionally, the output should be stable, /// reproducible and suitable for use in scripts or applications. /// /// The only way to trigger plain mode is by setting either the /// `HGPLAIN' or `HGPLAINEXCEPT' environment variables. /// /// The return value can either be /// - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT /// - False if feature is disabled by default and not included in HGPLAIN /// - True otherwise pub fn plain(&self) -> bool { // TODO: add support for HGPLAINEXCEPT env::var_os("HGPLAIN").is_some() } } /// A buffered stdout writer for faster batch printing operations. pub struct StdoutBuffer<W: Write> { buf: io::BufWriter<W>, } impl<W: Write> StdoutBuffer<W> { pub fn new(writer: W) -> Self { let buf = io::BufWriter::new(writer); Self { buf } } /// Write bytes to stdout buffer pub fn write_all(&mut self, bytes: &[u8]) -> Result<(), UiError> { self.buf.write_all(bytes).or_else(handle_stdout_error) } /// Flush bytes to stdout pub fn flush(&mut self) -> Result<(), UiError> { self.buf.flush().or_else(handle_stdout_error) } } /// Sometimes writing to stdout is not possible, try writing to stderr to /// signal that failure, otherwise just bail. fn handle_stdout_error(error: io::Error) -> Result<(), UiError> { if let ErrorKind::BrokenPipe = error.kind() { // This makes `| head` work for example return Ok(()); } let mut stderr = io::stderr(); stderr .write_all(&format_bytes!( b"abort: {}\n", error.to_string().as_bytes() )) .map_err(UiError::StderrError)?; stderr.flush().map_err(UiError::StderrError)?; Err(UiError::StdoutError(error)) } /// Sometimes writing to stderr is not possible. fn handle_stderr_error(error: io::Error) -> Result<(), UiError> { // A broken pipe should not result in a error // like with `| head` for example if let ErrorKind::BrokenPipe = error.kind() { return Ok(()); } Err(UiError::StdoutError(error)) } /// Encode rust strings according to the user system. pub fn utf8_to_local(s: &str) -> Cow<[u8]> { // TODO encode for the user's system // let bytes = s.as_bytes(); Cow::Borrowed(bytes) }