Skip to content

Commit 0cae2f7

Browse files
authored
Merge pull request #807 from posit-dev/feature/debug-completions
Inject debug environment in search path completions
2 parents 2013ca1 + 4be91aa commit 0cae2f7

File tree

3 files changed

+44
-9
lines changed

3 files changed

+44
-9
lines changed

crates/ark/src/interface.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,11 @@ pub struct RMain {
255255
/// The stack of frames we saw the last time we stopped. Used as a mostly
256256
/// reliable indication of whether we moved since last time.
257257
debug_last_stack: Vec<FrameInfoId>,
258+
259+
/// Current topmost environment on the stack while waiting for input in the
260+
/// debugger. This is `Some()` only when R is idle and in a `browser()`
261+
/// prompt.
262+
debug_env: Option<RObject>,
258263
}
259264

260265
/// Represents the currently active execution request from the frontend. It
@@ -588,6 +593,7 @@ impl RMain {
588593
captured_output: String::new(),
589594
debug_preserve_focus: false,
590595
debug_last_stack: vec![],
596+
debug_env: None,
591597
}
592598
}
593599

@@ -774,6 +780,13 @@ impl RMain {
774780
if info.browser {
775781
match self.dap.stack_info() {
776782
Ok(stack) => {
783+
if let Some(frame) = stack.first() {
784+
if let Some(ref env) = frame.environment {
785+
// This is reset on exit in the cleanup phase, see `r_read_console()`
786+
self.debug_env = Some(env.get().clone());
787+
}
788+
}
789+
777790
// Figure out whether we changed location since last time,
778791
// e.g. because the user evaluated an expression that hit
779792
// another breakpoint. In that case we do want to move
@@ -961,6 +974,11 @@ impl RMain {
961974
};
962975
}
963976

977+
fn read_console_cleanup(&mut self) {
978+
// The debug environment is only valid while R is idle
979+
self.debug_env = None;
980+
}
981+
964982
/// Returns:
965983
/// - `None` if we should fall through to the event loop to wait for more user input
966984
/// - `Some(ConsoleResult)` if we should immediately exit `read_console()`
@@ -2054,6 +2072,11 @@ impl RMain {
20542072
StdInRpcReply::Interrupt => Ok(RObject::null()),
20552073
}
20562074
}
2075+
2076+
#[cfg(not(test))] // Avoid warnings in unit test
2077+
pub(crate) fn debug_env(&self) -> Option<RObject> {
2078+
self.debug_env.clone()
2079+
}
20572080
}
20582081

20592082
/// Report an incomplete request to the frontend
@@ -2124,6 +2147,7 @@ pub extern "C-unwind" fn r_read_console(
21242147
) -> i32 {
21252148
let main = RMain::get_mut();
21262149
let result = r_sandbox(|| main.read_console(prompt, buf, buflen, hist));
2150+
main.read_console_cleanup();
21272151

21282152
let result = unwrap!(result, Err(err) => {
21292153
panic!("Unexpected longjump while reading console: {err:?}");

crates/ark/src/lsp/completions/sources/composite/search_path.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,25 @@ fn completions_from_search_path(
5858

5959
unsafe {
6060
// Iterate through environments starting from the global environment.
61-
let mut envir = R_GlobalEnv;
61+
let mut env = R_GlobalEnv;
62+
63+
// If we're waiting for input in `read_console()` with a debugger
64+
// prompt, start from current environment
65+
#[cfg(not(test))] // Unit tests do not have an `RMain`
66+
{
67+
use crate::interface::RMain;
68+
if let Some(debug_env) = &RMain::get().debug_env() {
69+
// Mem-Safety: Object protected by `RMain` for the duration of the `r_task()`
70+
env = debug_env.sexp;
71+
}
72+
}
6273

63-
while envir != R_EmptyEnv {
64-
let is_pkg_env = r_env_is_pkg_env(envir);
74+
while env != R_EmptyEnv {
75+
let is_pkg_env = r_env_is_pkg_env(env);
6576

6677
// Get package environment name, if there is one
6778
let name = if is_pkg_env {
68-
let name = RObject::from(r_pkg_env_name(envir));
79+
let name = RObject::from(r_pkg_env_name(env));
6980
let name = String::try_from(name)?;
7081
Some(name)
7182
} else {
@@ -84,7 +95,7 @@ fn completions_from_search_path(
8495
};
8596

8697
// List symbols in the environment.
87-
let symbols = R_lsInternal(envir, 1);
98+
let symbols = R_lsInternal(env, 1);
8899

89100
// Create completion items for each.
90101
let vector = CharacterVector::new(symbols)?;
@@ -103,9 +114,9 @@ fn completions_from_search_path(
103114
// Add the completion item.
104115
match completion_item_from_symbol(
105116
symbol,
106-
envir,
117+
env,
107118
name,
108-
promise_strategy.clone(),
119+
promise_strategy,
109120
parameter_hints,
110121
) {
111122
Ok(item) => completions.push(item),
@@ -118,7 +129,7 @@ fn completions_from_search_path(
118129
}
119130

120131
// Get the next environment.
121-
envir = ENCLOS(envir);
132+
env = ENCLOS(env);
122133
}
123134

124135
// Include installed packages as well.

crates/ark/src/lsp/completions/types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub(super) enum CompletionData {
5454
Unknown,
5555
}
5656

57-
#[derive(Clone, Debug, PartialEq)]
57+
#[derive(Copy, Clone, Debug, PartialEq)]
5858
pub(crate) enum PromiseStrategy {
5959
Simple,
6060
Force,

0 commit comments

Comments
 (0)