terrazzo-terminal 0.2.7

A simple web-based terminal emulator built on Terrazzo.
#![cfg(feature = "server")]
#![cfg_attr(debug_assertions, allow(dead_code))]

pub use std::borrow::Cow;

/// https://github.com/rust-lang/cargo/blob/rust-1.87.0/src/cargo/util/machine_message.rs#L23
#[derive(Debug, serde::Deserialize)]
pub struct CargoCheckMessage<'a> {
    #[serde(borrow)]
    pub reason: Cow<'a, str>,

    #[cfg(debug_assertions)]
    #[serde(borrow)]
    pub package_id: Cow<'a, str>,

    #[serde(borrow)]
    pub manifest_path: Cow<'a, str>,

    #[serde(borrow)]
    pub target: TargetInfo<'a>,

    #[serde(borrow)]
    pub message: Diagnostic<'a>,
}

#[derive(Debug, serde::Deserialize)]
pub struct TargetInfo<'a> {
    #[cfg(debug_assertions)]
    #[serde(borrow)]
    pub kind: Vec<Cow<'a, str>>,

    #[cfg(debug_assertions)]
    #[serde(borrow)]
    pub crate_types: Vec<Cow<'a, str>>,

    #[cfg(debug_assertions)]
    #[serde(borrow)]
    pub name: Cow<'a, str>,

    #[serde(borrow)]
    pub src_path: Cow<'a, str>,

    #[cfg(debug_assertions)]
    #[serde(borrow)]
    pub edition: Cow<'a, str>,

    #[cfg(debug_assertions)]
    pub doc: bool,

    #[cfg(debug_assertions)]
    pub doctest: bool,

    #[cfg(debug_assertions)]
    pub test: bool,
}

/// https://github.com/rust-lang/cargo/blob/rust-1.87.0/crates/rustfix/src/diagnostics.rs#L11
#[derive(Debug, serde::Deserialize)]
pub struct Diagnostic<'a> {
    #[serde(borrow)]
    pub message: Cow<'a, str>,

    #[serde(borrow)]
    pub code: Option<DiagnosticCode<'a>>,

    #[serde(borrow)]
    pub level: Cow<'a, str>,

    #[serde(borrow)]
    pub spans: Vec<DiagnosticSpan<'a>>,

    #[serde(borrow)]
    pub children: Vec<Diagnostic<'a>>,

    #[cfg(debug_assertions)]
    #[serde(borrow)]
    pub rendered: Option<Cow<'a, str>>,
}

/// https://github.com/rust-lang/cargo/blob/rust-1.87.0/crates/rustfix/src/diagnostics.rs#L110
#[derive(Debug, serde::Deserialize)]
pub struct DiagnosticCode<'a> {
    #[serde(borrow)]
    pub code: Cow<'a, str>,

    #[serde(borrow)]
    pub explanation: Option<Cow<'a, str>>,
}

/// https://github.com/rust-lang/cargo/blob/rust-1.87.0/crates/rustfix/src/diagnostics.rs#L26
#[derive(Debug, serde::Deserialize)]
pub struct DiagnosticSpan<'a> {
    #[serde(borrow)]
    pub file_name: Cow<'a, str>,

    pub byte_start: u32,
    pub byte_end: u32,

    /// 1-based.
    pub line_start: u32,
    pub line_end: u32,

    /// 1-based.
    pub column_start: u32,
    pub column_end: u32,

    /// The point where the error actually occurred.
    pub is_primary: bool,

    #[cfg(debug_assertions)]
    #[serde(borrow)]
    pub text: Vec<DiagnosticSpanLine<'a>>,

    #[serde(borrow)]
    pub label: Option<Cow<'a, str>>,

    #[serde(borrow)]
    pub suggested_replacement: Option<Cow<'a, str>>,
    pub suggestion_applicability: Option<Applicability>,

    /// Macro invocations that created the code at this span, if any.
    #[serde(borrow)]
    pub expansion: Option<Box<DiagnosticSpanMacroExpansion<'a>>>,
}

/// https://github.com/rust-lang/cargo/blob/rust-1.87.0/crates/rustfix/src/diagnostics.rs#L58
#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
pub enum Applicability {
    MachineApplicable,
    MaybeIncorrect,
    HasPlaceholders,
    Unspecified,
}

/// https://github.com/rust-lang/cargo/blob/rust-1.87.0/crates/rustfix/src/diagnostics.rs#L82
#[cfg(debug_assertions)]
#[derive(Debug, serde::Deserialize)]
pub struct DiagnosticSpanLine<'a> {
    #[serde(borrow)]
    pub text: Cow<'a, str>,

    pub highlight_start: u32,
    pub highlight_end: u32,
}

/// https://github.com/rust-lang/cargo/blob/rust-1.87.0/crates/rustfix/src/diagnostics.rs#L93
#[derive(Debug, serde::Deserialize)]
pub struct DiagnosticSpanMacroExpansion<'a> {
    #[serde(borrow)]
    pub span: DiagnosticSpan<'a>,

    #[serde(borrow)]
    pub macro_decl_name: Cow<'a, str>,

    #[serde(borrow)]
    pub def_site_span: Option<DiagnosticSpan<'a>>,
}

