From 5b7370470f790c0eb5c60264d707623bb3e0809a Mon Sep 17 00:00:00 2001 From: ETWen Date: Thu, 2 Jul 2026 15:39:45 +0800 Subject: [PATCH] feat: add Show script trace in terminal setting Settings -> Terminal gains a 'Show script trace in terminal' checkbox (AppSettings.ShowScriptTrace, default on). When off, TTL trace lines ([wait] progress, sent-command echo, errors) are no longer drawn in the terminal. dispstr moves to a dedicated Display event and always shows, since it is the script explicitly printing something. Trace was already display-only (never written to session logs, the AI serial bridge, or the device) - docs now state this explicitly. Co-Authored-By: Claude Fable 5 --- CLAUDE.md | 2 +- docs/ttl-script-reference.md | 8 ++++++-- src/ETTerms/App/AboutView.cs | 2 +- src/ETTerms/App/SettingsView.cs | 9 +++++++++ src/ETTerms/Infrastructure/AppSettings.cs | 3 +++ src/ETTerms/Scripting/ScriptRunner.cs | 6 +++++- src/ETTerms/Scripting/TTLInterpreter.cs | 8 ++++++-- src/ETTerms/Sessions/SessionPage.cs | 11 +++++++++-- 8 files changed, 40 insertions(+), 9 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index b0f5c56..564f75f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,7 +10,7 @@ ETTerms 是一個 **C# .NET 8 WinForms** 的原生 Windows 終端機工作台, **進度:** Phase 1–5 ✅、Phase 6 ✅(TTL 引擎 + Group 同步,SSH 待驗收)、Phase 7 ✅(Settings/About)、Phase 8 ✅(PDU + Shell/ConPTY + SFTP + Settings 擴充)、Phase 9 ✅(Serial MCP server:**GUI 持有 COM port,MCP 經本機 named pipe 橋接**,AI 收發的資料即時以 `[AI]` 標色顯示在 GUI)。打包待指示。 -**v0.5.0:** 搜尋 / 關鍵字警示 / TTL 大擴充。**(1) Ctrl+F scrollback 搜尋** — `TerminalView` 內建搜尋列(Enter 往上找、Shift+Enter 往下、F3/Esc),全部命中黃底、目前命中橘底;命中以「絕對行號 = `ScreenBuffer.DroppedLines` + abs」錨定,環形緩衝丟舊行不漂移。**(2) 關鍵字高亮 + 分頁警示** — `AppSettings.KeywordRules`(`KeywordRule{Text,Enabled}` + 全域開關),Settings 新 **Highlight** 分頁可增刪/勾選;`TerminalView` 每次重繪只掃可見行標紅底(不分大小寫),`Feed` 路徑用獨立 Decoder+去 ANSI 偵測觸發 `KeywordAlert`(每關鍵字 2s 冷卻)→ `SessionPage` → `WorkspaceView` 把**非 active 分頁**的圓點標紅、切過去自動清除。**(3) TTL 對齊 TeraTerm** — 新 `TtlExpression` 運算式解析器(括號/邏輯/比較/十六進位 `0x`/`$`,失敗退回 legacy 規則相容舊腳本);新增控制流 `goto/call(行內執行,迴圈內可用)/return/for-next/do-loop/until-enduntil/break/continue/end/exit/include/mpause`、等待 `waitln/waitregex/recvln/wait 多字串(TeraTerm 語意:逾時 result=0 繼續)/mtimeout`、字串 `strlen/strcompare/strconcat/strcopy/strinsert/strremove/strmatch/strscan/strreplace/strtrim/strsplit/strjoin/tolower/toupper/str2int/int2str/code2str/str2code/sprintf(→inputstr)/expandenv`、檔案 `fileopen/filereadln(result=1 是 EOF)/filewrite(ln)/fileclose/filecreate/filedelete/filesearch/basename/dirname/makepath/foldercreate/folderdelete/foldersearch/getdir/setdir`、雜項 `beep/getdate/gettime(strftime 子集)/getenv/setenv/random/exec/getver/getttdir/uptime/ifdefined/clipb2var/var2clipb/inputbox/yesnobox/crc32/checksum8/16/32/dispstr`、serial 專用 `sendbreak/setbaud/setdtr/setrts/sendfile`(`SerialChannel` 新增對應方法);單行 `if ` 支援;`Preprocess` 引號內 `;` 不再被當註解;系統變數 `inputstr/matchstr/groupmatchstr1-9`;`_vars` 改大小寫不敏感;**單字串 `wait` 保留 ETTerms settle+逾時中止語意(勿改)**,多字串才是 TeraTerm 語意。`SessionPage` 把 `runner.Output`(含 `dispstr`)以灰色 echo 進終端機。指令表+範例:[docs/ttl-script-reference.md](docs/ttl-script-reference.md)(前段 ETTerms 獨有、後段與 TeraTerm 共有)。 +**v0.5.0:** 搜尋 / 關鍵字警示 / TTL 大擴充。**(1) Ctrl+F scrollback 搜尋** — `TerminalView` 內建搜尋列(Enter 往上找、Shift+Enter 往下、F3/Esc),全部命中黃底、目前命中橘底;命中以「絕對行號 = `ScreenBuffer.DroppedLines` + abs」錨定,環形緩衝丟舊行不漂移。**(2) 關鍵字高亮 + 分頁警示** — `AppSettings.KeywordRules`(`KeywordRule{Text,Enabled}` + 全域開關),Settings 新 **Highlight** 分頁可增刪/勾選;`TerminalView` 每次重繪只掃可見行標紅底(不分大小寫),`Feed` 路徑用獨立 Decoder+去 ANSI 偵測觸發 `KeywordAlert`(每關鍵字 2s 冷卻)→ `SessionPage` → `WorkspaceView` 把**非 active 分頁**的圓點標紅、切過去自動清除。**(3) TTL 對齊 TeraTerm** — 新 `TtlExpression` 運算式解析器(括號/邏輯/比較/十六進位 `0x`/`$`,失敗退回 legacy 規則相容舊腳本);新增控制流 `goto/call(行內執行,迴圈內可用)/return/for-next/do-loop/until-enduntil/break/continue/end/exit/include/mpause`、等待 `waitln/waitregex/recvln/wait 多字串(TeraTerm 語意:逾時 result=0 繼續)/mtimeout`、字串 `strlen/strcompare/strconcat/strcopy/strinsert/strremove/strmatch/strscan/strreplace/strtrim/strsplit/strjoin/tolower/toupper/str2int/int2str/code2str/str2code/sprintf(→inputstr)/expandenv`、檔案 `fileopen/filereadln(result=1 是 EOF)/filewrite(ln)/fileclose/filecreate/filedelete/filesearch/basename/dirname/makepath/foldercreate/folderdelete/foldersearch/getdir/setdir`、雜項 `beep/getdate/gettime(strftime 子集)/getenv/setenv/random/exec/getver/getttdir/uptime/ifdefined/clipb2var/var2clipb/inputbox/yesnobox/crc32/checksum8/16/32/dispstr`、serial 專用 `sendbreak/setbaud/setdtr/setrts/sendfile`(`SerialChannel` 新增對應方法);單行 `if ` 支援;`Preprocess` 引號內 `;` 不再被當註解;系統變數 `inputstr/matchstr/groupmatchstr1-9`;`_vars` 改大小寫不敏感;**單字串 `wait` 保留 ETTerms settle+逾時中止語意(勿改)**,多字串才是 TeraTerm 語意。`SessionPage` 把 `runner.Output`(trace:`[wait]`/`>>`/錯誤)以灰色 echo 進終端機,**可由 Settings → Terminal 的 `ShowScriptTrace` 開關關閉**;`dispstr` 走獨立的 `Display` 事件一律顯示。灰色訊息只進畫面 buffer——不進 ⏺ Log 側錄、不進 AI bridge、不送裝置(機台原始 log 乾淨)。指令表+範例:[docs/ttl-script-reference.md](docs/ttl-script-reference.md)(前段 ETTerms 獨有、後段與 TeraTerm 共有)。 **v0.4.0:** 效能 / 穩定性總整理(來自全 codebase 審視)。**(1) 終端機繪製熱路徑去配置** — `TerminalView` 快取 4 種 Font 變體(Bold/Underline 組合)與單一可變色 `SolidBrush`,run 合併時每 cell 顏色只解析一次,`Dispose` 收掉 GDI 資源;**(2) scrollback 改環形緩衝** — `ScreenBuffer` 從 `List+RemoveRange(0,…)`(滿了每行 O(n) 搬移)改 O(1) ring buffer;**(3) UTF-8 跨 chunk 亂碼修正(3 處)** — `TTLInterpreter.OnData`、`SerialBridgeServer` rx 轉發、`SessionLogger.Write` 改用 stateful `Decoder`(比照 `AnsiParser` 原本的正確做法);**(4) PDU SNMP 批次查詢** — 新共用專案 **`src/ETTerms.PduCore/`** 取代 GUI 與 PduMcp 兩份複製的 `PduController`(log 走建構子委派),新增 `GetAllPortsStatus()` 一個 SNMP GET 帶 12 個 varbind,12 port 輪詢從 36 個 UDP 來回縮成 3 個(StatusView 與 `pdu_status` 都改用);**(5) ShellChannel 資源修正** — `DeleteProcThreadAttributeList`+`FreeHGlobal` 釋放 attribute list、`CloseHandle(pi.hProcess)`,shell 自行 exit 時顯示灰色 `[ETTerms] shell process exited` 提示;**(6) SSH 斷線可見** — 訂 `ErrorOccurred`/`ShellStream.Closed` 顯示提示,`Write` 例外不再炸 UI thread;**(7) 終端機行為** — 新輸出只在已貼底時跟隨(看歷史不被拉回底部)、alt screen 滾輪轉方向鍵(vim/htop 可滾)、回應 DSR `ESC[6n`/`ESC[5n` 與 DA `ESC[c`(TUI 查游標位置不再卡住);**(8) TTL** — `_recv` 上限 1MB、wait 輪詢長度沒變不重掃;**(9) 去重複** — `ScriptRunner` 兩個 Run 合併、`TtlScript` 共用選檔/group 指令檢查(SessionPage/WorkspaceView 三份流程收斂)、`ConnectionStore` 讀取改 InvariantCulture+RoundtripKind。註:group `waitall` 一個成員失敗其他成員停在 barrier 是**刻意行為**(使用者要求整組停下),勿「修」。 diff --git a/docs/ttl-script-reference.md b/docs/ttl-script-reference.md index 03ccd96..3b65077 100644 --- a/docs/ttl-script-reference.md +++ b/docs/ttl-script-reference.md @@ -8,7 +8,11 @@ > 本文**前段是 ETTerms 獨有指令**,**後段是與 TeraTerm 共有的指令**。 執行於背景執行緒,可隨時按 **Stop** 中止;`wait` / `pause` 期間皆可取消。 -腳本的進度訊息(`[wait]`、`dispstr`、錯誤等)會以灰色顯示在該分頁的終端機裡。 + +腳本的 trace 訊息(`[wait]` 進度、`>>` 送出回顯、錯誤)會以灰色顯示在該分頁的終端機裡, +可由 **Settings → Terminal → Show script trace in terminal** 關閉;`dispstr` 是腳本明確要 +顯示的內容,一律顯示。**這些灰色訊息只出現在畫面上**——不會送到裝置、不會寫進 ⏺ Log +側錄檔、AI serial bridge 也讀不到,機台原始 log 保持乾淨。 --- @@ -108,7 +112,7 @@ wait 'login:' | `waitregex` | `waitregex '樣式' ['樣式2' ...]` | 等 regex 命中;`matchstr` / `groupmatchstr1-9` 設定,`result`=第幾個;逾時 0。 | | `recvln` | `recvln` | 收下一行到 `inputstr`;`result` 1 成功 / 0 逾時。 | | `flushrecv` | `flushrecv` | 清空接收緩衝。 | -| `dispstr` | `dispstr '文字' [更多...]` | 在終端機顯示訊息(灰色,不送出到裝置)。 | +| `dispstr` | `dispstr '文字' [更多...]` | 在終端機顯示訊息(灰色;不送裝置、不進側錄 log、不受 Show script trace 開關影響)。 | | `sendbreak` | `sendbreak` | 送 serial break(**Serial 限定**,約 300ms)。 | | `setbaud` | `setbaud 115200` | 執行中改 baud rate(**Serial 限定**)。 | | `setdtr` / `setrts` | `setdtr 1` / `setrts 0` | 控制 DTR / RTS 腳位(**Serial 限定**)。 | diff --git a/src/ETTerms/App/AboutView.cs b/src/ETTerms/App/AboutView.cs index de9e67d..07289ca 100644 --- a/src/ETTerms/App/AboutView.cs +++ b/src/ETTerms/App/AboutView.cs @@ -189,7 +189,7 @@ public sealed class AboutView : UserControl "New Settings → Highlight page: add your own keywords (like ERROR or FAIL) and they light up in red wherever they appear.", "When a keyword shows up in a tab you're not looking at, that tab's dot turns red so you don't miss it.", "TTL scripting grew from ~15 commands to 90+, matching Tera Term macros: loops (for / do / until), goto and subroutines, waitln / waitregex with regex capture, string and file operations, input dialogs, and serial line control (sendbreak, setbaud).", - "Scripts now show their progress in gray right inside the terminal, so you can watch what they're doing.", + "Scripts now show their progress in gray right inside the terminal — display only, never written to session logs; turn it off in Settings → Terminal (Show script trace) if you want a clean screen.", "See the full command table with examples in docs/ttl-script-reference.md.", ]), new("0.4.0", new DateOnly(2026, 7, 2), "Performance & stability overhaul", diff --git a/src/ETTerms/App/SettingsView.cs b/src/ETTerms/App/SettingsView.cs index fc434c5..5acb3d5 100644 --- a/src/ETTerms/App/SettingsView.cs +++ b/src/ETTerms/App/SettingsView.cs @@ -94,6 +94,14 @@ public sealed class SettingsView : UserControl flow.Controls.Add(MakeRow("Scrollback Lines", scrollback)); flow.Controls.Add(MakeRow("Color Scheme", scheme)); flow.Controls.Add(MakeRow("Default Newline", newline)); + + var scriptTrace = new CheckBox + { + Text = "Show script trace in terminal ([wait] / sent commands / errors in gray; dispstr always shows)", + Checked = s.ShowScriptTrace, AutoSize = true, + ForeColor = Theme.Text, Font = Theme.UiFont, Margin = new Padding(0, 6, 0, 0) + }; + flow.Controls.Add(scriptTrace); flow.Controls.Add(MakeSpacer(16)); // Shell settings @@ -161,6 +169,7 @@ public sealed class SettingsView : UserControl s.ScrollbackLines = (int)scrollback.Value; s.ColorScheme = scheme.Text; s.DefaultNewLine = newline.Text; + s.ShowScriptTrace = scriptTrace.Checked; s.ShellType = shellType.Text; s.ShellStartupDir = shellDir.Text; s.Save(); diff --git a/src/ETTerms/Infrastructure/AppSettings.cs b/src/ETTerms/Infrastructure/AppSettings.cs index 30ac9d8..fb9dd46 100644 --- a/src/ETTerms/Infrastructure/AppSettings.cs +++ b/src/ETTerms/Infrastructure/AppSettings.cs @@ -22,6 +22,9 @@ public sealed class AppSettings public int ScrollbackLines { get; set; } = 5000; public string DefaultNewLine { get; set; } = "\\r\\n"; public string ColorScheme { get; set; } = "Dark"; + /// TTL 腳本執行時,[wait] / >> 送出回顯 / 錯誤等 trace 是否以灰色顯示在終端機 + /// (只影響畫面;本來就不會寫進側錄 log。dispstr 一律顯示,不受此開關影響)。 + public bool ShowScriptTrace { get; set; } = true; // ── Shell ── public string ShellType { get; set; } = "PowerShell"; // PowerShell, Bash, Cmd diff --git a/src/ETTerms/Scripting/ScriptRunner.cs b/src/ETTerms/Scripting/ScriptRunner.cs index 2da84ab..95a91f3 100644 --- a/src/ETTerms/Scripting/ScriptRunner.cs +++ b/src/ETTerms/Scripting/ScriptRunner.cs @@ -14,9 +14,12 @@ public sealed class ScriptRunner /// (檔名, 行號, 指令) 進度。 public event Action? StatusChanged; - /// 輸出訊息(log / 提示 / 錯誤)。 + /// trace 訊息([wait] 進度 / >> 送出回顯 / 錯誤);顯示與否由 UI 依設定決定。 public event Action? Output; + /// dispstr 的顯示輸出(一律顯示)。 + public event Action? Display; + /// 結束:(成功, 訊息)。 public event Action? Finished; @@ -37,6 +40,7 @@ public sealed class ScriptRunner var interp = new TTLInterpreter(channel, sync, memberLabel); interp.StatusChanged += (f, l, c) => StatusChanged?.Invoke(f, l, c); interp.Output += m => Output?.Invoke(m); + interp.Display += m => Display?.Invoke(m); _interp = interp; try diff --git a/src/ETTerms/Scripting/TTLInterpreter.cs b/src/ETTerms/Scripting/TTLInterpreter.cs index 2803f93..a7c7115 100644 --- a/src/ETTerms/Scripting/TTLInterpreter.cs +++ b/src/ETTerms/Scripting/TTLInterpreter.cs @@ -56,9 +56,13 @@ public sealed class TTLInterpreter : IDisposable /// (檔名, 行號, 當前指令) 進度更新。 public event Action? StatusChanged; - /// 輸出訊息(log / 提示 / 錯誤 / dispstr),供 UI 顯示。 + /// trace 訊息([wait] 進度 / >> 送出回顯 / 錯誤),供 UI 顯示; + /// 可由 Settings 的 Show script trace 開關關閉顯示。 public event Action? Output; + /// dispstr 的顯示輸出:腳本明確要顯示的內容,一律顯示(不受 trace 開關影響)。 + public event Action? Display; + public TTLInterpreter(ISessionChannel channel, GroupSyncContext? groupSync = null, string memberLabel = "") { _channel = channel ?? throw new ArgumentNullException(nameof(channel)); @@ -1065,7 +1069,7 @@ public sealed class TTLInterpreter : IDisposable var t = TokenizeArgs(args); var sb = new StringBuilder(); foreach (var tok in t) sb.Append(ValS(tok)); - Output?.Invoke(sb.ToString()); + Display?.Invoke(sb.ToString()); } private void SendFile(string args) diff --git a/src/ETTerms/Sessions/SessionPage.cs b/src/ETTerms/Sessions/SessionPage.cs index 7339397..6798642 100644 --- a/src/ETTerms/Sessions/SessionPage.cs +++ b/src/ETTerms/Sessions/SessionPage.cs @@ -100,8 +100,15 @@ public sealed class SessionPage : UserControl _runner.StatusChanged += (_, line, cmd) => Ui(() => _status.Text = $"line {line}: {Trunc(cmd)}"); _runner.Finished += (_, msg) => Ui(() => { _status.Text = msg; SetRunning(false); }); - // 腳本輸出(dispstr / [wait] 進度 / 錯誤)以灰色 echo 到終端機,執行過程看得見 - _runner.Output += m => Ui(() => + // 腳本 trace([wait] 進度 / >> 送出回顯 / 錯誤)以灰色 echo 到終端機; + // 可由 Settings → Terminal 的 Show script trace 關閉。只影響畫面,不會進側錄 log。 + _runner.Output += m => + { + if (!AppSettings.Instance.ShowScriptTrace) return; + Ui(() => _term.Feed(System.Text.Encoding.UTF8.GetBytes($"\x1b[90m{m}\x1b[0m\r\n"))); + }; + // dispstr 是腳本明確要顯示的內容,一律顯示(不受開關影響) + _runner.Display += m => Ui(() => _term.Feed(System.Text.Encoding.UTF8.GetBytes($"\x1b[90m{m}\x1b[0m\r\n"))); }