hammer/diagnose.rs
1//! The `diagnose` export: Hammer sends paragraphs of a scene, and the plugin replies with the issues
2//! in them, which the editor underlines. A check's manifest `scope` says which paragraphs: `paragraph`,
3//! the default, sends only those whose text the check has not seen; `scene` sends every paragraph of
4//! the scene each time, blank ones included, for issues that depend on other paragraphs.
5
6use serde::{Deserialize, Serialize};
7use serde_json::{Map, Value};
8
9#[derive(Deserialize)]
10pub struct Request {
11 /// Which of the manifest's `[[diagnostics]]` checks to run.
12 pub diagnostics: String,
13 /// Plain text, without markdown.
14 pub paragraphs: Vec<String>,
15 /// The project's BCP 47 tag, or none.
16 pub language: Option<String>,
17 /// The name of the project the text belongs to, for operations such as `entry.list`.
18 pub project: String,
19 /// The plugin's declared settings, every key present.
20 #[serde(default)]
21 pub settings: Map<String, Value>,
22 /// The UI's BCP 47 tag, for messages in the user's language; not [Request::language], the text's.
23 #[serde(default)]
24 pub locale: Option<String>,
25}
26
27#[derive(Serialize, Default)]
28pub struct Reply {
29 pub diagnostics: Vec<Diagnostic>,
30}
31
32/// An issue in one paragraph, from `start` to `end` as UTF-8 byte offsets into it.
33#[derive(Serialize)]
34pub struct Diagnostic {
35 /// Its index in [Request::paragraphs].
36 pub paragraph: usize,
37 pub start: usize,
38 pub end: usize,
39 pub message: String,
40 /// Offered to the user.
41 pub fixes: Vec<Fix>,
42 #[serde(skip_serializing_if = "Severity::is_error")]
43 pub severity: Severity,
44}
45
46#[derive(Serialize, Clone, Copy, PartialEq, Eq, Default, Debug)]
47#[serde(rename_all = "lowercase")]
48pub enum Severity {
49 /// A mistake: a wavy underline.
50 #[default]
51 Error,
52 /// Something the writer may want to change: a quieter, dotted underline.
53 Suggestion,
54}
55
56impl Severity {
57 fn is_error(&self) -> bool {
58 *self == Severity::Error
59 }
60}
61
62/// A replacement for a [Diagnostic]'s range, shown to the user as itself, or as a label where the
63/// replacement alone would not say what it does, such as removing a word.
64#[derive(Serialize)]
65#[serde(untagged)]
66pub enum Fix {
67 Replace(String),
68 Labelled { replacement: String, label: String },
69}