Summary
After exploring the Positron source code (posit-dev/positron), I identified a significant architectural improvement for how the extension communicates with the R runtime. The current approach of writing to temporary files and polling with setTimeout is fragile and race-condition prone. Positron provides a purpose-built API for this exact use case: positron.runtime.evaluateCode().
Current Pattern (Anti-pattern)
Multiple files (src/makeExplicit.js, src/fixLint.js, src/checkR.js) follow this flow:
- Write data to a temp file.
- Call
positron.runtime.executeCode('r', ...).
await new Promise(resolve => setTimeout(resolve, 100)).
- Read the temp file back.
- Parse string prefixes like
Error_001, Error_002.
This is unreliable because:
- 100ms may not be enough on slow systems.
- It leaves orphaned temp files if an error occurs before cleanup.
- It requires string-based error signaling instead of proper exception handling.
Recommended Pattern
Positron exposes evaluateCode() specifically for silent, promise-based evaluation:
export function evaluateCode(
languageId: string,
code: string,
cancellationToken?: vscode.CancellationToken,
sessionId?: string
): Thenable<EvalResult>;
export interface EvalResult {
result: any;
output: string;
}
Example: checkR.js
Before:
const r_check_command = `writeLines(as.character(...), con = '${normalizedPath}')`;
await positron.runtime.executeCode('r', r_check_command, false, false, positron.RuntimeCodeExecutionMode.Silent);
await new Promise(resolve => setTimeout(resolve, 100));
const output = await fs.readFile(tempFilePath, { encoding: 'utf8' });
After:
const evalResult = await positron.runtime.evaluateCode(
'r',
'as.character(c(nchar(system.file(package = "pedant")) != 0, nchar(system.file(package = "remotes")) != 0, nchar(system.file(package = "pak")) != 0))'
);
const [pedant, remotes, pak] = evalResult.result;
Other Improvements
- Use
finally blocks for temp file cleanup to prevent orphaned files.
- Add
try/catch around evaluateCode to handle R execution failures gracefully.
- Use
vscode.window.withProgress when running pedant::explicitize() on large selections.
- Add
@types/positron reference in jsconfig.json for better IntelliSense.
References
Summary
After exploring the Positron source code (posit-dev/positron), I identified a significant architectural improvement for how the extension communicates with the R runtime. The current approach of writing to temporary files and polling with
setTimeoutis fragile and race-condition prone. Positron provides a purpose-built API for this exact use case:positron.runtime.evaluateCode().Current Pattern (Anti-pattern)
Multiple files (
src/makeExplicit.js,src/fixLint.js,src/checkR.js) follow this flow:positron.runtime.executeCode('r', ...).await new Promise(resolve => setTimeout(resolve, 100)).Error_001,Error_002.This is unreliable because:
Recommended Pattern
Positron exposes
evaluateCode()specifically for silent, promise-based evaluation:Example:
checkR.jsBefore:
After:
Other Improvements
finallyblocks for temp file cleanup to prevent orphaned files.try/catcharoundevaluateCodeto handle R execution failures gracefully.vscode.window.withProgresswhen runningpedant::explicitize()on large selections.@types/positronreference injsconfig.jsonfor better IntelliSense.References
evaluateCodeAPI definition:src/positron-dts/positron.d.tsextensions/vscode-api-tests/src/singlefolder-tests/positron/runtime.test.ts