Skip to content

Commit 91b251e

Browse files
dfalbelCopilotDavisVaughan
authored
Add the has_viewer method (#773)
Co-authored-by: Copilot <[email protected]> Co-authored-by: Davis Vaughan <[email protected]>
1 parent c8d4650 commit 91b251e

File tree

5 files changed

+103
-2
lines changed

5 files changed

+103
-2
lines changed

crates/ark/src/methods.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ pub enum ArkGenerics {
3939

4040
#[strum(serialize = "ark_positron_variable_get_children")]
4141
VariableGetChildren,
42+
43+
#[strum(serialize = "ark_positron_variable_has_viewer")]
44+
VariableHasViewer,
4245
}
4346

4447
impl ArkGenerics {

crates/ark/src/modules/positron/methods.R

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ ark_methods_table$ark_positron_variable_get_child_at <- new.env(
2222
ark_methods_table$ark_positron_variable_get_children <- new.env(
2323
parent = emptyenv()
2424
)
25+
ark_methods_table$ark_positron_variable_has_viewer <- new.env(
26+
parent = emptyenv()
27+
)
2528
lockEnvironment(ark_methods_table, TRUE)
2629

2730
ark_methods_allowed_packages <- c("torch", "reticulate", "duckplyr")

crates/ark/src/variables/variable.rs

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,28 @@ fn has_children(value: SEXP) -> bool {
588588
}
589589
}
590590

591+
fn has_viewer(value: SEXP) -> bool {
592+
if !(r_is_data_frame(value) || r_is_matrix(value)) {
593+
return false;
594+
}
595+
596+
// We have a data.frame or matrix. Dispatch to the has_viewer method
597+
match ArkGenerics::VariableHasViewer.try_dispatch::<bool>(value, vec![]) {
598+
Err(err) => {
599+
log::error!(
600+
"Error from '{}' method: {err}",
601+
ArkGenerics::VariableHasViewer.to_string()
602+
);
603+
// The viewer method exists, but failed
604+
false
605+
},
606+
// A matching viewer method was not found
607+
Ok(None) => true,
608+
// The viewer method was found, use its result
609+
Ok(Some(val)) => val,
610+
}
611+
}
612+
591613
enum EnvironmentVariableNode {
592614
Concrete { object: RObject },
593615
R6Node { object: RObject, name: String },
@@ -653,7 +675,7 @@ impl PositronVariable {
653675
size: 0, // It's up to the caller to set the size.
654676
has_children: has_children(x),
655677
is_truncated,
656-
has_viewer: r_is_data_frame(x) || r_is_matrix(x),
678+
has_viewer: has_viewer(x),
657679
updated_time: Self::update_timestamp(),
658680
},
659681
}
@@ -1681,6 +1703,10 @@ mod tests {
16811703
"other"
16821704
})
16831705
1706+
.ark.register_method("ark_positron_variable_has_viewer", "foo", function(x) {
1707+
TRUE
1708+
})
1709+
16841710
.ark.register_method("ark_positron_variable_get_children", "foo", function(x) {
16851711
children <- list(
16861712
"hello" = list(a = 1, b = 2),
@@ -1741,6 +1767,10 @@ mod tests {
17411767

17421768
assert_eq!(variable.kind, VariableKind::Other);
17431769

1770+
// Even though the viewer method returns TRUE, the object is not a data.frame
1771+
// or matrix, so it doesn't have a viewer.
1772+
assert_eq!(variable.has_viewer, false);
1773+
17441774
// Now inspect `x`
17451775
let path = vec![String::from("x")];
17461776
let variables = PositronVariable::inspect(env.clone(), &path).unwrap();
@@ -1766,6 +1796,7 @@ mod tests {
17661796
.ark.unregister_method("ark_positron_variable_display_value", "foo")
17671797
.ark.unregister_method("ark_positron_variable_display_type", "foo")
17681798
.ark.unregister_method("ark_positron_variable_has_children", "foo")
1799+
.ark.unregister_method("ark_positron_variable_has_viewer", "foo")
17691800
.ark.unregister_method("ark_positron_variable_kind", "foo")
17701801
.ark.unregister_method("ark_positron_variable_get_children", "foo")
17711802
.ark.unregister_method("ark_positron_variable_get_child_at", "foo")
@@ -1775,6 +1806,52 @@ mod tests {
17751806
})
17761807
}
17771808

1809+
#[test]
1810+
fn test_has_viewer_data_frame_subclass() {
1811+
r_task(|| {
1812+
// Create an object with that class in an env.
1813+
let env = harp::parse_eval_base(
1814+
r#"
1815+
local({
1816+
env <- new.env(parent = emptyenv())
1817+
env$x <- structure(data.frame(x = 1, y = 2), class = c("foo", "data.frame"))
1818+
env
1819+
})
1820+
"#,
1821+
)
1822+
.unwrap();
1823+
1824+
let has_viewer = || {
1825+
let path = vec![];
1826+
let variables = PositronVariable::inspect(env.clone(), &path).unwrap();
1827+
1828+
assert_eq!(variables.len(), 1);
1829+
let variable = variables[0].clone();
1830+
variable.has_viewer
1831+
};
1832+
1833+
assert!(has_viewer());
1834+
1835+
harp::parse_eval_global(
1836+
r#"
1837+
.ark.register_method("ark_positron_variable_has_viewer", "foo", function(x) {
1838+
FALSE
1839+
})
1840+
"#,
1841+
)
1842+
.unwrap();
1843+
1844+
assert!(!has_viewer());
1845+
1846+
harp::parse_eval_global(
1847+
r#"
1848+
.ark.unregister_method("ark_positron_variable_has_viewer", "foo")
1849+
"#,
1850+
)
1851+
.unwrap();
1852+
})
1853+
}
1854+
17781855
#[test]
17791856
fn test_inspect_r6() {
17801857
r_task(|| {

doc/variables-pane-extending.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,15 @@ You can also register a method outside an R package using `.ps.register_ark_meth
2626

2727
## Available Methods
2828

29-
Ark currently supports six methods with the following signatures:
29+
Ark currently supports seven methods with the following signatures:
3030

3131
- `ark_positron_variable_display_value(x, ..., width = getOption("width"))`
3232
- `ark_positron_variable_display_type(x, ..., include_length = TRUE)`
3333
- `ark_positron_variable_kind(x, ...)`
3434
- `ark_positron_variable_has_children(x, ...)`
3535
- `ark_positron_variable_get_children(x, ...)`
3636
- `ark_positron_variable_get_child_at(x, ..., index, name)`
37+
- `ark_positron_variable_has_viewer(x, ...)`
3738

3839
### Customizing Display Value
3940

@@ -77,6 +78,23 @@ ark_positron_variable_kind.foo <- function(x, ...) {
7778
}
7879
```
7980

81+
### Disabling the Viewer action
82+
83+
The `ark_positron_variable_has_viewer` can be used to disable the `View` actions for `data.frame` and `matrix`
84+
objects that don't support it. This method is only called for such objects, other objects are not supported
85+
by Positron yet.
86+
87+
Example:
88+
89+
```r
90+
#' @param x Object to check for Viewer support
91+
ark_positron_variable_has_viewer.foo <- function(x, ...) {
92+
# The viewer will not be enabled for `foo` objects.
93+
# This is only called if `foo` is a subclass of a data.frame or matrix.
94+
FALSE
95+
}
96+
```
97+
8098
## Inspecting Objects
8199

82100
Package authors can also implement methods that allow users to inspect R objects, similar to how the `str()` function works in R. This enables displaying object structures in the variables pane.

doc/variables-pane.png

26 KB
Loading

0 commit comments

Comments
 (0)