1use crate::editor::git_memory::GitJob;
8use crate::editor::{ClipboardResult, ShellResult};
9use serde_json::json;
10use strop_trace::{record_with, EventKind};
11
12#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
15pub struct NativePath(#[serde(with = "strop_core::path_serde")] pub std::path::PathBuf);
16
17pub fn rejected(service: &'static str, reason: &str) {
18 record_with(
19 EventKind::JobRejected,
20 || json!({"service":service,"reason":reason}),
21 );
22}
23fn outcome<T>(value: &strop_core::worker::Outcome<T>) -> serde_json::Value {
24 use strop_core::worker::Outcome;
25 match value {
26 Outcome::Success(_) => json!({"kind":"success"}),
27 Outcome::Failed { failure, partial } => {
28 json!({"kind":"failed","failure":failure,"partial":partial.is_some()})
29 }
30 Outcome::Cancelled(reason) => json!({"kind":"cancelled","reason":reason}),
31 }
32}
33
34fn completion<K: serde::Serialize, T>(
35 service: &str,
36 result: &str,
37 value: &strop_core::worker::Completion<K, T>,
38) -> serde_json::Value {
39 json!({"service":service,"result":result,"ticket":value.ticket,"outcome":outcome(&value.outcome)})
40}
41
42pub fn git(job: &GitJob) {
43 record_with(EventKind::JobFinished, || match job {
44 GitJob::Context(value) => completion("git", "context", value),
45 GitJob::Hunks(value) => completion("git", "hunks", value),
46 GitJob::Mutation(value) => completion("git", "mutation", value),
47 GitJob::Log(value) => completion("git", "log", value),
48 GitJob::Gutter(value) => completion("git", "gutter", value),
49 GitJob::Card(value) => completion("git", "blame_card", value),
50 GitJob::Dive(value) => completion("git", "dive", value),
51 });
52}
53
54pub fn io(event: &crate::editor::io::IoEvent) {
55 use crate::editor::io::IoEvent;
56 record_with(EventKind::JobFinished, || match event {
57 IoEvent::Open(value) => completion("io", "open", value),
58 IoEvent::Save(value) => completion("io", "save", value),
59 IoEvent::Native(value) => completion("io", "native", value),
60 IoEvent::Review(value) => completion("search", "review", value),
61 IoEvent::DirectoryFilter(value) => completion("directory", "filter", value),
62 IoEvent::Filesystem(event) => {
63 use crate::editor::filesystem::FsEvent;
64 match event.as_ref() {
65 FsEvent::Prepared(value) => completion("filesystem", "prepare", value),
66 FsEvent::Applied(value) => completion("filesystem", "apply", value),
67 FsEvent::Verified(value) => completion("filesystem", "verify", value),
68 }
69 }
70 IoEvent::Remote(event) => {
71 use crate::editor::remote::RemoteEvent;
72 match event {
73 RemoteEvent::Tick(ticket) => {
74 json!({"service":"remote","result":"follow_tick","ticket":ticket})
75 }
76 RemoteEvent::Timer(value) => completion("remote", "follow_clock", value),
77 RemoteEvent::Read(value) => completion("remote", "follow_read", value),
78 RemoteEvent::Control(value) => completion("remote", "control", value),
79 RemoteEvent::Choices(value) => completion("remote", "destinations", value),
80 RemoteEvent::Write(value) => {
81 let mut record = completion("remote", "write", value);
82 if let strop_core::worker::Outcome::Success(
83 crate::editor::remote::save::RemoteWriteResult::Refused(error),
84 ) = &value.outcome
85 {
86 record["outcome"] = outcome(&strop_core::worker::Outcome::<()>::failed(
87 strop_core::worker::FailureKind::Io,
88 error.to_string(),
89 ));
90 }
91 record
92 }
93 RemoteEvent::DestinationWritten(value) => {
94 completion("remote", "destination_write", value)
95 }
96 }
97 }
98 IoEvent::Session {
99 request,
100 outcome: value,
101 } => json!({"service":"io","result":"session","request":request,"outcome":outcome(value)}),
102 });
103}
104
105pub fn shell(result: &ShellResult) {
106 record_with(EventKind::JobFinished, || {
107 let key = match &result.ticket.key {
108 crate::editor::ShellKey::Display {
109 origin, revision, ..
110 } => json!({
111 "kind":"display","document":super::snapshot::document_id(*origin),
112 "revision":revision,
113 }),
114 crate::editor::ShellKey::Pipe {
115 document,
116 revision,
117 start,
118 end,
119 } => json!({
120 "kind":"pipe","document":super::snapshot::document_id(*document),
121 "revision":revision,"start_byte":start,"end_byte":end,
122 }),
123 };
124 let outcome = match &result.outcome {
125 strop_core::worker::Outcome::Success(output) => json!({
126 "stdout_bytes":output.stdout.len(),"stderr_bytes":output.stderr.len(),
127 }),
128 strop_core::worker::Outcome::Failed { failure, .. } => {
129 json!({"error": failure.message})
130 }
131 _ => json!({"cancelled": true}),
132 };
133 json!({"service":"shell","request":result.ticket.request.get(),
134 "key":key,"outcome":outcome})
135 });
136}
137
138pub fn clipboard(result: &ClipboardResult) {
139 record_with(EventKind::JobFinished, || {
140 let outcome = match &result.outcome {
141 strop_core::worker::Outcome::Success(text) => json!({"bytes": text.len()}),
142 strop_core::worker::Outcome::Failed { failure, .. } => {
143 json!({"error": failure.message})
144 }
145 _ => json!({"cancelled": true}),
146 };
147 json!({"service":"clipboard","request":result.ticket.request.get(),
148 "document":super::snapshot::document_id(result.ticket.key.document),
149 "outcome":outcome})
150 });
151}
152
153pub fn lsp(event: &strop_lsp::LspEvent) {
154 use strop_lsp::LspEvent;
155 record_with(EventKind::JobFinished, || {
156 if strop_trace::capture_content() {
157 return json!({"service":"lsp", "event":event});
158 }
159 match event {
160 LspEvent::Ready { server, name } => {
161 json!({"service":"lsp","result":"ready","server":server,"name":name})
162 }
163 LspEvent::Failed { server, name, hint } => {
164 json!({"service":"lsp","result":"failed","server":server,"name":name,"hint":hint})
166 }
167 LspEvent::ServerMessage { server, name, text } => {
168 json!({"service":"lsp","result":"message","server":server,"name":name,"bytes":text.len()})
169 }
170 LspEvent::Diagnostics { context, diags, .. } => json!({
171 "service":"lsp","result":"diagnostics","context":context,"count":diags.len(),
172 }),
173 LspEvent::Edits { context, edits } => json!({
174 "service":"lsp","result":"edits","context":context,"count":edits.len(),
175 }),
176 LspEvent::WorkspaceEdits { context, edits } => json!({
177 "service":"lsp","result":"workspace_edits","context":context,"targets":edits.len(),
178 }),
179 LspEvent::Symbols { context, symbols } => json!({
180 "service":"lsp","result":"symbols","context":context,"count":symbols.len(),
181 }),
182 LspEvent::ActionList { context, actions } => json!({
183 "service":"lsp","result":"code_actions","context":context,"count":actions.len(),
184 }),
185 LspEvent::HoverText { context, text } => json!({
186 "service":"lsp","result":"hover","context":context,"bytes":text.len(),
187 }),
188 LspEvent::Note { context, text } => json!({
189 "service":"lsp","result":"note","context":context,"bytes":text.len(),
190 }),
191 LspEvent::GotoLocation { context, .. } => json!({
192 "service":"lsp","result":"goto","context":context,
193 }),
194 LspEvent::Locations {
195 context,
196 kind,
197 items,
198 } => json!({
199 "service":"lsp","result":kind.label(),"context":context,"count":items.len(),
200 }),
201 }
202 });
203}
204
205pub fn picker(event: &crate::editor::picker::PickerEvent) {
206 use strop_picker::PickerMsg;
207 record_with(EventKind::JobFinished, || {
208 let outcome = match &event.msg {
209 PickerMsg::Items(items) => json!({"result":"items","count":items.len()}),
210 PickerMsg::Warning(warning) => json!({"result":"warning","bytes":warning.len()}),
211 PickerMsg::QueryError(diagnostic) => {
212 json!({"result":"query-error","range":diagnostic.range})
213 }
214 PickerMsg::Finished(outcome) => match outcome {
215 strop_core::worker::Outcome::Success(()) => json!({"result":"finished"}),
216 strop_core::worker::Outcome::Failed { failure, .. } => {
217 json!({"result":"error","error":failure.message})
218 }
219 _ => json!({"result":"cancelled"}),
220 },
221 };
222 json!({"service":"picker","request":event.ticket.request.get(),
223 "outcome":outcome})
224 });
225}