posit-dev / posit-dev/positron

Improving on "open" behavior of HTML-ish URLs

Open
#4,472 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

area: viewer lang: r
Dominant language
TypeScript
Stars
4.3k
Forks
184
Avg merge
1d 9h
Merged PRs (30d)
195

Description

In particular, this issue is about fixing pkgdown::preview_site(path = "reference/across.html"), which opens in the browser but not with the correct CSS available to render it correctly (see below). But is is also about better / more robust handling of HTML that comes through browseURL() in general


In https://github.com/posit-dev/positron/issues/4297 we saw issues with browseURL() and HTML files, in particular the following HTML files were opening in an editor rather than opening them in the browser / viewer:

  • pkgdown::preview_site()
  • pkgdown::preview_site(path = "reference/across.html")
  • profvis::profvis(expr)

These all called browseURL("<path>/file.html") in some way.

We determined here https://github.com/posit-dev/positron/issues/4297#issuecomment-2307212078 that this was a regression from https://github.com/posit-dev/positron/pull/4151 and mostly fixed the issues here https://github.com/posit-dev/positron/pull/4468

However, pkgdown::preview_site(path = "reference/across.html") still does not work correctly:

Screenshot 2024-08-23 at 3 38 28 PM

The problem is that we currently send a ShowUrl event from ark, and now as of https://github.com/posit-dev/positron/pull/4468 we detect an HTML file coming through that event and start a proxy server serving from its parent directory. The problem with that is that the parent directory of across.html is just reference/, but that is missing all the CSS to correctly render across.html.

@jmcphers and I think the right approach to fix this is to instead:

  • Go through ShowHtmlFile on the ark side, who's purpose is to show static HTML content in a proxy server

  • Probably add an external argument to ShowHtmlFile to request that it be opened in a browser rather than the viewer

  • Rework the ShowHtmlFile params signature to split the absolute path into:

    • directory, the base directory to serve from
    • path, the relative path from the base directory to the HTML file

    That allows Positron to know where to serve from, possibly allowing us to remove this code where previously we were guessing and using the parent directory

https://github.com/posit-dev/positron/blob/4bb3fe8e2150e96968f8d772eeb0890965af569b/extensions/positron-proxy/src/htmlProxy.ts#L75-L82

It would be up to ark to figure out that a URL like

/Users/davis/files/r/packages/dplyr/docs/dev/reference/across.html

should be split into

/Users/davis/files/r/packages/dplyr/docs/dev/ = dir
reference/across.html = path

But for that we could probably look up one directory at a time until we can't find an index.html anymore, and use the last time we saw index.html as the root directory to try and serve from.

Inside the details below is ark code for browser.rs that I was working on to start working towards this:

//
// browser.rs
//
// Copyright (C) 2023-2024 Posit Software, PBC. All rights reserved.
//
//

use amalthea::comm::ui_comm::ShowHtmlFileParams;
use amalthea::comm::ui_comm::ShowUrlParams;
use amalthea::comm::ui_comm::UiFrontendEvent;
use harp::object::RObject;
use libr::Rf_ScalarLogical;
use libr::SEXP;

use crate::help::message::HelpEvent;
use crate::help::message::ShowHelpUrlParams;
use crate::interface::RMain;

#[harp::register]
pub unsafe extern "C" fn ps_browse_url(url: SEXP) -> anyhow::Result<SEXP> {
    ps_browse_url_impl(url).or_else(|err| {
        log::error!("Failed to browse url due to: {err}");
        Ok(Rf_ScalarLogical(0))
    })
}

fn is_help_url(url: &str) -> bool {
    RMain::with(|main| main.is_help_url(url))
}

fn handle_help_url(url: String) -> anyhow::Result<()> {
    log::trace!("Sending `ShowHelpUrl` event");
    let event = HelpEvent::ShowHelpUrl(ShowHelpUrlParams { url });
    RMain::with(|main| main.send_help_event(event))
}

fn is_html_file(url: &str) -> bool {
    url.ends_with(".html")
}

fn handle_html_file(url: String) {
    // TODO: Needs separate `path` and `directory` arguments.
    // TODO: Possibly needs an `external` argument to request that it opens in a browser.
    log::trace!("Sending `ShowHtmlFile` event");
    let params = ShowHtmlFileParams {
        path: url,
        title: "".to_string(),
        is_plot: false,
        height: 0,
    };
    let event = UiFrontendEvent::ShowHtmlFile(params);
    RMain::with(|main| main.send_frontend_event(event))
}

fn handle_url(url: String) {
    log::trace!("Sending `ShowUrl` event");
    let params = ShowUrlParams { url };
    let event = UiFrontendEvent::ShowUrl(params);
    RMain::with(|main| main.send_frontend_event(event))
}

unsafe fn ps_browse_url_impl(url: SEXP) -> anyhow::Result<SEXP> {
    // Extract URL.
    let url = RObject::view(url).to::<String>()?;
    let _span = tracing::trace_span!("browseURL", url = %url).entered();

    // Handle help server requests.
    if is_help_url(&url) {
        handle_help_url(url)?;
        return Ok(Rf_ScalarLogical(1));
    }

    // Handle HTML files.
    if is_html_file(&url) {
        handle_html_file(url);
        return Ok(Rf_ScalarLogical(1));
    }

    // For all other URLs, create a ShowUrl event and send it to the main
    // thread; Positron will handle it.
    handle_url(url);
    Ok(Rf_ScalarLogical(1))
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in ark's browser.rs, especially handle_html_file() and the ShowHtmlFileParams construction, then inspect extensions/positron-proxy/src/htmlProxy.ts around the linked serving logic. Trace how browseURL() reaches ShowHtmlFile and determine the directory/path and external-browser parameters needed for nested HTML; done means pkgdown::preview_site(path = "reference/across.html") renders with its CSS and other HTML URLs retain correct behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust, typescript
Domain
desktop, developer-experience
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.