strop_engine/editor/trace/
snapshot.rs1use crate::editor::Editor;
3use serde_json::json;
4use strop_core::id::DocumentId;
5use strop_trace::{capture_content, enabled, record, EventKind};
6
7pub(super) fn document_id(id: DocumentId) -> serde_json::Value {
8 json!(id)
9}
10
11fn pending_state(editor: &Editor) -> serde_json::Value {
12 let Some(prompt) = editor.pending.prompt() else {
13 return serde_json::Value::Null;
14 };
15 let origin = prompt.origin();
16 let context = match prompt.context() {
17 crate::editor::pending::PromptContext::Ex(_) => json!({"kind":"ex"}),
18 crate::editor::pending::PromptContext::Pipe { range, visual, .. } => {
19 json!({"kind":"pipe","range":range,"visual":visual})
20 }
21 crate::editor::pending::PromptContext::Search { backward, .. } => {
22 json!({"kind":"search","backward":backward})
23 }
24 };
25 json!({"text":capture_content().then(||prompt.text()),"cursor_byte":prompt.cursor(),
26 "normal":prompt.normal(),"context":context,"pane_index":origin.pane_index,
27 "origin":origin.pane,"revision":origin.revision})
28}
29
30impl Editor {
31 pub fn trace_state(&mut self) {
32 if !enabled() {
33 return;
34 }
35 self.trace_documents
36 .retain(|id, _| self.docs.get(*id).is_some());
37 for (id, document) in self.docs.iter() {
38 if self.trace_documents.insert(id, document.buf.trace_id())
39 != Some(document.buf.trace_id())
40 {
41 #[derive(serde::Serialize)]
42 struct DocumentRecord<'a> {
43 document: DocumentId,
44 buffer: strop_core::diagnostics::BufferTraceId,
45 #[serde(with = "strop_core::path_serde::option")]
46 path: &'a Option<std::path::PathBuf>,
47 name: &'a Option<String>,
48 revision: strop_core::id::BufferRevision,
49 bytes: usize,
50 readonly: bool,
51 text: Option<String>,
52 }
53 record(
54 EventKind::Document,
55 &DocumentRecord {
56 document: id,
57 buffer: document.buf.trace_id(),
58 path: &document.buf.path,
59 name: &document.buf.name,
60 revision: document.buf.revision(),
61 bytes: document.buf.len_bytes(),
62 readonly: document.buf.readonly,
63 text: capture_content().then(|| document.buf.text().to_string()),
64 },
65 );
66 }
67 }
68 let documents: Vec<_> = self.docs.iter().map(|(id, document)| json!({
69 "document":id,"buffer":document.buf.trace_id(),"revision":document.buf.revision(),
70 "bytes":document.buf.len_bytes(),"dirty":document.buf.dirty,"history_nodes":document.buf.history().depth(),
71 })).collect();
72 let cursor = self.panes.get(self.active_pane).and_then(|pane| {
73 let document = self.docs.get(pane.doc)?;
74 let selection = pane.sels.primary();
75 Some(json!({"document":pane.doc,"head_byte":selection.head,"anchor_byte":selection.anchor,
76 "line":document.buf.line_of(selection.head),"byte_column":document.buf.col_of(selection.head)}))
77 });
78 record(
79 EventKind::State,
80 &json!({
81 "mode":self.mode.chip(),"pending":pending_state(self),"walker":self.walker.display(),
82 "last_search":self.last_search.as_ref().map(|search|json!({
83 "pattern":capture_content().then(||search.query.source()),"backward":search.backward,
84 "whole_word":search.query.whole_word()})),
85 "cursor":cursor,"documents":documents,"panes":self.panes,"active_pane":self.active_pane,
86 "view_rows":self.view_rows,"message":self.message,"should_quit":self.should_quit,
87 "picker":self.picker.as_ref().map(|glue|json!({"id":glue.id.0.get(),
88 "request":glue.active.as_ref().map(|ticket|ticket.request.get()),"query":glue.picker.input.text,
89 "items":glue.picker.items.len(),"streaming":glue.picker.streaming})),
90 "config":self.config,
91 }),
92 );
93 }
94}