Skip to content

Return description and author for installed packages#1165

Open
bricestacey wants to merge 2 commits intomainfrom
12925/packages-metadata
Open

Return description and author for installed packages#1165
bricestacey wants to merge 2 commits intomainfrom
12925/packages-metadata

Conversation

@bricestacey
Copy link
Copy Markdown
Contributor

Extend .ps.rpc.pkg_list to return description and author alongside the existing fields so Positron's Packages pane card view can render them. Both are normalized for display: descriptions collapse whitespace so multi-line text fits on one line, and author strips trailing <email> markers from Maintainer values.

All three methods (pak / base / renv) populate the new fields. base and renv share a helper that wraps utils::installed.packages() so the lib lookup only differs by lib.loc.

See posit-dev/positron#12925

Extend .ps.rpc.pkg_list to return `description` and `author` alongside
the existing fields so Positron's Packages pane card view can render
them. Both are normalized for display: descriptions collapse whitespace
so multi-line text fits on one line, and author strips trailing
`<email>` markers from Maintainer values.

All three methods (pak / base / renv) populate the new fields. base and
renv share a helper that wraps utils::installed.packages() so the lib
lookup only differs by `lib.loc`.

See posit-dev/positron#12925
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Member

@jennybc jennybc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some high-level thoughts:

  1. It's not immediately obvious to me why a pak variant is needed when listing installed packages and perhaps enriching with some information from DESCRIPTION. My instinct is that someone choosing or accepting a pak lifestyle re: packages pane operations is really (and probably only?) about installation. I suspect this can be simplified to using something like .ps.pkg_list_installed() for pak/base/renv and just feeding the lib.loc in the renv case.
  2. I'd lean more into R's native vectorization. I think there's a lot of explicit iteration that can be eliminated. I gather some sort of row-by-row move is needed eventually to get this into the needed shape, but I think we can do that all at once at the last moment. Something along these lines:
.ps.pkg_list_installed <- function(lib.loc = NULL) {
    ip <- utils::installed.packages(
        lib.loc = lib.loc,
        fields = c("Description", "Maintainer")
    )

    pkgs <- ip[, "Package"]
    vers <- ip[, "Version"]
    description <- trimws(gsub(
        "\\s+",
        " ",
        ifelse(is.na(ip[, "Description"]), "", ip[, "Description"]),
        perl = TRUE
    ))
    maintainer <- trimws(gsub(
        "\\s*<[^>]+>",
        "",
        gsub(
            "\\s+",
            " ",
            ifelse(is.na(ip[, "Maintainer"]), "", ip[, "Maintainer"]),
            perl = TRUE
        ),
        perl = TRUE
    ))
    ids <- paste0(pkgs, "-", vers)

    Map(
        function(id, pkg, ver, description, maintainer) {
            list(
                id = id,
                name = pkg,
                displayName = pkg,
                version = ver,
                description = description,
                maintainer = maintainer
            )
        },
        ids,
        pkgs,
        vers,
        description,
        maintainer
    )
}

@jennybc
Copy link
Copy Markdown
Member

jennybc commented Apr 24, 2026

Here's a slightly cleaner version of my suggestion:

.ps.pkg_list_installed <- function(lib.loc = NULL) {
    ip <- utils::installed.packages(
        lib.loc = lib.loc,
        fields = c("Description", "Maintainer")
    )

    name <- ip[, "Package"]
    version <- ip[, "Version"]
    id <- paste0(name, "-", version)
    description <- trimws(gsub(
        "\\s+",
        " ",
        ifelse(is.na(ip[, "Description"]), "", ip[, "Description"]),
        perl = TRUE
    ))
    maintainer <- trimws(gsub(
        "\\s*<[^>]+>",
        "",
        gsub(
            "\\s+",
            " ",
            ifelse(is.na(ip[, "Maintainer"]), "", ip[, "Maintainer"]),
            perl = TRUE
        ),
        perl = TRUE
    ))

    Map(
        list,
        id = id,
        name = name,
        displayName = name,
        version = version,
        description = description,
        maintainer = maintainer
    )
}

The Map() could be even cleaner if name and displayName did not derive from the same intermediate object, i.e. we wouldn't need this = that stuff at all. Are name and displayName ever different? And if so, would that ever happen here in ark or might that be a Positron/typescript matter?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants