@@ -232,6 +232,7 @@ test_that("unknown hyperlink type", {
232232
233233test_that(" iterm file links" , {
234234withr :: local_envvar(R_CLI_HYPERLINK_STYLE = " iterm" )
235+ withr :: local_envvar(R_CLI_HYPERLINK_FILE_URL_FORMAT = NA_character_ )
235236withr :: local_options(cli.hyperlink = TRUE )
236237 expect_snapshot({
237238cli :: cli_text(" {.file /path/to/file:10}" )
@@ -422,3 +423,185 @@ test_that("get_hyperlink_format() delivers custom format", {
422423 expect_equal(get_hyperlink_format(" help" )," option{topic}" )
423424 expect_equal(get_hyperlink_format(" vignette" )," option{vignette}" )
424425})
426+
427+ test_that(" parse_file_link_params(), typical input" , {
428+ expect_equal(
429+ parse_file_link_params(" some/path.ext" ),
430+ list (
431+ path = " some/path.ext" ,
432+ line = NULL ,
433+ column = NULL
434+ )
435+ )
436+ expect_equal(
437+ parse_file_link_params(" some/path.ext:14" ),
438+ list (
439+ path = " some/path.ext" ,
440+ line = " 14" ,
441+ column = NULL
442+ )
443+ )
444+ expect_equal(
445+ parse_file_link_params(" some/path.ext:14:23" ),
446+ list (
447+ path = " some/path.ext" ,
448+ line = " 14" ,
449+ column = " 23"
450+ )
451+ )
452+ })
453+
454+ test_that(" parse_file_link_params(), weird trailing colons" , {
455+ expect_equal(
456+ parse_file_link_params(" some/path.ext:" ),
457+ list (
458+ path = " some/path.ext" ,
459+ line = NULL ,
460+ column = NULL
461+ )
462+ )
463+ expect_equal(
464+ parse_file_link_params(" some/path.ext::" ),
465+ list (
466+ path = " some/path.ext" ,
467+ line = NULL ,
468+ column = NULL
469+ )
470+ )
471+ expect_equal(
472+ parse_file_link_params(" some/path.ext:14:" ),
473+ list (
474+ path = " some/path.ext" ,
475+ line = " 14" ,
476+ column = NULL
477+ )
478+ )
479+ })
480+
481+ test_that(" interpolate_parts(), more or less data in `params`" , {
482+ fmt <- " whatever/{path}#@${line}^&*{column}"
483+ params <- list (path = " some/path.ext" ,line = " 14" ,column = " 23" )
484+
485+ expect_equal(
486+ interpolate_parts(fmt ,params ),
487+ " whatever/some/path.ext#@$14^&*23"
488+ )
489+
490+ params <- list (path = " some/path.ext" ,line = " 14" ,column = NULL )
491+ expect_equal(
492+ interpolate_parts(fmt ,params ),
493+ " whatever/some/path.ext#@$14"
494+ )
495+
496+ params <- list (path = " some/path.ext" ,line = NULL ,column = NULL )
497+ expect_equal(
498+ interpolate_parts(fmt ,params ),
499+ " whatever/some/path.ext"
500+ )
501+ })
502+
503+ test_that(" interpolate_parts(), format only has `path`" , {
504+ fmt <- " whatever/{path}"
505+ params <- list (path = " some/path.ext" ,line = " 14" ,column = " 23" )
506+ expect_equal(
507+ interpolate_parts(fmt ,params ),
508+ " whatever/some/path.ext"
509+ )
510+ })
511+
512+ test_that(" construct_file_link() works with custom format and an absolute path" , {
513+ withr :: local_options(
514+ " cli.hyperlink_file_url_format" = " positron://file{path}:{line}:{column}"
515+ )
516+
517+ expect_equal(
518+ construct_file_link(list (path = " /absolute/path" )),
519+ list (url = " positron://file/absolute/path" )
520+ )
521+ expect_equal(
522+ construct_file_link(list (path = " /absolute/path" ,line = " 12" )),
523+ list (url = " positron://file/absolute/path:12" )
524+ )
525+ expect_equal(
526+ construct_file_link(list (path = " /absolute/path" ,line = " 12" ,column = " 5" )),
527+ list (url = " positron://file/absolute/path:12:5" )
528+ )
529+
530+ local_mocked_bindings(is_windows = function ()TRUE )
531+ expect_equal(
532+ construct_file_link(list (path = " c:/absolute/path" )),
533+ list (url = " positron://file/c:/absolute/path" )
534+ )
535+ })
536+
537+ test_that(" construct_file_link() works with custom format and a relative path" , {
538+ withr :: local_options(
539+ " cli.hyperlink_file_url_format" = " positron://file{path}:{line}:{column}"
540+ )
541+
542+ # inspired by test helpers `sanitize_wd()` and `sanitize_home()`, but these
543+ # don't prefix the pattern-to-replace with `file://`
544+ sanitize_dir <- function (x ,what = c(" wd" ," home" )) {
545+ what <- match.arg(what )
546+ pattern <- switch (what ,wd = getwd(),home = path.expand(" ~" ))
547+ if (is_windows()) {
548+ pattern <- paste0(" /" ,pattern )
549+ }
550+ replacement <- switch (what ,wd = " /working/directory" ,home = " /my/home" )
551+ sub(pattern ,replacement ,x $ url ,fixed = TRUE )
552+ }
553+
554+ expect_equal(
555+ sanitize_dir(construct_file_link(list (path = " relative/path" )),what = " wd" ),
556+ " positron://file/working/directory/relative/path"
557+ )
558+ expect_equal(
559+ sanitize_dir(construct_file_link(list (path = " relative/path:12" )),what = " wd" ),
560+ " positron://file/working/directory/relative/path:12"
561+ )
562+ expect_equal(
563+ sanitize_dir(construct_file_link(list (path = " relative/path:12:5" )),what = " wd" ),
564+ " positron://file/working/directory/relative/path:12:5"
565+ )
566+
567+ expect_equal(
568+ sanitize_dir(construct_file_link(list (path = " ./relative/path" )),what = " wd" ),
569+ " positron://file/working/directory/./relative/path"
570+ )
571+ expect_equal(
572+ sanitize_dir(construct_file_link(list (path = " ./relative/path:12" )),what = " wd" ),
573+ " positron://file/working/directory/./relative/path:12"
574+ )
575+ expect_equal(
576+ sanitize_dir(construct_file_link(list (path = " ./relative/path:12:5" )),what = " wd" ),
577+ " positron://file/working/directory/./relative/path:12:5"
578+ )
579+
580+ expect_equal(
581+ sanitize_dir(construct_file_link(list (path = " ~/relative/path" )),what = " home" ),
582+ " positron://file/my/home/relative/path"
583+ )
584+ expect_equal(
585+ sanitize_dir(construct_file_link(list (path = " ~/relative/path:17" )),what = " home" ),
586+ " positron://file/my/home/relative/path:17"
587+ )
588+ expect_equal(
589+ sanitize_dir(construct_file_link(list (path = " ~/relative/path:17:22" )),what = " home" ),
590+ " positron://file/my/home/relative/path:17:22"
591+ )
592+ })
593+
594+ test_that(" construct_file_link() works with custom format and input starting with 'file://'" , {
595+ withr :: local_options(
596+ " cli.hyperlink_file_url_format" = " positron://file{path}:{line}:{column}"
597+ )
598+
599+ expect_equal(
600+ construct_file_link(list (path = " file:///absolute/path" )),
601+ list (url = " positron://file/absolute/path" )
602+ )
603+ expect_equal(
604+ construct_file_link(list (path = " file:///absolute/path" ,line = " 12" ,column = " 5" )),
605+ list (url = " positron://file/absolute/path:12:5" )
606+ )
607+ })