diff --git a/winehelper_gui.py b/winehelper_gui.py
index 354f304..cb8fefd 100644
--- a/winehelper_gui.py
+++ b/winehelper_gui.py
@@ -2,6 +2,7 @@
import os
import subprocess
import sys
+import re
import shlex
import shutil
import html
@@ -96,6 +97,9 @@ class WineHelperGUI(QMainWindow):
self.create_installed_tab()
self.create_help_tab()
+ # Инициализируем состояние, которое будет использоваться для логов
+ self._reset_log_state()
+
# Обновляем список установленных приложений
self.update_installed_apps()
@@ -1339,10 +1343,16 @@ class WineHelperGUI(QMainWindow):
self.install_dialog.show()
+ def _reset_log_state(self):
+ """Сбрасывает состояние буфера и флага прогресса для лога установки."""
+ self.output_buffer = ""
+ self.last_line_was_progress = False
+
def _prepare_installation(self):
"""Подготавливает и запускает процесс установки"""
self.stacked_widget.setCurrentIndex(1)
-
+ self._reset_log_state() # Сбрасываем состояние для обработки лога
+
winehelper_path = self.winehelper_path
script_path = os.path.join(Var.DATA_PATH,
"autoinstall" if self.current_script in self.autoinstall_scripts else "manualinstall",
@@ -1395,28 +1405,93 @@ class WineHelperGUI(QMainWindow):
QMessageBox.critical(self.install_dialog, "Ошибка", f"Не удалось запустить установку:\n{str(e)}")
self.cleanup_process()
- def append_log(self, text, is_error=False):
+ def append_log(self, text, is_error=False, add_newline=True):
"""Добавляет сообщение в лог"""
if not hasattr(self, 'log_output'): return
cursor = self.log_output.textCursor()
cursor.movePosition(QTextCursor.End)
if is_error:
+ # Для ошибок всегда добавляем перенос строки для лучшей читаемости
cursor.insertHtml(f'{text}
')
else:
- cursor.insertText(f"{text}\n")
+ # Вставляем текст. Добавляем перенос строки, если нужно.
+ formatted_text = f"{text}\n" if add_newline else text
+ cursor.insertText(formatted_text)
self.log_output.ensureCursorVisible()
QApplication.processEvents()
+ def _process_log_line(self, line_with_delimiter):
+ """Обрабатывает одну строку лога, управляя заменой строк прогресса."""
+ is_progress_line = '\r' in line_with_delimiter
+
+ # Фильтруем "мусорные" строки прогресса (например, '-=O=-' от wget),
+ # обрабатывая только те, что содержат знак процента.
+ if is_progress_line:
+ if not re.search(r'\d\s*%', line_with_delimiter):
+ return # Игнорируем строку прогресса без процентов
+
+ clean_line = line_with_delimiter.replace('\r', '').replace('\n', '').strip()
+
+ if not clean_line:
+ return
+
+ cursor = self.log_output.textCursor()
+
+ # Если новая строка - это прогресс, и предыдущая тоже была прогрессом,
+ # то мы удаляем старую, чтобы заменить ее новой.
+ if is_progress_line and self.last_line_was_progress:
+ cursor.movePosition(QTextCursor.End)
+ cursor.select(QTextCursor.LineUnderCursor)
+ cursor.removeSelectedText()
+ elif not is_progress_line and self.last_line_was_progress:
+ # Это переход от строки прогресса к финальной строке.
+ # Вместо добавления переноса, мы заменяем предыдущую строку новой.
+ cursor.movePosition(QTextCursor.End)
+ cursor.select(QTextCursor.LineUnderCursor)
+ cursor.removeSelectedText()
+
+ # Добавляем новую очищенную строку.
+ # Для прогресса - без переноса строки, для обычных строк - с переносом.
+ self.append_log(clean_line, add_newline=not is_progress_line)
+
+ self.last_line_was_progress = is_progress_line
+
def handle_process_output(self):
- """Обрабатывает вывод процесса"""
- output = self.install_process.readAllStandardOutput().data().decode('utf-8', errors='ignore').strip()
- if output:
- self.append_log(output)
+ """Обрабатывает вывод процесса, корректно отображая однострочный прогресс."""
+ new_data = self.install_process.readAllStandardOutput().data().decode('utf-8', errors='ignore')
+ self.output_buffer += new_data
+
+ while True:
+ # Ищем ближайший разделитель (\n или \r)
+ idx_n = self.output_buffer.find('\n')
+ idx_r = self.output_buffer.find('\r')
+
+ if idx_n == -1 and idx_r == -1:
+ break # Нет полных строк для обработки
+
+ split_idx = min(idx for idx in [idx_n, idx_r] if idx != -1)
+
+ # Получаем строку, включая разделитель
+ line = self.output_buffer[:split_idx + 1]
+ self.output_buffer = self.output_buffer[split_idx + 1:]
+
+ self._process_log_line(line)
def handle_process_finished(self, exit_code, exit_status):
"""Обрабатывает завершение процесса"""
+ # Обрабатываем остаток в буфере, если он есть
+ if self.output_buffer:
+ self._process_log_line(self.output_buffer)
+
+ # Если последней строкой был прогресс, "завершаем" его переносом строки.
+ if self.last_line_was_progress:
+ cursor = self.log_output.textCursor()
+ cursor.movePosition(QTextCursor.End)
+ cursor.insertText("\n")
+
+ self._reset_log_state()
if exit_code == 0 and exit_status == QProcess.NormalExit:
self.append_log("\n=== Установка успешно завершена ===")
# Создаем кастомный диалог, чтобы кнопка была на русском