brighterscript 1.0.0-alpha.44 → 1.0.0-alpha.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +63 -0
- package/bsconfig.schema.json +6 -1
- package/dist/AstValidationSegmenter.js +6 -1
- package/dist/AstValidationSegmenter.js.map +1 -1
- package/dist/BsConfig.d.ts +4 -0
- package/dist/BusyStatusTracker.d.ts +37 -7
- package/dist/BusyStatusTracker.js +73 -8
- package/dist/BusyStatusTracker.js.map +1 -1
- package/dist/Cache.d.ts +0 -4
- package/dist/Cache.js +0 -6
- package/dist/Cache.js.map +1 -1
- package/dist/CrossScopeValidator.d.ts +1 -1
- package/dist/CrossScopeValidator.js +4 -4
- package/dist/CrossScopeValidator.js.map +1 -1
- package/dist/DiagnosticCollection.d.ts +19 -5
- package/dist/DiagnosticCollection.js +71 -23
- package/dist/DiagnosticCollection.js.map +1 -1
- package/dist/DiagnosticFilterer.d.ts +14 -1
- package/dist/DiagnosticFilterer.js +130 -12
- package/dist/DiagnosticFilterer.js.map +1 -1
- package/dist/DiagnosticManager.d.ts +11 -1
- package/dist/DiagnosticManager.js +192 -35
- package/dist/DiagnosticManager.js.map +1 -1
- package/dist/LanguageServer.d.ts +82 -139
- package/dist/LanguageServer.js +402 -980
- package/dist/LanguageServer.js.map +1 -1
- package/dist/Logger.d.ts +9 -4
- package/dist/Logger.js +30 -6
- package/dist/Logger.js.map +1 -1
- package/dist/PluginInterface.d.ts +8 -8
- package/dist/PluginInterface.js.map +1 -1
- package/dist/Program.d.ts +23 -4
- package/dist/Program.js +294 -194
- package/dist/Program.js.map +1 -1
- package/dist/ProgramBuilder.d.ts +22 -7
- package/dist/ProgramBuilder.js +44 -21
- package/dist/ProgramBuilder.js.map +1 -1
- package/dist/Scope.d.ts +11 -6
- package/dist/Scope.js +60 -36
- package/dist/Scope.js.map +1 -1
- package/dist/SemanticTokenUtils.js +1 -1
- package/dist/SemanticTokenUtils.js.map +1 -1
- package/dist/astUtils/reflection.d.ts +4 -4
- package/dist/astUtils/reflection.js +12 -10
- package/dist/astUtils/reflection.js.map +1 -1
- package/dist/bscPlugin/BscPlugin.d.ts +3 -3
- package/dist/bscPlugin/BscPlugin.js.map +1 -1
- package/dist/bscPlugin/CallExpressionInfo.js +4 -2
- package/dist/bscPlugin/CallExpressionInfo.js.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.js +15 -15
- package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +82 -5
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/hover/HoverProcessor.js +3 -0
- package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
- package/dist/bscPlugin/validation/ScopeValidator.d.ts +4 -1
- package/dist/bscPlugin/validation/ScopeValidator.js +161 -61
- package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
- package/dist/common/Sequencer.d.ts +53 -0
- package/dist/common/Sequencer.js +232 -0
- package/dist/common/Sequencer.js.map +1 -0
- package/dist/common/Sequencer.spec.d.ts +1 -0
- package/dist/common/Sequencer.spec.js +75 -0
- package/dist/common/Sequencer.spec.js.map +1 -0
- package/dist/deferred.d.ts +2 -0
- package/dist/deferred.js +10 -0
- package/dist/deferred.js.map +1 -1
- package/dist/examples/plugins/removePrint.d.ts +2 -2
- package/dist/examples/plugins/removePrint.js.map +1 -1
- package/dist/files/BrsFile.d.ts +1 -1
- package/dist/files/BrsFile.js +11 -40
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BrsFile.spec.js +51 -2
- package/dist/files/BrsFile.spec.js.map +1 -1
- package/dist/files/BscFile.d.ts +1 -0
- package/dist/files/LazyFileData.d.ts +1 -0
- package/dist/files/XmlFile.spec.js +1 -1
- package/dist/files/XmlFile.spec.js.map +1 -1
- package/dist/globalCallables.js +186 -186
- package/dist/globalCallables.js.map +1 -1
- package/dist/interfaces.d.ts +56 -13
- package/dist/interfaces.js.map +1 -1
- package/dist/lexer/Lexer.js +1 -1
- package/dist/lexer/Lexer.js.map +1 -1
- package/dist/logging.d.ts +6 -1
- package/dist/logging.js +14 -1
- package/dist/logging.js.map +1 -1
- package/dist/lsp/ActionQueue.d.ts +35 -0
- package/dist/lsp/ActionQueue.js +115 -0
- package/dist/lsp/ActionQueue.js.map +1 -0
- package/dist/lsp/ActionQueue.spec.d.ts +1 -0
- package/dist/lsp/ActionQueue.spec.js +80 -0
- package/dist/lsp/ActionQueue.spec.js.map +1 -0
- package/dist/lsp/DocumentManager.d.ts +63 -0
- package/dist/lsp/DocumentManager.js +122 -0
- package/dist/lsp/DocumentManager.js.map +1 -0
- package/dist/lsp/DocumentManager.spec.d.ts +1 -0
- package/dist/lsp/DocumentManager.spec.js +103 -0
- package/dist/lsp/DocumentManager.spec.js.map +1 -0
- package/dist/lsp/LspProject.d.ts +231 -0
- package/dist/lsp/LspProject.js +3 -0
- package/dist/lsp/LspProject.js.map +1 -0
- package/dist/lsp/PathFilterer.d.ts +75 -0
- package/dist/lsp/PathFilterer.js +196 -0
- package/dist/lsp/PathFilterer.js.map +1 -0
- package/dist/lsp/PathFilterer.spec.d.ts +1 -0
- package/dist/lsp/PathFilterer.spec.js +182 -0
- package/dist/lsp/PathFilterer.spec.js.map +1 -0
- package/dist/lsp/Project.d.ts +167 -0
- package/dist/lsp/Project.js +432 -0
- package/dist/lsp/Project.js.map +1 -0
- package/dist/lsp/Project.spec.d.ts +1 -0
- package/dist/lsp/Project.spec.js +220 -0
- package/dist/lsp/Project.spec.js.map +1 -0
- package/dist/lsp/ProjectManager.d.ts +221 -0
- package/dist/lsp/ProjectManager.js +735 -0
- package/dist/lsp/ProjectManager.js.map +1 -0
- package/dist/lsp/ProjectManager.spec.d.ts +1 -0
- package/dist/lsp/ProjectManager.spec.js +757 -0
- package/dist/lsp/ProjectManager.spec.js.map +1 -0
- package/dist/lsp/ReaderWriterManager.d.ts +21 -0
- package/dist/lsp/ReaderWriterManager.js +60 -0
- package/dist/lsp/ReaderWriterManager.js.map +1 -0
- package/dist/lsp/worker/MessageHandler.d.ts +99 -0
- package/dist/lsp/worker/MessageHandler.js +138 -0
- package/dist/lsp/worker/MessageHandler.js.map +1 -0
- package/dist/lsp/worker/MessageHandler.spec.d.ts +1 -0
- package/dist/lsp/worker/MessageHandler.spec.js +64 -0
- package/dist/lsp/worker/MessageHandler.spec.js.map +1 -0
- package/dist/lsp/worker/WorkerPool.d.ts +38 -0
- package/dist/lsp/worker/WorkerPool.js +78 -0
- package/dist/lsp/worker/WorkerPool.js.map +1 -0
- package/dist/lsp/worker/WorkerPool.spec.d.ts +1 -0
- package/dist/lsp/worker/WorkerPool.spec.js +59 -0
- package/dist/lsp/worker/WorkerPool.spec.js.map +1 -0
- package/dist/lsp/worker/WorkerThreadProject.d.ts +144 -0
- package/dist/lsp/worker/WorkerThreadProject.js +183 -0
- package/dist/lsp/worker/WorkerThreadProject.js.map +1 -0
- package/dist/lsp/worker/WorkerThreadProject.spec.d.ts +2 -0
- package/dist/lsp/worker/WorkerThreadProject.spec.js +68 -0
- package/dist/lsp/worker/WorkerThreadProject.spec.js.map +1 -0
- package/dist/lsp/worker/WorkerThreadProjectRunner.d.ts +15 -0
- package/dist/lsp/worker/WorkerThreadProjectRunner.js +58 -0
- package/dist/lsp/worker/WorkerThreadProjectRunner.js.map +1 -0
- package/dist/parser/Expression.js +7 -2
- package/dist/parser/Expression.js.map +1 -1
- package/dist/parser/Parser.spec.js +12 -0
- package/dist/parser/Parser.spec.js.map +1 -1
- package/dist/parser/Statement.js +2 -2
- package/dist/parser/Statement.js.map +1 -1
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js +51 -5
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
- package/dist/roku-types/data.json +745 -751
- package/dist/types/BooleanType.d.ts +0 -2
- package/dist/types/BooleanType.js +4 -6
- package/dist/types/BooleanType.js.map +1 -1
- package/dist/types/BscType.js +5 -0
- package/dist/types/BscType.js.map +1 -1
- package/dist/types/BuiltInInterfaceAdder.d.ts +1 -0
- package/dist/types/BuiltInInterfaceAdder.js +24 -17
- package/dist/types/BuiltInInterfaceAdder.js.map +1 -1
- package/dist/types/DoubleType.d.ts +0 -2
- package/dist/types/DoubleType.js +4 -6
- package/dist/types/DoubleType.js.map +1 -1
- package/dist/types/DynamicType.d.ts +0 -2
- package/dist/types/DynamicType.js +3 -5
- package/dist/types/DynamicType.js.map +1 -1
- package/dist/types/FloatType.d.ts +0 -2
- package/dist/types/FloatType.js +4 -6
- package/dist/types/FloatType.js.map +1 -1
- package/dist/types/FunctionType.d.ts +0 -2
- package/dist/types/FunctionType.js +5 -7
- package/dist/types/FunctionType.js.map +1 -1
- package/dist/types/IntegerType.d.ts +0 -2
- package/dist/types/IntegerType.js +4 -6
- package/dist/types/IntegerType.js.map +1 -1
- package/dist/types/LongIntegerType.d.ts +0 -2
- package/dist/types/LongIntegerType.js +4 -6
- package/dist/types/LongIntegerType.js.map +1 -1
- package/dist/types/ObjectType.d.ts +3 -3
- package/dist/types/ObjectType.js +6 -8
- package/dist/types/ObjectType.js.map +1 -1
- package/dist/types/StringType.d.ts +0 -2
- package/dist/types/StringType.js +4 -6
- package/dist/types/StringType.js.map +1 -1
- package/dist/types/VoidType.d.ts +0 -2
- package/dist/types/VoidType.js +4 -6
- package/dist/types/VoidType.js.map +1 -1
- package/dist/types/helpers.d.ts +4 -0
- package/dist/types/helpers.js +5 -1
- package/dist/types/helpers.js.map +1 -1
- package/dist/util.d.ts +44 -16
- package/dist/util.js +196 -70
- package/dist/util.js.map +1 -1
- package/dist/validators/ClassValidator.js +2 -2
- package/dist/validators/ClassValidator.js.map +1 -1
- package/package.json +15 -5
package/dist/LanguageServer.js
CHANGED
|
@@ -7,38 +7,29 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
};
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.NotificationName = exports.CustomCommands = exports.LanguageServer = void 0;
|
|
10
|
-
require("array-flat-polyfill");
|
|
11
|
-
const fastGlob = require("fast-glob");
|
|
12
10
|
const path = require("path");
|
|
13
|
-
|
|
11
|
+
require("array-flat-polyfill");
|
|
14
12
|
const node_1 = require("vscode-languageserver/node");
|
|
15
13
|
const vscode_uri_1 = require("vscode-uri");
|
|
16
14
|
const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
|
|
17
|
-
const deferred_1 = require("./deferred");
|
|
18
|
-
const ProgramBuilder_1 = require("./ProgramBuilder");
|
|
19
15
|
const util_1 = require("./util");
|
|
20
|
-
const Throttler_1 = require("./Throttler");
|
|
21
|
-
const KeyedThrottler_1 = require("./KeyedThrottler");
|
|
22
16
|
const DiagnosticCollection_1 = require("./DiagnosticCollection");
|
|
23
|
-
const reflection_1 = require("./astUtils/reflection");
|
|
24
17
|
const SemanticTokenUtils_1 = require("./SemanticTokenUtils");
|
|
25
|
-
const BusyStatusTracker_1 = require("./BusyStatusTracker");
|
|
26
18
|
const logging_1 = require("./logging");
|
|
19
|
+
const ignore_1 = require("ignore");
|
|
20
|
+
const micromatch = require("micromatch");
|
|
21
|
+
const PathFilterer_1 = require("./lsp/PathFilterer");
|
|
22
|
+
const ProjectManager_1 = require("./lsp/ProjectManager");
|
|
23
|
+
const fsExtra = require("fs-extra");
|
|
24
|
+
const WorkerThreadProject_1 = require("./lsp/worker/WorkerThreadProject");
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
26
|
+
const isEqual = require("lodash.isequal");
|
|
27
27
|
class LanguageServer {
|
|
28
28
|
constructor() {
|
|
29
|
-
this.connection = undefined;
|
|
30
|
-
this.projects = [];
|
|
31
29
|
/**
|
|
32
|
-
* The
|
|
30
|
+
* The language server protocol connection, used to send and receive all requests and responses
|
|
33
31
|
*/
|
|
34
|
-
this.
|
|
35
|
-
/**
|
|
36
|
-
* These projects are created on the fly whenever a file is opened that is not included
|
|
37
|
-
* in any of the workspace-based projects.
|
|
38
|
-
* Basically these are single-file projects to at least get parsing for standalone files.
|
|
39
|
-
* Also, they should only be created when the file is opened, and destroyed when the file is closed.
|
|
40
|
-
*/
|
|
41
|
-
this.standaloneFileProjects = {};
|
|
32
|
+
this.connection = undefined;
|
|
42
33
|
this.hasConfigurationCapability = false;
|
|
43
34
|
/**
|
|
44
35
|
* Indicates whether the client supports workspace folders
|
|
@@ -49,98 +40,79 @@ class LanguageServer {
|
|
|
49
40
|
* The text document manager supports full document sync only
|
|
50
41
|
*/
|
|
51
42
|
this.documents = new node_1.TextDocuments(vscode_languageserver_textdocument_1.TextDocument);
|
|
52
|
-
this.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
this.
|
|
56
|
-
this.busyStatusTracker = new BusyStatusTracker_1.BusyStatusTracker();
|
|
43
|
+
this.logger = (0, logging_1.createLogger)({
|
|
44
|
+
logLevel: logging_1.LogLevel.log
|
|
45
|
+
});
|
|
46
|
+
this.workspaceConfigsCache = new Map();
|
|
57
47
|
this.busyStatusIndex = -1;
|
|
58
|
-
|
|
59
|
-
* A unique project counter to help distinguish log entries in lsp mode
|
|
60
|
-
*/
|
|
61
|
-
this.projectCounter = 0;
|
|
48
|
+
this.pathFiltererDisposables = [];
|
|
62
49
|
this.diagnosticCollection = new DiagnosticCollection_1.DiagnosticCollection();
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
50
|
+
(0, logging_1.setLspLoggerProps)();
|
|
51
|
+
//replace the workerPool logger with our own so logging info can be synced
|
|
52
|
+
WorkerThreadProject_1.workerPool.logger = this.logger.createLogger();
|
|
53
|
+
this.pathFilterer = new PathFilterer_1.PathFilterer({ logger: this.logger });
|
|
54
|
+
this.projectManager = new ProjectManager_1.ProjectManager({
|
|
55
|
+
pathFilterer: this.pathFilterer,
|
|
56
|
+
logger: this.logger.createLogger()
|
|
57
|
+
});
|
|
58
|
+
//anytime a project emits a collection of diagnostics, send them to the client
|
|
59
|
+
this.projectManager.on('diagnostics', (event) => {
|
|
60
|
+
this.logger.debug(`Received ${event.diagnostics.length} diagnostics from project ${event.project.projectNumber}`);
|
|
61
|
+
this.sendDiagnostics(event).catch(logAndIgnoreError);
|
|
62
|
+
});
|
|
63
|
+
// Send all open document changes whenever a project is activated. This is necessary because at project startup, the project loads files from disk
|
|
64
|
+
// and may not have the latest unsaved file changes. Any existing projects that already use these files will just ignore the changes
|
|
65
|
+
// because the file contents haven't changed.
|
|
66
|
+
this.projectManager.on('project-activate', (event) => {
|
|
67
|
+
var _a;
|
|
68
|
+
//keep logLevel in sync with the most verbose log level found across all projects
|
|
69
|
+
this.syncLogLevel().catch(logAndIgnoreError);
|
|
70
|
+
//resend all open document changes
|
|
71
|
+
const documents = [...this.documents.all()];
|
|
72
|
+
if (documents.length > 0) {
|
|
73
|
+
this.logger.log(`[${(_a = event.project) === null || _a === void 0 ? void 0 : _a.projectIdentifier}] loaded or changed. Resending all open document changes.`, documents.map(x => x.uri));
|
|
74
|
+
for (const document of this.documents.all()) {
|
|
75
|
+
this.onTextDocumentDidChangeContent({
|
|
76
|
+
document: document
|
|
77
|
+
}).catch(logAndIgnoreError);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
this.projectManager.busyStatusTracker.on('active-runs-change', (event) => {
|
|
82
|
+
this.sendBusyStatus();
|
|
83
|
+
});
|
|
69
84
|
}
|
|
70
85
|
//run the server
|
|
71
86
|
run() {
|
|
87
|
+
var _a;
|
|
72
88
|
// Create a connection for the server. The connection uses Node's IPC as a transport.
|
|
73
|
-
|
|
74
|
-
this.connection = this.createConnection();
|
|
75
|
-
// Send the current status of the busyStatusTracker anytime it changes
|
|
76
|
-
this.busyStatusTracker.on('change', (status) => {
|
|
77
|
-
void this.sendBusyStatus(status);
|
|
78
|
-
});
|
|
89
|
+
this.connection = this.establishConnection();
|
|
79
90
|
//disable logger colors when running in LSP mode
|
|
80
91
|
logging_1.logger.enableColor = false;
|
|
81
92
|
//listen to all of the output log events and pipe them into the debug channel in the extension
|
|
82
93
|
this.loggerSubscription = logging_1.logger.subscribe((message) => {
|
|
83
94
|
this.connection.tracer.log(message.argsText);
|
|
84
95
|
});
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
96
|
+
//bind all our on* methods that share the same name from connection
|
|
97
|
+
for (const name of Object.getOwnPropertyNames(LanguageServer.prototype)) {
|
|
98
|
+
if (/on+/.test(name) && typeof ((_a = this.connection) === null || _a === void 0 ? void 0 : _a[name]) === 'function') {
|
|
99
|
+
this.connection[name](this[name].bind(this));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//Register semantic token requests. TODO switch to a more specific connection function call once they actually add it
|
|
103
|
+
this.connection.onRequest(node_1.SemanticTokensRequest.method, this.onFullSemanticTokens.bind(this));
|
|
89
104
|
// The content of a text document has changed. This event is emitted
|
|
90
105
|
// when the text document is first opened, when its content has changed,
|
|
91
106
|
// or when document is closed without saving (original contents are sent as a change)
|
|
92
107
|
//
|
|
93
|
-
this.documents.onDidChangeContent(this.
|
|
108
|
+
this.documents.onDidChangeContent(this.onTextDocumentDidChangeContent.bind(this));
|
|
94
109
|
//whenever a document gets closed
|
|
95
110
|
this.documents.onDidClose(this.onDocumentClose.bind(this));
|
|
96
|
-
// This handler provides the initial list of the completion items.
|
|
97
|
-
this.connection.onCompletion(this.onCompletion.bind(this));
|
|
98
|
-
// This handler resolves additional information for the item selected in
|
|
99
|
-
// the completion list.
|
|
100
|
-
this.connection.onCompletionResolve(this.onCompletionResolve.bind(this));
|
|
101
|
-
this.connection.onHover(this.onHover.bind(this));
|
|
102
|
-
this.connection.onExecuteCommand(this.onExecuteCommand.bind(this));
|
|
103
|
-
this.connection.onDefinition(this.onDefinition.bind(this));
|
|
104
|
-
this.connection.onDocumentSymbol(this.onDocumentSymbol.bind(this));
|
|
105
|
-
this.connection.onWorkspaceSymbol(this.onWorkspaceSymbol.bind(this));
|
|
106
|
-
this.connection.onSignatureHelp(this.onSignatureHelp.bind(this));
|
|
107
|
-
this.connection.onReferences(this.onReferences.bind(this));
|
|
108
|
-
this.connection.onCodeAction(this.onCodeAction.bind(this));
|
|
109
|
-
//TODO switch to a more specific connection function call once they actually add it
|
|
110
|
-
this.connection.onRequest(node_1.SemanticTokensRequest.method, this.onFullSemanticTokens.bind(this));
|
|
111
|
-
/*
|
|
112
|
-
this.connection.onDidOpenTextDocument((params) => {
|
|
113
|
-
// A text document got opened in VSCode.
|
|
114
|
-
// params.uri uniquely identifies the document. For documents stored on disk this is a file URI.
|
|
115
|
-
// params.text the initial full content of the document.
|
|
116
|
-
this.connection.console.log(`${params.textDocument.uri} opened.`);
|
|
117
|
-
});
|
|
118
|
-
this.connection.onDidChangeTextDocument((params) => {
|
|
119
|
-
// The content of a text document did change in VSCode.
|
|
120
|
-
// params.uri uniquely identifies the document.
|
|
121
|
-
// params.contentChanges describe the content changes to the document.
|
|
122
|
-
this.connection.console.log(`${params.textDocument.uri} changed: ${JSON.stringify(params.contentChanges)}`);
|
|
123
|
-
});
|
|
124
|
-
this.connection.onDidCloseTextDocument((params) => {
|
|
125
|
-
// A text document got closed in VSCode.
|
|
126
|
-
// params.uri uniquely identifies the document.
|
|
127
|
-
this.connection.console.log(`${params.textDocument.uri} closed.`);
|
|
128
|
-
});
|
|
129
|
-
*/
|
|
130
111
|
// listen for open, change and close text document events
|
|
131
112
|
this.documents.listen(this.connection);
|
|
132
113
|
// Listen on the connection
|
|
133
114
|
this.connection.listen();
|
|
134
115
|
}
|
|
135
|
-
async sendBusyStatus(status) {
|
|
136
|
-
this.busyStatusIndex = ++this.busyStatusIndex <= 0 ? 0 : this.busyStatusIndex;
|
|
137
|
-
await this.connection.sendNotification(NotificationName.busyStatus, {
|
|
138
|
-
status: status,
|
|
139
|
-
timestamp: Date.now(),
|
|
140
|
-
index: this.busyStatusIndex,
|
|
141
|
-
activeRuns: [...this.busyStatusTracker.activeRuns]
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
116
|
/**
|
|
145
117
|
* Called when the client starts initialization
|
|
146
118
|
*/
|
|
@@ -156,7 +128,7 @@ class LanguageServer {
|
|
|
156
128
|
textDocumentSync: node_1.TextDocumentSyncKind.Full,
|
|
157
129
|
// Tell the client that the server supports code completion
|
|
158
130
|
completionProvider: {
|
|
159
|
-
resolveProvider:
|
|
131
|
+
resolveProvider: false,
|
|
160
132
|
//anytime the user types a period, auto-show the completion results
|
|
161
133
|
triggerCharacters: ['.'],
|
|
162
134
|
allCommitCharacters: ['.', '@']
|
|
@@ -184,146 +156,38 @@ class LanguageServer {
|
|
|
184
156
|
}
|
|
185
157
|
};
|
|
186
158
|
}
|
|
187
|
-
/**
|
|
188
|
-
* Ask the client for the list of `files.exclude` patterns. Useful when determining if we should process a file
|
|
189
|
-
*/
|
|
190
|
-
async getWorkspaceExcludeGlobs(workspaceFolder) {
|
|
191
|
-
var _a;
|
|
192
|
-
let config = {
|
|
193
|
-
exclude: {}
|
|
194
|
-
};
|
|
195
|
-
//if supported, ask vscode for the `files.exclude` configuration
|
|
196
|
-
if (this.hasConfigurationCapability) {
|
|
197
|
-
//get any `files.exclude` globs to use to filter
|
|
198
|
-
config = await this.connection.workspace.getConfiguration({
|
|
199
|
-
scopeUri: workspaceFolder,
|
|
200
|
-
section: 'files'
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
return Object
|
|
204
|
-
.keys((_a = config === null || config === void 0 ? void 0 : config.exclude) !== null && _a !== void 0 ? _a : {})
|
|
205
|
-
.filter(x => { var _a; return (_a = config === null || config === void 0 ? void 0 : config.exclude) === null || _a === void 0 ? void 0 : _a[x]; })
|
|
206
|
-
//vscode files.exclude patterns support ignoring folders without needing to add `**/*`. So for our purposes, we need to
|
|
207
|
-
//append **/* to everything without a file extension or magic at the end
|
|
208
|
-
.map(pattern => [
|
|
209
|
-
//send the pattern as-is (this handles weird cases and exact file matches)
|
|
210
|
-
pattern,
|
|
211
|
-
//treat the pattern as a directory (no harm in doing this because if it's a file, the pattern will just never match anything)
|
|
212
|
-
`${pattern}/**/*`
|
|
213
|
-
])
|
|
214
|
-
.flat(1)
|
|
215
|
-
.concat([
|
|
216
|
-
//always ignore projects from node_modules
|
|
217
|
-
'**/node_modules/**/*'
|
|
218
|
-
]);
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Scan the workspace for all `bsconfig.json` files. If at least one is found, then only folders who have bsconfig.json are returned.
|
|
222
|
-
* If none are found, then the workspaceFolder itself is treated as a project
|
|
223
|
-
*/
|
|
224
|
-
async getProjectPaths(workspaceFolder) {
|
|
225
|
-
const excludes = (await this.getWorkspaceExcludeGlobs(workspaceFolder)).map(x => (0, util_1.standardizePath) `!${x}`);
|
|
226
|
-
const files = await roku_deploy_1.rokuDeploy.getFilePaths([
|
|
227
|
-
'**/bsconfig.json',
|
|
228
|
-
//exclude all files found in `files.exclude`
|
|
229
|
-
...excludes
|
|
230
|
-
], workspaceFolder);
|
|
231
|
-
//if we found at least one bsconfig.json, then ALL projects must have a bsconfig.json.
|
|
232
|
-
if (files.length > 0) {
|
|
233
|
-
return files.map(file => (0, util_1.standardizePath) `${path.dirname(file.src)}`);
|
|
234
|
-
}
|
|
235
|
-
//look for roku project folders
|
|
236
|
-
const rokuLikeDirs = (await Promise.all(
|
|
237
|
-
//find all folders containing a `manifest` file
|
|
238
|
-
(await roku_deploy_1.rokuDeploy.getFilePaths([
|
|
239
|
-
'**/manifest',
|
|
240
|
-
...excludes
|
|
241
|
-
//is there at least one .bs|.brs file under the `/source` folder?
|
|
242
|
-
], workspaceFolder)).map(async (manifestEntry) => {
|
|
243
|
-
const manifestDir = path.dirname(manifestEntry.src);
|
|
244
|
-
const files = await roku_deploy_1.rokuDeploy.getFilePaths([
|
|
245
|
-
'source/**/*.{brs,bs}',
|
|
246
|
-
...excludes
|
|
247
|
-
], manifestDir);
|
|
248
|
-
if (files.length > 0) {
|
|
249
|
-
return manifestDir;
|
|
250
|
-
}
|
|
251
|
-
})
|
|
252
|
-
//throw out nulls
|
|
253
|
-
)).filter(x => !!x);
|
|
254
|
-
if (rokuLikeDirs.length > 0) {
|
|
255
|
-
return rokuLikeDirs;
|
|
256
|
-
}
|
|
257
|
-
//treat the workspace folder as a brightscript project itself
|
|
258
|
-
return [workspaceFolder];
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Find all folders with bsconfig.json files in them, and treat each as a project.
|
|
262
|
-
* Treat workspaces that don't have a bsconfig.json as a project.
|
|
263
|
-
* Handle situations where bsconfig.json files were added or removed (to elevate/lower workspaceFolder projects accordingly)
|
|
264
|
-
* Leave existing projects alone if they are not affected by these changes
|
|
265
|
-
*/
|
|
266
|
-
async syncProjects() {
|
|
267
|
-
const workspacePaths = await this.getWorkspacePaths();
|
|
268
|
-
let projectPaths = (await Promise.all(workspacePaths.map(async (workspacePath) => {
|
|
269
|
-
const projectPaths = await this.getProjectPaths(workspacePath);
|
|
270
|
-
return projectPaths.map(projectPath => ({
|
|
271
|
-
projectPath: projectPath,
|
|
272
|
-
workspacePath: workspacePath
|
|
273
|
-
}));
|
|
274
|
-
}))).flat(1);
|
|
275
|
-
//delete projects not represented in the list
|
|
276
|
-
for (const project of this.getProjects()) {
|
|
277
|
-
if (!projectPaths.find(x => x.projectPath === project.projectPath)) {
|
|
278
|
-
this.removeProject(project);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
//exclude paths to projects we already have
|
|
282
|
-
projectPaths = projectPaths.filter(x => {
|
|
283
|
-
//only keep this project path if there's not a project with that path
|
|
284
|
-
return !this.projects.find(project => project.projectPath === x.projectPath);
|
|
285
|
-
});
|
|
286
|
-
//dedupe by project path
|
|
287
|
-
projectPaths = [
|
|
288
|
-
...projectPaths.reduce((acc, x) => acc.set(x.projectPath, x), new Map()).values()
|
|
289
|
-
];
|
|
290
|
-
//create missing projects
|
|
291
|
-
await Promise.all(projectPaths.map(x => this.createProject(x.projectPath, x.workspacePath)));
|
|
292
|
-
//flush diagnostics
|
|
293
|
-
await this.sendDiagnostics();
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Get all workspace paths from the client
|
|
297
|
-
*/
|
|
298
|
-
async getWorkspacePaths() {
|
|
299
|
-
var _a;
|
|
300
|
-
let workspaceFolders = (_a = await this.connection.workspace.getWorkspaceFolders()) !== null && _a !== void 0 ? _a : [];
|
|
301
|
-
return workspaceFolders.map((x) => {
|
|
302
|
-
return util_1.util.uriToPath(x.uri);
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
159
|
/**
|
|
306
160
|
* Called when the client has finished initializing
|
|
307
161
|
*/
|
|
308
162
|
async onInitialized() {
|
|
309
|
-
|
|
310
|
-
|
|
163
|
+
this.logger.log('onInitialized');
|
|
164
|
+
//cache a copy of all workspace configurations to use for comparison later
|
|
165
|
+
this.workspaceConfigsCache = new Map((await this.getWorkspaceConfigs()).map(x => [x.workspaceFolder, x]));
|
|
166
|
+
//set our logger to the most verbose logLevel found across any project
|
|
167
|
+
await this.syncLogLevel();
|
|
311
168
|
try {
|
|
312
169
|
if (this.hasConfigurationCapability) {
|
|
313
|
-
//
|
|
314
|
-
await this.connection.client.register(node_1.DidChangeConfigurationNotification.type,
|
|
170
|
+
// register for when the user changes workspace or user settings
|
|
171
|
+
await this.connection.client.register(node_1.DidChangeConfigurationNotification.type, {
|
|
172
|
+
//we only care about when these settings sections change
|
|
173
|
+
section: [
|
|
174
|
+
'brightscript',
|
|
175
|
+
'files'
|
|
176
|
+
]
|
|
177
|
+
});
|
|
315
178
|
}
|
|
179
|
+
//populate the path filterer with the client's include/exclude lists
|
|
180
|
+
await this.rebuildPathFilterer();
|
|
316
181
|
await this.syncProjects();
|
|
317
182
|
if (this.clientHasWorkspaceFolderCapability) {
|
|
183
|
+
//if the client changes their workspaces, we need to get our projects in sync
|
|
318
184
|
this.connection.workspace.onDidChangeWorkspaceFolders(async (evt) => {
|
|
319
185
|
await this.syncProjects();
|
|
320
186
|
});
|
|
321
187
|
}
|
|
322
|
-
await this.waitAllProjectFirstRuns(false);
|
|
323
|
-
projectCreatedDeferred.resolve();
|
|
324
188
|
}
|
|
325
189
|
catch (e) {
|
|
326
|
-
|
|
190
|
+
this.sendCriticalFailure(`Critical failure during BrighterScript language server startup.
|
|
327
191
|
Please file a github issue and include the contents of the 'BrighterScript Language Server' output channel.
|
|
328
192
|
|
|
329
193
|
Error message: ${e.message}`);
|
|
@@ -331,367 +195,63 @@ class LanguageServer {
|
|
|
331
195
|
}
|
|
332
196
|
}
|
|
333
197
|
/**
|
|
334
|
-
*
|
|
198
|
+
* Set our logLevel to the most verbose log level found across all projects and workspaces
|
|
335
199
|
*/
|
|
336
|
-
async
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
200
|
+
async syncLogLevel() {
|
|
201
|
+
var _a, _b;
|
|
202
|
+
/**
|
|
203
|
+
* helper to get the logLevel from a list of items and return the item and level (if found), or undefined if not
|
|
204
|
+
*/
|
|
205
|
+
const getLogLevel = async (items, fetcher) => {
|
|
206
|
+
const logLevels = await Promise.all(items.map(async (item) => {
|
|
207
|
+
let value = await fetcher(item);
|
|
208
|
+
//force string values to lower case (so we can support things like 'log' or 'Log' or 'LOG')
|
|
209
|
+
if (typeof value === 'string') {
|
|
210
|
+
value = value.toLowerCase();
|
|
211
|
+
}
|
|
212
|
+
const logLevelNumeric = this.logger.getLogLevelNumeric(value);
|
|
213
|
+
if (typeof logLevelNumeric === 'number') {
|
|
214
|
+
return logLevelNumeric;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
return -1;
|
|
218
|
+
}
|
|
219
|
+
}));
|
|
220
|
+
let idx = logLevels.findIndex(x => x > -1);
|
|
221
|
+
if (idx > -1) {
|
|
222
|
+
const mostVerboseLogLevel = Math.max(...logLevels);
|
|
223
|
+
return {
|
|
224
|
+
logLevel: mostVerboseLogLevel,
|
|
225
|
+
logLevelText: this.logger.getLogLevelText(mostVerboseLogLevel),
|
|
226
|
+
//find the first item having the most verbose logLevel
|
|
227
|
+
item: items[logLevels.findIndex(x => x === mostVerboseLogLevel)]
|
|
228
|
+
};
|
|
355
229
|
}
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
/**
|
|
359
|
-
* Event handler for when the program wants to load file contents.
|
|
360
|
-
* anytime the program wants to load a file, check with our in-memory document cache first
|
|
361
|
-
*/
|
|
362
|
-
documentFileResolver(srcPath) {
|
|
363
|
-
let pathUri = util_1.util.pathToUri(srcPath);
|
|
364
|
-
let document = this.documents.get(pathUri);
|
|
365
|
-
if (document) {
|
|
366
|
-
return document.getText();
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
async getConfigFilePath(workspacePath) {
|
|
370
|
-
let scopeUri;
|
|
371
|
-
if (workspacePath.startsWith('file:')) {
|
|
372
|
-
scopeUri = vscode_uri_1.URI.parse(workspacePath).toString();
|
|
373
|
-
}
|
|
374
|
-
else {
|
|
375
|
-
scopeUri = util_1.util.pathToUri(workspacePath);
|
|
376
|
-
}
|
|
377
|
-
let config = {
|
|
378
|
-
configFile: undefined
|
|
379
230
|
};
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
let configFilePath;
|
|
388
|
-
//if there's a setting, we need to find the file or show error if it can't be found
|
|
389
|
-
if (config === null || config === void 0 ? void 0 : config.configFile) {
|
|
390
|
-
configFilePath = path.resolve(workspacePath, config.configFile);
|
|
391
|
-
if (await util_1.util.pathExists(configFilePath)) {
|
|
392
|
-
return configFilePath;
|
|
393
|
-
}
|
|
394
|
-
else {
|
|
395
|
-
await this.sendCriticalFailure(`Cannot find config file specified in user / workspace settings at '${configFilePath}'`);
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
//default to config file path found in the root of the workspace
|
|
399
|
-
configFilePath = path.resolve(workspacePath, 'bsconfig.json');
|
|
400
|
-
if (await util_1.util.pathExists(configFilePath)) {
|
|
401
|
-
return configFilePath;
|
|
402
|
-
}
|
|
403
|
-
//look for the deprecated `brsconfig.json` file
|
|
404
|
-
configFilePath = path.resolve(workspacePath, 'brsconfig.json');
|
|
405
|
-
if (await util_1.util.pathExists(configFilePath)) {
|
|
406
|
-
return configFilePath;
|
|
407
|
-
}
|
|
408
|
-
//no config file could be found
|
|
409
|
-
return undefined;
|
|
410
|
-
}
|
|
411
|
-
/**
|
|
412
|
-
* @param projectPath path to the project
|
|
413
|
-
* @param workspacePath path to the workspace in which all project should reside or are referenced by
|
|
414
|
-
* @param projectNumber an optional project number to assign to the project. Used when reloading projects that should keep the same number
|
|
415
|
-
*/
|
|
416
|
-
async createProject(projectPath, workspacePath = projectPath, projectNumber) {
|
|
417
|
-
workspacePath !== null && workspacePath !== void 0 ? workspacePath : (workspacePath = projectPath);
|
|
418
|
-
let project = this.projects.find((x) => x.projectPath === projectPath);
|
|
419
|
-
//skip this project if we already have it
|
|
420
|
-
if (project) {
|
|
231
|
+
const workspaces = await this.getWorkspaceConfigs();
|
|
232
|
+
let workspaceResult = await getLogLevel(workspaces, workspace => { var _a; return (_a = workspace === null || workspace === void 0 ? void 0 : workspace.languageServer) === null || _a === void 0 ? void 0 : _a.logLevel; });
|
|
233
|
+
if (workspaceResult) {
|
|
234
|
+
this.logger.info(`Setting global logLevel to '${workspaceResult.logLevelText}' based on configuration from workspace '${(_a = workspaceResult === null || workspaceResult === void 0 ? void 0 : workspaceResult.item) === null || _a === void 0 ? void 0 : _a.workspaceFolder}'`);
|
|
235
|
+
this.logger.logLevel = workspaceResult.logLevel;
|
|
421
236
|
return;
|
|
422
237
|
}
|
|
423
|
-
let
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
builder.plugins.add({
|
|
429
|
-
name: 'bsc-language-server',
|
|
430
|
-
afterProgramValidate: () => {
|
|
431
|
-
void this.sendDiagnostics();
|
|
432
|
-
}
|
|
433
|
-
});
|
|
434
|
-
//prevent clearing the console on run...this isn't the CLI so we want to keep a full log of everything
|
|
435
|
-
builder.allowConsoleClearing = false;
|
|
436
|
-
//look for files in our in-memory cache before going to the file system
|
|
437
|
-
builder.addFileResolver(this.documentFileResolver.bind(this));
|
|
438
|
-
let configFilePath = await this.getConfigFilePath(projectPath);
|
|
439
|
-
let cwd = projectPath;
|
|
440
|
-
//if the config file exists, use it and its folder as cwd
|
|
441
|
-
if (configFilePath && await util_1.util.pathExists(configFilePath)) {
|
|
442
|
-
cwd = path.dirname(configFilePath);
|
|
443
|
-
}
|
|
444
|
-
else {
|
|
445
|
-
//config file doesn't exist...let `brighterscript` resolve the default way
|
|
446
|
-
configFilePath = undefined;
|
|
447
|
-
}
|
|
448
|
-
const firstRunDeferred = new deferred_1.Deferred();
|
|
449
|
-
let newProject = {
|
|
450
|
-
projectNumber: projectNumber,
|
|
451
|
-
builder: builder,
|
|
452
|
-
firstRunPromise: firstRunDeferred.promise,
|
|
453
|
-
projectPath: projectPath,
|
|
454
|
-
workspacePath: workspacePath,
|
|
455
|
-
isFirstRunComplete: false,
|
|
456
|
-
isFirstRunSuccessful: false,
|
|
457
|
-
configFilePath: configFilePath,
|
|
458
|
-
isStandaloneFileProject: false
|
|
459
|
-
};
|
|
460
|
-
this.projects.push(newProject);
|
|
461
|
-
try {
|
|
462
|
-
await builder.run({
|
|
463
|
-
cwd: cwd,
|
|
464
|
-
project: configFilePath,
|
|
465
|
-
watch: false,
|
|
466
|
-
createPackage: false,
|
|
467
|
-
deploy: false,
|
|
468
|
-
copyToStaging: false,
|
|
469
|
-
showDiagnosticsInConsole: false
|
|
470
|
-
});
|
|
471
|
-
newProject.isFirstRunComplete = true;
|
|
472
|
-
newProject.isFirstRunSuccessful = true;
|
|
473
|
-
firstRunDeferred.resolve();
|
|
474
|
-
}
|
|
475
|
-
catch (e) {
|
|
476
|
-
builder.logger.error(e);
|
|
477
|
-
firstRunDeferred.reject(e);
|
|
478
|
-
newProject.isFirstRunComplete = true;
|
|
479
|
-
newProject.isFirstRunSuccessful = false;
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
async createStandaloneFileProject(srcPath) {
|
|
483
|
-
//skip this workspace if we already have it
|
|
484
|
-
if (this.standaloneFileProjects[srcPath]) {
|
|
485
|
-
return this.standaloneFileProjects[srcPath];
|
|
486
|
-
}
|
|
487
|
-
let builder = new ProgramBuilder_1.ProgramBuilder();
|
|
488
|
-
//prevent clearing the console on run...this isn't the CLI so we want to keep a full log of everything
|
|
489
|
-
builder.allowConsoleClearing = false;
|
|
490
|
-
//look for files in our in-memory cache before going to the file system
|
|
491
|
-
builder.addFileResolver(this.documentFileResolver.bind(this));
|
|
492
|
-
//get the path to the directory where this file resides
|
|
493
|
-
let cwd = path.dirname(srcPath);
|
|
494
|
-
//get the closest config file and use most of the settings from that
|
|
495
|
-
let configFilePath = await util_1.util.findClosestConfigFile(srcPath);
|
|
496
|
-
let project = {};
|
|
497
|
-
if (configFilePath) {
|
|
498
|
-
project = util_1.util.normalizeAndResolveConfig({ project: configFilePath });
|
|
499
|
-
}
|
|
500
|
-
//override the rootDir and files array
|
|
501
|
-
project.rootDir = cwd;
|
|
502
|
-
project.files = [{
|
|
503
|
-
src: srcPath,
|
|
504
|
-
dest: path.basename(srcPath)
|
|
505
|
-
}];
|
|
506
|
-
let firstRunPromise = builder.run(Object.assign(Object.assign({}, project), { cwd: cwd, project: configFilePath, watch: false, createPackage: false, deploy: false, copyToStaging: false, diagnosticFilters: [
|
|
507
|
-
//hide the "file not referenced by any other file" error..that's expected in a standalone file.
|
|
508
|
-
1013
|
|
509
|
-
] })).catch((err) => {
|
|
510
|
-
console.error(err);
|
|
511
|
-
});
|
|
512
|
-
let newProject = {
|
|
513
|
-
projectNumber: this.projectCounter++,
|
|
514
|
-
builder: builder,
|
|
515
|
-
firstRunPromise: firstRunPromise,
|
|
516
|
-
projectPath: srcPath,
|
|
517
|
-
workspacePath: srcPath,
|
|
518
|
-
isFirstRunComplete: false,
|
|
519
|
-
isFirstRunSuccessful: false,
|
|
520
|
-
configFilePath: configFilePath,
|
|
521
|
-
isStandaloneFileProject: true
|
|
522
|
-
};
|
|
523
|
-
this.standaloneFileProjects[srcPath] = newProject;
|
|
524
|
-
await firstRunPromise.then(() => {
|
|
525
|
-
newProject.isFirstRunComplete = true;
|
|
526
|
-
newProject.isFirstRunSuccessful = true;
|
|
527
|
-
}).catch(() => {
|
|
528
|
-
newProject.isFirstRunComplete = true;
|
|
529
|
-
newProject.isFirstRunSuccessful = false;
|
|
530
|
-
});
|
|
531
|
-
return newProject;
|
|
532
|
-
}
|
|
533
|
-
getProjects() {
|
|
534
|
-
let projects = this.projects.slice();
|
|
535
|
-
for (let key in this.standaloneFileProjects) {
|
|
536
|
-
projects.push(this.standaloneFileProjects[key]);
|
|
537
|
-
}
|
|
538
|
-
return projects;
|
|
539
|
-
}
|
|
540
|
-
/**
|
|
541
|
-
* Provide a list of completion items based on the current cursor position
|
|
542
|
-
*/
|
|
543
|
-
async onCompletion(params) {
|
|
544
|
-
//ensure programs are initialized
|
|
545
|
-
await this.waitAllProjectFirstRuns();
|
|
546
|
-
let filePath = util_1.util.uriToPath(params.textDocument.uri);
|
|
547
|
-
//wait until the file has settled
|
|
548
|
-
await this.keyedThrottler.onIdleOnce(filePath, true);
|
|
549
|
-
// make sure validation is complete
|
|
550
|
-
await this.validateAllThrottled();
|
|
551
|
-
//wait for the validation cycle to settle
|
|
552
|
-
await this.onValidateSettled();
|
|
553
|
-
let completions = this
|
|
554
|
-
.getProjects()
|
|
555
|
-
.flatMap(workspace => workspace.builder.program.getCompletions(filePath, params.position));
|
|
556
|
-
//only send one completion if name and type are the same
|
|
557
|
-
let completionsMap = new Map();
|
|
558
|
-
for (let completion of completions) {
|
|
559
|
-
completion.commitCharacters = ['.'];
|
|
560
|
-
let key = `${completion.sortText}-${completion.label}-${completion.kind}`;
|
|
561
|
-
completionsMap.set(key, completion);
|
|
562
|
-
}
|
|
563
|
-
return [...completionsMap.values()];
|
|
564
|
-
}
|
|
565
|
-
/**
|
|
566
|
-
* Provide a full completion item from the selection
|
|
567
|
-
*/
|
|
568
|
-
onCompletionResolve(item) {
|
|
569
|
-
if (item.data === 1) {
|
|
570
|
-
item.detail = 'TypeScript details';
|
|
571
|
-
item.documentation = 'TypeScript documentation';
|
|
572
|
-
}
|
|
573
|
-
else if (item.data === 2) {
|
|
574
|
-
item.detail = 'JavaScript details';
|
|
575
|
-
item.documentation = 'JavaScript documentation';
|
|
576
|
-
}
|
|
577
|
-
return item;
|
|
578
|
-
}
|
|
579
|
-
async onCodeAction(params) {
|
|
580
|
-
var _a;
|
|
581
|
-
//ensure programs are initialized
|
|
582
|
-
await this.waitAllProjectFirstRuns();
|
|
583
|
-
let srcPath = util_1.util.uriToPath(params.textDocument.uri);
|
|
584
|
-
//wait until the file has settled
|
|
585
|
-
await this.keyedThrottler.onIdleOnce(srcPath, true);
|
|
586
|
-
const codeActions = this
|
|
587
|
-
.getProjects()
|
|
588
|
-
//skip programs that don't have this file
|
|
589
|
-
.filter(x => { var _a, _b; return (_b = (_a = x.builder) === null || _a === void 0 ? void 0 : _a.program) === null || _b === void 0 ? void 0 : _b.hasFile(srcPath); })
|
|
590
|
-
.flatMap(workspace => workspace.builder.program.getCodeActions(srcPath, params.range));
|
|
591
|
-
//clone the diagnostics for each code action, since certain diagnostics can have circular reference properties that kill the language server if serialized
|
|
592
|
-
for (const codeAction of codeActions) {
|
|
593
|
-
if (codeAction.diagnostics) {
|
|
594
|
-
codeAction.diagnostics = (_a = codeAction.diagnostics) === null || _a === void 0 ? void 0 : _a.map(x => util_1.util.toDiagnostic(x, params.textDocument.uri));
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
return codeActions;
|
|
598
|
-
}
|
|
599
|
-
/**
|
|
600
|
-
* Remove a project from the language server
|
|
601
|
-
*/
|
|
602
|
-
removeProject(project) {
|
|
603
|
-
var _a;
|
|
604
|
-
const idx = this.projects.indexOf(project);
|
|
605
|
-
if (idx > -1) {
|
|
606
|
-
this.projects.splice(idx, 1);
|
|
607
|
-
}
|
|
608
|
-
(_a = project === null || project === void 0 ? void 0 : project.builder) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
609
|
-
}
|
|
610
|
-
/**
|
|
611
|
-
* Reload each of the specified workspaces
|
|
612
|
-
*/
|
|
613
|
-
async reloadProjects(projects) {
|
|
614
|
-
await Promise.all(projects.map(async (project) => {
|
|
615
|
-
//ensure the workspace has finished starting up
|
|
616
|
-
try {
|
|
617
|
-
await project.firstRunPromise;
|
|
618
|
-
}
|
|
619
|
-
catch (e) { }
|
|
620
|
-
//handle standard workspace
|
|
621
|
-
if (project.isStandaloneFileProject === false) {
|
|
622
|
-
this.removeProject(project);
|
|
623
|
-
//create a new workspace/brs program
|
|
624
|
-
await this.createProject(project.projectPath, project.workspacePath, project.projectNumber);
|
|
625
|
-
//handle temp workspace
|
|
626
|
-
}
|
|
627
|
-
else {
|
|
628
|
-
project.builder.dispose();
|
|
629
|
-
delete this.standaloneFileProjects[project.projectPath];
|
|
630
|
-
await this.createStandaloneFileProject(project.projectPath);
|
|
631
|
-
}
|
|
632
|
-
}));
|
|
633
|
-
if (projects.length > 0) {
|
|
634
|
-
//wait for all of the programs to finish starting up
|
|
635
|
-
await this.waitAllProjectFirstRuns();
|
|
636
|
-
// valdiate all workspaces
|
|
637
|
-
this.validateAllThrottled(); //eslint-disable-line
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
getRootDir(workspace) {
|
|
641
|
-
var _a, _b, _c;
|
|
642
|
-
let options = (_b = (_a = workspace === null || workspace === void 0 ? void 0 : workspace.builder) === null || _a === void 0 ? void 0 : _a.program) === null || _b === void 0 ? void 0 : _b.options;
|
|
643
|
-
return (_c = options === null || options === void 0 ? void 0 : options.rootDir) !== null && _c !== void 0 ? _c : options === null || options === void 0 ? void 0 : options.cwd;
|
|
644
|
-
}
|
|
645
|
-
/**
|
|
646
|
-
* Sometimes users will alter their bsconfig files array, and will include standalone files.
|
|
647
|
-
* If this is the case, those standalone workspaces should be removed because the file was
|
|
648
|
-
* included in an actual program now.
|
|
649
|
-
*
|
|
650
|
-
* Sometimes files that used to be included are now excluded, so those open files need to be re-processed as standalone
|
|
651
|
-
*/
|
|
652
|
-
async synchronizeStandaloneProjects() {
|
|
653
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
654
|
-
//remove standalone workspaces that are now included in projects
|
|
655
|
-
for (let standaloneFilePath in this.standaloneFileProjects) {
|
|
656
|
-
let standaloneProject = this.standaloneFileProjects[standaloneFilePath];
|
|
657
|
-
for (let project of this.projects) {
|
|
658
|
-
await standaloneProject.firstRunPromise;
|
|
659
|
-
let dest = roku_deploy_1.rokuDeploy.getDestPath(standaloneFilePath, (_d = (_c = (_b = (_a = project === null || project === void 0 ? void 0 : project.builder) === null || _a === void 0 ? void 0 : _a.program) === null || _b === void 0 ? void 0 : _b.options) === null || _c === void 0 ? void 0 : _c.files) !== null && _d !== void 0 ? _d : [], this.getRootDir(project));
|
|
660
|
-
//destroy this standalone workspace because the file has now been included in an actual workspace,
|
|
661
|
-
//or if the workspace wants the file
|
|
662
|
-
if (((_f = (_e = project === null || project === void 0 ? void 0 : project.builder) === null || _e === void 0 ? void 0 : _e.program) === null || _f === void 0 ? void 0 : _f.hasFile(standaloneFilePath)) || dest) {
|
|
663
|
-
standaloneProject.builder.dispose();
|
|
664
|
-
delete this.standaloneFileProjects[standaloneFilePath];
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
//create standalone projects for open files that no longer have a project
|
|
669
|
-
let textDocuments = this.documents.all();
|
|
670
|
-
outer: for (let textDocument of textDocuments) {
|
|
671
|
-
let filePath = vscode_uri_1.URI.parse(textDocument.uri).fsPath;
|
|
672
|
-
for (let project of this.getProjects()) {
|
|
673
|
-
let dest = roku_deploy_1.rokuDeploy.getDestPath(filePath, (_k = (_j = (_h = (_g = project === null || project === void 0 ? void 0 : project.builder) === null || _g === void 0 ? void 0 : _g.program) === null || _h === void 0 ? void 0 : _h.options) === null || _j === void 0 ? void 0 : _j.files) !== null && _k !== void 0 ? _k : [], this.getRootDir(project));
|
|
674
|
-
//if this project has the file, or it wants the file, do NOT make a standaloneProject for this file
|
|
675
|
-
if (((_m = (_l = project === null || project === void 0 ? void 0 : project.builder) === null || _l === void 0 ? void 0 : _l.program) === null || _m === void 0 ? void 0 : _m.hasFile(filePath)) || dest) {
|
|
676
|
-
continue outer;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
//if we got here, no workspace has this file, so make a standalone file workspace
|
|
680
|
-
let project = await this.createStandaloneFileProject(filePath);
|
|
681
|
-
await project.firstRunPromise;
|
|
238
|
+
let projectResult = await getLogLevel(this.projectManager.projects, (project) => project.logger.logLevel);
|
|
239
|
+
if (projectResult) {
|
|
240
|
+
this.logger.info(`Setting global logLevel to '${projectResult.logLevelText}' based on project #${(_b = projectResult === null || projectResult === void 0 ? void 0 : projectResult.item) === null || _b === void 0 ? void 0 : _b.projectNumber}`);
|
|
241
|
+
this.logger.logLevel = projectResult.logLevel;
|
|
242
|
+
return;
|
|
682
243
|
}
|
|
244
|
+
//use a default level if no other level was found
|
|
245
|
+
this.logger.logLevel = logging_1.LogLevel.log;
|
|
683
246
|
}
|
|
684
|
-
async
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
// (change.settings.languageServerExample || this.defaultSettings)
|
|
693
|
-
// );
|
|
694
|
-
}
|
|
247
|
+
async onTextDocumentDidChangeContent(event) {
|
|
248
|
+
this.logger.debug('onTextDocumentDidChangeContent', event.document.uri);
|
|
249
|
+
await this.projectManager.handleFileChanges([{
|
|
250
|
+
srcPath: vscode_uri_1.URI.parse(event.document.uri).fsPath,
|
|
251
|
+
type: node_1.FileChangeType.Changed,
|
|
252
|
+
fileContents: event.document.getText(),
|
|
253
|
+
allowStandaloneProject: true
|
|
254
|
+
}]);
|
|
695
255
|
}
|
|
696
256
|
/**
|
|
697
257
|
* Called when watched files changed (add/change/delete).
|
|
@@ -700,485 +260,353 @@ class LanguageServer {
|
|
|
700
260
|
* file types are watched (.brs,.bs,.xml,manifest, and any json/text/image files)
|
|
701
261
|
*/
|
|
702
262
|
async onDidChangeWatchedFiles(params) {
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
//
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
let filePaths = changes.map((x) => x.srcPath);
|
|
727
|
-
for (let project of projects) {
|
|
728
|
-
if (project.configFilePath && filePaths.includes(project.configFilePath)) {
|
|
729
|
-
projectsToReload.push(project);
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
if (projectsToReload.length > 0) {
|
|
733
|
-
//vsc can generate a ton of these changes, for vsc system files, so we need to bail if there's no work to do on any of our actual project files
|
|
734
|
-
//reload any projects that need to be reloaded
|
|
735
|
-
await this.reloadProjects(projectsToReload);
|
|
736
|
-
}
|
|
737
|
-
//reassign `projects` to the non-reloaded projects
|
|
738
|
-
projects = projects.filter(x => !projectsToReload.includes(x));
|
|
739
|
-
}
|
|
740
|
-
//convert created folders into a list of files of their contents
|
|
741
|
-
const directoryChanges = changes
|
|
742
|
-
//get only creation items
|
|
743
|
-
.filter(change => change.type === node_1.FileChangeType.Created)
|
|
744
|
-
//keep only the directories
|
|
745
|
-
.filter(change => util_1.util.isDirectorySync(change.srcPath));
|
|
746
|
-
//remove the created directories from the changes array (we will add back each of their files next)
|
|
747
|
-
changes = changes.filter(x => !directoryChanges.includes(x));
|
|
748
|
-
//look up every file in each of the newly added directories
|
|
749
|
-
const newFileChanges = directoryChanges
|
|
750
|
-
//take just the path
|
|
751
|
-
.map(x => x.srcPath)
|
|
752
|
-
//exclude the roku deploy staging folder
|
|
753
|
-
.filter(dirPath => !dirPath.includes('.roku-deploy-staging'))
|
|
754
|
-
//get the files for each folder recursively
|
|
755
|
-
.flatMap(dirPath => {
|
|
756
|
-
//look up all files
|
|
757
|
-
let files = fastGlob.sync('**/*', {
|
|
758
|
-
absolute: true,
|
|
759
|
-
cwd: roku_deploy_1.util.toForwardSlashes(dirPath)
|
|
760
|
-
});
|
|
761
|
-
return files.map(x => {
|
|
762
|
-
return {
|
|
763
|
-
type: node_1.FileChangeType.Created,
|
|
764
|
-
srcPath: (0, util_1.standardizePath) `${x}`
|
|
765
|
-
};
|
|
766
|
-
});
|
|
767
|
-
});
|
|
768
|
-
//add the new file changes to the changes array.
|
|
769
|
-
changes.push(...newFileChanges);
|
|
770
|
-
//give every workspace the chance to handle file changes
|
|
771
|
-
await Promise.all(projects.map((project) => this.handleFileChanges(project, changes)));
|
|
772
|
-
}
|
|
263
|
+
const workspacePaths = (await this.connection.workspace.getWorkspaceFolders()).map(x => util_1.util.uriToPath(x.uri));
|
|
264
|
+
let changes = params.changes
|
|
265
|
+
.map(x => ({
|
|
266
|
+
srcPath: util_1.util.uriToPath(x.uri),
|
|
267
|
+
type: x.type,
|
|
268
|
+
//if this is an open document, allow this file to be loaded in a standalone project (if applicable)
|
|
269
|
+
allowStandaloneProject: this.documents.get(x.uri) !== undefined
|
|
270
|
+
}))
|
|
271
|
+
//exclude all explicit top-level workspace folder paths (to fix a weird macos fs watcher bug that emits events for the workspace folder itself)
|
|
272
|
+
.filter(x => !workspacePaths.includes(x.srcPath));
|
|
273
|
+
this.logger.debug('onDidChangeWatchedFiles', changes);
|
|
274
|
+
//if the client changed any files containing include/exclude patterns, rebuild the path filterer before processing these changes
|
|
275
|
+
if (micromatch.some(changes.map(x => x.srcPath), [
|
|
276
|
+
'**/.gitignore',
|
|
277
|
+
'**/.vscode/settings.json',
|
|
278
|
+
'**/*bsconfig*.json'
|
|
279
|
+
], {
|
|
280
|
+
dot: true
|
|
281
|
+
})) {
|
|
282
|
+
await this.rebuildPathFilterer();
|
|
283
|
+
}
|
|
284
|
+
//handle the file changes
|
|
285
|
+
await this.projectManager.handleFileChanges(changes);
|
|
773
286
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
//this loop assumes paths are both file paths and folder paths, which eliminates the need to detect.
|
|
780
|
-
//All functions below can handle being given a file path AND a folder path, and will only operate on the one they are looking for
|
|
781
|
-
let handledFile = false;
|
|
782
|
-
await Promise.all(changes.map(async (change) => {
|
|
783
|
-
await this.keyedThrottler.run(change.srcPath, async () => {
|
|
784
|
-
if (await this.handleFileChange(project, change)) {
|
|
785
|
-
handledFile = true;
|
|
786
|
-
}
|
|
787
|
-
});
|
|
788
|
-
}));
|
|
789
|
-
if (handledFile) {
|
|
790
|
-
// only validate if there was a legitimate change
|
|
791
|
-
await this.validateAllThrottled();
|
|
792
|
-
}
|
|
287
|
+
async onDocumentClose(event) {
|
|
288
|
+
this.logger.debug('onDocumentClose', event.document.uri);
|
|
289
|
+
await this.projectManager.handleFileClose({
|
|
290
|
+
srcPath: util_1.util.uriToPath(event.document.uri)
|
|
291
|
+
});
|
|
793
292
|
}
|
|
794
293
|
/**
|
|
795
|
-
*
|
|
796
|
-
* any file changes you receive with no unexpected side-effects
|
|
797
|
-
* @returns true if the file was handled by this project, false if it was not
|
|
294
|
+
* Provide a list of completion items based on the current cursor position
|
|
798
295
|
*/
|
|
799
|
-
async
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
return true;
|
|
809
|
-
}
|
|
810
|
-
else {
|
|
811
|
-
return false;
|
|
812
|
-
}
|
|
813
|
-
//created
|
|
814
|
-
}
|
|
815
|
-
else if (change.type === node_1.FileChangeType.Created) {
|
|
816
|
-
// thanks to `onDidChangeWatchedFiles`, we can safely assume that all "Created" changes are file paths, (not directories)
|
|
817
|
-
//get the dest path for this file.
|
|
818
|
-
let destPath = roku_deploy_1.rokuDeploy.getDestPath(change.srcPath, options.files, rootDir);
|
|
819
|
-
const newFileContents = await this.getChangedFileContents(project, program, change.srcPath);
|
|
820
|
-
//if we got a dest path, then the program wants this file
|
|
821
|
-
if (destPath && newFileContents !== null) {
|
|
822
|
-
program.setFile({
|
|
823
|
-
src: change.srcPath,
|
|
824
|
-
dest: roku_deploy_1.rokuDeploy.getDestPath(change.srcPath, options.files, rootDir)
|
|
825
|
-
}, await project.builder.getFileContents(change.srcPath));
|
|
826
|
-
return true;
|
|
827
|
-
}
|
|
828
|
-
else {
|
|
829
|
-
//no dest path means the program doesn't want this file
|
|
830
|
-
return false;
|
|
831
|
-
}
|
|
832
|
-
//changed
|
|
833
|
-
}
|
|
834
|
-
else if (program.hasFile(change.srcPath)) {
|
|
835
|
-
//sometimes "changed" events are emitted on files that were actually deleted,
|
|
836
|
-
//so determine file existance and act accordingly
|
|
837
|
-
if (await util_1.util.pathExists(change.srcPath)) {
|
|
838
|
-
const newFileContents = await this.getChangedFileContents(project, program, change.srcPath);
|
|
839
|
-
if (!newFileContents) {
|
|
840
|
-
// file did not actually change
|
|
841
|
-
return false;
|
|
842
|
-
}
|
|
843
|
-
program.setFile({
|
|
844
|
-
src: change.srcPath,
|
|
845
|
-
dest: roku_deploy_1.rokuDeploy.getDestPath(change.srcPath, options.files, rootDir)
|
|
846
|
-
}, newFileContents);
|
|
847
|
-
}
|
|
848
|
-
else {
|
|
849
|
-
program.removeFile(change.srcPath);
|
|
850
|
-
}
|
|
851
|
-
return true;
|
|
852
|
-
}
|
|
296
|
+
async onCompletion(params, cancellationToken, workDoneProgress, resultProgress) {
|
|
297
|
+
this.logger.debug('onCompletion', params, cancellationToken);
|
|
298
|
+
const srcPath = util_1.util.uriToPath(params.textDocument.uri);
|
|
299
|
+
const completions = await this.projectManager.getCompletions({
|
|
300
|
+
srcPath: srcPath,
|
|
301
|
+
position: params.position,
|
|
302
|
+
cancellationToken: cancellationToken
|
|
303
|
+
});
|
|
304
|
+
return completions;
|
|
853
305
|
}
|
|
854
306
|
/**
|
|
855
|
-
*
|
|
856
|
-
*
|
|
857
|
-
*
|
|
307
|
+
* Get a list of workspaces, and their configurations.
|
|
308
|
+
* Get only the settings for the workspace that are relevant to the language server. We do this so we can cache this object for use in change detection in the future.
|
|
858
309
|
*/
|
|
859
|
-
async
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
else if ((0, reflection_1.isAssetFile)(existingFile) && existingFile.data.isValueLoaded) {
|
|
874
|
-
if (existingFile.data.value.toString() === newFileContents.toString()) {
|
|
875
|
-
// file did not actually change
|
|
876
|
-
return null;
|
|
310
|
+
async getWorkspaceConfigs() {
|
|
311
|
+
var _a;
|
|
312
|
+
//get all workspace folders (we'll use these to get settings)
|
|
313
|
+
let workspaces = await Promise.all(((_a = await this.connection.workspace.getWorkspaceFolders()) !== null && _a !== void 0 ? _a : []).map(async (x) => {
|
|
314
|
+
var _a, _b, _c;
|
|
315
|
+
const workspaceFolder = util_1.util.uriToPath(x.uri);
|
|
316
|
+
const brightscriptConfig = await this.getClientConfiguration(x.uri, 'brightscript');
|
|
317
|
+
return {
|
|
318
|
+
workspaceFolder: workspaceFolder,
|
|
319
|
+
excludePatterns: await this.getWorkspaceExcludeGlobs(workspaceFolder),
|
|
320
|
+
bsconfigPath: brightscriptConfig.configFile,
|
|
321
|
+
languageServer: {
|
|
322
|
+
enableThreading: (_b = (_a = brightscriptConfig.languageServer) === null || _a === void 0 ? void 0 : _a.enableThreading) !== null && _b !== void 0 ? _b : LanguageServer.enableThreadingDefault,
|
|
323
|
+
logLevel: (_c = brightscriptConfig === null || brightscriptConfig === void 0 ? void 0 : brightscriptConfig.languageServer) === null || _c === void 0 ? void 0 : _c.logLevel
|
|
877
324
|
}
|
|
878
|
-
}
|
|
325
|
+
};
|
|
326
|
+
}));
|
|
327
|
+
return workspaces;
|
|
328
|
+
}
|
|
329
|
+
async onDidChangeConfiguration(args) {
|
|
330
|
+
this.logger.log('onDidChangeConfiguration', 'Reloading all projects');
|
|
331
|
+
const configs = new Map((await this.getWorkspaceConfigs()).map(x => [x.workspaceFolder, x]));
|
|
332
|
+
//find any changed configs. This includes newly created workspaces, deleted workspaces, etc.
|
|
333
|
+
//TODO: enhance this to only reload specific projects, depending on the change
|
|
334
|
+
if (!isEqual(configs, this.workspaceConfigsCache)) {
|
|
335
|
+
//now that we've processed any config diffs, update the cached copy of them
|
|
336
|
+
this.workspaceConfigsCache = configs;
|
|
337
|
+
//if configuration changed, rebuild the path filterer
|
|
338
|
+
await this.rebuildPathFilterer();
|
|
339
|
+
//if the user changes any user/workspace config settings, just mass-reload all projects
|
|
340
|
+
await this.syncProjects(true);
|
|
879
341
|
}
|
|
880
|
-
return newFileContents;
|
|
881
342
|
}
|
|
882
343
|
async onHover(params) {
|
|
883
|
-
|
|
884
|
-
//ensure programs are initialized
|
|
885
|
-
await this.waitAllProjectFirstRuns();
|
|
344
|
+
this.logger.debug('onHover', params);
|
|
886
345
|
const srcPath = util_1.util.uriToPath(params.textDocument.uri);
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
//get hovers from all projects
|
|
890
|
-
.map((x) => x.builder.program.getHover(srcPath, params.position))
|
|
891
|
-
//flatten to a single list
|
|
892
|
-
.flat();
|
|
893
|
-
const contents = [
|
|
894
|
-
...(hovers !== null && hovers !== void 0 ? hovers : [])
|
|
895
|
-
//pull all hover contents out into a flag array of strings
|
|
896
|
-
.map(x => {
|
|
897
|
-
return Array.isArray(x === null || x === void 0 ? void 0 : x.contents) ? x === null || x === void 0 ? void 0 : x.contents : [x === null || x === void 0 ? void 0 : x.contents];
|
|
898
|
-
}).flat()
|
|
899
|
-
//remove nulls
|
|
900
|
-
.filter(x => !!x)
|
|
901
|
-
//dedupe hovers across all projects
|
|
902
|
-
.reduce((set, content) => set.add(content), new Set()).values()
|
|
903
|
-
];
|
|
904
|
-
if (contents.length > 0) {
|
|
905
|
-
let hover = {
|
|
906
|
-
//use the range from the first hover
|
|
907
|
-
range: (_a = hovers[0]) === null || _a === void 0 ? void 0 : _a.range,
|
|
908
|
-
//the contents of all hovers
|
|
909
|
-
contents: contents
|
|
910
|
-
};
|
|
911
|
-
return hover;
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
async onDocumentClose(event) {
|
|
915
|
-
const { document } = event;
|
|
916
|
-
let filePath = vscode_uri_1.URI.parse(document.uri).fsPath;
|
|
917
|
-
let standaloneFileProject = this.standaloneFileProjects[filePath];
|
|
918
|
-
//if this was a temp file, close it
|
|
919
|
-
if (standaloneFileProject) {
|
|
920
|
-
await standaloneFileProject.firstRunPromise;
|
|
921
|
-
standaloneFileProject.builder.dispose();
|
|
922
|
-
delete this.standaloneFileProjects[filePath];
|
|
923
|
-
await this.sendDiagnostics();
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
async validateTextDocument(event) {
|
|
927
|
-
const { document } = event;
|
|
928
|
-
//ensure programs are initialized
|
|
929
|
-
await this.waitAllProjectFirstRuns();
|
|
930
|
-
let filePath = vscode_uri_1.URI.parse(document.uri).fsPath;
|
|
931
|
-
try {
|
|
932
|
-
//throttle file processing. first call is run immediately, and then the last call is processed.
|
|
933
|
-
await this.keyedThrottler.run(filePath, () => {
|
|
934
|
-
var _a;
|
|
935
|
-
let documentText = document.getText();
|
|
936
|
-
for (const project of this.getProjects()) {
|
|
937
|
-
//only add or replace existing files. All of the files in the project should
|
|
938
|
-
//have already been loaded by other means
|
|
939
|
-
if (project.builder.program.hasFile(filePath)) {
|
|
940
|
-
let rootDir = (_a = project.builder.program.options.rootDir) !== null && _a !== void 0 ? _a : project.builder.program.options.cwd;
|
|
941
|
-
let dest = roku_deploy_1.rokuDeploy.getDestPath(filePath, project.builder.program.options.files, rootDir);
|
|
942
|
-
project.builder.program.setFile({
|
|
943
|
-
src: filePath,
|
|
944
|
-
dest: dest
|
|
945
|
-
}, documentText);
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
});
|
|
949
|
-
// validate all projects
|
|
950
|
-
await this.validateAllThrottled();
|
|
951
|
-
}
|
|
952
|
-
catch (e) {
|
|
953
|
-
await this.sendCriticalFailure(`Critical error parsing/validating ${filePath}: ${e.message}`);
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
async validateAll() {
|
|
957
|
-
var _a;
|
|
958
|
-
try {
|
|
959
|
-
//synchronize parsing for open files that were included/excluded from projects
|
|
960
|
-
await this.synchronizeStandaloneProjects();
|
|
961
|
-
let projects = this.getProjects();
|
|
962
|
-
//validate all programs
|
|
963
|
-
await Promise.all(projects.map((project) => {
|
|
964
|
-
project.builder.program.validate();
|
|
965
|
-
return project;
|
|
966
|
-
}));
|
|
967
|
-
}
|
|
968
|
-
catch (e) {
|
|
969
|
-
this.connection.console.error(e);
|
|
970
|
-
await this.sendCriticalFailure(`Critical error validating project: ${e.message}${(_a = e.stack) !== null && _a !== void 0 ? _a : ''}`);
|
|
971
|
-
}
|
|
346
|
+
const result = await this.projectManager.getHover({ srcPath: srcPath, position: params.position });
|
|
347
|
+
return result;
|
|
972
348
|
}
|
|
973
349
|
async onWorkspaceSymbol(params) {
|
|
974
|
-
|
|
975
|
-
const
|
|
976
|
-
|
|
977
|
-
})), c => c);
|
|
978
|
-
// Remove duplicates
|
|
979
|
-
const allSymbols = Object.values(results.reduce((map, symbol) => {
|
|
980
|
-
const key = symbol.location.uri + symbol.name;
|
|
981
|
-
map[key] = symbol;
|
|
982
|
-
return map;
|
|
983
|
-
}, {}));
|
|
984
|
-
return allSymbols;
|
|
350
|
+
this.logger.debug('onWorkspaceSymbol', params);
|
|
351
|
+
const result = await this.projectManager.getWorkspaceSymbol();
|
|
352
|
+
return result;
|
|
985
353
|
}
|
|
986
354
|
async onDocumentSymbol(params) {
|
|
987
|
-
|
|
988
|
-
await this.keyedThrottler.onIdleOnce(util_1.util.uriToPath(params.textDocument.uri), true);
|
|
355
|
+
this.logger.debug('onDocumentSymbol', params);
|
|
989
356
|
const srcPath = util_1.util.uriToPath(params.textDocument.uri);
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
if ((0, reflection_1.isBrsFile)(file)) {
|
|
993
|
-
return file.getDocumentSymbols();
|
|
994
|
-
}
|
|
995
|
-
}
|
|
357
|
+
const result = await this.projectManager.getDocumentSymbol({ srcPath: srcPath });
|
|
358
|
+
return result;
|
|
996
359
|
}
|
|
997
360
|
async onDefinition(params) {
|
|
998
|
-
|
|
361
|
+
this.logger.debug('onDefinition', params);
|
|
999
362
|
const srcPath = util_1.util.uriToPath(params.textDocument.uri);
|
|
1000
|
-
const
|
|
1001
|
-
|
|
1002
|
-
})), c => c);
|
|
1003
|
-
return results;
|
|
363
|
+
const result = this.projectManager.getDefinition({ srcPath: srcPath, position: params.position });
|
|
364
|
+
return result;
|
|
1004
365
|
}
|
|
1005
366
|
async onSignatureHelp(params) {
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
const
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
const signatures = util_1.util.flatMap(await Promise.all(this.getProjects().map(project => project.builder.program.getSignatureHelp(filepath, params.position))), c => c);
|
|
1012
|
-
const activeSignature = signatures.length > 0 ? 0 : null;
|
|
1013
|
-
const activeParameter = activeSignature !== null ? (_a = signatures[activeSignature]) === null || _a === void 0 ? void 0 : _a.index : null;
|
|
1014
|
-
let results = {
|
|
1015
|
-
signatures: signatures.map((s) => s.signature),
|
|
1016
|
-
activeSignature: activeSignature,
|
|
1017
|
-
activeParameter: activeParameter
|
|
1018
|
-
};
|
|
1019
|
-
return results;
|
|
367
|
+
this.logger.debug('onSignatureHelp', params);
|
|
368
|
+
const srcPath = util_1.util.uriToPath(params.textDocument.uri);
|
|
369
|
+
const result = await this.projectManager.getSignatureHelp({ srcPath: srcPath, position: params.position });
|
|
370
|
+
if (result) {
|
|
371
|
+
return result;
|
|
1020
372
|
}
|
|
1021
|
-
|
|
1022
|
-
this.connection.console.error(`error in onSignatureHelp: ${(_c = (_b = e.stack) !== null && _b !== void 0 ? _b : e.message) !== null && _c !== void 0 ? _c : e}`);
|
|
373
|
+
else {
|
|
1023
374
|
return {
|
|
1024
375
|
signatures: [],
|
|
1025
|
-
activeSignature:
|
|
1026
|
-
activeParameter:
|
|
376
|
+
activeSignature: null,
|
|
377
|
+
activeParameter: null
|
|
1027
378
|
};
|
|
1028
379
|
}
|
|
1029
380
|
}
|
|
1030
381
|
async onReferences(params) {
|
|
1031
|
-
|
|
1032
|
-
const position = params.position;
|
|
382
|
+
this.logger.debug('onReferences', params);
|
|
1033
383
|
const srcPath = util_1.util.uriToPath(params.textDocument.uri);
|
|
1034
|
-
const
|
|
1035
|
-
|
|
1036
|
-
})), c => c !== null && c !== void 0 ? c : []);
|
|
1037
|
-
return results.filter((r) => r);
|
|
1038
|
-
}
|
|
1039
|
-
onValidateSettled() {
|
|
1040
|
-
return Promise.all([
|
|
1041
|
-
//wait for the validator to start running (or timeout if it never did)
|
|
1042
|
-
this.validateThrottler.onRunOnce(100),
|
|
1043
|
-
//wait for the validator to stop running (or resolve immediately if it's already idle)
|
|
1044
|
-
this.validateThrottler.onIdleOnce(true)
|
|
1045
|
-
]);
|
|
384
|
+
const result = await this.projectManager.getReferences({ srcPath: srcPath, position: params.position });
|
|
385
|
+
return result !== null && result !== void 0 ? result : [];
|
|
1046
386
|
}
|
|
1047
387
|
async onFullSemanticTokens(params) {
|
|
1048
|
-
|
|
1049
|
-
//wait for the file to settle (in case there are multiple file changes in quick succession)
|
|
1050
|
-
await this.keyedThrottler.onIdleOnce(util_1.util.uriToPath(params.textDocument.uri), true);
|
|
1051
|
-
// make sure validation is complete
|
|
1052
|
-
await this.validateAllThrottled();
|
|
1053
|
-
//wait for the validation cycle to settle
|
|
1054
|
-
await this.onValidateSettled();
|
|
388
|
+
this.logger.debug('onFullSemanticTokens', params);
|
|
1055
389
|
const srcPath = util_1.util.uriToPath(params.textDocument.uri);
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
if (semanticTokens !== undefined) {
|
|
1061
|
-
return {
|
|
1062
|
-
data: (0, SemanticTokenUtils_1.encodeSemanticTokens)(semanticTokens)
|
|
1063
|
-
};
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
390
|
+
const result = await this.projectManager.getSemanticTokens({ srcPath: srcPath });
|
|
391
|
+
return {
|
|
392
|
+
data: (0, SemanticTokenUtils_1.encodeSemanticTokens)(result)
|
|
393
|
+
};
|
|
1067
394
|
}
|
|
1068
|
-
async
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
const patch = this.diagnosticCollection.getPatch(this.projects);
|
|
1074
|
-
for (let fileUri in patch) {
|
|
1075
|
-
const diagnostics = patch[fileUri].map(d => util_1.util.toDiagnostic(d, fileUri));
|
|
1076
|
-
await this.connection.sendDiagnostics({
|
|
1077
|
-
uri: fileUri,
|
|
1078
|
-
diagnostics: diagnostics
|
|
1079
|
-
});
|
|
1080
|
-
}
|
|
1081
|
-
});
|
|
395
|
+
async onCodeAction(params) {
|
|
396
|
+
this.logger.debug('onCodeAction', params);
|
|
397
|
+
const srcPath = util_1.util.uriToPath(params.textDocument.uri);
|
|
398
|
+
const result = await this.projectManager.getCodeActions({ srcPath: srcPath, range: params.range });
|
|
399
|
+
return result;
|
|
1082
400
|
}
|
|
1083
401
|
async onExecuteCommand(params) {
|
|
1084
|
-
|
|
402
|
+
this.logger.debug('onExecuteCommand', params);
|
|
1085
403
|
if (params.command === CustomCommands.TranspileFile) {
|
|
1086
|
-
const
|
|
404
|
+
const args = {
|
|
405
|
+
srcPath: params.arguments[0]
|
|
406
|
+
};
|
|
407
|
+
const result = await this.projectManager.transpileFile(args);
|
|
1087
408
|
//back-compat: include `pathAbsolute` property so older vscode versions still work
|
|
1088
409
|
result.pathAbsolute = result.srcPath;
|
|
1089
410
|
return result;
|
|
1090
411
|
}
|
|
1091
412
|
}
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
413
|
+
/**
|
|
414
|
+
* Establish a connection to the client if not already connected
|
|
415
|
+
*/
|
|
416
|
+
establishConnection() {
|
|
417
|
+
if (!this.connection) {
|
|
418
|
+
this.connection = (0, node_1.createConnection)(node_1.ProposedFeatures.all);
|
|
419
|
+
}
|
|
420
|
+
return this.connection;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Send a new busy status notification to the client based on the current busy status
|
|
424
|
+
*/
|
|
425
|
+
sendBusyStatus() {
|
|
426
|
+
var _a;
|
|
427
|
+
this.busyStatusIndex = ++this.busyStatusIndex <= 0 ? 0 : this.busyStatusIndex;
|
|
428
|
+
(_a = this.connection.sendNotification(NotificationName.busyStatus, {
|
|
429
|
+
status: this.projectManager.busyStatusTracker.status,
|
|
430
|
+
timestamp: Date.now(),
|
|
431
|
+
index: this.busyStatusIndex,
|
|
432
|
+
activeRuns: [
|
|
433
|
+
//extract only specific information from the active run so we know what's going on
|
|
434
|
+
...this.projectManager.busyStatusTracker.activeRuns.map(x => {
|
|
435
|
+
var _a;
|
|
436
|
+
return ({
|
|
437
|
+
scope: (_a = x.scope) === null || _a === void 0 ? void 0 : _a.projectIdentifier,
|
|
438
|
+
label: x.label,
|
|
439
|
+
startTime: x.startTime.getTime()
|
|
440
|
+
});
|
|
441
|
+
})
|
|
442
|
+
]
|
|
443
|
+
})) === null || _a === void 0 ? void 0 : _a.catch(logAndIgnoreError);
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Populate the path filterer with the client's include/exclude lists and the projects include lists
|
|
447
|
+
* @returns the instance of the path filterer
|
|
448
|
+
*/
|
|
449
|
+
async rebuildPathFilterer() {
|
|
450
|
+
var _a;
|
|
451
|
+
//dispose of any previous pathFilterer disposables
|
|
452
|
+
(_a = this.pathFiltererDisposables) === null || _a === void 0 ? void 0 : _a.forEach(dispose => dispose());
|
|
453
|
+
//keep track of all the pathFilterer disposables so we can dispose them later
|
|
454
|
+
this.pathFiltererDisposables = [];
|
|
455
|
+
const workspaceConfigs = await this.getWorkspaceConfigs();
|
|
456
|
+
await Promise.all(workspaceConfigs.map(async (workspaceConfig) => {
|
|
457
|
+
const rootDir = util_1.util.uriToPath(workspaceConfig.workspaceFolder);
|
|
458
|
+
//always exclude everything from these common folders
|
|
459
|
+
this.pathFiltererDisposables.push(this.pathFilterer.registerExcludeList(rootDir, [
|
|
460
|
+
'**/node_modules/**/*',
|
|
461
|
+
'**/.git/**/*',
|
|
462
|
+
'out/**/*',
|
|
463
|
+
'**/.roku-deploy-staging/**/*'
|
|
464
|
+
]));
|
|
465
|
+
//get any `files.exclude` patterns from the client from this workspace
|
|
466
|
+
this.pathFiltererDisposables.push(this.pathFilterer.registerExcludeList(rootDir, workspaceConfig.excludePatterns));
|
|
467
|
+
//get any .gitignore patterns from the client from this workspace
|
|
468
|
+
const gitignorePath = path.resolve(rootDir, '.gitignore');
|
|
469
|
+
if (await fsExtra.pathExists(gitignorePath)) {
|
|
470
|
+
const matcher = (0, ignore_1.default)({ ignoreCase: true }).add(fsExtra.readFileSync(gitignorePath).toString());
|
|
471
|
+
this.pathFiltererDisposables.push(this.pathFilterer.registerExcludeMatcher((p) => {
|
|
472
|
+
const relPath = path.relative(rootDir, p);
|
|
473
|
+
if (ignore_1.default.isPathValid(relPath)) {
|
|
474
|
+
return matcher.test(relPath).ignored;
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
//we do not have a valid relative path, so we cannot determine if it is ignored...thus it is NOT ignored
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
480
|
+
}));
|
|
1099
481
|
}
|
|
482
|
+
}));
|
|
483
|
+
this.logger.log('pathFilterer successfully reconstructed');
|
|
484
|
+
return this.pathFilterer;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Ask the client for the list of `files.exclude` patterns. Useful when determining if we should process a file
|
|
488
|
+
*/
|
|
489
|
+
async getWorkspaceExcludeGlobs(workspaceFolder) {
|
|
490
|
+
var _a;
|
|
491
|
+
const config = await this.getClientConfiguration(workspaceFolder, 'files');
|
|
492
|
+
const result = Object
|
|
493
|
+
.keys((_a = config === null || config === void 0 ? void 0 : config.exclude) !== null && _a !== void 0 ? _a : {})
|
|
494
|
+
.filter(x => { var _a; return (_a = config === null || config === void 0 ? void 0 : config.exclude) === null || _a === void 0 ? void 0 : _a[x]; })
|
|
495
|
+
//vscode files.exclude patterns support ignoring folders without needing to add `**/*`. So for our purposes, we need to
|
|
496
|
+
//append **/* to everything without a file extension or magic at the end
|
|
497
|
+
.map(pattern => [
|
|
498
|
+
//send the pattern as-is (this handles weird cases and exact file matches)
|
|
499
|
+
pattern,
|
|
500
|
+
//treat the pattern as a directory (no harm in doing this because if it's a file, the pattern will just never match anything)
|
|
501
|
+
`${pattern}/**/*`
|
|
502
|
+
])
|
|
503
|
+
.flat(1);
|
|
504
|
+
return result;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Ask the project manager to sync all projects found within the list of workspaces
|
|
508
|
+
* @param forceReload if true, all projects are discarded and recreated from scratch
|
|
509
|
+
*/
|
|
510
|
+
async syncProjects(forceReload = false) {
|
|
511
|
+
const workspaces = await this.getWorkspaceConfigs();
|
|
512
|
+
await this.projectManager.syncProjects(workspaces, forceReload);
|
|
513
|
+
//set our logLevel to the most verbose log level found across all projects and workspaces
|
|
514
|
+
await this.syncLogLevel();
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Given a workspaceFolder path, get the specified configuration from the client (if applicable).
|
|
518
|
+
* Be sure to use optional chaining to traverse the result in case that configuration doesn't exist or the client doesn't support `getConfiguration`
|
|
519
|
+
* @param workspaceFolder the folder for the workspace in the client
|
|
520
|
+
*/
|
|
521
|
+
async getClientConfiguration(workspaceFolder, section) {
|
|
522
|
+
const scopeUri = util_1.util.pathToUri(workspaceFolder);
|
|
523
|
+
let config = {};
|
|
524
|
+
//if the client supports configuration, look for config group called "brightscript"
|
|
525
|
+
if (this.hasConfigurationCapability) {
|
|
526
|
+
config = await this.connection.workspace.getConfiguration({
|
|
527
|
+
scopeUri: scopeUri,
|
|
528
|
+
section: section
|
|
529
|
+
});
|
|
1100
530
|
}
|
|
531
|
+
return config;
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Send a critical failure notification to the client, which should show a notification of some kind
|
|
535
|
+
*/
|
|
536
|
+
sendCriticalFailure(message) {
|
|
537
|
+
this.connection.sendNotification('critical-failure', message).catch(logAndIgnoreError);
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Send diagnostics to the client
|
|
541
|
+
*/
|
|
542
|
+
async sendDiagnostics(options) {
|
|
543
|
+
const patch = this.diagnosticCollection.getPatch(options.project.projectNumber, options.diagnostics);
|
|
544
|
+
await Promise.all(Object.keys(patch).map(async (srcPath) => {
|
|
545
|
+
const uri = vscode_uri_1.URI.file(srcPath).toString();
|
|
546
|
+
const diagnostics = patch[srcPath].map(d => util_1.util.toDiagnostic(d, uri));
|
|
547
|
+
await this.connection.sendDiagnostics({
|
|
548
|
+
uri: uri,
|
|
549
|
+
diagnostics: diagnostics
|
|
550
|
+
});
|
|
551
|
+
}));
|
|
1101
552
|
}
|
|
1102
553
|
dispose() {
|
|
1103
|
-
var _a;
|
|
554
|
+
var _a, _b, _c;
|
|
1104
555
|
(_a = this.loggerSubscription) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
1105
|
-
this.
|
|
556
|
+
(_c = (_b = this.projectManager) === null || _b === void 0 ? void 0 : _b.dispose) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
1106
557
|
}
|
|
1107
558
|
}
|
|
559
|
+
/**
|
|
560
|
+
* The default threading setting for the language server. Can be overridden by per-workspace settings
|
|
561
|
+
*/
|
|
562
|
+
LanguageServer.enableThreadingDefault = true;
|
|
1108
563
|
__decorate([
|
|
1109
564
|
AddStackToErrorMessage
|
|
1110
565
|
], LanguageServer.prototype, "onInitialize", null);
|
|
1111
566
|
__decorate([
|
|
1112
|
-
|
|
1113
|
-
], LanguageServer.prototype, "getProjectPaths", null);
|
|
1114
|
-
__decorate([
|
|
1115
|
-
TrackBusyStatus
|
|
1116
|
-
], LanguageServer.prototype, "syncProjects", null);
|
|
1117
|
-
__decorate([
|
|
1118
|
-
AddStackToErrorMessage,
|
|
1119
|
-
TrackBusyStatus
|
|
567
|
+
AddStackToErrorMessage
|
|
1120
568
|
], LanguageServer.prototype, "onInitialized", null);
|
|
1121
569
|
__decorate([
|
|
1122
|
-
|
|
1123
|
-
], LanguageServer.prototype, "
|
|
570
|
+
AddStackToErrorMessage
|
|
571
|
+
], LanguageServer.prototype, "onTextDocumentDidChangeContent", null);
|
|
1124
572
|
__decorate([
|
|
1125
|
-
AddStackToErrorMessage
|
|
1126
|
-
|
|
1127
|
-
], LanguageServer.prototype, "onCompletion", null);
|
|
573
|
+
AddStackToErrorMessage
|
|
574
|
+
], LanguageServer.prototype, "onDidChangeWatchedFiles", null);
|
|
1128
575
|
__decorate([
|
|
1129
576
|
AddStackToErrorMessage
|
|
1130
|
-
], LanguageServer.prototype, "
|
|
577
|
+
], LanguageServer.prototype, "onDocumentClose", null);
|
|
1131
578
|
__decorate([
|
|
1132
|
-
AddStackToErrorMessage
|
|
1133
|
-
|
|
1134
|
-
], LanguageServer.prototype, "onCodeAction", null);
|
|
579
|
+
AddStackToErrorMessage
|
|
580
|
+
], LanguageServer.prototype, "onCompletion", null);
|
|
1135
581
|
__decorate([
|
|
1136
582
|
AddStackToErrorMessage
|
|
1137
583
|
], LanguageServer.prototype, "onDidChangeConfiguration", null);
|
|
1138
|
-
__decorate([
|
|
1139
|
-
AddStackToErrorMessage,
|
|
1140
|
-
TrackBusyStatus
|
|
1141
|
-
], LanguageServer.prototype, "onDidChangeWatchedFiles", null);
|
|
1142
584
|
__decorate([
|
|
1143
585
|
AddStackToErrorMessage
|
|
1144
586
|
], LanguageServer.prototype, "onHover", null);
|
|
1145
587
|
__decorate([
|
|
1146
588
|
AddStackToErrorMessage
|
|
1147
|
-
], LanguageServer.prototype, "onDocumentClose", null);
|
|
1148
|
-
__decorate([
|
|
1149
|
-
AddStackToErrorMessage,
|
|
1150
|
-
TrackBusyStatus
|
|
1151
|
-
], LanguageServer.prototype, "validateTextDocument", null);
|
|
1152
|
-
__decorate([
|
|
1153
|
-
TrackBusyStatus
|
|
1154
|
-
], LanguageServer.prototype, "validateAll", null);
|
|
1155
|
-
__decorate([
|
|
1156
|
-
AddStackToErrorMessage,
|
|
1157
|
-
TrackBusyStatus
|
|
1158
589
|
], LanguageServer.prototype, "onWorkspaceSymbol", null);
|
|
1159
590
|
__decorate([
|
|
1160
|
-
AddStackToErrorMessage
|
|
1161
|
-
TrackBusyStatus
|
|
591
|
+
AddStackToErrorMessage
|
|
1162
592
|
], LanguageServer.prototype, "onDocumentSymbol", null);
|
|
1163
593
|
__decorate([
|
|
1164
|
-
AddStackToErrorMessage
|
|
1165
|
-
TrackBusyStatus
|
|
594
|
+
AddStackToErrorMessage
|
|
1166
595
|
], LanguageServer.prototype, "onDefinition", null);
|
|
1167
596
|
__decorate([
|
|
1168
|
-
AddStackToErrorMessage
|
|
1169
|
-
TrackBusyStatus
|
|
597
|
+
AddStackToErrorMessage
|
|
1170
598
|
], LanguageServer.prototype, "onSignatureHelp", null);
|
|
1171
599
|
__decorate([
|
|
1172
|
-
AddStackToErrorMessage
|
|
1173
|
-
TrackBusyStatus
|
|
600
|
+
AddStackToErrorMessage
|
|
1174
601
|
], LanguageServer.prototype, "onReferences", null);
|
|
1175
602
|
__decorate([
|
|
1176
|
-
AddStackToErrorMessage
|
|
1177
|
-
TrackBusyStatus
|
|
603
|
+
AddStackToErrorMessage
|
|
1178
604
|
], LanguageServer.prototype, "onFullSemanticTokens", null);
|
|
1179
605
|
__decorate([
|
|
1180
|
-
AddStackToErrorMessage
|
|
1181
|
-
|
|
606
|
+
AddStackToErrorMessage
|
|
607
|
+
], LanguageServer.prototype, "onCodeAction", null);
|
|
608
|
+
__decorate([
|
|
609
|
+
AddStackToErrorMessage
|
|
1182
610
|
], LanguageServer.prototype, "onExecuteCommand", null);
|
|
1183
611
|
exports.LanguageServer = LanguageServer;
|
|
1184
612
|
var CustomCommands;
|
|
@@ -1220,16 +648,10 @@ function AddStackToErrorMessage(target, propertyKey, descriptor) {
|
|
|
1220
648
|
}
|
|
1221
649
|
};
|
|
1222
650
|
}
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
//wrapping the original method
|
|
1229
|
-
descriptor.value = function value(...args) {
|
|
1230
|
-
return this.busyStatusTracker.run(() => {
|
|
1231
|
-
return originalMethod.apply(this, args);
|
|
1232
|
-
}, originalMethod.name);
|
|
1233
|
-
};
|
|
651
|
+
function logAndIgnoreError(error) {
|
|
652
|
+
if (error === null || error === void 0 ? void 0 : error.stack) {
|
|
653
|
+
error.message = error.stack;
|
|
654
|
+
}
|
|
655
|
+
console.error(error);
|
|
1234
656
|
}
|
|
1235
657
|
//# sourceMappingURL=LanguageServer.js.map
|