Skip to content

Commit

Permalink
Merge pull request #354 from rstudio/feature/renvpane_list
Browse files Browse the repository at this point in the history
R environment pane: named list expansion
  • Loading branch information
romainfrancois authored Apr 4, 2023
2 parents 9345da2 + d8b0e93 commit cdeff8a
Show file tree
Hide file tree
Showing 8 changed files with 357 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ pub enum EnvironmentMessage {

/// A message containing an error message.
Error(EnvironmentMessageError),

/// A message requesting to inspect a variable
Inspect(EnvironmentMessageInspect),

/// Details about a variable, response to an Inspect message
Details(EnvironmentMessageDetails)
}

/**
Expand Down Expand Up @@ -89,3 +95,21 @@ pub struct EnvironmentMessageClear {
pub struct EnvironmentMessageDelete {
pub variables: Vec<String>,
}

/**
* The data for the Inspect message
*/
#[derive(Debug, Serialize, Deserialize)]
pub struct EnvironmentMessageInspect {
pub path: Vec<String>,
}

/**
* The data for the Details message
*/
#[derive(Debug, Serialize, Deserialize)]
pub struct EnvironmentMessageDetails {
pub path: Vec<String>,
pub children: Vec<EnvironmentVariable>,
pub length: usize,
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ use log::warn;
use crate::environment::message::EnvironmentMessage;
use crate::environment::message::EnvironmentMessageClear;
use crate::environment::message::EnvironmentMessageDelete;
use crate::environment::message::EnvironmentMessageDetails;
use crate::environment::message::EnvironmentMessageError;
use crate::environment::message::EnvironmentMessageInspect;
use crate::environment::message::EnvironmentMessageList;
use crate::environment::message::EnvironmentMessageUpdate;
use crate::environment::variable::EnvironmentVariable;
Expand Down Expand Up @@ -159,6 +162,10 @@ impl REnvironment {
self.delete(variables, Some(id));
},

EnvironmentMessage::Inspect(EnvironmentMessageInspect{path}) => {
self.inspect(&path, Some(id));
},

_ => {
error!(
"Environment: Don't know how to handle message type '{:?}'",
Expand Down Expand Up @@ -275,6 +282,30 @@ impl REnvironment {
self.update(request_id);
}

fn inspect(&mut self, path: &Vec<String>, request_id: Option<String>) {
let inspect = r_lock!{
EnvironmentVariable::inspect(RObject::view(*self.env), &path)
};
let msg = match inspect {
Ok(children) => {
let length = children.len();
EnvironmentMessage::Details(EnvironmentMessageDetails {
path: path.clone(),
children,
length
})
},
Err(_) => {
EnvironmentMessage::Error(EnvironmentMessageError {
message: String::from("Inspection error")
})
}
};

self.send_message(msg, request_id);

}

fn send_message(&mut self, message: EnvironmentMessage, request_id: Option<String>) {
let data = serde_json::to_value(message);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@
//

use harp::environment::Binding;
use harp::environment::BindingType;
use harp::environment::BindingValue;
use harp::exec::RFunction;
use harp::exec::RFunctionExt;
use harp::object::RObject;
use harp::utils::r_typeof;
use harp::vector::CharacterVector;
use harp::vector::Vector;
use libR_sys::*;
use serde::Deserialize;
use serde::Serialize;

Expand Down Expand Up @@ -82,21 +91,62 @@ impl EnvironmentVariable {
pub fn new(binding: &Binding) -> Self {
let display_name = binding.name.to_string();

let value = binding.display_value();
let display_type = binding.display_type();
let BindingValue{display_value, is_truncated} = binding.get_value();
let BindingType{display_type, type_info} = binding.get_type();

let kind = ValueKind::String;
let has_children = binding.has_children();

Self {
display_name,
display_value: value.value,
display_value,
display_type,
type_info: String::new(),
type_info,
kind,
length: 0,
size: 0,
has_children: false,
is_truncated: value.is_truncated,
has_children,
is_truncated,
}
}

pub fn inspect(env: RObject, path: &Vec<String>) -> Result<Vec<Self>, harp::error::Error> {
// for now only lists can be expanded
let list = unsafe {
RFunction::from(".ps.environment.resolveObjectFromPath")
.param("env", env)
.param("path", CharacterVector::create(path).cast())
.call()?
};

let mut out : Vec<Self> = vec![];
let n = unsafe { XLENGTH(*list) };

let names = unsafe {
CharacterVector::new_unchecked(RFunction::from(".ps.environment.listDisplayNames").add(*list).call()?)
};

for i in 0..n {
let x = RObject::view(unsafe{ VECTOR_ELT(*list, i)});
let display_name = names.get_unchecked(i).unwrap();
let BindingValue{display_value, is_truncated} = BindingValue::from(*x);
let BindingType{display_type, type_info} = BindingType::from(*x);
let has_children = r_typeof(*x) == VECSXP;

out.push(Self {
display_name,
display_value,
display_type,
type_info,
kind: ValueKind::Other,
length: 0,
size: 0,
has_children,
is_truncated
});
}

Ok(out)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#
# environment.R
#
# Copyright (C) 2023 Posit Software, PBC. All rights reserved.
#
#
.ps.environment.listDisplayNames <- function(x) {
names <- names(x)
if (is.null(names)) {
names <- paste0("[[", seq_along(x), "]]")
} else {
empty <- which(names == "")
names[empty] <- paste0("[[", empty, "]]")
}
names
}

.ps.environment.resolveObjectFromPath <- function(env, path) {
rx_unnamed <- "^[[][[]([[:digit:]])[]][]]"

# start with environment
object <- env

# and then move down the path
for (p in path) {
if (grepl(rx_unnamed, p)) {
index <- as.integer(sub(rx_unnamed, "\\1", p))
object <- object[[index]]
} else {
object <- object[[p]]
}
}

object
}
2 changes: 1 addition & 1 deletion extensions/positron-r/amalthea/crates/ark/src/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use harp::exec::r_parse_vector;
use harp::exec::ParseResult;
use harp::object::RObject;
use harp::r_lock;
use libR_sys::R_GlobalEnv;
use libR_sys::*;
use log::*;
use serde_json::json;

Expand Down
Loading

0 comments on commit cdeff8a

Please sign in to comment.