debugger: Generate inline values based on debugger.scm file (#33081)
## Context To support inline values a language will have to implement their own provider trait that walks through tree sitter nodes. This is overly complicated, hard to accurately implement for each language, and lacks proper extension support. This PR switches to a singular inline provider that uses a language's `debugger.scm` query field to capture variables and scopes. The inline provider is able to use this information to generate inlays that take scope into account and work with any language that defines a debugger query file. ### Todos - [x] Implement a utility test function to easily test inline values - [x] Generate inline values based on captures - [x] Reimplement Python, Rust, and Go support - [x] Take scope into account when iterating through variable captures - [x] Add tests for Go inline values - [x] Remove old inline provider code and trait implementations Release Notes: - debugger: Generate inline values based on a language debugger.scm file
This commit is contained in:
parent
800b925fd7
commit
fc1fc264ec
17 changed files with 786 additions and 751 deletions
|
@ -81,3 +81,4 @@ unindent.workspace = true
|
|||
util = { workspace = true, features = ["test-support"] }
|
||||
workspace = { workspace = true, features = ["test-support"] }
|
||||
zlog.workspace = true
|
||||
tree-sitter-go.workspace = true
|
||||
|
|
|
@ -246,10 +246,10 @@ fn main() {
|
|||
editor.update_in(cx, |editor, window, cx| {
|
||||
pretty_assertions::assert_eq!(
|
||||
r#"
|
||||
static mut GLOBAL: 1: usize = 1;
|
||||
static mut GLOBAL: usize = 1;
|
||||
|
||||
fn main() {
|
||||
let x = 10;
|
||||
let x: 10 = 10;
|
||||
let value = 42;
|
||||
let y = 4;
|
||||
let tester = {
|
||||
|
@ -303,11 +303,11 @@ fn main() {
|
|||
editor.update_in(cx, |editor, window, cx| {
|
||||
pretty_assertions::assert_eq!(
|
||||
r#"
|
||||
static mut GLOBAL: 1: usize = 1;
|
||||
static mut GLOBAL: usize = 1;
|
||||
|
||||
fn main() {
|
||||
let x: 10 = 10;
|
||||
let value = 42;
|
||||
let value: 42 = 42;
|
||||
let y = 4;
|
||||
let tester = {
|
||||
let y = 10;
|
||||
|
@ -360,12 +360,12 @@ fn main() {
|
|||
editor.update_in(cx, |editor, window, cx| {
|
||||
pretty_assertions::assert_eq!(
|
||||
r#"
|
||||
static mut GLOBAL: 1: usize = 1;
|
||||
static mut GLOBAL: usize = 1;
|
||||
|
||||
fn main() {
|
||||
let x: 10 = 10;
|
||||
let value: 42 = 42;
|
||||
let y = 4;
|
||||
let y: 4 = 4;
|
||||
let tester = {
|
||||
let y = 10;
|
||||
let y = 5;
|
||||
|
@ -417,7 +417,7 @@ fn main() {
|
|||
editor.update_in(cx, |editor, window, cx| {
|
||||
pretty_assertions::assert_eq!(
|
||||
r#"
|
||||
static mut GLOBAL: 1: usize = 1;
|
||||
static mut GLOBAL: usize = 1;
|
||||
|
||||
fn main() {
|
||||
let x: 10 = 10;
|
||||
|
@ -474,14 +474,14 @@ fn main() {
|
|||
editor.update_in(cx, |editor, window, cx| {
|
||||
pretty_assertions::assert_eq!(
|
||||
r#"
|
||||
static mut GLOBAL: 1: usize = 1;
|
||||
static mut GLOBAL: usize = 1;
|
||||
|
||||
fn main() {
|
||||
let x: 10 = 10;
|
||||
let value: 42 = 42;
|
||||
let y: 4 = 4;
|
||||
let tester = {
|
||||
let y = 10;
|
||||
let y: 4 = 10;
|
||||
let y = 5;
|
||||
let b = 3;
|
||||
vec![y, 20, 30]
|
||||
|
@ -581,15 +581,15 @@ fn main() {
|
|||
editor.update_in(cx, |editor, window, cx| {
|
||||
pretty_assertions::assert_eq!(
|
||||
r#"
|
||||
static mut GLOBAL: 1: usize = 1;
|
||||
static mut GLOBAL: usize = 1;
|
||||
|
||||
fn main() {
|
||||
let x: 10 = 10;
|
||||
let value: 42 = 42;
|
||||
let y = 4;
|
||||
let y: 10 = 4;
|
||||
let tester = {
|
||||
let y: 10 = 10;
|
||||
let y = 5;
|
||||
let y: 10 = 5;
|
||||
let b = 3;
|
||||
vec![y, 20, 30]
|
||||
};
|
||||
|
@ -688,14 +688,14 @@ fn main() {
|
|||
editor.update_in(cx, |editor, window, cx| {
|
||||
pretty_assertions::assert_eq!(
|
||||
r#"
|
||||
static mut GLOBAL: 1: usize = 1;
|
||||
static mut GLOBAL: usize = 1;
|
||||
|
||||
fn main() {
|
||||
let x: 10 = 10;
|
||||
let value: 42 = 42;
|
||||
let y = 4;
|
||||
let y: 5 = 4;
|
||||
let tester = {
|
||||
let y = 10;
|
||||
let y: 5 = 10;
|
||||
let y: 5 = 5;
|
||||
let b = 3;
|
||||
vec![y, 20, 30]
|
||||
|
@ -807,17 +807,17 @@ fn main() {
|
|||
editor.update_in(cx, |editor, window, cx| {
|
||||
pretty_assertions::assert_eq!(
|
||||
r#"
|
||||
static mut GLOBAL: 1: usize = 1;
|
||||
static mut GLOBAL: usize = 1;
|
||||
|
||||
fn main() {
|
||||
let x: 10 = 10;
|
||||
let value: 42 = 42;
|
||||
let y = 4;
|
||||
let y: 5 = 4;
|
||||
let tester = {
|
||||
let y = 10;
|
||||
let y: 5 = 10;
|
||||
let y: 5 = 5;
|
||||
let b: 3 = 3;
|
||||
vec![y, 20, 30]
|
||||
vec![y: 5, 20, 30]
|
||||
};
|
||||
|
||||
let caller = || {
|
||||
|
@ -926,7 +926,7 @@ fn main() {
|
|||
editor.update_in(cx, |editor, window, cx| {
|
||||
pretty_assertions::assert_eq!(
|
||||
r#"
|
||||
static mut GLOBAL: 1: usize = 1;
|
||||
static mut GLOBAL: usize = 1;
|
||||
|
||||
fn main() {
|
||||
let x: 10 = 10;
|
||||
|
@ -1058,7 +1058,7 @@ fn main() {
|
|||
editor.update_in(cx, |editor, window, cx| {
|
||||
pretty_assertions::assert_eq!(
|
||||
r#"
|
||||
static mut GLOBAL: 1: usize = 1;
|
||||
static mut GLOBAL: usize = 1;
|
||||
|
||||
fn main() {
|
||||
let x: 10 = 10;
|
||||
|
@ -1115,21 +1115,21 @@ fn main() {
|
|||
editor.update_in(cx, |editor, window, cx| {
|
||||
pretty_assertions::assert_eq!(
|
||||
r#"
|
||||
static mut GLOBAL: 1: usize = 1;
|
||||
static mut GLOBAL: usize = 1;
|
||||
|
||||
fn main() {
|
||||
let x = 10;
|
||||
let value = 42;
|
||||
let y = 4;
|
||||
let tester = {
|
||||
let x: 10 = 10;
|
||||
let value: 42 = 42;
|
||||
let y: 4 = 4;
|
||||
let tester: size=3 = {
|
||||
let y = 10;
|
||||
let y = 5;
|
||||
let b = 3;
|
||||
vec![y, 20, 30]
|
||||
};
|
||||
|
||||
let caller = || {
|
||||
let x = 3;
|
||||
let caller: <not available> = || {
|
||||
let x: 10 = 3;
|
||||
println!("x={}", x);
|
||||
};
|
||||
|
||||
|
@ -1193,10 +1193,10 @@ fn main() {
|
|||
editor.update_in(cx, |editor, window, cx| {
|
||||
pretty_assertions::assert_eq!(
|
||||
r#"
|
||||
static mut GLOBAL: 1: usize = 1;
|
||||
static mut GLOBAL: usize = 1;
|
||||
|
||||
fn main() {
|
||||
let x = 10;
|
||||
let x: 3 = 10;
|
||||
let value = 42;
|
||||
let y = 4;
|
||||
let tester = {
|
||||
|
@ -1208,7 +1208,7 @@ fn main() {
|
|||
|
||||
let caller = || {
|
||||
let x: 3 = 3;
|
||||
println!("x={}", x);
|
||||
println!("x={}", x: 3);
|
||||
};
|
||||
|
||||
caller();
|
||||
|
@ -1338,7 +1338,7 @@ fn main() {
|
|||
editor.update_in(cx, |editor, window, cx| {
|
||||
pretty_assertions::assert_eq!(
|
||||
r#"
|
||||
static mut GLOBAL: 2: usize = 1;
|
||||
static mut GLOBAL: usize = 1;
|
||||
|
||||
fn main() {
|
||||
let x: 10 = 10;
|
||||
|
@ -1362,7 +1362,7 @@ fn main() {
|
|||
GLOBAL = 2;
|
||||
}
|
||||
|
||||
let result = value * 2 * x;
|
||||
let result = value: 42 * 2 * x: 10;
|
||||
println!("Simple test executed: value={}, result={}", value, result);
|
||||
assert!(true);
|
||||
}
|
||||
|
@ -1483,7 +1483,7 @@ fn main() {
|
|||
editor.update_in(cx, |editor, window, cx| {
|
||||
pretty_assertions::assert_eq!(
|
||||
r#"
|
||||
static mut GLOBAL: 2: usize = 1;
|
||||
static mut GLOBAL: usize = 1;
|
||||
|
||||
fn main() {
|
||||
let x: 10 = 10;
|
||||
|
@ -1507,8 +1507,8 @@ fn main() {
|
|||
GLOBAL = 2;
|
||||
}
|
||||
|
||||
let result: 840 = value * 2 * x;
|
||||
println!("Simple test executed: value={}, result={}", value, result);
|
||||
let result: 840 = value: 42 * 2 * x: 10;
|
||||
println!("Simple test executed: value={}, result={}", value: 42, result: 840);
|
||||
assert!(true);
|
||||
}
|
||||
"#
|
||||
|
@ -1519,6 +1519,7 @@ fn main() {
|
|||
}
|
||||
|
||||
fn rust_lang() -> Language {
|
||||
let debug_variables_query = include_str!("../../../languages/src/rust/debugger.scm");
|
||||
Language::new(
|
||||
LanguageConfig {
|
||||
name: "Rust".into(),
|
||||
|
@ -1530,6 +1531,8 @@ fn rust_lang() -> Language {
|
|||
},
|
||||
Some(tree_sitter_rust::LANGUAGE.into()),
|
||||
)
|
||||
.with_debug_variables_query(debug_variables_query)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
|
@ -1818,8 +1821,8 @@ def process_data(untyped_param, typed_param: int, another_typed: str):
|
|||
def process_data(untyped_param: test_value, typed_param: 42: int, another_typed: world: str):
|
||||
# Local variables
|
||||
x: 10 = 10
|
||||
result: 84 = typed_param * 2
|
||||
text: Hello, world = "Hello, " + another_typed
|
||||
result: 84 = typed_param: 42 * 2
|
||||
text: Hello, world = "Hello, " + another_typed: world
|
||||
|
||||
# For loop with range
|
||||
sum_value: 10 = 0
|
||||
|
@ -1837,6 +1840,7 @@ def process_data(untyped_param, typed_param: int, another_typed: str):
|
|||
}
|
||||
|
||||
fn python_lang() -> Language {
|
||||
let debug_variables_query = include_str!("../../../languages/src/python/debugger.scm");
|
||||
Language::new(
|
||||
LanguageConfig {
|
||||
name: "Python".into(),
|
||||
|
@ -1848,4 +1852,392 @@ fn python_lang() -> Language {
|
|||
},
|
||||
Some(tree_sitter_python::LANGUAGE.into()),
|
||||
)
|
||||
.with_debug_variables_query(debug_variables_query)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn go_lang() -> Language {
|
||||
let debug_variables_query = include_str!("../../../languages/src/go/debugger.scm");
|
||||
Language::new(
|
||||
LanguageConfig {
|
||||
name: "Go".into(),
|
||||
matcher: LanguageMatcher {
|
||||
path_suffixes: vec!["go".to_string()],
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
Some(tree_sitter_go::LANGUAGE.into()),
|
||||
)
|
||||
.with_debug_variables_query(debug_variables_query)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Test utility function for inline values testing
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `variables` - List of tuples containing (variable_name, variable_value)
|
||||
/// * `before` - Source code before inline values are applied
|
||||
/// * `after` - Expected source code after inline values are applied
|
||||
/// * `language` - Language configuration to use for parsing
|
||||
/// * `executor` - Background executor for async operations
|
||||
/// * `cx` - Test app context
|
||||
async fn test_inline_values_util(
|
||||
local_variables: &[(&str, &str)],
|
||||
global_variables: &[(&str, &str)],
|
||||
before: &str,
|
||||
after: &str,
|
||||
active_debug_line: Option<usize>,
|
||||
language: Language,
|
||||
executor: BackgroundExecutor,
|
||||
cx: &mut TestAppContext,
|
||||
) {
|
||||
init_test(cx);
|
||||
|
||||
let lines_count = before.lines().count();
|
||||
let stop_line =
|
||||
active_debug_line.unwrap_or_else(|| if lines_count > 6 { 6 } else { lines_count - 1 });
|
||||
|
||||
let fs = FakeFs::new(executor.clone());
|
||||
fs.insert_tree(path!("/project"), json!({ "main.rs": before.to_string() }))
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
workspace
|
||||
.update(cx, |workspace, window, cx| {
|
||||
workspace.focus_panel::<DebugPanel>(window, cx);
|
||||
})
|
||||
.unwrap();
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let session = start_debug_session(&workspace, cx, |_| {}).unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client.on_request::<dap::requests::Threads, _>(|_, _| {
|
||||
Ok(dap::ThreadsResponse {
|
||||
threads: vec![dap::Thread {
|
||||
id: 1,
|
||||
name: "main".into(),
|
||||
}],
|
||||
})
|
||||
});
|
||||
|
||||
client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
|
||||
Ok(dap::StackTraceResponse {
|
||||
stack_frames: vec![dap::StackFrame {
|
||||
id: 1,
|
||||
name: "main".into(),
|
||||
source: Some(dap::Source {
|
||||
name: Some("main.rs".into()),
|
||||
path: Some(path!("/project/main.rs").into()),
|
||||
source_reference: None,
|
||||
presentation_hint: None,
|
||||
origin: None,
|
||||
sources: None,
|
||||
adapter_data: None,
|
||||
checksums: None,
|
||||
}),
|
||||
line: stop_line as u64,
|
||||
column: 1,
|
||||
end_line: None,
|
||||
end_column: None,
|
||||
can_restart: None,
|
||||
instruction_pointer_reference: None,
|
||||
module_id: None,
|
||||
presentation_hint: None,
|
||||
}],
|
||||
total_frames: None,
|
||||
})
|
||||
});
|
||||
|
||||
let local_vars: Vec<Variable> = local_variables
|
||||
.iter()
|
||||
.map(|(name, value)| Variable {
|
||||
name: (*name).into(),
|
||||
value: (*value).into(),
|
||||
type_: None,
|
||||
presentation_hint: None,
|
||||
evaluate_name: None,
|
||||
variables_reference: 0,
|
||||
named_variables: None,
|
||||
indexed_variables: None,
|
||||
memory_reference: None,
|
||||
declaration_location_reference: None,
|
||||
value_location_reference: None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let global_vars: Vec<Variable> = global_variables
|
||||
.iter()
|
||||
.map(|(name, value)| Variable {
|
||||
name: (*name).into(),
|
||||
value: (*value).into(),
|
||||
type_: None,
|
||||
presentation_hint: None,
|
||||
evaluate_name: None,
|
||||
variables_reference: 0,
|
||||
named_variables: None,
|
||||
indexed_variables: None,
|
||||
memory_reference: None,
|
||||
declaration_location_reference: None,
|
||||
value_location_reference: None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
client.on_request::<Variables, _>({
|
||||
let local_vars = Arc::new(local_vars.clone());
|
||||
let global_vars = Arc::new(global_vars.clone());
|
||||
move |_, args| {
|
||||
let variables = match args.variables_reference {
|
||||
2 => (*local_vars).clone(),
|
||||
3 => (*global_vars).clone(),
|
||||
_ => vec![],
|
||||
};
|
||||
Ok(dap::VariablesResponse { variables })
|
||||
}
|
||||
});
|
||||
|
||||
client.on_request::<dap::requests::Scopes, _>(move |_, _| {
|
||||
Ok(dap::ScopesResponse {
|
||||
scopes: vec![
|
||||
Scope {
|
||||
name: "Local".into(),
|
||||
presentation_hint: None,
|
||||
variables_reference: 2,
|
||||
named_variables: None,
|
||||
indexed_variables: None,
|
||||
expensive: false,
|
||||
source: None,
|
||||
line: None,
|
||||
column: None,
|
||||
end_line: None,
|
||||
end_column: None,
|
||||
},
|
||||
Scope {
|
||||
name: "Global".into(),
|
||||
presentation_hint: None,
|
||||
variables_reference: 3,
|
||||
named_variables: None,
|
||||
indexed_variables: None,
|
||||
expensive: false,
|
||||
source: None,
|
||||
line: None,
|
||||
column: None,
|
||||
end_line: None,
|
||||
end_column: None,
|
||||
},
|
||||
],
|
||||
})
|
||||
});
|
||||
|
||||
if !global_variables.is_empty() {
|
||||
let global_evaluate_map: std::collections::HashMap<String, String> = global_variables
|
||||
.iter()
|
||||
.map(|(name, value)| (name.to_string(), value.to_string()))
|
||||
.collect();
|
||||
|
||||
client.on_request::<dap::requests::Evaluate, _>(move |_, args| {
|
||||
let value = global_evaluate_map
|
||||
.get(&args.expression)
|
||||
.unwrap_or(&"undefined".to_string())
|
||||
.clone();
|
||||
|
||||
Ok(dap::EvaluateResponse {
|
||||
result: value,
|
||||
type_: None,
|
||||
presentation_hint: None,
|
||||
variables_reference: 0,
|
||||
named_variables: None,
|
||||
indexed_variables: None,
|
||||
memory_reference: None,
|
||||
value_location_reference: None,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
client
|
||||
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
|
||||
reason: dap::StoppedEventReason::Pause,
|
||||
description: None,
|
||||
thread_id: Some(1),
|
||||
preserve_focus_hint: None,
|
||||
text: None,
|
||||
all_threads_stopped: None,
|
||||
hit_breakpoint_ids: None,
|
||||
}))
|
||||
.await;
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
let project_path = Path::new(path!("/project"));
|
||||
let worktree = project
|
||||
.update(cx, |project, cx| project.find_worktree(project_path, cx))
|
||||
.expect("This worktree should exist in project")
|
||||
.0;
|
||||
|
||||
let worktree_id = workspace
|
||||
.update(cx, |_, _, cx| worktree.read(cx).id())
|
||||
.unwrap();
|
||||
|
||||
let buffer = project
|
||||
.update(cx, |project, cx| {
|
||||
project.open_buffer((worktree_id, "main.rs"), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
buffer.update(cx, |buffer, cx| {
|
||||
buffer.set_language(Some(Arc::new(language)), cx);
|
||||
});
|
||||
|
||||
let (editor, cx) = cx.add_window_view(|window, cx| {
|
||||
Editor::new(
|
||||
EditorMode::full(),
|
||||
MultiBuffer::build_from_buffer(buffer, cx),
|
||||
Some(project),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
active_debug_session_panel(workspace, cx).update_in(cx, |_, window, cx| {
|
||||
cx.focus_self(window);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
editor.update(cx, |editor, cx| editor.refresh_inline_values(cx));
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
editor.update_in(cx, |editor, window, cx| {
|
||||
pretty_assertions::assert_eq!(after, editor.snapshot(window, cx).text());
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_inline_values_example(executor: BackgroundExecutor, cx: &mut TestAppContext) {
|
||||
let variables = [("x", "10"), ("y", "20"), ("result", "30")];
|
||||
|
||||
let before = r#"
|
||||
fn main() {
|
||||
let x = 10;
|
||||
let y = 20;
|
||||
let result = x + y;
|
||||
println!("Result: {}", result);
|
||||
}
|
||||
"#
|
||||
.unindent();
|
||||
|
||||
let after = r#"
|
||||
fn main() {
|
||||
let x: 10 = 10;
|
||||
let y: 20 = 20;
|
||||
let result: 30 = x: 10 + y: 20;
|
||||
println!("Result: {}", result: 30);
|
||||
}
|
||||
"#
|
||||
.unindent();
|
||||
|
||||
test_inline_values_util(
|
||||
&variables,
|
||||
&[],
|
||||
&before,
|
||||
&after,
|
||||
None,
|
||||
rust_lang(),
|
||||
executor,
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_inline_values_with_globals(executor: BackgroundExecutor, cx: &mut TestAppContext) {
|
||||
let variables = [("x", "5"), ("y", "10")];
|
||||
|
||||
let before = r#"
|
||||
static mut GLOBAL_COUNTER: usize = 42;
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
unsafe {
|
||||
GLOBAL_COUNTER += 1;
|
||||
}
|
||||
println!("x={}, y={}, global={}", x, y, unsafe { GLOBAL_COUNTER });
|
||||
}
|
||||
"#
|
||||
.unindent();
|
||||
|
||||
let after = r#"
|
||||
static mut GLOBAL_COUNTER: 42: usize = 42;
|
||||
|
||||
fn main() {
|
||||
let x: 5 = 5;
|
||||
let y: 10 = 10;
|
||||
unsafe {
|
||||
GLOBAL_COUNTER += 1;
|
||||
}
|
||||
println!("x={}, y={}, global={}", x, y, unsafe { GLOBAL_COUNTER });
|
||||
}
|
||||
"#
|
||||
.unindent();
|
||||
|
||||
test_inline_values_util(
|
||||
&variables,
|
||||
&[("GLOBAL_COUNTER", "42")],
|
||||
&before,
|
||||
&after,
|
||||
None,
|
||||
rust_lang(),
|
||||
executor,
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_go_inline_values(executor: BackgroundExecutor, cx: &mut TestAppContext) {
|
||||
let variables = [("x", "42"), ("y", "hello")];
|
||||
|
||||
let before = r#"
|
||||
package main
|
||||
|
||||
var globalCounter int = 100
|
||||
|
||||
func main() {
|
||||
x := 42
|
||||
y := "hello"
|
||||
z := x + 10
|
||||
println(x, y, z)
|
||||
}
|
||||
"#
|
||||
.unindent();
|
||||
|
||||
let after = r#"
|
||||
package main
|
||||
|
||||
var globalCounter: 100 int = 100
|
||||
|
||||
func main() {
|
||||
x: 42 := 42
|
||||
y := "hello"
|
||||
z := x + 10
|
||||
println(x, y, z)
|
||||
}
|
||||
"#
|
||||
.unindent();
|
||||
|
||||
test_inline_values_util(
|
||||
&variables,
|
||||
&[("globalCounter", "100")],
|
||||
&before,
|
||||
&after,
|
||||
None,
|
||||
go_lang(),
|
||||
executor,
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue