HenrikBengtsson / Wishlist-for-R

Features and tweaks to R that I and others would love to see - feel free to add yours!
https://github.com/HenrikBengtsson/Wishlist-for-R/issues
GNU Lesser General Public License v3.0
133 stars 4 forks source link

WISH: make print() output <srcfile: ...> information for functions #105

Open HenrikBengtsson opened 4 years ago

HenrikBengtsson commented 4 years ago

When a function is defined in a script and we source() the script, the function carry "srcref" attributes with details on the script file location and on what lines in that file the function was defined. It would be useful have print() display this information for functions, e.g.

> my_fcn
function(msg = "hello world") {
  message(msg)
}
<srcfile: '/home/alice/R-scripts/utils.R' (lines 12:14)>

Not all functions carry this information, e.g. functions part of a package do not have this information, e.g.

> rnorm
function (n, mean = 0, sd = 1) 
.Call(C_rnorm, n, mean, sd)
<bytecode: 0x5635158cf130>
<environment: namespace:stats>

Prototype

The current implementation is:

> base::print.function
function (x, useSource = TRUE, ...) 
print.default(x, useSource = useSource, ...)
<bytecode: 0x563513be4ba0>
<environment: namespace:base>

This can easily be extended to print "srcref" information afterward, e.g.

print.function <- function(x, useSource = TRUE, ...) {
    print.default(x, useSource=useSource, ...)
    pathname <- utils::getSrcFilename(x, full.names = TRUE)
    pathname <- pathname[nzchar(pathname)]
    if (length(pathname) > 0L) {
        info <- sQuote(pathname[1])
        first <- utils::getSrcLocation(x, which = "line", first = TRUE)
        if (!is.null(first)) {
            last <- utils::getSrcLocation(x, which = "line", first = FALSE)
            if (last == first) {
                info <- sprintf("%s (line %d)", info, first)
            } else {
                info <- sprintf("%s (lines %d:%d)", info, first, last)
            }
        }
        cat(sprintf("<srcfile: %s>\n", info))
    }
    invisible(x)
}

Try it

To test the above print.function(), just add it to ~/.Rprofile wrapped in a if (interactive()) { ... }, or as-is to ~/.Rprofile.d/interactive=TRUE/print.function.R if you use startup.

See also

HenrikBengtsson commented 4 years ago

Help wanted

What's not clear to me is whether pathname <- utils::getSrcFilename(x, full.names = TRUE) can ever return more than one filename, i.e. length(pathname) > 1? Likewise, can line <- utils::getSrcLocation(x, which = "line") ever return more than one line index, i.e. length(line) > 1?

This needs to be figured out before proposing a patch to base R.

HenrikBengtsson commented 3 years ago

Is Bug 17968 - removeSource doesn't completely remove srcrefs for nested functions relevant here, i.e. the fact that there can be nested source references?