-
Notifications
You must be signed in to change notification settings - Fork 25
Simplify .Last.value handling
#1062
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,8 @@ use harp::utils::r_assert_type; | |
| use harp::utils::r_is_function; | ||
| use harp::vector::CharacterVector; | ||
| use harp::vector::Vector; | ||
| use harp::RSymbol; | ||
| use harp::R_ENVS; | ||
| use libr::R_GlobalEnv; | ||
| use libr::Rf_ScalarLogical; | ||
| use libr::ENVSXP; | ||
|
|
@@ -53,17 +55,6 @@ use crate::variables::variable::try_dispatch_view; | |
| use crate::variables::variable::PositronVariable; | ||
| use crate::view::view; | ||
|
|
||
| /// Enumeration of treatments for the .Last.value variable | ||
| pub enum LastValue { | ||
| /// Always show the .Last.value variable in the Variables pane. This is used | ||
| /// by tests to show the value without changing the global option. | ||
| Always, | ||
|
|
||
| /// Use the value of the global option `positron.show_last_value` to | ||
| /// determine whether to show the .Last.value variable | ||
| UseOption, | ||
| } | ||
|
|
||
| /** | ||
| * The R Variables handler provides the server side of Positron's Variables panel, and is | ||
| * responsible for creating and updating the list of variables. | ||
|
|
@@ -90,14 +81,6 @@ pub struct RVariables { | |
| current_bindings: RThreadSafe<Vec<Binding>>, | ||
| version: u64, | ||
|
|
||
| /// Whether to always show the .Last.value in the Variables pane, regardless | ||
| /// of the value of positron.show_last_value | ||
| show_last_value: LastValue, | ||
|
|
||
| /// Whether we are currently showing the .Last.value variable in the Variables | ||
| /// pane. | ||
| showing_last_value: bool, | ||
|
|
||
| /// Whether we need to send an initial `Refresh` event to the frontend, | ||
| /// which is required for frontend initialization. Set on construction, | ||
| /// cleared after the first `update()` call. | ||
|
|
@@ -116,24 +99,6 @@ impl RVariables { | |
| comm: CommSocket, | ||
| comm_event_tx: Sender<CommEvent>, | ||
| iopub_tx: Sender<IOPubMessage>, | ||
| ) { | ||
| // Start with default settings | ||
| Self::start_with_config(env, comm, comm_event_tx, iopub_tx, LastValue::UseOption); | ||
| } | ||
|
|
||
| /** | ||
| * Creates a new RVariables instance with specific configuration. | ||
| * | ||
| * - `env`: An R environment to scan for variables, typically R_GlobalEnv | ||
| * - `comm`: A channel used to send messages to the frontend | ||
| * - `show_last_value`: Whether to include .Last.value in the variables list | ||
| */ | ||
| pub fn start_with_config( | ||
| env: RObject, | ||
| comm: CommSocket, | ||
| comm_event_tx: Sender<CommEvent>, | ||
| iopub_tx: Sender<IOPubMessage>, | ||
| show_last_value: LastValue, | ||
| ) { | ||
| // Validate that the RObject we were passed is actually an environment | ||
| if let Err(err) = r_assert_type(env.sexp, &[ENVSXP]) { | ||
|
|
@@ -159,8 +124,6 @@ impl RVariables { | |
| env, | ||
| current_bindings, | ||
| version: 0, | ||
| show_last_value, | ||
| showing_last_value: false, | ||
| needs_initial_refresh: true, | ||
| }; | ||
| environment.execution_thread(); | ||
|
|
@@ -256,10 +219,6 @@ impl RVariables { | |
| fn list_variables(&mut self) -> Vec<Variable> { | ||
| let mut variables: Vec<Variable> = vec![]; | ||
| r_task(|| { | ||
| if let Some(last_value) = self.last_value() { | ||
| variables.push(last_value.var()); | ||
| } | ||
|
|
||
| for binding in self.current_bindings.get() { | ||
|
Comment on lines
220
to
222
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought it was very strange that we had all this special handling around I realized it could be greatly simplified by shoving Either:
Everything else (including |
||
| variables.push(PositronVariable::new(binding).var()); | ||
| } | ||
|
|
@@ -526,45 +485,21 @@ impl RVariables { | |
| } | ||
| } | ||
|
|
||
| /// Gets the value of the special variable '.Last.value' (the value of the | ||
| /// last expression evaluated at the top level), if enabled. | ||
| /// | ||
| /// Returns None in all other cases. | ||
| fn last_value(&self) -> Option<PositronVariable> { | ||
| // Check the cached value first | ||
| let show_last_value = match self.show_last_value { | ||
| LastValue::Always => true, | ||
| LastValue::UseOption => { | ||
| // If we aren't always showing the last value, update from the | ||
| // global option | ||
| let use_last_value = get_option("positron.show_last_value"); | ||
| match use_last_value.get_bool(0) { | ||
| Ok(Some(true)) => true, | ||
| _ => false, | ||
| } | ||
| }, | ||
| }; | ||
|
|
||
| if show_last_value { | ||
| match harp::environment::last_value() { | ||
| Ok(last_robj) => Some(PositronVariable::from( | ||
| String::from(".Last.value"), | ||
| String::from(".Last.value"), | ||
| last_robj.sexp, | ||
| )), | ||
| Err(err) => { | ||
| // This isn't a critical error but would also be very | ||
| // unexpected. | ||
| log::error!("Variables: Could not evaluate .Last.value ({err:?})"); | ||
| None | ||
| }, | ||
| } | ||
| } else { | ||
| // Last value display is disabled | ||
| None | ||
| /// Determines whether or not we should be showing the special `.Last.value` object | ||
| fn show_last_value(&self) -> bool { | ||
| match get_option("positron.show_last_value").get_bool(0) { | ||
| Ok(Some(true)) => true, | ||
| _ => false, | ||
| } | ||
| } | ||
|
|
||
| fn last_value() -> harp::Result<Binding> { | ||
| Binding::new( | ||
| &Environment::view(R_ENVS.base), | ||
| RSymbol::from(".Last.value"), | ||
| ) | ||
| } | ||
|
|
||
| #[tracing::instrument(level = "trace", skip_all)] | ||
| fn update(&mut self) { | ||
| r_task(|| { | ||
|
|
@@ -580,10 +515,6 @@ impl RVariables { | |
|
|
||
| let mut variables: Vec<Variable> = vec![]; | ||
|
|
||
| if let (Some(var), _) = self.track_last_value() { | ||
| variables.push(var); | ||
| } | ||
|
|
||
| for binding in self.current_bindings.get() { | ||
| variables.push(PositronVariable::new(binding).var()); | ||
| } | ||
|
|
@@ -602,12 +533,6 @@ impl RVariables { | |
| let mut assigned: Vec<Variable> = vec![]; | ||
| let mut removed: Vec<String> = vec![]; | ||
|
|
||
| match self.track_last_value() { | ||
| (Some(var), _) => assigned.push(var), | ||
| (None, true) => removed.push(".Last.value".to_string()), | ||
| (None, false) => {}, | ||
| } | ||
|
|
||
| let new_bindings = self.bindings(); | ||
|
|
||
| let mut old_iter = self.current_bindings.get().iter(); | ||
|
|
@@ -684,20 +609,6 @@ impl RVariables { | |
|
|
||
| // SAFETY: The following methods must be called in an `r_task()` | ||
|
|
||
| /// Updates `self.showing_last_value` and returns the last value variable | ||
| /// if it should be shown, along with whether it was previously shown. | ||
| fn track_last_value(&mut self) -> (Option<Variable>, bool) { | ||
| let was_showing = self.showing_last_value; | ||
|
|
||
| if let Some(last_value) = self.last_value() { | ||
| self.showing_last_value = true; | ||
| (Some(last_value.var()), was_showing) | ||
| } else { | ||
| self.showing_last_value = false; | ||
| (None, was_showing) | ||
| } | ||
| } | ||
|
|
||
| /// Updates `self.env` to the current effective environment if it changed | ||
| /// (e.g. entering or exiting debug mode). Returns `true` if switched. | ||
| fn update_env(&mut self) -> bool { | ||
|
|
@@ -721,6 +632,12 @@ impl RVariables { | |
|
|
||
| let mut bindings: Vec<Binding> = env.iter().filter_map(|b| b.ok()).collect(); | ||
|
|
||
| if self.show_last_value() { | ||
| if let Some(last_value) = Self::last_value().log_err() { | ||
| bindings.push(last_value); | ||
| } | ||
| } | ||
|
Comment on lines
+635
to
+639
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the one special place we handle it now |
||
|
|
||
| bindings.sort_by(|a, b| a.name.cmp(&b.name)); | ||
|
|
||
| RThreadSafe::new(bindings) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only used by tests before, but we don't use this now. We literally set the option like an R user would.