-
Notifications
You must be signed in to change notification settings - Fork 71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Configurable file hyperlinks #744
Changes from 13 commits
6bb0b21
55c2eb3
4e31755
f4e7c06
1282f7d
7edf052
544507e
cfe015c
3e19f79
8757629
c6bea43
a5a96c7
9316386
79bbe8f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
Package: cli | ||
Title: Helpers for Developing Command Line Interfaces | ||
Version: 3.6.3.9001 | ||
Version: 3.6.3.9002 | ||
Authors@R: c( | ||
person("Gábor", "Csárdi", , "[email protected]", role = c("aut", "cre")), | ||
person("Hadley", "Wickham", role = "ctb"), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -74,39 +74,98 @@ make_link_file <- function(txt) { | |
linked <- grepl("\007|\033\\\\", txt) | ||
ret[!linked] <- vcapply(which(!linked), function(i) { | ||
params <- parse_file_link_params(txt[i]) | ||
link <- construct_file_link(params) | ||
style_hyperlink( | ||
txt[i], | ||
paste0(abs_path(params$path), params$suffix), | ||
params = params$params | ||
link$url, | ||
params = link$params | ||
) | ||
}) | ||
ret | ||
} | ||
|
||
parse_file_link_params <- function(txt) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This became narrower, i.e. just about parsing. |
||
if (grepl(":[0-9]+:[0-9]+$", txt)) { | ||
# path:line:col | ||
path <- sub("^(.*):[0-9]+:[0-9]+$", "\\1", txt) | ||
num <- strsplit(sub("^.*:([0-9]+:[0-9]+)$", "\\1", txt), ":", fixed = TRUE)[[1]] | ||
if (Sys.getenv("R_CLI_HYPERLINK_STYLE") == "iterm") { | ||
list(path = path, params = NULL, suffix = paste0("#", num[1], ":", num[2])) | ||
} else { | ||
list(path = path, params = c(line = num[1], col = num[2])) | ||
} | ||
pattern <- "^(?<path>.*?)(?::(?<line>\\d*))?(?::(?<column>\\d*))?$" | ||
matches <- re_match(txt, pattern) | ||
ret <- as.list(matches) | ||
ret[!nzchar(ret)] <- list(NULL) | ||
ret | ||
} | ||
|
||
} else if (grepl(":[0-9]+$", txt)) { | ||
# path:line | ||
path <- sub("^(.*):[0-9]+$", "\\1", txt) | ||
num <- sub("^.*:([0-9]+$)", "\\1", txt) | ||
if (Sys.getenv("R_CLI_HYPERLINK_STYLE") == "iterm") { | ||
list(path = path, params = NULL, suffix = paste0("#", num)) | ||
} else { | ||
list(path = path, params = c(line = num, col = "1")) | ||
} | ||
construct_file_link <- function(params) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This turns the parsed filepath into the data |
||
fmt <- get_config_chr("hyperlink_file_url_format") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As it stands, only an explicitly configured hyperlink format has any effect. But you could imagine detecting that we're in, e.g. a Positron or VS Code terminal, and setting this configuration from the cli side. Food for thought. But definitely something that could be added later. |
||
|
||
if (is.null(fmt)) { | ||
return(construct_file_link_OG(params)) | ||
} | ||
|
||
params$path <- sub("^file://", "", params$path) | ||
params$path <- path.expand(params$path) | ||
|
||
looks_absolute <- function(path) { | ||
grepl("^/", params$path) || (is_windows() && grepl("^[a-zA-Z]:", params$path)) | ||
} | ||
if (!looks_absolute(params$path)) { | ||
params$path <- file.path(getwd(), params$path) | ||
} | ||
if (!grepl("^/", params$path)) { | ||
params$path <- paste0("/", params$path) | ||
} | ||
|
||
res <- interpolate_parts(fmt, params) | ||
list(url = res) | ||
} | ||
|
||
# the order of operations is very intentional and important: | ||
# column, then line, then path | ||
# relates to how interpolate_part() works | ||
interpolate_parts <- function(fmt, params) { | ||
res <- interpolate_part(fmt, "column", params$column) | ||
res <- interpolate_part(res, "line", params$line) | ||
interpolate_part(res, "path", params$path) | ||
} | ||
|
||
# interpolate a part, if possible | ||
# if no placeholder for part, this is a no-op | ||
# if placeholder exists, but no value to fill, remove placeholder (and everything after it!) | ||
interpolate_part <- function(fmt, part = c("column", "line", "path"), value = NULL) { | ||
part <- match.arg(part) | ||
re <- glue( | ||
"^(?<before>.*)(?<part>\\{<<<part>>>\\})(?<after>.*?)$", | ||
.open = "<<<", .close = ">>>" | ||
) | ||
m <- re_match(fmt, re) | ||
|
||
if (is.na(m$part) || !nzchar(m$part)) { | ||
return(fmt) | ||
} | ||
|
||
if (is.null(value) || !nzchar(value)) { | ||
return(sub("}[^}]*$", "}", m$before)) | ||
} | ||
|
||
paste0(m$before, value, m$after) | ||
} | ||
|
||
# handle the iterm and RStudio cases, which predated the notion of configuring | ||
# the file hyperlink format | ||
construct_file_link_OG <- function(params) { | ||
params$path <- abs_path(params$path) | ||
|
||
if (Sys.getenv("R_CLI_HYPERLINK_STYLE") == "iterm") { | ||
fmt <- "{path}#{line}:{column}" | ||
res <- interpolate_parts(fmt, params) | ||
return(list(url = res)) | ||
} | ||
|
||
# RStudio takes line and col via params | ||
loc <- if (is.null(params$line)) { | ||
NULL | ||
} else { | ||
list(path = txt, params = NULL) | ||
list(line = params$line, col = params$column %||% 1) | ||
} | ||
|
||
list(url = params$path, params = loc) | ||
} | ||
|
||
abs_path <- function(x) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to need to detect this version in Positron. We only want to enable hyperlinks in the relevant terminals if we know they're going work exactly as we want.