From ba918b90b0837b3a64cbb597388b4fe316cee6e6 Mon Sep 17 00:00:00 2001 From: Fred Wu Date: Thu, 16 Jul 2026 11:05:07 +1000 Subject: [PATCH] Fixed R errors not appearing in the output channel --- CHANGELOG.md | 12 ++++++ package-lock.json | 4 +- package.json | 2 +- resources/r/console-language-server.R | 3 +- src/Language/consoleLspClient.ts | 62 ++++++++++++++++----------- 5 files changed, 53 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 217f513..fc82cba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to R Console will be documented in this file. +## [0.4.3] - 2026-07-16 + +### Recent changes + +- Added a dedicated `R Console Language Server` output channel that reports server starts, stops, errors and the R executable location, without showing language-server protocol traffic. +- Added `F7` to open console completions anywhere, including positions without a completion prefix or context. +- Added `Restore Default Name` to the console tab menu for returning a renamed console to `R Console (PID)`. + +### Fixed + +- Fixed R errors not appearing in the output channel, while keeping debug and language-server protocol traffic hidden. + ## [0.4.2] - 2026-07-15 ### Added diff --git a/package-lock.json b/package-lock.json index c942b4a..02c6b4f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vsc-r-console", - "version": "0.4.2", + "version": "0.4.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "vsc-r-console", - "version": "0.4.2", + "version": "0.4.3", "license": "SEE LICENSE IN LICENSE", "dependencies": { "@xterm/headless": "^6.0.0", diff --git a/package.json b/package.json index 343bd07..0f6c454 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "vsc-r-console", "displayName": "R Console for VS Code", "description": "A lightweight R console for VS Code", - "version": "0.4.2", + "version": "0.4.3", "publisher": "RConsole", "license": "SEE LICENSE IN LICENSE", "icon": "images/Rlogo.png", diff --git a/resources/r/console-language-server.R b/resources/r/console-language-server.R index ae23818..7f77593 100644 --- a/resources/r/console-language-server.R +++ b/resources/r/console-language-server.R @@ -17,7 +17,6 @@ if (use_renv_lib_path) { } .libPaths(.paths) -message("R library paths: ", paste(.libPaths(), collapse = "\n")) if (!requireNamespace("languageserver", quietly = TRUE)) { q(save = "no", status = 10) @@ -35,8 +34,8 @@ tools::Rd2txt_options(underline_titles = FALSE) tools::Rd2txt_options(itemBullet = "* ") languageserver:::lsp_settings$update_from_options() languageserver:::lsp_settings$set("diagnostics", FALSE) +languageserver:::lsp_settings$set("debug", isTRUE(debug)) if (isTRUE(debug)) { - languageserver:::lsp_settings$set("debug", TRUE) languageserver:::lsp_settings$set("log_file", NULL) } diff --git a/src/Language/consoleLspClient.ts b/src/Language/consoleLspClient.ts index e7ce53a..8ca6528 100644 --- a/src/Language/consoleLspClient.ts +++ b/src/Language/consoleLspClient.ts @@ -3,6 +3,7 @@ import * as fs from "fs"; import * as net from "net"; import * as os from "os"; import * as path from "path"; +import * as readline from "readline"; import { URL } from "url"; import * as vscode from "vscode"; import { @@ -126,7 +127,7 @@ export class ConsoleLspClient implements CompletionProvider { })() .catch(async (error) => { if (!this.disposed) { - this.logServerError(error, this.spawnedServer); + this.logServerError(error); } const failedClient = this.client; this.client = undefined; @@ -335,13 +336,13 @@ export class ConsoleLspClient implements CompletionProvider { errorHandler: { error: (error) => { if (this.client) { - this.logServerError(error, this.spawnedServer); + this.logServerError(error); } return { action: ErrorAction.Continue, handled: true }; }, closed: () => { if (this.client) { - this.logServerError("connection closed unexpectedly", this.spawnedServer); + this.logServerError("connection closed unexpectedly"); } return { action: CloseAction.DoNotRestart, handled: true }; }, @@ -379,11 +380,9 @@ export class ConsoleLspClient implements CompletionProvider { } this.spawnedServer = child; - child.stderr?.on("data", (data: Buffer | string) => { - this.outputChannel.appendLine(data.toString()); - }); + this.forwardServerStderr(child); child.once("spawn", () => { - this.logServerStarted(child); + this.logServerStarted(); if (settled) { return; } @@ -397,7 +396,7 @@ export class ConsoleLspClient implements CompletionProvider { }); child.once("error", (error) => { if (settled) { - this.logServerError(error, child); + this.logServerError(error); } if (!settled) { settled = true; @@ -405,7 +404,7 @@ export class ConsoleLspClient implements CompletionProvider { } }); child.once("exit", (code, signal) => { - this.logServerStopped(child); + this.logServerStopped(code, signal); if (code === 10) { void vscode.window.showWarningMessage( "R package {languageserver} is required for console autocompletion." @@ -494,20 +493,18 @@ export class ConsoleLspClient implements CompletionProvider { return; } this.spawnedServer = child; - child.stderr?.on("data", (data: Buffer | string) => { - this.outputChannel.appendLine(data.toString()); - }); + this.forwardServerStderr(child); child.once("spawn", () => { - this.logServerStarted(child); + this.logServerStarted(); }); child.once("error", (error) => { if (settled) { - this.logServerError(error, child); + this.logServerError(error); } rejectOnce(error); }); child.once("exit", (code, signal) => { - this.logServerStopped(child); + this.logServerStopped(code, signal); if (code === 10) { void vscode.window.showWarningMessage( "R package {languageserver} is required for console autocompletion." @@ -583,12 +580,13 @@ export class ConsoleLspClient implements CompletionProvider { private buildServerEnv(config: vscode.WorkspaceConfiguration): NodeJS.ProcessEnv { const env: NodeJS.ProcessEnv = { ...this.options.env }; - const debug = config.get("lsp.debug") === true; const useRenvLibPath = config.get("useRenvLibPath") === true; const lang = config.get("lsp.lang") ?? ""; const libPaths = config.get("libPaths") ?? []; - env.VSCR_LSP_DEBUG = debug ? "TRUE" : "FALSE"; + // The lifecycle channel reports errors only; languageserver writes its + // debug and info entries to the same stderr stream as errors. + env.VSCR_LSP_DEBUG = "FALSE"; env.VSCR_USE_RENV_LIB_PATH = useRenvLibPath ? "TRUE" : "FALSE"; env.VSCR_LIB_PATHS = libPaths.join("\n"); if (lang) { @@ -621,28 +619,42 @@ export class ConsoleLspClient implements CompletionProvider { } } - private logServerStarted(child: ChildProcess): void { + private logServerStarted(): void { const timestamp = formatLogTimestamp(); lifecycleOutputChannel.appendLine( - `[Info - ${timestamp}] R Console Language Server (${child.pid ?? "unknown"}) started` + `[Info - ${timestamp}] R Console language server started` ); lifecycleOutputChannel.appendLine( `[Info - ${timestamp}] R executable: "${this.options.rPath}"` ); } - private logServerError(error: unknown, child: ChildProcess | undefined = this.spawnedServer): void { + private logServerError(error: unknown): void { const message = error instanceof Error ? error.message : String(error); lifecycleOutputChannel.appendLine( - `[Error - ${formatLogTimestamp()}] ` + - `R Console Language Server (${child?.pid ?? "unknown"}) error: ${message}` + `[Error - ${formatLogTimestamp()}] ${message}` ); } - private logServerStopped(child: ChildProcess): void { + private forwardServerStderr(child: ChildProcess): void { + if (!child.stderr) { + return; + } + const lines = readline.createInterface({ input: child.stderr }); + lines.on("line", (line) => { + lifecycleOutputChannel.appendLine( + `[R stderr - ${formatLogTimestamp()}] ${line}` + ); + }); + } + + private logServerStopped( + code: number | null, + signal: NodeJS.Signals | null + ): void { + const result = signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`; lifecycleOutputChannel.appendLine( - `[Info - ${formatLogTimestamp()}] ` + - `R Console Language Server (${child.pid ?? "unknown"}) stopped` + `[Info - ${formatLogTimestamp()}] stopped (${result})` ); }