Skip to content
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

Add support for autodetecting URLs and making hyperlinks #7691

Merged
53 commits merged into from
Oct 28, 2020
Merged

Conversation

PankajBhojwani
Copy link
Contributor

@PankajBhojwani PankajBhojwani commented Sep 21, 2020

This pull request is the initial implementation of hyperlink auto
detection

Overall design:

  • Upon startup, TerminalCore gives the TextBuffer some patterns it
    should know about
  • Whenever something in the viewport changes (i.e. text
    output/scrolling), TerminalControl tells TerminalCore (through a
    throttled function for performance) to retrieve the visible pattern
    locations from the TextBuffer
  • When the renderer encounters a region that is associated with a
    pattern, it paints that region differently

References #5001
Closes #574

@ghost ghost added Area-Extensibility A feature that would ideally be fulfilled by us having an extension model. Issue-Feature Complex enough to require an in depth planning process and actual budgeted, scheduled work. Product-Terminal The new Windows Terminal. labels Sep 21, 2020
@codeofdusk
Copy link
Contributor

It doesn't look like this PR adds any custom logic to the UIA text range, so I doubt UIA clients will be able to detect clickable links with this implementation. Have you tested for this (i.e. with Narrator/NVDA)?

As an aside, this PR makes a good case for allowing browse mode in terminals (nvaccess/nvda#11172).
Cc @carlos-zamora, @Neurrone.

@carlos-zamora
Copy link
Member

Regarding accessibility. I haven't had a chance to test this out yet. Especially since it's in draft. But here's some resources and an idea of the work we'll probably have to do (probably in a separate PR):

In UiaTextRange, we'll need to update...

  • GetChildren(): hyperlink ranges count as a child
  • GetEnclosingElement(): if we're on a hyperlink, return the parent text range. Otherwise, normal behavior.
  • FindAttribute() and GetAttribute(): hyperlinks need to have the hyperlink attribute (exposed via GetAttribute()). And FindAttribute() needs to be implemented to find if one exists in the text range.

Another thought. Hyperlink support is just for Windows Terminal, not ConHost, right? That'll complicate things a bit with our accessibility model because UiaTextRange is currently shared. I see the implementation for autodetection is in TextBuffer (which makes this easier), but if ConHost won't expose it, we need to figure out a way to not expose hyperlinks that don't exist in ConHost. Of course, if this functionality is shared, just completely ignore this paragraph haha.

@codeofdusk
Copy link
Contributor

Hyperlink support is just for Windows Terminal, not ConHost, right?

If this is the plan, might this be reconsidered? While Windows Terminal is very feature-filled, in my experience conhost has much wider usage.

@DHowett
Copy link
Member

DHowett commented Sep 22, 2020

@codeofdusk, @carlos-zamora Hyperlink support is Terminal-FIRST, not Terminal-ONLY. Sorry for the confusion.

Since we can move so much faster in Terminal it lets us figure out the interaction model a lot sooner than if we throw something together and hope that people jump on the Windows Insider builds and test our thing out.

Many, many changes that make it into Terminal will eventually flow back. This is especially true for anything that deals with accessibility, standards compliance and text rendering.

We'd like to figure out the interaction model for formatted text and browseable regions in Terminal before we bring anything like this back into conhost, absolutely.

Comment on lines 2429 to 2434
const auto startRow = gsl::narrow<SHORT>(start / rowSize);
const auto startCol = gsl::narrow<SHORT>(start % rowSize);
const auto endRow = gsl::narrow<SHORT>(end / rowSize);
const auto endCol = gsl::narrow<SHORT>(end % rowSize);
const COORD startCoord{ startCol, startRow };
const COORD endCoord{ endCol, endRow };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am pretty sure this level of math is also done in Find/Selection and it might be using TIL or one of the utilities/types classes to help with it. Consider deduplicating with those.

Copy link
Contributor Author

@PankajBhojwani PankajBhojwani Sep 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm I can't seem to find the similar math - those parts of the code seem to begin with coordinates already (buffer or viewport) whereas here, since we only search after concatenating all the text together, we need to calculate the coordinates from the concatenated string

@miniksa
Copy link
Member

miniksa commented Sep 25, 2020

Now I don't want to go too crazypants here, but I'm thinking about future extensions to some degree.

I'm curious if you considered a design where the text buffer figures out the patterns on its own instead of being pumped to do that action by a thread from way outside itself, in this case from up in the Terminal* and friends.

I'm not saying this one is bad or wrong, but an alternate vision I have is that you would register an object with the TextBuffer that contained a pattern, region of interest, and a callback method/event inside of it. The TextBuffer would just... of its own accord as things are written in on the other methods (and maybe with its own internal, private thread or threadpool worker) grind through the region with the pattern and make callbacks as necessary.

Almost like you have an ITextScanner interface with an ITextMatchFound callback interface... which might lend itself toward easy adaptation into a COM/WinRT-based plug-in model for arbitrary buffer scanners in the future.

@miniksa
Copy link
Member

miniksa commented Sep 25, 2020

Now I don't want to go too crazypants here, but I'm thinking about future extensions to some degree.

I'm curious if you considered a design where the text buffer figures out the patterns on its own instead of being pumped to do that action by a thread from way outside itself, in this case from up in the Terminal* and friends.

I'm not saying this one is bad or wrong, but an alternate vision I have is that you would register an object with the TextBuffer that contained a pattern, region of interest, and a callback method/event inside of it. The TextBuffer would just... of its own accord as things are written in on the other methods (and maybe with its own internal, private thread or threadpool worker) grind through the region with the pattern and make callbacks as necessary.

Almost like you have an ITextScanner interface with an ITextMatchFound callback interface... which might lend itself toward easy adaptation into a COM/WinRT-based plug-in model for arbitrary buffer scanners in the future.

As Dustin and I are musing about this... your ITextScanner could just also contain ITextEffect on it as an optional in lieu of a callback that is just handed straight into the renderer and now you've also managed to design rendering effect extensions at the same time...

@miniksa
Copy link
Member

miniksa commented Sep 25, 2020

Now I don't want to go too crazypants here, but I'm thinking about future extensions to some degree.
I'm curious if you considered a design where the text buffer figures out the patterns on its own instead of being pumped to do that action by a thread from way outside itself, in this case from up in the Terminal* and friends.
I'm not saying this one is bad or wrong, but an alternate vision I have is that you would register an object with the TextBuffer that contained a pattern, region of interest, and a callback method/event inside of it. The TextBuffer would just... of its own accord as things are written in on the other methods (and maybe with its own internal, private thread or threadpool worker) grind through the region with the pattern and make callbacks as necessary.
Almost like you have an ITextScanner interface with an ITextMatchFound callback interface... which might lend itself toward easy adaptation into a COM/WinRT-based plug-in model for arbitrary buffer scanners in the future.

As Dustin and I are musing about this... your ITextScanner could just also contain ITextEffect on it as an optional in lieu of a callback that is just handed straight into the renderer and now you've also managed to design rendering effect extensions at the same time...

OK we all discussed this with Teams. I'm willing to concede this point because Hyperlinks are so interesting here that they push the boundaries of this sort of unified model. And where the threads live is a bit contentious. And Dustin keeps coming up with more ideas why, while this model sort of works, it has sharp edges. So I'm fine with proceeding per what this draft has as a design.

oss/interval_tree/LICENSE Outdated Show resolved Hide resolved
Copy link
Member

@miniksa miniksa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very close to signoff. Just a few oddball comments.

@DHowett
Copy link
Member

DHowett commented Oct 28, 2020

I edited your PR body down to be a nice commit body :)

