From 4a7c3e3909197ece67c0f5d8885aa1d21db04dd2 Mon Sep 17 00:00:00 2001 From: elvan03 Date: Tue, 1 Apr 2025 23:14:02 +0200 Subject: [PATCH 1/7] fix: add advice(tip) for user when they try to select text, based on the terminal they use --- src/idd/ui/scrollable_area.py | 73 +++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/src/idd/ui/scrollable_area.py b/src/idd/ui/scrollable_area.py index 571c6a4..30c80a3 100644 --- a/src/idd/ui/scrollable_area.py +++ b/src/idd/ui/scrollable_area.py @@ -1,5 +1,10 @@ from __future__ import annotations +import os +import time from textual.widgets import RichLog +from textual import events +from textual.reactive import reactive +import time class TextScrollView(RichLog): @@ -11,18 +16,86 @@ class TextScrollView(RichLog): TextScrollView { height: 100%; scrollbar-size: 1 1; + border: solid green; } """ + # Terminal-specific selection tips + SELECTION_TIPS = { + "Terminal.app": "Option(⌥)+Click to select text", + "iTerm2": "Cmd(⌘)+Shift+C: Copy mode | Option(⌥)+Click: Selection", + "Warp": "Shift+Click to select text", + "default": "Use terminal's selection mechanism to copy text" #default mac terminal + } + + # Track if we've shown the tip for this panel + tip_shown = reactive(False) + def __init__(self, title: str = "", component_id: str = None) -> None: super().__init__(name=title, auto_scroll=True, markup=True) self.border_title = title if component_id: self.id = component_id + self._hover_start = 0 + self._content = [] def append(self, lines: list[str]): + self._content.extend(lines) self.write("\n".join(lines)) def text(self, lines: list[str]): self.clear() + self._content = lines.copy() self.append(lines) + + def _get_terminal_type(self): + """Try to detect terminal type from environment variables.""" + term_program = os.environ.get("TERM_PROGRAM", "") + if "iTerm" in term_program: + return "iTerm2" + elif "Apple_Terminal" in term_program: + return "Terminal.app" + elif "WarpTerminal" in term_program: + return "Warp" + return "default" + + def on_mouse_down(self, event: events.MouseDown) -> None: + """Track when the user clicks on the panel.""" + self._clicked = True + self._hover_start = time.time() # Start timing from the click + + def on_mouse_move(self, event: events.MouseMove) -> None: + """Show selection tip after clicking and hovering.""" + # Only show tip if we've been clicked and haven't shown a tip yet + if hasattr(self, '_clicked') and self._clicked and not self.tip_shown: + current_time = time.time() + hover_duration = current_time - self._hover_start + + # Show tip after 0.1 seconds of hovering after a click + if hover_duration > 0.1: + terminal = self._get_terminal_type() + tip = self.SELECTION_TIPS.get(terminal, self.SELECTION_TIPS["default"]) + self.notify(tip, severity="information", timeout=5) + self.tip_shown = True + + def on_mouse_up(self, event: events.MouseUp) -> None: + """Reset click state when mouse button is released.""" + if hasattr(self, '_clicked'): + self._clicked = False + + def on_leave(self, event: events.Leave) -> None: + """Reset hover timer and click state when mouse leaves the widget.""" + self._hover_start = 0 + if hasattr(self, '_clicked'): + self._clicked = False + + def export_content(self, filename=None) -> str: + """Export content to a file or return it as a string.""" + text = "\n".join(self._content) + if filename and text: + try: + with open(filename, "w") as f: + f.write(text) + except Exception as e: + print(f"Error saving to {filename}: {e}") + return text \ No newline at end of file From daba3b6c71a4a8842f02128a1f44d389f379288d Mon Sep 17 00:00:00 2001 From: elvan03 Date: Tue, 1 Apr 2025 23:16:01 +0200 Subject: [PATCH 2/7] Remove unused import --- src/idd/ui/scrollable_area.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/idd/ui/scrollable_area.py b/src/idd/ui/scrollable_area.py index 30c80a3..a4b437e 100644 --- a/src/idd/ui/scrollable_area.py +++ b/src/idd/ui/scrollable_area.py @@ -4,7 +4,6 @@ from textual.widgets import RichLog from textual import events from textual.reactive import reactive -import time class TextScrollView(RichLog): From b275b0d407910f0227d0eae9587c17dfc2c15ca4 Mon Sep 17 00:00:00 2001 From: elvan03 Date: Tue, 1 Apr 2025 23:31:03 +0200 Subject: [PATCH 3/7] Remove unused function and variables from previous implementation tries --- src/idd/ui/scrollable_area.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/idd/ui/scrollable_area.py b/src/idd/ui/scrollable_area.py index a4b437e..19f85e7 100644 --- a/src/idd/ui/scrollable_area.py +++ b/src/idd/ui/scrollable_area.py @@ -36,15 +36,12 @@ def __init__(self, title: str = "", component_id: str = None) -> None: if component_id: self.id = component_id self._hover_start = 0 - self._content = [] def append(self, lines: list[str]): - self._content.extend(lines) self.write("\n".join(lines)) def text(self, lines: list[str]): self.clear() - self._content = lines.copy() self.append(lines) def _get_terminal_type(self): @@ -88,13 +85,3 @@ def on_leave(self, event: events.Leave) -> None: if hasattr(self, '_clicked'): self._clicked = False - def export_content(self, filename=None) -> str: - """Export content to a file or return it as a string.""" - text = "\n".join(self._content) - if filename and text: - try: - with open(filename, "w") as f: - f.write(text) - except Exception as e: - print(f"Error saving to {filename}: {e}") - return text \ No newline at end of file From 050f6db163028d56d760e4d74052a0e9d3549193 Mon Sep 17 00:00:00 2001 From: elvan03 Date: Tue, 1 Apr 2025 23:36:17 +0200 Subject: [PATCH 4/7] Remove border --- src/idd/ui/scrollable_area.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/idd/ui/scrollable_area.py b/src/idd/ui/scrollable_area.py index 19f85e7..37f2f10 100644 --- a/src/idd/ui/scrollable_area.py +++ b/src/idd/ui/scrollable_area.py @@ -14,8 +14,7 @@ class TextScrollView(RichLog): DEFAULT_CSS = """ TextScrollView { height: 100%; - scrollbar-size: 1 1; - border: solid green; + scrollbar-size: 1 1; } """ From 9f41463521c84b84f8e27710ab492da75fb4009a Mon Sep 17 00:00:00 2001 From: elvan03 Date: Fri, 4 Apr 2025 21:14:46 +0200 Subject: [PATCH 5/7] Move logic into DiffDebug and initialize variables in init --- src/idd/cli.py | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/idd/cli.py b/src/idd/cli.py index b7e5145..eb562fc 100755 --- a/src/idd/cli.py +++ b/src/idd/cli.py @@ -16,6 +16,9 @@ from idd.ui.header import Header from idd.ui.scrollable_area import TextScrollView +import os +import time + class DiffDebug(App): CSS_PATH = "layout.tcss" @@ -29,6 +32,19 @@ class DiffDebug(App): base_args = "" regression_args = "" + # Terminal-specific selection tips + # VSCode : Paste this in user settings: "terminal.integrated.macOptionClickForcesSelection": true + SELECTION_TIPS = { + "Terminal.app": "Option(⌥)+Click to select text OR Cmd(⌘)+R and select", + "iTerm2": "Cmd(⌘)+Shift+C: Copy mode | Option(⌥)+Click: Selection", + "Warp": "Shift+Click to select text", + "vscode": "Option(⌥)+Click", + "default": "Use terminal's selection mechanism to copy text (Maybe Shift+Click)" + } + + # Track if we've shown the tip for this panel + tip_shown = False + diff_area1 = TextScrollView(title="Base Diff", component_id="diff-area1") diff_area2 = TextScrollView(title="Regression Diff", component_id = "diff-area2") diff_frames1 = TextScrollView(title="Base Stackframe", component_id = "diff-frames1") @@ -60,6 +76,10 @@ def __init__(self, disable_asm=False, disable_registers=False, only_base=False): self.base_history_index = 0 self.regressed_history = [""] self.regressed_history_index = 0 + self._hover_start = 0 + self._clicked = False + terminal = self._get_terminal_type() + self.tip = self.SELECTION_TIPS.get(terminal, self.SELECTION_TIPS["default"]) async def set_command_result(self, version) -> None: state = Debugger.get_state(version) @@ -426,6 +446,48 @@ async def on_key(self, event: events.Key) -> None: self.regressed_command_bar.value = self.regressed_history[self.regressed_history_index] + def _get_terminal_type(self): + """Try to detect terminal type from environment variables.""" + term_program = os.environ.get("TERM_PROGRAM", "") + if "iTerm" in term_program: + return "iTerm2" + elif "Apple_Terminal" in term_program: + return "Terminal.app" + elif "WarpTerminal" in term_program: + return "Warp" + elif "vscode" in term_program: + return "vscode" + return "default" + + def on_mouse_down(self, event: events.MouseDown) -> None: + """Track when the user clicks on the panel.""" + self._clicked = True + self._hover_start = time.time() # Start timing from the click + + def on_mouse_move(self, event: events.MouseMove) -> None: + """Show selection tip after clicking and hovering.""" + # Only show tip if we've been clicked and haven't shown a tip yet + if self._clicked and not self.tip_shown: + current_time = time.time() + hover_duration = current_time - self._hover_start + + # Show tip after 0.1 seconds of hovering after a click + if hover_duration > 0.1: + self.notify(self.tip, severity="information", timeout=3) + self.tip_shown = True + + def on_mouse_up(self, event: events.MouseUp) -> None: + """Reset click state when mouse button is released.""" + self._clicked = False + self.tip_shown = False + + + def on_leave(self, event: events.Leave) -> None: + """Reset hover timer and click state when mouse leaves the widget.""" + self._hover_start = 0 + self._clicked = False + + Debugger = None def main() -> None: global Debugger From 4f05f8fa8f949909877eec57081d05bc612d2c85 Mon Sep 17 00:00:00 2001 From: elvan03 Date: Fri, 4 Apr 2025 21:16:38 +0200 Subject: [PATCH 6/7] Remove implementation TextScrollView --- src/idd/ui/scrollable_area.py | 62 ++--------------------------------- 1 file changed, 2 insertions(+), 60 deletions(-) diff --git a/src/idd/ui/scrollable_area.py b/src/idd/ui/scrollable_area.py index 37f2f10..668b636 100644 --- a/src/idd/ui/scrollable_area.py +++ b/src/idd/ui/scrollable_area.py @@ -1,9 +1,5 @@ from __future__ import annotations -import os -import time from textual.widgets import RichLog -from textual import events -from textual.reactive import reactive class TextScrollView(RichLog): @@ -14,73 +10,19 @@ class TextScrollView(RichLog): DEFAULT_CSS = """ TextScrollView { height: 100%; - scrollbar-size: 1 1; + scrollbar-size: 1 1; } """ - # Terminal-specific selection tips - SELECTION_TIPS = { - "Terminal.app": "Option(⌥)+Click to select text", - "iTerm2": "Cmd(⌘)+Shift+C: Copy mode | Option(⌥)+Click: Selection", - "Warp": "Shift+Click to select text", - "default": "Use terminal's selection mechanism to copy text" #default mac terminal - } - - # Track if we've shown the tip for this panel - tip_shown = reactive(False) - def __init__(self, title: str = "", component_id: str = None) -> None: super().__init__(name=title, auto_scroll=True, markup=True) self.border_title = title if component_id: self.id = component_id - self._hover_start = 0 def append(self, lines: list[str]): self.write("\n".join(lines)) def text(self, lines: list[str]): self.clear() - self.append(lines) - - def _get_terminal_type(self): - """Try to detect terminal type from environment variables.""" - term_program = os.environ.get("TERM_PROGRAM", "") - if "iTerm" in term_program: - return "iTerm2" - elif "Apple_Terminal" in term_program: - return "Terminal.app" - elif "WarpTerminal" in term_program: - return "Warp" - return "default" - - def on_mouse_down(self, event: events.MouseDown) -> None: - """Track when the user clicks on the panel.""" - self._clicked = True - self._hover_start = time.time() # Start timing from the click - - def on_mouse_move(self, event: events.MouseMove) -> None: - """Show selection tip after clicking and hovering.""" - # Only show tip if we've been clicked and haven't shown a tip yet - if hasattr(self, '_clicked') and self._clicked and not self.tip_shown: - current_time = time.time() - hover_duration = current_time - self._hover_start - - # Show tip after 0.1 seconds of hovering after a click - if hover_duration > 0.1: - terminal = self._get_terminal_type() - tip = self.SELECTION_TIPS.get(terminal, self.SELECTION_TIPS["default"]) - self.notify(tip, severity="information", timeout=5) - self.tip_shown = True - - def on_mouse_up(self, event: events.MouseUp) -> None: - """Reset click state when mouse button is released.""" - if hasattr(self, '_clicked'): - self._clicked = False - - def on_leave(self, event: events.Leave) -> None: - """Reset hover timer and click state when mouse leaves the widget.""" - self._hover_start = 0 - if hasattr(self, '_clicked'): - self._clicked = False - + self.append(lines) \ No newline at end of file From a163a651fa47ba1094bcd8fc97fadf36d5461784 Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Thu, 10 Apr 2025 10:43:14 +0000 Subject: [PATCH 7/7] [ci] React on a tag push --- .github/workflows/release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cffe8c7..c7cec27 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,9 +1,9 @@ name: PyPI Upload on: - release: - types: - - published + push: + tags: + - [ 'v*.*.*' ] jobs: dist: