Adopt the new output.rs

This switches output.cpp from C++ to Rust.
This commit is contained in:
ridiculousfish 2023-05-28 16:13:54 -07:00 committed by Peter Ammon
parent 8f38e175ce
commit 84b24d5615
10 changed files with 152 additions and 456 deletions

View file

@ -56,6 +56,7 @@ fn main() {
"src/job_group.rs",
"src/kill.rs",
"src/null_terminated_array.rs",
"src/output.rs",
"src/parse_constants.rs",
"src/parse_tree.rs",
"src/parse_util.rs",

View file

@ -492,7 +492,7 @@ fn update_fish_color_support(vars: &EnvStack) {
let mut color_support = ColorSupport::NONE;
color_support.set(ColorSupport::TERM_256COLOR, supports_256color);
color_support.set(ColorSupport::TERM_24BIT, supports_24bit);
crate::output::output_set_color_support(color_support);
crate::output::set_color_support(color_support);
}
/// Try to initialize the terminfo/curses subsystem using our fallback terminal name. Do not set

View file

@ -24,20 +24,20 @@ bitflags! {
}
}
/// FFI bits.
pub fn output_set_color_support(value: ColorSupport) {
extern "C" {
pub fn output_set_color_support(value: libc::c_int);
}
unsafe {
output_set_color_support(value.bits() as i32);
}
}
/// Whether term256 and term24bit are supported.
static COLOR_SUPPORT: AtomicU8 = AtomicU8::new(0);
/// FFI bits.
#[no_mangle]
extern "C" fn output_get_color_support() -> u8 {
COLOR_SUPPORT.load(Ordering::Relaxed)
}
#[no_mangle]
extern "C" fn output_set_color_support(val: u8) {
COLOR_SUPPORT.store(val, Ordering::Relaxed);
}
/// Returns true if we think tparm can handle outputting a color index.
fn term_supports_color_natively(term: &Term, c: i32) -> bool {
#[allow(clippy::int_plus_one)]
@ -646,3 +646,91 @@ pub fn writembs_check<T: Borrow<Option<CString>>>(
FLOG!(error, text);
}
}
/// FFI junk.
fn stdoutput_ffi() -> &'static mut Outputter {
// TODO: this is bogus because it avoids RefCell's check, but is temporary for FFI purposes.
unsafe { &mut *Outputter::stdoutput().as_ptr() }
}
/// Make an outputter which outputs to its string.
fn make_buffering_outputter_ffi() -> Box<Outputter> {
Box::new(Outputter::new_buffering())
}
type RgbColorFFI = crate::ffi::rgb_color_t;
use crate::wchar_ffi::AsWstr;
impl Outputter {
fn set_color_ffi(&mut self, fg: &RgbColorFFI, bg: &RgbColorFFI) {
self.set_color(fg.from_ffi(), bg.from_ffi());
}
fn writech_ffi(&mut self, ch: crate::ffi::wchar_t) {
self.writech(char::from_u32(ch).expect("Invalid wchar"));
}
// Write a nul-terminated string.
// We accept CxxString because it prevents needing to do typecasts at the call site,
// as it's unclear what Cxx type corresponds to const char *.
// We are unconcerned with interior nul-bytes: none of the termcap sequences contain them
// for obvious reasons.
fn writembs_ffi(&mut self, mbs: &cxx::CxxString) {
let mbs = unsafe { CStr::from_ptr(mbs.as_ptr() as *const std::ffi::c_char) };
writembs!(self, Some(mbs.to_owned()));
}
fn writestr_ffi(&mut self, str: crate::ffi::wcharz_t) {
self.write_wstr(str.as_wstr());
}
fn write_color_ffi(&mut self, color: &RgbColorFFI, is_fg: bool) -> bool {
self.write_color(color.from_ffi(), is_fg)
}
}
#[cxx::bridge]
mod ffi {
extern "C++" {
include!("color.h");
include!("wutil.h");
#[cxx_name = "rgb_color_t"]
type RgbColorFFI = super::RgbColorFFI;
type wcharz_t = crate::ffi::wcharz_t;
}
extern "Rust" {
#[cxx_name = "outputter_t"]
type Outputter;
#[cxx_name = "make_buffering_outputter"]
fn make_buffering_outputter_ffi() -> Box<Outputter>;
#[cxx_name = "stdoutput"]
fn stdoutput_ffi() -> &'static mut Outputter;
#[cxx_name = "set_color"]
fn set_color_ffi(&mut self, fg: &RgbColorFFI, bg: &RgbColorFFI);
#[cxx_name = "writech"]
fn writech_ffi(&mut self, ch: wchar_t);
#[cxx_name = "writestr"]
fn writestr_ffi(&mut self, str: wcharz_t);
#[cxx_name = "writembs"]
fn writembs_ffi(&mut self, mbs: &CxxString);
#[cxx_name = "write_color"]
fn write_color_ffi(&mut self, color: &RgbColorFFI, is_fg: bool) -> bool;
// These do not need separate FFI variants.
fn contents(&self) -> &[u8];
fn begin_buffering(&mut self);
fn end_buffering(&mut self);
#[cxx_name = "push_back"]
fn push(&mut self, ch: u8);
}
}

