checkpoint resize diagnostics and debug profile

This commit is contained in:
kuddev committed 2026-08-15 08:33:47 +08:00
1 parent 49c421dc8b
commit 4610610d12
6 files changed
+69 -31

No files matched your search

+18
View File
@@ -22,6 +22,24 @@ debug = 0
strip = "debuginfo"
incremental = false
# Debug 壳仍要承担真实终端负载:GPUI 布局/字体塑形和 VT 解析若以
# opt-level 0 运行,窗口拖拽与持续输入都会出现发布版没有的延迟。
# 只优化热依赖,主 crate 继续使用增量 debug,避免把日常构建变成 release。
[profile.dev]
codegen-units = 16
debug = "limited"
split-debuginfo = "unpacked"
[profile.dev.package]
resvg = { opt-level = 3 }
rustybuzz = { opt-level = 3 }
taffy = { opt-level = 3 }
ttf-parser = { opt-level = 3 }
smol = { opt-level = 3 }
gpui = { opt-level = 3 }
gpui_macros = { opt-level = 3 }
nebula_terminal = { opt-level = 3 }
[workspace.dependencies]
mlua = { version = "0.11.4", features = ["lua54", "vendored", "serialize", "send"] }
serde_path_to_error = "0.1.20"
+38 -13
View File
@@ -181,8 +181,9 @@ where
/// Drain the channel.
///
/// Returns `false` when a shutdown message was received.
fn drain_recv_channel(&mut self, state: &mut State) -> bool {
/// Returns `Err(())` when a shutdown message was received; otherwise the
/// last resize in this channel batch is returned for an ordered commit.
fn drain_recv_channel(&mut self, state: &mut State) -> Result<Option<WindowSize>, ()> {
// Resize storms (live window drags) queue faster than
// ResizePseudoConsole drains them — the console host performs a full
// viewport reflow per call. Within one drain only the newest size
@@ -195,16 +196,11 @@ where
match msg {
Msg::Input(input) => state.write_list.push_back(input),
Msg::Resize(window_size) => resize = Some(window_size),
Msg::Shutdown => return false,
Msg::Shutdown => return Err(()),
}
}
if let Some(window_size) = resize {
state.stream.resize(window_size);
self.pty.on_resize(window_size);
}
true
Ok(resize)
}
#[inline]
@@ -213,7 +209,7 @@ where
state: &mut State,
buf: &mut [u8],
mut writer: Option<&mut X>,
) -> io::Result<()>
) -> io::Result<usize>
where
X: Write,
{
@@ -285,7 +281,7 @@ where
self.event_proxy.send_event(Event::Wakeup);
}
Ok(())
Ok(processed)
}
#[inline]
@@ -374,8 +370,37 @@ where
}
// Handle channel events, if there are any.
if !self.drain_recv_channel(&mut state) {
break;
let pending_resize = match self.drain_recv_channel(&mut state) {
Ok(resize) => resize,
Err(()) => break,
};
if let Some(window_size) = pending_resize {
// A resize is a stream boundary, not a UI-side property.
// Drain everything already readable while the grid still
// has the old geometry; otherwise old-width absolute CUP
// output can be parsed into a new-width grid. This is the
// local equivalent of tty7's ordered Size echo.
loop {
match self.pty_read(&mut state, &mut buf, pipe.as_mut()) {
Ok(processed) if processed >= MAX_LOCKED_READ => continue,
Ok(_) => break,
Err(err) => {
error!("PTY read before resize failed: {err}");
failure = Some(format!("PTY read before resize failed: {err}"));
break 'event_loop;
},
}
}
// Match Windows Terminal's order: reflow the client model
// first, then ask ConPTY to resize. ResizePseudoConsole is
// synchronous; repaint bytes it produces are consumed by
// the normal readable-event path below against this grid.
self.terminal.lock().resize(window_size);
self.pty.on_resize(window_size);
state.stream.resize(window_size);
self.event_proxy.send_event(Event::Wakeup);
}
for event in events.iter() {
+7 -8
View File
@@ -1,6 +1,6 @@
//! Grid resize and reflow.
use std::cmp::{max, min, Ordering};
use std::cmp::{Ordering, max, min};
use std::mem;
use crate::index::{Boundary, Column, Line};
@@ -99,8 +99,9 @@ impl<T: GridCell + Default + PartialEq> Grid<T> {
/// is scrollback available. Once scrollback is exhausted, new lines are
/// simply added to the bottom of the screen.
///
/// ConPTY does not restore scrollback when growing. It leaves visible rows
/// and the cursor pinned, opening blank rows below them instead.
/// ConPTY 增高时不会把先前推出视口的行重新拉回:现有内容和光标保持
/// 原位,只在底部补空行。这里必须复刻 host 的行坐标,否则下一次
/// PSReadLine 绝对定位重绘会落到旧输出中间。
fn grow_lines<D>(&mut self, conpty: bool, target: usize)
where
T: ResetDiscriminant<D>,
@@ -192,10 +193,7 @@ impl<T: GridCell + Default + PartialEq> Grid<T> {
/// Bottommost viewport row containing a non-empty cell.
#[inline]
fn bottommost_occupied_line(&self) -> usize {
(0..self.lines)
.rev()
.find(|&line| !self.raw[Line(line as i32)].is_clear())
.unwrap_or(0)
(0..self.lines).rev().find(|&line| !self.raw[Line(line as i32)].is_clear()).unwrap_or(0)
}
/// Grow number of columns in each row, reflowing if necessary.
@@ -402,7 +400,8 @@ impl<T: GridCell + Default + PartialEq> Grid<T> {
let mut wrapped = match row.shrink_with_minimum(columns, minimum) {
Some(wrapped) if reflow => wrapped,
_ => {
if reflow && i == cursor_buffer_line && self.cursor.point.column >= columns {
if reflow && i == cursor_buffer_line && self.cursor.point.column >= columns
{
// If there are empty cells before the cursor, we assume it is explicit
// whitespace and need to wrap it like normal content.
Vec::new()
+2 -4
View File
@@ -402,10 +402,8 @@ fn display_iterator_can_crop_to_the_bottom_of_the_live_viewport() {
}
}
let points: Vec<_> = grid
.display_iter_from(Line(2), 2, 2)
.map(|cell| (cell.point, *cell.cell))
.collect();
let points: Vec<_> =
grid.display_iter_from(Line(2), 2, 2).map(|cell| (cell.point, *cell.cell)).collect();
assert_eq!(
points,
+2 -6
View File
@@ -8,8 +8,8 @@ use std::{cmp, mem, ptr, str};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use base64::engine::general_purpose::STANDARD as Base64;
use base64::Engine;
use base64::engine::general_purpose::STANDARD as Base64;
use bitflags::bitflags;
use log::{debug, trace};
use unicode_width::UnicodeWidthChar;
@@ -2429,11 +2429,7 @@ enum ModeState {
impl From<bool> for ModeState {
fn from(value: bool) -> Self {
if value {
Self::Set
} else {
Self::Reset
}
if value { Self::Set } else { Self::Reset }
}
}
@@ -393,6 +393,8 @@ impl OnResize for Conpty {
// not take the whole process down — log and let the exit path handle it.
let result = unsafe { (self.api.resize)(self.handle, window_size.into()) };
if result != S_OK {
// stderr 兜底:GPUI 主窗形态没有装 logger,失败不能无声。
eprintln!("[nebula:conpty] ResizePseudoConsole failed: HRESULT {result:#x}");
warn!("ResizePseudoConsole failed: HRESULT {result:#x}");
}
}