@DHowett DHowett changed the title Hyperlink auto-detection Add support for autodetecting URLs and making them links Oct 28, 2020
@DHowett DHowett changed the title Add support for autodetecting URLs and making them links Add support for autodetecting URLs and making hyperlinks Oct 28, 2020
@PankajBhojwani PankajBhojwani added the AutoMerge Marked for automatic merge by the bot when requirements are met label Oct 28, 2020
@ghost
Copy link

ghost commented Oct 28, 2020

Hello @PankajBhojwani!

Because this pull request has the AutoMerge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

@ghost ghost merged commit 2bf5d18 into main Oct 28, 2020
@ghost ghost deleted the dev/pabhoj/auto_link branch October 28, 2020 20:24
@zadjii-msft
Copy link
Member

oh-my-god-its-happening

@comzyh
Copy link
Contributor

comzyh commented Oct 31, 2020

I guess there is something wrong with handling wide characters.
image

ghost pushed a commit that referenced this pull request Nov 3, 2020
… URL detecting (#8124)

Fix #8121
![image](https://user-images.githubusercontent.com/1068203/97811235-2081ca80-1cb4-11eb-82bd-1ddaf15c757c.png)


<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request

When calculating the position of the matched pattern, consider the width of the characters.

However, if there are some wide glyphs in the detected hyperlink(not possible for now, for the existing regex will not match wide-character?). The repeated character in the tooltip is not fixed by this PR.

<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> 
## References

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [ ] Closes #8121
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

When calculating the coordinate of the match in #7691, it simply uses the `prefix.size()` as the total prefix width on the screen.

This PR fixes that behavior.

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Manually Verified
@ghost
Copy link

ghost commented Nov 11, 2020

🎉Windows Terminal Preview v1.5.3142.0 has been released which incorporates this pull request.:tada:

Handy links:

@ghost
Copy link

ghost commented Nov 15, 2020

Scott's wish finally became true: https://youtu.be/veqs2WVou9M?t=797

@xeho91
Copy link

xeho91 commented Nov 15, 2020

I love this feature!

I have a question, would it be possible to make this hovering on the link customizeable? I know it gives an underline effects, but in the scenario where I have all of the links already "underlined", I can't see if I am hovering on a link or not.

The example of custom customization would be to give a background color for the text with link or something similar.

@ghost
Copy link

ghost commented Nov 15, 2020

I guess that would be another issue

@DHowett
Copy link
Member

DHowett commented Nov 15, 2020

@xeho91 today it underlines on hover. Is that not working for you?

@xeho91
Copy link

xeho91 commented Nov 15, 2020

@xeho91 today it underlines on hover. Is that not working for you?

It does. However, in the example when I am using bat to preview my *.md files. It has a syntax which already recognizes and underlines the links in the output. There's a quick preview below.
image

When I am hovering with the cursor, there's no "visual feedback", except this small dialogue box "Ctrl + Click to follow link.".

What I am asking for to give us ability to define the style effect in settings for hovering on links. Like make the background white, and black text. If that's possible, no pressure, I still love this feature. ❤️

@zadjii-msft
Copy link
Member

@xeho91 I've tossed this request into #5001, since this isn't actually the first time this has come up 😉 Thanks!

@joshuabiddle
Copy link

I'd like to use this ability to open an html file stored on a remote computer using the UNC path. I haven't been able to get it to open. Any ideas?

Example: \COMPUTER\UNC\Path\To\File.html

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Extensibility A feature that would ideally be fulfilled by us having an extension model. AutoMerge Marked for automatic merge by the bot when requirements are met Issue-Feature Complex enough to require an in depth planning process and actual budgeted, scheduled work. Product-Terminal The new Windows Terminal.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Design Clickable Links & Link preview feature/extension
9 participants