🐛 fix(core): 优化终端同步刷新与缓冲区处理逻辑
* 引入终端同步更新转义序列以减少屏幕闪烁 * 重构缓冲区机制,区分普通数据与传输数据缓存 * 新增前缀匹配算法函数用于处理跨分段的标记位识别 * 完善同步状态机逻辑,实现对同步更新区域的精确追踪 * 优化输入流读取与分发流程,提升终端输出稳定性
This commit is contained in:
@@ -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);
|
||||||
'
|
'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user