🐛 fix(core): 优化终端同步刷新与缓冲区处理逻辑
* 引入终端同步更新转义序列以减少屏幕闪烁 * 重构缓冲区机制,区分普通数据与传输数据缓存 * 新增前缀匹配算法函数用于处理跨分段的标记位识别 * 完善同步状态机逻辑,实现对同步更新区域的精确追踪 * 优化输入流读取与分发流程,提升终端输出稳定性
This commit is contained in:
@@ -674,13 +674,36 @@ sub colorize_line {
|
||||
}
|
||||
}
|
||||
|
||||
my $buffer = "";
|
||||
while (sysread(STDIN, my $chunk, 8192)) {
|
||||
$buffer .= $chunk;
|
||||
my $sync_begin = "\e[?2026h";
|
||||
my $sync_end = "\e[?2026l";
|
||||
my $transport_buffer = "";
|
||||
my $normal_buffer = "";
|
||||
my $inside_sync_update = 0;
|
||||
|
||||
while (length $buffer) {
|
||||
my $newline = index($buffer, "\n");
|
||||
my $carriage = index($buffer, "\r");
|
||||
sub suffix_prefix_length {
|
||||
my ($text, $marker) = @_;
|
||||
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;
|
||||
if ($newline < 0) {
|
||||
$position = $carriage;
|
||||
@@ -689,33 +712,79 @@ while (sysread(STDIN, my $chunk, 8192)) {
|
||||
} else {
|
||||
$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 的边界,等待下一块再决定它是换行还是进度重绘。
|
||||
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);
|
||||
if ($separator eq "\r" && substr($buffer, $position + 1, 1) eq "\n") {
|
||||
substr($buffer, 0, $position + 2, "");
|
||||
my $record = substr($normal_buffer, 0, $position);
|
||||
if ($separator eq "\r" && substr($normal_buffer, $position + 1, 1) eq "\n") {
|
||||
substr($normal_buffer, 0, $position + 2, "");
|
||||
colorize_line($record);
|
||||
} elsif ($separator eq "\n") {
|
||||
substr($buffer, 0, $position + 1, "");
|
||||
substr($normal_buffer, 0, $position + 1, "");
|
||||
colorize_line($record);
|
||||
} else {
|
||||
substr($buffer, 0, $position + 1, "");
|
||||
substr($normal_buffer, 0, $position + 1, "");
|
||||
print $record, "\r";
|
||||
}
|
||||
emit_leading_control_sequences();
|
||||
}
|
||||
}
|
||||
|
||||
if (length $buffer) {
|
||||
if ($buffer =~ s/\r\z//) {
|
||||
print $buffer, "\r";
|
||||
} else {
|
||||
colorize_line($buffer);
|
||||
sub drain_transport_output {
|
||||
my ($final) = @_;
|
||||
|
||||
while (length $transport_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);
|
||||
'
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user