Move debug_elements to AsyncAppContext

Previously, `debug_elements` was available on `WindowContext`. If that
method was called while having a borrow out to a view, it would panic because
the view would already have been borrowed.

By moving it to an `AsyncAppContext` we ensure the method can't be called while
a view is being used.
This commit is contained in:
Antonio Scandurra 2023-05-02 11:03:01 +02:00
parent 4c1cba6def
commit 794446bf8b
4 changed files with 23 additions and 20 deletions

View File

@ -43,6 +43,7 @@ use window_input_handler::WindowInputHandler;
use crate::{
elements::{AnyElement, AnyRootElement, RootElement},
executor::{self, Task},
json,
keymap_matcher::{self, Binding, KeymapContext, KeymapMatcher, Keystroke, MatchResult},
platform::{
self, FontSystem, KeyDownEvent, KeyUpEvent, ModifiersChangedEvent, MouseButton,
@ -309,6 +310,14 @@ impl AsyncAppContext {
self.0.borrow_mut().update_window(window_id, callback)
}
pub fn debug_elements(&self, window_id: usize) -> Option<json::Value> {
self.0.borrow().read_window(window_id, |cx| {
let root_view = cx.window.root_view();
let root_element = cx.window.rendered_views.get(&root_view.id())?;
root_element.debug(cx).log_err()
})?
}
pub fn dispatch_action(
&mut self,
window_id: usize,

View File

@ -1,7 +1,7 @@
use crate::{
elements::AnyRootElement,
geometry::rect::RectF,
json::{self, ToJson},
json::ToJson,
keymap_matcher::{Binding, Keystroke, MatchResult},
platform::{
self, Appearance, CursorStyle, Event, KeyDownEvent, KeyUpEvent, ModifiersChangedEvent,
@ -975,17 +975,6 @@ impl<'a> WindowContext<'a> {
.flatten()
}
pub fn debug_elements(&self) -> Option<json::Value> {
let view = self.window.root_view();
Some(json!({
"root_view": view.debug_json(self),
"root_element": self.window.rendered_views.get(&view.id())
.and_then(|root_element| {
root_element.debug(self).log_err()
})
}))
}
pub fn set_window_title(&mut self, title: &str) {
self.window.platform_window.set_title(title);
}
@ -1454,13 +1443,7 @@ impl<V: View> Element<V> for ChildView {
) -> serde_json::Value {
json!({
"type": "ChildView",
"view_id": self.view_id,
"bounds": bounds.to_json(),
"view": if let Some(view) = cx.views.get(&(cx.window_id, self.view_id)) {
view.debug_json(cx)
} else {
json!(null)
},
"child": if let Some(element) = cx.window.rendered_views.get(&self.view_id) {
element.debug(&cx.window_context).log_err().unwrap_or_else(|| json!(null))
} else {

View File

@ -708,7 +708,12 @@ impl<V: View> AnyRootElement for RootElement<V> {
.ok_or_else(|| anyhow!("debug called on a root element for a dropped view"))?;
let view = view.read(cx);
let view_context = ViewContext::immutable(cx, self.view.id());
Ok(self.element.debug(view, &view_context))
Ok(serde_json::json!({
"view_id": self.view.id(),
"view_name": V::ui_name(),
"view": view.debug_json(cx),
"element": self.element.debug(view, &view_context)
}))
}
fn name(&self) -> Option<&str> {

View File

@ -11,6 +11,7 @@ use collections::VecDeque;
pub use editor;
use editor::{Editor, MultiBuffer};
use anyhow::anyhow;
use feedback::{
feedback_info_text::FeedbackInfoText, submit_feedback_button::SubmitFeedbackButton,
};
@ -215,9 +216,14 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::AppContext) {
move |workspace: &mut Workspace, _: &DebugElements, cx: &mut ViewContext<Workspace>| {
let app_state = workspace.app_state().clone();
let markdown = app_state.languages.language_for_name("JSON");
let content = to_string_pretty(&cx.debug_elements()).unwrap();
let window_id = cx.window_id();
cx.spawn(|workspace, mut cx| async move {
let markdown = markdown.await.log_err();
let content = to_string_pretty(
&cx.debug_elements(window_id)
.ok_or_else(|| anyhow!("could not debug elements for {window_id}"))?,
)
.unwrap();
workspace
.update(&mut cx, |workspace, cx| {
workspace.with_local_workspace(cx, move |workspace, cx| {