From 9107d9b1dc2eb6a4fc12ac822b342ba954a4278c Mon Sep 17 00:00:00 2001 From: Kun Ren Date: Fri, 10 Jan 2020 15:26:01 +0800 Subject: [PATCH 01/11] Update session watcher section in README.md --- README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 96165f4af..1e13a4007 100644 --- a/README.md +++ b/README.md @@ -75,12 +75,23 @@ An opt-in experimental R session watcher is implemented to support the following * Show plot output on update * Show htmlwidgets and shiny apps -To enable this feature, turn on `r.sessionWatcher` and append the following code to your `.Rprofile` (in your home directory): +To enable this feature, turn on `r.sessionWatcher` and then edit your `.Rprofile` by running the following code in R: ```r -source(file.path(if (.Platform$OS.type == "windows") file.path(Sys.getenv("HOMEDRIVE"), Sys.getenv("HOMEPATH")) else Sys.getenv("HOME"), ".vscode-R", "init.R")) +system2("code", normalizePath("~/.Rprofile")) ``` +It will open a VSCode tab for you to edit the file. You may change `code` to whatever editor you like. + +Then append the following code to the file you get in the output of above command: + +```r +source(file.path(Sys.getenv(if (.Platform$OS.type == "windows") "USERPROFILE" else "HOME"), ".vscode-R", "init.R")) +``` + +If the workspace folder you open in VSCode already has a `.Rprofile`, you need to append the code above in this file too because `~/.Rprofile` will not +be executed when a local `.Rprofile` is found. + This script writes the metadata of symbols in the global environment and plot file to `${workspaceFolder}/.vscode/vscode-R/PID` where `PID` is the R process ID. It also captures user input and append command lines to `${workspaceFolder}/.vscode/vscode-R/response.log`, which enables the communication between vscode-R and a live R sesson. Each time the extension is activated, the latest session watcher script (`init.R`) will be deployed to `~/.vscode-R/init.R`. From ac91a398b4fd9aa12276b5b3b82f972fa82310c8 Mon Sep 17 00:00:00 2001 From: Kun Ren Date: Fri, 10 Jan 2020 16:45:59 +0800 Subject: [PATCH 02/11] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e13a4007..4301c6529 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ system2("code", normalizePath("~/.Rprofile")) It will open a VSCode tab for you to edit the file. You may change `code` to whatever editor you like. -Then append the following code to the file you get in the output of above command: +Then append the following code to the file: ```r source(file.path(Sys.getenv(if (.Platform$OS.type == "windows") "USERPROFILE" else "HOME"), ".vscode-R", "init.R")) From 9c29090e7924845f5e96cb0b532918355ab3dc37 Mon Sep 17 00:00:00 2001 From: Kun Ren Date: Fri, 10 Jan 2020 21:08:44 +0800 Subject: [PATCH 03/11] Update README.md --- README.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 4301c6529..db7c9aa18 100644 --- a/README.md +++ b/README.md @@ -75,19 +75,25 @@ An opt-in experimental R session watcher is implemented to support the following * Show plot output on update * Show htmlwidgets and shiny apps -To enable this feature, turn on `r.sessionWatcher` and then edit your `.Rprofile` by running the following code in R: +To enable this feature, follow the following steps: -```r -system2("code", normalizePath("~/.Rprofile")) -``` +1. Turn on `r.sessionWatcher` in VSCode settings. +2. Locate `.Rprofile` in your home directory by running the following code in R: -It will open a VSCode tab for you to edit the file. You may change `code` to whatever editor you like. + ```r + normalizePath("~/.Rprofile") + ``` -Then append the following code to the file: + Following are typical paths in different operating systems: + * Windows: `C:\\Users\\user\\Documents\\.Rprofile` + * Linux: `/home/user/.Rprofile` + * macOS: `/Users/user/.Rprofile` -```r -source(file.path(Sys.getenv(if (.Platform$OS.type == "windows") "USERPROFILE" else "HOME"), ".vscode-R", "init.R")) -``` +3. Create (if not exists) or open the file and append the following code to the file: + + ```r + source(file.path(Sys.getenv(if (.Platform$OS.type == "windows") "USERPROFILE" else "HOME"), ".vscode-R", "init.R")) + ``` If the workspace folder you open in VSCode already has a `.Rprofile`, you need to append the code above in this file too because `~/.Rprofile` will not be executed when a local `.Rprofile` is found. @@ -102,7 +108,7 @@ R sessions started from the workspace root folder will be automatically attached * R session started by vscode-R or user * R session in a `tmux` or `screen` window * Switch between multiple running R sessions -* [Remote Development](https://code.visualstudio.com/docs/remote/remote-overview) +* [Remote Development](https://code.visualstudio.com/docs/remote/remote-overview) via SSH, WSL and Docker The status bar item shows the process id of the attached R session. Click the status bar item and it will attach to currently active session. From fc13c713f89c34bbad53865b2669a8b2f19b1851 Mon Sep 17 00:00:00 2001 From: Kun Ren Date: Fri, 10 Jan 2020 21:15:54 +0800 Subject: [PATCH 04/11] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index db7c9aa18..b2e6ff636 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,8 @@ To enable this feature, follow the following steps: source(file.path(Sys.getenv(if (.Platform$OS.type == "windows") "USERPROFILE" else "HOME"), ".vscode-R", "init.R")) ``` +4. Restart or Reload Window in VSCode + If the workspace folder you open in VSCode already has a `.Rprofile`, you need to append the code above in this file too because `~/.Rprofile` will not be executed when a local `.Rprofile` is found. From 7ed6c068fe1e9551c862f1b3216a4673024c1577 Mon Sep 17 00:00:00 2001 From: Kun Ren Date: Thu, 16 Jan 2020 11:51:12 +0800 Subject: [PATCH 05/11] Add link and short description of radian --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index b2e6ff636..4d9b3e767 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,9 @@ attach to currently active session. ![R session watcher](https://user-images.githubusercontent.com/4662568/70815935-65391480-1e09-11ea-9ad6-7ebbebf9a9c8.gif) +*The R terminal used in the screenshot is [radian](https://github.com/randy3k/radian) which is cross-platform and +supports syntax highlighting, auto-completion and many other features.* + ## TODO * Debug From 3f600c1c6cfdcccd6cbdb70a4022370f67c149f5 Mon Sep 17 00:00:00 2001 From: Kun Ren Date: Tue, 21 Jan 2020 12:30:47 +0800 Subject: [PATCH 06/11] Use R_PROFILE_USER --- R/.Rprofile | 9 +++++++++ src/rTerminal.ts | 17 +++++++++++++++-- src/session.ts | 6 +++--- 3 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 R/.Rprofile diff --git a/R/.Rprofile b/R/.Rprofile new file mode 100644 index 000000000..977325106 --- /dev/null +++ b/R/.Rprofile @@ -0,0 +1,9 @@ +if (file.exists(".Rprofile")) { + source(".Rprofile") +} else if (file.exists("~/.Rprofile")) { + source("~/.Rprofile") +} + +if (is.null(getOption("vscodeR"))) { + source(file.path(Sys.getenv(if (.Platform$OS.type == "windows") "USERPROFILE" else "HOME"), ".vscode-R", "init.R")) +} diff --git a/src/rTerminal.ts b/src/rTerminal.ts index f492c0843..604caec10 100644 --- a/src/rTerminal.ts +++ b/src/rTerminal.ts @@ -1,8 +1,11 @@ "use strict"; +import os = require("os"); +import path = require("path"); + import { pathExists } from "fs-extra"; import { isDeepStrictEqual } from "util"; -import { commands, Terminal, window } from "vscode"; +import { commands, Terminal, window, TerminalOptions } from "vscode"; import { getSelection } from "./selection"; import { removeSessionFiles } from "./session"; @@ -18,7 +21,17 @@ export function createRTerm(preserveshow?: boolean): boolean { const termOpt: string[] = config.get("rterm.option"); pathExists(termPath, (err, exists) => { if (exists) { - rTerm = window.createTerminal(termName, termPath, termOpt); + let termOptions: TerminalOptions = { + name: termName, + shellPath: termPath, + shellArgs: termOpt + }; + if (config.get("sessionWatcher")) { + termOptions.env = { + R_PROFILE_USER: path.join(os.homedir(), ".vscode-R", ".Rprofile") + }; + } + rTerm = window.createTerminal(termOptions); rTerm.show(preserveshow); return true; } diff --git a/src/session.ts b/src/session.ts index 5571d34ba..97a53b639 100644 --- a/src/session.ts +++ b/src/session.ts @@ -20,13 +20,13 @@ const sessionDir = path.join(".vscode", "vscode-R"); export function deploySessionWatcher(extensionPath: string) { resDir = path.join(extensionPath, "dist", "resources"); - const srcPath = path.join(extensionPath, "R", "init.R"); const targetDir = path.join(os.homedir(), ".vscode-R"); if (!fs.existsSync(targetDir)) { fs.mkdirSync(targetDir); } - const targetPath = path.join(targetDir, "init.R"); - fs.copySync(srcPath, targetPath); + + fs.copySync(path.join(extensionPath, "R", "init.R"), path.join(targetDir, "init.R")); + fs.copySync(path.join(extensionPath, "R", ".Rprofile"), path.join(targetDir, ".Rprofile")); } export function startResponseWatcher(sessionStatusBarItem: StatusBarItem) { From 54c5f100f0338f2e84324be578bc82fb0084f6f3 Mon Sep 17 00:00:00 2001 From: Kun Ren Date: Tue, 21 Jan 2020 12:32:37 +0800 Subject: [PATCH 07/11] init.R only work with TERM_PROGRAM=vscode --- R/init.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/init.R b/R/init.R index 387fbef35..3aac1e5a6 100644 --- a/R/init.R +++ b/R/init.R @@ -1,4 +1,4 @@ -if (interactive() && !identical(Sys.getenv("RSTUDIO"), "1")) { +if (interactive() && Sys.getenv("TERM_PROGRAM") == "vscode") { if (requireNamespace("jsonlite", quietly = TRUE)) { local({ pid <- Sys.getpid() From c4b1e8887766380b8450afc4e0d7e1ac96353992 Mon Sep 17 00:00:00 2001 From: Kun Ren Date: Tue, 21 Jan 2020 13:18:12 +0800 Subject: [PATCH 08/11] Update README.md --- README.md | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 4d9b3e767..639e913d8 100644 --- a/README.md +++ b/README.md @@ -71,25 +71,28 @@ An opt-in experimental R session watcher is implemented to support the following * Watch any R session * Show value of session symbol on hover * Provide completion for session symbol -* `View()` data frames and list objects +* `View()` any objects including data frames and list objects * Show plot output on update -* Show htmlwidgets and shiny apps +* Show htmlwidgets, documentation and shiny apps in WebView -To enable this feature, follow the following steps: +### Basic usage + +To enable this feature, turn on `r.sessionWatcher` in VSCode settings, reload or restart VSCode, and the session watcher will be activated automatically +on R sessions launched by vscode-R via `R: Create R Terminal` command. + +### Advanced usage (for self-managed R sessions) + +For advanced users to work with self-managed R sessions (e.g. manually started R terminal in `tmux` or `screen` window), some extra +configuration is needed. Follow the steps below to make R session watcher work with any external R session: 1. Turn on `r.sessionWatcher` in VSCode settings. -2. Locate `.Rprofile` in your home directory by running the following code in R: +2. Edit `.Rprofile` in your home directory by running the following code in R: ```r - normalizePath("~/.Rprofile") + file.edit("~/.Rprofile") ``` - Following are typical paths in different operating systems: - * Windows: `C:\\Users\\user\\Documents\\.Rprofile` - * Linux: `/home/user/.Rprofile` - * macOS: `/Users/user/.Rprofile` - -3. Create (if not exists) or open the file and append the following code to the file: +3. Append the following code to the file: ```r source(file.path(Sys.getenv(if (.Platform$OS.type == "windows") "USERPROFILE" else "HOME"), ".vscode-R", "init.R")) @@ -100,6 +103,17 @@ To enable this feature, follow the following steps: If the workspace folder you open in VSCode already has a `.Rprofile`, you need to append the code above in this file too because `~/.Rprofile` will not be executed when a local `.Rprofile` is found. +The script only works with environment variable `TERM_PROGRAM=vscode`. the script will not take effect with R sessions started in a `tmux` or `screen` window that does not have it, unless this environment variable is manually set before sourcing `init.R`, for example, you may insert a line `Sys.setenv(TERM_PROGRAM="vscode")` before it. + +### How to disable it + +For the case of basic usage, turning off `r.sessionWatcher` in VSCode settings is sufficient +to disable R session watcher. + +For the case of advanced usage, user should, in addition, comment out or remove the `source(...)` line appended to `~/.Rprofile`. + +### How it works + This script writes the metadata of symbols in the global environment and plot file to `${workspaceFolder}/.vscode/vscode-R/PID` where `PID` is the R process ID. It also captures user input and append command lines to `${workspaceFolder}/.vscode/vscode-R/response.log`, which enables the communication between vscode-R and a live R sesson. Each time the extension is activated, the latest session watcher script (`init.R`) will be deployed to `~/.vscode-R/init.R`. From 8a07532a558b26d82b70729b26e6791fca8b2d21 Mon Sep 17 00:00:00 2001 From: Kun Ren Date: Tue, 21 Jan 2020 13:34:27 +0800 Subject: [PATCH 09/11] Respect existing R_PROFILE_USER --- R/.Rprofile | 4 +++- src/rTerminal.ts | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/R/.Rprofile b/R/.Rprofile index 977325106..324e475a5 100644 --- a/R/.Rprofile +++ b/R/.Rprofile @@ -1,4 +1,6 @@ -if (file.exists(".Rprofile")) { +if (nzchar(Sys.getenv("R_PROFILE_USER_OLD"))) { + source(Sys.getenv("R_PROFILE_USER_OLD")) +} else if (file.exists(".Rprofile")) { source(".Rprofile") } else if (file.exists("~/.Rprofile")) { source("~/.Rprofile") diff --git a/src/rTerminal.ts b/src/rTerminal.ts index 604caec10..c59a5cef3 100644 --- a/src/rTerminal.ts +++ b/src/rTerminal.ts @@ -28,6 +28,7 @@ export function createRTerm(preserveshow?: boolean): boolean { }; if (config.get("sessionWatcher")) { termOptions.env = { + R_PROFILE_USER_OLD: process.env.R_PROFILE_USER, R_PROFILE_USER: path.join(os.homedir(), ".vscode-R", ".Rprofile") }; } From 9bd4ab54afff383e15101a82eecb5e2c5cd5cc0a Mon Sep 17 00:00:00 2001 From: Kun Ren Date: Tue, 21 Jan 2020 14:10:33 +0800 Subject: [PATCH 10/11] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 639e913d8..49c8519a7 100644 --- a/README.md +++ b/README.md @@ -80,9 +80,12 @@ An opt-in experimental R session watcher is implemented to support the following To enable this feature, turn on `r.sessionWatcher` in VSCode settings, reload or restart VSCode, and the session watcher will be activated automatically on R sessions launched by vscode-R via `R: Create R Terminal` command. +*If you previously appended the `source(...)` line to `~/.Rprofile`, you may safely remove it since the configuration for basic usage is automated. It is +now only necessary for advanced usage described below.* + ### Advanced usage (for self-managed R sessions) -For advanced users to work with self-managed R sessions (e.g. manually started R terminal in `tmux` or `screen` window), some extra +For advanced users to work with self-managed R sessions (e.g. manually launched R terminal or started in `tmux` or `screen` window), some extra configuration is needed. Follow the steps below to make R session watcher work with any external R session: 1. Turn on `r.sessionWatcher` in VSCode settings. From 75a5edd8bb0c4ed42b4e955749550f1337972cc0 Mon Sep 17 00:00:00 2001 From: Kun Ren Date: Fri, 24 Jan 2020 16:54:01 +0800 Subject: [PATCH 11/11] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 49c8519a7..386bf1832 100644 --- a/README.md +++ b/README.md @@ -69,10 +69,10 @@ This extension contributes the following settings: An opt-in experimental R session watcher is implemented to support the following features: * Watch any R session -* Show value of session symbol on hover -* Provide completion for session symbol +* Show value of session symbols on hover +* Provide completion for session symbols * `View()` any objects including data frames and list objects -* Show plot output on update +* Show plot output on update and plot history * Show htmlwidgets, documentation and shiny apps in WebView ### Basic usage