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
Introduce help context #1484
base: main
Are you sure you want to change the base?
Introduce help context #1484
Conversation
Hotkeys that used to be excluded from general help hints, can be useful as hints in particular contexts.
Tests updated.
- Add a context property. - Update footer text on context changes, if a footer event is not already in progress. Tests added.
Tests updated.
Tests updated.
Set context to "editor" only if it is not already set to more specific editor contexts. Reset context to "" on exiting any editor. Tests added and updated.
b75f6f5
to
04c2f4f
Compare
Check if the current focus is on - the menu view -> set context to 'general' - the stream list - the topic list Tests added.
Tests updated.
Tests added.
Tests added.
04c2f4f
to
5b38003
Compare
Add checks for clashing keys in the same context. Added new `context` argument. Generates a new file `hotkeys-by-context.md`. Refactored all the functions to take any field as an input, either category / context, by passing newly created variables. Added FileNotFoundError exception. Removed `Esc` from `ALL_MESSAGES` to pass linting.
5b38003
to
0a1909c
Compare
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.
There's a bunch of unfinished work here, and some significant changes to be made. I've mentioned the main ones in the CZO discussion.
I wanted to first ensure that I'm going in the right direction, so I've opened it up for review already.
@@ -220,7 +220,7 @@ class KeyBinding(TypedDict): | |||
'key_context': 'stream_view', | |||
}, | |||
'ALL_MESSAGES': { | |||
'keys': ['a', 'esc'], | |||
'keys': ['a'], |
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.
This is a temporary change. To make the linting tests pass.
As both the Esc
key mappings clash in the 'general' context.
I could add an exception instead too, if necessary later.
Or I could move the ALL_MESSAGES
command to the "message_view" context instead until that bug is resolved.
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.
This was discussed in the stream recently, I believe? :)
Your last suggestion reflects the current reality, so might be the short-term solution, with a comment re the bug/issue/discussion.
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 know the changes to this file would be pretty difficult to read and verify.
Do I need to break it down into layers?
Tested manually for the following cases:
[x] no hotkeys-by-context.md file
[x] mismatching existing hotkeys-by-context.md file
[x] matching existing hotkeys-by-context.md file
[x] no hotkeys.md file
[x] mismatching existing hotkeys.md file
[x] matching existing hotkeys.md file
[x] no arguments
[x] context argument
[x] fix argument
[x] both arguments
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.
It would definitely help to split this up, since this is multiple aspects:
- linting in any new ways, or relaxing linting as we move forward
- adding the new doc generation, if we end up going in that direction
However, as you say it would also be easier to verify, such as if you eg. refactor existing names first.
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.
@Niloth-p There's a lot here!
I did give this a manual test, and many parts definitely seem to be working. I mainly moved around areas of the UI, and since some hotkeys (including just ?
) effectively show a new random hint, it allows some degree of sampling of them.
I've not looked at the hotkeys assignment doc, since keys.py
works fairly well in the first instance, and I'd started reading that before you added the feature :)
I've only left inline comments until prior to the specific context setting. That's partly since I'm wondering if there may be an alternative approach rather than setting it explicitly in many places. For example, you've already set the context depending on a focus path in a few places instead, and for popups this could be a class variable that is accessed by generic popup show code?
One helpful change would be to address the 'cycling' issue sooner rather than later, but even before or part of that we can improve the design slightly. The original design was to indicate that ?
is general help, and show a random help next to it, but currently we have the help key right up next to Help
and in parentheses rather than square brackets (which we now tend to use). There's also a colon rather than an indication that the general help is distinct from the hint. As an extension specific to this change, it'd be great to show the relevance of the hint - does it work in compose, stream list, selected message, etc. I could tell that it was displaying reasonable hints based on the context, but showing the context itself would be helpful for those less familiar :)
'SEARCH_STREAMS': { | ||
'keys': ['q'], | ||
'help_text': 'Search Streams', | ||
'key_category': 'searching', | ||
'key_context': 'general', | ||
}, | ||
'SEARCH_TOPICS': { | ||
'keys': ['q'], | ||
'help_text': 'Search topics in a stream', | ||
'key_category': 'searching', | ||
'key_context': 'topic_view', |
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 think you mentioned this, but there is nuance with these two, since they depend on the state?
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, they both would actually belong in a general context, but need to apply a check (based on the state) to determine which one is applicable at the moment.
}, | ||
'REPLY_MESSAGE': { | ||
'keys': ['r', 'enter'], | ||
'help_text': 'Reply to the current message', | ||
'key_category': 'msg_actions', | ||
'key_context': 'message_view', |
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.
The _view
doesn't appear to add much descriptively, or for other context names?
This relates to a message being selected/focused, right?
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.
True.
I hadn't considered just not using any suffix, was instead trying to choose a good suffix.
Good idea!
Yes, it does. I'll add that as a comment to the HELP_CONTEXTS dict.
}, | ||
'CYCLE_COMPOSE_FOCUS': { | ||
'keys': ['tab'], | ||
'help_text': 'Cycle through recipient and content boxes', | ||
'key_category': 'msg_compose', | ||
'key_context': 'write_box', |
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.
As per another comment, using a user-facing name would be preferable for contexts.
This could be similar to the key_category, eg composing_message
? Keeping names easily searchable (distinct from others) could be useful, so the same as key_category could be challenging if we want that.
}, | ||
'AUTOCOMPLETE': { | ||
'keys': ['ctrl f'], | ||
'help_text': ('Autocomplete @mentions, #stream_names, :emoji:' | ||
' and topics'), | ||
'key_category': 'msg_compose', | ||
'key_context': 'editor', |
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.
If this has the same help text, it only applies to the message composition content, though we do support autocomplete in the stream/topic/recipient boxes for composing too - but only in the matching boxes, and no @mention
s or #stream
s with prefixes, and never emoji.
This may come down to my understanding your use of editor
, and the overrides or subsets.
@@ -220,7 +220,7 @@ class KeyBinding(TypedDict): | |||
'key_context': 'stream_view', | |||
}, | |||
'ALL_MESSAGES': { | |||
'keys': ['a', 'esc'], | |||
'keys': ['a'], |
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.
This was discussed in the stream recently, I believe? :)
Your last suggestion reflects the current reality, so might be the short-term solution, with a comment re the bug/issue/discussion.
# Avoid updating repeatedly (then pausing and showing default text) | ||
# This is simple, though doesn't avoid starting one thread for each call | ||
if context_change and self._is_footer_event_running: | ||
return | ||
if text_list == self._w.footer.text: | ||
return |
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.
The existing comment doesn't apply to your new code? Though see my other response, since I suspect it could do, depending if you refactor first and how you rewrite.
zulipterminal/ui.py
Outdated
@asynch | ||
def _update_context(self, context_value: str) -> None: | ||
self._context = context_value | ||
self.set_footer_text(context_change=True) | ||
|
||
context = property(lambda self: self._context, _update_context) |
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.
Does this need to be in a new thread?
if context_change and self._is_footer_event_running: | ||
return |
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.
The idea here is that we don't interrupt a running event, ie. timed-duration message, with a context change?
Paraphrasing the logic: if there's no context change (ie. previous to this commit), or a footer event isn't running, we continue with the previous behavior. That seems good, though can we use the new state boolean you added in the previous commit to simplify the existing logic at that point? That would make the previous commit a useful refactor, and this a more clear standalone change that only adds the context_change
part.
if event_running: | ||
view.frame.footer.set_text.assert_not_called() | ||
view.controller.update_screen.assert_not_called() | ||
else: | ||
view.frame.footer.set_text.assert_called_once_with(["some help text"]) | ||
view.controller.update_screen.assert_called_once_with() |
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.
With this split, it's pretty clear that this should be two separate tests.
It's occasionally reasonable to have these conditionals for complex multi-parameter inputs, but you only have a boolean here :)
One alternative is to simplify the mock asserts to be a bool; it depends how important the parameters to the call being asserted are.
text_list: Optional[List[Any]] = None, | ||
style: str = "footer", | ||
duration: Optional[float] = None, | ||
context_change: Optional[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.
This has become an increasingly complex (threaded!) function, which stores various state in the UI and the view, and has different calling styles depending upon the usage.
After this commit, I believe we'll support calling this with:
- no parameters -> reset to show random value
- specific fixed text/style (eg. autocomplete) -> show text
- specific fixed text/style with a duration -> show text, then later call with no parameters
- context change -> show different random value?
However, we can't generally mix and match all these parameters, or at least the new one? It's also unclear by the name, that no parameters does a 'reset' to show the default/random value.
For now, the best change would be to ensure using assert
(s) that all calls have the correct combination of parameters, and extend it to incorporate context_change
in this commit.
For the future this may warrant refactoring to explicitly cover the different uses and state for this.
I know you have lots of ideas and are getting code out well, but I'd suggest being cautious regarding pushing too far in one direction. It can be better to have work in another area to work on in parallel, rather than needing to heavily prune/drop/adjust a single direction if work in that one area takes a different path. |
What does this PR do, and why?
Introduces
context
to track the current focus.Uses context to generate relevant footer hints.
Adds missing tests and new tests.
External discussion & connections
Context Based Help Tips
andAdding context to hotkeys
How did you test this?