Skip to content

Commit

Permalink
finish a bunch of TODOs, add some more
Browse files Browse the repository at this point in the history
  • Loading branch information
zadjii-msft committed May 18, 2023
1 parent ca0811e commit 9dbe70a
Showing 1 changed file with 110 additions and 20 deletions.
130 changes: 110 additions & 20 deletions doc/specs/drafts/#5916 - Triggers/#5916 - Triggers.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
---
author: Mike Griese @zadjii-msft
created on: 2022-09-07
last updated: 2023-05-11
last updated: 2023-05-17
issue id: 5916
---

# Triggers and Custom Clickable Links

## Abstract

[comment]: # Outline what this spec describes.
This spec outines a mechanism by which users can define custom actions to run
when a string of text is written to the Terminal. This lets users create
powerful ways of automating their Terminal to match their own workflows. This
same mechanism can be used by third-party applications to customize the way the
terminal control automatically identifies links or other clickable regions of
the buffer, and handle it in their own way.

## Background

### Inspiration

[comment]: # Are there existing precedents for this type of configuration? These may be in the Terminal, or in other applications
Much of this was heavily inspired by the [VsCode "auto replies"], as well as the
[triggers in iTerm2]. VsCode is also working on a draft "[Quick Fix API]", from
which a lot of inspiration was taken as far as crafting the `match` syntax. You
can seen a sample of their syntax
[here](https://github.com/microsoft/vscode/blob/4c6e0b5eee419550e31e386a0a5ca9840ac3280b/extensions/npm/package.json#L342-L354).

### User Stories

Expand All @@ -28,15 +37,26 @@ This is a collection of all the possible issues I found on this topic.
- This is a dupe of some of the above, honestly. Either [#5916] or [#8849]
* [x] [#6969] Let terminal consumers provide click handlers and pattern recognizers for buffer text
* [x] [#11901] IPv6 links can not be Ctrl+Clicked
* [x] Probably don't do this for the alt buffer? Make it per-trigger if they work in the alt buffer?

Not addressed as a part of this spec:

* [ ] [#8294] Add a setting to configure display of auto detected links, normally and on hover
* [ ] Probably don't do this for the alt buffer? Make it per-trigger if they work in the alt buffer?

We'll probably want to come back and seperately spec how users can control the
appearance of both auto-detected clickable text, and links that are manually
emitted to the Terminal (via OSC 8). This may be increasingly relevant, as this
spec will introduce new ways for users to make text clickable.

## Solution Design

To support "triggers", we'll add a new object to the profile settings called
`triggers`. This is an array of objects that describe

[TODO!]: # TODO! this was a draft from a comment. Polish.
1. What string to match on for running the trigger
2. What to do when that match is found.

Example JSON:
Let's start with an example blob of JSON:

```jsonc
"triggers":[
Expand Down Expand Up @@ -76,16 +96,21 @@ Example JSON:
`triggers` is an array of `Trigger` objects, which are a combination of an
`ActionAndArgs`, a `Control.Matcher`, and a `Control.TriggerAction`.

> **Note**
> Interface and other types here are shown in C#, since that's fairly close to
> MIDL3, which would be used for cross-component interfaces.
```c#
runtimeclass Terminal.Settings.Model.Trigger
{
Int32 Id;
String Id;

Control.Matcher Matcher;
Control.TriggerAction ControlAction;

private String _actionJson;
Terminal.Settings.Model.ActionAndArgs ParseMatches(String[] matches);

private String _actionJson;
}
```

Expand All @@ -100,7 +125,8 @@ following properties, which are heavily inspired by the matchers in VsCode.
"offset": 0, // starting how many rows from the bottom
"length": 5, // how many lines to match against
"pattern": " git push --set-upstream origin ([^\\w]*)",
"runOn": "everything|newline|mark"
"runOn": "everything|newline|mark",
"buffer": "main|alt|any"
}
```

Expand All @@ -118,6 +144,10 @@ following properties, which are heavily inspired by the matchers in VsCode.
`autoMarkPrompts`, this includes when the user presses <kbd>enter</kbd>.
This has a much smaller performance impact, assuming the user isn't marking
every line.
* `"buffer"` (_default_: `"any"`): Configure which terminal buffer this trigger runs on.
* `main`: only run in the main buffer (e.g., most shells)
* `alt`: only run in the alternate screen buffer (e.g., `vim`, `tmux`, any full-screen application)
* `any`: Run in either buffer.

`match` also accepts just a single string, to automatically assume default
values for the other properties. For example, the JSON `"match":
Expand Down Expand Up @@ -165,6 +195,7 @@ runtimeclass Terminal.Control.TriggerAction
{
TriggerType Type;
TriggerArgs Args;
internal void Execute(ControlCore core, String[] matches);
}

runtimeclass Terminal.Control.TriggerAndMatch
Expand Down Expand Up @@ -306,7 +337,9 @@ Challenges:

#### Clickable `sendInput`

This is the same idea as above. We want users to be able to magicially turn regions of the buffer into interactive content. When clicking on that content, the text will get written to the input, rather than `ShellExecute`d.
This is the same idea as above. We want users to be able to magicially turn
regions of the buffer into interactive content. When clicking on that content,
the text will get written to the input, rather than `ShellExecute`d.

```jsonc
{
Expand All @@ -316,18 +349,63 @@ This is the same idea as above. We want users to be able to magicially turn regi
},
````


### Disabling triggers
### Layering & Disabling triggers

Three main cases:
* If we define a trigger in `defaults.json`, users should be able to disable it.
* If a user puts a trigger into `profiles.defaults`, but doesn't want it to show up in a specific profile
* If a user puts a trigger into `profiles.defaults`, but doesn't want it to show
up in a specific profile
* If a fragment decides to add a trigger to a specific profile
[TODO!]: # TODO!
We actually _can't_ put triggers into `defaults.json`. For complicated reasons,
we can't have a `profiles.defaults` block in `defaults.json`. This has caused
issues in the past. So there's no way for the Terminal to pre-define triggers
for all profiles in `defaults.json`. We could entertain the idea of a
`defaults.json`-only global `triggers` property, that would work as the
"default" triggers. I don't want to commit to that until we have more use cases
for default triggers than just the URL detection one.
We'll just use `"id"` as a key in a map of triggers. Users can unbind them with
`"id": "Terminal.builtInThing", match:""`. Just like global actions.
`"id": "Terminal.builtInThing", match:""`. Just like global actions. So a user can have:

```json
"profiles": {
"defaults": {
"triggers": [
{
"id": "my winget thing",
"match": "'(.*)' is not recognized as an internal or external command,",
"command": {
"action": "checkWinGet",
"commandline": "${match[1]}"
},
},
]
},
"list": [
{
"name": "my profile",
"commandline": "wsl.exe",
"triggers": [
{ "id": "my winget thing", "match":"" }
]
}
]
}
```

Triggers do not support partial layering. In the previous example, doing something like:

```json
{ "id": "my winget thing", "command": "newTab" }
```

would not have created a trigger with the same regex match to perform a `newTab`
action instead. That json in the profile would be treated as not having a
`match`, and would then "unbind" the action from the defaults.

### Triggers for Terminal Control consumers

Expand All @@ -342,6 +420,8 @@ These are addressed generally by the rest of the spec. They could provide
actions, or similar to the Windows Terminal, handle custom actions on the
control's `CustomAction` event handler.
## Potential Issues
<table>
Expand All @@ -350,6 +430,12 @@ control's `CustomAction` event handler.
[comment]: # Will the proposed change break existing code/behaviors? If so, how, and is the breaking change "worth it"?
How does someone turn off the built-in hyperlink detector? It _can't_ go in `defaults.json@profiles.defailts`

Clickable links, sendInput get the same appearance treatment as auto-detected links (but not as manually emitted ones)



</td></tr>

<tr><td><strong>Accessibility</strong></td><td>
Expand All @@ -368,14 +454,13 @@ control's `CustomAction` event handler.

[comment]: # TODO!

Mildly worried here about the potential for community-driven tasks to have
non-localized descriptions. We may need to accept a `description:{ en-us:"",
pt-br:"", ...}`-style map of language->string descriptions.
</td></tr>

</table>

* Q: What happens if multiple regexes match the same text
- A: We'll apply the regexes in the order they're defined in the JSON.

[comment]: # If there are any other potential issues, make sure to include them here.

## Implementation Plan
Expand All @@ -400,6 +485,8 @@ pt-br:"", ...}`-style map of language->string descriptions.

### Future Considerations

<!-- This was originally in this doc, but I think that should be moved to it's own spec -->
<!--
#### Clickable sendInput
There's already an existing standard for "this text is a hyperlink" - [OSC8].
Expand All @@ -422,7 +509,7 @@ like `echo foo ; rm -rf`.
This seems like something that could get roped in with triggers. The [iTerm2
docs] have a *Make Hyperlink* action, which can be used to turn regex-matched
text into a hyperlink. We could always author our equivalent to allow for *Make
Clickable* with a string of input instead.
Clickable* with a string of input instead. -->

## Resources

Expand Down Expand Up @@ -482,4 +569,7 @@ boundary, like a visual bell or a notification).
[#11901]: https://github.com/microsoft/terminal/issues/11901
[OSC8]: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
[triggers in iTerm2]: https://iterm2.com/documentation-one-page.html#documentation-triggers.html
[iTerm2 docs]: https://iterm2.com/documentation-one-page.html#documentation-triggers.html
[VsCode "auto replies"]: https://code.visualstudio.com/docs/terminal/advanced#_auto-replies
[Quick Fix API]: https://github.com/microsoft/vscode/blob/4c6e0b5eee419550e31e386a0a5ca9840ac3280b/src/vs/workbench/contrib/terminalContrib/quickFix/browser/terminalQuickFixService.ts#L80-L146

1 comment on commit 9dbe70a

@github-actions
Copy link

Choose a reason for hiding this comment

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

@check-spelling-bot Report

🔴 Please review

See the 📜action log for details.

Unrecognized words (13)
bbe
concieved
Coprocess
defailts
encapslates
IMO
magicially
outines
recieve
regexes
reparse
seperately
Sustainability
Previously acknowledged words that are now absent Hirots inthread reingest :arrow_right:
To accept ✔️ these unrecognized words as correct and remove the previously acknowledged and now absent words, run the following commands

... in a clone of the git@github.com:microsoft/terminal.git repository
on the dev/migrie/s/5916-draft branch (ℹ️ how do I use this?):

curl -s -S -L 'https://raw.githubusercontent.com/check-spelling/check-spelling/v0.0.21/apply.pl' |
perl - 'https://github.com/microsoft/terminal/actions/runs/5014087240/attempts/1'
✏️ Contributor please read this

By default the command suggestion will generate a file named based on your commit. That's generally ok as long as you add the file to your commit. Someone can reorganize it later.

⚠️ The command is written for posix shells. If it doesn't work for you, you can manually add (one word per line) / remove items to expect.txt and the excludes.txt files.

If the listed items are:

  • ... misspelled, then please correct them instead of using the command.
  • ... names, please add them to .github/actions/spelling/allow/names.txt.
  • ... APIs, you can add them to a file in .github/actions/spelling/allow/.
  • ... just things you're using, please add them to an appropriate file in .github/actions/spelling/expect/.
  • ... tokens you only need in one place and shouldn't generally be used, you can add an item in an appropriate file in .github/actions/spelling/patterns/.

See the README.md in each directory for more information.

🔬 You can test your commits without appending to a PR by creating a new branch with that extra change and pushing it to your fork. The check-spelling action will run in response to your push -- it doesn't require an open pull request. By using such a branch, you can limit the number of typos your peers see you make. 😉

If the flagged items are 🤯 false positives

If items relate to a ...

  • binary file (or some other file you wouldn't want to check at all).

    Please add a file path to the excludes.txt file matching the containing file.

    File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

    ^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

  • well-formed pattern.

    If you can write a pattern that would match it,
    try adding it to the patterns.txt file.

    Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.

    Note that patterns can't match multiline strings.

Please sign in to comment.