Skip to content
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

Breakpoints #7

Merged
merged 31 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
92b9385
Add support for DAP to use std for communication
Anthony-Eid Jul 14, 2024
3e1aa65
Add more descriptive error logs for DAP
Anthony-Eid Jul 14, 2024
73ef771
Implement handler for continued event
Anthony-Eid Jul 15, 2024
8d7ec33
Add PR feedback to handle_continued_event function
Anthony-Eid Jul 15, 2024
18cb542
Merge branch 'remco-debugger' into debugger
Anthony-Eid Jul 16, 2024
7c9771b
Updated debugger
Anthony-Eid Jul 18, 2024
9bc1d4a
Merge branch 'remco-debugger' into debugger
Anthony-Eid Jul 23, 2024
15d5186
Fix race condition when using late case debug adapters
Anthony-Eid Jul 23, 2024
0b8c4de
Get clippy to run successfully
Anthony-Eid Jul 23, 2024
780bfaf
Add some function docs to dap client
Anthony-Eid Jul 23, 2024
96d3f13
Merge branch 'remco-debugger' into debugger
Anthony-Eid Jul 25, 2024
c7f7d18
Fix debugger's highlight when stepping through code
Anthony-Eid Jul 25, 2024
7f1bd3b
Get clippy to pass & add an error log instead of using dbg!()
Anthony-Eid Jul 25, 2024
a136b72
Merge branch 'main' into debugger
Anthony-Eid Jul 25, 2024
0975ca8
Get sequence id to be incremented after getting respond and event
Anthony-Eid Jul 25, 2024
8b05b88
Merge branch 'main' into debugger
RemcoSmitsDev Jul 25, 2024
9c2b909
Merge branch 'remco-debugger' into debugger
Anthony-Eid Jul 25, 2024
61533d7
Merge branch 'remco-debugger' into debugger
Anthony-Eid Jul 25, 2024
916150a
Get breakpoints to use anchors instead
Anthony-Eid Jul 25, 2024
f0a5775
Fix toggle breakpoints having a max of one bp per buffer
Anthony-Eid Jul 25, 2024
4373e47
Get Editor & Project to share breakpoints through RWLock
Anthony-Eid Jul 27, 2024
c39c0a5
Have project share breakpoints pointer with editor
Anthony-Eid Jul 27, 2024
08dbf36
Start work on getting breakpoint indicator to show in gutter
Anthony-Eid Jul 27, 2024
4bb8ec9
Get gutter breakpoint hint to display at correct point and set breakp…
Anthony-Eid Jul 27, 2024
12c853e
Merge branch 'remco-debugger' into breakpoints
Anthony-Eid Jul 27, 2024
a545400
Set up breakpoint toggle to send breakpoints to dap when necessary
Anthony-Eid Jul 28, 2024
4c5deb0
Finalize refactoring breakpoints to use RWLocks
Anthony-Eid Jul 28, 2024
d222fbe
Fix breakpoint indicator lagging behind mouse in gutter
Anthony-Eid Jul 29, 2024
620e654
Fix crash that can happen after placing breakpoint in file and changi…
Anthony-Eid Jul 29, 2024
655b23c
Get clippy to pass
Anthony-Eid Jul 29, 2024
d6dd59c
Merge with debugger branch
Anthony-Eid Jul 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .zed/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,10 @@
"label": "clippy",
"command": "./script/clippy",
"args": []
},
{
"label": "Run Zed Tests",
"command": "cargo nextest run --workspace --no-fail-fast",
"args": []
}
]
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions crates/dap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ async-std = "1.12.0"
dap-types = { git = "https://github.com/zed-industries/dap-types" }
futures.workspace = true
gpui.workspace = true
multi_buffer.workspace = true
language.workspace = true
log.workspace = true
parking_lot.workspace = true
postage.workspace = true
Expand All @@ -24,4 +26,5 @@ serde_json.workspace = true
serde_json_lenient.workspace = true
smol.workspace = true
task.workspace = true
text.workspace = true
util.workspace = true
36 changes: 29 additions & 7 deletions crates/dap/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use dap_types::{
};
use futures::{AsyncBufRead, AsyncReadExt, AsyncWrite};
use gpui::{AppContext, AsyncAppContext};
use language::Buffer;
use parking_lot::{Mutex, MutexGuard};
use serde_json::Value;
use smol::{
Expand All @@ -35,6 +36,7 @@ use std::{
time::Duration,
};
use task::{DebugAdapterConfig, DebugConnectionType, DebugRequestType, TCPHost};
use text::Point;
use util::ResultExt;

#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
Expand Down Expand Up @@ -331,7 +333,9 @@ impl DebugAdapterClient {
{
while let Ok(payload) = client_rx.recv().await {
match payload {
Payload::Event(event) => cx.update(|cx| event_handler(*event, cx))?,
Payload::Event(event) => cx
.update(|cx| event_handler(*event, cx))
.context("Event handler failed")?,
Payload::Request(request) => {
if RunInTerminal::COMMAND == request.command {
Self::handle_run_in_terminal_request(request, &server_tx).await?;
Expand Down Expand Up @@ -395,8 +399,7 @@ impl DebugAdapterClient {
request: crate::transport::Request,
cx: &mut AsyncAppContext,
) -> Result<()> {
dbg!(&request);
let arguments: StartDebuggingRequestArguments =
let _arguments: StartDebuggingRequestArguments =
serde_json::from_value(request.arguments.clone().unwrap_or_default())?;

let sub_client = DebugAdapterClient::new(
Expand All @@ -416,10 +419,7 @@ impl DebugAdapterClient {
)
.await?;

dbg!(&arguments);

let res = sub_client.launch(request.arguments).await?;
dbg!(res);
let _res = sub_client.launch(request.arguments).await?;

*this.sub_client.lock() = Some(sub_client);

Expand Down Expand Up @@ -455,6 +455,7 @@ impl DebugAdapterClient {
self.server_tx.send(Payload::Request(request)).await?;

let response = callback_rx.recv().await??;
let _ = self.next_sequence_id();

match response.success {
true => Ok(serde_json::from_value(response.body.unwrap_or_default())?),
Expand Down Expand Up @@ -644,3 +645,24 @@ impl DebugAdapterClient {
.await
}
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Breakpoint {
pub position: multi_buffer::Anchor,
}

impl Breakpoint {
pub fn to_source_breakpoint(&self, buffer: &Buffer) -> SourceBreakpoint {
SourceBreakpoint {
line: (buffer
.summary_for_anchor::<Point>(&self.position.text_anchor)
.row
+ 1) as u64,
condition: None,
hit_condition: None,
log_message: None,
column: None,
mode: None,
}
}
}
3 changes: 3 additions & 0 deletions crates/debugger_ui/src/debugger_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ impl DebugPanel {
event: &Events,
cx: &mut ViewContext<Self>,
) {
// Increment the sequence id because an event is being processed
let _ = client.next_sequence_id();

match event {
Events::Initialized(event) => Self::handle_initialized_event(client, event, cx),
Events::Stopped(event) => Self::handle_stopped_event(client, event, cx),
Expand Down
1 change: 1 addition & 0 deletions crates/editor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ clock.workspace = true
collections.workspace = true
convert_case = "0.6.0"
db.workspace = true
dap.workspace = true
emojis.workspace = true
file_icons.workspace = true
futures.workspace = true
Expand Down
84 changes: 61 additions & 23 deletions crates/editor/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ use language::{point_to_lsp, BufferRow, Runnable, RunnableRange};
use linked_editing_ranges::refresh_linked_ranges;
use task::{ResolvedTask, TaskTemplate, TaskVariables};

use dap::client::Breakpoint;
use hover_links::{HoverLink, HoveredLinkState, InlayHighlight};
pub use lsp::CompletionContext;
use lsp::{
Expand Down Expand Up @@ -450,12 +451,6 @@ struct ResolvedTasks {
position: Anchor,
}

#[derive(Clone, Debug)]
struct Breakpoint {
row: MultiBufferRow,
_line: BufferRow,
}

#[derive(Copy, Clone, Debug)]
struct MultiBufferOffset(usize);
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
Expand Down Expand Up @@ -575,7 +570,13 @@ pub struct Editor {
expect_bounds_change: Option<Bounds<Pixels>>,
tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
tasks_update_task: Option<Task<()>>,
breakpoints: BTreeMap<(BufferId, BufferRow), Breakpoint>,
/// All the breakpoints that are active within a project
/// Is shared with editor's active project
breakpoints: Option<Arc<RwLock<BTreeMap<BufferId, HashSet<Breakpoint>>>>>,
/// Allow's a user to create a breakpoint by selecting this indicator
/// It should be None while a user is not hovering over the gutter
/// Otherwise it represents the point that the breakpoint will be shown
pub gutter_breakpoint_indicator: Option<DisplayPoint>,
previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
file_header_size: u8,
breadcrumb_header: Option<String>,
Expand Down Expand Up @@ -1789,6 +1790,12 @@ impl Editor {
None
};

let breakpoints = if let Some(project) = project.as_ref() {
Some(project.update(cx, |project, _cx| project.breakpoints.clone()))
} else {
None
};

let mut this = Self {
focus_handle,
show_cursor_when_unfocused: false,
Expand Down Expand Up @@ -1891,7 +1898,8 @@ impl Editor {
blame_subscription: None,
file_header_size,
tasks: Default::default(),
breakpoints: Default::default(),
breakpoints,
gutter_breakpoint_indicator: None,
_subscriptions: vec![
cx.observe(&buffer, Self::on_buffer_changed),
cx.subscribe(&buffer, Self::on_buffer_event),
Expand Down Expand Up @@ -5141,14 +5149,19 @@ impl Editor {
}
}

fn render_breakpoint(&self, row: DisplayRow, cx: &mut ViewContext<Self>) -> IconButton {
fn render_breakpoint(
&self,
position: Anchor,
row: DisplayRow,
cx: &mut ViewContext<Self>,
) -> IconButton {
IconButton::new(("breakpoint_indicator", row.0 as usize), ui::IconName::Play)
.icon_size(IconSize::XSmall)
.size(ui::ButtonSize::None)
.icon_color(Color::Error)
.on_click(cx.listener(move |editor, _e, cx| {
editor.focus(cx);
editor.toggle_breakpoint_at_row(row.0, cx) //TODO handle folded
editor.toggle_breakpoint_at_row(position, cx) //TODO handle folded
}))
}

Expand Down Expand Up @@ -5972,33 +5985,58 @@ impl Editor {

pub fn toggle_breakpoint(&mut self, _: &ToggleBreakpoint, cx: &mut ViewContext<Self>) {
let cursor_position: Point = self.selections.newest(cx).head();
self.toggle_breakpoint_at_row(cursor_position.row, cx);

let breakpoint_position = self
.snapshot(cx)
.display_snapshot
.buffer_snapshot
.anchor_before(cursor_position);

self.toggle_breakpoint_at_row(breakpoint_position, cx);
}

pub fn toggle_breakpoint_at_row(&mut self, row: u32, cx: &mut ViewContext<Self>) {
pub fn toggle_breakpoint_at_row(
&mut self,
breakpoint_position: Anchor,
cx: &mut ViewContext<Self>,
) {
let Some(project) = &self.project else {
return;
};

let Some(breakpoints) = &self.breakpoints else {
return;
};

let Some(buffer) = self.buffer.read(cx).as_singleton() else {
return;
};

let buffer_id = buffer.read(cx).remote_id();
let key = (buffer_id, row);

if self.breakpoints.remove(&key).is_none() {
self.breakpoints.insert(
key,
Breakpoint {
row: MultiBufferRow(row),
_line: row,
},
);

let breakpoint = Breakpoint {
position: breakpoint_position,
};

// Putting the write guard within it's own scope so it's dropped
// before project updates it's breakpoints. This is done to prevent
// a data race condition where project waits to get a read lock
{
let mut write_guard = breakpoints.write();

let breakpoint_set = write_guard.entry(buffer_id).or_default();

if !breakpoint_set.remove(&breakpoint) {
breakpoint_set.insert(breakpoint);
}
}

project.update(cx, |project, cx| {
project.update_breakpoint(buffer, row + 1, cx);
if project.has_active_debugger() {
project.update_file_breakpoints(buffer_id, cx);
}
});

cx.notify();
}

Expand Down
Loading
Loading