diff --git a/addon/globalPlugins/virtualRevision.py b/addon/globalPlugins/virtualRevision.py index c4ab909..7369ded 100644 --- a/addon/globalPlugins/virtualRevision.py +++ b/addon/globalPlugins/virtualRevision.py @@ -18,18 +18,48 @@ except: SCRCAT_TEXTREVIEW = None +def _isTermControl(obj): + return hasattr(obj, "UIAElement") and obj.UIAElement and obj.UIAElement.currentClassName == "TermControl" + +def _isDecorativeTerminalLine(line): + # True for lines whose only non-whitespace characters are in the Unicode Box Drawing + # block (U+2500-U+257F): the borders, separators, and corners that TUI apps such as + # Claude Code paint. Content lines that happen to contain a "│" border still survive + # because the letters/digits inside fall outside the range. + stripped = line.strip() + if not stripped: + return True + return all("─" <= ch <= "╿" for ch in stripped) + +def _cleanTerminalText(text): + # Terminal cells are space-padded to the column width, and TUI apps reserve fixed + # rows/columns for borders, status, input, etc. Captured as a UNIT_STORY this turns + # into long runs of blank padding and box-border-only lines that bury the actual + # content when navigated line-by-line in the review window. Strip per-line trailing + # whitespace and drop lines that carry no real content. + lines = [] + for line in text.split("\n"): + stripped = line.rstrip() + if _isDecorativeTerminalLine(stripped): + continue + lines.append(stripped) + return "\n".join(lines) + def obtainUWPWindowText(): foreground = api.getForegroundObject() desktop = api.getDesktopObject() uwpTextList = [foreground.name] + termTextList = [] + hasTerm = _isTermControl(foreground) curObject=foreground.firstChild while curObject: - if curObject.name is not None: uwpTextList.append(curObject.name) - if hasattr(curObject, "UIAElement") and curObject.UIAElement and curObject.UIAElement.currentClassName == "TermControl": + if _isTermControl(curObject): + hasTerm = True info = curObject.makeTextInfo(textInfos.POSITION_FIRST) info.expand(textInfos.UNIT_STORY) - text = info.clipboardText.rstrip() - uwpTextList.append(text) + termTextList.append(_cleanTerminalText(info.clipboardText)) + elif curObject.name is not None: + uwpTextList.append(curObject.name) if curObject.simpleFirstChild: curObject=curObject.simpleFirstChild continue @@ -49,11 +79,16 @@ def obtainUWPWindowText(): curObject=parent.simpleNext except AttributeError: continue - if hasattr(foreground, "UIAElement") and foreground.UIAElement and foreground.UIAElement.currentClassName == "TermControl": + if _isTermControl(foreground): + hasTerm = True info = foreground.makeTextInfo(textInfos.POSITION_FIRST) info.expand(textInfos.UNIT_STORY) - text = info.clipboardText.rstrip() - uwpTextList.append(text) + termTextList.append(_cleanTerminalText(info.clipboardText)) + # For terminal-hosted windows (e.g. cmd.exe inside Windows Terminal), the child walk + # also picks up the duplicated title, scroll-bar parts, "Close Tab" and "System" menu. + # Suppress that chrome and return only the title plus the actual terminal text. + if hasTerm: + return [foreground.name] + termTextList return uwpTextList class GlobalPlugin(globalPluginHandler.GlobalPlugin):