atlas-engineer / nyxt

Nyxt - the hacker's browser.
https://nyxt-browser.com/
9.83k stars 411 forks source link

conqeror-style hinting | making hinting more intuitive/comfortable #2972

Open impaktor opened 1 year ago

impaktor commented 1 year ago

This is a continuation of #536 which was closed as "fixed", but as I return to evaluate nyxt as my next browser, I can't seem to get the feature to work (might be my configuration that is wrong? I post it below). I demonstrate this in the screenshots below.

Motivation

I find the fastest browsing is using keyboard navigation for following links. In the cases where I can see the link I want to follow before I start the link hinting, I know what to type before I even do the follow-hint (equivalent in conkeror) command, and my fingers are already on the keys, rather than waiting until follow-hint has indexed the links, and I've read what the index label is, and my brain maps that to the keys I need to type on the keyboard.

Desired solution

Below I show link hinting in conkeror vs. nyxt (current master). where I want to open the file "dir-locals", by typing "locals". As I type letters matching a word the link, I want the active links to interact with to be narrowed down to the links matching what I type.

Conkeror

Note how I in the minibuffer type loc to narrow to the file dir-local, (and can then just press enter, as the green indicates it is now the selected link) conkeror

Nyxt

After typing the first letter, l, in the minibuffer all labels dissapear, no link can be selected? Yet all blue fields remain (feature?) nyxt

My configuration

Maybe my configuration is wrong, and the requested behavior is possible? This is my entire nyxt config, code is from #538 but adapted to what I hope is correct v3.0 syntax:

