mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-06-04 07:21:14 -03:00
Extract unwrapping for buffer-writes that are assumed to not fail
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
use crate::global_safety::RelaxedAtomicBool;
|
||||
use crate::key;
|
||||
use crate::libc::MB_CUR_MAX;
|
||||
use crate::output::Output;
|
||||
use crate::parse_util::parse_util_escape_string_with_quote;
|
||||
use crate::termsize::Termsize;
|
||||
use crate::wchar::{decode_byte_from_char, encode_byte_to_char, prelude::*};
|
||||
@@ -1377,6 +1378,38 @@ pub fn write_loop<Fd: AsRawFd>(fd: &Fd, buf: &[u8]) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Output writes always succeed; this adapter allows us to use it in a write-like macro.
|
||||
struct OutputWriteAdapter<'a, T: Output>(&'a mut T);
|
||||
|
||||
impl<'a, T: Output> std::fmt::Write for OutputWriteAdapter<'a, T> {
|
||||
fn write_str(&mut self, s: &str) -> std::fmt::Result {
|
||||
self.0.write_bytes(s.as_bytes());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Output> std::io::Write for OutputWriteAdapter<'a, T> {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
self.0.write_bytes(buf);
|
||||
Ok(buf.len())
|
||||
}
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn do_write_to_output(writer: &mut impl Output, args: std::fmt::Arguments<'_>) {
|
||||
let mut adapter = OutputWriteAdapter(writer);
|
||||
std::fmt::write(&mut adapter, args).unwrap()
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! write_to_output {
|
||||
($out:expr, $($arg:tt)*) => {{
|
||||
$crate::common::do_write_to_output($out, format_args!($($arg)*));
|
||||
}};
|
||||
}
|
||||
|
||||
/// A rusty port of the C++ `read_loop()` function from `common.cpp`. This should be deprecated in
|
||||
/// favor of native rust read/write methods at some point.
|
||||
///
|
||||
|
||||
@@ -42,6 +42,16 @@ pub fn set_color_support(val: ColorSupport) {
|
||||
COLOR_SUPPORT.store(val.bits(), Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub(crate) trait Output {
|
||||
fn write_bytes(&mut self, buf: &[u8]);
|
||||
}
|
||||
|
||||
impl Output for Vec<u8> {
|
||||
fn write_bytes(&mut self, buf: &[u8]) {
|
||||
self.extend_from_slice(buf);
|
||||
}
|
||||
}
|
||||
|
||||
fn index_for_color(c: RgbColor) -> u8 {
|
||||
if c.is_named() || !(get_color_support().contains(ColorSupport::TERM_256COLOR)) {
|
||||
return c.to_name_index();
|
||||
@@ -65,14 +75,13 @@ fn write_color_escape(outp: &mut Outputter, term: &Term, todo: &CStr, mut idx: u
|
||||
if term.max_colors == Some(8) && idx > 8 {
|
||||
idx -= 8;
|
||||
}
|
||||
write!(
|
||||
write_to_output!(
|
||||
outp,
|
||||
"\x1B[{}m",
|
||||
(if idx > 7 { 82 } else { 30 }) + i32::from(idx) + ((i32::from(!is_fg)) * 10)
|
||||
)
|
||||
.expect("Writing to in-memory buffer should never fail");
|
||||
);
|
||||
} else {
|
||||
write!(outp, "\x1B[{};5;{}m", if is_fg { 38 } else { 48 }, idx).unwrap();
|
||||
write_to_output!(outp, "\x1B[{};5;{}m", if is_fg { 38 } else { 48 }, idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,15 +192,14 @@ pub fn write_color(&mut self, color: RgbColor, is_fg: bool) -> bool {
|
||||
// Foreground: ^[38;2;<r>;<g>;<b>m
|
||||
// Background: ^[48;2;<r>;<g>;<b>m
|
||||
let rgb = color.to_color24();
|
||||
write!(
|
||||
write_to_output!(
|
||||
self,
|
||||
"\x1B[{};2;{};{};{}m",
|
||||
if is_fg { 38 } else { 48 },
|
||||
rgb.r,
|
||||
rgb.g,
|
||||
rgb.b
|
||||
)
|
||||
.expect("Outputter::write should never fail");
|
||||
);
|
||||
true
|
||||
}
|
||||
|
||||
@@ -423,6 +431,13 @@ fn flush(&mut self) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Output for Outputter {
|
||||
fn write_bytes(&mut self, buf: &[u8]) {
|
||||
self.contents.extend_from_slice(buf);
|
||||
self.maybe_flush();
|
||||
}
|
||||
}
|
||||
|
||||
impl Outputter {
|
||||
/// Emit a terminfo string, like tputs.
|
||||
/// affcnt (number of lines affected) is assumed to be 1, i.e. not applicable.
|
||||
@@ -472,17 +487,9 @@ fn drop(&mut self) {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Write for BufferedOuputter<'a> {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
self.0
|
||||
.write(buf)
|
||||
.expect("Writing to in-memory buffer should never fail");
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<()> {
|
||||
self.0.flush().unwrap();
|
||||
Ok(())
|
||||
impl<'a> Output for BufferedOuputter<'a> {
|
||||
fn write_bytes(&mut self, buf: &[u8]) {
|
||||
self.0.write_bytes(buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
use crate::output::parse_color;
|
||||
use crate::output::parse_color_maybe_none;
|
||||
use crate::output::BufferedOuputter;
|
||||
use crate::output::Output;
|
||||
use crate::output::Outputter;
|
||||
use crate::pager::{PageRendering, Pager, SelectionMotion};
|
||||
use crate::panic::AT_EXIT;
|
||||
@@ -689,12 +690,11 @@ fn read_i(parser: &Parser) {
|
||||
data.clear(EditableLineTag::Commandline);
|
||||
data.update_buff_pos(EditableLineTag::Commandline, None);
|
||||
// OSC 133 "Command start"
|
||||
write!(
|
||||
write_to_output!(
|
||||
&mut BufferedOuputter::new(Outputter::stdoutput()),
|
||||
"\x1b]133;C;cmdline_url={}\x07",
|
||||
escape_string(&command, EscapeStringStyle::Url),
|
||||
)
|
||||
.unwrap();
|
||||
);
|
||||
event::fire_generic(parser, L!("fish_preexec").to_owned(), vec![command.clone()]);
|
||||
let eval_res = reader_run_command(parser, &command);
|
||||
signal_clear_cancel();
|
||||
@@ -707,12 +707,11 @@ fn read_i(parser: &Parser) {
|
||||
parser.libdata_mut().exit_current_script = false;
|
||||
|
||||
// OSC 133 "Command finished"
|
||||
write!(
|
||||
write_to_output!(
|
||||
&mut BufferedOuputter::new(Outputter::stdoutput()),
|
||||
"\x1b]133;D;{}\x07",
|
||||
parser.get_last_status()
|
||||
)
|
||||
.unwrap();
|
||||
);
|
||||
event::fire_generic(parser, L!("fish_postexec").to_owned(), vec![command]);
|
||||
// Allow any pending history items to be returned in the history array.
|
||||
data.history.resolve_pending();
|
||||
@@ -1451,7 +1450,7 @@ pub fn request_cursor_position(
|
||||
assert!(wait_guard.is_none());
|
||||
*wait_guard = Some(BlockingWait::CursorPosition(cursor_position_wait));
|
||||
}
|
||||
let _ = out.write_all(b"\x1b[6n");
|
||||
out.write_bytes(b"\x1b[6n");
|
||||
self.save_screen_state();
|
||||
}
|
||||
|
||||
@@ -2580,7 +2579,7 @@ fn handle_char_event(&mut self, injected_event: Option<CharEvent>) -> ControlFlo
|
||||
}
|
||||
}
|
||||
|
||||
fn xtgettcap(out: &mut impl Write, cap: &str) {
|
||||
fn xtgettcap(out: &mut impl Output, cap: &str) {
|
||||
FLOG!(
|
||||
reader,
|
||||
format!(
|
||||
@@ -2589,16 +2588,16 @@ fn xtgettcap(out: &mut impl Write, cap: &str) {
|
||||
format!("\x1bP+q{}\x1b\\", DisplayAsHex(cap))
|
||||
)
|
||||
);
|
||||
let _ = write!(out, "\x1bP+q{}\x1b\\", DisplayAsHex(cap));
|
||||
write_to_output!(out, "\x1bP+q{}\x1b\\", DisplayAsHex(cap));
|
||||
}
|
||||
|
||||
fn query_capabilities_via_dcs(out: &mut impl std::io::Write) {
|
||||
let _ = out.write_all(b"\x1b[?2026h"); // begin synchronized update
|
||||
let _ = out.write_all(b"\x1b[?1049h"); // enable alternative screen buffer
|
||||
xtgettcap(out.by_ref(), "indn");
|
||||
xtgettcap(out.by_ref(), "cuu");
|
||||
let _ = out.write_all(b"\x1b[?1049l"); // disable alternative screen buffer
|
||||
let _ = out.write_all(b"\x1b[?2026l"); // end synchronized update
|
||||
fn query_capabilities_via_dcs(out: &mut impl Output) {
|
||||
out.write_bytes(b"\x1b[?2026h"); // begin synchronized update
|
||||
out.write_bytes(b"\x1b[?1049h"); // enable alternative screen buffer
|
||||
xtgettcap(out, "indn");
|
||||
xtgettcap(out, "cuu");
|
||||
out.write_bytes(b"\x1b[?1049l"); // disable alternative screen buffer
|
||||
out.write_bytes(b"\x1b[?2026l"); // end synchronized update
|
||||
}
|
||||
|
||||
impl<'a> Reader<'a> {
|
||||
|
||||
Reference in New Issue
Block a user