View file

@ -67,7 +67,8 @@ static void print_modifiers(outputter_t &outp, bool bold, bool underline, bool i
static void print_colors(io_streams_t &streams, std::vector<wcstring> args, bool bold,
bool underline, bool italics, bool dim, bool reverse, rgb_color_t bg) {
outputter_t outp;
rust::Box<outputter_t> outputter = make_buffering_outputter();
outputter_t &outp = *outputter;
if (args.empty()) args = rgb_color_t::named_color_names();
for (const auto &color_name : args) {
if (!streams.out_is_redirected && isatty(STDOUT_FILENO)) {
@ -78,7 +79,7 @@ static void print_colors(io_streams_t &streams, std::vector<wcstring> args, bool
outp.write_color(bg, false /* not is_fg */);
}
}
outp.writestr(color_name);
outp.writestr(color_name.c_str());
if (!bg.is_none()) {
// If we have a background, stop it after the color
// or it goes to the end of the line and looks ugly.
@ -87,7 +88,9 @@ static void print_colors(io_streams_t &streams, std::vector<wcstring> args, bool
outp.writech(L'\n');
} // conveniently, 'normal' is always the last color so we don't need to reset here
streams.out.append(str2wcstring(outp.contents()));
auto contents = outp.contents();
streams.out.append(
str2wcstring(reinterpret_cast<const char *>(contents.data()), contents.size()));
}
static const wchar_t *const short_options = L":b:hoidrcu";
@ -210,7 +213,8 @@ maybe_t<int> builtin_set_color(parser_t &parser, io_streams_t &streams, const wc
if (cur_term == nullptr || !exit_attribute_mode) {
return STATUS_CMD_ERROR;
}
outputter_t outp;
rust::Box<outputter_t> outputter = make_buffering_outputter();
outputter_t &outp = *outputter;
print_modifiers(outp, bold, underline, italics, dim, reverse, bg);
@ -236,7 +240,9 @@ maybe_t<int> builtin_set_color(parser_t &parser, io_streams_t &streams, const wc
}
// Output the collected string.
streams.out.append(str2wcstring(outp.contents()));
auto contents = outp.contents();
streams.out.append(
str2wcstring(reinterpret_cast<const char *>(contents.data()), contents.size()));
return STATUS_CMD_OK;
}

View file

@ -1296,19 +1296,20 @@ std::string colorize(const wcstring &text, const std::vector<highlight_spec_t> &
const environment_t &vars) {
assert(colors.size() == text.size());
highlight_color_resolver_t rv;
outputter_t outp;
rust::Box<outputter_t> outp = make_buffering_outputter();
highlight_spec_t last_color = highlight_role_t::normal;
for (size_t i = 0; i < text.size(); i++) {
highlight_spec_t color = colors.at(i);
if (color != last_color) {
outp.set_color(rv.resolve_spec(color, false, vars), rgb_color_t::normal());
outp->set_color(rv.resolve_spec(color, false, vars), rgb_color_t::normal());
last_color = color;
}
outp.writech(text.at(i));
outp->writech(text.at(i));
}
outp.set_color(rgb_color_t::normal(), rgb_color_t::normal());
return outp.contents();
outp->set_color(rgb_color_t::normal(), rgb_color_t::normal());
auto contents = outp->contents();
return std::string(contents.begin(), contents.end());
}
void highlight_shell(const wcstring &buff, std::vector<highlight_spec_t> &color,

View file

@ -33,297 +33,9 @@
#include "wcstringutil.h"
#include "wutil.h" // IWYU pragma: keep
/// Whether term256 and term24bit are supported.
static color_support_t color_support = 0;
/// Returns true if we think fish_tparm can handle outputting a color index
static bool term_supports_color_natively(unsigned int c) {
return static_cast<unsigned>(max_colors) >= c + 1;
}
extern "C" {
void output_set_color_support(color_support_t val) { color_support = val; }
color_support_t output_get_color_support() { return color_support; }
}
unsigned char index_for_color(rgb_color_t c) {
if (c.is_named() || !(output_get_color_support() & color_support_term256)) {
return c.to_name_index();
}
return c.to_term256_index();
}
static bool write_color_escape(outputter_t &outp, const char *todo, unsigned char idx, bool is_fg) {
if (term_supports_color_natively(idx)) {
// Use fish_tparm to emit color escape.
writembs(outp, fish_tparm(const_cast<char *>(todo), idx));
return true;
}
// We are attempting to bypass the term here. Generate the ANSI escape sequence ourself.
char buff[16] = "";
if (idx < 16) {
// this allows the non-bright color to happen instead of no color working at all when a
// bright is attempted when only colors 0-7 are supported.
//
// TODO: enter bold mode in builtin_set_color in the same circumstance- doing that combined
// with what we do here, will make the brights actually work for virtual consoles/ancient
// emulators.
if (max_colors == 8 && idx > 8) idx -= 8;
snprintf(buff, sizeof buff, "\x1B[%dm", ((idx > 7) ? 82 : 30) + idx + !is_fg * 10);
} else {
snprintf(buff, sizeof buff, "\x1B[%d;5;%dm", is_fg ? 38 : 48, idx);
}
outp.writestr(buff);
return true;
}
static bool write_foreground_color(outputter_t &outp, unsigned char idx) {
if (!cur_term) return false;
if (set_a_foreground && set_a_foreground[0]) {
return write_color_escape(outp, set_a_foreground, idx, true);
} else if (set_foreground && set_foreground[0]) {
return write_color_escape(outp, set_foreground, idx, true);
}
return false;
}
static bool write_background_color(outputter_t &outp, unsigned char idx) {
if (!cur_term) return false;
if (set_a_background && set_a_background[0]) {
return write_color_escape(outp, set_a_background, idx, false);
} else if (set_background && set_background[0]) {
return write_color_escape(outp, set_background, idx, false);
}
return false;
}
void outputter_t::flush_to(int fd) {
if (fd >= 0 && !contents_.empty()) {
write_loop(fd, contents_.data(), contents_.size());
contents_.clear();
}
}
// Exported for builtin_set_color's usage only.
bool outputter_t::write_color(rgb_color_t color, bool is_fg) {
if (!cur_term) return false;
bool supports_term24bit =
static_cast<bool>(output_get_color_support() & color_support_term24bit);
if (!supports_term24bit || !color.is_rgb()) {
// Indexed or non-24 bit color.
unsigned char idx = index_for_color(color);
return (is_fg ? write_foreground_color : write_background_color)(*this, idx);
}
// 24 bit! No fish_tparm here, just ANSI escape sequences.
// Foreground: ^[38;2;<r>;<g>;<b>m
// Background: ^[48;2;<r>;<g>;<b>m
color24_t rgb = color.to_color24();
char buff[128];
snprintf(buff, sizeof buff, "\x1B[%d;2;%u;%u;%um", is_fg ? 38 : 48, rgb.rgb[0], rgb.rgb[1],
rgb.rgb[2]);
writestr(buff);
return true;
}
/// Sets the fg and bg color. May be called as often as you like, since if the new color is the same
/// as the previous, nothing will be written. Negative values for set_color will also be ignored.
/// Since the terminfo string this function emits can potentially cause the screen to flicker, the
/// function takes care to write as little as possible.
///
/// Possible values for colors are rgb_color_t colors or special values like rgb_color_t::normal()
///
/// In order to set the color to normal, three terminfo strings may have to be written.
///
/// - First a string to set the color, such as set_a_foreground. This is needed because otherwise
/// the previous strings colors might be removed as well.
///
/// - After that we write the exit_attribute_mode string to reset all color attributes.
///
/// - Lastly we may need to write set_a_background or set_a_foreground to set the other half of the
/// color pair to what it should be.
///
/// \param fg Foreground color.
/// \param bg Background color.
void outputter_t::set_color(rgb_color_t fg, rgb_color_t bg) {
// Test if we have at least basic support for setting fonts, colors and related bits - otherwise
// just give up...
if (!cur_term || !exit_attribute_mode) return;
const rgb_color_t normal = rgb_color_t::normal();
bool bg_set = false, last_bg_set = false;
bool is_bold = fg.is_bold() || bg.is_bold();
bool is_underline = fg.is_underline() || bg.is_underline();
bool is_italics = fg.is_italics() || bg.is_italics();
bool is_dim = fg.is_dim() || bg.is_dim();
bool is_reverse = fg.is_reverse() || bg.is_reverse();
if (fg.is_reset() || bg.is_reset()) {
fg = bg = normal;
reset_modes();
// If we exit attribute mode, we must first set a color, or previously colored text might
// lose it's color. Terminals are weird...
write_foreground_color(*this, 0);
writembs(*this, exit_attribute_mode);
return;
}
if ((was_bold && !is_bold) || (was_dim && !is_dim) || (was_reverse && !is_reverse)) {
// Only way to exit bold/dim/reverse mode is a reset of all attributes.
writembs(*this, exit_attribute_mode);
last_color = normal;
last_color2 = normal;
reset_modes();
}
if (!last_color2.is_special()) {
// Background was set.
// "Special" here refers to the special "normal", "reset" and "none" colors,
// that really jus disable the background.
last_bg_set = true;
}
if (!bg.is_special()) {
// Background is set.
bg_set = true;
if (fg == bg)
fg = (bg == rgb_color_t::white()) ? rgb_color_t::black() : rgb_color_t::white();
}
if (enter_bold_mode && enter_bold_mode[0] != '\0') {
if (bg_set && !last_bg_set) {
// Background color changed and is set, so we enter bold mode to make reading easier.
// This means bold mode is _always_ on when the background color is set.
writembs_nofail(*this, enter_bold_mode);
}
if (!bg_set && last_bg_set) {
// Background color changed and is no longer set, so we exit bold mode.
writembs(*this, exit_attribute_mode);
reset_modes();
// We don't know if exit_attribute_mode resets colors, so we set it to something known.
if (write_foreground_color(*this, 0)) {
last_color = rgb_color_t::black();
}
}
}
if (last_color != fg) {
if (fg.is_normal()) {
write_foreground_color(*this, 0);
writembs(*this, exit_attribute_mode);
last_color2 = rgb_color_t::normal();
reset_modes();
} else if (!fg.is_special()) {
write_color(fg, true /* foreground */);
}
}
last_color = fg;
if (last_color2 != bg) {
if (bg.is_normal()) {
write_background_color(*this, 0);
writembs(*this, exit_attribute_mode);
if (!last_color.is_normal()) {
write_color(last_color, true /* foreground */);
}
reset_modes();
last_color2 = bg;
} else if (!bg.is_special()) {
write_color(bg, false /* not foreground */);
last_color2 = bg;
}
}
// Lastly, we set bold, underline, italics, dim, and reverse modes correctly.
if (is_bold && !was_bold && enter_bold_mode && enter_bold_mode[0] != '\0' && !bg_set) {
// The unconst cast is for NetBSD's benefit. DO NOT REMOVE!
writembs_nofail(*this, fish_tparm(const_cast<char *>(enter_bold_mode)));
was_bold = is_bold;
}
if (was_underline && !is_underline) {
writembs_nofail(*this, exit_underline_mode);
}
if (!was_underline && is_underline) {
writembs_nofail(*this, enter_underline_mode);
}
was_underline = is_underline;
if (was_italics && !is_italics && enter_italics_mode && enter_italics_mode[0] != '\0') {
writembs_nofail(*this, exit_italics_mode);
was_italics = is_italics;
}
if (!was_italics && is_italics && enter_italics_mode && enter_italics_mode[0] != '\0') {
writembs_nofail(*this, enter_italics_mode);
was_italics = is_italics;
}
if (is_dim && !was_dim && enter_dim_mode && enter_dim_mode[0] != '\0') {
writembs_nofail(*this, enter_dim_mode);
was_dim = is_dim;
}
if (is_reverse && !was_reverse) {
// Some terms do not have a reverse mode set, so standout mode is a fallback.
if (enter_reverse_mode && enter_reverse_mode[0] != '\0') {
writembs_nofail(*this, enter_reverse_mode);
was_reverse = is_reverse;
} else if (enter_standout_mode && enter_standout_mode[0] != '\0') {
writembs_nofail(*this, enter_standout_mode);
was_reverse = is_reverse;
}
}
}
// tputs accepts a function pointer that receives an int only.
// Use the following lock to redirect it to the proper outputter.
// Note we can't use owning_lock because the tputs_writer must access it and owning_lock is not
// recursive.
static std::mutex s_tputs_receiver_lock;
static outputter_t *s_tputs_receiver{nullptr};
static int tputs_writer(tputs_arg_t b) {
ASSERT_IS_LOCKED(s_tputs_receiver_lock);
assert(s_tputs_receiver && "null s_tputs_receiver");
char c = static_cast<char>(b);
s_tputs_receiver->writestr(&c, 1);
return 0;
}
int outputter_t::term_puts(const char *str, int affcnt) {
// Acquire the lock, use a scoped_push to substitute in our receiver, then call tputs. The
// scoped_push will restore it.
scoped_lock locker{s_tputs_receiver_lock};
scoped_push<outputter_t *> push(&s_tputs_receiver, this);
s_tputs_receiver->begin_buffering();
// On some systems, tputs takes a char*, on others a const char*.
// Like fish_tparm, we just cast it to unconst, that should work everywhere.
int res = tputs(const_cast<char *>(str), affcnt, tputs_writer);
s_tputs_receiver->end_buffering();
return res;
}
void outputter_t::writestr(const wchar_t *str, size_t len) {
wcs2string_appending(str, len, &contents_);
maybe_flush();
}
outputter_t &outputter_t::stdoutput() {
ASSERT_IS_MAIN_THREAD();
static outputter_t res(STDOUT_FILENO);
return res;
}
/// Given a list of rgb_color_t, pick the "best" one, as determined by the color support. Returns
/// rgb_color_t::none() if empty.
/// TODO: This is duplicated with Rust.
rgb_color_t best_color(const std::vector<rgb_color_t> &candidates, color_support_t support) {
if (candidates.empty()) {
return rgb_color_t::none();
@ -355,6 +67,7 @@ rgb_color_t best_color(const std::vector<rgb_color_t> &candidates, color_support
/// Return the internal color code representing the specified color.
/// TODO: This code should be refactored to enable sharing with builtin_set_color.
/// In particular, the argument parsing still isn't fully capable.
/// TODO: This is duplicated with Rust.
rgb_color_t parse_color(const env_var_t &var, bool is_background) {
bool is_bold = false;
bool is_underline = false;
@ -425,17 +138,9 @@ rgb_color_t parse_color(const env_var_t &var, bool is_background) {
return result;
}
/// Write specified multibyte string.
void writembs_check(outputter_t &outp, const char *mbs, const char *mbs_name, bool critical,
const char *file, long line) {
if (mbs != nullptr) {
outp.term_puts(mbs, 1);
} else if (critical) {
auto term = env_stack_t::globals().get(L"TERM");
const wchar_t *fmt =
_(L"Tried to use terminfo string %s on line %ld of %s, which is "
L"undefined in terminal of type \"%ls\". Please report this error to %s");
FLOG(error, fmt, mbs_name, line, file, term ? term->as_string().c_str() : L"",
PACKAGE_BUGREPORT);
}
void writembs_nofail(outputter_t &outp, const char *str) {
assert(str != nullptr && "Null string");
outp.writembs(str);
}
void writembs(outputter_t &outp, const char *str) { writembs_nofail(outp, str); }

View file

@ -5,135 +5,32 @@
#ifndef FISH_OUTPUT_H
#define FISH_OUTPUT_H
#include <cstdint>
#include <cstring>
#include <cwchar>
#include <string>
#include <vector>
#include <stdint.h>
#include "color.h"
#include "common.h"
#include "fallback.h" // IWYU pragma: keep
#if INCLUDE_RUST_HEADERS
#include "output.rs.h"
#else
// Hacks to allow us to compile without Rust headers.
struct outputter_t;
#endif
class env_var_t;
class outputter_t {
/// Storage for buffered contents.
std::string contents_;
/// Count of how many outstanding begin_buffering() calls there are.
uint32_t buffer_count_{0};
/// fd to output to.
int fd_{-1};
rgb_color_t last_color = rgb_color_t::normal();
rgb_color_t last_color2 = rgb_color_t::normal();
bool was_bold = false;
bool was_underline = false;
bool was_italics = false;
bool was_dim = false;
bool was_reverse = false;
void reset_modes() {
was_bold = false;
was_underline = false;
was_italics = false;
was_dim = false;
was_reverse = false;
}
/// Construct an outputter which outputs to a given fd.
explicit outputter_t(int fd) : fd_(fd) {}
/// Flush output, if we have a set fd and our buffering count is 0.
void maybe_flush() {
if (fd_ >= 0 && buffer_count_ == 0) flush_to(fd_);
}
public:
/// Construct an outputter which outputs to its string.
outputter_t() = default;
/// Unconditionally write the color string to the output.
bool write_color(rgb_color_t color, bool is_fg);
/// Set the foreground and background color.
void set_color(rgb_color_t fg, rgb_color_t bg);
/// Write a wide character to the receiver.
void writech(wchar_t ch) { writestr(&ch, 1); }
/// Write a NUL-terminated wide character string to the receiver.
void writestr(const wchar_t *str) { writestr(str, wcslen(str)); }
/// Write a wide character string to the receiver.
void writestr(const wcstring &str) { writestr(str.data(), str.size()); }
/// Write the given terminfo string to the receiver, like tputs().
int term_puts(const char *str, int affcnt);
/// Write a wide string of the given length.
void writestr(const wchar_t *str, size_t len);
/// Write a narrow string of the given length.
void writestr(const char *str, size_t len) {
contents_.append(str, len);
maybe_flush();
}
/// Write a narrow NUL-terminated string.
void writestr(const char *str) { writestr(str, std::strlen(str)); }
/// Write a narrow character.
void push_back(char c) {
contents_.push_back(c);
maybe_flush();
}
/// \return the "output" contents.
const std::string &contents() const { return contents_; }
/// Output any buffered data to the given \p fd.
void flush_to(int fd);
/// Begins buffering. Output will not be automatically flushed until a corresponding
/// end_buffering() call.
void begin_buffering() {
buffer_count_++;
assert(buffer_count_ > 0 && "bufferCount_ overflow");
}
/// Balance a begin_buffering() call.
void end_buffering() {
assert(buffer_count_ > 0 && "bufferCount_ underflow");
buffer_count_--;
maybe_flush();
}
/// Accesses the singleton stdout outputter.
/// This can only be used from the main thread.
/// This outputter flushes its buffer after every write operation.
static outputter_t &stdoutput();
};
void writembs_check(outputter_t &outp, const char *mbs, const char *mbs_name, bool critical,
const char *file, long line);
#define writembs(outp, mbs) writembs_check((outp), (mbs), #mbs, true, __FILE__, __LINE__)
#define writembs_nofail(outp, mbs) writembs_check((outp), (mbs), #mbs, false, __FILE__, __LINE__)
rgb_color_t parse_color(const env_var_t &var, bool is_background);
/// Sets what colors are supported.
enum { color_support_term256 = 1 << 0, color_support_term24bit = 1 << 1 };
using color_support_t = unsigned int;
using color_support_t = uint8_t;
extern "C" {
color_support_t output_get_color_support();
void output_set_color_support(color_support_t val);
color_support_t output_get_color_support();
void output_set_color_support(color_support_t val);
}
rgb_color_t best_color(const std::vector<rgb_color_t> &candidates, color_support_t support);
unsigned char index_for_color(rgb_color_t c);
// Temporary to support builtin set_color.
void writembs_nofail(outputter_t &outp, const char *str);
void writembs(outputter_t &outp, const char *str);
#endif

View file

@ -1569,7 +1569,7 @@ void reader_write_title(const wcstring &cmd, parser_t &parser, bool reset_cursor
ignore_result(write_loop(STDOUT_FILENO, narrow.data(), narrow.size()));
}
outputter_t::stdoutput().set_color(rgb_color_t::reset(), rgb_color_t::reset());
stdoutput().set_color(rgb_color_t::reset(), rgb_color_t::reset());
if (reset_cursor_position && !lst.empty()) {
// Put the cursor back at the beginning of the line (issue #2453).
ignore_result(write(STDOUT_FILENO, "\r", 1));
@ -2611,7 +2611,7 @@ static void reader_interactive_init(parser_t &parser) {
/// Destroy data for interactive use.
static void reader_interactive_destroy() {
outputter_t::stdoutput().set_color(rgb_color_t::reset(), rgb_color_t::reset());
stdoutput().set_color(rgb_color_t::reset(), rgb_color_t::reset());
}
/// Set the specified string as the current buffer.
@ -2747,7 +2747,7 @@ static eval_res_t reader_run_command(parser_t &parser, const wcstring &cmd) {
parser.vars().set_one(L"_", ENV_GLOBAL, ft);
}
outputter_t &outp = outputter_t::stdoutput();
outputter_t &outp = stdoutput();
reader_write_title(cmd, parser);
outp.set_color(rgb_color_t::normal(), rgb_color_t::normal());
term_donate();
@ -2924,7 +2924,7 @@ void reader_change_cursor_selection_mode(cursor_selection_mode_t selection_mode)
}
void reader_change_cursor_selection_mode(uint8_t selection_mode) {
reader_change_cursor_selection_mode((cursor_selection_mode_t) selection_mode);
reader_change_cursor_selection_mode((cursor_selection_mode_t)selection_mode);
}
static bool check_autosuggestion_enabled(const env_stack_t &vars) {
@ -3482,7 +3482,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
}
case rl::cancel_commandline: {
if (!command_line.empty()) {
outputter_t &outp = outputter_t::stdoutput();
outputter_t &outp = stdoutput();
// Move cursor to the end of the line.
update_buff_pos(&command_line, command_line.size());
autosuggestion.clear();
@ -4285,7 +4285,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
break;
}
case rl::disable_mouse_tracking: {
outputter_t &outp = outputter_t::stdoutput();
outputter_t &outp = stdoutput();
outp.writestr(L"\x1B[?1000l");
break;
}
@ -4624,7 +4624,7 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
if (errno == EIO) redirect_tty_output();
wperror(L"tcsetattr"); // return to previous mode
}
outputter_t::stdoutput().set_color(rgb_color_t::reset(), rgb_color_t::reset());
stdoutput().set_color(rgb_color_t::reset(), rgb_color_t::reset());
}
return rls.finished ? maybe_t<wcstring>{command_line.text()} : none();
}

View file

@ -63,9 +63,7 @@ class scoped_buffer_t : noncopyable_t, nonmovable_t {
// Note this is deliberately exported so that init_curses can clear it.
layout_cache_t layout_cache_t::shared;
void screen_clear_layout_cache_ffi() {
layout_cache_t::shared.clear();
}
void screen_clear_layout_cache_ffi() { layout_cache_t::shared.clear(); }
/// Tests if the specified narrow character sequence is present at the specified position of the
/// specified wide character string. All of \c seq must match, but str may be longer than seq.
@ -584,7 +582,7 @@ void screen_t::move(int new_x, int new_y) {
}
for (i = 0; i < abs(y_steps); i++) {
writembs(outp, str);
outp.writembs(str);
}
x_steps = new_x - this->actual.cursor.x;
@ -641,7 +639,7 @@ void screen_t::write_mbs(const char *s) { writembs(this->outp(), s); }
/// Convert a wide string to a multibyte string and append it to the buffer.
void screen_t::write_str(const wchar_t *s) { this->outp().writestr(s); }
void screen_t::write_str(const wcstring &s) { this->outp().writestr(s); }
void screen_t::write_str(const wcstring &s) { this->outp().writestr(s.c_str()); }
/// Returns the length of the "shared prefix" of the two lines, which is the run of matching text
/// and colors. If the prefix ends on a combining character, do not include the previous character
@ -1333,11 +1331,11 @@ void screen_t::reset_abandoning_line(int screen_width) {
void screen_force_clear_to_end() {
if (clr_eos) {
writembs(outputter_t::stdoutput(), clr_eos);
writembs(stdoutput(), clr_eos);
}
}
screen_t::screen_t() : outp_(outputter_t::stdoutput()) {}
screen_t::screen_t() : outp_(stdoutput()) {}
bool screen_t::cursor_is_wrapped_to_own_line() const {
// Note == comparison against the line count is correct: we do not create a line just for the

View file

@ -127,7 +127,7 @@ class screen_data_t {
bool empty() const { return line_datas.empty(); }
};
class outputter_t;
struct outputter_t;
/// The class representing the current and desired screen contents.
class screen_t {