#[cfg(test)]
mod tests {
    use std::borrow::Cow;

    #[test]
    fn deserialize() {
        let message: super::CargoCheckMessage = serde_json::from_str(COMPILER_MESSAGE).unwrap();
        assert!(matches!(message.reason, Cow::Borrowed(_)));
    }

    const COMPILER_MESSAGE: &str = r#"
{
  "reason": "compiler-message",
  "package_id": "path+file:///home/user/Documents/Terminal/terminal#terrazzo-terminal@0.1.15",
  "manifest_path": "/home/user/Documents/Terminal/terminal/Cargo.toml",
  "target": {
    "kind": [
      "cdylib",
      "rlib"
    ],
    "crate_types": [
      "cdylib",
      "rlib"
    ],
    "name": "terrazzo_terminal",
    "src_path": "/home/user/Documents/Terminal/terminal/src/lib.rs",
    "edition": "2024",
    "doc": true,
    "doctest": true,
    "test": true
  },
  "message": {
    "rendered": "error[E0599]: no method named `expect` found for opaque type `impl futures::Future<Output = Result<ExitStatus, std::io::Error>>` in the current scope\n   --> terminal/src/text_editor/rust_lang/service.rs:48:31\n    |\n48  |     let status = child.wait().expect(\"Failed to wait on child\");\n    |                               ^^^^^^\n    |\nhelp: there is a method `explicit` with a similar name, but with different arguments\n   --> /home/user/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/asn1-rs-0.7.1/src/traits.rs:324:5\n    |\n324 |     fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E> {\n    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nhelp: consider `await`ing on the `Future` and calling the method on its `Output`\n    |\n48  |     let status = child.wait().await.expect(\"Failed to wait on child\");\n    |                               ++++++\n\n",
    "$message_type": "diagnostic",
    "children": [
      {
        "children": [],
        "code": null,
        "level": "help",
        "message": "there is a method `explicit` with a similar name, but with different arguments",
        "rendered": null,
        "spans": [
          {
            "byte_end": 9990,
            "byte_start": 9910,
            "column_end": 85,
            "column_start": 5,
            "expansion": null,
            "file_name": "/home/user/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/asn1-rs-0.7.1/src/traits.rs",
            "is_primary": true,
            "label": null,
            "line_end": 324,
            "line_start": 324,
            "suggested_replacement": null,
            "suggestion_applicability": null,
            "text": [
              {
                "highlight_end": 85,
                "highlight_start": 5,
                "text": "    fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E> {"
              }
            ]
          }
        ]
      },
      {
        "children": [],
        "code": null,
        "level": "help",
        "message": "consider `await`ing on the `Future` and calling the method on its `Output`",
        "rendered": null,
        "spans": [
          {
            "byte_end": 1577,
            "byte_start": 1577,
            "column_end": 31,
            "column_start": 31,
            "expansion": null,
            "file_name": "terminal/src/text_editor/rust_lang/service.rs",
            "is_primary": true,
            "label": null,
            "line_end": 48,
            "line_start": 48,
            "suggested_replacement": "await.",
            "suggestion_applicability": "MaybeIncorrect",
            "text": [
              {
                "highlight_end": 31,
                "highlight_start": 31,
                "text": "    let status = child.wait().expect(\"Failed to wait on child\");"
              }
            ]
          }
        ]
      }
    ],
    "code": {
      "code": "E0599",
      "explanation": "This error occurs when a method is used on a type which doesn't implement it:\n\nErroneous code example:\n\n```compile_fail,E0599\nstruct Mouth;\n\nlet x = Mouth;\nx.chocolate(); // error: no method named `chocolate` found for type `Mouth`\n               //        in the current scope\n```\n\nIn this case, you need to implement the `chocolate` method to fix the error:\n\n```\nstruct Mouth;\n\nimpl Mouth {\n    fn chocolate(&self) { // We implement the `chocolate` method here.\n        println!(\"Hmmm! I love chocolate!\");\n    }\n}\n\nlet x = Mouth;\nx.chocolate(); // ok!\n```\n"
    },
    "level": "error",
    "message": "no method named `expect` found for opaque type `impl futures::Future<Output = Result<ExitStatus, std::io::Error>>` in the current scope",
    "spans": [
      {
        "byte_end": 1583,
        "byte_start": 1577,
        "column_end": 37,
        "column_start": 31,
        "expansion": null,
        "file_name": "terminal/src/text_editor/rust_lang/service.rs",
        "is_primary": true,
        "label": null,
        "line_end": 48,
        "line_start": 48,
        "suggested_replacement": null,
        "suggestion_applicability": null,
        "text": [
          {
            "highlight_end": 37,
            "highlight_start": 31,
            "text": "    let status = child.wait().expect(\"Failed to wait on child\");"
          }
        ]
      }
    ]
  }
}
"#;
}