🐛 fix(core): 优化终端同步刷新与缓冲区处理逻辑

* 引入终端同步更新转义序列以减少屏幕闪烁
* 重构缓冲区机制,区分普通数据与传输数据缓存
* 新增前缀匹配算法函数用于处理跨分段的标记位识别
* 完善同步状态机逻辑,实现对同步更新区域的精确追踪
* 优化输入流读取与分发流程,提升终端输出稳定性
This commit is contained in:
2026-07-28 09:01:40 +08:00
parent e55d63991c
commit a1d66a700d
+88 -19
View File
@@ -674,13 +674,36 @@ sub colorize_line {
} }
} }
my $buffer = ""; my $sync_begin = "\e[?2026h";
while (sysread(STDIN, my $chunk, 8192)) { my $sync_end = "\e[?2026l";
$buffer .= $chunk; my $transport_buffer = "";
my $normal_buffer = "";
my $inside_sync_update = 0;
while (length $buffer) { sub suffix_prefix_length {
my $newline = index($buffer, "\n"); my ($text, $marker) = @_;
my $carriage = index($buffer, "\r"); my $maximum = length($marker) - 1;
$maximum = length($text) if length($text) < $maximum;
for (my $length = $maximum; $length > 0; $length--) {
return $length if substr($text, -$length) eq substr($marker, 0, $length);
}
return 0;
}
sub emit_leading_control_sequences {
while ($normal_buffer =~ s/\A(\e\[[0-?]*[ -\/]*[@-~])//) {
print $1;
}
}
sub drain_normal_output {
my ($final) = @_;
emit_leading_control_sequences();
while (length $normal_buffer) {
my $newline = index($normal_buffer, "\n");
my $carriage = index($normal_buffer, "\r");
my $position; my $position;
if ($newline < 0) { if ($newline < 0) {
$position = $carriage; $position = $carriage;
@@ -689,33 +712,79 @@ while (sysread(STDIN, my $chunk, 8192)) {
} else { } else {
$position = $newline < $carriage ? $newline : $carriage; $position = $newline < $carriage ? $newline : $carriage;
} }
last if $position < 0;
my $separator = substr($buffer, $position, 1); if ($position < 0) {
if ($final) {
colorize_line($normal_buffer);
$normal_buffer = "";
}
return;
}
my $separator = substr($normal_buffer, $position, 1);
# 分块时 CR 可能正好在 CRLF 的边界,等待下一块再决定它是换行还是进度重绘。 # 分块时 CR 可能正好在 CRLF 的边界,等待下一块再决定它是换行还是进度重绘。
last if $separator eq "\r" && $position + 1 == length($buffer); return if !$final && $separator eq "\r" && $position + 1 == length($normal_buffer);
my $record = substr($buffer, 0, $position); my $record = substr($normal_buffer, 0, $position);
if ($separator eq "\r" && substr($buffer, $position + 1, 1) eq "\n") { if ($separator eq "\r" && substr($normal_buffer, $position + 1, 1) eq "\n") {
substr($buffer, 0, $position + 2, ""); substr($normal_buffer, 0, $position + 2, "");
colorize_line($record); colorize_line($record);
} elsif ($separator eq "\n") { } elsif ($separator eq "\n") {
substr($buffer, 0, $position + 1, ""); substr($normal_buffer, 0, $position + 1, "");
colorize_line($record); colorize_line($record);
} else { } else {
substr($buffer, 0, $position + 1, ""); substr($normal_buffer, 0, $position + 1, "");
print $record, "\r"; print $record, "\r";
} }
emit_leading_control_sequences();
} }
} }
if (length $buffer) { sub drain_transport_output {
if ($buffer =~ s/\r\z//) { my ($final) = @_;
print $buffer, "\r";
} else { while (length $transport_buffer) {
colorize_line($buffer); if ($inside_sync_update) {
my $end_position = index($transport_buffer, $sync_end);
if ($end_position >= 0) {
my $length = $end_position + length($sync_end);
print substr($transport_buffer, 0, $length, "");
$inside_sync_update = 0;
next;
}
my $keep = $final ? 0 : suffix_prefix_length($transport_buffer, $sync_end);
my $available = length($transport_buffer) - $keep;
print substr($transport_buffer, 0, $available, "") if $available > 0;
return;
}
my $begin_position = index($transport_buffer, $sync_begin);
if ($begin_position >= 0) {
$normal_buffer .= substr($transport_buffer, 0, $begin_position, "");
drain_normal_output(0);
print substr($transport_buffer, 0, length($sync_begin), "");
$inside_sync_update = 1;
next;
}
my $keep = $final ? 0 : suffix_prefix_length($transport_buffer, $sync_begin);
my $available = length($transport_buffer) - $keep;
if ($available > 0) {
$normal_buffer .= substr($transport_buffer, 0, $available, "");
drain_normal_output(0);
}
return;
} }
} }
while (sysread(STDIN, my $chunk, 8192)) {
$transport_buffer .= $chunk;
drain_transport_output(0);
}
drain_transport_output(1);
drain_normal_output(1);
' '
} }