Skip to content
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

Highlights #29

Merged
merged 8 commits into from
Nov 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -224,14 +224,14 @@
"order": 60,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable folding ranges."
},
"sass.scss.highlights.enabled": {
"order": 70,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable highlights."
},
"sass.scss.hover.enabled": {
Expand All @@ -245,7 +245,7 @@
"order": 81,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Show property and value documentation in CSS hovers."
},
"sass.scss.hover.references": {
Expand Down Expand Up @@ -280,7 +280,7 @@
"order": 120,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable selection ranges."
},
"sass.scss.signatureHelp.enabled": {
Expand Down Expand Up @@ -471,21 +471,21 @@
"order": 10,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable all code actions."
},
"sass.css.colors.enabled": {
"order": 20,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable all color decorators."
},
"sass.css.completion.enabled": {
"order": 30,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable all completions (IntelliSense)."
},
"sass.css.completion.triggerPropertyValueCompletion": {
Expand All @@ -506,14 +506,14 @@
"order": 40,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable Go to Definition."
},
"sass.css.diagnostics.enabled": {
"order": 50,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable all diagnostics."
},
"sass.css.documentSymbols.enabled": {
Expand All @@ -527,21 +527,21 @@
"order": 60,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable folding ranges."
},
"sass.css.highlights.enabled": {
"order": 70,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable highlights."
},
"sass.css.hover.enabled": {
"order": 80,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable all hover information."
},
"sass.css.hover.documentation": {
Expand All @@ -562,42 +562,42 @@
"order": 90,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable the link provider that lets you click an import and open the file."
},
"sass.css.references.enabled": {
"order": 100,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable Find all references."
},
"sass.css.rename.enabled": {
"order": 110,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable Rename."
},
"sass.css.selectionRanges.enabled": {
"order": 120,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable selection ranges."
},
"sass.css.signatureHelp.enabled": {
"order": 130,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable signature help."
},
"sass.css.workspaceSymbols.enabled": {
"order": 140,
"type": "boolean",
"scope": "resource",
"default": false,
"default": true,
"description": "Enable or disable workspace symbols."
}
}
Expand Down
52 changes: 52 additions & 0 deletions extension/test/electron/definition/document-highlights.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
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').DocumentHighlight>>}
*/
async function getHighlights(documentUri, position) {
const result = await vscode.commands.executeCommand(
'vscode.executeDocumentHighlights',
documentUri,
position
);
return result;
}

test('gets document highlights', async () => {
const [first, second] = await getHighlights(
stylesUri,
new vscode.Position(7, 5)
);

assert.ok(first, 'Should have found highlights');
assert.ok(second, 'Should have found two highlights');

assert.equal(first.range.start.line, 7);
assert.equal(first.range.start.character, 2);

assert.equal(first.range.end.line, 7);
assert.equal(first.range.end.character, 14);

assert.equal(second.range.start.line, 11);
assert.equal(second.range.start.character, 13);

assert.equal(second.range.end.line, 11);
assert.equal(second.range.end.character, 25);
});
8 changes: 8 additions & 0 deletions extension/test/electron/definition/fixtures/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,11 @@
.a {
@extend %brand;
}

:root {
--color-text: #000;
}

body {
color: var(--color-text);
}
23 changes: 23 additions & 0 deletions pkgs/sass_language_server/lib/src/language_server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ class LanguageServer {

var serverCapabilities = ServerCapabilities(
definitionProvider: Either2.t1(true),
documentHighlightProvider: Either2.t1(true),
documentLinkProvider: DocumentLinkOptions(resolveProvider: false),
documentSymbolProvider: Either2.t1(true),
referencesProvider: Either2.t1(true),
Expand Down Expand Up @@ -265,6 +266,28 @@ class LanguageServer {
}
});

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

var configuration = _getLanguageConfiguration(document);
if (configuration.highlights.enabled) {
if (initialScan != null) {
await initialScan;
}

var result = _ls.findDocumentHighlights(document, params.position);
return result;
} else {
return [];
}
} on Exception catch (e) {
_log.debug(e.toString());
return [];
}
});

_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,43 +4,26 @@ class FeatureConfiguration {
FeatureConfiguration({required this.enabled});
}

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

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

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

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

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

class LanguageConfiguration {
late final DefinitionConfiguration definition;
late final DocumentSymbolsConfiguration documentSymbols;
late final DocumentLinksConfiguration documentLinks;
late final ReferencesConfiguration references;
late final WorkspaceSymbolsConfiguration workspaceSymbols;
late final FeatureConfiguration definition;
late final FeatureConfiguration highlights;
late final FeatureConfiguration documentSymbols;
late final FeatureConfiguration documentLinks;
late final FeatureConfiguration references;
late final FeatureConfiguration workspaceSymbols;

LanguageConfiguration.from(dynamic config) {
definition = DefinitionConfiguration(
definition = FeatureConfiguration(
enabled: config?['definition']?['enabled'] as bool? ?? true);
documentSymbols = DocumentSymbolsConfiguration(
documentSymbols = FeatureConfiguration(
enabled: config?['documentSymbols']?['enabled'] as bool? ?? true);
documentLinks = DocumentLinksConfiguration(
documentLinks = FeatureConfiguration(
enabled: config?['documentLinks']?['enabled'] as bool? ?? true);
references = ReferencesConfiguration(
highlights = FeatureConfiguration(
enabled: config?['highlights']?['enabled'] as bool? ?? true);
references = FeatureConfiguration(
enabled: config?['references']?['enabled'] as bool? ?? true);
workspaceSymbols = WorkspaceSymbolsConfiguration(
workspaceSymbols = FeatureConfiguration(
enabled: config?['workspaceSymbols']?['enabled'] as bool? ?? true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import 'package:lsp_server/lsp_server.dart' as lsp;
import 'package:sass_api/sass_api.dart' as sass;
import 'package:sass_language_services/sass_language_services.dart';
import 'package:sass_language_services/src/features/find_references/find_references_visitor.dart';

import '../go_to_definition/scope_visitor.dart';
import '../go_to_definition/scoped_symbols.dart';
import '../language_feature.dart';
import '../node_at_offset_visitor.dart';

class DocumentHighlightsFeature extends LanguageFeature {
DocumentHighlightsFeature({required super.ls});

List<lsp.DocumentHighlight> findDocumentHighlights(
TextDocument document, lsp.Position position) {
var stylesheet = ls.parseStylesheet(document);

// Find the node whose definition we're looking for.
var offset = document.offsetAt(position);
var node = getNodeAtOffset(stylesheet, offset);
if (node == null || node is sass.Stylesheet) {
return [];
}

var name = getNodeName(node);
if (name == null) {
return [];
}
var kind = getNodeReferenceKind(node);

var symbols = ls.cache.getDocumentSymbols(document) ??
ScopedSymbols(
stylesheet,
document.languageId == 'sass' ? Dialect.indented : Dialect.scss,
);
ls.cache.setDocumentSymbols(document, symbols);

var symbol = symbols.findSymbolFromNode(node);

var result = <lsp.DocumentHighlight>[];
var visitor = FindReferencesVisitor(
document,
name,
includeDeclaration: true,
);

stylesheet.accept(visitor);

for (var reference in visitor.candidates) {
if (symbol != null) {
if (symbols.matchesSymbol(
reference,
document.offsetAt(reference.location.range.start),
symbol,
)) {
result.add(
lsp.DocumentHighlight(range: reference.location.range),
);
}
} else if (kind != null &&
reference.kind == kind &&
reference.name == name) {
result.add(
lsp.DocumentHighlight(range: reference.location.range),
);
}
}

return result;
}
}
Loading