forked from mirrors/jj
cli: leverage Stdout/errLock in place of Mutex<Box<dyn Write>>
Since stdout/stderr has its own locking mechanism, we don't need yet another Mutex.
This commit is contained in:
parent
536cab4cd7
commit
6a126bc033
1 changed files with 50 additions and 14 deletions
64
src/ui.rs
64
src/ui.rs
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::io::Write;
|
use std::io::{Stderr, Stdout, Write};
|
||||||
use std::path::{Component, Path, PathBuf};
|
use std::path::{Component, Path, PathBuf};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::{Mutex, MutexGuard};
|
use std::sync::{Mutex, MutexGuard};
|
||||||
|
@ -27,8 +27,7 @@ use crate::formatter::{Formatter, FormatterFactory};
|
||||||
pub struct Ui<'a> {
|
pub struct Ui<'a> {
|
||||||
cwd: PathBuf,
|
cwd: PathBuf,
|
||||||
formatter_factory: FormatterFactory,
|
formatter_factory: FormatterFactory,
|
||||||
stdout: Mutex<Box<dyn Write + 'a>>,
|
output_pair: UiOutputPair<'a>,
|
||||||
stderr: Mutex<Box<dyn Write + 'a>>,
|
|
||||||
settings: UserSettings,
|
settings: UserSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,18 +86,27 @@ impl<'stdout> Ui<'stdout> {
|
||||||
Ui {
|
Ui {
|
||||||
cwd,
|
cwd,
|
||||||
formatter_factory,
|
formatter_factory,
|
||||||
stdout: Mutex::new(stdout),
|
output_pair: UiOutputPair::Dyn {
|
||||||
stderr: Mutex::new(stderr),
|
stdout: Mutex::new(stdout),
|
||||||
|
stderr: Mutex::new(stderr),
|
||||||
|
},
|
||||||
settings,
|
settings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn for_terminal(settings: UserSettings) -> Ui<'static> {
|
pub fn for_terminal(settings: UserSettings) -> Ui<'static> {
|
||||||
let cwd = std::env::current_dir().unwrap();
|
let cwd = std::env::current_dir().unwrap();
|
||||||
let stdout: Box<dyn Write + 'static> = Box::new(io::stdout());
|
|
||||||
let stderr: Box<dyn Write + 'static> = Box::new(io::stderr());
|
|
||||||
let color = use_color(color_setting(&settings));
|
let color = use_color(color_setting(&settings));
|
||||||
Ui::new(cwd, stdout, stderr, color, settings)
|
let formatter_factory = FormatterFactory::prepare(&settings, color);
|
||||||
|
Ui {
|
||||||
|
cwd,
|
||||||
|
formatter_factory,
|
||||||
|
output_pair: UiOutputPair::Terminal {
|
||||||
|
stdout: io::stdout(),
|
||||||
|
stderr: io::stderr(),
|
||||||
|
},
|
||||||
|
settings,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reconfigures the underlying outputs with the new color choice.
|
/// Reconfigures the underlying outputs with the new color choice.
|
||||||
|
@ -129,22 +137,39 @@ impl<'stdout> Ui<'stdout> {
|
||||||
/// Labels added to the returned formatter should be removed by caller.
|
/// Labels added to the returned formatter should be removed by caller.
|
||||||
/// Otherwise the last color would persist.
|
/// Otherwise the last color would persist.
|
||||||
pub fn stdout_formatter<'a>(&'a self) -> Box<dyn Formatter + 'a> {
|
pub fn stdout_formatter<'a>(&'a self) -> Box<dyn Formatter + 'a> {
|
||||||
let output = DynWriteLock(self.stdout.lock().unwrap());
|
match &self.output_pair {
|
||||||
self.new_formatter(output)
|
UiOutputPair::Dyn { stdout, .. } => {
|
||||||
|
let output = DynWriteLock(stdout.lock().unwrap());
|
||||||
|
self.new_formatter(output)
|
||||||
|
}
|
||||||
|
UiOutputPair::Terminal { stdout, .. } => self.new_formatter(stdout.lock()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a formatter for the locked stderr stream.
|
/// Creates a formatter for the locked stderr stream.
|
||||||
pub fn stderr_formatter<'a>(&'a self) -> Box<dyn Formatter + 'a> {
|
pub fn stderr_formatter<'a>(&'a self) -> Box<dyn Formatter + 'a> {
|
||||||
let output = DynWriteLock(self.stderr.lock().unwrap());
|
match &self.output_pair {
|
||||||
self.new_formatter(output)
|
UiOutputPair::Dyn { stderr, .. } => {
|
||||||
|
let output = DynWriteLock(stderr.lock().unwrap());
|
||||||
|
self.new_formatter(output)
|
||||||
|
}
|
||||||
|
UiOutputPair::Terminal { stderr, .. } => self.new_formatter(stderr.lock()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(&mut self, text: &str) -> io::Result<()> {
|
pub fn write(&mut self, text: &str) -> io::Result<()> {
|
||||||
self.stdout.get_mut().unwrap().write_all(text.as_bytes())
|
let data = text.as_bytes();
|
||||||
|
match &mut self.output_pair {
|
||||||
|
UiOutputPair::Dyn { stdout, .. } => stdout.get_mut().unwrap().write_all(data),
|
||||||
|
UiOutputPair::Terminal { stdout, .. } => stdout.write_all(data),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
|
pub fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
|
||||||
self.stdout.get_mut().unwrap().write_fmt(fmt)
|
match &mut self.output_pair {
|
||||||
|
UiOutputPair::Dyn { stdout, .. } => stdout.get_mut().unwrap().write_fmt(fmt),
|
||||||
|
UiOutputPair::Terminal { stdout, .. } => stdout.write_fmt(fmt),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_hint(&mut self, text: impl AsRef<str>) -> io::Result<()> {
|
pub fn write_hint(&mut self, text: impl AsRef<str>) -> io::Result<()> {
|
||||||
|
@ -201,6 +226,17 @@ impl<'stdout> Ui<'stdout> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum UiOutputPair<'output> {
|
||||||
|
Dyn {
|
||||||
|
stdout: Mutex<Box<dyn Write + 'output>>,
|
||||||
|
stderr: Mutex<Box<dyn Write + 'output>>,
|
||||||
|
},
|
||||||
|
Terminal {
|
||||||
|
stdout: Stdout,
|
||||||
|
stderr: Stderr,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
/// Wrapper to implement `Write` for locked `Box<dyn Write>`.
|
/// Wrapper to implement `Write` for locked `Box<dyn Write>`.
|
||||||
struct DynWriteLock<'a, 'output>(MutexGuard<'a, Box<dyn Write + 'output>>);
|
struct DynWriteLock<'a, 'output>(MutexGuard<'a, Box<dyn Write + 'output>>);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue