reset_abandoning_line: remove redundant allocations

This commit is contained in:
Johannes Altmanninger
2025-11-13 10:55:19 +01:00
parent a8bf4db32d
commit fbad0ab50a
2 changed files with 21 additions and 42 deletions

View File

@@ -1044,11 +1044,11 @@ pub fn get_ellipsis_str() -> &'static wstr {
}
/// Character representing an omitted newline at the end of text.
pub fn get_omitted_newline_str() -> &'static wstr {
pub fn get_omitted_newline_str() -> &'static str {
OMITTED_NEWLINE_STR.load()
}
static OMITTED_NEWLINE_STR: AtomicRef<wstr> = AtomicRef::new(&L!(""));
static OMITTED_NEWLINE_STR: AtomicRef<str> = AtomicRef::new(&"");
pub fn get_omitted_newline_width() -> usize {
OMITTED_NEWLINE_STR.load().len()
@@ -1231,25 +1231,16 @@ pub fn wcs2bytes_appending(output: &mut Vec<u8>, input: &wstr) {
pub type FilenameRef = Arc<WString>;
pub fn init_special_chars_once() {
// Helper to make a static reference to a static &'wstr, from a string literal.
// This is necessary to store them in global atomics, as these can't handle fat pointers.
macro_rules! LL {
($s:literal) => {{
const S: &'static wstr = L!($s);
&S
}};
}
if is_windows_subsystem_for_linux(WSL::Any) {
// neither of \u23CE and \u25CF can be displayed in the default fonts on Windows, though
// they can be *encoded* just fine. Use alternative glyphs.
OMITTED_NEWLINE_STR.store(LL!("\u{00b6}")); // "pilcrow"
OMITTED_NEWLINE_STR.store(&"\u{00b6}"); // "pilcrow"
OBFUSCATION_READ_CHAR.store(u32::from('\u{2022}'), Ordering::Relaxed); // "bullet" (•)
} else if is_console_session() {
OMITTED_NEWLINE_STR.store(LL!("^J"));
OMITTED_NEWLINE_STR.store(&"^J");
OBFUSCATION_READ_CHAR.store(u32::from('*'), Ordering::Relaxed);
} else {
OMITTED_NEWLINE_STR.store(LL!("\u{23CE}")); // "return symbol" (⏎)
OMITTED_NEWLINE_STR.store(&"\u{23CE}"); // "return symbol" (⏎)
OBFUSCATION_READ_CHAR.store(
u32::from(
'\u{25CF}', // "black circle" (●)

View File

@@ -24,7 +24,7 @@
use libc::{ONLCR, STDERR_FILENO, STDOUT_FILENO};
use crate::common::{
bytes2wcstring, get_ellipsis_char, get_omitted_newline_str, get_omitted_newline_width,
get_ellipsis_char, get_omitted_newline_str, get_omitted_newline_width,
has_working_tty_timestamps, shell_modes, wcs2bytes, write_loop,
};
use crate::env::Environment;
@@ -673,13 +673,15 @@ pub fn offset_in_cmdline_given_cursor(
/// If clear_to_eos is set,
/// The screen width must be provided for the PROMPT_SP hack.
pub fn reset_abandoning_line(&mut self, screen_width: usize) {
use std::iter::repeat_n;
self.actual.cursor.y = 0;
self.actual.clear_lines();
self.actual_left_prompt = None;
self.need_clear_lines = true;
// Do the PROMPT_SP hack.
let mut abandon_line_string = WString::with_capacity(screen_width + 32);
let mut abandon_line_string = Vec::with_capacity(screen_width + 32);
// Don't need to check for fish_wcwidth errors; this is done when setting up
// omitted_newline_char in common.rs.
@@ -691,11 +693,11 @@ pub fn reset_abandoning_line(&mut self, screen_width: usize) {
use std::ffi::CString;
let term = crate::terminal::term();
let mut justgrey = true;
let add = |abandon_line_string: &mut WString, s: Option<CString>| {
let add = |abandon_line_string: &mut Vec<u8>, s: Option<CString>| {
let Some(s) = s else {
return false;
};
abandon_line_string.push_utfstr(&bytes2wcstring(s.as_bytes()));
abandon_line_string.extend(s.as_bytes());
true
};
if let Some(enter_dim_mode) = term.enter_dim_mode.as_ref() {
@@ -722,43 +724,29 @@ pub fn reset_abandoning_line(&mut self, screen_width: usize) {
}
}
} else {
let mut tmp = Vec::<u8>::new();
tmp.write_command(EnterDimMode);
abandon_line_string.push_utfstr(&bytes2wcstring(&tmp));
abandon_line_string.write_command(EnterDimMode);
}
abandon_line_string.push_utfstr(&get_omitted_newline_str());
// normal text ANSI escape sequence
let mut tmp = Vec::<u8>::new();
tmp.write_command(ExitAttributeMode);
abandon_line_string.push_utfstr(&bytes2wcstring(&tmp));
for _ in 0..screen_width - non_space_width {
abandon_line_string.push(' ');
}
abandon_line_string.extend_from_slice(get_omitted_newline_str().as_bytes());
abandon_line_string.write_command(ExitAttributeMode);
abandon_line_string.extend(repeat_n(b' ', screen_width - non_space_width));
}
abandon_line_string.push('\r');
abandon_line_string.push_utfstr(get_omitted_newline_str());
abandon_line_string.push(b'\r');
abandon_line_string.extend_from_slice(get_omitted_newline_str().as_bytes());
// Now we are certainly on a new line. But we may have dropped the omitted newline char on
// it. So append enough spaces to overwrite the omitted newline char, and then clear all the
// spaces from the new line.
for _ in 0..non_space_width {
abandon_line_string.push(' ');
}
abandon_line_string.push('\r');
abandon_line_string.extend(repeat_n(b' ', non_space_width));
abandon_line_string.push(b'\r');
// Clear entire line. Zsh doesn't do this. Fish added this with commit 4417a6ee: If you have
// a prompt preceded by a new line, you'll get a line full of spaces instead of an empty
// line above your prompt. This doesn't make a difference in normal usage, but copying and
// pasting your terminal log becomes a pain. This commit clears that line, making it an
// actual empty line.
let mut tmp = Vec::<u8>::new();
tmp.write_command(ClearToEndOfLine);
abandon_line_string.push_utfstr(&bytes2wcstring(&tmp));
abandon_line_string.write_command(ClearToEndOfLine);
let narrow_abandon_line_string = wcs2bytes(&abandon_line_string);
let _ = write_loop(&STDOUT_FILENO, &narrow_abandon_line_string);
let _ = write_loop(&STDOUT_FILENO, &abandon_line_string);
self.actual.cursor.x = 0;
self.save_status();