Detailed changes
@@ -2,7 +2,7 @@
"*": {
"ctrl-alt-cmd-f": "workspace::FollowNextCollaborator",
"cmd-s": "workspace::Save",
- "cmd-alt-i": "workspace::DebugElements",
+ "cmd-alt-i": "zed::DebugElements",
"cmd-k cmd-left": "workspace::ActivatePreviousPane",
"cmd-k cmd-right": "workspace::ActivateNextPane",
"cmd-=": "zed::IncreaseBufferFontSize",
@@ -8,13 +8,15 @@ use editor::{
highlight_diagnostic_message, Editor, ExcerptId, MultiBuffer, ToOffset,
};
use gpui::{
- actions, elements::*, fonts::TextStyle, AnyViewHandle, AppContext, Entity, ModelHandle,
- MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle,
+ actions, elements::*, fonts::TextStyle, serde_json, AnyViewHandle, AppContext, Entity,
+ ModelHandle, MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle,
+ WeakViewHandle,
};
use language::{
Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection, SelectionGoal,
};
use project::{DiagnosticSummary, Project, ProjectPath};
+use serde_json::json;
use settings::Settings;
use std::{
any::{Any, TypeId},
@@ -90,6 +92,31 @@ impl View for ProjectDiagnosticsEditor {
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 {
@@ -1,6 +1,7 @@
use crate::render_summary;
use gpui::{
- elements::*, platform::CursorStyle, Entity, ModelHandle, RenderContext, View, ViewContext,
+ elements::*, platform::CursorStyle, serde_json, Entity, ModelHandle, RenderContext, View,
+ ViewContext,
};
use project::Project;
use settings::Settings;
@@ -67,6 +68,10 @@ impl View for DiagnosticSummary {
.on_click(|cx| cx.dispatch_action(crate::Deploy))
.boxed()
}
+
+ fn debug_json(&self, _: &gpui::AppContext) -> serde_json::Value {
+ serde_json::json!({ "summary": self.summary })
+ }
}
impl StatusItemView for DiagnosticSummary {
@@ -1008,7 +1008,7 @@ impl Editor {
if project.read(cx).is_remote() {
cx.propagate_action();
} 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()
{
workspace.add_item(
@@ -62,6 +62,9 @@ pub trait View: Entity + Sized {
cx.set.insert(Self::ui_name().into());
cx
}
+ fn debug_json(&self, _: &AppContext) -> serde_json::Value {
+ serde_json::Value::Null
+ }
}
pub trait ReadModel {
@@ -2277,6 +2280,12 @@ pub struct 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> {
self.windows
.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_blur(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize);
fn keymap_context(&self, cx: &AppContext) -> keymap::Context;
+ fn debug_json(&self, cx: &AppContext) -> serde_json::Value;
}
impl<T> AnyView for T
@@ -2653,6 +2663,10 @@ where
fn keymap_context(&self, cx: &AppContext) -> keymap::Context {
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> {
@@ -3927,6 +3941,12 @@ impl AnyViewHandle {
pub fn view_type(&self) -> TypeId {
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 {
@@ -209,15 +209,18 @@ impl Presenter {
}
pub fn debug_elements(&self, cx: &AppContext) -> Option<json::Value> {
- cx.root_view_id(self.window_id)
- .and_then(|root_view_id| self.rendered_views.get(&root_view_id))
- .map(|root_element| {
- root_element.debug(&DebugContext {
- rendered_views: &self.rendered_views,
- font_cache: &self.font_cache,
- app: cx,
+ let view = cx.root_view(self.window_id)?;
+ Some(json!({
+ "root_view": view.debug_json(cx),
+ "root_element": self.rendered_views.get(&view.id())
+ .map(|root_element| {
+ root_element.debug(&DebugContext {
+ rendered_views: &self.rendered_views,
+ font_cache: &self.font_cache,
+ app: cx,
+ })
})
- })
+ }))
}
}
@@ -554,6 +557,7 @@ impl Element for ChildView {
"type": "ChildView",
"view_id": self.view.id(),
"bounds": bounds.to_json(),
+ "view": self.view.debug_json(cx.app),
"child": if let Some(view) = cx.rendered_views.get(&self.view.id()) {
view.debug(cx)
} else {
@@ -28,6 +28,7 @@ use parking_lot::Mutex;
use postage::watch;
use rand::prelude::*;
use search::SearchQuery;
+use serde::Serialize;
use settings::Settings;
use sha2::{Digest, Sha256};
use similar::{ChangeTag, TextDiff};
@@ -132,16 +133,18 @@ pub enum Event {
CollaboratorLeft(PeerId),
}
+#[derive(Serialize)]
pub struct LanguageServerStatus {
pub name: String,
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 message: Option<String>,
pub percentage: Option<usize>,
+ #[serde(skip_serializing)]
pub last_update_at: Instant,
}
@@ -151,7 +154,7 @@ pub struct ProjectPath {
pub path: Arc<Path>,
}
-#[derive(Clone, Debug, Default, PartialEq)]
+#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct DiagnosticSummary {
pub error_count: usize,
pub warning_count: usize,
@@ -467,7 +470,6 @@ impl Project {
.and_then(|buffer| buffer.upgrade(cx))
}
- #[cfg(any(test, feature = "test-support"))]
pub fn languages(&self) -> &Arc<LanguageRegistry> {
&self.languages
}
@@ -813,13 +815,19 @@ impl Project {
!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() {
return Err(anyhow!("creating buffers as a guest is not supported yet"));
}
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)?;
Ok(buffer)
@@ -6581,7 +6589,9 @@ mod tests {
.unwrap();
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.edit([0..0], "abc", cx);
assert!(buffer.is_dirty());
@@ -18,11 +18,11 @@ use gpui::{
elements::*,
geometry::{rect::RectF, vector::vec2f, PathBuilder},
impl_internal_actions,
- json::{self, to_string_pretty, ToJson},
+ json::{self, ToJson},
platform::{CursorStyle, WindowOptions},
- AnyModelHandle, AnyViewHandle, AppContext, AsyncAppContext, Border, ClipboardItem, Entity,
- ImageData, ModelHandle, MutableAppContext, PathPromptOptions, PromptLevel, RenderContext, Task,
- View, ViewContext, ViewHandle, WeakViewHandle,
+ AnyModelHandle, AnyViewHandle, AppContext, AsyncAppContext, Border, Entity, ImageData,
+ ModelHandle, MutableAppContext, PathPromptOptions, PromptLevel, RenderContext, Task, View,
+ ViewContext, ViewHandle, WeakViewHandle,
};
use language::LanguageRegistry;
use log::error;
@@ -75,7 +75,6 @@ actions!(
ToggleShare,
Unfollow,
Save,
- DebugElements,
ActivatePreviousPane,
ActivateNextPane,
FollowNextCollaborator,
@@ -133,7 +132,6 @@ pub fn init(client: &Arc<Client>, cx: &mut MutableAppContext) {
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_focus);
cx.add_action(|workspace: &mut Workspace, _: &ActivatePreviousPane, cx| {
@@ -1053,22 +1051,6 @@ impl Workspace {
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> {
let pane = cx.add_view(|cx| Pane::new(cx));
let pane_id = pane.id();
@@ -10,6 +10,7 @@ pub use client;
pub use contacts_panel;
use contacts_panel::ContactsPanel;
pub use editor;
+use editor::Editor;
use gpui::{
actions,
geometry::vector::vec2f,
@@ -22,8 +23,10 @@ use project::Project;
pub use project::{self, fs};
use project_panel::ProjectPanel;
use search::{BufferSearchBar, ProjectSearchBar};
+use serde_json::to_string_pretty;
use settings::Settings;
use std::{path::PathBuf, sync::Arc};
+use util::ResultExt;
pub use workspace;
use workspace::{AppState, Workspace, WorkspaceParams};
@@ -32,6 +35,7 @@ actions!(
[
About,
Quit,
+ DebugElements,
OpenSettings,
IncreaseBufferFontSize,
DecreaseBufferFontSize
@@ -100,6 +104,28 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
.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);