|
6 | 6 | #include <FluentQtWidgets/Dialogs/FolderListDialog.h> |
7 | 7 | #include <FluentQtWidgets/Settings/SettingCard.h> |
8 | 8 | #include <FluentQtWidgets/StyleSheet.h> |
| 9 | +#include <FluentQtWidgets/Theme.h> |
9 | 10 |
|
10 | 11 | #include <QtCore/QDir> |
11 | 12 | #include <QtCore/QFileInfo> |
@@ -51,6 +52,64 @@ constexpr int CompactControlHeight = 32; |
51 | 52 | constexpr int DefaultFileChunkSize = 256; |
52 | 53 | constexpr int DefaultFileChunkIntervalMs = 10; |
53 | 54 |
|
| 55 | +QColor terminalTimestampColor() |
| 56 | +{ |
| 57 | + return ThemeManager::instance()->effectiveTheme() == Theme::Dark ? QColor(132, 192, 214) : QColor(75, 103, 128); |
| 58 | +} |
| 59 | + |
| 60 | +QColor terminalDirectionMarkerColor(bool tx) |
| 61 | +{ |
| 62 | + const bool dark = ThemeManager::instance()->effectiveTheme() == Theme::Dark; |
| 63 | + if(tx) { |
| 64 | + return dark ? QColor(255, 185, 115) : QColor(177, 86, 15); |
| 65 | + } |
| 66 | + return dark ? QColor(79, 214, 191) : QColor(0, 121, 107); |
| 67 | +} |
| 68 | + |
| 69 | +QColor terminalEspIdfLogLevelColor(QChar level) |
| 70 | +{ |
| 71 | + const bool dark = ThemeManager::instance()->effectiveTheme() == Theme::Dark; |
| 72 | + switch(level.toUpper().toLatin1()) { |
| 73 | + case 'V': |
| 74 | + return dark ? QColor(187, 154, 255) : QColor(108, 84, 190); |
| 75 | + case 'D': |
| 76 | + return dark ? QColor(117, 190, 255) : QColor(33, 118, 188); |
| 77 | + case 'I': |
| 78 | + return dark ? QColor(103, 219, 123) : QColor(0, 126, 67); |
| 79 | + case 'W': |
| 80 | + return dark ? QColor(255, 209, 102) : QColor(171, 103, 0); |
| 81 | + case 'E': |
| 82 | + return dark ? QColor(255, 132, 132) : QColor(190, 35, 35); |
| 83 | + default: |
| 84 | + return QColor(); |
| 85 | + } |
| 86 | +} |
| 87 | + |
| 88 | +int espIdfLogPrefixEnd(const QString &line, int prefixStart) |
| 89 | +{ |
| 90 | + if(prefixStart + 4 >= line.size()) { |
| 91 | + return -1; |
| 92 | + } |
| 93 | + |
| 94 | + const QColor levelColor = terminalEspIdfLogLevelColor(line.at(prefixStart)); |
| 95 | + if(!levelColor.isValid() || line.at(prefixStart + 1) != QLatin1Char(' ') || |
| 96 | + line.at(prefixStart + 2) != QLatin1Char('(')) { |
| 97 | + return -1; |
| 98 | + } |
| 99 | + |
| 100 | + int cursor = prefixStart + 3; |
| 101 | + const int digitStart = cursor; |
| 102 | + while(cursor < line.size() && line.at(cursor).isDigit()) { |
| 103 | + ++cursor; |
| 104 | + } |
| 105 | + |
| 106 | + if(cursor == digitStart || cursor >= line.size() || line.at(cursor) != QLatin1Char(')')) { |
| 107 | + return -1; |
| 108 | + } |
| 109 | + |
| 110 | + return cursor + 1; |
| 111 | +} |
| 112 | + |
54 | 113 | void setFixedControlWidth(QWidget *widget, int width) |
55 | 114 | { |
56 | 115 | widget->setMinimumWidth(width); |
@@ -315,6 +374,9 @@ WorkbenchPage::WorkbenchPage(QWidget *parent) |
315 | 374 | connect(&m_statsTimer, &QTimer::timeout, this, &WorkbenchPage::updateRateStats); |
316 | 375 | m_fileSendTimer.setSingleShot(true); |
317 | 376 | connect(&m_fileSendTimer, &QTimer::timeout, this, &WorkbenchPage::sendNextFileChunk); |
| 377 | + connect(ThemeManager::instance(), &ThemeManager::effectiveThemeChanged, this, [this]() { |
| 378 | + renderTerminal(); |
| 379 | + }); |
318 | 380 |
|
319 | 381 | refreshPorts(); |
320 | 382 | loadSendHistory(); |
@@ -1790,6 +1852,49 @@ bool WorkbenchPage::appendRecordToTerminal(QTextCursor &cursor, const SessionRec |
1790 | 1852 | if(!searchText.isEmpty() && line.contains(searchText, Qt::CaseInsensitive)) { |
1791 | 1853 | format.setBackground(QColor(255, 214, 10, 72)); |
1792 | 1854 | } |
| 1855 | + |
| 1856 | + const bool showTimestamp = m_timestampCheck && m_timestampCheck->isChecked(); |
| 1857 | + const QString timestamp = record.timestamp.toString(QStringLiteral("HH:mm:ss.zzz")); |
| 1858 | + const QString marker = record.direction == RecordDirection::Tx ? QStringLiteral("»") : QStringLiteral("«"); |
| 1859 | + int position = 0; |
| 1860 | + if(showTimestamp && line.startsWith(timestamp)) { |
| 1861 | + QTextCharFormat timestampFormat = format; |
| 1862 | + timestampFormat.setForeground(terminalTimestampColor()); |
| 1863 | + cursor.insertText(timestamp, timestampFormat); |
| 1864 | + position = timestamp.size(); |
| 1865 | + } |
| 1866 | + |
| 1867 | + const int markerIndex = line.indexOf(marker, position); |
| 1868 | + if(markerIndex >= position) { |
| 1869 | + QTextCharFormat markerFormat = format; |
| 1870 | + markerFormat.setForeground(terminalDirectionMarkerColor(record.direction == RecordDirection::Tx)); |
| 1871 | + cursor.insertText(line.mid(position, markerIndex - position), format); |
| 1872 | + cursor.insertText(marker, markerFormat); |
| 1873 | + |
| 1874 | + const int afterMarker = markerIndex + marker.size(); |
| 1875 | + int prefixStart = afterMarker; |
| 1876 | + while(prefixStart < line.size() && line.at(prefixStart).isSpace()) { |
| 1877 | + ++prefixStart; |
| 1878 | + } |
| 1879 | + |
| 1880 | + const int prefixEnd = espIdfLogPrefixEnd(line, prefixStart); |
| 1881 | + if(prefixEnd > prefixStart) { |
| 1882 | + QTextCharFormat levelFormat = format; |
| 1883 | + levelFormat.setForeground(terminalEspIdfLogLevelColor(line.at(prefixStart))); |
| 1884 | + cursor.insertText(line.mid(afterMarker, prefixStart - afterMarker), format); |
| 1885 | + cursor.insertText(line.mid(prefixStart, prefixEnd - prefixStart), levelFormat); |
| 1886 | + cursor.insertText(line.mid(prefixEnd), format); |
| 1887 | + } else { |
| 1888 | + cursor.insertText(line.mid(afterMarker), format); |
| 1889 | + } |
| 1890 | + return true; |
| 1891 | + } |
| 1892 | + |
| 1893 | + if(position > 0) { |
| 1894 | + cursor.insertText(line.mid(position), format); |
| 1895 | + return true; |
| 1896 | + } |
| 1897 | + |
1793 | 1898 | cursor.insertText(line, format); |
1794 | 1899 | return true; |
1795 | 1900 | } |
|
0 commit comments