Skip to content

Conversation

@jmcphers
Copy link
Contributor

@jmcphers jmcphers commented Dec 11, 2025

This change causes profiler output from profvis to be shown in a new Positron editor tab.

Rough outline:

  • In the UI comm, the is_plot flag has been replaced with a destination enum that specifies one of three destinations: the viewer pane, the plot pane, or an editor tab
  • We set the profvis.print option and cause profvis files to be output as temporary HTML files, which we send to Positron to be opened in an editor tab (very similar to the workflow for HTML widgets).

There are a few unrelated changes that are the result of ark being a little out of sync with the UI comm definition in Positron.

Requires posit-dev/positron#11067.

Part of posit-dev/positron#3269.

# Show Profvis output in the viewer
options(profvis.print = function(x) {
# Render the HTML content to a temporary file
tmp_file <- htmltools::html_print(x, viewer = NULL)
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably worth a note that hmtltools is an (indirect) dependency of profvis

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed

let input = if harp::get_option_bool("keep.source") {
_srcfile = Some(SrcFile::new_virtual_empty_filename(input.into()));
harp::ParseInput::SrcFile(&_srcfile.unwrap())
harp::ParseInput::SrcFile(_srcfile.as_ref().unwrap())
Copy link
Contributor

Choose a reason for hiding this comment

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

I looked into this again and just learned about a neat Rust feature called lifetime extension.

I originally thought I needed _srcfile to be stored at top-level so I could pass a reference to it. But that's not what happens even in the original version of the code! Since unwrap() takes self here, the value is moved out of _srcfile into a temporary. We then take a reference to it, and Rust extends the lifetime of the temporary to match that of the reference (which is tied to input).

More info at: https://doc.rust-lang.org/reference/destructors.html#temporary-lifetime-extension

With your change, we're creating a new Option containing a reference, so unwrapping it doesn't consume _srcfile.

But armed with the knowledge of lifetime extension we can write this much cleaner version:

        let input = if harp::get_option_bool("keep.source") {
            harp::ParseInput::SrcFile(&SrcFile::new_virtual_empty_filename(input.into()))
        } else {
            harp::ParseInput::Text(input)
        };

Can you please revert your change? Merging it would cause a conflict with PRs/branches of mine. I'll implement the new approach suggested above in these branches.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason I made this change was that locally I can't even build ark without it. The original code generates this fatal error on my machine:

error[E0716]: temporary value dropped while borrowed
   --> crates/ark/src/interface.rs:340:40
    |
338 |         let input = if harp::get_option_bool("keep.source") {
    |             ----- borrow later stored here
339 |             _srcfile = Some(SrcFile::new_virtual_empty_filename(input.into()));
340 |             harp::ParseInput::SrcFile(&_srcfile.unwrap())
    |                                        ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
341 |         } else {
    |         - temporary value is freed at the end of this statement
    |
    = note: consider using a `let` binding to create a longer lived value

Incidentally your proposed version doesn't compile for me either:

   Compiling ark v0.1.220 (/Users/jmcphers/git2/ark/crates/ark)
error[E0716]: temporary value dropped while borrowed
   --> crates/ark/src/interface.rs:337:40
    |
336 |         let input = if harp::get_option_bool("keep.source") {
    |             ----- borrow later stored here
337 |             harp::ParseInput::SrcFile(&SrcFile::new_virtual_empty_filename(input.into()))
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
338 |         } else {
    |         - temporary value is freed at the end of this statement
    |
    = note: consider using a `let` binding to create a longer lived value

Probably has to do with the version of Rust I'm using? I'm on 1.87.

I did revert the change, since it doesn't seem to be causing any trouble in CI.

Copy link
Contributor

Choose a reason for hiding this comment

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

oh I'm on 1.89. Good to know!

This is from the 1.89 changelog and explains the difference: rust-lang/rust#140593

Copy link
Contributor

Choose a reason for hiding this comment

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

I've bumped the minimum version to 1.89 on main to avoid such issues in the future.

jmcphers and others added 2 commits December 12, 2025 16:03
Copy link
Contributor

@DavisVaughan DavisVaughan left a comment

Choose a reason for hiding this comment

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

Looks like it is working as expected in my testing. The lack of resizing does stink though. If that's easy to figure out it would probably be worth like 30 minutes of investigative effort, since it somehow works in RStudio.

# Show Profvis output in the viewer
options(profvis.print = function(x) {
# Render the HTML content to a temporary file
tmp_file <- htmltools::html_print(x, viewer = NULL)
Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed

# Show Profvis output in the viewer
options(profvis.print = function(x) {
# Render the HTML content to a temporary file
tmp_file <- htmltools::html_print(x, viewer = NULL)
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess passing the background color to htmltools::html_print() would be asking too much? 😄

Image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When I was first implementing htmlwidgets support I actually hooked this up, which was when I discovered that most htmlwidgets are not theme-aware and always render in dark/black colors, so setting the background to black made them unreadable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same deal for profvis 😂
image

# Render the HTML content to a temporary file
tmp_file <- htmltools::html_print(x, viewer = NULL)

# Pass the file to the viewer
Copy link
Contributor

Choose a reason for hiding this comment

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

It is rather annoying that it doesn't resize. It means the window of text that you are reading is quite small to read.

It does resize in RStudio, I wonder what is different there?

Screen.Recording.2025-12-15.at.2.03.40.PM.mov

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the nudge, I think I figured it out ... the trick is to force it to render in standalone mode by rendering to tags first. (That's not how RStudio does it, but works here.) db02e6f

@jmcphers jmcphers merged commit d748867 into main Dec 16, 2025
8 checks passed
@jmcphers jmcphers deleted the feature/profvis-output branch December 16, 2025 01:40
@github-actions github-actions bot locked and limited conversation to collaborators Dec 16, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants