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

Completions #34

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
41 changes: 40 additions & 1 deletion pkgs/sass_language_server/lib/src/language_server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,25 @@ class LanguageServer {
);

var serverCapabilities = ServerCapabilities(
completionProvider: CompletionOptions(
resolveProvider: false,
triggerCharacters: [
// For SassDoc annotation completion
"@",
"/",
// For @use completion
'"',
"'",
// For placeholder completion
"%",
// For namespaced completions
".",
// For property values
":",
// For custom properties
"-",
],
),
definitionProvider: Either2.t1(true),
documentHighlightProvider: Either2.t1(true),
documentLinkProvider: DocumentLinkOptions(resolveProvider: false),
Expand Down Expand Up @@ -327,6 +346,26 @@ class LanguageServer {
_connection.peer
.registerMethod('textDocument/documentSymbol', onDocumentSymbol);

_connection.onCompletion((params) async {
try {
var document = _documents.get(params.textDocument.uri);
if (document == null) {
return CompletionList(isIncomplete: true, items: []);
}

var configuration = _getLanguageConfiguration(document);
if (configuration.completion.enabled) {
var result = await _ls.doComplete(document, params.position);
return result;
} else {
return CompletionList(isIncomplete: true, items: []);
}
} on Exception catch (e) {
_log.debug(e.toString());
return CompletionList(isIncomplete: true, items: []);
}
});

_connection.onHover((params) async {
try {
var document = _documents.get(params.textDocument.uri);
Expand All @@ -337,7 +376,7 @@ class LanguageServer {

var configuration = _getLanguageConfiguration(document);
if (configuration.hover.enabled) {
var result = await _ls.hover(document, params.position);
var result = await _ls.doHover(document, params.position);
return result ?? Hover(contents: Either2.t2(""));
} else {
return Hover(contents: Either2.t2(""));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,25 @@ class FeatureConfiguration {
FeatureConfiguration({required this.enabled});
}

enum MixinStyle { all, noBracket, bracket }

class CompletionConfiguration extends FeatureConfiguration {
final bool completePropertyWithSemicolon;
final bool css;
final MixinStyle mixinStyle;
final bool suggestFromUseOnly;
final bool triggerPropertyValueCompletion;

CompletionConfiguration({
required super.enabled,
required this.completePropertyWithSemicolon,
required this.css,
required this.mixinStyle,
required this.suggestFromUseOnly,
required this.triggerPropertyValueCompletion,
});
}

class HoverConfiguration extends FeatureConfiguration {
final bool documentation;
final bool references;
Expand All @@ -16,6 +35,7 @@ class HoverConfiguration extends FeatureConfiguration {
}

class LanguageConfiguration {
late final CompletionConfiguration completion;
late final FeatureConfiguration definition;
late final FeatureConfiguration documentSymbols;
late final FeatureConfiguration documentLinks;
Expand All @@ -28,6 +48,20 @@ class LanguageConfiguration {
late final FeatureConfiguration workspaceSymbols;

LanguageConfiguration.from(dynamic config) {
completion = CompletionConfiguration(
enabled: config?['completion']?['enabled'] as bool? ?? true,
completePropertyWithSemicolon:
config?['completion']?['completePropertyWithSemicolon'] as bool? ??
true,
css: config?['completion']?['css'] as bool? ?? true,
mixinStyle: _toMixinStyle(config?['completion']?['mixinStyle']),
suggestFromUseOnly:
config?['completion']?['suggestFromUseOnly'] as bool? ?? true,
triggerPropertyValueCompletion:
config?['completion']?['triggerPropertyValueCompletion'] as bool? ??
true,
);

definition = FeatureConfiguration(
enabled: config?['definition']?['enabled'] as bool? ?? true);
documentSymbols = FeatureConfiguration(
Expand All @@ -54,4 +88,17 @@ class LanguageConfiguration {
workspaceSymbols = FeatureConfiguration(
enabled: config?['workspaceSymbols']?['enabled'] as bool? ?? true);
}

MixinStyle _toMixinStyle(dynamic style) {
var styleString = style as String? ?? 'all';
switch (styleString) {
case 'nobracket':
return MixinStyle.noBracket;
case 'bracket':
return MixinStyle.bracket;
case 'all':
default:
return MixinStyle.all;
}
}
}
84 changes: 74 additions & 10 deletions pkgs/sass_language_services/lib/src/css/css_property.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import 'package:lsp_server/lsp_server.dart' as lsp;

import '../utils/sass_lsp_utils.dart';
import 'css_value.dart';
import 'entry_status.dart';
import 'reference.dart';

final re = RegExp(r'([A-Z]+)(\d+)?');
const browserNames = {
"E": "Edge",
"FF": "Firefox",
"S": "Safari",
"C": "Chrome",
"IE": "IE",
"O": "Opera",
};

class CssProperty {
final String name;
final String? description;
Expand All @@ -14,14 +27,65 @@ class CssProperty {
final int? relevance;
final String? atRule;

CssProperty(this.name,
{this.description,
this.browsers,
this.restrictions,
this.status,
this.syntax,
this.values,
this.references,
this.relevance,
this.atRule});
CssProperty(
this.name, {
this.description,
this.browsers,
this.restrictions,
this.status,
this.syntax,
this.values,
this.references,
this.relevance,
this.atRule,
});

lsp.Either2<lsp.MarkupContent, String> getPlaintextDescription() {
var browsersString = browsers?.map<String>((b) {
var matches = re.firstMatch(b);
if (matches != null) {
var browser = matches.group(1);
var version = matches.group(2);
return "${browserNames[browser]} $version";
}
return b;
}).join(', ');

var contents = asPlaintext('''
$description

Syntax: $syntax

$browsersString
''');
return contents;
}

lsp.Either2<lsp.MarkupContent, String> getMarkdownDescription() {
var browsersString = browsers?.map<String>((b) {
var matches = re.firstMatch(b);
if (matches != null) {
var browser = matches.group(1);
var version = matches.group(2);
return "${browserNames[browser]} $version";
}
return b;
}).join(', ');

var referencesString = references
?.map<String>((r) => '[${r.name}](${r.uri.toString()})')
.join('\n');

var contents = asMarkdown('''
$description

Syntax: $syntax

$referencesString

$browsersString
'''
.trim());
return contents;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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 '../../configuration/language_configuration.dart';

class CompletionContext {
final lsp.Position position;
final String currentWord;
final String lineBeforePosition;
final int offset;
final lsp.Range defaultReplaceRange;
final TextDocument document;
final sass.Stylesheet stylesheet;
final CompletionConfiguration configuration;

CompletionContext({
required this.offset,
required this.position,
required this.currentWord,
required this.defaultReplaceRange,
required this.document,
required this.stylesheet,
required this.configuration,
required this.lineBeforePosition,
});
}
Loading
Loading