Skip to content

Commit

Permalink
End-to-end test for Go to definition
Browse files Browse the repository at this point in the history
  • Loading branch information
wkillerud committed Nov 17, 2024
1 parent 9716d8f commit 2a3d6ee
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 11 deletions.
3 changes: 3 additions & 0 deletions extension/test/electron/definition/fixtures/_theme.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
%brand
color: purple

5 changes: 5 additions & 0 deletions extension/test/electron/definition/fixtures/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@use 'theme';

.a {
@extend %brand;
}
43 changes: 43 additions & 0 deletions extension/test/electron/definition/go-to-definition.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const assert = require('node:assert');
const path = require('node:path');
const vscode = require('vscode');
const { showFile, sleepCI } = require('../util');

const stylesUri = vscode.Uri.file(
path.resolve(__dirname, 'fixtures', 'styles.scss')
);

before(async () => {
await showFile(stylesUri);
await sleepCI();
});

after(async () => {
await vscode.commands.executeCommand('workbench.action.closeAllEditors');
});

/**
* @param {import('vscode').Uri} documentUri
* @returns {Promise<Array<import('vscode').Location>>}
*/
async function goToDefinition(documentUri, position) {
const result = await vscode.commands.executeCommand(
'vscode.executeDefinitionProvider',
documentUri,
position
);
return result;
}

test('gets document symbols', async () => {
const [result] = await goToDefinition(stylesUri, new vscode.Position(3, 12));

assert.ok(result, 'Should have found the definition for %brand');
assert.match(result.uri.toString(), /_theme\.sass$/);

assert.equal(result.range.start.line, 0);
assert.equal(result.range.start.character, 0);

assert.equal(result.range.end.line, 0);
assert.equal(result.range.end.character, 6);
});
25 changes: 25 additions & 0 deletions extension/test/electron/definition/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const path = require('node:path');
const fs = require('node:fs/promises');
const vscode = require('vscode');
const { runMocha } = require('../mocha');

/**
* @returns {Promise<void>}
*/
async function run() {
const filePaths = [];

const dir = await fs.readdir(__dirname, { withFileTypes: true });
for (let entry of dir) {
if (entry.isFile() && entry.name.endsWith('test.js')) {
filePaths.push(path.join(entry.parentPath, entry.name));
}
}

await runMocha(
filePaths,
vscode.Uri.file(path.resolve(__dirname, 'fixtures', 'styles.scss'))
);
}

module.exports = { run };
26 changes: 26 additions & 0 deletions pkgs/sass_language_server/lib/src/language_server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ class LanguageServer {
clientCapabilities: _clientCapabilities, fs: fileSystemProvider);

var serverCapabilities = ServerCapabilities(
definitionProvider: Either2.t1(true),
documentLinkProvider: DocumentLinkOptions(resolveProvider: false),
documentSymbolProvider: Either2.t1(true),
textDocumentSync: Either2.t1(TextDocumentSyncKind.Incremental),
Expand Down Expand Up @@ -236,6 +237,31 @@ class LanguageServer {
}
});

_connection.onDefinition((params) async {
try {
var document = _documents.get(params.textDocument.uri);
if (document == null) return null;

var configuration = _getLanguageConfiguration(document);
if (configuration.definition.enabled) {
if (initialScan != null) {
await initialScan;
}
var result = await _ls.goToDefinition(document, params.position);
if (result is Location) {
return Either3.t1(result);
} else {
return null;
}
} else {
return null;
}
} on Exception catch (e) {
_log.debug(e.toString());
return null;
}
});

_connection.onDocumentLinks((params) async {
try {
var document = _documents.get(params.textDocument.uri);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ class FeatureConfiguration {
FeatureConfiguration({required this.enabled});
}

class DefinitionConfiguration extends FeatureConfiguration {
DefinitionConfiguration({required super.enabled});
}

class DocumentSymbolsConfiguration extends FeatureConfiguration {
DocumentSymbolsConfiguration({required super.enabled});
}
Expand All @@ -17,11 +21,14 @@ class WorkspaceSymbolsConfiguration extends FeatureConfiguration {
}

class LanguageConfiguration {
late final DefinitionConfiguration definition;
late final DocumentSymbolsConfiguration documentSymbols;
late final DocumentLinksConfiguration documentLinks;
late final WorkspaceSymbolsConfiguration workspaceSymbols;

LanguageConfiguration.from(dynamic config) {
definition = DefinitionConfiguration(
enabled: config?['definition']?['enabled'] as bool? ?? true);
documentSymbols = DocumentSymbolsConfiguration(
enabled: config?['documentSymbols']?['enabled'] as bool? ?? true);
documentLinks = DocumentLinksConfiguration(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,14 +203,12 @@ class ScopeVisitor with sass.RecursiveStatementVisitor {
var scopeStartIndex =
node.span.text.indexOf(openBracketOrNewline, argsEndIndex);

var clauseChildrenLength = clause.children
.map<int>((e) => e.span.context.length)
.reduce((value, element) => value + element);

var toMatch = dialect == Dialect.indented ? '\n' : '}';

var scopeEndIndex = node.span.text
.indexOf(toMatch, scopeStartIndex + clauseChildrenLength);
var lastChildIndex =
node.span.text.indexOf(clause.children.last.span.text);
var scopeEndIndex = node.span.text.indexOf(
toMatch, lastChildIndex + clause.children.last.span.text.length);

previousClause = _addScope(
offset: node.span.start.offset + scopeStartIndex,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@ abstract class LanguageFeature {
return result;
}

result ??= [];

visited.add(currentDocument.uri.toString());

var allLinks = await ls.findDocumentLinks(currentDocument);
Expand All @@ -92,9 +90,10 @@ abstract class LanguageFeature {
});

if (links.isEmpty) {
return result;
return null;
}

var linksResult = <T>[];
for (var link in links) {
if (link.target == null ||
link.target.toString() == currentDocument.uri.toString()) {
Expand Down Expand Up @@ -140,11 +139,11 @@ abstract class LanguageFeature {
);

if (linkResult != null) {
result.addAll(linkResult);
linksResult.addAll(linkResult);
}
}

return result;
return linksResult;
}

Future<TextDocument> getTextDocument(Uri uri) async {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,38 @@ void main() {
expect(fourth.length, equals(24));
});

test('if rule with multiple child nodes', () {
var document = fs.createDocument(r'''
@mixin _single-spacing($spacing-step, $position) {
@if $position and list.index($positions, $position) {
// Add dash before position to ease interpolation
$position: "-#{$position}";
}
@if map.has-key($spacing, $spacing-step) {
margin#{$position}: map.get($spacing, $spacing-step);
} @else {
@error "Could not find \"#{$spacing-step}\" in the list of spacing values";
}
}
''');
var symbols = getSymbols(document);

expect(symbols.globalScope.children, hasLength(1));
expect(symbols.globalScope.children.first.children, hasLength(3));

var [first, second, third] = symbols.globalScope.children.first.children;

expect(first.offset, equals(107));
expect(first.length, equals(101));

expect(second.offset, equals(255));
expect(second.length, equals(69));

expect(third.offset, equals(331));
expect(third.length, equals(91));
});

test('mixin rules', () {
var document = fs.createDocument('''
@mixin large-text {
Expand Down

0 comments on commit 2a3d6ee

Please sign in to comment.