Skip to content

Metaprogramming: extracting formatted objects #750

Description

@MichaelChirico

To support interpreting {cli} calls in lintr::object_usage_linter() & thereby prevent false positives related to "unused variables", we'd like to examine relevant calls & extracting out the used variables.

r-lib/lintr#2252

We do something similar for {glue} already, but the language for {cli} is similar-but-much-richer, e.g. {glue} does not support {.arg x}-style markup.

For {glue}, we use the .transformer argument to pull out all the names in {} execution regions inside glue() calls:

https://github.com/r-lib/lintr/blob/07c55846c1189740b7ac7a83b4b53203e23940ca/R/shared_constants.R#L264-L272

Is there any equivalent for {cli}? I saw #152 but I don't think cli_format_method() is quite suitable.

To be a bit clearer, here's some sample input/output:

cli_abort("{.arg x} has {length(x)} elements, but it should be {.emph {length(y)}}")
# --> c("x", "y")

We might be able to do something where we regex our way through and delete the {.markup ...} wrappers, but I think that's less than ideal.

Activity

  1. gaborcsardi commented on Feb 20, 2025

    @gaborcsardi
    Member

    I think the best would be to add an option or function to cli to do this.

  2. MichaelChirico commented on Feb 20, 2025

    @MichaelChirico
    ContributorAuthor

    OK, glad to know I'm not missing something.

    Any initial thoughts on an API? something similar to the {glue} approach? I'm not all that familiar with {cli} internals.

    cc @olivroy who has helped out with some related issues here.

  3. gaborcsardi commented on Feb 20, 2025

    @gaborcsardi
    Member

    I would add a cli_extract_vars() (internal?) function.

  4. MichaelChirico commented on Feb 20, 2025

    @MichaelChirico
    ContributorAuthor

    Looked at the implementation a little bit. AIUI, we'd want to use all.vars() (or all.names()) on expr here:

    cli/R/inline.R

    Line 303 in b388132

    expr <- parse(text = code, keep.source = FALSE) %??%

    I'm still not sure the right way to surface that.

    I also see that all of the functions like cli_abort() that support inline formatting are doing so through a call to cli::format_inline().

    WDYT about a new argument like .record_names=FALSE to that function which would then alter how glue() is invoked?

  5. gaborcsardi commented on Feb 20, 2025

    @gaborcsardi
    Member

    I also see that all of the functions like cli_abort() that support inline formatting are doing so through a call to cli::format_inline().

    That would be very surprising to me. I would think almost none of them call format_inline().

  6. MichaelChirico commented on Feb 20, 2025

    @MichaelChirico
    ContributorAuthor

    Oh, my mistake :)

    I only checked one

    cli/R/rlang.R

    Lines 39 to 44 in b388132

    cli_abort <- function(message,
    ...,
    call = .envir,
    .envir = parent.frame(),
    .frame = .envir) {
    message[] <- vcapply(message, format_inline, .envir = .envir)

  7. MichaelChirico commented on Feb 20, 2025

    @MichaelChirico
    ContributorAuthor

    In that case the workhorse is actually glue_cmd(), which is currently private.

    Maybe that could be exported with the suggested .record_names option instead?

    Another idea is an option to strip {cli}-specific markup instead, returning a string that could be passed directly to {glue} with the {cli} logic removed, I think that means returning code in the above branch.

    "{.arg x} has {length(x)} elements, but it should be {.emph {length(y)}} in {.pkg {.emph {pkg}}}"
    # --> "x has {length(x)} elements, but it should be {length(y)} in {pkg}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    featurea feature request or enhancement

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions