mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-20 02:47:34 +03:00
Merge pull request #799 from zed-industries/debug-project-diagnostics-as-json
Allow dumping the project diagnostic view's state as JSON
This commit is contained in:
commit
aa37c364bb
@ -2,7 +2,7 @@
|
|||||||
"*": {
|
"*": {
|
||||||
"ctrl-alt-cmd-f": "workspace::FollowNextCollaborator",
|
"ctrl-alt-cmd-f": "workspace::FollowNextCollaborator",
|
||||||
"cmd-s": "workspace::Save",
|
"cmd-s": "workspace::Save",
|
||||||
"cmd-alt-i": "workspace::DebugElements",
|
"cmd-alt-i": "zed::DebugElements",
|
||||||
"cmd-k cmd-left": "workspace::ActivatePreviousPane",
|
"cmd-k cmd-left": "workspace::ActivatePreviousPane",
|
||||||
"cmd-k cmd-right": "workspace::ActivateNextPane",
|
"cmd-k cmd-right": "workspace::ActivateNextPane",
|
||||||
"cmd-=": "zed::IncreaseBufferFontSize",
|
"cmd-=": "zed::IncreaseBufferFontSize",
|
||||||
|
@ -8,13 +8,15 @@ use editor::{
|
|||||||
highlight_diagnostic_message, Editor, ExcerptId, MultiBuffer, ToOffset,
|
highlight_diagnostic_message, Editor, ExcerptId, MultiBuffer, ToOffset,
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, elements::*, fonts::TextStyle, AnyViewHandle, AppContext, Entity, ModelHandle,
|
actions, elements::*, fonts::TextStyle, serde_json, AnyViewHandle, AppContext, Entity,
|
||||||
MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle,
|
ModelHandle, MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle,
|
||||||
|
WeakViewHandle,
|
||||||
};
|
};
|
||||||
use language::{
|
use language::{
|
||||||
Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection, SelectionGoal,
|
Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection, SelectionGoal,
|
||||||
};
|
};
|
||||||
use project::{DiagnosticSummary, Project, ProjectPath};
|
use project::{DiagnosticSummary, Project, ProjectPath};
|
||||||
|
use serde_json::json;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use std::{
|
use std::{
|
||||||
any::{Any, TypeId},
|
any::{Any, TypeId},
|
||||||
@ -90,6 +92,31 @@ impl View for ProjectDiagnosticsEditor {
|
|||||||
cx.focus(&self.editor);
|
cx.focus(&self.editor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn debug_json(&self, cx: &AppContext) -> serde_json::Value {
|
||||||
|
let project = self.project.read(cx);
|
||||||
|
json!({
|
||||||
|
"project": json!({
|
||||||
|
"language_servers": project.language_server_statuses().collect::<Vec<_>>(),
|
||||||
|
"summary": project.diagnostic_summary(cx),
|
||||||
|
}),
|
||||||
|
"summary": self.summary,
|
||||||
|
"paths_to_update": self.paths_to_update.iter().map(|path|
|
||||||
|
path.path.to_string_lossy()
|
||||||
|
).collect::<Vec<_>>(),
|
||||||
|
"paths_states": self.path_states.iter().map(|state|
|
||||||
|
json!({
|
||||||
|
"path": state.path.path.to_string_lossy(),
|
||||||
|
"groups": state.diagnostic_groups.iter().map(|group|
|
||||||
|
json!({
|
||||||
|
"block_count": group.blocks.len(),
|
||||||
|
"excerpt_count": group.excerpts.len(),
|
||||||
|
})
|
||||||
|
).collect::<Vec<_>>(),
|
||||||
|
})
|
||||||
|
).collect::<Vec<_>>(),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProjectDiagnosticsEditor {
|
impl ProjectDiagnosticsEditor {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::render_summary;
|
use crate::render_summary;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
elements::*, platform::CursorStyle, Entity, ModelHandle, RenderContext, View, ViewContext,
|
elements::*, platform::CursorStyle, serde_json, Entity, ModelHandle, RenderContext, View,
|
||||||
|
ViewContext,
|
||||||
};
|
};
|
||||||
use project::Project;
|
use project::Project;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
@ -67,6 +68,10 @@ impl View for DiagnosticSummary {
|
|||||||
.on_click(|cx| cx.dispatch_action(crate::Deploy))
|
.on_click(|cx| cx.dispatch_action(crate::Deploy))
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn debug_json(&self, _: &gpui::AppContext) -> serde_json::Value {
|
||||||
|
serde_json::json!({ "summary": self.summary })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StatusItemView for DiagnosticSummary {
|
impl StatusItemView for DiagnosticSummary {
|
||||||
|
@ -1008,7 +1008,7 @@ impl Editor {
|
|||||||
if project.read(cx).is_remote() {
|
if project.read(cx).is_remote() {
|
||||||
cx.propagate_action();
|
cx.propagate_action();
|
||||||
} else if let Some(buffer) = project
|
} else if let Some(buffer) = project
|
||||||
.update(cx, |project, cx| project.create_buffer(cx))
|
.update(cx, |project, cx| project.create_buffer("", None, cx))
|
||||||
.log_err()
|
.log_err()
|
||||||
{
|
{
|
||||||
workspace.add_item(
|
workspace.add_item(
|
||||||
|
@ -62,6 +62,9 @@ pub trait View: Entity + Sized {
|
|||||||
cx.set.insert(Self::ui_name().into());
|
cx.set.insert(Self::ui_name().into());
|
||||||
cx
|
cx
|
||||||
}
|
}
|
||||||
|
fn debug_json(&self, _: &AppContext) -> serde_json::Value {
|
||||||
|
serde_json::Value::Null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ReadModel {
|
pub trait ReadModel {
|
||||||
@ -2277,6 +2280,12 @@ pub struct AppContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AppContext {
|
impl AppContext {
|
||||||
|
pub(crate) fn root_view(&self, window_id: usize) -> Option<AnyViewHandle> {
|
||||||
|
self.windows
|
||||||
|
.get(&window_id)
|
||||||
|
.map(|window| window.root_view.clone())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn root_view_id(&self, window_id: usize) -> Option<usize> {
|
pub fn root_view_id(&self, window_id: usize) -> Option<usize> {
|
||||||
self.windows
|
self.windows
|
||||||
.get(&window_id)
|
.get(&window_id)
|
||||||
@ -2590,6 +2599,7 @@ pub trait AnyView {
|
|||||||
fn on_focus(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize);
|
fn on_focus(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize);
|
||||||
fn on_blur(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize);
|
fn on_blur(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize);
|
||||||
fn keymap_context(&self, cx: &AppContext) -> keymap::Context;
|
fn keymap_context(&self, cx: &AppContext) -> keymap::Context;
|
||||||
|
fn debug_json(&self, cx: &AppContext) -> serde_json::Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AnyView for T
|
impl<T> AnyView for T
|
||||||
@ -2653,6 +2663,10 @@ where
|
|||||||
fn keymap_context(&self, cx: &AppContext) -> keymap::Context {
|
fn keymap_context(&self, cx: &AppContext) -> keymap::Context {
|
||||||
View::keymap_context(self, cx)
|
View::keymap_context(self, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn debug_json(&self, cx: &AppContext) -> serde_json::Value {
|
||||||
|
View::debug_json(self, cx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ModelContext<'a, T: ?Sized> {
|
pub struct ModelContext<'a, T: ?Sized> {
|
||||||
@ -3927,6 +3941,12 @@ impl AnyViewHandle {
|
|||||||
pub fn view_type(&self) -> TypeId {
|
pub fn view_type(&self) -> TypeId {
|
||||||
self.view_type
|
self.view_type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn debug_json(&self, cx: &AppContext) -> serde_json::Value {
|
||||||
|
cx.views
|
||||||
|
.get(&(self.window_id, self.view_id))
|
||||||
|
.map_or_else(|| serde_json::Value::Null, |view| view.debug_json(cx))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for AnyViewHandle {
|
impl Clone for AnyViewHandle {
|
||||||
|
@ -209,15 +209,18 @@ impl Presenter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_elements(&self, cx: &AppContext) -> Option<json::Value> {
|
pub fn debug_elements(&self, cx: &AppContext) -> Option<json::Value> {
|
||||||
cx.root_view_id(self.window_id)
|
let view = cx.root_view(self.window_id)?;
|
||||||
.and_then(|root_view_id| self.rendered_views.get(&root_view_id))
|
Some(json!({
|
||||||
.map(|root_element| {
|
"root_view": view.debug_json(cx),
|
||||||
root_element.debug(&DebugContext {
|
"root_element": self.rendered_views.get(&view.id())
|
||||||
rendered_views: &self.rendered_views,
|
.map(|root_element| {
|
||||||
font_cache: &self.font_cache,
|
root_element.debug(&DebugContext {
|
||||||
app: cx,
|
rendered_views: &self.rendered_views,
|
||||||
|
font_cache: &self.font_cache,
|
||||||
|
app: cx,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -554,6 +557,7 @@ impl Element for ChildView {
|
|||||||
"type": "ChildView",
|
"type": "ChildView",
|
||||||
"view_id": self.view.id(),
|
"view_id": self.view.id(),
|
||||||
"bounds": bounds.to_json(),
|
"bounds": bounds.to_json(),
|
||||||
|
"view": self.view.debug_json(cx.app),
|
||||||
"child": if let Some(view) = cx.rendered_views.get(&self.view.id()) {
|
"child": if let Some(view) = cx.rendered_views.get(&self.view.id()) {
|
||||||
view.debug(cx)
|
view.debug(cx)
|
||||||
} else {
|
} else {
|
||||||
|
@ -28,6 +28,7 @@ use parking_lot::Mutex;
|
|||||||
use postage::watch;
|
use postage::watch;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use search::SearchQuery;
|
use search::SearchQuery;
|
||||||
|
use serde::Serialize;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use similar::{ChangeTag, TextDiff};
|
use similar::{ChangeTag, TextDiff};
|
||||||
@ -132,16 +133,18 @@ pub enum Event {
|
|||||||
CollaboratorLeft(PeerId),
|
CollaboratorLeft(PeerId),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
pub struct LanguageServerStatus {
|
pub struct LanguageServerStatus {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub pending_work: BTreeMap<String, LanguageServerProgress>,
|
pub pending_work: BTreeMap<String, LanguageServerProgress>,
|
||||||
pending_diagnostic_updates: isize,
|
pub pending_diagnostic_updates: isize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
pub struct LanguageServerProgress {
|
pub struct LanguageServerProgress {
|
||||||
pub message: Option<String>,
|
pub message: Option<String>,
|
||||||
pub percentage: Option<usize>,
|
pub percentage: Option<usize>,
|
||||||
|
#[serde(skip_serializing)]
|
||||||
pub last_update_at: Instant,
|
pub last_update_at: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +154,7 @@ pub struct ProjectPath {
|
|||||||
pub path: Arc<Path>,
|
pub path: Arc<Path>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
|
||||||
pub struct DiagnosticSummary {
|
pub struct DiagnosticSummary {
|
||||||
pub error_count: usize,
|
pub error_count: usize,
|
||||||
pub warning_count: usize,
|
pub warning_count: usize,
|
||||||
@ -467,7 +470,6 @@ impl Project {
|
|||||||
.and_then(|buffer| buffer.upgrade(cx))
|
.and_then(|buffer| buffer.upgrade(cx))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
|
||||||
pub fn languages(&self) -> &Arc<LanguageRegistry> {
|
pub fn languages(&self) -> &Arc<LanguageRegistry> {
|
||||||
&self.languages
|
&self.languages
|
||||||
}
|
}
|
||||||
@ -813,13 +815,19 @@ impl Project {
|
|||||||
!self.is_local()
|
!self.is_local()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_buffer(&mut self, cx: &mut ModelContext<Self>) -> Result<ModelHandle<Buffer>> {
|
pub fn create_buffer(
|
||||||
|
&mut self,
|
||||||
|
text: &str,
|
||||||
|
language: Option<Arc<Language>>,
|
||||||
|
cx: &mut ModelContext<Self>,
|
||||||
|
) -> Result<ModelHandle<Buffer>> {
|
||||||
if self.is_remote() {
|
if self.is_remote() {
|
||||||
return Err(anyhow!("creating buffers as a guest is not supported yet"));
|
return Err(anyhow!("creating buffers as a guest is not supported yet"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer = cx.add_model(|cx| {
|
let buffer = cx.add_model(|cx| {
|
||||||
Buffer::new(self.replica_id(), "", cx).with_language(language::PLAIN_TEXT.clone(), cx)
|
Buffer::new(self.replica_id(), text, cx)
|
||||||
|
.with_language(language.unwrap_or(language::PLAIN_TEXT.clone()), cx)
|
||||||
});
|
});
|
||||||
self.register_buffer(&buffer, cx)?;
|
self.register_buffer(&buffer, cx)?;
|
||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
@ -6581,7 +6589,9 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let worktree_id = worktree.read_with(cx, |worktree, _| worktree.id());
|
let worktree_id = worktree.read_with(cx, |worktree, _| worktree.id());
|
||||||
|
|
||||||
let buffer = project.update(cx, |project, cx| project.create_buffer(cx).unwrap());
|
let buffer = project.update(cx, |project, cx| {
|
||||||
|
project.create_buffer("", None, cx).unwrap()
|
||||||
|
});
|
||||||
buffer.update(cx, |buffer, cx| {
|
buffer.update(cx, |buffer, cx| {
|
||||||
buffer.edit([0..0], "abc", cx);
|
buffer.edit([0..0], "abc", cx);
|
||||||
assert!(buffer.is_dirty());
|
assert!(buffer.is_dirty());
|
||||||
|
@ -18,11 +18,11 @@ use gpui::{
|
|||||||
elements::*,
|
elements::*,
|
||||||
geometry::{rect::RectF, vector::vec2f, PathBuilder},
|
geometry::{rect::RectF, vector::vec2f, PathBuilder},
|
||||||
impl_internal_actions,
|
impl_internal_actions,
|
||||||
json::{self, to_string_pretty, ToJson},
|
json::{self, ToJson},
|
||||||
platform::{CursorStyle, WindowOptions},
|
platform::{CursorStyle, WindowOptions},
|
||||||
AnyModelHandle, AnyViewHandle, AppContext, AsyncAppContext, Border, ClipboardItem, Entity,
|
AnyModelHandle, AnyViewHandle, AppContext, AsyncAppContext, Border, Entity, ImageData,
|
||||||
ImageData, ModelHandle, MutableAppContext, PathPromptOptions, PromptLevel, RenderContext, Task,
|
ModelHandle, MutableAppContext, PathPromptOptions, PromptLevel, RenderContext, Task, View,
|
||||||
View, ViewContext, ViewHandle, WeakViewHandle,
|
ViewContext, ViewHandle, WeakViewHandle,
|
||||||
};
|
};
|
||||||
use language::LanguageRegistry;
|
use language::LanguageRegistry;
|
||||||
use log::error;
|
use log::error;
|
||||||
@ -75,7 +75,6 @@ actions!(
|
|||||||
ToggleShare,
|
ToggleShare,
|
||||||
Unfollow,
|
Unfollow,
|
||||||
Save,
|
Save,
|
||||||
DebugElements,
|
|
||||||
ActivatePreviousPane,
|
ActivatePreviousPane,
|
||||||
ActivateNextPane,
|
ActivateNextPane,
|
||||||
FollowNextCollaborator,
|
FollowNextCollaborator,
|
||||||
@ -133,7 +132,6 @@ pub fn init(client: &Arc<Client>, cx: &mut MutableAppContext) {
|
|||||||
workspace.save_active_item(cx).detach_and_log_err(cx);
|
workspace.save_active_item(cx).detach_and_log_err(cx);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
cx.add_action(Workspace::debug_elements);
|
|
||||||
cx.add_action(Workspace::toggle_sidebar_item);
|
cx.add_action(Workspace::toggle_sidebar_item);
|
||||||
cx.add_action(Workspace::toggle_sidebar_item_focus);
|
cx.add_action(Workspace::toggle_sidebar_item_focus);
|
||||||
cx.add_action(|workspace: &mut Workspace, _: &ActivatePreviousPane, cx| {
|
cx.add_action(|workspace: &mut Workspace, _: &ActivatePreviousPane, cx| {
|
||||||
@ -1053,22 +1051,6 @@ impl Workspace {
|
|||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_elements(&mut self, _: &DebugElements, cx: &mut ViewContext<Self>) {
|
|
||||||
match to_string_pretty(&cx.debug_elements()) {
|
|
||||||
Ok(json) => {
|
|
||||||
let kib = json.len() as f32 / 1024.;
|
|
||||||
cx.as_mut().write_to_clipboard(ClipboardItem::new(json));
|
|
||||||
log::info!(
|
|
||||||
"copied {:.1} KiB of element debug JSON to the clipboard",
|
|
||||||
kib
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
log::error!("error debugging elements: {}", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_pane(&mut self, cx: &mut ViewContext<Self>) -> ViewHandle<Pane> {
|
fn add_pane(&mut self, cx: &mut ViewContext<Self>) -> ViewHandle<Pane> {
|
||||||
let pane = cx.add_view(|cx| Pane::new(cx));
|
let pane = cx.add_view(|cx| Pane::new(cx));
|
||||||
let pane_id = pane.id();
|
let pane_id = pane.id();
|
||||||
|
@ -10,6 +10,7 @@ pub use client;
|
|||||||
pub use contacts_panel;
|
pub use contacts_panel;
|
||||||
use contacts_panel::ContactsPanel;
|
use contacts_panel::ContactsPanel;
|
||||||
pub use editor;
|
pub use editor;
|
||||||
|
use editor::Editor;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions,
|
actions,
|
||||||
geometry::vector::vec2f,
|
geometry::vector::vec2f,
|
||||||
@ -22,8 +23,10 @@ use project::Project;
|
|||||||
pub use project::{self, fs};
|
pub use project::{self, fs};
|
||||||
use project_panel::ProjectPanel;
|
use project_panel::ProjectPanel;
|
||||||
use search::{BufferSearchBar, ProjectSearchBar};
|
use search::{BufferSearchBar, ProjectSearchBar};
|
||||||
|
use serde_json::to_string_pretty;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use std::{path::PathBuf, sync::Arc};
|
use std::{path::PathBuf, sync::Arc};
|
||||||
|
use util::ResultExt;
|
||||||
pub use workspace;
|
pub use workspace;
|
||||||
use workspace::{AppState, Workspace, WorkspaceParams};
|
use workspace::{AppState, Workspace, WorkspaceParams};
|
||||||
|
|
||||||
@ -32,6 +35,7 @@ actions!(
|
|||||||
[
|
[
|
||||||
About,
|
About,
|
||||||
Quit,
|
Quit,
|
||||||
|
DebugElements,
|
||||||
OpenSettings,
|
OpenSettings,
|
||||||
IncreaseBufferFontSize,
|
IncreaseBufferFontSize,
|
||||||
DecreaseBufferFontSize
|
DecreaseBufferFontSize
|
||||||
@ -100,6 +104,28 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
|
|||||||
.detach_and_log_err(cx);
|
.detach_and_log_err(cx);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
cx.add_action(
|
||||||
|
|workspace: &mut Workspace, _: &DebugElements, cx: &mut ViewContext<Workspace>| {
|
||||||
|
let content = to_string_pretty(&cx.debug_elements()).unwrap();
|
||||||
|
let project = workspace.project().clone();
|
||||||
|
let json_language = project.read(cx).languages().get_language("JSON").unwrap();
|
||||||
|
if project.read(cx).is_remote() {
|
||||||
|
cx.propagate_action();
|
||||||
|
} else if let Some(buffer) = project
|
||||||
|
.update(cx, |project, cx| {
|
||||||
|
project.create_buffer(&content, Some(json_language), cx)
|
||||||
|
})
|
||||||
|
.log_err()
|
||||||
|
{
|
||||||
|
workspace.add_item(
|
||||||
|
Box::new(
|
||||||
|
cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)),
|
||||||
|
),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
workspace::lsp_status::init(cx);
|
workspace::lsp_status::init(cx);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user