From 049900bc695e8ec5c2fd3745ddd69c3cd7c9cb8b Mon Sep 17 00:00:00 2001 From: Andrew Craig Date: Sun, 6 Oct 2019 16:28:56 +0900 Subject: [PATCH 1/4] Remove redundant functions --- src/extension.ts | 19 +------------------ src/util.ts | 9 --------- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 11981feb9..8440ee336 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -9,7 +9,7 @@ import { previewDataframe, previewEnvironment } from "./preview"; import { createGitignore } from "./rGitignore"; import { createRTerm, deleteTerminal, rTerm } from "./rTerminal"; import { getSelection } from "./selection"; -import { config, delay } from "./util"; +import { config, delay, ToRStringLiteral } from "./util"; const wordPattern = /(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\<\>\/\s]+)/g; @@ -205,23 +205,6 @@ export function activate(context: ExtensionContext) { commands.registerCommand("r.document", documentPkg), window.onDidCloseTerminal(deleteTerminal), ); - - function ToRStringLiteral(s: string, quote: string) { - if (s === null) { - return "NULL"; - } - return (quote + - s.replace(/\\/g, "\\\\") - .replace(/"""/g, "\\" + quote) - .replace(/\\n/g, "\\n") - .replace(/\\r/g, "\\r") - .replace(/\\t/g, "\\t") - .replace(/\\b/g, "\\b") - .replace(/\\a/g, "\\a") - .replace(/\\f/g, "\\f") - .replace(/\\v/g, "\\v") + - quote); - } } // This method is called when your extension is deactivated diff --git a/src/util.ts b/src/util.ts index 1d3533c7c..4a7e82170 100644 --- a/src/util.ts +++ b/src/util.ts @@ -45,12 +45,3 @@ export function checkForSpecialCharacters(text) { export function checkIfFileExists(filePath) { return fs.existsSync(filePath); } - -export function assertRTerminalCreation(rTerm): boolean { - if (!rTerm) { - window.showErrorMessage("Could not create R terminal."); - return false; - } else { - return true; - } -} From 84f4558424f2d6ac0c993e2c04f7ef42787a8fdd Mon Sep 17 00:00:00 2001 From: Andrew Craig Date: Sun, 6 Oct 2019 14:19:23 +0900 Subject: [PATCH 2/4] Move send text functions into rTerminal --- src/extension.ts | 71 ++---------------------------------------------- src/rTerminal.ts | 71 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 71 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 8440ee336..c9ff05b2f 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -7,9 +7,8 @@ import { commands, CompletionItem, ExtensionContext, IndentAction, import { buildPkg, documentPkg, installPkg, loadAllPkg, testPkg } from "./package"; import { previewDataframe, previewEnvironment } from "./preview"; import { createGitignore } from "./rGitignore"; -import { createRTerm, deleteTerminal, rTerm } from "./rTerminal"; -import { getSelection } from "./selection"; -import { config, delay, ToRStringLiteral } from "./util"; +import { chooseTerminal, createRTerm, deleteTerminal, rTerm, runSelectionInTerm, setFocus } from "./rTerminal"; +import { config, ToRStringLiteral } from "./util"; const wordPattern = /(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\<\>\/\s]+)/g; @@ -87,40 +86,6 @@ export function activate(context: ExtensionContext) { runSelectionInTerm(callableTerminal, rFunctionName); } - async function chooseTerminal() { - if (window.terminals.length > 0) { - const RTermNameOpinions = ["R", "R Interactive"]; - if (window.activeTerminal) { - const activeTerminalName = window.activeTerminal.name; - if (RTermNameOpinions.includes(activeTerminalName)) { - return window.activeTerminal; - } - } else { - // Creating a terminal when there aren't any already - // does not seem to set activeTerminal - if (window.terminals.length === 1) { - const activeTerminalName = window.terminals[0].name; - if (RTermNameOpinions.includes(activeTerminalName)) { - return window.terminals[0]; - } - } else { - // tslint:disable-next-line: max-line-length - window.showInformationMessage("Error identifying terminal! This shouldn't happen, so please file an issue at https://github.com/Ikuyadeu/vscode-R/issues"); - return null; - } - } - } - - if (!rTerm) { - const success = createRTerm(true); - await delay(200); // Let RTerm warm up - if (!success) { - return null; - } - } - return rTerm; - } - function runSelectionInActiveTerm(rFunctionName: string[]) { if (window.terminals.length < 1) { window.showInformationMessage("There are no open terminals."); @@ -130,38 +95,6 @@ export function activate(context: ExtensionContext) { } } - async function runSelectionInTerm(term: Terminal, rFunctionName: string[]) { - const selection = getSelection(); - if (selection.linesDownToMoveCursor > 0) { - commands.executeCommand("cursorMove", { to: "down", value: selection.linesDownToMoveCursor }); - commands.executeCommand("cursorMove", { to: "wrappedLineFirstNonWhitespaceCharacter" }); - } - - if (selection.selectedTextArray.length > 1 && config.get("bracketedPaste")) { - // Surround with ANSI control characters for bracketed paste mode - selection.selectedTextArray[0] = "\x1b[200~" + selection.selectedTextArray[0]; - selection.selectedTextArray[selection.selectedTextArray.length - 1] += "\x1b[201~"; - } - - for (let line of selection.selectedTextArray) { - await delay(8); // Increase delay if RTerm can't handle speed. - - if (rFunctionName && rFunctionName.length) { - let rFunctionCall = ""; - for (const feature of rFunctionName) { - rFunctionCall += feature + "("; - } - line = rFunctionCall + line.trim() + ")".repeat(rFunctionName.length); - } - term.sendText(line); - } - } - - function setFocus(term: Terminal) { - const focus = config.get("source.focus") as string; - term.show(focus !== "terminal"); - } - languages.registerCompletionItemProvider("r", { provideCompletionItems(document: TextDocument, position: Position) { if (document.lineAt(position).text.substr(0, 2) === "#'") { diff --git a/src/rTerminal.ts b/src/rTerminal.ts index b64452acf..ae721adab 100644 --- a/src/rTerminal.ts +++ b/src/rTerminal.ts @@ -1,8 +1,9 @@ "use strict"; import fs = require("fs-extra"); -import { Terminal, window } from "vscode"; -import { config, getRpath } from "./util"; +import { commands, Terminal, window } from "vscode"; +import { getSelection } from "./selection"; +import { config, delay, getRpath } from "./util"; export let rTerm: Terminal; export function createRTerm(preserveshow?: boolean): boolean { @@ -29,3 +30,69 @@ export function deleteTerminal(term: Terminal) { rTerm = null; } } + +export async function chooseTerminal() { + if (window.terminals.length > 0) { + const RTermNameOpinions = ["R", "R Interactive"]; + if (window.activeTerminal) { + const activeTerminalName = window.activeTerminal.name; + if (RTermNameOpinions.includes(activeTerminalName)) { + return window.activeTerminal; + } + } else { + // Creating a terminal when there aren't any already + // does not seem to set activeTerminal + if (window.terminals.length === 1) { + const activeTerminalName = window.terminals[0].name; + if (RTermNameOpinions.includes(activeTerminalName)) { + return window.terminals[0]; + } + } else { + // tslint:disable-next-line: max-line-length + window.showInformationMessage("Error identifying terminal! This shouldn't happen, so please file an issue at https://github.com/Ikuyadeu/vscode-R/issues"); + return null; + } + } + } + + if (!rTerm) { + const success = createRTerm(true); + await delay(200); // Let RTerm warm up + if (!success) { + return null; + } + } + return rTerm; +} + +export async function runSelectionInTerm(term: Terminal, rFunctionName: string[]) { + const selection = getSelection(); + if (selection.linesDownToMoveCursor > 0) { + commands.executeCommand("cursorMove", { to: "down", value: selection.linesDownToMoveCursor }); + commands.executeCommand("cursorMove", { to: "wrappedLineFirstNonWhitespaceCharacter" }); + } + + if (selection.selectedTextArray.length > 1 && config.get("bracketedPaste")) { + // Surround with ANSI control characters for bracketed paste mode + selection.selectedTextArray[0] = "\x1b[200~" + selection.selectedTextArray[0]; + selection.selectedTextArray[selection.selectedTextArray.length - 1] += "\x1b[201~"; + } + + for (let line of selection.selectedTextArray) { + await delay(8); // Increase delay if RTerm can't handle speed. + + if (rFunctionName && rFunctionName.length) { + let rFunctionCall = ""; + for (const feature of rFunctionName) { + rFunctionCall += feature + "("; + } + line = rFunctionCall + line.trim() + ")".repeat(rFunctionName.length); + } + term.sendText(line); + } +} + +export function setFocus(term: Terminal) { + const focus = config.get("source.focus") as string; + term.show(focus !== "terminal"); +} From 692f491950e39398b7f42df087381ac739c5485d Mon Sep 17 00:00:00 2001 From: Andrew Craig Date: Sun, 6 Oct 2019 14:22:02 +0900 Subject: [PATCH 3/4] Add alwaysUseActiveTerminal setting --- README.md | 1 + package.json | 5 +++++ src/extension.ts | 43 +++++++++++++++------------------------ src/package.ts | 53 ------------------------------------------------ src/preview.ts | 14 +++---------- src/rTerminal.ts | 24 ++++++++++++++++++++-- 6 files changed, 47 insertions(+), 93 deletions(-) delete mode 100644 src/package.ts diff --git a/README.md b/README.md index 422d6d115..bbe04f601 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Requires [R](https://www.r-project.org/). ![Create R terminal](images/terminal.png) * Run code in terminal containing existing R session, for example over SSH (`Run Selection/Line in Active Terminal`) +* Run all commands in terminal containing existing R session (enable config `r.alwaysUseActiveTerminal`) ![R over SSH](images/ssh.gif) diff --git a/package.json b/package.json index e510ec9a0..540e0eeba 100644 --- a/package.json +++ b/package.json @@ -352,6 +352,11 @@ ], "description": "Keeping focus when running" }, + "r.alwaysUseActiveTerminal": { + "type": "boolean", + "default": false, + "description": "If enabled, will use active terminal for all commands, rather than creating a new R terminal" + }, "r.bracketedPaste": { "type": "boolean", "default": false, diff --git a/src/extension.ts b/src/extension.ts index c9ff05b2f..c27d1f9eb 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -3,11 +3,11 @@ // Import the module and reference it with the alias vscode in your code below import { isNull } from "util"; import { commands, CompletionItem, ExtensionContext, IndentAction, - languages, Position, Terminal, TextDocument, window } from "vscode"; -import { buildPkg, documentPkg, installPkg, loadAllPkg, testPkg } from "./package"; + languages, Position, TextDocument, window } from "vscode"; import { previewDataframe, previewEnvironment } from "./preview"; import { createGitignore } from "./rGitignore"; -import { chooseTerminal, createRTerm, deleteTerminal, rTerm, runSelectionInTerm, setFocus } from "./rTerminal"; +import { chooseTerminal, chooseTerminalAndSendText, createRTerm, deleteTerminal, + runSelectionInTerm } from "./rTerminal"; import { config, ToRStringLiteral } from "./util"; const wordPattern = /(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\<\>\/\s]+)/g; @@ -46,12 +46,7 @@ export function activate(context: ExtensionContext) { if (echo) { rPath = [rPath, "echo = TRUE"].join(", "); } - if (!rTerm) { - const success = createRTerm(true); - if (!success) { return; } - } - rTerm.sendText(`source(${rPath})`); - setFocus(rTerm); + chooseTerminalAndSendText(`source(${rPath})`); } function knitRmd(echo: boolean, outputFormat: string) { @@ -66,14 +61,10 @@ export function activate(context: ExtensionContext) { if (echo) { rPath = [rPath, "echo = TRUE"].join(", "); } - if (!rTerm) { - const success = createRTerm(true); - if (!success) { return; } - } if (isNull(outputFormat)) { - rTerm.sendText(`rmarkdown::render(${rPath})`); + chooseTerminalAndSendText(`rmarkdown::render(${rPath})`); } else { - rTerm.sendText(`rmarkdown::render(${rPath}, "${outputFormat}")`); + chooseTerminalAndSendText(`rmarkdown::render(${rPath}, "${outputFormat}")`); } } @@ -82,17 +73,15 @@ export function activate(context: ExtensionContext) { if (isNull(callableTerminal)) { return; } - setFocus(callableTerminal); runSelectionInTerm(callableTerminal, rFunctionName); } - function runSelectionInActiveTerm(rFunctionName: string[]) { - if (window.terminals.length < 1) { - window.showInformationMessage("There are no open terminals."); - } else { - runSelectionInTerm(window.activeTerminal, rFunctionName); - setFocus(window.activeTerminal); + async function runSelectionInActiveTerm(rFunctionName: string[]) { + const callableTerminal = await chooseTerminal(true); + if (isNull(callableTerminal)) { + return; } + runSelectionInTerm(callableTerminal, rFunctionName); } languages.registerCompletionItemProvider("r", { @@ -131,11 +120,11 @@ export function activate(context: ExtensionContext) { commands.registerCommand("r.createGitignore", createGitignore), commands.registerCommand("r.previewDataframe", previewDataframe), commands.registerCommand("r.previewEnvironment", previewEnvironment), - commands.registerCommand("r.loadAll", loadAllPkg), - commands.registerCommand("r.test", testPkg), - commands.registerCommand("r.install", installPkg), - commands.registerCommand("r.build", buildPkg), - commands.registerCommand("r.document", documentPkg), + commands.registerCommand("r.loadAll", () => chooseTerminalAndSendText("devtools::load_all()")), + commands.registerCommand("r.test", () => chooseTerminalAndSendText("devtools::test()")), + commands.registerCommand("r.install", () => chooseTerminalAndSendText("devtools::install()")), + commands.registerCommand("r.build", () => chooseTerminalAndSendText("devtools::build()")), + commands.registerCommand("r.document", () => chooseTerminalAndSendText("devtools::document()")), window.onDidCloseTerminal(deleteTerminal), ); } diff --git a/src/package.ts b/src/package.ts deleted file mode 100644 index 3ed3e1eab..000000000 --- a/src/package.ts +++ /dev/null @@ -1,53 +0,0 @@ -"use strict"; - -import { createRTerm, rTerm } from "./rTerminal"; - -export async function loadAllPkg() { - if (!rTerm) { - const success = createRTerm(true); - if (!success) { return; } - } - - const rLoadAllCommand = "devtools::load_all('.')"; - rTerm.sendText(rLoadAllCommand); -} - -export async function testPkg() { - if (!rTerm) { - const success = createRTerm(true); - if (!success) { return; } - } - - const rTestCommand = "devtools::test()"; - rTerm.sendText(rTestCommand); -} - -export async function installPkg() { - if (!rTerm) { - const success = createRTerm(true); - if (!success) { return; } - } - - const rInstallCommand = "devtools::install()"; - rTerm.sendText(rInstallCommand); -} - -export async function buildPkg() { - if (!rTerm) { - const success = createRTerm(true); - if (!success) { return; } - } - - const rBuildCommand = "devtools::build()"; - rTerm.sendText(rBuildCommand); -} - -export async function documentPkg() { - if (!rTerm) { - const success = createRTerm(true); - if (!success) { return; } - } - - const rDocumentCommand = "devtools::document()"; - rTerm.sendText(rDocumentCommand); -} diff --git a/src/preview.ts b/src/preview.ts index ba9b85616..4646e5f20 100644 --- a/src/preview.ts +++ b/src/preview.ts @@ -2,15 +2,11 @@ import fs = require("fs-extra"); import { commands, extensions, window, workspace } from "vscode"; -import { createRTerm, rTerm } from "./rTerminal"; +import { chooseTerminalAndSendText } from "./rTerminal"; import { getSelection } from "./selection"; import { checkForSpecialCharacters, checkIfFileExists, delay } from "./util"; export async function previewEnvironment() { - if (!rTerm) { - const success = createRTerm(true); - if (!success) { return; } - } if (!checkcsv()) { return; } @@ -24,15 +20,11 @@ export async function previewEnvironment() { + envClass + "," + envOut + "), '" + pathToTmpCsv + "', row.names=FALSE, quote = TRUE)"; - rTerm.sendText(rWriteCsvCommand); + chooseTerminalAndSendText(rWriteCsvCommand); await openTmpCSV(pathToTmpCsv, tmpDir); } export async function previewDataframe() { - if (!rTerm) { - const success = createRTerm(true); - if (!success) { return; } - } if (!checkcsv()) { return; } @@ -52,7 +44,7 @@ export async function previewDataframe() { const rWriteCsvCommand = "write.csv(" + dataframeName + ", '" + pathToTmpCsv + "', row.names = FALSE, quote = FALSE)"; - rTerm.sendText(rWriteCsvCommand); + chooseTerminalAndSendText(rWriteCsvCommand); await openTmpCSV(pathToTmpCsv, tmpDir); } diff --git a/src/rTerminal.ts b/src/rTerminal.ts index ae721adab..062389dae 100644 --- a/src/rTerminal.ts +++ b/src/rTerminal.ts @@ -1,6 +1,7 @@ "use strict"; import fs = require("fs-extra"); +import { isNull } from "util"; import { commands, Terminal, window } from "vscode"; import { getSelection } from "./selection"; import { config, delay, getRpath } from "./util"; @@ -31,7 +32,16 @@ export function deleteTerminal(term: Terminal) { } } -export async function chooseTerminal() { +export async function chooseTerminal(active: boolean = false) { + if (active || config.get("alwaysUseActiveTerminal")) { + if (window.terminals.length < 1) { + window.showInformationMessage("There are no open terminals."); + return null; + } else { + return window.activeTerminal; + } + } + if (window.terminals.length > 0) { const RTermNameOpinions = ["R", "R Interactive"]; if (window.activeTerminal) { @@ -90,9 +100,19 @@ export async function runSelectionInTerm(term: Terminal, rFunctionName: string[] } term.sendText(line); } + setFocus(term); +} + +export async function chooseTerminalAndSendText(text: string) { + const callableTerminal = await chooseTerminal(); + if (isNull(callableTerminal)) { + return; + } + callableTerminal.sendText(text); + setFocus(callableTerminal); } -export function setFocus(term: Terminal) { +function setFocus(term: Terminal) { const focus = config.get("source.focus") as string; term.show(focus !== "terminal"); } From 44b08727a8ad2e9198a4f9167c9f6f80727f830c Mon Sep 17 00:00:00 2001 From: Andrew Craig Date: Tue, 8 Oct 2019 20:33:16 +0900 Subject: [PATCH 4/4] Add alwaysUseActiveTerminal to README, templates --- .github/ISSUE_TEMPLATE/bug_report.md | 3 +++ ISSUE_TEMPLATE.md | 6 ++++++ README.md | 1 + package.json | 2 +- 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index f53c4f111..7fb2d52f1 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -44,6 +44,9 @@ Yes / No // Keeping focus when running "r.source.focus": "editor", +// Use active terminal for all commands, rather than creating a new R terminal +"r.alwaysUseActiveTerminal": false, + // Use bracketed paste mode "r.bracketedPaste": false, ``` diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 2d597ed53..eb9a7b417 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -36,4 +36,10 @@ Yes / No // Keeping focus when running "r.source.focus": "editor", + +// Use active terminal for all commands, rather than creating a new R terminal +"r.alwaysUseActiveTerminal": false, + +// Use bracketed paste mode +"r.bracketedPaste": false, ``` diff --git a/README.md b/README.md index bbe04f601..6a9627dc7 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ This extension contributes the following settings: * `r.rterm.option`: R command line options (i.e: --vanilla) * `r.source.encoding`: An optional encoding to pass to R when executing the file * `r.source.focus`: Keeping focus when running (editor or terminal) +* `r.alwaysUseActiveTerminal`: Use active terminal for all commands, rather than creating a new R terminal * `r.bracketedPaste`: For consoles supporting bracketed paste mode (such as Radian) * Language server(developing [here](https://github.com/REditorSupport/languageserver)) diff --git a/package.json b/package.json index 540e0eeba..4f0bbc222 100644 --- a/package.json +++ b/package.json @@ -355,7 +355,7 @@ "r.alwaysUseActiveTerminal": { "type": "boolean", "default": false, - "description": "If enabled, will use active terminal for all commands, rather than creating a new R terminal" + "description": "Use active terminal for all commands, rather than creating a new R terminal" }, "r.bracketedPaste": { "type": "boolean",