diff --git a/docs/Settings.md b/docs/Settings.md index 6e7144a2..6217babc 100644 --- a/docs/Settings.md +++ b/docs/Settings.md @@ -11,15 +11,52 @@ found [here][3]. ## Disable Code Lens -If you don't want to see the code lenses you can turn it of with the following +If you don't want to see the code lenses you can turn it off with the following property: ```json { - "code-lens-enabled" : "off" + "code-lenses" : "off" } ``` +## Feature Toggles + +Individual language server features can be enabled or disabled. All features +default to `"on"`. + +```json +{ + "code-lenses": "off", + "semantic-tokens": "off", + "validation": "off", + "formatting": "off", + "code-actions": "off", + "completion": "off", + "hover": "off", + "definition": "off", + "references": "off", + "document-symbols": "off", + "document-highlight": "off", + "rename": "off" +} +``` + +| Setting | Description | +|---|---| +| `code-lenses` | Code lens references | +| `semantic-tokens` | Semantic token highlighting | +| `validation` | Validation diagnostics | +| `formatting` | Document formatting | +| `code-actions` | Code actions (quick fixes) | +| `completion` | Auto-completion | +| `hover` | Hover information | +| `definition` | Go to definition | +| `references` | Find references | +| `document-symbols` | Document symbols (outline) | +| `document-highlight` | Highlight occurrences | +| `rename` | Symbol renaming | + ## Excluded Paths Many IDEs and tools copy YANG files into another folder within the same diff --git a/schema/yang-lsp-settings-schema.json b/schema/yang-lsp-settings-schema.json index 8c7b73e8..a31c859a 100644 --- a/schema/yang-lsp-settings-schema.json +++ b/schema/yang-lsp-settings-schema.json @@ -6,8 +6,96 @@ "markdownDescription": "See [documentation](https://github.com/TypeFox/yang-lsp/blob/master/docs/Settings.md)", "type": "object", "properties": { - "code-lens-enabled": { - "description": "If you don't want to see the code lenses you can turn it off.", + "code-lenses": { + "description": "Enable or disable code lens references.", + "enum": [ + "off", + "on" + ], + "default": "on" + }, + "semantic-tokens": { + "description": "Enable or disable semantic token highlighting.", + "enum": [ + "off", + "on" + ], + "default": "on" + }, + "validation": { + "description": "Enable or disable YANG validation diagnostics.", + "enum": [ + "off", + "on" + ], + "default": "on" + }, + "formatting": { + "description": "Enable or disable document formatting.", + "enum": [ + "off", + "on" + ], + "default": "on" + }, + "code-actions": { + "description": "Enable or disable code actions (quick fixes).", + "enum": [ + "off", + "on" + ], + "default": "on" + }, + "completion": { + "description": "Enable or disable auto-completion.", + "enum": [ + "off", + "on" + ], + "default": "on" + }, + "hover": { + "description": "Enable or disable hover information.", + "enum": [ + "off", + "on" + ], + "default": "on" + }, + "references": { + "description": "Enable or disable find references.", + "enum": [ + "off", + "on" + ], + "default": "on" + }, + "document-symbols": { + "description": "Enable or disable document symbols (outline).", + "enum": [ + "off", + "on" + ], + "default": "on" + }, + "rename": { + "description": "Enable or disable symbol renaming.", + "enum": [ + "off", + "on" + ], + "default": "on" + }, + "definition": { + "description": "Enable or disable go to definition.", + "enum": [ + "off", + "on" + ], + "default": "on" + }, + "document-highlight": { + "description": "Enable or disable document highlight (highlight occurrences).", "enum": [ "off", "on" diff --git a/yang-lsp/io.typefox.yang.diagram/src/main/java/io/typefox/yang/diagram/YangSyncDiagramLanguageServer.java b/yang-lsp/io.typefox.yang.diagram/src/main/java/io/typefox/yang/diagram/YangSyncDiagramLanguageServer.java index f7c6fd04..5b22bb37 100644 --- a/yang-lsp/io.typefox.yang.diagram/src/main/java/io/typefox/yang/diagram/YangSyncDiagramLanguageServer.java +++ b/yang-lsp/io.typefox.yang.diagram/src/main/java/io/typefox/yang/diagram/YangSyncDiagramLanguageServer.java @@ -1,17 +1,41 @@ package io.typefox.yang.diagram; import java.util.Collections; +import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.log4j.Logger; import org.eclipse.emf.common.util.URI; +import org.eclipse.lsp4j.CodeAction; +import org.eclipse.lsp4j.CodeActionParams; +import org.eclipse.lsp4j.Command; +import org.eclipse.lsp4j.CompletionItem; +import org.eclipse.lsp4j.CompletionList; +import org.eclipse.lsp4j.CompletionParams; +import org.eclipse.lsp4j.DefinitionParams; +import org.eclipse.lsp4j.DocumentFormattingParams; +import org.eclipse.lsp4j.DocumentHighlight; +import org.eclipse.lsp4j.DocumentHighlightParams; +import org.eclipse.lsp4j.DocumentSymbol; +import org.eclipse.lsp4j.DocumentSymbolParams; +import org.eclipse.lsp4j.Hover; +import org.eclipse.lsp4j.HoverParams; import org.eclipse.lsp4j.InitializeParams; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.LocationLink; +import org.eclipse.lsp4j.ReferenceParams; +import org.eclipse.lsp4j.RenameParams; import org.eclipse.lsp4j.SemanticTokens; import org.eclipse.lsp4j.SemanticTokensParams; import org.eclipse.lsp4j.ServerCapabilities; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.TextEdit; +import org.eclipse.lsp4j.WorkspaceEdit; +import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.sprotty.xtext.ls.SyncDiagramLanguageServer; import org.eclipse.xtext.ide.editor.syntaxcoloring.ISemanticHighlightingCalculator; import org.eclipse.xtext.ide.server.Document; +import org.eclipse.xtext.preferences.PreferenceKey; import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.util.CancelIndicator; @@ -19,17 +43,34 @@ import io.typefox.yang.ide.editor.syntaxcoloring.YangSemanticTokensProvider; import io.typefox.yang.ide.server.YangAdditionalServerCapabilities; +import io.typefox.yang.ide.server.YangFeatureToggleKeys; +import io.typefox.yang.settings.PreferenceValuesProvider; public class YangSyncDiagramLanguageServer extends SyncDiagramLanguageServer { private static final Logger LOG = Logger.getLogger(YangSyncDiagramLanguageServer.class); private static final SemanticTokens EMPTY_SEMANTIC_TOKENS = new SemanticTokens(Collections.emptyList()); + public static final PreferenceKey SEMANTIC_TOKENS_ENABLED = new PreferenceKey("semantic-tokens", "on"); @Inject YangAdditionalServerCapabilities serverAdditions; @Inject YangSemanticTokensProvider semantikTokens; + @Inject + PreferenceValuesProvider preferenceProvider; + + private boolean isEnabled(URI uri, PreferenceKey key) { + if (uri == null || !uri.isFile()) { + return true; + } + try { + return "on".equals(getWorkspaceManager().doRead(uri, (doc, resource) -> + preferenceProvider.getPreferenceValues(resource).getPreference(key))); + } catch (Exception e) { + return true; + } + } @Override protected ServerCapabilities createServerCapabilities(InitializeParams params) { @@ -46,13 +87,88 @@ private SemanticTokens semanticTokensCompute(SemanticTokensParams params, Cancel URI uri = getURI(params.getTextDocument()); ISemanticHighlightingCalculator highlightingCalculator = getService(uri, ISemanticHighlightingCalculator.class); if (highlightingCalculator == null) { - LOG.error("Semantic Highlighting Calculator service is not registered for URI: " +uri.toString()); return EMPTY_SEMANTIC_TOKENS; } return getWorkspaceManager().doRead(uri, (final Document doc, final XtextResource resource) -> { + String enabled = preferenceProvider.getPreferenceValues(resource).getPreference(SEMANTIC_TOKENS_ENABLED); + if (!"on".equals(enabled)) { + return EMPTY_SEMANTIC_TOKENS; + } return semantikTokens.highlightedPositionsToSemanticTokens(doc, resource, highlightingCalculator, cancelIndicator); }); } + @Override + protected Either, CompletionList> completion(CancelIndicator cancelIndicator, CompletionParams params) { + if (!isEnabled(getURI(params), YangFeatureToggleKeys.COMPLETION)) { + return Either.forRight(new CompletionList(Collections.emptyList())); + } + return super.completion(cancelIndicator, params); + } + + @Override + protected Hover hover(HoverParams params, CancelIndicator cancelIndicator) { + if (!isEnabled(getURI(params), YangFeatureToggleKeys.HOVER)) { + return new Hover(); + } + return super.hover(params, cancelIndicator); + } + + @Override + protected Either, List> definition(DefinitionParams params, CancelIndicator cancelIndicator) { + if (!isEnabled(getURI(params), YangFeatureToggleKeys.DEFINITION)) { + return Either.forLeft(Collections.emptyList()); + } + return super.definition(params, cancelIndicator); + } + + @Override + protected List references(ReferenceParams params, CancelIndicator cancelIndicator) { + if (!isEnabled(getURI(params), YangFeatureToggleKeys.REFERENCES)) { + return Collections.emptyList(); + } + return super.references(params, cancelIndicator); + } + + @Override + protected List> documentSymbol(DocumentSymbolParams params, CancelIndicator cancelIndicator) { + if (!isEnabled(getURI(params.getTextDocument()), YangFeatureToggleKeys.DOCUMENT_SYMBOLS)) { + return Collections.emptyList(); + } + return super.documentSymbol(params, cancelIndicator); + } + + @Override + protected List documentHighlight(DocumentHighlightParams params, CancelIndicator cancelIndicator) { + if (!isEnabled(getURI(params), YangFeatureToggleKeys.DOCUMENT_HIGHLIGHT)) { + return Collections.emptyList(); + } + return super.documentHighlight(params, cancelIndicator); + } + + @Override + public CompletableFuture rename(RenameParams params) { + if (!isEnabled(getURI(params.getTextDocument()), YangFeatureToggleKeys.RENAME)) { + return CompletableFuture.completedFuture(new WorkspaceEdit()); + } + return super.rename(params); + } + + @Override + protected List> codeAction(CodeActionParams params, CancelIndicator cancelIndicator) { + if (!isEnabled(getURI(params.getTextDocument()), YangFeatureToggleKeys.CODE_ACTIONS)) { + return Collections.emptyList(); + } + return super.codeAction(params, cancelIndicator); + } + + @Override + protected List formatting(DocumentFormattingParams params, CancelIndicator cancelIndicator) { + if (!isEnabled(getURI(params.getTextDocument()), YangFeatureToggleKeys.FORMATTING)) { + return Collections.emptyList(); + } + return super.formatting(params, cancelIndicator); + } + } diff --git a/yang-lsp/io.typefox.yang.ide/src/main/java/io/typefox/yang/ide/codeAction/CodeActionService.xtend b/yang-lsp/io.typefox.yang.ide/src/main/java/io/typefox/yang/ide/codeAction/CodeActionService.xtend index e3cad74a..1a8c3b3b 100644 --- a/yang-lsp/io.typefox.yang.ide/src/main/java/io/typefox/yang/ide/codeAction/CodeActionService.xtend +++ b/yang-lsp/io.typefox.yang.ide/src/main/java/io/typefox/yang/ide/codeAction/CodeActionService.xtend @@ -38,4 +38,4 @@ class CodeActionService implements ICodeActionService2 { return result } -} \ No newline at end of file +} diff --git a/yang-lsp/io.typefox.yang.ide/src/main/java/io/typefox/yang/ide/server/YangFeatureToggleKeys.java b/yang-lsp/io.typefox.yang.ide/src/main/java/io/typefox/yang/ide/server/YangFeatureToggleKeys.java new file mode 100644 index 00000000..bc8d4514 --- /dev/null +++ b/yang-lsp/io.typefox.yang.ide/src/main/java/io/typefox/yang/ide/server/YangFeatureToggleKeys.java @@ -0,0 +1,16 @@ +package io.typefox.yang.ide.server; + +import org.eclipse.xtext.preferences.PreferenceKey; + +public class YangFeatureToggleKeys { + public static final PreferenceKey COMPLETION = new PreferenceKey("completion", "on"); + public static final PreferenceKey HOVER = new PreferenceKey("hover", "on"); + public static final PreferenceKey DEFINITION = new PreferenceKey("definition", "on"); + public static final PreferenceKey REFERENCES = new PreferenceKey("references", "on"); + public static final PreferenceKey DOCUMENT_SYMBOLS = new PreferenceKey("document-symbols", "on"); + public static final PreferenceKey DOCUMENT_HIGHLIGHT = new PreferenceKey("document-highlight", "on"); + public static final PreferenceKey RENAME = new PreferenceKey("rename", "on"); + public static final PreferenceKey CODE_ACTIONS = new PreferenceKey("code-actions", "on"); + public static final PreferenceKey FORMATTING = new PreferenceKey("formatting", "on"); + public static final PreferenceKey VALIDATION = new PreferenceKey("validation", "on"); +} diff --git a/yang-lsp/io.typefox.yang/src/test/java/io/typefox/yang/tests/validation/FeatureToggleTest.xtend b/yang-lsp/io.typefox.yang/src/test/java/io/typefox/yang/tests/validation/FeatureToggleTest.xtend new file mode 100644 index 00000000..f8463a07 --- /dev/null +++ b/yang-lsp/io.typefox.yang/src/test/java/io/typefox/yang/tests/validation/FeatureToggleTest.xtend @@ -0,0 +1,20 @@ +package io.typefox.yang.tests.validation + +import io.typefox.yang.tests.AbstractYangTest +import org.junit.Assert +import org.junit.Test + +class FeatureToggleTest extends AbstractYangTest { + + @Test def void testValidationOnByDefault() { + val m = load(''' + module foo { + namespace urn:foo; + prefix foo; + revision 2999-99-99; + } + ''') + val issues = validator.validate(m.root) + Assert.assertFalse('Expected validation issues', issues.isEmpty) + } +}