-
-
Notifications
You must be signed in to change notification settings - Fork 425
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
WIP: Minibuffer overhaul #1054
WIP: Minibuffer overhaul #1054
Conversation
This is based on the Calispel patchset (#1047) because I need it here. See the tests for a nice use of Calispel with |
For now there is nothing that can be used in Nyxt, however the backend data structures are ready for review. Next steps:
|
Any early code review is already welcome! In particular, I'm happy to hear feedback about the class and slot names. |
The other slots are optional.")) | ||
|
||
;; We must eval the class at read-time because `make-source' is generated using | ||
;; the initargs of the class. |
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 do we need a make-source? what are the benefits over make-instance 'minibuffer-source and then having initialize-instance after?
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.
initialize-instance
can be used regardless.
make-source
is a tiny shorthand for make-instance 'minibuffer-source
. I figured that the user is going to use it a lot, so let's make this as short as possible.
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.
OK, that is a good point. I assume you also want to have the key arguments for the user hence why we have to read the slots?
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, that's the point of the define-function
macro, it allows us to automatically generate the keyword arguments.
(actions '() ; TODO: Implement! | ||
:type list) | ||
|
||
(persistent-action nil |
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.
would just =action= be OK too? I think that would make more sense personally
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.
But having both actions
and action
is confusing.
Otherwise I can change actions
to be a structure of
- list of actions
- default action
- persistent action
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 had already assumed that actions was a list of action objects, what else would it be?
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 is, but it's a bit limited because a simple list of actions does not specify:
- the default action (when the user presses
return
) - the persistent action (when follow-mode is on, or when the user presses a dedicated key).
So either we add slots to specify these two, or we set actions
to be of the action-list
type which has the aforementioned 3 slots.
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.
or we could use a plist?
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.
OR actions is actually an object and not a list, with methods to return the default action, the persistent action, etc.
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.
A plist could do, but the benefit of a dedicated object is that it catches error (plist accept arbitrary keys) which is very useful to catch typos in the user config.
About methods: the drawback is that it forces the user to define the action list globally to be able to decide which action is the default, which is much more verbose. Compare this (untested) config sample:
;; Without methods
(minibuffer:make
:sources (list (minibuffer:make-source
:actions (minibuffer:make-actions
:default default-action
:persistent persistent-action
:others (list action-a action-b)))))
;; With methods
(defvar *my-actions* (minibuffer:make-actions default-action
persistent-action
action-a action-b))
(defmethod default-action ((actions (eql *my-actions*)))
(first (minibuffer:actions actions)))
(defmethod persistent-action ((actions (eql *my-actions*)))
(second (minibuffer:actions actions)))
(minibuffer:make
:sources (list minibuffer:make-source
:actions *my-actions*))
(apply #'make-instance 'minibuffer-source args)) | ||
|
||
(defmethod initialize-instance :after ((source minibuffer-source) &key) | ||
;; TODO: Should we always do this? What if initial-suggestions are already |
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.
We can just check if they are or not, no? I guess I don't understand the problem indicated by the TODO here :-D
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 problem is that we change initarg data at initialization time, which may be surprising to the user. This is not very good practice in terms of data consistency.
An alternative would be to have a separate slot, e.g. initial-data
, and leave initial-suggestions
unexported.
Another solution is to remove the initarg for initial-suggestions
and add a new keyword argument initial-data
to make-source
.
libraries/minibuffer/minibuffer.lisp
Outdated
(maybe-funcall (after-cleanup minibuffer))) | ||
|
||
(export-always 'ready?) | ||
(defun ready? (minibuffer &optional timeout) |
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 would prefer readyp
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.
Forgot to update this one. I prefer ready-p
over readyp
though.
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.
Thats fine, the convention is a bit silly to me that single words don't get a dash and multiple words get a dash. I think it should just always be a dash.
Just some surface level comments for now, I haven't dug into the code yet :-) |
I'm thinking of renaming While we are at it, we can make methods for them as suggested in #1005. |
I agree with that change |
Note: make-source should return a lambda that creates minibuffer-source |
ab45ccf
to
8ddf574
Compare
…o minibuffer system.
For consistency with the rest of Nyxt.
On second though, do we really need a macro to create top-level sources? (define-class minibuffer-foo-source (minibuffer-source)
((initial-suggestions '("foo" "bar"))
(filter #'slow-identity-match)))
(minibuffer:make
:sources (list (make-instance 'minibuffer-foo-source))) Thought? |
define-class may suffice for the purpose, if you find yourself limited by it, we can always create a macro :-) |
Acknowledged.
I tried getting input methods to work in the minibuffer.
The easiest way to test is with unicode input, e.g. press
"control-shift-u 1 2 3 4 space" and see if it inserts a unicode
character.
It does not work because in our gtk-entry workaround because we only have
gtk:gtk-entry-im-context-filter-keypress and no way to tell that some
input preedit is happening.
One way around it would be to define a custom GTK input method. This
seems difficult to get right and it's unclear to me whether it will work
well with the various user settings (UIM, IBUS, etc.).
https://developer.gnome.org/gtk3/stable/GtkIMContext.html
So for now I'm leaning towards using a GtkTextInput widget instead of
our home-rolled HTML input.
The main reason we had this HTML input initially was because we used
Javascript to control the text editing features. But now that we have
input-edit.lisp, we can perfectly edit any GTK text input.
Another thing to keep in mind is that GTK is capable of applying CSS
anywhere, so styling would not be an issue.
Thoughts?
|
I am not a huge fan of it because one part of the minibuffer would be native widget, while the other would be a GTK widget. Also, the HTML affords us many benefits that a normal GtkTextInput widget does not. For example, we could implement Hydra really easily within the minibuffer right now. If we use a GtkTextInput, then we won't be able to. What if we had an invisible GtkTextInput that is focused and recieves input, and we just mirror the contents of that into our HTML view? |
Can you explain why Hydra would be a problem with GtkTextInput?
What if we had an invisible GtkTextInput that is focused and recieves input, and we just mirror the contents of that into our HTML view?
I'll try that.
Another benefit of using a native text widget is that it gives us
regions for free.
|
A hydra would be a problem because:
|
Also, regions not existing is a limitation of our text-buffer library, we will have them eventually :-)! |
1. it would be renderer dependent implementation
2. It would take up unresolvable space in the minibuffer
We can render the Hydra as part of the minibuffer suggestions, so this
won't be a problem.
|
…work. Pressing control-shift-u correctly inputs an underlined "u" in the dummy text widget, however it will be erased on next character press, instead of expanding into a unicode character.
See commit d5204f0.
I tried what you suggested, it was a good idea but sdaly it does not seem to
work :/
I think it's because intercepting key events breaks the IM context.
Can you think of a way around this?
|
If intercepting key events breaks the IM context, then it won't work no matter what. How does Emacs allow insertion of special symbols? We don't necessarily have to use the input manager, is there another way? |
Could we perahps toggle/untoggle intercepting the IM context? Have a sort of "raw input" button? |
Many updates on this branch, it's starting to be quite usable! You can try out 2 commands that use the new prompt buffer:
Highlights:
The The What remains to be done:
The good news is that most of the above tasks are really easy to implement. The Then after a final review, I'll replace all the minibuffer instances with There are also some cosmetic tweaks I would need help with (pinging @jmercouris :p):
Stay tuned! |
fixed todo regarding with of input area did not fix todo with regards to autofocus, more generalizable problem, probably requires intervention via GTK
the prompt-area is a less ambiguous name because it is composed of a prompt, and an input
div creation here only exists as a structural placeholder
all columns are of equal width very long tds result in overflow'd text, the user can scroll them disable scrollbars to avoid occluding the text
it prevent scroll behavior hiding the prompt
frequently scrolls and breaks minibuffer by limiting the size of the 'minibuffer entries' we can mitigate the problem in a simpler way
To do:
|
Closing in favour of #1157. |
This is an attempt to address #777 and most (all?) minibuffer-related issues.
First step is to implement the "backend": anything that's not display related, roughly reimplementing Emacs Helm.
Second step is to integrate it in Nyxt by implementing the frontend.