#|
# ==============================================================================
# .Rprofile for World Bank R Users
# ==============================================================================
# This file customizes R startup behavior
# Location: ~/.Rprofile (user home directory)
# To find your home directory: path.expand("~")
# To bypass this file: Start R with --vanilla flag
# ==============================================================================
local({
# Wrap everything in local() to avoid polluting global environment
# If something breaks, R will still start
# --------------------------------------------------------------------------
# 1. ESSENTIAL UTILITIES (Build tools first)
# --------------------------------------------------------------------------
.safe_require <- function(pkg) {
requireNamespace(pkg, quietly = TRUE) |> isTRUE()
}
.msg <- function(...) {
if (.safe_require("cli")) {
try(cli::cli_inform(...), silent = TRUE)
} else {
message(paste0(...))
}
}
# --------------------------------------------------------------------------
# 2. LIBRARY PATH MANAGEMENT (Critical for WB environment)
# --------------------------------------------------------------------------
rlu <- Sys.getenv("R_LIBS_USER", unset = "")
if (nzchar(rlu)) {
rlu <- path.expand(rlu)
if (!dir.exists(rlu)) {
try(dir.create(rlu, recursive = TRUE), silent = TRUE)
}
if (dir.exists(rlu)) {
.libPaths(unique(c(rlu, .libPaths())))
}
}
# --------------------------------------------------------------------------
# 3. SESSION MODE TOGGLE (Vanilla vs Regular)
# --------------------------------------------------------------------------
toggle_file <- "~/.Rsession_toggle"
next_R_session <- function(
mode = c("regular", "vanilla"),
toggle_file = "~/.Rsession_toggle"
) {
mode <- match.arg(mode)
try(
dir.create(
dirname(path.expand(toggle_file)),
recursive = TRUE,
showWarnings = FALSE
),
silent = TRUE
)
writeLines(mode, path.expand(toggle_file))
msg <- paste("Next session will be", mode)
message(msg)
invisible(msg)
}
vanilla_next <- function() {
next_R_session("vanilla")
if (requireNamespace("rstudioapi", quietly = TRUE)) {
rstudioapi::restartSession()
}
invisible(TRUE)
}
# Export toggle functions
assign("next_R_session", next_R_session, envir = .GlobalEnv)
assign("vanilla_next", vanilla_next, envir = .GlobalEnv)
# Read current mode
mode <- if (file.exists(path.expand(toggle_file))) {
readLines(toggle_file, warn = FALSE)[1]
} else {
"regular"
}
# Branch: Vanilla mode
if (identical(mode, "vanilla")) {
message("[startup] Vanilla-like session (light init)")
try(writeLines("regular", path.expand(toggle_file)), silent = TRUE)
Sys.setenv(RENV_CONFIG_AUTOLOADER_ENABLED = "FALSE")
options(renv.consent = FALSE)
if (.Platform$OS.type == "windows") {
Sys.setenv(R_HISTFILE = "NUL")
} else {
Sys.setenv(R_HISTFILE = "/dev/null")
}
message("Next session will be regular. Type rstudioapi::restartSession()")
return(invisible())
}
# --------------------------------------------------------------------------
# REGULAR SESSION STARTS HERE
# --------------------------------------------------------------------------
.msg("Starting regular R session...")
# --------------------------------------------------------------------------
# 4. CRAN REPOSITORY
# --------------------------------------------------------------------------
local({
r <- getOption("repos")
r["CRAN"] <- "https://cran.rstudio.com/"
options(repos = r)
})
# --------------------------------------------------------------------------
# 5. PERFORMANCE OPTIMIZATION (Threading)
# --------------------------------------------------------------------------
ncores <- if (.safe_require("parallel")) {
parallel::detectCores(logical = TRUE)
} else {
5L
}
nthreads <- max(1L, floor(ncores * 0.9))
nthreads <- min(nthreads, 12L)
if (.safe_require("data.table")) {
data.table::setDTthreads(nthreads)
}
if (.safe_require("collapse")) {
collapse::set_collapse(nthreads = nthreads)
}
.msg("Threading set to: {.field {nthreads}} cores")
# --------------------------------------------------------------------------
# 6. ESSENTIAL PACKAGE LOADING (Interactive only)
# --------------------------------------------------------------------------
if (interactive()) {
lib_sup <- function(x) {
if (.safe_require(x)) {
library(x, character.only = TRUE) |>
suppressPackageStartupMessages() |>
suppressWarnings() |>
suppressMessages()
invisible(TRUE)
} else {
invisible(FALSE)
}
}
# Load your essential packages here
lapply(c("devtools", "gert", "usethis"), lib_sup) |> invisible()
}
# --------------------------------------------------------------------------
# 7. DAILY PACKAGE UPDATE CHECK (Smart caching)
# --------------------------------------------------------------------------
if (interactive() && .safe_require("fs") && .safe_require("qs")) {
todays <- format(Sys.Date(), "%Y%m%d")
up <- function(path, n = 1) {
for (i in seq_len(n)) {
path <- fs::path_dir(path)
}
path
}
opdir <- tryCatch(up(rlu, 2), error = function(e) NA_character_)
if (is.character(opdir) && !is.na(opdir)) {
fs::path(opdir, "_old") |> fs::dir_create()
file_date <- fs::path(opdir, "date.txt")
if (!fs::file_exists(file_date)) {
try(writeLines("", file_date), silent = TRUE)
}
date_checked <- tryCatch(
readLines(file_date, warn = FALSE),
error = function(e) ""
)
old <- NULL
if (!identical(todays, date_checked)) {
old <- tryCatch(utils::old.packages(), error = function(e) NULL)
try(qs::qsave(old, fs::path(opdir, "old_packages.qs")), silent = TRUE)
try(writeLines(todays, file_date), silent = TRUE)
.msg("Saved daily packages snapshot")
} else {
old <- tryCatch(
qs::qread(fs::path(opdir, "old_packages.qs")),
error = function(e) NULL
)
.msg("Reading cached packages snapshot")
}
if (!is.null(old) && nrow(old) > 0) {
.msg("Updatable packages: {.field {old[,1]}}")
} else {
message("All packages up to date")
}
}
}
# --------------------------------------------------------------------------
# 8. R OPTIONS (Customize experience)
# --------------------------------------------------------------------------
options(
digits = 4,
scipen = 999,
stringsAsFactors = FALSE,
prompt = "R> ",
continue = "... ",
warn = 1,
timeout = 300,
usethis.protocol = "https",
blogdown.ext = ".Rmd"
)
Sys.setenv(TZ = "UTC")
# --------------------------------------------------------------------------
# 9. NETWORK/PROXY SETTINGS (WB specific - uncomment if needed)
# --------------------------------------------------------------------------
# if (.Platform$OS.type == "windows") {
# Sys.setenv(
# http_proxy = "http://proxy.worldbank.org:8080",
# https_proxy = "http://proxy.worldbank.org:8080",
# no_proxy = "localhost,127.0.0.1,.worldbank.org"
# )
# }
# --------------------------------------------------------------------------
# 10. HELPER FUNCTIONS (Productivity boosters)
# --------------------------------------------------------------------------
# Git shortcuts
if (.safe_require("gert")) {
gca <- function(x, ...) gert::git_commit_all(x, ...)
gp <- function(x = NULL, ...) gert::git_push(x, ...)
ga <- function(...) {
st <- gert::git_status(...)
if (nrow(st)) {
gert::git_add(st$file)
} else {
cli::cli_alert_info("No files changed. Nothing to stage.")
}
}
gi <- function() gert::git_info()$upstream
gs <- function() gert::git_status()
for (nm in c("gca", "gp", "ga", "gi", "gs")) {
assign(nm, get(nm, inherits = FALSE), envir = .GlobalEnv)
}
}
# Devtools shortcut
if (.safe_require("devtools")) {
la <- function() devtools::load_all()
assign("la", la, envir = .GlobalEnv)
}
# Number formatting
pn <- function(x, digits = 3) {
formatC(
x,
format = "f",
digits = digits,
big.mark = ",",
decimal.mark = "."
)
}
# Variable assignment helper
assign_to_global <- function(vars = NULL, from_env = parent.frame()) {
x <- if (is.null(vars)) ls(envir = from_env) else vars
for (nm in x) {
assign(nm, get(nm, envir = from_env), envir = .GlobalEnv)
}
invisible(NULL)
}
# Directory navigation
up <- function(path, n = 1) {
for (i in seq_len(n)) {
path <- fs::path_dir(path)
}
path
}
# Export utility functions
for (fn in c("pn", "assign_to_global", "up")) {
if (exists(fn, inherits = FALSE)) {
assign(fn, get(fn, inherits = FALSE), envir = .GlobalEnv)
}
}
# --------------------------------------------------------------------------
# 11. STARTUP AND EXIT HOOKS
# --------------------------------------------------------------------------
.First <- function() {
if (!interactive()) {
return(invisible())
}
.msg("Welcome to R! Session ready.")
cat(sprintf("[.Rprofile loaded, cwd: %s]\n", getwd()))
}
.Last <- function() {
if (!interactive()) {
return(invisible())
}
message("Goodbye!")
}
# Export hooks
assign(".First", .First, envir = .GlobalEnv)
assign(".Last", .Last, envir = .GlobalEnv)
}) # End of local() wrapper
# ==============================================================================
# END OF .RPROFILE
# ==============================================================================