-
Notifications
You must be signed in to change notification settings - Fork 6
Fix text selection from the panes #53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 4 commits
4a7c3e3
daba3b6
b275b0d
050f6db
9f41463
4f05f8f
a163a65
e440c69
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,5 +1,9 @@ | ||||||
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): | ||||||
|
@@ -10,19 +14,73 @@ 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 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Does this sound better? |
||||||
} | ||||||
|
||||||
# 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): | ||||||
vgvassilev marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
"""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: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's show the tip multiple times. I will need it, I can't remember anything 😄. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Vipul-Cariappa I have tried this by setting tip_shown to false again in on_mouse_up function. The other issue I have is about the tip showing multiple times (depending on the pane I scroll+click). So I get multiple tips(one on top of the other) all showing at the same time. This comes from the fact that each pane initialises its own TextScrollView in DiffDebug. How would you go about this ? I have tried using global variables but it still seems to be attached to each instance of TextScrollView. I thought about maybe moving the tip_shown variable to DiffDebug ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did not realise you were modifying There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok thanks! |
||||||
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"]) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be part of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense, thanks! |
||||||
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'): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Initialize There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! |
||||||
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 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above. |
||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we detect which app we are running and display the relevant tip?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is what is done currently(?)
For the "default" which is the Mac terminal, I haven't figured out the command and I don't think it's possible just with a command, that's why I put a general message for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, sounds good. Do we need to enumerate the shortcuts by hand -- isn't there some api that we can use? I bet there is some way to configure these on the user end...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I unfortunately couldn't find any api... I will definitely keep it in mind for later though