-
Notifications
You must be signed in to change notification settings - Fork 5
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
feat: enhance PathTag validation and improve TUI file picker #18
base: dev
Are you sure you want to change the base?
Conversation
- Add validation for single/multiple path selections - Implement directory-only path validation - Add file existence checks - Fix Enter key handling in TUI interface
@e3rd I tried on my machine, but I am not prof at Textual stuff, pls check it, waiting for your feedback |
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.
mininterface/types/rich_tags.py
Outdated
multiple: bool = False | ||
""" The user can select multiple files. """ | ||
|
||
file_exist: bool = False |
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.
Let's name it just exist
to keep the same nomenclature as pathlib.Path.
def on_button_pressed(self, event): | ||
event.prevent_default() # prevent calling the parent MyButton | ||
event.prevent_default() |
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.
keep that comment
# Special type: Submit button | ||
elif tag.annotation is SubmitButton: # NOTE EXPERIMENTAL | ||
elif tag.annotation is SubmitButton: |
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.
keep that comment, this PR has nothing to do with SubmitButton I think
case SecretTag(): | ||
o = SecretInput(tag, placeholder=tag.name or "", type="text") | ||
case DatetimeTag(): |
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.
let's add a comment
# NOTE: To be expanded
or something. Because before, a DatetimeTag automatically defaulted to MyInput. You did not seem to change the behaviour.
from .widgets import (Changeable, MyButton, MyCheckbox, MyInput, MyRadioSet, | ||
MySubmitButton, SecretInput) | ||
|
||
if TYPE_CHECKING: | ||
from . import TextualInterface | ||
|
||
|
||
class FilePickerInput(Horizontal, Changeable): |
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.
put it to another file
- Add new file_picker_input.py with FileBrowser and FilePickerInput classes - Fix PathTag annotation handling to prevent "Type must be str" errors - Improve file selection UX with better tree visualization - Update widgets.py to handle Path objects properly - Enhance textual_adaptor.py and textual_app.py for better integration
Great, I'll check soon! |
It's much better than I thought it might be!
|
… visual feedback - Add auto-focus on tree after opening file browser - Implement keyboard navigation with arrow keys and Enter/Escape/Space shortcuts - Add type-to-search functionality to quickly navigate to files/directories
- Implement starting directory based on tag value instead of home dir
Cool, I did it! Now, it is more useful |
Really, the arrows work excellent now! Thanks! Could I have few more requests to make it even better please?
|
Cool, I'll update asap! |
Hi @e3rd, tried to fix all, but I confused what you mean in here; Please check new version. |
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 just meant the same thing you've already done for SecretTag. There, a shortcut Ctrl+T toggles the masked state. Here, the shorcut might toggle the button.
But nevertheless, what you did is awsome, a proper Quick Search, wow, it's working great and you don't have to add this detail.
Just resolve the two new minor comments and I'll gladly merge.
@@ -48,9 +131,6 @@ def on_radio_set_changed(self): | |||
|
|||
def on_key(self, event: events.Key) -> None: | |||
if event.key == "enter": | |||
# If the radio button is not selected, select it and prevent default |
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.
Why stripping the comment out?
def __hash__(self): | ||
# The function is needed, otherwise the following would not work: |
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 see the same method hash already in parent. I still don't get why it's needed... but do you think it's a good idea to remove the method from PathTag altogether?
@@ -132,9 +135,46 @@ def __post_init__(self): | |||
else: | |||
for origin, _ in self._get_possible_types(): | |||
if origin in common_iterables: | |||
self.multiple = True |
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.
Why removing this? I thing we'll miss this. It's like
PathTag(["/tmp","/var"])
will become PathTag(["/tmp","/var"], multiple=True)
@@ -33,8 +33,91 @@ def get_ui_value(self): | |||
|
|||
|
|||
class MyInput(Input, Changeable): | |||
async def on_blur(self): | |||
return self.trigger_change() | |||
def __init__(self, value_or_tag, *args, **kwargs): |
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.
Sorry, I've missed this part earlier. I fear the code will become a yet more labyrinth if such things are done not only in the Tag abstract logic and in the Adaptor widgetize logic but also in the widgets themself. Even though that does work now!
Make it accept either the val or the tag, not both.
Make a PathInput or MyPathInput or anything instead of checking isinstance. If needed, spread it into multiple Changeable classes.
# This is triggered when Enter is pressed | ||
if self._convert_value(self.value) is not None: | ||
self.trigger_change() | ||
if hasattr(self._link, 'facet'): |
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.
Facet is an optional attribute, so it is always there but might be None.
Hence if self._link.facet
.
initial_value = "" | ||
if hasattr(tag, 'val') and tag.val is not None: | ||
if isinstance(tag.val, list): | ||
initial_value = ", ".join(str(p) for p in tag.val) |
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.
What use case do you cover here? A list handling. I fear this looks so difficult it should have a test for it. Tell me, I struggled a lot with the Tag internal typing and it might be handled somewhere there in the Tag.
Hi @e3rd, I just saw your comments, I'll check it out soon |
feat: enhance PathTag validation and improve TUI file picker