(define-configuration buffer
  ((default-modes
    (pushnew 'nyxt/mode/emacs:emacs-mode %slot-value%))))

;; Conkeror hinting style (trying to make it work on v.3.0)
(define-configuration :hint-mode
  "The :hint-mode magic here is to avoid writing these tedious prefixes.
It's auto-resolved to nyxt/mode/hint:hint-mode.

Slot names also resolve to the right prefix based on the mode they
belong to:"
  ((hint-alphabed "KDJFLSAEUROWPQCMVXZ")
   (hinting-type
    :vi
    :doc ":vi-type hints encapsulate fit-to-prompt-p=t, auto-follow-hints-p=t,
compute-hints-in-view-port-p=t from the earlier pre-releases.
Another (default) hinting type is :emacs.")
   (show-hint-scope-p
    t
    :documentation "This is not exactly necessary, because the default value is NIL already.")))

Design consideration

Now one potential problem in getting this behavior in Nyxt, is that conkeror uses numbers for indexing, and nyxt uses letters, thus how do we know if the letter user types refers to the index label, or a word in the link? Actually, conkeror has the same problem when a link starts with / has numbers in them, i.e. numbers are always interpreted as referring to the index label, and letters to words in the link title. So just a question of priority, if typing letters part of the index label, that takes precedence over matching words in the link. Using hint-alphabed to only use numbers, one would even get identical situation as conkeror.

aadcg commented 1 year ago

I think that, for the behavior you're looking for, you should set the hinting-type to :emacs (the default). Then, use the arrow keys to select the link you're looking for (if needed) and press RET.


Let me explain the rationale behind setting hinting-type to :vi. You trigger 'follow-hint' after you have made visual contact with the link you want to interact with, and you type the hint string drawn on the screen. The order of the alphabet matters, so that it's more ergonomic. For example, for QWERTY, "KDJFLSAIEUROWPQCMVXZ".


how do we know if the letter user types refers to the index label, or a word in the link?

I believe you've answered it yourself!


Personally, I think that what you propose brings more problems than the ones it solves.

Concretely, say that the goal is to narrow down to a link that contains "fo" and a hint "fo" exists too. Then, whatever precedence you establish, it's very confusing and annoying. A way to solve this would be to establish the rule "if the length of the input string is longer than all string hints, consider that it is being matched against link text, not hints".

But then, if we go down this road, say that the goal is to narrow down to a link that contains "foo" and all hints shown when follow-hint was called had length 2. Then, "foo" will be interpreted as "find a link that contains "foo". There's no guarantee that "foo" matches a single link. I.e., new link hints need to be drawn to disambiguate. Well, at this point, it would have been easier to have inputted the hint string from the start!

Even if numbers are chosen for indexing, you've mentioned it also has its drawbacks:

Actually, conkeror has the same problem when a link starts with / has numbers in them, i.e. numbers are always interpreted as referring to the index label, and letters to words in the link title.

This should suffice to show why this is not a good idea.


@heiwiper, if you have the time to follow this interaction, your opinion as a user and developer of some of these features would be valuable.

aartaka commented 1 year ago

@impaktor, try using an :emacs hinting type, it should fit your use-case better than :vi one :)

But yes, the fact that hint scope doesn't disappear after hint narrowing is not cool :(

heiwiper commented 1 year ago

I think we should update the documentation regarding the newly introduced config slot hinting-type to specify what is being searched against.

I personally don't use :emacs hinting type but i was wondering if users who are more comfortable with this hinting type would ever search against hints, it seems to me more user friendly to use :vi hinting type if one is willing to type hints to click on links, otherwise they would have to either type the hint string then click Enter or type a few letters of the hint string then click up or down a few times when they could've just typed the remaining letters of the hint (probably 1 or 2). The :emacs hinting type makes more sense when one already knows what they are about to type regardless of hints.

All that to suggest that we would might change the hinting behaviour of :emacs hinting type to ignore hint string. In this case the hint string would only serve for visual reference to the user so they can see which link they are about to click when scrolling through the prompt buffer. We might as well replace the hint string with numbers if we go that way (keep and mind that I am more comfortable with :vi hinting type, so my suggestion is not based on usage feedback).

As for the hint scope, I haven't been aware of this feature, I might have missed it when I implemented the tree style hinting mechanism. I will look more into it and submit a pull request to fix it. Although I'm currently working on adding Shadow DOM support (which I'm nearly done with),so I might leave the hint scope fix for after I'm done with the former.

aartaka commented 1 year ago

@heiwiper, so the reason we have :emacs hinting type by default is that it has much more safety checks (you have to hit return, you're checking the text etc.) and has more features (like multiple selection). While :vi type is useful, it's quite specialized.

aartaka commented 1 year ago

Hint string removal could hurt :emacs type of hinting—just now I was using hint strings to check off a bunch of checkboxes on Github notifications. It wouldn't make much sense to use anything but link hints there, because checkboxes are not likely to have any meaningful text.

EDIT: link hints. EDIT: non -> on

heiwiper commented 1 year ago

You re totally right I comoletely forgot about that part, even icon only buttons would be hard to interact with.

I do have one more suggestion in that case (although I think :emacs hinting type is sufficient for what @impaktor is asking for). We could have a prefix symbol to indicate we would like to search for element text content only, example ! <search-input>.

aadcg commented 1 year ago

I think we should update the documentation regarding the newly introduced config slot hinting-type to specify what is being searched against.

Take a look at the docstring below. I think it's quite good, but can we do better? Notice that "usual prompt-buffer facilities" entails that input sent to the prompt buffer is matches against the attributes of each suggestion. It may not be immediately obvious, but it makes little sense to be exhaustive in docstrings. Manuals are the place for things to be explained in multiple ways and/or from multiple angles.

In :emacs, hints are computed for the whole page, and the usual `prompt-buffer'
facilities are available.  
In :vi, the `prompt-buffer' is collapsed to the input area, hints are computed
in viewport only and they're followed when user input matches the hint string.

But yes, the fact that hint scope doesn't disappear after hint narrowing is not cool :(

Let's open an issue about it.


We could have a prefix symbol to indicate we would like to search for element text content only, example ! .

I think we'd be looking at this from the wrong angle. Think about it as a problem of "matching prompt buffer input against suggestions", rather than "specialize hint-mode for a niche use-case".

It's possible to achieve what you suggest if we take the first angle I've presented above. Prompt buffer suggestions have attributes, and they can be toggled with the command toggle-attributes-display. Input is matched against the text of displayed attributes. And there you have it. We don't support disabling certain attributes by default, but we may do it in the future.


Closing @aartaka?

impaktor commented 1 year ago

Sorry for late reply, and thanks for the attention to this issue.

My conkeror habit

First, let me describe how I find conkeror very useful. I do all my "link clicks" by one of, or a combination of:

  1. type link index label / "tag" (these are numbers in conkeror, hint-alphabet in nyxt)
  2. narrow-to-search by typing part of link title
  3. use navigation keys (C-n/p or arrows)

And all above are finalized with a key (RET) to open the link in current buffer, or another key to open in new buffer in background and another key to open in foreground. Often I can start typing the title, it narrows down the links I can interact with to some single digit number, and I can then either press the number of the label, or keep narrow until I have unique link, or I can use navigation keys to get me the final way. However, often typing just two three letters of the link title will get me there.

Replies

I think that, for the behavior you're looking for, you should set the hinting-type to :emacs (the default). Then, use the arrow keys to select the link you're looking for (if needed) and press RET.

I tested :emacs mode, I get a mini-buffer that pops up and obscures the link I want to follow, if it's in the bottom half of the page. This obscuring of links happens for the case I'm testing in the gif above, i.e. type "loc" on nyxt github code page. It narrows down to several links in the mini-buffer, and I don't know which is the right, and I can not see what more to type to keep narrowing to the one I want, because it's obscured, nor use arrows to get to the correct one, because I don't see which link in the main buffer is the one I see in the mini-buffer.

Personally, I think that what you propose brings more problems than the ones it solves. Concretely, say that the goal is to narrow down to a link that contains "fo" and a hint "fo" exists too. Then, whatever precedence you establish, it's very confusing and annoying.

I've used conkeror for +10 years (It's still my daily driver), and the hinting shown in the gif works like a charm for me. Exceptionally rarely / almost never, do I encounter the problem of labels colliding with the "narrow to search" strings I've typed*. I'm thinking for nyxt: if the letter typed is in a label, it's a label, if not, then do narrow-to-search. Then if I have numbers in my hint-alphabet, I will get identical solution as in conkeror.

*(because I never narrow-to-search using number if the link title has a number "1984 was a book by Orwell", I would type anything matching the title except the numbers)

Description of what I hope nyxt could do

The following describes what I hope I could configure nyxt to do (basically same as the conkeror gif above):

aadcg commented 1 year ago

I believe that there's room for improvement, but we need to arrive at a very well thought out specification that takes into account all angles and perspectives.

In order to arrive at it one needs to re-read very carefully:

Please don't rush at "fixing" things. Come up with a spec first and deduct all consequences. Nonetheless, I don't think this is a priority and we already cover the most frequent use cases.

aartaka commented 1 year ago

@impaktor, what could also be useful for you is: you can scroll the main buffer while in prompt buffer. Commands are: scroll-other-buffer-down (Emacs C-M-n, VI M-j), scroll-other-buffer-up (Emacs C-M-p, VI M-k), scroll-page-down-other-buffer (Emacs C-M-v, VI C-M-j), scroll-page-up-other-buffer (Emacs C-M-s-v, VI C-M-k).

EDIT: Borked markup.

aadcg commented 1 year ago

@aartaka that's good advice, but I'm wondering why do we set :scroll to nil in highlight-selected-hint*.

This change was made in commit 83b60a11e0cf62bc5ae7bf111f9468b8ccf20f82. @jmercouris, could you explain your decision? I don't see why scrolling to the current suggestion/hint confuses the user.

@impaktor here's yet another tip for your use-case. Issue command scroll-to-hint so that the current hint is not hidden by the prompt buffer.

jmercouris commented 1 year ago

The reason I removed it was because as soon as we started hinting, the user would lose their position and it would scroll on screen for them.

Let's say we are halfway down the page, and I invoke element hints, then I will be instantly scrolled to the top of the page because of the first suggestion.

That said, there is a way to manually invoke the follow action with a keybinding IIRC.

aadcg commented 1 year ago

Of course. Clear, thanks!

aartaka commented 1 year ago

Maybe integrate it into pre/post-processors? These run just after user input, which is pretty safe to do, at least for hints.

It's an ugly solution, but still a working one ( ͡° ͜ʖ ͡°)

jmercouris commented 1 year ago

That's an interesting idea Artyom, perhaps that will work! It does depend on what appears to be an undocumented API behavior (as far as I understand)... but still, could be the way.

aadcg commented 1 year ago

I'm trying to imagine it and it seems that I can anticipate a problem. The user sets the input, and only after that (via post-processor) the scrolling kick in. So far so good. But when the user changes the current suggestion, the scrolling won't happen.

jmercouris commented 1 year ago

It would almost seem that C-l really is the best solution, or an easier way to toggle the follow action on/off in the Prompt buffer UI.

aartaka commented 1 year ago

Yes, C-l is the familiar and useful thing! (We already use in file manager for another action, but it still an Emacs-inspired action there...)

jmercouris commented 1 year ago

Alternatively, consider a delayed prompt buffer follow action after typing?

would avoid instant scroll, but still support following.

aartaka commented 1 year ago

So it seems we have a case for a third hinting-type. To summarize:

aadcg commented 1 year ago

So it seems we have a case for a third hinting-type.

I strongly disagree with that conclusion, and I've detailed above why pursing a "conqeror-style" hint system leads to a dead end. On top of that, we shouldn't support all implementations of a certain feature. We should follow the principle "Design with maximum flexibility and provide one single set of defaults". Users can adapt the flexibility we provide to their needs. Any other strategy is too costly for virtually no gains. According to it, we've already did more than required when we added :vi. In that case, however, there have been lots of user requests in that direction. We can't base our decision based on the feedback of one user.

In addition, in retrospective, we might have made a mistake when we decided to provide two mutually exclusive hinting types. Ideally, there should be a way to toggle between those two strategies, depending on the goal at hand. I've mentioned it here.


What we have to acknowledge is that :emacs, the way as it stands now, is a subpar default. And the best indicator is the number of reports we receive about it. We need to improve the default hint system, :emacs. One thing that everyone seems to agree is that having the current hint hidden by the prompt buffer is unacceptable. @jmercouris has proposed an interesting idea:

Alternatively, consider a delayed prompt buffer follow action after typing?

This idea should be explored by @aartaka or @jmercouris, since I don't use :emacs.

aartaka commented 1 year ago

What we have to acknowledge is that :emacs, the way as it stands now, is a subpar default. And the best indicator is the number of reports we receive about it.

We receive a lot of reports about defaulting to VI bindings, so that's not necessarily a good metric :P

We need to improve the default hint system, :emacs. One thing that everyone seems to agree is that having the current hint hidden by the prompt buffer is unacceptable.

Another improvement would bem making extremely clear an obvious that one can scroll the main buffer—or even focus it—while in prompt buffer. That would solve most of the problems I believe.

Delayed prompt action or an action for all moments except startup is a good option for hinting mechanisms too, yes.

aadcg commented 1 year ago

We receive a lot of reports about defaulting to VI bindings, so that's not necessarily a good metric :package:

This is off-topic but I'll reply, since I don't think that the comparison is fair. We don't receive reports to default to VI bindings because another keyscheme (say Emacs of CUA) is less functional than VI. In the case of hint-mode, users report that the default behavior is lacking.