-
Notifications
You must be signed in to change notification settings - Fork 99
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Autocomplete using the Newton parser (#599)
I've reworked the autocomplete parser to more closely match Newton, the Fig-compatible parser I prototyped earlier this year. I was able to move a lot faster by reusing patterns that inshellisense proved out, such as for templates and generators. I also support some features that inshellisense doesn't, like proper combining of Posix-compatible flags, handling of option argument separators, and handling of cursors in insertValues.
- Loading branch information
1 parent
cd15beb
commit 13f4203
Showing
35 changed files
with
2,957 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
.suggestions-view .auxview-content { | ||
display: flex; | ||
flex-direction: column; | ||
min-height: 1em; | ||
.suggestion-item { | ||
white-space: nowrap; | ||
text-overflow: ellipsis; | ||
overflow: hidden; | ||
cursor: pointer; | ||
border-radius: 5px; | ||
|
||
&:hover { | ||
background-color: var(--table-tr-hover-bg-color); | ||
} | ||
|
||
&.is-selected { | ||
font-weight: bold; | ||
color: var(--app-text-primary-color); | ||
background-color: var(--table-tr-selected-bg-color); | ||
&:hover { | ||
background-color: var(--table-tr-selected-hover-bg-color); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { getAll, getFirst } from "@/autocomplete/runtime/utils"; | ||
import { AuxiliaryCmdView } from "./auxview"; | ||
import { clsx } from "clsx"; | ||
import { action } from "mobx"; | ||
import { observer } from "mobx-react"; | ||
import { GlobalModel } from "@/models"; | ||
import React, { useEffect } from "react"; | ||
import { If } from "tsx-control-statements/components"; | ||
|
||
import "./suggestionview.less"; | ||
|
||
export const AutocompleteSuggestionView: React.FC = observer(() => { | ||
const inputModel = GlobalModel.inputModel; | ||
const autocompleteModel = GlobalModel.autocompleteModel; | ||
const selectedSuggestion = autocompleteModel.getPrimarySuggestionIndex(); | ||
|
||
const updateScroll = action((index: number) => { | ||
autocompleteModel.setPrimarySuggestionIndex(index); | ||
const element = document.getElementsByClassName("suggestion-item")[index] as HTMLElement; | ||
if (element) { | ||
element.scrollIntoView({ block: "nearest" }); | ||
} | ||
}); | ||
|
||
const closeView = action(() => { | ||
inputModel.closeAuxView(); | ||
}); | ||
|
||
const setSuggestion = action((idx: number) => { | ||
autocompleteModel.applySuggestion(idx); | ||
autocompleteModel.loadSuggestions(); | ||
closeView(); | ||
}); | ||
|
||
useEffect(() => { | ||
const keybindManager = GlobalModel.keybindManager; | ||
|
||
keybindManager.registerKeybinding("pane", "autocomplete", "generic:confirm", (waveEvent) => { | ||
setSuggestion(selectedSuggestion); | ||
return true; | ||
}); | ||
keybindManager.registerKeybinding("pane", "autocomplete", "generic:cancel", (waveEvent) => { | ||
closeView(); | ||
return true; | ||
}); | ||
keybindManager.registerKeybinding("pane", "autocomplete", "generic:selectAbove", (waveEvent) => { | ||
updateScroll(Math.max(0, selectedSuggestion - 1)); | ||
return true; | ||
}); | ||
keybindManager.registerKeybinding("pane", "autocomplete", "generic:selectBelow", (waveEvent) => { | ||
updateScroll(Math.min(suggestions?.length - 1, selectedSuggestion + 1)); | ||
return true; | ||
}); | ||
keybindManager.registerKeybinding("pane", "autocomplete", "generic:tab", (waveEvent) => { | ||
updateScroll(Math.min(suggestions?.length - 1, selectedSuggestion + 1)); | ||
return true; | ||
}); | ||
|
||
return () => { | ||
GlobalModel.keybindManager.unregisterDomain("autocomplete"); | ||
}; | ||
}); | ||
|
||
const suggestions: Fig.Suggestion[] = autocompleteModel.getSuggestions(); | ||
|
||
return ( | ||
<AuxiliaryCmdView title="Suggestions" className="suggestions-view" onClose={closeView} scrollable={true}> | ||
<If condition={!suggestions || suggestions.length == 0}> | ||
<div className="no-suggestions">No suggestions</div> | ||
</If> | ||
{suggestions?.map((suggestion, idx) => ( | ||
<option | ||
key={getFirst(suggestion.name)} | ||
title={suggestion.description} | ||
className={clsx("suggestion-item", { "is-selected": selectedSuggestion === idx })} | ||
onClick={() => { | ||
setSuggestion(idx); | ||
}} | ||
> | ||
{`${suggestion.icon} ${suggestion.displayName ?? getAll(suggestion.name).join(",")} ${ | ||
suggestion.description ? `- ${suggestion.description}` : "" | ||
}`} | ||
</option> | ||
))} | ||
</AuxiliaryCmdView> | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# Newton autocomplete parser | ||
|
||
Newton is a Fig-compatible autocomplete parser. It builds on a lot of goodness from the [@microsoft/inshellisense project](https://github.com/microsoft/inshellisense), with heavy modifications to minimize recursion and allow for caching of intermediate states. All suggestions, as with inshellisense, come from the [@withfig/autocomplete project](https://github.com/withfig/autocomplete). | ||
|
||
Any exec commands that need to be run are proxied through the Wave backend to ensure no additional permissions are required. | ||
|
||
The following features from Fig's object definitions are not yet supported: | ||
|
||
- Specs | ||
- Versioned specs, such as the `az` CLI | ||
- Custom specs from your filesystem | ||
- Wave's slash commands and bracket syntax | ||
- Slash commands will be added in a future PR, we just need to generate the proper specs for them | ||
- Bracket syntax should not break the parser right now, you just won't get any suggestions when filling out metacommands within brackets | ||
- Suggestions | ||
- Rich icons support and icons served from the filesystem | ||
- `isDangerous` field | ||
- `hidden` field | ||
- `deprecated` field | ||
- `replaceValue` field - this requires a bit more work to properly parse out the text that needs to be replaced. | ||
- `previewComponent` field - this does not appear to be used by any specs right now | ||
- Subcommands | ||
- `cache` field - All script outputs are currently cached for 5 minutes | ||
- Options | ||
- `isPersistent` field - this requires a bit of work to make sure we pass forward the correct options to subcommands | ||
- `isRequired` field - this should prioritize options that are required | ||
- `isRepeatable` field - this should let a flag be repeated a specified number of times before being invalidated and no longer suggested | ||
- `requiresEquals` field - this is deprecated, but some popular specs still use it | ||
- Args | ||
- `suggestCurrentToken` field | ||
- `isDangerous` field | ||
- `isScript` field | ||
- `isModule` field - only Python uses this right now | ||
- `debounce` field | ||
- `default` field | ||
- `parserDirectives.alias` field | ||
- Generators | ||
- `getQueryTerm` field | ||
- `cache` field - All script outputs are currently cached for 5 minutes |
Oops, something went wrong.