-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Resolve module specifiers for auto imports in completion list (in incomplete chunks) #44713
Resolve module specifiers for auto imports in completion list (in incomplete chunks) #44713
Conversation
…up front, pull as many as we want from cache
Thanks for the PR! It looks like you've changed the TSServer protocol in some way. Please ensure that any changes here don't break consumers of the current TSServer API. For some extra review, we'll ping @sheetalkamat, @amcasey, @mjbvz, @minestarks for you. Feel free to loop in other consumers/maintainers if necessary |
} | ||
return wrapped; | ||
|
||
function replaceTransientSymbols(info: SymbolExportInfo, checker: TypeChecker) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Transient symbols should never have been in this cache, but this isn’t new, it’s just moved and renamed. I’m working on a follow-up to restructure this cache to be safer and less kludgy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good based on my understanding -- thanks for walking through the code with me.
let computedWithoutCacheCount = 0; | ||
const fixes = flatMap(moduleSymbols, exportInfo => { | ||
const { computedWithoutCache, moduleSpecifiers } = getModuleSpecifiers(exportInfo.moduleSymbol); | ||
computedWithoutCacheCount += Number(computedWithoutCache); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Boolean -> Number is a liiitle too clever for my taste (but might be great in practice I don't know)
if (strChar === testChar || strChar === toUpperCharCode(testChar)) { | ||
matchedFirstCharacter ||= | ||
prevChar === undefined || // Beginning of word | ||
CharacterCodes.a <= prevChar && prevChar <= CharacterCodes.z && CharacterCodes.A <= strChar && strChar <= CharacterCodes.Z || // camelCase transition |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
future work: maybe use general unicode categories to detect lower -> uppercase transition
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems important, e.g. for languages with accents (I assume languages without lettercase use snake case?).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The protocol change LGTM and the explanation makes sense.
* | ||
* True: | ||
* 'state' in 'useState' | ||
* 'sae' in 'useState' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could have been "sate". 😛
if (strChar === testChar || strChar === toUpperCharCode(testChar)) { | ||
matchedFirstCharacter ||= | ||
prevChar === undefined || // Beginning of word | ||
CharacterCodes.a <= prevChar && prevChar <= CharacterCodes.z && CharacterCodes.A <= strChar && strChar <= CharacterCodes.Z || // camelCase transition |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems important, e.g. for languages with accents (I assume languages without lettercase use snake case?).
return false; | ||
} | ||
|
||
function toUpperCharCode(charCode: number) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we usually use toLower, though I don't know whether that was to improve the behavior.
Fixes #42005
Summary
Screen capture 🎥
You can see a smattering of fully resolved module specifiers in the initial list here, but some, like
changeDepenciesStateTo0
still saynode_modules
. But once I’ve type enough characters to find it without scrolling, its label has updated to be its full module specifier.Kapture.2021-06-24.at.10.41.26.mp4
It occurred to me while making this recording that it would probably be better to try resolving module specifiers in alphabetical order (instead of module traversal order), so all the resolved ones would be more toward the top of the list. However, this may not matter as much as it feels like it would since VS Code by default snaps you to names you recently completed elsewhere. So in the real world, you might be snapped to an essentially random spot in the list instead of near the top, depending on your settings. But I’ll think about whether the order can be smarter in some way as a future optimization.
Significant related changes
Ambient modules don’t count against the resolution limit—they always get fully resolved in the first go now, because they’re very cheap to resolve and we notice that they’re ambient while putting them in the export map cache. This applies even to older clients who otherwise can’t use this feature because they don’t signal that they can support incomplete responses/retriggerings.
As part of the way we can keep the performance cost of this down, the fuzzy matching logic for auto imports has changed from “the symbol name contains the typed characters, in order, anywhere in it” to a slightly more restrictive version, akin to what was used for import statement completions in Import statement completions #43149. I can’t do better to explain it than I did in the doc comment:
Performance measurements
In a test project containing lots of expensive dependencies (especially
aws-sdk
):I’m not thrilled with 136 → 220 for the cached scenario, but that number is only so low in the first place because of cache improvements that have been made over the last year or two, and it’s still low in absolute terms for a completion list that large. I plan to continue optimizations here as needed, but I’m ok with these numbers considering the value added.