DB & Dev Tools · Data formats: JSON, YAML and XML as trees, a JSON editor

A document reads into one value, Datum: JSON through serde_json, its
keys now kept in their written order, and YAML's block style through a
small reader that says which line it could not read. JsonViewer and
YamlViewer draw it as one tree: each key with its value, maps and lists
with their counts; a search keeps what holds its words and opens the
way; Enter on a value copies its JSONPath. XmlViewer reads elements,
attributes and text and says where tags cross. JsonEditor writes JSON
in the code editor with Format and Minify and says whether it reads.
DocumentViewer is JsonViewer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-09-27 09:22:30 -04:00
1 parent 8c3811aef9
commit 1c01adc4d6
11 files changed
+1099 -8

No files matched your search

+63
View File
@@ -0,0 +1,63 @@
use gpui::{AnyElement, App, AppContext as _, Entity, IntoElement, TestAppContext, Window, div};
use super::{Bench, bench, settle, tab, tap};
use crate::{
devtools::{JsonEditor, JsonViewer},
editor::CodeEditor,
forms::TextInput,
};
fn viewer(_: &Bench, window: &mut Window, cx: &mut App, _: Entity<Bench>) -> AnyElement {
let search = window.use_keyed_state("search", cx, TextInput::new);
JsonViewer::new(
"viewer",
r#"{"spec": {"replicas": 3}, "kind": "Deployment"}"#,
&search,
)
.into_any_element()
}
/// Stops: the find field, then the tree, whose cursor starts on the root.
#[gpui::test]
fn enter_on_a_value_copies_its_path(cx: &mut TestAppContext) {
let (_, cx) = bench(viewer, cx);
tab(2, cx);
for key in ["down", "right", "down", "enter"] {
tap(key, cx);
}
let copied = cx
.update(|_, cx| cx.read_from_clipboard())
.and_then(|item| item.text());
assert_eq!(copied.as_deref(), Some("$.spec.replicas"));
}
fn editor(bench: &Bench, _: &mut Window, _: &mut App, _: Entity<Bench>) -> AnyElement {
match &bench.editor {
Some(editor) => JsonEditor::new("json", editor).into_any_element(),
None => div().into_any_element(),
}
}
/// Stops: Format, then Minify.
#[gpui::test]
fn format_indents_the_json_and_minify_folds_it(cx: &mut TestAppContext) {
let (host, cx) = bench(editor, cx);
let editor = cx.update(|window, cx| cx.new(|cx| CodeEditor::new(r#"{"a":[1,2]}"#, window, cx)));
host.update(cx, |bench, cx| {
bench.editor = Some(editor.clone());
cx.notify();
});
settle(cx);
tab(1, cx);
tap("space", cx);
assert_eq!(
editor.read_with(cx, |editor, _| editor.text().to_string()),
"{\n \"a\": [\n 1,\n 2\n ]\n}"
);
tab(2, cx);
tap("space", cx);
assert_eq!(
editor.read_with(cx, |editor, _| editor.text().to_string()),
r#"{"a":[1,2]}"#
);
}
+6 -2
View File
@@ -4,14 +4,17 @@ use gpui::{
};
use super::{Connection, ConnectionForm, ConnectionManager, Engine, Field, TableStructureEditor};
use crate::{forms, primitives::FocusNext, theme::Theme};
use crate::{editor::CodeEditor, forms, primitives::FocusNext, theme::Theme};
mod formats;
type Part = fn(&Bench, &mut Window, &mut App, Entity<Bench>) -> AnyElement;
/// A view that shows one tool, keeps the words it heard, and holds a choice among its part's cases.
/// A view that shows one tool, keeps the words it heard, and holds what a test hands its part: an editor, and a choice among the part's cases.
struct Bench {
part: Part,
said: Vec<String>,
editor: Option<Entity<CodeEditor>>,
choice: usize,
}
@@ -41,6 +44,7 @@ fn bench(part: Part, cx: &mut TestAppContext) -> (Entity<Bench>, &mut VisualTest
let (host, cx) = cx.add_window_view(|_, _| Bench {
part,
said: Vec::new(),
editor: None,
choice: 0,
});
settle(cx);