@pellux/goodvibes-sdk 0.25.0 → 0.25.2

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.
Files changed (128) hide show
  1. package/dist/_internal/daemon/otlp-protobuf.d.ts +3 -0
  2. package/dist/_internal/daemon/otlp-protobuf.d.ts.map +1 -0
  3. package/dist/_internal/daemon/otlp-protobuf.js +968 -0
  4. package/dist/_internal/daemon/telemetry-routes.d.ts.map +1 -1
  5. package/dist/_internal/daemon/telemetry-routes.js +22 -13
  6. package/dist/_internal/platform/intelligence/lsp/service.d.ts.map +1 -1
  7. package/dist/_internal/platform/intelligence/lsp/service.js +18 -9
  8. package/dist/_internal/platform/providers/anthropic-vertex.d.ts.map +1 -1
  9. package/dist/_internal/platform/providers/anthropic-vertex.js +135 -2
  10. package/dist/_internal/platform/version.js +1 -1
  11. package/dist/_internal/platform/watchers/registry.d.ts.map +1 -1
  12. package/dist/_internal/platform/watchers/registry.js +4 -1
  13. package/package.json +9 -8
  14. package/vendor/bash-language-server/CHANGELOG.md +453 -0
  15. package/vendor/bash-language-server/GOODVIBES_PATCH.md +22 -0
  16. package/vendor/bash-language-server/README.md +230 -0
  17. package/vendor/bash-language-server/out/analyser.d.ts +187 -0
  18. package/vendor/bash-language-server/out/analyser.js +782 -0
  19. package/vendor/bash-language-server/out/analyser.js.map +1 -0
  20. package/vendor/bash-language-server/out/builtins.d.ts +2 -0
  21. package/vendor/bash-language-server/out/builtins.js +71 -0
  22. package/vendor/bash-language-server/out/builtins.js.map +1 -0
  23. package/vendor/bash-language-server/out/cli.d.ts +3 -0
  24. package/vendor/bash-language-server/out/cli.js +74 -0
  25. package/vendor/bash-language-server/out/cli.js.map +1 -0
  26. package/vendor/bash-language-server/out/config.d.ts +88 -0
  27. package/vendor/bash-language-server/out/config.js +96 -0
  28. package/vendor/bash-language-server/out/config.js.map +1 -0
  29. package/vendor/bash-language-server/out/executables.d.ts +19 -0
  30. package/vendor/bash-language-server/out/executables.js +86 -0
  31. package/vendor/bash-language-server/out/executables.js.map +1 -0
  32. package/vendor/bash-language-server/out/parser.d.ts +2 -0
  33. package/vendor/bash-language-server/out/parser.js +36 -0
  34. package/vendor/bash-language-server/out/parser.js.map +1 -0
  35. package/vendor/bash-language-server/out/reserved-words.d.ts +2 -0
  36. package/vendor/bash-language-server/out/reserved-words.js +33 -0
  37. package/vendor/bash-language-server/out/reserved-words.js.map +1 -0
  38. package/vendor/bash-language-server/out/server.d.ts +56 -0
  39. package/vendor/bash-language-server/out/server.js +756 -0
  40. package/vendor/bash-language-server/out/server.js.map +1 -0
  41. package/vendor/bash-language-server/out/shellcheck/config.d.ts +5 -0
  42. package/vendor/bash-language-server/out/shellcheck/config.js +17 -0
  43. package/vendor/bash-language-server/out/shellcheck/config.js.map +1 -0
  44. package/vendor/bash-language-server/out/shellcheck/directive.d.ts +18 -0
  45. package/vendor/bash-language-server/out/shellcheck/directive.js +62 -0
  46. package/vendor/bash-language-server/out/shellcheck/directive.js.map +1 -0
  47. package/vendor/bash-language-server/out/shellcheck/index.d.ts +22 -0
  48. package/vendor/bash-language-server/out/shellcheck/index.js +229 -0
  49. package/vendor/bash-language-server/out/shellcheck/index.js.map +1 -0
  50. package/vendor/bash-language-server/out/shellcheck/types.d.ts +175 -0
  51. package/vendor/bash-language-server/out/shellcheck/types.js +35 -0
  52. package/vendor/bash-language-server/out/shellcheck/types.js.map +1 -0
  53. package/vendor/bash-language-server/out/shfmt/index.d.ts +18 -0
  54. package/vendor/bash-language-server/out/shfmt/index.js +151 -0
  55. package/vendor/bash-language-server/out/shfmt/index.js.map +1 -0
  56. package/vendor/bash-language-server/out/snippets.d.ts +2 -0
  57. package/vendor/bash-language-server/out/snippets.js +671 -0
  58. package/vendor/bash-language-server/out/snippets.js.map +1 -0
  59. package/vendor/bash-language-server/out/types.d.ts +13 -0
  60. package/vendor/bash-language-server/out/types.js +12 -0
  61. package/vendor/bash-language-server/out/types.js.map +1 -0
  62. package/vendor/bash-language-server/out/util/array.d.ts +14 -0
  63. package/vendor/bash-language-server/out/util/array.js +36 -0
  64. package/vendor/bash-language-server/out/util/array.js.map +1 -0
  65. package/vendor/bash-language-server/out/util/async.d.ts +13 -0
  66. package/vendor/bash-language-server/out/util/async.js +24 -0
  67. package/vendor/bash-language-server/out/util/async.js.map +1 -0
  68. package/vendor/bash-language-server/out/util/declarations.d.ts +88 -0
  69. package/vendor/bash-language-server/out/util/declarations.js +295 -0
  70. package/vendor/bash-language-server/out/util/declarations.js.map +1 -0
  71. package/vendor/bash-language-server/out/util/discriminate.d.ts +1 -0
  72. package/vendor/bash-language-server/out/util/discriminate.js +7 -0
  73. package/vendor/bash-language-server/out/util/discriminate.js.map +1 -0
  74. package/vendor/bash-language-server/out/util/fs.d.ts +6 -0
  75. package/vendor/bash-language-server/out/util/fs.js +73 -0
  76. package/vendor/bash-language-server/out/util/fs.js.map +1 -0
  77. package/vendor/bash-language-server/out/util/logger.d.ts +35 -0
  78. package/vendor/bash-language-server/out/util/logger.js +105 -0
  79. package/vendor/bash-language-server/out/util/logger.js.map +1 -0
  80. package/vendor/bash-language-server/out/util/lsp.d.ts +5 -0
  81. package/vendor/bash-language-server/out/util/lsp.js +13 -0
  82. package/vendor/bash-language-server/out/util/lsp.js.map +1 -0
  83. package/vendor/bash-language-server/out/util/platform.d.ts +1 -0
  84. package/vendor/bash-language-server/out/util/platform.js +7 -0
  85. package/vendor/bash-language-server/out/util/platform.js.map +1 -0
  86. package/vendor/bash-language-server/out/util/sh.d.ts +16 -0
  87. package/vendor/bash-language-server/out/util/sh.js +132 -0
  88. package/vendor/bash-language-server/out/util/sh.js.map +1 -0
  89. package/vendor/bash-language-server/out/util/shebang.d.ts +10 -0
  90. package/vendor/bash-language-server/out/util/shebang.js +53 -0
  91. package/vendor/bash-language-server/out/util/shebang.js.map +1 -0
  92. package/vendor/bash-language-server/out/util/sourcing.d.ts +15 -0
  93. package/vendor/bash-language-server/out/util/sourcing.js +182 -0
  94. package/vendor/bash-language-server/out/util/sourcing.js.map +1 -0
  95. package/vendor/bash-language-server/out/util/tree-sitter.d.ts +22 -0
  96. package/vendor/bash-language-server/out/util/tree-sitter.js +110 -0
  97. package/vendor/bash-language-server/out/util/tree-sitter.js.map +1 -0
  98. package/vendor/bash-language-server/package.json +52 -0
  99. package/vendor/bash-language-server/parser.info +2 -0
  100. package/vendor/bash-language-server/tree-sitter-bash.wasm +0 -0
  101. package/dist/_internal/platform/runtime/contracts/index.d.ts +0 -40
  102. package/dist/_internal/platform/runtime/contracts/index.d.ts.map +0 -1
  103. package/dist/_internal/platform/runtime/contracts/index.js +0 -133
  104. package/dist/_internal/platform/runtime/contracts/migrations/index.d.ts +0 -75
  105. package/dist/_internal/platform/runtime/contracts/migrations/index.d.ts.map +0 -1
  106. package/dist/_internal/platform/runtime/contracts/migrations/index.js +0 -158
  107. package/dist/_internal/platform/runtime/contracts/migrations/schemas.d.ts +0 -57
  108. package/dist/_internal/platform/runtime/contracts/migrations/schemas.d.ts.map +0 -1
  109. package/dist/_internal/platform/runtime/contracts/migrations/schemas.js +0 -157
  110. package/dist/_internal/platform/runtime/contracts/types.d.ts +0 -123
  111. package/dist/_internal/platform/runtime/contracts/types.d.ts.map +0 -1
  112. package/dist/_internal/platform/runtime/contracts/types.js +0 -41
  113. package/dist/_internal/platform/runtime/contracts/validators/event-envelope.d.ts +0 -24
  114. package/dist/_internal/platform/runtime/contracts/validators/event-envelope.d.ts.map +0 -1
  115. package/dist/_internal/platform/runtime/contracts/validators/event-envelope.js +0 -104
  116. package/dist/_internal/platform/runtime/contracts/validators/index.d.ts +0 -11
  117. package/dist/_internal/platform/runtime/contracts/validators/index.d.ts.map +0 -1
  118. package/dist/_internal/platform/runtime/contracts/validators/index.js +0 -10
  119. package/dist/_internal/platform/runtime/contracts/validators/runtime-state.d.ts +0 -23
  120. package/dist/_internal/platform/runtime/contracts/validators/runtime-state.d.ts.map +0 -1
  121. package/dist/_internal/platform/runtime/contracts/validators/runtime-state.js +0 -101
  122. package/dist/_internal/platform/runtime/contracts/validators/session.d.ts +0 -24
  123. package/dist/_internal/platform/runtime/contracts/validators/session.d.ts.map +0 -1
  124. package/dist/_internal/platform/runtime/contracts/validators/session.js +0 -103
  125. package/dist/_internal/platform/runtime/contracts/version.d.ts +0 -84
  126. package/dist/_internal/platform/runtime/contracts/version.d.ts.map +0 -1
  127. package/dist/_internal/platform/runtime/contracts/version.js +0 -41
  128. package/scripts/postinstall-patch-minimatch.mjs +0 -285
@@ -0,0 +1,756 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getCommandOptions = getCommandOptions;
13
+ const node_child_process_1 = require("node:child_process");
14
+ const path = require("node:path");
15
+ const node_util_1 = require("node:util");
16
+ const TurndownService = require("turndown");
17
+ const LSP = require("vscode-languageserver/node");
18
+ const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
19
+ const analyser_1 = require("./analyser");
20
+ const Builtins = require("./builtins");
21
+ const config = require("./config");
22
+ const executables_1 = require("./executables");
23
+ const parser_1 = require("./parser");
24
+ const ReservedWords = require("./reserved-words");
25
+ const shellcheck_1 = require("./shellcheck");
26
+ const shfmt_1 = require("./shfmt");
27
+ const snippets_1 = require("./snippets");
28
+ const types_1 = require("./types");
29
+ const array_1 = require("./util/array");
30
+ const logger_1 = require("./util/logger");
31
+ const lsp_1 = require("./util/lsp");
32
+ const sh_1 = require("./util/sh");
33
+ const PARAMETER_EXPANSION_PREFIXES = new Set(['$', '${']);
34
+ const CONFIGURATION_SECTION = 'bashIde';
35
+ /**
36
+ * The BashServer glues together the separate components to implement
37
+ * the various parts of the Language Server Protocol.
38
+ */
39
+ class BashServer {
40
+ constructor({ analyzer, capabilities, connection, executables, linter, formatter, workspaceFolder, }) {
41
+ this.documents = new LSP.TextDocuments(vscode_languageserver_textdocument_1.TextDocument);
42
+ this.uriToCodeActions = {};
43
+ this.analyzer = analyzer;
44
+ this.clientCapabilities = capabilities;
45
+ this.connection = connection;
46
+ this.executables = executables;
47
+ this.linter = linter;
48
+ this.formatter = formatter;
49
+ this.workspaceFolder = workspaceFolder;
50
+ this.config = {}; // NOTE: configured in updateConfiguration
51
+ this.updateConfiguration(config.getDefaultConfiguration(), true);
52
+ }
53
+ /**
54
+ * Initialize the server based on a connection to the client and the protocols
55
+ * initialization parameters.
56
+ */
57
+ static initialize(connection_1, _a) {
58
+ return __awaiter(this, arguments, void 0, function* (connection, { rootPath, rootUri, capabilities }) {
59
+ (0, logger_1.setLogConnection)(connection);
60
+ logger_1.logger.debug('Initializing...');
61
+ const { PATH } = process.env;
62
+ const workspaceFolder = rootUri || rootPath || null;
63
+ if (!PATH) {
64
+ throw new Error('Expected PATH environment variable to be set');
65
+ }
66
+ const parser = yield (0, parser_1.initializeParser)();
67
+ const analyzer = new analyser_1.default({
68
+ parser,
69
+ workspaceFolder,
70
+ });
71
+ const executables = yield executables_1.default.fromPath(PATH);
72
+ const server = new BashServer({
73
+ analyzer,
74
+ capabilities,
75
+ connection,
76
+ executables,
77
+ workspaceFolder,
78
+ });
79
+ logger_1.logger.debug('Initialized');
80
+ return server;
81
+ });
82
+ }
83
+ /**
84
+ * The parts of the Language Server Protocol that we are currently supporting.
85
+ */
86
+ capabilities() {
87
+ return {
88
+ // For now we're using full-sync even though tree-sitter has great support
89
+ // for partial updates.
90
+ textDocumentSync: LSP.TextDocumentSyncKind.Full,
91
+ completionProvider: {
92
+ resolveProvider: true,
93
+ triggerCharacters: ['$', '{'],
94
+ },
95
+ hoverProvider: true,
96
+ documentHighlightProvider: true,
97
+ definitionProvider: true,
98
+ documentSymbolProvider: true,
99
+ workspaceSymbolProvider: true,
100
+ referencesProvider: true,
101
+ codeActionProvider: {
102
+ codeActionKinds: [LSP.CodeActionKind.QuickFix],
103
+ resolveProvider: false,
104
+ workDoneProgress: false,
105
+ },
106
+ renameProvider: { prepareProvider: true },
107
+ documentFormattingProvider: true,
108
+ };
109
+ }
110
+ /**
111
+ * Register handlers for the events from the Language Server Protocol that we
112
+ * care about.
113
+ */
114
+ register(connection) {
115
+ var _a, _b, _c, _d, _e;
116
+ const hasConfigurationCapability = !!((_b = (_a = this.clientCapabilities) === null || _a === void 0 ? void 0 : _a.workspace) === null || _b === void 0 ? void 0 : _b.configuration);
117
+ const canDynamicallyRegisterConfigurationChangeNotification = !!((_e = (_d = (_c = this.clientCapabilities) === null || _c === void 0 ? void 0 : _c.workspace) === null || _d === void 0 ? void 0 : _d.didChangeConfiguration) === null || _e === void 0 ? void 0 : _e.dynamicRegistration);
118
+ let currentDocument = null;
119
+ let initialized = false; // Whether the client finished initializing
120
+ this.documents.listen(this.connection);
121
+ this.documents.onDidChangeContent(({ document }) => {
122
+ // The content of a text document has changed. This event is emitted
123
+ // when the text document first opened or when its content has changed.
124
+ currentDocument = document;
125
+ if (initialized) {
126
+ this.analyzeAndLintDocument(document);
127
+ }
128
+ });
129
+ this.documents.onDidClose((event) => {
130
+ connection.sendDiagnostics({ uri: event.document.uri, diagnostics: [] });
131
+ delete this.uriToCodeActions[event.document.uri];
132
+ });
133
+ // Register all the handlers for the LSP events.
134
+ connection.onCodeAction(this.onCodeAction.bind(this));
135
+ connection.onCompletion(this.onCompletion.bind(this));
136
+ connection.onCompletionResolve(this.onCompletionResolve.bind(this));
137
+ connection.onDefinition(this.onDefinition.bind(this));
138
+ connection.onDocumentHighlight(this.onDocumentHighlight.bind(this));
139
+ connection.onDocumentSymbol(this.onDocumentSymbol.bind(this));
140
+ connection.onHover(this.onHover.bind(this));
141
+ connection.onReferences(this.onReferences.bind(this));
142
+ connection.onWorkspaceSymbol(this.onWorkspaceSymbol.bind(this));
143
+ connection.onPrepareRename(this.onPrepareRename.bind(this));
144
+ connection.onRenameRequest(this.onRenameRequest.bind(this));
145
+ connection.onDocumentFormatting(this.onDocumentFormatting.bind(this));
146
+ /**
147
+ * The initialized notification is sent from the client to the server after
148
+ * the client received the result of the initialize request but before the
149
+ * client is sending any other request or notification to the server.
150
+ * The server can use the initialized notification for example to dynamically
151
+ * register capabilities. The initialized notification may only be sent once.
152
+ */
153
+ connection.onInitialized(() => __awaiter(this, void 0, void 0, function* () {
154
+ const { config: environmentConfig, environmentVariablesUsed } = config.getConfigFromEnvironmentVariables();
155
+ if (environmentVariablesUsed.length > 0) {
156
+ this.updateConfiguration(environmentConfig);
157
+ logger_1.logger.warn(`Environment variable configuration is being deprecated, please use workspace configuration. The following environment variables were used: ${environmentVariablesUsed.join(', ')}`);
158
+ }
159
+ if (hasConfigurationCapability) {
160
+ // Register event for all configuration changes.
161
+ if (canDynamicallyRegisterConfigurationChangeNotification) {
162
+ connection.client.register(LSP.DidChangeConfigurationNotification.type, {
163
+ section: CONFIGURATION_SECTION,
164
+ });
165
+ }
166
+ // get current configuration from client
167
+ const configObject = yield connection.workspace.getConfiguration(CONFIGURATION_SECTION);
168
+ this.updateConfiguration(configObject);
169
+ logger_1.logger.debug('Configuration loaded from client');
170
+ }
171
+ initialized = true;
172
+ if (currentDocument) {
173
+ // If we already have a document, analyze it now that we're initialized
174
+ // and the linter is ready.
175
+ this.analyzeAndLintDocument(currentDocument);
176
+ }
177
+ // NOTE: we do not block the server initialization on this background analysis.
178
+ return { backgroundAnalysisCompleted: this.startBackgroundAnalysis() };
179
+ }));
180
+ // Respond to changes in the configuration.
181
+ connection.onDidChangeConfiguration(({ settings }) => {
182
+ const configChanged = this.updateConfiguration(settings[CONFIGURATION_SECTION]);
183
+ if (configChanged && initialized) {
184
+ logger_1.logger.debug('Configuration changed');
185
+ this.startBackgroundAnalysis();
186
+ if (currentDocument) {
187
+ this.uriToCodeActions[currentDocument.uri] = undefined;
188
+ this.analyzeAndLintDocument(currentDocument);
189
+ }
190
+ }
191
+ });
192
+ // FIXME: re-lint on workspace folder change
193
+ }
194
+ // ==================
195
+ // Internal functions
196
+ // ==================
197
+ startBackgroundAnalysis() {
198
+ return __awaiter(this, void 0, void 0, function* () {
199
+ const { workspaceFolder } = this;
200
+ if (workspaceFolder) {
201
+ return this.analyzer.initiateBackgroundAnalysis({
202
+ globPattern: this.config.globPattern,
203
+ backgroundAnalysisMaxFiles: this.config.backgroundAnalysisMaxFiles,
204
+ });
205
+ }
206
+ return Promise.resolve({ filesParsed: 0 });
207
+ });
208
+ }
209
+ updateConfiguration(configObject, isDefaultConfig = false) {
210
+ var _a;
211
+ if (typeof configObject === 'object' && configObject !== null) {
212
+ try {
213
+ const newConfig = config.ConfigSchema.parse(configObject);
214
+ if (!(0, node_util_1.isDeepStrictEqual)(this.config, newConfig)) {
215
+ this.config = newConfig;
216
+ // NOTE: I don't really like this... An alternative would be to pass in the
217
+ // shellcheck executable path when linting. We would need to handle
218
+ // resetting the canLint flag though.
219
+ const { shellcheckPath } = this.config;
220
+ if (!shellcheckPath) {
221
+ logger_1.logger.info('ShellCheck linting is disabled as "shellcheckPath" was not set');
222
+ this.linter = undefined;
223
+ }
224
+ else {
225
+ this.linter = new shellcheck_1.Linter({ executablePath: shellcheckPath });
226
+ }
227
+ const shfmtPath = (_a = this.config.shfmt) === null || _a === void 0 ? void 0 : _a.path;
228
+ if (!shfmtPath) {
229
+ logger_1.logger.info('Shfmt formatting is disabled as "shfmt.path" was not set');
230
+ this.formatter = undefined;
231
+ }
232
+ else {
233
+ this.formatter = new shfmt_1.Formatter({ executablePath: shfmtPath });
234
+ }
235
+ this.analyzer.setEnableSourceErrorDiagnostics(this.config.enableSourceErrorDiagnostics);
236
+ this.analyzer.setIncludeAllWorkspaceSymbols(this.config.includeAllWorkspaceSymbols);
237
+ if (!isDefaultConfig) {
238
+ // We skip setting the log level as the default configuration should
239
+ // not override the environment defined log level.
240
+ (0, logger_1.setLogLevel)(this.config.logLevel);
241
+ }
242
+ return true;
243
+ }
244
+ }
245
+ catch (err) {
246
+ logger_1.logger.warn(`updateConfiguration: failed with ${err}`);
247
+ }
248
+ }
249
+ return false;
250
+ }
251
+ /**
252
+ * Analyze and lint the given document.
253
+ */
254
+ analyzeAndLintDocument(document) {
255
+ return __awaiter(this, void 0, void 0, function* () {
256
+ const { uri } = document;
257
+ // Load the tree for the modified contents into the analyzer:
258
+ let diagnostics = this.analyzer.analyze({ uri, document });
259
+ // Run ShellCheck diagnostics:
260
+ if (this.linter) {
261
+ try {
262
+ const sourceFolders = this.workspaceFolder ? [this.workspaceFolder] : [];
263
+ const { diagnostics: lintDiagnostics, codeActions } = yield this.linter.lint(document, sourceFolders, this.config.shellcheckArguments);
264
+ diagnostics = diagnostics.concat(lintDiagnostics);
265
+ this.uriToCodeActions[uri] = codeActions;
266
+ }
267
+ catch (err) {
268
+ logger_1.logger.error(`Error while linting: ${err}`);
269
+ }
270
+ }
271
+ this.connection.sendDiagnostics({ uri, version: document.version, diagnostics });
272
+ });
273
+ }
274
+ logRequest({ request, params, word, }) {
275
+ const wordLog = word ? `"${word}"` : 'null';
276
+ logger_1.logger.debug(`${request} ${params.position.line}:${params.position.character} word=${wordLog}`);
277
+ }
278
+ getCompletionItemsForSymbols({ symbols, currentUri, }) {
279
+ return deduplicateSymbols({ symbols, currentUri }).map((symbol) => ({
280
+ label: symbol.name,
281
+ kind: symbolKindToCompletionKind(symbol.kind),
282
+ data: {
283
+ type: types_1.CompletionItemDataType.Symbol,
284
+ },
285
+ documentation: symbol.location.uri !== currentUri
286
+ ? this.getDocumentationForSymbol({
287
+ currentUri,
288
+ symbol,
289
+ })
290
+ : undefined,
291
+ }));
292
+ }
293
+ getDocumentationForSymbol({ currentUri, symbol, }) {
294
+ logger_1.logger.debug(`getDocumentationForSymbol: symbol=${symbol.name} uri=${symbol.location.uri}`);
295
+ const symbolUri = symbol.location.uri;
296
+ const symbolStartLine = symbol.location.range.start.line;
297
+ const commentAboveSymbol = this.analyzer.commentsAbove(symbolUri, symbolStartLine);
298
+ const symbolDocumentation = commentAboveSymbol ? `\n\n${commentAboveSymbol}` : '';
299
+ const hoverHeader = `${symbolKindToDescription(symbol.kind)}: **${symbol.name}**`;
300
+ const symbolLocation = symbolUri !== currentUri
301
+ ? `in ${path.relative(path.dirname(currentUri), symbolUri)}`
302
+ : `on line ${symbolStartLine + 1}`;
303
+ // TODO: An improvement could be to add show the symbol definition in the hover instead
304
+ // of the defined location – similar to how VSCode works for languages like TypeScript.
305
+ return getMarkdownContent(`${hoverHeader} - *defined ${symbolLocation}*${symbolDocumentation}`);
306
+ }
307
+ throwResponseError(message, code = LSP.LSPErrorCodes.RequestFailed) {
308
+ throw new LSP.ResponseError(code, message);
309
+ }
310
+ // ==============================
311
+ // Language server event handlers
312
+ // ==============================
313
+ onCodeAction(params) {
314
+ return __awaiter(this, void 0, void 0, function* () {
315
+ const codeActionsForUri = this.uriToCodeActions[params.textDocument.uri] || {};
316
+ const codeActions = params.context.diagnostics
317
+ .map(({ data }) => codeActionsForUri[data === null || data === void 0 ? void 0 : data.id])
318
+ .filter((action) => action != null);
319
+ logger_1.logger.debug(`onCodeAction: found ${codeActions.length} code action(s)`);
320
+ return codeActions;
321
+ });
322
+ }
323
+ onCompletion(params) {
324
+ var _a;
325
+ const word = this.analyzer.wordAtPointFromTextPosition(Object.assign(Object.assign({}, params), { position: {
326
+ line: params.position.line,
327
+ // Go one character back to get completion on the current word
328
+ character: Math.max(params.position.character - 1, 0),
329
+ } }));
330
+ this.logRequest({ request: 'onCompletion', params, word });
331
+ if (word === null || word === void 0 ? void 0 : word.startsWith('#')) {
332
+ // Inside a comment block
333
+ return [];
334
+ }
335
+ if (word === '{') {
336
+ // We should not complete when it is not prefixed by a $.
337
+ // This case needs to be here as "{" is a completionProvider triggerCharacter.
338
+ return [];
339
+ }
340
+ if (!word) {
341
+ const nextCharacter = (_a = this.analyzer.getDocument(params.textDocument.uri)) === null || _a === void 0 ? void 0 : _a.getText({
342
+ start: params.position,
343
+ end: Object.assign(Object.assign({}, params.position), { character: params.position.character + 1 }),
344
+ });
345
+ const isNextCharacterSpaceOrEmpty = nextCharacter === '' || nextCharacter === ' ';
346
+ if (!isNextCharacterSpaceOrEmpty) {
347
+ // We are in the middle of something, so don't complete
348
+ return [];
349
+ }
350
+ }
351
+ const currentUri = params.textDocument.uri;
352
+ // TODO: an improvement here would be to detect if the current word is
353
+ // not only a parameter expansion prefix, but also if the word is actually
354
+ // inside a parameter expansion (e.g. auto completing on a word $MY_VARIA).
355
+ const shouldCompleteOnVariables = word
356
+ ? PARAMETER_EXPANSION_PREFIXES.has(word)
357
+ : false;
358
+ const symbolCompletions = word === null
359
+ ? []
360
+ : this.getCompletionItemsForSymbols({
361
+ symbols: shouldCompleteOnVariables
362
+ ? this.analyzer.getAllVariables({
363
+ uri: currentUri,
364
+ position: params.position,
365
+ })
366
+ : this.analyzer.findDeclarationsMatchingWord({
367
+ exactMatch: false,
368
+ uri: currentUri,
369
+ word,
370
+ position: params.position,
371
+ }),
372
+ currentUri,
373
+ });
374
+ if (shouldCompleteOnVariables) {
375
+ // In case we auto complete on a word that starts a parameter expansion,
376
+ // we do not return anything else than variable/parameter suggestions.
377
+ // Note: that LSP clients should not call onCompletion in the middle
378
+ // of a word, so the following should work for client.
379
+ return symbolCompletions;
380
+ }
381
+ const reservedWordsCompletions = ReservedWords.LIST.map((reservedWord) => ({
382
+ label: reservedWord,
383
+ kind: LSP.CompletionItemKind.Keyword,
384
+ data: {
385
+ type: types_1.CompletionItemDataType.ReservedWord,
386
+ },
387
+ }));
388
+ const programCompletions = this.executables
389
+ .list()
390
+ .filter((executable) => !Builtins.isBuiltin(executable))
391
+ .map((executable) => {
392
+ return {
393
+ label: executable,
394
+ kind: LSP.CompletionItemKind.Function,
395
+ data: {
396
+ type: types_1.CompletionItemDataType.Executable,
397
+ },
398
+ };
399
+ });
400
+ const builtinsCompletions = Builtins.LIST.map((builtin) => ({
401
+ label: builtin,
402
+ kind: LSP.CompletionItemKind.Function,
403
+ data: {
404
+ type: types_1.CompletionItemDataType.Builtin,
405
+ },
406
+ }));
407
+ let optionsCompletions = [];
408
+ if (word === null || word === void 0 ? void 0 : word.startsWith('-')) {
409
+ const commandName = this.analyzer.commandNameAtPoint(params.textDocument.uri, params.position.line,
410
+ // Go one character back to get completion on the current word
411
+ Math.max(params.position.character - 1, 0));
412
+ if (commandName) {
413
+ optionsCompletions = getCommandOptions(commandName, word).map((option) => ({
414
+ label: option,
415
+ kind: LSP.CompletionItemKind.Constant,
416
+ data: {
417
+ type: types_1.CompletionItemDataType.Symbol,
418
+ },
419
+ textEdit: {
420
+ newText: option.slice(word.length),
421
+ range: {
422
+ start: {
423
+ character: params.position.character,
424
+ line: params.position.line,
425
+ },
426
+ end: {
427
+ character: params.position.character,
428
+ line: params.position.line,
429
+ },
430
+ },
431
+ },
432
+ }));
433
+ }
434
+ }
435
+ const allCompletions = [
436
+ ...reservedWordsCompletions,
437
+ ...symbolCompletions,
438
+ ...programCompletions,
439
+ ...builtinsCompletions,
440
+ ...optionsCompletions,
441
+ ...snippets_1.SNIPPETS,
442
+ ];
443
+ if (word) {
444
+ // Filter to only return suffixes of the current word
445
+ return allCompletions.filter((item) => item.label.startsWith(word));
446
+ }
447
+ return allCompletions;
448
+ }
449
+ onCompletionResolve(item) {
450
+ return __awaiter(this, void 0, void 0, function* () {
451
+ const { label, data: { type }, } = item;
452
+ logger_1.logger.debug(`onCompletionResolve label=${label} type=${type}`);
453
+ try {
454
+ let documentation = null;
455
+ if (type === types_1.CompletionItemDataType.Executable ||
456
+ type === types_1.CompletionItemDataType.Builtin ||
457
+ type === types_1.CompletionItemDataType.ReservedWord) {
458
+ documentation = yield (0, sh_1.getShellDocumentation)({ word: label });
459
+ }
460
+ return documentation
461
+ ? Object.assign(Object.assign({}, item), { documentation: getMarkdownContent(documentation, 'man') }) : item;
462
+ }
463
+ catch (error) {
464
+ return item;
465
+ }
466
+ });
467
+ }
468
+ onDefinition(params) {
469
+ const word = this.analyzer.wordAtPointFromTextPosition(params);
470
+ this.logRequest({ request: 'onDefinition', params, word });
471
+ if (!word) {
472
+ return null;
473
+ }
474
+ return this.analyzer.findDeclarationLocations({
475
+ position: params.position,
476
+ uri: params.textDocument.uri,
477
+ word,
478
+ });
479
+ }
480
+ onDocumentHighlight(params) {
481
+ const word = this.analyzer.wordAtPointFromTextPosition(params);
482
+ this.logRequest({ request: 'onDocumentHighlight', params, word });
483
+ if (!word) {
484
+ return [];
485
+ }
486
+ return this.analyzer
487
+ .findOccurrences(params.textDocument.uri, word)
488
+ .map((n) => ({ range: n.range }));
489
+ }
490
+ onDocumentSymbol(params) {
491
+ // TODO: ideally this should return LSP.DocumentSymbol[] instead of LSP.SymbolInformation[]
492
+ // which is a hierarchy of symbols.
493
+ // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentSymbol
494
+ logger_1.logger.debug(`onDocumentSymbol`);
495
+ return this.analyzer.getDeclarationsForUri({ uri: params.textDocument.uri });
496
+ }
497
+ onHover(params) {
498
+ return __awaiter(this, void 0, void 0, function* () {
499
+ const word = this.analyzer.wordAtPointFromTextPosition(params);
500
+ const currentUri = params.textDocument.uri;
501
+ this.logRequest({ request: 'onHover', params, word });
502
+ if (!word || word.startsWith('#')) {
503
+ return null;
504
+ }
505
+ const { explainshellEndpoint } = this.config;
506
+ if (explainshellEndpoint) {
507
+ try {
508
+ const { helpHTML } = yield this.analyzer.getExplainshellDocumentation({
509
+ params,
510
+ endpoint: explainshellEndpoint,
511
+ });
512
+ if (helpHTML) {
513
+ return {
514
+ contents: {
515
+ kind: 'markdown',
516
+ value: new TurndownService().turndown(helpHTML),
517
+ },
518
+ };
519
+ }
520
+ }
521
+ catch (error) {
522
+ const errorMessage = error instanceof Error ? error.message : error;
523
+ logger_1.logger.warn(`getExplainshellDocumentation exception: ${errorMessage}`);
524
+ }
525
+ }
526
+ const symbolsMatchingWord = this.analyzer.findDeclarationsMatchingWord({
527
+ exactMatch: true,
528
+ uri: currentUri,
529
+ word,
530
+ position: params.position,
531
+ });
532
+ if (ReservedWords.isReservedWord(word) ||
533
+ Builtins.isBuiltin(word) ||
534
+ (this.executables.isExecutableOnPATH(word) && symbolsMatchingWord.length == 0)) {
535
+ logger_1.logger.debug(`onHover: getting shell documentation for reserved word or builtin or executable`);
536
+ const shellDocumentation = yield (0, sh_1.getShellDocumentation)({ word });
537
+ if (shellDocumentation) {
538
+ return { contents: getMarkdownContent(shellDocumentation, 'man') };
539
+ }
540
+ }
541
+ else {
542
+ const symbolDocumentation = deduplicateSymbols({
543
+ symbols: symbolsMatchingWord,
544
+ currentUri,
545
+ })
546
+ // do not return hover referencing for the current line
547
+ .filter((symbol) => symbol.location.uri !== currentUri ||
548
+ symbol.location.range.start.line !== params.position.line)
549
+ .map((symbol) => this.getDocumentationForSymbol({ currentUri, symbol }));
550
+ if (symbolDocumentation.length === 1) {
551
+ return { contents: symbolDocumentation[0] };
552
+ }
553
+ }
554
+ return null;
555
+ });
556
+ }
557
+ onReferences(params) {
558
+ const word = this.analyzer.wordAtPointFromTextPosition(params);
559
+ this.logRequest({ request: 'onReferences', params, word });
560
+ if (!word) {
561
+ return null;
562
+ }
563
+ const isCurrentDeclaration = (l) => l.uri === params.textDocument.uri &&
564
+ (0, lsp_1.isPositionIncludedInRange)(params.position, l.range);
565
+ return this.analyzer
566
+ .findReferences(word)
567
+ .filter((l) => params.context.includeDeclaration || !isCurrentDeclaration(l));
568
+ }
569
+ onWorkspaceSymbol(params) {
570
+ logger_1.logger.debug('onWorkspaceSymbol');
571
+ return this.analyzer.findDeclarationsWithFuzzySearch(params.query);
572
+ }
573
+ onPrepareRename(params) {
574
+ const symbol = this.analyzer.symbolAtPointFromTextPosition(params);
575
+ this.logRequest({ request: 'onPrepareRename', params, word: symbol === null || symbol === void 0 ? void 0 : symbol.word });
576
+ if (!symbol ||
577
+ (symbol.kind === LSP.SymbolKind.Variable &&
578
+ (symbol.word === '_' || !/^[a-z_][\w]*$/i.test(symbol.word)))) {
579
+ return null;
580
+ }
581
+ return symbol.range;
582
+ }
583
+ onRenameRequest(params) {
584
+ const symbol = this.analyzer.symbolAtPointFromTextPosition(params);
585
+ this.logRequest({ request: 'onRenameRequest', params, word: symbol === null || symbol === void 0 ? void 0 : symbol.word });
586
+ if (!symbol) {
587
+ return null;
588
+ }
589
+ if (symbol.kind === LSP.SymbolKind.Variable &&
590
+ (params.newName === '_' || !/^[a-z_][\w]*$/i.test(params.newName))) {
591
+ this.throwResponseError('Invalid variable name given.');
592
+ }
593
+ if (symbol.kind === LSP.SymbolKind.Function && params.newName.includes('$')) {
594
+ this.throwResponseError('Invalid function name given.');
595
+ }
596
+ const { declaration, parent } = this.analyzer.findOriginalDeclaration({
597
+ position: params.position,
598
+ uri: params.textDocument.uri,
599
+ word: symbol.word,
600
+ kind: symbol.kind,
601
+ });
602
+ // File-wide rename
603
+ if (!declaration || parent) {
604
+ return {
605
+ changes: {
606
+ [params.textDocument.uri]: this.analyzer
607
+ .findOccurrencesWithin({
608
+ uri: params.textDocument.uri,
609
+ word: symbol.word,
610
+ kind: symbol.kind,
611
+ start: declaration === null || declaration === void 0 ? void 0 : declaration.range.start,
612
+ scope: parent === null || parent === void 0 ? void 0 : parent.range,
613
+ })
614
+ .map((r) => LSP.TextEdit.replace(r, params.newName)),
615
+ },
616
+ };
617
+ }
618
+ // Workspace-wide rename
619
+ const edits = {};
620
+ edits.changes = {
621
+ [declaration.uri]: this.analyzer
622
+ .findOccurrencesWithin({
623
+ uri: declaration.uri,
624
+ word: symbol.word,
625
+ kind: symbol.kind,
626
+ start: declaration.range.start,
627
+ })
628
+ .map((r) => LSP.TextEdit.replace(r, params.newName)),
629
+ };
630
+ for (const uri of this.analyzer.findAllLinkedUris(declaration.uri)) {
631
+ edits.changes[uri] = this.analyzer
632
+ .findOccurrencesWithin({
633
+ uri,
634
+ word: symbol.word,
635
+ kind: symbol.kind,
636
+ })
637
+ .map((r) => LSP.TextEdit.replace(r, params.newName));
638
+ }
639
+ return edits;
640
+ }
641
+ onDocumentFormatting(params) {
642
+ return __awaiter(this, void 0, void 0, function* () {
643
+ if (this.formatter) {
644
+ try {
645
+ const document = this.documents.get(params.textDocument.uri);
646
+ if (!document) {
647
+ logger_1.logger.error(`Error getting document: ${params.textDocument.uri}`);
648
+ return null;
649
+ }
650
+ return yield this.formatter.format(document, params.options, this.config.shfmt);
651
+ }
652
+ catch (err) {
653
+ logger_1.logger.error(`Error while formatting: ${err}`);
654
+ }
655
+ }
656
+ return null;
657
+ });
658
+ }
659
+ }
660
+ exports.default = BashServer;
661
+ /**
662
+ * Deduplicate symbols by prioritizing the current file.
663
+ */
664
+ function deduplicateSymbols({ symbols, currentUri, }) {
665
+ const isCurrentFile = ({ location: { uri } }) => uri === currentUri;
666
+ const getSymbolId = ({ name, kind }) => `${name}${kind}`;
667
+ const symbolsCurrentFile = symbols.filter((s) => isCurrentFile(s));
668
+ const symbolsOtherFiles = symbols
669
+ .filter((s) => !isCurrentFile(s))
670
+ // Remove identical symbols matching current file
671
+ .filter((symbolOtherFiles) => !symbolsCurrentFile.some((symbolCurrentFile) => getSymbolId(symbolCurrentFile) === getSymbolId(symbolOtherFiles)));
672
+ // NOTE: it might be that uniqueBasedOnHash is not needed anymore
673
+ return (0, array_1.uniqueBasedOnHash)([...symbolsCurrentFile, ...symbolsOtherFiles], getSymbolId);
674
+ }
675
+ function symbolKindToCompletionKind(s) {
676
+ switch (s) {
677
+ case LSP.SymbolKind.File:
678
+ return LSP.CompletionItemKind.File;
679
+ case LSP.SymbolKind.Module:
680
+ case LSP.SymbolKind.Namespace:
681
+ case LSP.SymbolKind.Package:
682
+ return LSP.CompletionItemKind.Module;
683
+ case LSP.SymbolKind.Class:
684
+ return LSP.CompletionItemKind.Class;
685
+ case LSP.SymbolKind.Method:
686
+ return LSP.CompletionItemKind.Method;
687
+ case LSP.SymbolKind.Property:
688
+ return LSP.CompletionItemKind.Property;
689
+ case LSP.SymbolKind.Field:
690
+ return LSP.CompletionItemKind.Field;
691
+ case LSP.SymbolKind.Constructor:
692
+ return LSP.CompletionItemKind.Constructor;
693
+ case LSP.SymbolKind.Enum:
694
+ return LSP.CompletionItemKind.Enum;
695
+ case LSP.SymbolKind.Interface:
696
+ return LSP.CompletionItemKind.Interface;
697
+ case LSP.SymbolKind.Function:
698
+ return LSP.CompletionItemKind.Function;
699
+ case LSP.SymbolKind.Variable:
700
+ return LSP.CompletionItemKind.Variable;
701
+ case LSP.SymbolKind.Constant:
702
+ return LSP.CompletionItemKind.Constant;
703
+ case LSP.SymbolKind.String:
704
+ case LSP.SymbolKind.Number:
705
+ case LSP.SymbolKind.Boolean:
706
+ case LSP.SymbolKind.Array:
707
+ case LSP.SymbolKind.Key:
708
+ case LSP.SymbolKind.Null:
709
+ return LSP.CompletionItemKind.Text;
710
+ case LSP.SymbolKind.Object:
711
+ return LSP.CompletionItemKind.Module;
712
+ case LSP.SymbolKind.EnumMember:
713
+ return LSP.CompletionItemKind.EnumMember;
714
+ case LSP.SymbolKind.Struct:
715
+ return LSP.CompletionItemKind.Struct;
716
+ case LSP.SymbolKind.Event:
717
+ return LSP.CompletionItemKind.Event;
718
+ case LSP.SymbolKind.Operator:
719
+ return LSP.CompletionItemKind.Operator;
720
+ case LSP.SymbolKind.TypeParameter:
721
+ return LSP.CompletionItemKind.TypeParameter;
722
+ default:
723
+ return LSP.CompletionItemKind.Text;
724
+ }
725
+ }
726
+ function symbolKindToDescription(s) {
727
+ switch (s) {
728
+ case LSP.SymbolKind.Function:
729
+ return 'Function';
730
+ case LSP.SymbolKind.Variable:
731
+ return 'Variable';
732
+ default:
733
+ return 'Keyword';
734
+ }
735
+ }
736
+ function getMarkdownContent(documentation, language) {
737
+ return {
738
+ value: language
739
+ ? // eslint-disable-next-line prefer-template
740
+ ['``` ' + language, documentation, '```'].join('\n')
741
+ : documentation,
742
+ kind: LSP.MarkupKind.Markdown,
743
+ };
744
+ }
745
+ function getCommandOptions(name, word) {
746
+ const options = (0, node_child_process_1.spawnSync)(path.join(__dirname, '../src/get-options.sh'), [name, word]);
747
+ if (options.status !== 0) {
748
+ return [];
749
+ }
750
+ return options.stdout
751
+ .toString()
752
+ .split('\t')
753
+ .map((l) => l.trim())
754
+ .filter((l) => l.length > 0);
755
+ }
756
+ //# sourceMappingURL=server.js.map