-
-
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
Minibuffer overhaul #777
Comments
I have been working on this in the background, doing some research, and I believe I have some insights to offer:
I've investigated Lem. I do not think much can be extracted from it. It is not written in a way that is conducive to that.
What is a "readline" library? A completion engine? If so, I have a lot to say about completion, prediction, etc. Though Emacs is good, I have some ideas about this domain that I think could help boost it into the stratosphere! :-)
You are mistaken :-) It does not use javascript to know which candidate is selected.
The reason we use continuation passing style to gather data from the minibuffer is to avoid blocking decisions on the main thread. This asynchronicity provides us many benefits (such as allowing single thread execution while waiting for input). We could do it with multiple threads, but it is not necessary for something like the minibuffer, and actually the code would probably be more complex.
suggestion
select
how about
It is not necessary that each element report how much space it takes to support paging. It would be enough for the view to know the height of a group of elements.
Probably we can support this by having 2D arrays as potential input.
I disagree, being able to toggle columns within the minibuffer will probably be complex. Sometimes more choice = more complexity.
This goes to my previous thinking about Emacs sorting. While it is great, there is a lot to be said about predictive technologies :-D I really like this idea for simple applications, implementing it (from a UX perspective), will be challenging.
I do not believe this is necessary, since we can pass filters to the rendering, they can have the knowledge of how to sort things, why must the object contain the knowledge about itself?
Isn't this already the case?
Certainly a VERY good idea! This would make the interface far more snappy. One thing to keep in mind though is that we probably want to prepare all of the suggestions before displaying them such that they don't resort themselves as the user is looking at them.
what do you mean? like if we are doing switch-buffer it would preview the buffer we are moused over? that could be pretty cool!
maybe for this we could capture state in a closure?
|
John Mercouris <[email protected]> writes:
What is a "readline" library? A completion engine? If so, I have a lot to say about completion, prediction, etc. Though Emacs is good, I have some ideas about this domain that I think could help boost it into the stratosphere! :-)
Here I was referring to "GNU readline", which is the most widely used
command line completion engine.
Anyways, we need to find a good name :)
You are mistaken :-)
It does not use javascript to know which candidate is selected.
Indeed, sorry about that.
The reason we use continuation passing style to gather data from the minibuffer is to avoid blocking decisions on the main thread. This asynchronicity provides us many benefits (such as allowing single thread execution while waiting for input). We could do it with multiple threads, but it is not necessary for something like the minibuffer, and actually the code would probably be more complex.
I don't think it would be. The threading is an implementation detail
that could be completely abstracted by "minibuffer-read".
The issue with our current implementation is that it leaks the
abstraction: every call must write the `(with-result ...)` boilerplate.
This also has the downside of (read-from-minibuffer...) not returning a
return value which may trip many user.
> * The currently highlighted item could be called `current candidate` or `current suggestion`.
> * Now we have `select-next` and `select-previous` to shift the current
> suggestion to the nexet. Since it's ambiguous (`select` has the meaning of
> `mark`), I suggest to simply name it `next`. With the package prefix, that
> would be `readline:next`.
how about `suggestion-cursor-next`?
I like `next-suggestion` for a command or `suggestion-next` for a
function.
I suggest changing the "cursor" term:
- It can be confused with the input buffer cursor.
- It's not very idiomatic to call "cursor" what is more often call
"index" of a list.
> New features:
>
> * Support paging (#454). This
> means we need to know the number of suggestions currently displayed. It's not
> trivial, especially if the suggestion contains a picture for instance. This
> is why each suggestion item needs to report how much space it takes, but
> horizontally and vertically.
It is not necessary that each element report how much space it takes
to support paging. It would be enough for the view to know the height
of a group of elements.
The problem is when we extract the library. The height can only be
known by Next, not by readline.
So if we go with your solution (which might be simpler), it means that
we need to call the readline paging functions with a height (or number
of suggestions) argument.
> * Support multi-columns: currently `execute-command` has 3 columns and we want
> to add a 4th one (#624).
Probably we can support this by having 2D arrays as potential input.
Input of what?
> For the sake a clear display and better control, we need to allow for
> tabulated display and add a command to allow the user to choose which column
> to toggle.
I disagree, being able to toggle columns within the minibuffer will probably be complex. Sometimes more choice = more complexity.
Why complex? Seems simple to me at first glance.
> Also add a column to choose which columns (yes, plural!) to sort by.
This goes to my previous thinking about Emacs sorting. While it is great, there is a lot to be said about predictive technologies :-D
Indeed, but sometimes we really want to sort.
I'm thinking of my Emacs Helm experience here with files in particular:
sometimes I would like to sort the list by date for instance.
> * Support filters. Find a way or an input syntax to filter suggestions
> depending on their characteristic. The filtering should be done by a callback
> in the suggestion itself, so that each different suggestion type understands
> their own filtering.
I do not believe this is necessary, since we can pass filters to the rendering, they can have the knowledge of how to sort things, why must the object contain the knowledge about itself?
For instance, filter by file extension (or MIME/Type), but only for file/URL objects.
Only objects know what an extension/type means.
Example:
- Input: ".jpg"
- Suggestions:
- bookmark "foo.jpg.bar" is displayed.
- URL "quz.jpg.qux" is NOT displayed.
- URL "quz.jpg" is displayed.
This way we could do smart, contextual filtering.
> * Support multiple actions. Each suggestion should specify a list of actions to
> operate on it. Hitting `return` runs the default action, but hitting some
> other key allows for choosing the action.
Isn't this already the case?
I think you are confused with multi-selection.
Multiple actions means you can perform _different_ actions on one or
more suggestions.
> * Support Helm "follow mode", e.g. when navigating a minibuffer displaying
> buffers, it would temporarily display the current suggestion in place of the
> current buffer. On cancel, it restores the state.
what do you mean? like if we are doing switch-buffer it would preview the buffer we are moused over? that could be pretty cool!
Yes!
> * Support resuming minibuffers. This is especially useful to resume searches.
maybe for this we could capture state in a closure?
Or simply reuse our recent-buffers "library".
|
I've started from the original post, with some of my feedback and ideas. Support paging (#454):
Support multi-columns (#624):
Support multiple actions: Support multiple sources: Support asynchronous suggestion computation: Support multiple binding schemes: |
+ Each suggestion is aware of its size. This is significantly more difficult, more computationally expensive, and makes it harder to view long lists when the size of each entry is non-uniform.
There are two options to deal with the display of multiline suggestions:
- Insert a separator (e.g. a horizontal line) between the suggestions.
This takes a bit of space.
- Alternate the background color, e.g. white and dark gray.
Support multi-columns (#624):
+ The minibuffer should be able to accept objects (extending the minibuffer-suggestion class) with one or more dimensions. Each dimension corresponds to a column. The objects must have sort functions available for each dimension. These sort functions can be toggled by the user on top of each column. Therefore, we call `SORT` and pass the object the minibuffer input to compute its position in the minibuffer results. This can be parallelized to improve performance.
Even with 10000 suggestions (e.g. my bookmarks :p) sort finishes in a
split second, parallelization would be needed here I believe.
Support multiple actions:
I disagree with this premise. The minibuffer starts with a verb. I want to do X. Then you find noun Y to operate on X. It never is the other way around.
It's actually a great feature to be able to go in both directions! The
best implemented example that I know of is Helm-find-files which
effectively acts as a file manager. First browse your files then decide
which action to take.
The possibility to run multiple actions also means you can chain actions
within the same minibuffer sessions, thus preserving the selections and
input between each action.
Finally, multiple actions means the user can list which actions can be
performed on a given object.
|
On the GTK side, I think we should use a GTK text input widget for the input. This would solve the CJK input and the like. |
Minibuffer sessions should be first class objects so that they can be resumed. See #744. |
We can use the widget, if only as a virtual input. I would not like to render it, we do not have enough control over its appearance and behavior. |
Finally, we need to make sure our code is testable, that is to say make the minibuffer "mockable" to simulate user input. Having non-testable minibuffers is the single big blocker for writing tests in Nyxt. |
We can use the widget, if only as a virtual input.
This is already what we are doing, it does not work. We need to
investigate why.
I would not like to render it, we do not have enough control over its appearance and behavior.
Note that GTK supports HTML rendering in many of its widgets.
|
If we are already doing that, then I do not imagine that CJK input will miraculously start working :-D maybe it is a widget configuration or something. We can try with a minimal test where we use cl-cffi-gtk and see if we can make a text widget that accepts CJK first. |
John Mercouris <[email protected]> writes:
If we are already doing that, then I do not imagine that CJK input will miraculously start working :-D
Well, what we are doing is a hack. We are writing to a virtual GTK
buffer that is not set up for using input methods, but there is no way
the user can do it (I think) since the widget is not visible.
With a visible widget, the user can toggle the input method.
maybe it is a widget configuration or something. We can try with a minimal test where we use cl-cffi-gtk and see if we can make a text widget that accepts CJK first.
Good idea.
|
About minibuffer mocking: This can be used to make commands
non-interactive.
Say a command FOO prompt the minibuffer and we want to call FOO without
prompting the minibuffer, we need to be able to mock the minibuffer result.
|
Other features:
|
More features:
|
Most of these features are now on master. |
The minibuffer needs a rewrite to fix a couple of current issues and implement
many core features.
The code needs to be extracted:
sorting, etc. It would be heavily inspired by Emacs Helm.
One of the biggest flaws of our current implementation is that it uses
Javascript to know which candidate is selected. If I'm not mistaken, there is
no need for that. Instead, would could do all the logic in the readline
library, only using HTML to render.
A great benefit of this is that the minibuffer queries would not be asynchronous
anymore. In particular, instead of the convoluted
we could have
(let ((result (minibuffer-read ...))) (use result here))
Another thing that can be improved is the vocabulary:
candidate
orsuggestion
?mark
orselect
?current candidate
orcurrent suggestion
.select-next
andselect-previous
to shift the currentsuggestion to the nexet. Since it's ambiguous (
select
has the meaning ofmark
), I suggest to simply name itnext
. With the package prefix, thatwould be
readline:next
.New features:
Support paging (Support Page-Up / Page-Down keys in minibuffer #454). This
means we need to know the number of suggestions currently displayed. It's not
trivial, especially if the suggestion contains a picture for instance. This
is why each suggestion item needs to report how much space it takes, but
horizontally and vertically.
Support multi-columns: currently
execute-command
has 3 columns and we wantto add a 4th one (Add one-liner documentation to M-x command list #624).
For the sake a clear display and better control, we need to allow for
tabulated display and add a command to allow the user to choose which column
to toggle.
Also add a column to choose which columns (yes, plural!) to sort by.
Support filters. Find a way or an input syntax to filter suggestions
depending on their characteristic. The filtering should be done by a callback
in the suggestion itself, so that each different suggestion type understands
their own filtering.
Support multiple actions. Each suggestion should specify a list of actions to
operate on it. Hitting
return
runs the default action, but hitting someother key allows for choosing the action.
Support multiple sources. With multiple action support we could mix-match
suggestions of different types (e.g. bookmarks and history). Then we miss the
possibility to sort items by type, and more importantly, to browse the types
(like Emacs Helm allows for going from one source to the next). Maybe
filtering would do here.
Emacs Helm has a
persistent action
feature that show the result of theaction in another buffer, leaving the minibuffer open. Useful to display
contextual help for instance. Maybe we can generalize this.
Currently our filters are very repetitive: They all call fuzzy-match. Maybe
we can do better:
suggestions
key argument,create object just for the minibuffer), otherwise
object-display
is used.higher-order-function that builds the fuzzy-matcher according to a selection
of rules (fixes Use extensible fuzzy-matching everywhere #274).
Support asynchronous suggestion computation.
Support Helm "follow mode", e.g. when navigating a minibuffer displaying
buffers, it would temporarily display the current suggestion in place of the
current buffer. On cancel, it restores the state.
Support resuming minibuffers. This is especially useful to resume searches.
From Next itselt, use a GTK (or Qt) widget to get the input. This should fix
Input methods don't work in the minibuffer #324.
Still from Next, allow VI / CUA / Emacs binding schemes.
The text was updated successfully, but these errors were encountered: