File: environment_shadow.r

package info (click to toggle)
r-cran-irkernel 1.3.2%2Bgit20240429.124f234-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 400 kB
  • sloc: python: 242; javascript: 69; makefile: 26; sh: 15
file content (137 lines) | stat: -rw-r--r-- 4,995 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# Everthing related to the environment which takes functions which shadow base R functions.
# This is needed to build in our own needs, like properly shutting down the kernel
# when `quit()` is called.

add_to_user_searchpath <- function(name, FN, pkg = NULL) {
    pkg_avail <- !is.null(pkg) && requireNamespace(pkg, quietly = TRUE)
    if (pkg_avail) {
        replace_in_package(pkg, name, FN)
    } else {
        assign(name, FN, 'jupyter:irkernel')
    }
}

replace_in_package <- function(pkg, name, FN) {
    env_name <- paste0('package:', pkg)
    if (env_name %in% search())
        replace_in_env(name, FN, as.environment(env_name))
    replace_in_env(name, FN, getNamespace(pkg))
}

replace_in_env <- function(name, FN, env) {
    .BaseNamespaceEnv$unlockBinding(name, env)
    assign(name, FN, env)
    .BaseNamespaceEnv$lockBinding(name, env)
}

get_shadowenv <- function() {
    as.environment('jupyter:irkernel')
}

# save functions that are later replaced (called in .onLoad)
backup_env <- new.env()
# Circumvent windows build bug, see issue #530
backup_env$utils_flush_console <- function(...) {}
# Circumvent devtools bug
backup_env$base_flush_connection <- function(...) {}

init_backup_env <- function() {
    if (!identical(environment(utils::flush.console), environment(utils::read.delim))) {
        tb <- .traceback(2)
        warning(
            'init_backup_env called a second time after init_shadowenv:\n',
            paste(capture.output(traceback(tb)), collapse = '\n')
        )
        return()
    }
    backup_env$base_flush_connection <- base::flush.connection
    backup_env$utils_flush_console <- utils::flush.console
    backup_env$base_quit <- base::quit
}

# Adds functions which do not need any access to the executer into the users searchpath
#' @importFrom utils getFromNamespace getS3method
#' @importFrom evaluate flush_console
init_shadowenv <- function() {
    # add the accessors to the shadow env itself, so they are actually accessable
    # from everywhere...
    add_to_user_searchpath('.irk.get_shadowenv', get_shadowenv)
    add_to_user_searchpath('.irk.add_to_user_searchpath', add_to_user_searchpath)

    # For the rest of the functions, please explain why the workaround is needed
    # (=the problem) and link to the issue describing the problem.

    # workaround for problems with vignette(xxx) not bringing up the vignette
    # content in the browser: https://github.com/IRkernel/IRkernel/issues/267
    add_to_user_searchpath('print.vignette', function(x, ...) {
        # R CMD check does not like us using :::
        getS3method('print', 'vignette')(x, ...)
        # returning immediately will run into trouble with zmq and its polling
        # preventing the vignette server to startup. So wait a little to let
        # it startup...
        # 0.1 is too little, so add some margin...
        Sys.sleep(0.5)
    })

    add_to_user_searchpath('View', function(x, title) {
        if (!missing(title)) IRdisplay::display_text(title)
        IRdisplay::display(x)
        invisible(x)  # the manpage says it returns NULL, but this is useful for piping
    })
    # we simply have currently no way to edit dfs:
    # https://github.com/IRkernel/IRkernel/issues/280
    add_to_user_searchpath('edit', function(...) {
        stop(sQuote('edit()'), ' not yet supported in the Jupyter R kernel')
    })
    
    # stream output in loops:
    # https://github.com/IRkernel/IRkernel/issues/3
    replace_in_package('base', 'flush.connection', function(con) {
        backup_env$base_flush_connection(con)
        flush_console()
    })
    replace_in_package('utils', 'flush.console', function() {
        backup_env$utils_flush_console()
        flush_console()
    })
}


init_cran_repo <- function() {
    r <- getOption('repos')
    is_unuseable_mirror <- identical(r, c(CRAN = '@CRAN@'))
    if (is_unuseable_mirror) {
        # the default repo according to https://cran.R-project.org/mirrors.html
        # uses geo-redirects
        r[['CRAN']] <- 'https://cran.r-project.org'
        # attribute indicating the repos was set by us...
        attr(r, 'irkernel') <- TRUE
        options(repos = r)
    }
}

init_session <- function() {
    init_cran_repo()
    # We support color even if isatty(stdout()) is FALSE
    options(crayon.enabled = TRUE)
}


#' @importFrom grDevices pdf png
init_null_device <- function() {
    # if possible, use a device that
    # 1. prints no warnings for unicode (unlike pdf/postscript)
    # 2. can handle /dev/null (unlike OSX devices)
    # since there is nothing like that on OSX AFAIK, use pdf there (accepting warnings).
    
    os <- get_os()
    
    ok_device     <- switch(os, win = png,   osx = pdf,  unix = png)
    null_filename <- switch(os, win = 'NUL', osx = NULL, unix = '/dev/null')
    
    null_device <- function(filename = null_filename, ...) ok_device(filename, ...)
    
    if (identical(getOption('device'), pdf)) {
        options(device = null_device)
    }
}