Skip to content

Fix triple slash completions#11328

Merged
aozgaa merged 36 commits into
masterfrom
FixTripleSlashCompletions
Oct 6, 2016
Merged

Fix triple slash completions#11328
aozgaa merged 36 commits into
masterfrom
FixTripleSlashCompletions

Conversation

@aozgaa
Copy link
Copy Markdown
Contributor

@aozgaa aozgaa commented Oct 3, 2016

Fixes a bug where some editors wouldn't offer correct completions for triple-slash-reference-path completions (TSRPC's) and TSRPC's wouldn't appear for users using backslashes in the path (eg: Windows users).

@aozgaa
Copy link
Copy Markdown
Contributor Author

aozgaa commented Oct 3, 2016

Any thoughts, @mhegazy @billti @paulvanbrenk @jramsay ?

Comment thread src/server/lsHost.ts Outdated
readFile(fileName: string): string {
return this.host.readFile(fileName);
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[] {
return this.host.readDirectory(path, exclude, exclude, include);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This doesn't look right. Did you mean to use exclude twice, and not use extensions? If so, add a quick comment to note that it's deliberate.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Changed.

Comment thread src/services/completions.ts Outdated
}
}

result = result.filter(entry => entry.name.indexOf(baseName) >= 0);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this deliberately fuzzy, rather than just "starts with"? i.e. if the user had typed "./dir/ab|" and was getting completions at the "|", then "xxab" would match the filter as well as "abc".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes.

It's worth noting that some editors, eg vscode, appear to perform filtering of results on the client side (haven't found the exact spot in the source where this occurs). I'm not sure what the general expectation from clients is on this front, but if we can quickly tell whether the sub-string occurs or not, I imagine it is more correct and (speculatively) performance is improved by not sending garbage to the client.

Copy link
Copy Markdown
Contributor

@rbuckton rbuckton Oct 4, 2016

Choose a reason for hiding this comment

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

Are there any editors that prefer to show all possible completions to provide context, that this would then restrict?

Could we do this check in advance against foundFileName at line 363 and directoryName at line 380, rather than allocating a number of completion objects that are then thrown out?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've only checked vs and vs code. It appears vs doesn't do any additional filtering, but vs code does (namely, it repeats exactly the same fuzzy matching I've added).

In order to offer a consistent experience, and so typing additional characters refines completions, I added the filtering.

Changed the checking to occur earlier, but I worry slightly that we might be violating DRY.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removing the filtering altogether.

Per our offline conversation, I found that VS and VS Code provide more detailed completions such as camel-case based ones (for VS Code, viewable at src/vs/base/common/filters.ts) and so I'm deferring the work of filtering to the client, as appears to be the norm in the status quo.

Comment thread src/services/completions.ts Outdated
return undefined;
return {
isMemberCompletion: false,
isNewIdentifierLocation: false,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why is "isNewIdentifierLocation" true if there are results, but false if not? What difference does this make? (Leave a comment to explain if there's a reason for it).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The flag should be true in both cases.

isNewIdentifierLocation is used to tell the editor that the user may be typing in an identifier that doesn't yet exist anywhere in the language service's context. So if you are typing in a new variable, eg var fo| (cursor at |), the LS has no idea how you might finish the statement.

Editors use this to change their behavior in terms of how they encourage you to choose a completion or not. In VS, for example, the behavior of pressing Enter changes depending on whether the flag is set (if true, pressing enter inserts a newline and doesn't take a highlighted completion. If false, pressing enter inserts the selected completion. Behavior when pressing Tab is unaffected by the flag -- the completion is always inserted).

In our case, someone writing a triple slash reference path may want to point to a file that doesn't yet exist, so we should allow them to create what is potentially a "new identifier" in this case.

I've refactored the code to reflect this observation, and added a comment.

verify.completionListContains("f7");
verify.completionListContains("d1");
verify.completionListContains("d2");
verify.not.completionListItemsCountIsGreaterThan(6);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Isn't there just a "verify it is equal to 6" check? You already checked for 6 entries above, so... :-)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The interface (viewable in stc/fourslash/fourslash.ts) doesn't contain such a method, but I can add it if you think it's a good idea. If so, should I do that in a separate PR?

@@ -0,0 +1,31 @@
/// <reference path='fourslash.ts' />

// Should give completions for relative references to ts files when allowJs is false
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see lots of tests where allowJs is false. Is there sufficient coverage for checking that when it's true the .js[x] files do appear in references and imports?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

For references, we have:

  • tripleSlashRefPathCompletionAllowJSFalse.ts
  • tripleSlashRefPathCompletionAllowJSTrue.ts

For imports, we have:

  • completionForStringLiteralRelativeImportAllowJSFalse.ts
  • completionForStringLiteralRelativeImportAllowJSTrue.ts

(latter two renamed in the latest commit).

Comment thread src/services/completions.ts Outdated
}
}

result = result.filter(entry => entry.name.indexOf(baseName) >= 0);
Copy link
Copy Markdown
Contributor

@rbuckton rbuckton Oct 4, 2016

Choose a reason for hiding this comment

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

Are there any editors that prefer to show all possible completions to provide context, that this would then restrict?

Could we do this check in advance against foundFileName at line 363 and directoryName at line 380, rather than allocating a number of completion objects that are then thrown out?

fragment = ensureTrailingDirectorySeparator(fragment);

if (fragment === "") {
fragment = "." + directorySeparator;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Isn't this doing the same thing as line 330?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This function really should never get undefined as an argument for fragment, but I don't know of a way to assert that. So the check on line 330 is really a matter of null-checking. In particular, normalizeSlashes() on line 332 dereferences its argument without null-checking.

Regarding line 340, consider the case when fragment is "foo". Then getDirectoryPath(fragment) === "" because it removes the basename part of the path. So we need to check again.

Really, fragment no longer refers to a path fragment after the assignment on line 337. Perhaps a new variable called relativeOrAbsolutePath should be initialized on the LHS of line 337. I didn't make the change because I was trying to minimize the changes I was making to the codebase to get a fix in (with mixed success).

Should I add a new declaration?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No, the comment was specifically about the fact that line 330 uses "./" while line 340 uses "." + directorySeparator", though they do the same thing. Perhaps you should initialize fragment to "" on 330 rather than repeat yourself on 340.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Changed.

@aozgaa aozgaa merged commit 94d8955 into master Oct 6, 2016
@aozgaa aozgaa deleted the FixTripleSlashCompletions branch February 3, 2017 23:23
@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants