Welcome to Acode
Powerful code editor for Android
diff --git a/src/pages/welcome/welcome.scss b/src/pages/welcome/welcome.scss
index 5a1a95840..36e7f2c98 100644
--- a/src/pages/welcome/welcome.scss
+++ b/src/pages/welcome/welcome.scss
@@ -1,232 +1,242 @@
#welcome-tab {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: flex-start;
+ min-height: 100%;
+ height: auto;
+ padding: 32px 24px;
+ overflow-y: auto;
+ overflow-x: hidden;
+ background-color: var(--secondary-color);
+
+ // Hero Header
+ .welcome-header {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+ margin-bottom: 48px;
+
+ .logo {
+ width: 48px;
+ height: auto;
+ max-height: 48px;
+ flex-shrink: 0;
+ }
+
+ .welcome-header-text {
+ h1 {
+ font-size: 20px;
+ font-weight: 600;
+ color: var(--primary-text-color);
+ margin: 0 0 4px 0;
+ letter-spacing: -0.3px;
+ }
+
+ .tagline {
+ font-size: 13px;
+ color: color-mix(in srgb, var(--secondary-text-color) 60%, transparent);
+ margin: 0;
+ }
+ }
+ }
+
+ // Section Styles
+ .welcome-section {
+ width: 100%;
+ max-width: 400px;
+ margin-bottom: 32px;
+
+ .section-label {
+ font-size: 11px;
+ font-weight: 600;
+ letter-spacing: 1px;
+ color: color-mix(in srgb, var(--secondary-text-color) 50%, transparent);
+ margin: 0 0 12px 0;
+ padding-left: 4px;
+ }
+ }
+
+ // Action List
+ .action-list {
display: flex;
flex-direction: column;
+ gap: 2px;
+ }
+
+ .action-row {
+ display: flex;
align-items: center;
- justify-content: flex-start;
- min-height: 100%;
- height: auto;
- padding: 32px 24px;
- overflow-y: auto;
- overflow-x: hidden;
- background-color: var(--secondary-color);
-
- // Hero Header
- .welcome-header {
- display: flex;
- align-items: center;
- gap: 16px;
- margin-bottom: 48px;
-
- .logo {
- width: 64px;
- height: 64px;
- flex-shrink: 0;
-
- &::after {
- background-size: 48px;
- }
-
- &::before {
- background: radial-gradient(circle,
- color-mix(in srgb, var(--button-background-color) 30%, transparent) 0%,
- transparent 70%);
- }
- }
-
- .welcome-header-text {
- h1 {
- font-size: 20px;
- font-weight: 600;
- color: var(--primary-text-color);
- margin: 0 0 4px 0;
- letter-spacing: -0.3px;
- }
-
- .tagline {
- font-size: 13px;
- color: color-mix(in srgb, var(--secondary-text-color) 60%, transparent);
- margin: 0;
- }
- }
+ gap: 12px;
+ padding: 10px 12px;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: background-color 0.15s ease;
+
+ &:hover,
+ &:active {
+ background-color: color-mix(
+ in srgb,
+ var(--popup-background-color) 40%,
+ transparent
+ );
}
- // Section Styles
- .welcome-section {
- width: 100%;
- max-width: 400px;
- margin-bottom: 32px;
-
- .section-label {
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 1px;
- color: color-mix(in srgb, var(--secondary-text-color) 50%, transparent);
- margin: 0 0 12px 0;
- padding-left: 4px;
- }
+ .icon {
+ font-size: 16px;
+ color: color-mix(in srgb, var(--secondary-text-color) 70%, transparent);
+ width: 20px;
+ text-align: center;
}
- // Action List
- .action-list {
- display: flex;
- flex-direction: column;
- gap: 2px;
+ .action-label {
+ flex: 1;
+ font-size: 14px;
+ color: var(--secondary-text-color);
}
- .action-row {
- display: flex;
- align-items: center;
- gap: 12px;
- padding: 10px 12px;
- border-radius: 6px;
- cursor: pointer;
- transition: background-color 0.15s ease;
-
- &:hover,
- &:active {
- background-color: color-mix(in srgb, var(--popup-background-color) 40%, transparent);
- }
-
- .icon {
- font-size: 16px;
- color: color-mix(in srgb, var(--secondary-text-color) 70%, transparent);
- width: 20px;
- text-align: center;
- }
-
- .action-label {
- flex: 1;
- font-size: 14px;
- color: var(--secondary-text-color);
- }
-
- .action-shortcut {
- font-size: 12px;
- font-family: 'Roboto Mono', monospace;
- color: color-mix(in srgb, var(--secondary-text-color) 40%, transparent);
- letter-spacing: 0.5px;
- }
+ .action-shortcut {
+ font-size: 12px;
+ font-family: "Roboto Mono", monospace;
+ color: color-mix(in srgb, var(--secondary-text-color) 40%, transparent);
+ letter-spacing: 0.5px;
+ }
+ }
+
+ // Links Section
+ .welcome-links {
+ margin-top: 16px;
+
+ .link-row {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ justify-content: flex-start;
}
- // Links Section
- .welcome-links {
- margin-top: 16px;
-
- .link-row {
- display: flex;
- flex-wrap: wrap;
- gap: 8px;
- justify-content: flex-start;
- }
-
- .link-item {
- display: inline-flex;
- align-items: center;
- gap: 8px;
- padding: 10px 16px;
- border-radius: 8px;
- text-decoration: none;
- color: var(--secondary-text-color);
- font-size: 13px;
- font-weight: 500;
- transition: all 0.15s ease;
- background-color: color-mix(in srgb, var(--popup-background-color) 25%, transparent);
- border: 1px solid color-mix(in srgb, var(--border-color) 20%, transparent);
-
- &:hover,
- &:active {
- background-color: color-mix(in srgb, var(--popup-background-color) 50%, transparent);
- border-color: color-mix(in srgb, var(--border-color) 40%, transparent);
- transform: translateY(-1px);
- }
-
- .icon {
- font-size: 16px;
- color: color-mix(in srgb, var(--secondary-text-color) 80%, transparent);
- }
- }
+ .link-item {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ padding: 10px 16px;
+ border-radius: 8px;
+ text-decoration: none;
+ color: var(--secondary-text-color);
+ font-size: 13px;
+ font-weight: 500;
+ transition: all 0.15s ease;
+ background-color: color-mix(
+ in srgb,
+ var(--popup-background-color) 25%,
+ transparent
+ );
+ border: 1px solid color-mix(in srgb, var(--border-color) 20%, transparent);
+
+ &:hover,
+ &:active {
+ background-color: color-mix(
+ in srgb,
+ var(--popup-background-color) 50%,
+ transparent
+ );
+ border-color: color-mix(in srgb, var(--border-color) 40%, transparent);
+ transform: translateY(-1px);
+ }
+
+ .icon {
+ font-size: 16px;
+ color: color-mix(in srgb, var(--secondary-text-color) 80%, transparent);
+ }
}
+ }
}
- @supports not (gap: 1px) {
- .welcome-header > * + * { margin-left: 16px; }
- .action-list > * + * { margin-top: 2px; }
- .action-row > * + * { margin-left: 12px; }
- .link-row > * { margin-right: 8px; margin-bottom: 8px; }
- .link-item > * + * { margin-left: 8px; }
+@supports not (gap: 1px) {
+ .welcome-header > * + * {
+ margin-left: 16px;
+ }
+ .action-list > * + * {
+ margin-top: 2px;
+ }
+ .action-row > * + * {
+ margin-left: 12px;
+ }
+ .link-row > * {
+ margin-right: 8px;
+ margin-bottom: 8px;
}
+ .link-item > * + * {
+ margin-left: 8px;
+ }
+}
// Responsive adjustments for smaller screens
@media (max-width: 360px) {
- #welcome-tab {
- padding: 24px 16px;
-
- .welcome-header {
- flex-direction: column;
- text-align: center;
- margin-bottom: 36px;
-
- .logo {
- width: 56px;
- height: 56px;
-
- &::after {
- background-size: 40px;
- }
- }
-
- .welcome-header-text h1 {
- font-size: 18px;
- }
- }
-
- .welcome-section {
- margin-bottom: 24px;
- }
-
- .action-row {
- padding: 8px 10px;
-
- .action-label {
- font-size: 13px;
- }
-
- .action-shortcut {
- font-size: 11px;
- }
- }
-
- .welcome-links .link-row {
- justify-content: center;
- }
+ #welcome-tab {
+ padding: 24px 16px;
+
+ .welcome-header {
+ flex-direction: column;
+ text-align: center;
+ margin-bottom: 36px;
+
+ .logo {
+ width: 40px;
+ max-height: 40px;
+ }
+
+ .welcome-header-text h1 {
+ font-size: 18px;
+ }
+ }
+
+ .welcome-section {
+ margin-bottom: 24px;
+ }
+
+ .action-row {
+ padding: 8px 10px;
+
+ .action-label {
+ font-size: 13px;
+ }
+
+ .action-shortcut {
+ font-size: 11px;
+ }
}
+
+ .welcome-links .link-row {
+ justify-content: center;
+ }
+ }
}
// Larger screens - center content better
@media (min-width: 600px) {
- #welcome-tab {
- .welcome-section {
- max-width: 480px;
- }
-
- .action-row {
- padding: 12px 16px;
- }
+ #welcome-tab {
+ .welcome-section {
+ max-width: 480px;
}
+
+ .action-row {
+ padding: 12px 16px;
+ }
+ }
}
// Discord icon
.icon.discord {
- position: relative;
-
- &::before {
- content: '';
- display: block;
- width: 16px;
- height: 16px;
- background-image: url(../../pages/about/discord.svg);
- background-size: contain;
- background-repeat: no-repeat;
- background-position: center;
- }
-}
\ No newline at end of file
+ position: relative;
+
+ &::before {
+ content: "";
+ display: block;
+ width: 16px;
+ height: 16px;
+ background-image: url(../../pages/about/discord.svg);
+ background-size: contain;
+ background-repeat: no-repeat;
+ background-position: center;
+ }
+}
diff --git a/src/test/sanity.tests.js b/src/test/sanity.tests.js
index 6b5938475..61971c8d9 100644
--- a/src/test/sanity.tests.js
+++ b/src/test/sanity.tests.js
@@ -1,3 +1,4 @@
+import { getLanguageModeRecommendationSearchKeyword } from "../lib/languageModeRecommendations";
import { TestRunner } from "./tester";
export async function runSanityTests(writeOutput) {
@@ -63,6 +64,24 @@ export async function runSanityTests(writeOutput) {
test.assert(!(value < 5), "Negation should work");
});
+ runner.test("Language mode recommendation keywords", (test) => {
+ test.assertEqual(
+ getLanguageModeRecommendationSearchKeyword(".gitignore"),
+ "gitignore",
+ "Dotfiles without extensions should use the dotfile name",
+ );
+ test.assertEqual(
+ getLanguageModeRecommendationSearchKeyword("src/main.js"),
+ "js",
+ "Normal files should use the file extension",
+ );
+ test.assertEqual(
+ getLanguageModeRecommendationSearchKeyword("README"),
+ "",
+ "Extensionless non-dotfiles should not request plugin recommendations",
+ );
+ });
+
// Run all tests
return await runner.run(writeOutput);
}
From 9ce5cd8194f62cf92a4d7dc6be23ec75c2e34cf9 Mon Sep 17 00:00:00 2001
From: Raunak Raj <71929976+bajrangCoder@users.noreply.github.com>
Date: Fri, 26 Jun 2026 17:41:10 +0530
Subject: [PATCH 6/9] fix: folder persistent regression
---
src/lib/openFolder.js | 24 ++++++++++++------------
src/main.js | 5 ++++-
2 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/src/lib/openFolder.js b/src/lib/openFolder.js
index 312c0f52f..21e21b4f8 100644
--- a/src/lib/openFolder.js
+++ b/src/lib/openFolder.js
@@ -183,22 +183,22 @@ function openFolder(_path, opts = {}) {
},
};
+ if (typeof listFiles !== "boolean") {
+ listFiles = appSettings.value.fileBrowser?.listFiles ?? true;
+ }
+
+ folder.listFiles = listFiles;
+ addedFolder.push(folder);
+
editorManager.emit("update", "add-folder");
editorManager.onupdate("add-folder", event);
editorManager.emit("add-folder", event);
- (async () => {
- if (typeof listFiles !== "boolean") {
- listFiles = appSettings.value.fileBrowser?.listFiles ?? true;
- }
-
- if (listFiles) {
- FileList.addRoot({ url: _path, name: title });
- }
-
- folder.listFiles = listFiles;
- addedFolder.push(folder);
- })();
+ if (listFiles) {
+ FileList.addRoot({ url: _path, name: title }).catch((err) => {
+ console.error("Failed to add root to FileList:", err);
+ });
+ }
if (listState[_path]) {
$root.expand();
diff --git a/src/main.js b/src/main.js
index 004d1fe07..bb285801d 100644
--- a/src/main.js
+++ b/src/main.js
@@ -681,6 +681,7 @@ async function loadApp() {
onEditorUpdate(undefined, false);
}
+ acode.exec("save-state");
initFileList();
import(/* webpackChunkName: "terminal" */ "components/terminal").then(
@@ -733,7 +734,9 @@ async function loadApp() {
return;
}
- if (saveState) acode.exec("save-state");
+ if (saveState && sessionStorage.getItem("isfilesRestored") === "true") {
+ acode.exec("save-state");
+ }
}
async function onFileUpdate() {
From 7046b4f92c19faef96fd5d7fd8666979dec63225 Mon Sep 17 00:00:00 2001
From: Raunak Raj <71929976+bajrangCoder@users.noreply.github.com>
Date: Fri, 26 Jun 2026 22:00:52 +0530
Subject: [PATCH 7/9] improved lsp logs and fix lsp settings
---
src/cm/lsp/clientManager.ts | 5 +
src/cm/lsp/connectionState.js | 6 +-
src/cm/lsp/index.ts | 8 ++
src/cm/lsp/logs.ts | 88 +++++++++++++++
src/cm/lsp/runtimeActions.ts | 33 ++++--
src/cm/lsp/runtimes/builtinAlpine.ts | 4 +
src/cm/lsp/runtimes/externalWebSocket.ts | 5 +-
src/cm/lsp/serverLauncher.ts | 10 ++
src/cm/lsp/transport.ts | 16 +++
src/cm/lsp/types.ts | 1 +
src/components/lspInfoDialog/index.js | 132 +----------------------
11 files changed, 165 insertions(+), 143 deletions(-)
create mode 100644 src/cm/lsp/logs.ts
diff --git a/src/cm/lsp/clientManager.ts b/src/cm/lsp/clientManager.ts
index 1720a86ac..196ef14a7 100644
--- a/src/cm/lsp/clientManager.ts
+++ b/src/cm/lsp/clientManager.ts
@@ -18,6 +18,7 @@ import Url from "utils/Url";
import { clearDiagnosticsEffect } from "./diagnostics";
import { supportsBuiltinFormatting } from "./formattingSupport";
import { inlayHintsExtension } from "./inlayHints";
+import { addLspLog } from "./logs";
import { acodeRenameKeymap } from "./rename";
import { selectRuntimeProvider } from "./runtimeProviders";
import serverRegistry from "./serverRegistry";
@@ -689,6 +690,7 @@ export class LspClientManager {
level = "info";
}
const logFn = console[level] ?? console.info;
+ addLspLog(server.id, level === "log" ? "info" : level, message);
logFn(`[LSP:${server.id}] ${message}`);
return true;
},
@@ -716,6 +718,7 @@ export class LspClientManager {
icon: type === 1 ? "error" : "warningreport_problem",
type: type === 1 ? "error" : "warning",
});
+ addLspLog(server.id, type === 1 ? "error" : "warn", message);
logLspInfo(`[LSP:${server.id}] ${message}`);
return true;
}
@@ -728,6 +731,7 @@ export class LspClientManager {
icon: type === 4 ? "autorenew" : "info",
duration: 5000,
});
+ addLspLog(server.id, "info", message);
logLspInfo(`[LSP:${server.id}] ${message}`);
return true;
},
@@ -906,6 +910,7 @@ export class LspClientManager {
);
}
logLspInfo(`[LSP:${server.id}] initialized`);
+ addLspLog(server.id, "info", "Initialized");
client.__acodeLoggedInfo = true;
}
} catch (error) {
diff --git a/src/cm/lsp/connectionState.js b/src/cm/lsp/connectionState.js
index 29158a9f0..123665709 100644
--- a/src/cm/lsp/connectionState.js
+++ b/src/cm/lsp/connectionState.js
@@ -25,4 +25,8 @@ function hasConnectedServers() {
return getServersForCurrentFile().length > 0;
}
-export { getServersForCurrentFile, hasConnectedServers };
+export {
+ getCurrentFileLanguage,
+ getServersForCurrentFile,
+ hasConnectedServers,
+};
diff --git a/src/cm/lsp/index.ts b/src/cm/lsp/index.ts
index 41654762b..904c6c31c 100644
--- a/src/cm/lsp/index.ts
+++ b/src/cm/lsp/index.ts
@@ -55,6 +55,14 @@ export {
inlayHintsEditorExtension,
inlayHintsExtension,
} from "./inlayHints";
+export {
+ addLspLog,
+ clearLspLogs,
+ getLspLogs,
+ onLspLog,
+ type LspLogEntry,
+ type LspLogLevel,
+} from "./logs";
export {
closeReferencesPanel,
findAllReferences,
diff --git a/src/cm/lsp/logs.ts b/src/cm/lsp/logs.ts
new file mode 100644
index 000000000..eb5dacd8d
--- /dev/null
+++ b/src/cm/lsp/logs.ts
@@ -0,0 +1,88 @@
+export type LspLogLevel = "debug" | "info" | "log" | "warn" | "error" | "stderr";
+
+export interface LspLogEntry {
+ timestamp: Date;
+ level: LspLogLevel;
+ message: string;
+ details?: unknown;
+}
+
+const MAX_LOGS = 200;
+const logsByServer = new Map
();
+const listeners = new Set<(serverId: string, entry: LspLogEntry) => void>();
+const IGNORED_LOG_PATTERNS = [
+ /\$\/progress\b/i,
+ /\bProgress:/i,
+ /\bwindow\/workDoneProgress\/create\b/i,
+ /\bAuto-responded to window\/workDoneProgress\/create\b/i,
+];
+
+function stripAnsi(value: string): string {
+ return value.replace(/\x1b\[[0-9;]*m/g, "");
+}
+
+function normalizeMessage(message: unknown): string {
+ let text: string;
+ if (typeof message === "string") {
+ text = message;
+ } else if (message instanceof Error) {
+ text = message.message;
+ } else {
+ try {
+ text = JSON.stringify(message);
+ } catch {
+ text = String(message);
+ }
+ }
+ return stripAnsi(String(text || ""))
+ .replace(/\[LSP:[^\]]+\]\s*/g, "")
+ .replace(/\[LSP-STDERR:[^\]]+\]\s*/g, "")
+ .replace(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\s*/g, "")
+ .replace(/\s*(INFO|WARN|ERROR|DEBUG|TRACE)\s+/gi, "")
+ .replace(/[a-z_]+::[a-z_]+:\s*/gi, "")
+ .trim();
+}
+
+function shouldIgnoreLog(message: string): boolean {
+ return IGNORED_LOG_PATTERNS.some((pattern) => pattern.test(message));
+}
+
+export function addLspLog(
+ serverId: string,
+ level: LspLogLevel,
+ message: unknown,
+ details?: unknown,
+): void {
+ const id = String(serverId || "").trim();
+ if (!id) return;
+
+ const normalized = normalizeMessage(message);
+ if (!normalized || shouldIgnoreLog(normalized)) return;
+
+ const logs = logsByServer.get(id) || [];
+ const entry: LspLogEntry = {
+ timestamp: new Date(),
+ level,
+ message: normalized,
+ details,
+ };
+ logs.push(entry);
+ if (logs.length > MAX_LOGS) logs.splice(0, logs.length - MAX_LOGS);
+ logsByServer.set(id, logs);
+ listeners.forEach((listener) => listener(id, entry));
+}
+
+export function getLspLogs(serverId: string): LspLogEntry[] {
+ return logsByServer.get(String(serverId || "").trim()) || [];
+}
+
+export function clearLspLogs(serverId: string): void {
+ logsByServer.delete(String(serverId || "").trim());
+}
+
+export function onLspLog(
+ listener: (serverId: string, entry: LspLogEntry) => void,
+): () => void {
+ listeners.add(listener);
+ return () => listeners.delete(listener);
+}
diff --git a/src/cm/lsp/runtimeActions.ts b/src/cm/lsp/runtimeActions.ts
index 17455c9aa..2fe36af8a 100644
--- a/src/cm/lsp/runtimeActions.ts
+++ b/src/cm/lsp/runtimeActions.ts
@@ -9,26 +9,33 @@ import type {
function getSettingsContext(
server: LspServerDefinition,
context: LspRuntimeContext = {},
+ runtimeAction: LspRuntimeContext["runtimeAction"] = "command",
): LspRuntimeContext {
return {
...context,
serverId: context.serverId || server.id,
allowNonTerminalWorkspace: true,
+ runtimeAction,
};
}
async function getProvider(
server: LspServerDefinition,
context: LspRuntimeContext = {},
+ runtimeAction?: LspRuntimeContext["runtimeAction"],
): Promise {
- return selectRuntimeProvider(server, getSettingsContext(server, context));
+ return selectRuntimeProvider(
+ server,
+ getSettingsContext(server, context, runtimeAction),
+ );
}
export async function checkRuntimeServerInstallation(
server: LspServerDefinition,
context?: LspRuntimeContext,
): Promise {
- const provider = await getProvider(server, context);
+ const settingsContext = getSettingsContext(server, context, "checkInstallation");
+ const provider = await getProvider(server, context, "checkInstallation");
if (!provider?.checkInstallation) {
return {
status: "unknown",
@@ -38,7 +45,7 @@ export async function checkRuntimeServerInstallation(
message: "The selected runtime does not provide installation checks.",
};
}
- return provider.checkInstallation(server, getSettingsContext(server, context));
+ return provider.checkInstallation(server, settingsContext);
}
export async function installRuntimeServer(
@@ -47,11 +54,12 @@ export async function installRuntimeServer(
options: { promptConfirm?: boolean } = {},
context?: LspRuntimeContext,
): Promise {
- const provider = await getProvider(server, context);
+ const settingsContext = getSettingsContext(server, context, "install");
+ const provider = await getProvider(server, context, "install");
if (!provider?.install) {
throw new Error("The selected runtime does not support installation.");
}
- return provider.install(server, getSettingsContext(server, context), mode, options);
+ return provider.install(server, settingsContext, mode, options);
}
export async function uninstallRuntimeServer(
@@ -59,11 +67,12 @@ export async function uninstallRuntimeServer(
options: { promptConfirm?: boolean } = {},
context?: LspRuntimeContext,
): Promise {
- const provider = await getProvider(server, context);
+ const settingsContext = getSettingsContext(server, context, "uninstall");
+ const provider = await getProvider(server, context, "uninstall");
if (!provider?.uninstall) {
throw new Error("The selected runtime does not support uninstall.");
}
- return provider.uninstall(server, getSettingsContext(server, context), options);
+ return provider.uninstall(server, settingsContext, options);
}
export async function getRuntimeInstallCommand(
@@ -71,11 +80,12 @@ export async function getRuntimeInstallCommand(
mode: "install" | "update" = "install",
context?: LspRuntimeContext,
): Promise {
- const provider = await getProvider(server, context);
+ const settingsContext = getSettingsContext(server, context, "command");
+ const provider = await getProvider(server, context, "command");
return (
provider?.getInstallCommand?.(
server,
- getSettingsContext(server, context),
+ settingsContext,
mode,
) ?? null
);
@@ -85,11 +95,12 @@ export async function getRuntimeUninstallCommand(
server: LspServerDefinition,
context?: LspRuntimeContext,
): Promise {
- const provider = await getProvider(server, context);
+ const settingsContext = getSettingsContext(server, context, "command");
+ const provider = await getProvider(server, context, "command");
return (
provider?.getUninstallCommand?.(
server,
- getSettingsContext(server, context),
+ settingsContext,
) ?? null
);
}
diff --git a/src/cm/lsp/runtimes/builtinAlpine.ts b/src/cm/lsp/runtimes/builtinAlpine.ts
index 5e158bb6d..499ba1545 100644
--- a/src/cm/lsp/runtimes/builtinAlpine.ts
+++ b/src/cm/lsp/runtimes/builtinAlpine.ts
@@ -56,6 +56,10 @@ export const builtinAlpineRuntimeProvider: LspRuntimeProvider = {
server: LspServerDefinition,
context: LspRuntimeContext,
): boolean {
+ if (context.runtimeAction && server.launcher) {
+ return true;
+ }
+
return (
!!server.launcher &&
(canUseRealPath(context) ||
diff --git a/src/cm/lsp/runtimes/externalWebSocket.ts b/src/cm/lsp/runtimes/externalWebSocket.ts
index 90659bf8b..0d0d7e6ad 100644
--- a/src/cm/lsp/runtimes/externalWebSocket.ts
+++ b/src/cm/lsp/runtimes/externalWebSocket.ts
@@ -17,7 +17,10 @@ export const externalWebSocketRuntimeProvider: LspRuntimeProvider = {
label: "External WebSocket",
priority: -50,
- canHandle(server) {
+ canHandle(server, context) {
+ if (context.runtimeAction && server.launcher) {
+ return false;
+ }
return server.transport?.kind === "websocket" && !!server.transport.url;
},
diff --git a/src/cm/lsp/serverLauncher.ts b/src/cm/lsp/serverLauncher.ts
index 87f0a1852..c7db21e10 100644
--- a/src/cm/lsp/serverLauncher.ts
+++ b/src/cm/lsp/serverLauncher.ts
@@ -16,6 +16,7 @@ import {
} from "./runtimes/axsBridge";
import { getServerBundle } from "./serverCatalog";
import notificationManager from "lib/notificationManager";
+import { addLspLog } from "./logs";
import type {
InstallCheckResult,
InstallStatus,
@@ -278,6 +279,7 @@ export async function canReuseExistingServer(
(await checkServerAliveViaWebSocket(url, 1000)));
if (alive) {
+ addLspLog(server.id, "info", `Reusing existing server on port ${portInfo.port}`);
console.info(
`[LSP:${server.id}] Reusing existing server on port ${portInfo.port}`,
);
@@ -287,6 +289,7 @@ export async function canReuseExistingServer(
console.info(
`[LSP:${server.id}] Found stale port file, will start new server`,
);
+ addLspLog(server.id, "warn", "Found stale port file, starting a new server");
return null;
}
@@ -909,8 +912,10 @@ async function startInteractiveServer(
const callback: ExecutorCallback = (type, data) => {
if (type === "stderr") {
if (/proot warning/i.test(data)) return;
+ addLspLog(serverId, "stderr", data);
console.warn(`[LSP:${serverId}] ${data}`);
} else if (type === "stdout" && data && data.trim()) {
+ addLspLog(serverId, "info", data);
console.info(`[LSP:${serverId}] ${data}`);
// Detect when the axs proxy signals it's listening
if (/listening on/i.test(data)) {
@@ -919,6 +924,7 @@ async function startInteractiveServer(
}
};
const uuid = await executor.start(command, callback, true);
+ addLspLog(serverId, "info", `Started shell process ${uuid}`);
managedServers.set(serverId, {
uuid,
command,
@@ -1115,6 +1121,7 @@ export async function ensureServerRunning(
console.info(
`[LSP:${server.id}] Auto-discovered port ${discoveredPort}`,
);
+ addLspLog(server.id, "info", `Auto-discovered port ${discoveredPort}`);
// Update managed server entry with the port
const entry = managedServers.get(key);
if (entry) {
@@ -1137,12 +1144,14 @@ export async function ensureServerRunning(
if (!announcedServers.has(key)) {
console.info(`[LSP:${server.id}] ${server.label} connected`);
+ addLspLog(server.id, "info", `${server.label} connected`);
announcedServers.add(key);
}
return { uuid, discoveredPort };
} catch (error) {
console.error(`Failed to start language server ${server.id}`, error);
const errorMessage = error instanceof Error ? error.message : String(error);
+ addLspLog(server.id, "error", errorMessage || "Connection failed");
lspStatusBar.show({
message: errorMessage || "Connection failed",
title: `${server.label} failed`,
@@ -1173,6 +1182,7 @@ export async function ensureServerRunning(
export function stopManagedServer(serverId: string): void {
const entry = managedServers.get(serverId);
if (!entry) return;
+ addLspLog(serverId, "info", "Stopping managed server");
const executor = getExecutor();
executor.stop(entry.uuid).catch((error: Error) => {
console.warn(`Failed to stop language server ${serverId}`, error);
diff --git a/src/cm/lsp/transport.ts b/src/cm/lsp/transport.ts
index 3a9d0a71c..5697782b9 100644
--- a/src/cm/lsp/transport.ts
+++ b/src/cm/lsp/transport.ts
@@ -4,6 +4,7 @@
*/
import type { Transport } from "@codemirror/lsp-client";
+import { addLspLog } from "./logs";
import type {
LspServerDefinition,
TransportContext,
@@ -44,6 +45,7 @@ function createWebSocketTransport(
console.info(
`[LSP:${server.id}] Using auto-discovered port ${context.dynamicPort}`,
);
+ addLspLog(server.id, "info", `Using auto-discovered port ${context.dynamicPort}`);
}
// URL is only required when not using dynamic port
@@ -175,17 +177,24 @@ function createWebSocketTransport(
const wasClean = event.wasClean || event.code === 1000;
if (wasClean) {
console.info(`[LSP:${server.id}] WebSocket closed cleanly`);
+ addLspLog(server.id, "info", "WebSocket closed cleanly");
return;
}
console.warn(
`[LSP:${server.id}] WebSocket closed unexpectedly (code: ${event.code})`,
);
+ addLspLog(
+ server.id,
+ "warn",
+ `WebSocket closed unexpectedly (code: ${event.code})`,
+ );
if (enableReconnect && reconnectAttempts < maxReconnectAttempts) {
scheduleReconnect();
} else if (reconnectAttempts >= maxReconnectAttempts) {
console.error(`[LSP:${server.id}] Max reconnection attempts reached`);
+ addLspLog(server.id, "error", "Max reconnection attempts reached");
}
}
@@ -195,6 +204,7 @@ function createWebSocketTransport(
const reason =
errorEvent?.message || errorEvent?.type || "connection error";
console.error(`[LSP:${server.id}] WebSocket error: ${reason}`);
+ addLspLog(server.id, "error", `WebSocket error: ${reason}`);
}
function scheduleReconnect(): void {
@@ -209,6 +219,11 @@ function createWebSocketTransport(
console.info(
`[LSP:${server.id}] Reconnecting in ${delay}ms (attempt ${reconnectAttempts}/${maxReconnectAttempts})`,
);
+ addLspLog(
+ server.id,
+ "info",
+ `Reconnecting in ${delay}ms (attempt ${reconnectAttempts}/${maxReconnectAttempts})`,
+ );
reconnectTimer = setTimeout(() => {
reconnectTimer = null;
@@ -228,6 +243,7 @@ function createWebSocketTransport(
connected = true;
reconnectAttempts = 0;
console.info(`[LSP:${server.id}] Reconnected successfully`);
+ addLspLog(server.id, "info", "Reconnected successfully");
if (socket) {
socket.onopen = null;
}
diff --git a/src/cm/lsp/types.ts b/src/cm/lsp/types.ts
index 98174106f..1ea75b204 100644
--- a/src/cm/lsp/types.ts
+++ b/src/cm/lsp/types.ts
@@ -103,6 +103,7 @@ export interface LspRuntimeContext extends TransportContext {
serverId?: string;
workspaceKind?: WorkspaceKind;
allowNonTerminalWorkspace?: boolean;
+ runtimeAction?: "checkInstallation" | "install" | "uninstall" | "command";
}
export type LspClientScope = "workspace" | "document";
diff --git a/src/components/lspInfoDialog/index.js b/src/components/lspInfoDialog/index.js
index 190cbe0ec..c6e0afeb4 100644
--- a/src/components/lspInfoDialog/index.js
+++ b/src/components/lspInfoDialog/index.js
@@ -1,9 +1,11 @@
import "./styles.scss";
import lspClientManager from "cm/lsp/clientManager";
import {
+ getCurrentFileLanguage,
getServersForCurrentFile,
hasConnectedServers,
} from "cm/lsp/connectionState";
+import { addLspLog, clearLspLogs, getLspLogs } from "cm/lsp/logs";
import { getServerStats } from "cm/lsp/serverLauncher";
import toast from "components/toast";
import actionStack from "lib/actionStack";
@@ -11,136 +13,6 @@ import restoreTheme from "lib/restoreTheme";
let dialogInstance = null;
-const lspLogs = new Map();
-const MAX_LOGS = 200;
-const logListeners = new Set();
-const IGNORED_LOG_PATTERNS = [
- /\$\/progress\b/i,
- /\bProgress:/i,
- /\bwindow\/workDoneProgress\/create\b/i,
- /\bAuto-responded to window\/workDoneProgress\/create\b/i,
-];
-
-function shouldIgnoreLog(message) {
- if (typeof message !== "string") return false;
- return IGNORED_LOG_PATTERNS.some((pattern) => pattern.test(message));
-}
-
-function addLspLog(serverId, level, message, details = null) {
- if (shouldIgnoreLog(message)) {
- return;
- }
-
- if (!lspLogs.has(serverId)) {
- lspLogs.set(serverId, []);
- }
- const logs = lspLogs.get(serverId);
- const entry = {
- timestamp: new Date(),
- level,
- message,
- details,
- };
- logs.push(entry);
- if (logs.length > MAX_LOGS) {
- logs.shift();
- }
- logListeners.forEach((fn) => fn(serverId, entry));
-}
-
-function getLspLogs(serverId) {
- return lspLogs.get(serverId) || [];
-}
-
-function clearLspLogs(serverId) {
- lspLogs.delete(serverId);
-}
-
-const originalConsoleInfo = console.info;
-const originalConsoleWarn = console.warn;
-const originalConsoleError = console.error;
-
-function stripAnsi(str) {
- if (typeof str !== "string") return str;
- return str.replace(/\x1b\[[0-9;]*m/g, "");
-}
-
-function extractServerId(message) {
- const cleaned = stripAnsi(message);
- // Match [LSP:serverId] format
- const lspMatch = cleaned?.match?.(/\[LSP:([^\]]+)\]/);
- if (lspMatch) return lspMatch[1];
-
- // Match [LSP-STDERR:program] format from axs proxy
- const stderrMatch = cleaned?.match?.(/\[LSP-STDERR:([^\]]+)\]/);
- if (stderrMatch) {
- const program = stderrMatch[1];
- return program;
- }
-
- return null;
-}
-
-function extractLogMessage(message) {
- const cleaned = stripAnsi(message);
- // Strip [LSP:...] and [LSP-STDERR:...] prefixes
- // Strip ISO timestamps like 2026-02-05T08:26:24.745443Z
- // Strip log levels like INFO, WARN, ERROR and the source like axs::lsp:
- return (
- cleaned
- ?.replace?.(/\[LSP:[^\]]+\]\s*/, "")
- ?.replace?.(/\[LSP-STDERR:[^\]]+\]\s*/, "")
- ?.replace?.(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\s*/g, "")
- ?.replace?.(/\s*(INFO|WARN|ERROR|DEBUG|TRACE)\s+/gi, "")
- ?.replace?.(/[a-z_]+::[a-z_]+:\s*/gi, "")
- ?.trim() || cleaned
- );
-}
-
-console.info = function (...args) {
- originalConsoleInfo.apply(console, args);
- const msg = args[0];
- if (
- typeof msg === "string" &&
- (msg.includes("[LSP:") || msg.includes("[LSP-STDERR:"))
- ) {
- const serverId = extractServerId(msg);
- if (serverId) {
- addLspLog(serverId, "info", extractLogMessage(msg));
- }
- }
-};
-
-console.warn = function (...args) {
- originalConsoleWarn.apply(console, args);
- const msg = args[0];
- if (
- typeof msg === "string" &&
- (msg.includes("[LSP:") || msg.includes("[LSP-STDERR:"))
- ) {
- const serverId = extractServerId(msg);
- if (serverId) {
- // stderr from axs is logged as warn, mark it appropriately
- const isStderr = msg.includes("[LSP-STDERR:");
- addLspLog(serverId, isStderr ? "stderr" : "warn", extractLogMessage(msg));
- }
- }
-};
-
-console.error = function (...args) {
- originalConsoleError.apply(console, args);
- const msg = args[0];
- if (
- typeof msg === "string" &&
- (msg.includes("[LSP:") || msg.includes("[LSP-STDERR:"))
- ) {
- const serverId = extractServerId(msg);
- if (serverId) {
- addLspLog(serverId, "error", extractLogMessage(msg));
- }
- }
-};
-
function getActiveClients() {
try {
return lspClientManager.getActiveClients();
From 6c181ec0d08c6dc7e684bbeb1ab3e9edeb07e93e Mon Sep 17 00:00:00 2001
From: Ajit Kumar
Date: Sat, 27 Jun 2026 04:48:37 +0530
Subject: [PATCH 8/9] fix: small ui issue in plugin page
---
src/pages/plugin/plugin.scss | 68 ++++++++++++++++++++++++++++--------
1 file changed, 53 insertions(+), 15 deletions(-)
diff --git a/src/pages/plugin/plugin.scss b/src/pages/plugin/plugin.scss
index 3a55e7350..a33259b5f 100644
--- a/src/pages/plugin/plugin.scss
+++ b/src/pages/plugin/plugin.scss
@@ -5,6 +5,7 @@
max-width: 800px;
padding: 20px;
margin: 0 auto;
+ box-sizing: border-box;
.plugin-header {
display: grid;
@@ -379,26 +380,63 @@
}
@supports not (gap: 1px) {
- .plugin-header > * {
+ .plugin-header>* {
margin-right: 20px;
margin-bottom: 20px;
}
- .plugin-header > *:last-child {
+
+ .plugin-header>*:last-child {
margin-right: 0;
margin-bottom: 0;
}
- .title-wrapper > * + * { margin-left: 16px; }
- .source-indicator > * + * { margin-left: 6px; }
- .plugin-meta > * + * { margin-left: 16px; }
- .meta-item > * + * { margin-left: 4px; }
- .metrics-row > * + * { margin-left: 16px; }
- .metric > * + * { margin-left: 4px; }
- .keywords > * + * { margin-left: 6px; }
- .legacy-editor-warning > * + * { margin-left: 6px; }
- .action-buttons > * + * { margin-left: 8px; }
- .info:not(.icon) > * + * { margin-left: 5px; }
- .btn > * + * { margin-left: 6px; }
- .contributor > * + * { margin-left: 12px; }
+
+ .title-wrapper>*+* {
+ margin-left: 16px;
+ }
+
+ .source-indicator>*+* {
+ margin-left: 6px;
+ }
+
+ .plugin-meta>*+* {
+ margin-left: 16px;
+ }
+
+ .meta-item>*+* {
+ margin-left: 4px;
+ }
+
+ .metrics-row>*+* {
+ margin-left: 16px;
+ }
+
+ .metric>*+* {
+ margin-left: 4px;
+ }
+
+ .keywords>*+* {
+ margin-left: 6px;
+ }
+
+ .legacy-editor-warning>*+* {
+ margin-left: 6px;
+ }
+
+ .action-buttons>*+* {
+ margin-left: 8px;
+ }
+
+ .info:not(.icon)>*+* {
+ margin-left: 5px;
+ }
+
+ .btn>*+* {
+ margin-left: 6px;
+ }
+
+ .contributor>*+* {
+ margin-left: 12px;
+ }
}
@media (max-width: 768px) {
@@ -556,4 +594,4 @@
}
}
}
-}
+}
\ No newline at end of file
From 25fef29fe90ffc2dc979e87e40fb9dd085fbbdf3 Mon Sep 17 00:00:00 2001
From: Ajit Kumar
Date: Sat, 27 Jun 2026 18:19:29 +0530
Subject: [PATCH 9/9] fix: greptile review (#2401)
Co-authored-by: Ajit Kumar
---
src/cm/lsp/clientManager.ts | 2 ++
src/cm/lsp/codeActions.ts | 10 ++++++++++
src/cm/lsp/logs.ts | 28 ++++++++++++++++++++++++++++
src/cm/lsp/rename.ts | 8 ++++++++
src/cm/lsp/transport.ts | 1 +
src/cm/lsp/workspace.ts | 16 ++++++++++++++++
6 files changed, 65 insertions(+)
diff --git a/src/cm/lsp/clientManager.ts b/src/cm/lsp/clientManager.ts
index 196ef14a7..f95f539cc 100644
--- a/src/cm/lsp/clientManager.ts
+++ b/src/cm/lsp/clientManager.ts
@@ -268,6 +268,7 @@ interface ResolvedRuntimeTarget {
}
interface ExtendedLSPClient extends LSPClient {
+ __acodeServerId?: string;
__acodeLoggedInfo?: boolean;
}
@@ -888,6 +889,7 @@ export class LspClientManager {
);
await transportHandle.ready;
client = new LSPClient(clientConfig) as ExtendedLSPClient;
+ client.__acodeServerId = server.id;
connectClient(client, transportHandle.transport, initializationOptions);
await client.initializing;
if (!client.__acodeLoggedInfo) {
diff --git a/src/cm/lsp/codeActions.ts b/src/cm/lsp/codeActions.ts
index 7f5905761..736909dbd 100644
--- a/src/cm/lsp/codeActions.ts
+++ b/src/cm/lsp/codeActions.ts
@@ -12,6 +12,7 @@ import type {
WorkspaceEdit,
} from "vscode-languageserver-types";
import type { Position, Range } from "./types";
+import { addLspLogFor } from "./logs";
import type AcodeWorkspace from "./workspace";
type CodeActionResponse = (CodeAction | Command)[] | null;
@@ -116,6 +117,7 @@ async function resolveCodeAction(
);
return resolved ?? action;
} catch (error) {
+ addLspLogFor(plugin, "warn", "Code action resolve failed", error);
console.warn("[LSP:CodeAction] Failed to resolve:", error);
return action;
}
@@ -138,6 +140,7 @@ async function executeCommand(
// -32601 = Method not implemented (expected for some LSP servers)
const lspError = error as { code?: number };
if (lspError?.code !== -32601) {
+ addLspLogFor(plugin, "warn", "Code action command execution failed", error);
console.warn("[LSP:CodeAction] Command execution failed:", error);
}
return false;
@@ -173,6 +176,11 @@ async function applyChangesToFile(
const displayedView = await workspace.displayFile(uri);
if (!displayedView?.state?.doc) {
+ addLspLogFor(
+ workspace.client,
+ "warn",
+ `Code action could not open file: ${uri}`,
+ );
console.warn(`[LSP:CodeAction] Could not open file: ${uri}`);
return false;
}
@@ -326,6 +334,7 @@ export async function fetchCodeActions(
return items;
} catch (error) {
+ addLspLogFor(plugin, "error", "Code action fetch failed", error);
console.error("[LSP:CodeAction] Failed to fetch:", error);
return [];
}
@@ -349,6 +358,7 @@ export async function executeCodeAction(
// Handle CodeAction
return applyCodeAction(view, item.action);
} catch (error) {
+ addLspLogFor(plugin, "error", "Code action execution failed", error);
console.error("[LSP:CodeAction] Failed to execute:", error);
return false;
}
diff --git a/src/cm/lsp/logs.ts b/src/cm/lsp/logs.ts
index eb5dacd8d..dca83a9d1 100644
--- a/src/cm/lsp/logs.ts
+++ b/src/cm/lsp/logs.ts
@@ -72,6 +72,34 @@ export function addLspLog(
listeners.forEach((listener) => listener(id, entry));
}
+export function getLspLogServerId(source: unknown): string | null {
+ const client =
+ source &&
+ typeof source === "object" &&
+ Object.prototype.hasOwnProperty.call(source, "client")
+ ? (source as { client?: unknown }).client
+ : source;
+ const metadata = client as
+ | { __acodeServerId?: unknown }
+ | null
+ | undefined;
+ const serverId = metadata?.__acodeServerId;
+ return typeof serverId === "string" && serverId.trim()
+ ? serverId.trim()
+ : null;
+}
+
+export function addLspLogFor(
+ source: unknown,
+ level: LspLogLevel,
+ message: unknown,
+ details?: unknown,
+): void {
+ const serverId = getLspLogServerId(source);
+ if (!serverId) return;
+ addLspLog(serverId, level, message, details);
+}
+
export function getLspLogs(serverId: string): LspLogEntry[] {
return logsByServer.get(String(serverId || "").trim()) || [];
}
diff --git a/src/cm/lsp/rename.ts b/src/cm/lsp/rename.ts
index 1ba871f91..6ce0ff212 100644
--- a/src/cm/lsp/rename.ts
+++ b/src/cm/lsp/rename.ts
@@ -7,6 +7,7 @@ import {
} from "@codemirror/view";
import prompt from "dialogs/prompt";
import type * as lsp from "vscode-languageserver-protocol";
+import { addLspLogFor } from "./logs";
import type AcodeWorkspace from "./workspace";
interface RenameParams {
@@ -106,6 +107,7 @@ async function performRename(view: EditorView): Promise {
}
}
} catch (error) {
+ addLspLogFor(plugin, "warn", "Rename prepare failed; using word", error);
console.warn("[LSP:Rename] prepareRename failed, using word:", error);
}
}
@@ -133,6 +135,7 @@ async function performRename(view: EditorView): Promise {
try {
await doRename(view, String(newName), wordRange.from);
} catch (error) {
+ addLspLogFor(plugin, "error", "Rename failed", error);
console.error("[LSP:Rename] Rename failed:", error);
const errorMessage =
error instanceof Error ? error.message : "Failed to rename symbol";
@@ -176,6 +179,7 @@ async function applyChangesToFile(
const displayedView = await workspace.displayFile(uri);
if (!displayedView?.state?.doc) {
+ addLspLogFor(workspace.client, "warn", `Rename could not open file: ${uri}`);
console.warn(`[LSP:Rename] Could not open file: ${uri}`);
return false;
}
@@ -211,6 +215,7 @@ async function doRename(
);
if (!response) {
+ addLspLogFor(plugin, "info", "Rename returned no changes");
console.info("[LSP:Rename] No changes returned from server");
return;
}
@@ -255,10 +260,13 @@ async function doRename(
console.info(
`[LSP:Rename] Renamed to "${newName}" in ${filesChanged} file(s)`,
);
+ addLspLogFor(plugin, "info", `Renamed to "${newName}" in ${filesChanged} file(s)`);
}
export const renameSymbol: Command = (view) => {
performRename(view).catch((error) => {
+ const plugin = LSPPlugin.get(view);
+ addLspLogFor(plugin, "error", "Rename command failed", error);
console.error("[LSP:Rename] Rename command failed:", error);
});
return true;
diff --git a/src/cm/lsp/transport.ts b/src/cm/lsp/transport.ts
index 5697782b9..d760893ac 100644
--- a/src/cm/lsp/transport.ts
+++ b/src/cm/lsp/transport.ts
@@ -250,6 +250,7 @@ function createWebSocketTransport(
};
} catch (error) {
console.error(`[LSP:${server.id}] Reconnection failed`, error);
+ addLspLog(server.id, "error", "Reconnection failed", error);
if (reconnectAttempts < maxReconnectAttempts) {
scheduleReconnect();
}
diff --git a/src/cm/lsp/workspace.ts b/src/cm/lsp/workspace.ts
index 01a071dee..0ac350ff8 100644
--- a/src/cm/lsp/workspace.ts
+++ b/src/cm/lsp/workspace.ts
@@ -3,6 +3,7 @@ import { LSPPlugin, Workspace } from "@codemirror/lsp-client";
import type { Text, TransactionSpec } from "@codemirror/state";
import type { EditorView } from "@codemirror/view";
import { getModeForPath } from "cm/modelist";
+import { addLspLogFor, type LspLogLevel } from "./logs";
import type { WorkspaceFileUpdate, WorkspaceOptions } from "./types";
class AcodeWorkspaceFile implements WorkspaceFile {
@@ -55,6 +56,10 @@ export default class AcodeWorkspace extends Workspace {
this.options = options;
}
+ #log(level: LspLogLevel, message: string, details?: unknown): void {
+ addLspLogFor(this.client, level, message, details);
+ }
+
#getOrCreateFile(
uri: string,
languageId: string,
@@ -110,6 +115,11 @@ export default class AcodeWorkspace extends Workspace {
return String(mode.name).toLowerCase();
}
} catch (error) {
+ this.#log(
+ "warn",
+ `Workspace failed to resolve language id for ${uri}`,
+ error,
+ );
console.warn(
`[LSP:Workspace] Failed to resolve language id for ${uri}`,
error,
@@ -182,6 +192,7 @@ export default class AcodeWorkspace extends Workspace {
// File is not open - try to open it and apply the update
this.#applyUpdateToClosedFile(uri, update).catch((error) => {
+ this.#log("warn", `Workspace failed to apply update: ${uri}`, error);
console.warn(`[LSP:Workspace] Failed to apply update: ${uri}`, error);
});
}
@@ -202,6 +213,7 @@ export default class AcodeWorkspace extends Workspace {
fileView.dispatch(update);
}
} catch (error) {
+ this.#log("error", `Workspace failed to apply update: ${uri}`, error);
console.error(`[LSP:Workspace] Failed to apply update: ${uri}`, error);
}
}
@@ -211,6 +223,7 @@ export default class AcodeWorkspace extends Workspace {
try {
return await this.options.displayFile(uri);
} catch (error) {
+ this.#log("error", "Workspace failed to display file", error);
console.error("[LSP:Workspace] Failed to display file", error);
}
}
@@ -234,6 +247,7 @@ export default class AcodeWorkspace extends Workspace {
};
if (!client.connected || !client.transport) {
+ this.#log("warn", "Workspace cannot send notification: not connected");
console.warn(`[LSP:Workspace] Cannot send notification: not connected`);
return;
}
@@ -268,6 +282,7 @@ export default class AcodeWorkspace extends Workspace {
},
});
console.info(`[LSP:Workspace] Added workspace folder: ${uri}`);
+ this.#log("info", `Workspace folder added: ${uri}`);
return true;
}
@@ -284,6 +299,7 @@ export default class AcodeWorkspace extends Workspace {
},
});
console.info(`[LSP:Workspace] Removed workspace folder: ${uri}`);
+ this.#log("info", `Workspace folder removed: ${uri}`);
return true;
}
}