Skip to content

Commit

Permalink
Add a few more OpenRPC methods for rstudioapi shims (#286)
Browse files Browse the repository at this point in the history
* Add `execute_code` OpenRPC method

* Add `new_document` OpenRPC method

* Clarify how we do not yet support row/column
  • Loading branch information
juliasilge authored Apr 3, 2024
1 parent a79cd95 commit 47d52d5
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 8 deletions.
47 changes: 47 additions & 0 deletions crates/amalthea/src/comm/ui_comm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,16 @@ pub struct OpenEditorParams {
pub column: i64,
}

/// Parameters for the NewDocument method.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct NewDocumentParams {
/// Document contents
pub contents: String,

/// Language identifier
pub language_id: String,
}

/// Parameters for the ShowMessage method.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct ShowMessageParams {
Expand Down Expand Up @@ -191,6 +201,22 @@ pub struct ExecuteCommandParams {
pub command: String,
}

/// Parameters for the ExecuteCode method.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct ExecuteCodeParams {
/// The language ID of the code to execute
pub language_id: String,

/// The code to execute
pub code: String,

/// Whether to focus the runtime's console
pub focus: bool,

/// Whether to bypass runtime code completeness checks
pub allow_incomplete: bool,
}

/// Parameters for the OpenWorkspace method.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct OpenWorkspaceParams {
Expand Down Expand Up @@ -258,6 +284,13 @@ pub enum UiBackendReply {
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(tag = "method", content = "params")]
pub enum UiFrontendRequest {
/// Create a new document with text contents
///
/// Use this to create a new document with the given language ID and text
/// contents
#[serde(rename = "new_document")]
NewDocument(NewDocumentParams),

/// Show a question
///
/// Use this for a modal dialog that the user can accept or cancel
Expand All @@ -276,6 +309,12 @@ pub enum UiFrontendRequest {
#[serde(rename = "debug_sleep")]
DebugSleep(DebugSleepParams),

/// Execute code in a Positron runtime
///
/// Use this to execute code in a Positron runtime
#[serde(rename = "execute_code")]
ExecuteCode(ExecuteCodeParams),

/// Path to the workspace folder
///
/// Returns the path to the workspace folder, or first folder if there are
Expand Down Expand Up @@ -304,6 +343,9 @@ pub enum UiFrontendRequest {
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(tag = "method", content = "result")]
pub enum UiFrontendReply {
/// Reply for the new_document method (no result)
NewDocumentReply(),

/// Whether the user accepted or rejected the dialog.
ShowQuestionReply(bool),

Expand All @@ -313,6 +355,9 @@ pub enum UiFrontendReply {
/// Reply for the debug_sleep method (no result)
DebugSleepReply(),

/// Reply for the execute_code method (no result)
ExecuteCodeReply(),

/// The path to the workspace folder
WorkspaceFolderReply(Option<String>),

Expand Down Expand Up @@ -387,9 +432,11 @@ pub fn ui_frontend_reply_from_value(
request: &UiFrontendRequest,
) -> anyhow::Result<UiFrontendReply> {
match request {
UiFrontendRequest::NewDocument(_) => Ok(UiFrontendReply::NewDocumentReply()),
UiFrontendRequest::ShowQuestion(_) => Ok(UiFrontendReply::ShowQuestionReply(serde_json::from_value(reply)?)),
UiFrontendRequest::ShowDialog(_) => Ok(UiFrontendReply::ShowDialogReply()),
UiFrontendRequest::DebugSleep(_) => Ok(UiFrontendReply::DebugSleepReply()),
UiFrontendRequest::ExecuteCode(_) => Ok(UiFrontendReply::ExecuteCodeReply()),
UiFrontendRequest::WorkspaceFolder => Ok(UiFrontendReply::WorkspaceFolderReply(serde_json::from_value(reply)?)),
UiFrontendRequest::ModifyEditorSelections(_) => Ok(UiFrontendReply::ModifyEditorSelectionsReply()),
UiFrontendRequest::LastActiveEditorContext => Ok(UiFrontendReply::LastActiveEditorContextReply(serde_json::from_value(reply)?)),
Expand Down
10 changes: 10 additions & 0 deletions crates/ark/src/modules/positron/frontend-methods.R
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,21 @@
.ps.Call("ps_ui_navigate_to_file", file, line, column)
}

#' @export
.ps.ui.newDocument <- function(contents, languageId) {
.ps.Call("ps_ui_new_document", contents, languageId)
}

#' @export
.ps.ui.executeCommand <- function(command) {
.ps.Call("ps_ui_execute_command", command)
}

#' @export
.ps.ui.executeCode <- function(code, focus) {
.ps.Call("ps_ui_execute_code", code, focus)
}

#' @export
.ps.ui.showMessage <- function(message) {
.ps.Call("ps_ui_show_message", message)
Expand Down
12 changes: 4 additions & 8 deletions crates/ark/src/modules/rstudio/document-api.R
Original file line number Diff line number Diff line change
Expand Up @@ -94,16 +94,12 @@ selection_as_range <- function(ps_sel) {
}

#' @export
.rs.api.documentNew <- function(text,
type = c("r", "rmarkdown", "sql"),
position = rstudioapi::document_position(0, 0),
execute = FALSE) {
type <- match.arg(type)
# TODO: Support execute & position
stopifnot(!execute && position != rstudioapi::document_position(0, 0))
.rs.api.documentNew <- function(type, code, row = 0, column = 0, execute = FALSE) {
# TODO: Support execute and row/column
stopifnot(!execute && !row && !column)

languageId <- if (type == "rmarkdown") "rmd" else type
invisible(.ps.ui.documentNew(text, languageId))
invisible(.ps.ui.newDocument(paste(code, collapse = "\n"), languageId))
}

#' @export
Expand Down
9 changes: 9 additions & 0 deletions crates/ark/src/modules/rstudio/stubs.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@
invisible(.ps.ui.navigateToFile(file, line, column))
}

#' @export
.rs.api.sendToConsole <- function(code, echo = TRUE, execute = TRUE, focus = TRUE, animate = FALSE) {
# TODO: support other args
stopifnot(echo && execute && !animate)

# If we add new args later, remember to put them **after** the existing args
invisible(.ps.ui.executeCode(paste(code, collapse = "\n"), focus))
}

#' @export
.rs.api.restartSession <- function(command = "") {
# TODO: support followup `command` argument
Expand Down
31 changes: 31 additions & 0 deletions crates/ark/src/ui/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
//

use amalthea::comm::ui_comm::DebugSleepParams;
use amalthea::comm::ui_comm::ExecuteCodeParams;
use amalthea::comm::ui_comm::ModifyEditorSelectionsParams;
use amalthea::comm::ui_comm::NewDocumentParams;
use amalthea::comm::ui_comm::ShowDialogParams;
use amalthea::comm::ui_comm::ShowQuestionParams;
use amalthea::comm::ui_comm::UiFrontendRequest;
Expand Down Expand Up @@ -89,6 +91,35 @@ pub unsafe extern "C" fn ps_ui_show_question(
Ok(out.sexp)
}

#[harp::register]
pub unsafe extern "C" fn ps_ui_new_document(
contents: SEXP,
language_id: SEXP,
) -> anyhow::Result<SEXP> {
let params = NewDocumentParams {
contents: RObject::view(contents).try_into()?,
language_id: RObject::view(language_id).try_into()?,
};

let main = RMain::get();
let out = main.call_frontend_method(UiFrontendRequest::NewDocument(params))?;
Ok(out.sexp)
}

#[harp::register]
pub unsafe extern "C" fn ps_ui_execute_code(code: SEXP, focus: SEXP) -> anyhow::Result<SEXP> {
let params = ExecuteCodeParams {
language_id: String::from("r"),
code: RObject::view(code).try_into()?,
focus: RObject::view(focus).try_into()?,
allow_incomplete: false,
};

let main = RMain::get();
let out = main.call_frontend_method(UiFrontendRequest::ExecuteCode(params))?;
Ok(out.sexp)
}

#[harp::register]
pub unsafe extern "C" fn ps_ui_debug_sleep(ms: SEXP) -> anyhow::Result<SEXP> {
let params = DebugSleepParams {
Expand Down

0 comments on commit 47d52d5

Please sign in to comment.