Skip to content
This repository has been archived by the owner on Feb 25, 2025. It is now read-only.

Commit

Permalink
Version 2.12.0-113.0.dev
Browse files Browse the repository at this point in the history
Merge commit 'd86f0e2836d0941776f911dfc86ff444121fd29d' into 'dev'
  • Loading branch information
Dart CI committed Dec 3, 2020
2 parents a37a4d4 + d86f0e2 commit 2c74e62
Show file tree
Hide file tree
Showing 63 changed files with 1,428 additions and 347 deletions.
7 changes: 6 additions & 1 deletion pkg/analysis_server/doc/api.html
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
<body>
<h1>Analysis Server API Specification</h1>
<h1 style="color:#999999">Version
1.32.0
1.32.1
</h1>
<p>
This document contains a specification of the API provided by the
Expand Down Expand Up @@ -235,6 +235,11 @@ <h3>Enumerations</h3>
the server so clients should ensure unknown values are handled gracefully, either
ignoring the item or treating it with some default/fallback handling.
</p>
<h3>Changelog</h3>
<h4>1.32.1</h4>
<ul>
<li>Added <tt>CompletionSuggestionKind.PACKAGE_NAME</tt> for Pub package name completions in <tt>pubspec.yaml</tt></li>
</ul>
<h3>Domains</h3>
<p>
For convenience, the API is divided into domains. Each domain is specified
Expand Down
2 changes: 1 addition & 1 deletion pkg/analysis_server/lib/protocol/protocol_constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// To regenerate the file, use the script
// "pkg/analysis_server/tool/spec/generate_files".

const String PROTOCOL_VERSION = '1.32.0';
const String PROTOCOL_VERSION = '1.32.1';

const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
Expand Down
18 changes: 14 additions & 4 deletions pkg/analysis_server/lib/src/lsp/mapping.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,22 @@ String buildSnippetStringWithTabStops(
RegExp(r'[$}\\]'), // Replace any of $ } \
(c) => '\\${c[0]}', // Prefix with a backslash
);

// Snippets syntax is documented in the LSP spec:
// https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#snippet-syntax
// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#snippet_syntax
//
// $1, $2, etc. are used for tab stops and ${1:foo} inserts a placeholder of foo.

final output = [];
var offset = 0;
var tabStopNumber = 1;

// When there's only a single tabstop, it should be ${0} as this is treated
// specially as the final cursor position (if we use 1, the editor will insert
// a 0 at the end of the string which is not what we expect).
// When there are multiple, start with ${1} since these are placeholders the
// user can tab through and the editor-inserted ${0} at the end is expected.
var tabStopNumber = offsetLengthPairs.length <= 2 ? 0 : 1;

