noctuid / link-hint.el

Pentadactyl-like Link Hinting in Emacs with Avy
GNU General Public License v3.0
159 stars 22 forks source link

Enhancement: Detect links in overlays #24

Open yyoncho opened 5 years ago

yyoncho commented 5 years ago

Consider the following code which will create clickable overlay:

(overlay-put (make-overlay
              (1+ (point))
              (point)) 'after-string
              (with-temp-buffer
                (insert-text-button "link in overlay")
                (buffer-string)))

It would be good if link-hint-open-link could find them if possible.

noctuid commented 5 years ago

Agreed. Can you give an example of a package that makes clickable overlays that link-hint does not currently detect?

With the current extension system, this should be easy to do, but I'm very busy now, so it may take me a while to get to it. Feel free to ping me/bump the this issue in a couple weeks if no progress has been made.

yyoncho commented 5 years ago

Sure: https://github.com/emacs-lsp/lsp-ui/ . Also, I am planning to extend lsp-mode to provide code lenses (similar to what VSCode has) but it would be bad if you cannot hit them via keyboard and link-hint looks like a natural fit for this.

noctuid commented 5 years ago

If I understand your suggestion, I need to explore whether it is possible easily with avy.

Is your idea to use an overlay to, for example, show references for some function (just one example use of a code lens I believe)? And if so would link-hint then be used to put avy overlays on each reference? I have never worked with overlays directly, but is it even possible to put an overlay inside/on an overlay? This might be possible if the reference list was inside a child frame instead of overlay.

I think maybe a more specific mechanism (e.g. the equivalent of ivy-avy for a code lens) would be a better fit. I also think using a child frame might be a better fit than an overlay. I am not sure if I understand what you want though, so I may be wrong about this.

yyoncho commented 5 years ago

Is your idea to use an overlay to, for example, show references for some function (just one example use of a code lens I believe)? And if so would link-hint then be used to put avy overlays on each reference? I have never worked with overlays directly, but is it even possible to put an overlay inside/on an overlay?

Yes, this is exactly what I want. It was not clear to me whether it is possible at all too and I hoped you to have a better understanding of overlays than mine.

I think maybe a more specific mechanism (e.g. the equivalent of ivy-avy for a code lens) would be a better fit.

I am considering this as a second option. From user perspective, having one command(and one binding) that covers all of the cases seems like a better option - thus I decided to file this issue.

I also think using a child frame might be a better fit than an overlay. I am not sure if I understand what you want though, so I may be wrong about this.

Can you elaborate on that? Is there a sample I could take a look?

noctuid commented 5 years ago

Wouldn't you manually have to trigger a code lens? In that case, you could potentially set up some keybindings for scrolling through or selecting specific candidates at that point. The use case seems similar to company. With company's default front-end, you can select a specific candidate with something like M-1.

If code lenses were somehow automatically added, and there could be more than one of them, it might make sense to consider items within them as links. That doesn't seem like the desired behavior to me though. Also, you wouldn't really need to have any special code to find these links (they would just be lines in the code lens), so link hint wouldn't really be necessary for much. I think it would probably be better for them to be separate.

A child frame can be displayed anywhere just like an overlay, but it actually has an associated buffer, so you can potentially do a lot more with them. For example, I do not believe if is possible to implement avy selection of candidates for the default company front-end. Hypothetically, this should be doable with a child frame front-end. There are two examples you could look at that use a childframe for company (company-box and company-posframe). Company-posframe is built on the posframe library which is a convenience library for child frames. There is also a package that lets ivy use a childframe (ivy-posframe), one that uses one for flycheck messages, etc. Note that this functionality is only available in recent versions of Emacs (I don't remember the exact version off of the top of my head).

yyoncho commented 5 years ago

Thanks for the detailed answer!

In that case, you could potentially set up some keybindings for scrolling through or selecting specific candidates at that point.

I don't want to go in that direction - I want to make all of the lenses visible, otherwise helm will work too(I might end up with helm if I fail to find a satisfying solution). The main value of the lenses is that you are going to see the what in the current buffer has lenses and then directly jump.

In vscode the lenses are displayed automatically, I am still looking for what would work for Emacs and I am planning to support both options - automatic + manual. There could be multiple lenses on one location, e. g. references + implementations and each of them will have dedicated action.

I am aware of company-box but as far I know child frame will hide the content behind it which won't work if the lenses are displayed automatically?

noctuid commented 5 years ago

Bare with me as I have very little experience with vs code, vs, and have only just heard of codelens.

IIUC you want to put a bunch of clickable overlays in the buffer that do not display over code. In this case, then yes, link-hint should support this if possible, and overlays should be used. I will look into how easy this is to do.

As for my comments on child frames, I was thinking about the actual popup you get when clicking on an overlay. For most basic cases, ivy/helm/completing-read would be preferable. Child frames might be useful if there was ever a desire to show something particularly complicated (and it seems like some of the demos for VS are).

yyoncho commented 5 years ago

I have no experience with vscode either, I am only exploring the functionality and working on porting in in emacs. As a side note, the lenses could display a lot of information, e. g. "Run test" on test methods, runtime debug information, etc. If it was only references/implementation I wouldn't bother at all...

As for my comments on child frames, I was thinking about the actual popup you get when clicking on an overlay.

For this, I am going to use whatever user has configured in lsp-mode itself(e. g. lsp-ui-peek).

MaskRay commented 5 years ago

I want to chime in to say that clicking codeLens overlays with keyboard will be very useful.

Either link-hint or avy supports it, will help. By taking a cursory read of the supported link objects mentioned in README.md, link-hit.el already supports lots of link-like stuff in text properties. It does not seem out-of-scope to support overlays.

codeLens in ccls

noctuid commented 5 years ago

I mean to reply to this the day of; sorry for the late response.

This is hypothetically possible to do, but it would need to be addressed directly in avy. It would probably require fundamental, time-consuming-changes. The issue is that all the avy display functions are defined to create an overlay at a given position and window. If you only wanted to have one codelens at a position, this could be done without changes to avy, but your idea requires a bunch of overlays all right next to each other (or one overlay with all the differenct actions in it, if that's possible).

Avy could maybe instead have a display function that temporarily altered existing overlays to show the avy selection keys. If you wanted to potentially put avy overlays at both buffer positions and "inside" codelens overlays (which would be necessary to have link hint allow selection of both the existing links and these new code lens overlays), all of avy's display functions would need to be changed. If you would be okay with putting avy overlays only for code lenses and not for other links to, this might be easier to do.

I would make an issue on the avy repository to ask for a way to select overlays with avy (and link to/mention this comment). I think it's a good idea from a user standpoint, but it may not be worth it from an implementation standpoint.

I think some people's opinion would be that if you want to do things with the keyboard, it would be better to just have a dedicated keybinding for the action than to use avy. I don't know. My guess is that there would probably be some nice use cases for being able to select an overlay with avy. If this functionality isn't implemented, I think it would be fine to go with your alternative of e.g. using something like helm/ivy (or some other different menu-liku selection pacakage) to select the specific code lens instead of avy for people who wouldn't want to bind every single action or would want to be able to use a code lens that isn't available at the point.

This would be a lot easier to do, if there was something like an overlay that actually took up space in a buffer without affecting the underlying file, but I'm not aware of anything like that. I'm also not too familiar with overays, buttons, etc. like I said before though.

noctuid commented 5 years ago

To summarize my followup comment, you work with avy by giving it a buffer position, and what makes it hard to work with overlays as used in this example, is that you have a bunch of overlays at one position (or maybe one overlay with all the "goto ref", "run tests", etc. actions listed). You could potentially select the specific overlay(s) using link hint and then use some other mechanism to select the actual action (e.g. "runtests"), but with how avy works currently, you couldn't select the exact one immediately.

The comparison to text properties is if you had a text properties for a dozen links on one character. This usually isn't the case, but link-hint wouldn't be able to do much about selecting the correct one with avy either.

yyoncho commented 5 years ago

Avy could maybe instead have a display function that temporarily altered existing overlays to show the avy selection keys. If you wanted to potentially put avy overlays at both buffer positions and "inside" codelens overlays (which would be necessary to have link hint allow selection of both the existing links and these new code lens overlays), all of avy's display functions would need to be changed. If you would be okay with putting avy overlays only for code lenses and not for other links to, this might be easier to do.

I would make an issue on the avy repository to ask for a way to select overlays with avy (and link to/mention this comment). I think it's a good idea from a user standpoint, but it may not be worth it from an implementation standpoint.

I believe this is the way to go - extend avy to support selecting place in overlay. I did some tests and it looks like you can alter the overlays text and create the avy overlays into a overlay. I will go ahead and create an issue in avy.