for (var i = 0; i < offsetLengthPairs.length; i += 2) {
final pairOffset = offsetLengthPairs[i];
final pairLength = offsetLengthPairs[i + 1];
Expand Down Expand Up @@ -852,9 +860,11 @@ lsp.CompletionItem toCompletionItem(
suggestion.defaultArgumentListString,
suggestion.defaultArgumentListTextRanges,
)
: '\${1:}'; // No required params still gets a tabstop in the parens.
: '\${0:}'; // No required params still gets a tabstop in the parens.
insertText += '($functionCallSuffix)';
} else if (suggestion.selectionOffset != 0) {
} else if (suggestion.selectionOffset != 0 &&
// We don't need a tabstop if the selection is the end of the string.
suggestion.selectionOffset != suggestion.completion.length) {
insertTextFormat = lsp.InsertTextFormat.Snippet;
insertText = buildSnippetStringWithTabStops(
suggestion.completion,
Expand Down
48 changes: 40 additions & 8 deletions pkg/analysis_server/test/lsp/completion_dart_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ main() {
final item = res.singleWhere((c) => c.label == 'myFunction(…)');
// With no required params, there should still be parens and a tabstop inside.
expect(item.insertTextFormat, equals(InsertTextFormat.Snippet));
expect(item.insertText, equals(r'myFunction(${1:})'));
expect(item.insertText, equals(r'myFunction(${0:})'));
expect(item.textEdit.newText, equals(item.insertText));
expect(
item.textEdit.range,
Expand All @@ -170,10 +170,10 @@ main() {
await openFile(mainFileUri, withoutMarkers(content));
final res = await getCompletion(mainFileUri, positionFromMarker(content));
final item = res.singleWhere((c) => c.label == 'min(…)');
// Ensure the snippet does not include the parens/args as it doesn't
// make sense in the show clause. There will still be a trailing tabstop.
expect(item.insertTextFormat, equals(InsertTextFormat.Snippet));
expect(item.insertText, equals(r'min${1:}'));
// The insert text should be a simple string with no parens/args and
// no need for snippets.
expect(item.insertTextFormat, isNull);
expect(item.insertText, equals(r'min'));
expect(item.textEdit.newText, equals(item.insertText));
}

Expand Down Expand Up @@ -540,13 +540,45 @@ main() {
expect(updated, contains('one: '));
}

Future<void> test_namedArg_snippetStringSelection() async {
Future<void> test_namedArg_snippetStringSelection_endOfString() async {
final content = '''
class A { const A({int one}); }
@A(^)
main() { }
''';

await initialize(
textDocumentCapabilities: withCompletionItemSnippetSupport(
emptyTextDocumentClientCapabilities));
await openFile(mainFileUri, withoutMarkers(content));
final res = await getCompletion(mainFileUri, positionFromMarker(content));
expect(res.any((c) => c.label == 'one: '), isTrue);
final item = res.singleWhere((c) => c.label == 'one: ');
// As the selection is the end of the string, there's no need for a snippet
// here. Since the insert text is also the same as the label, it does not
// need to be provided.
expect(item.insertTextFormat, isNull);
expect(item.insertText, isNull);
expect(item.textEdit.newText, equals('one: '));
expect(
item.textEdit.range,
equals(Range(
start: positionFromMarker(content),
end: positionFromMarker(content))),
);
}

Future<void>
test_namedArgTrailing_snippetStringSelection_insideString() async {
final content = '''
main({int one, int two}) {
main(
^
two: 2,
);
}
''';

await initialize(
textDocumentCapabilities: withCompletionItemSnippetSupport(
emptyTextDocumentClientCapabilities));
Expand All @@ -557,8 +589,8 @@ main() {
// Ensure the snippet comes through in the expected format with the expected
// placeholder.
expect(item.insertTextFormat, equals(InsertTextFormat.Snippet));
expect(item.insertText, equals(r'one: ${1:}'));
expect(item.textEdit.newText, equals(r'one: ${1:}'));
expect(item.insertText, equals(r'one: ${0:},'));
expect(item.textEdit.newText, equals(r'one: ${0:},'));
expect(
item.textEdit.range,
equals(Range(
Expand Down
8 changes: 4 additions & 4 deletions pkg/analysis_server/test/lsp/mapping_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class MappingTest extends AbstractLspAnalysisServerTest {

Future<void> test_tabStopsInSnippets_contains() async {
var result = lsp.buildSnippetStringWithTabStops('a, b, c', [3, 1]);
expect(result, equals(r'a, ${1:b}, c'));
expect(result, equals(r'a, ${0:b}, c'));
}

Future<void> test_tabStopsInSnippets_empty() async {
Expand All @@ -86,13 +86,13 @@ class MappingTest extends AbstractLspAnalysisServerTest {

Future<void> test_tabStopsInSnippets_endsWith() async {
var result = lsp.buildSnippetStringWithTabStops('a, b', [3, 1]);
expect(result, equals(r'a, ${1:b}'));
expect(result, equals(r'a, ${0:b}'));
}

Future<void> test_tabStopsInSnippets_escape() async {
var result = lsp.buildSnippetStringWithTabStops(
r'te$tstri}ng, te$tstri}ng, te$tstri}ng', [13, 11]);
expect(result, equals(r'te\$tstri\}ng, ${1:te\$tstri\}ng}, te\$tstri\}ng'));
expect(result, equals(r'te\$tstri\}ng, ${0:te\$tstri\}ng}, te\$tstri\}ng'));
}

Future<void> test_tabStopsInSnippets_multiple() async {
Expand All @@ -103,6 +103,6 @@ class MappingTest extends AbstractLspAnalysisServerTest {

Future<void> test_tabStopsInSnippets_startsWith() async {
var result = lsp.buildSnippetStringWithTabStops('a, b', [0, 1]);
expect(result, equals(r'${1:a}, b'));
expect(result, equals(r'${0:a}, b'));
}
}
Loading

0 comments on commit 2c74e62

Please sign in to comment.