laburnum 1.17.1

An LSP framework for building language servers and compilers, powered by an incremental query tree with content-addressed storage, task-based dataflow, and parallel queries.
Documentation
// Copyright Two Neutron Stars Incorporated and contributors
// SPDX-License-Identifier: BlueOak-1.0.0

use {
  crate::{
    Uri,
    protocol::{
      lsp::{
        Location,
        NumberOrString,
        Range,
      },
      macros::lsp_enum,
    },
  },
  serde::{
    Deserialize,
    Serialize,
    de::Error,
  },
  std::collections::HashMap,
};

#[cfg(feature = "proposed")]
use crate::protocol::lsp::{
  MarkupContent,
  OneOf,
};

// TODO: we should Probably make this a struct that takes both the string and
// markup and depending on the client capability will use one or the other.
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum StringOrMarkup {
  String(String),
  Markup(MarkupContent),
}

impl std::default::Default for StringOrMarkup {
  fn default() -> Self {
    StringOrMarkup::String(String::new())
  }
}

impl std::fmt::Display for StringOrMarkup {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    write!(f, "{}", match self {
      | crate::protocol::lsp::StringOrMarkup::String(s) => s,
      | crate::protocol::lsp::StringOrMarkup::Markup(m) => {
        &m.value
      },
    })
  }
}

/// Represents a diagnostic, such as a compiler error or warning.
/// Diagnostic objects are only valid in the scope of a resource.
#[derive(Default, Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Diagnostic {
  /// The range at which the message applies.
  pub range: Range,

  /// The diagnostic's severity. Can be omitted. If omitted it is up to the
  /// client to interpret diagnostics as error, warning, info or hint.
  #[serde(skip_serializing_if = "Option::is_none")]
  pub severity: Option<DiagnosticSeverity>,

  /// The diagnostic's code. Can be omitted.
  #[serde(skip_serializing_if = "Option::is_none")]
  pub code: Option<NumberOrString>,

  /// An optional property to describe the error code.
  ///
  /// @since 3.16.0
  #[serde(skip_serializing_if = "Option::is_none")]
  pub code_description: Option<CodeDescription>,

  /// A human-readable string describing the source of this
  /// diagnostic, e.g. `typescript` or `super lint`.
  #[serde(skip_serializing_if = "Option::is_none")]
  pub source: Option<String>,

  /// The diagnostic's message.
  ///
  /// @since 3.18.0 - support for `MarkupContent`. This is guarded by the
  /// client capability `textDocument.diagnostic.markupMessageSupport`.]
  pub message: StringOrMarkup,

  /// An array of related diagnostic information, e.g. when symbol-names within
  /// a scope collide all definitions can be marked via this property.
  #[serde(skip_serializing_if = "Option::is_none")]
  pub related_information: Option<Vec<DiagnosticRelatedInformation>>,

  /// Additional metadata about the diagnostic.
  #[serde(skip_serializing_if = "Option::is_none")]
  pub tags: Option<Vec<DiagnosticTag>>,

  /// A data entry field that is preserved between a
  /// `textDocument/publishDiagnostics` notification and
  /// `textDocument/codeAction` request.
  ///
  /// @since 3.16.0
  #[serde(skip_serializing_if = "Option::is_none")]
  pub data: Option<serde_json::Value>,
}

impl Diagnostic {
  #[must_use]
  pub const fn new(
    range: Range,
    severity: Option<DiagnosticSeverity>,
    code: Option<NumberOrString>,
    source: Option<String>,
    message: StringOrMarkup,
    related_information: Option<Vec<DiagnosticRelatedInformation>>,
    tags: Option<Vec<DiagnosticTag>>,
  ) -> Self {
    Self {
      range,
      severity,
      code,
      source,
      message,
      related_information,
      tags,
      code_description: None,
      data: None,
    }
  }

  #[must_use]
  pub const fn new_simple(range: Range, message: String) -> Self {
    Self::new(
      range,
      None,
      None,
      None,
      StringOrMarkup::String(message),
      None,
      None,
    )
  }

  #[must_use]
  pub const fn new_with_code_number(
    range: Range,
    severity: DiagnosticSeverity,
    code_number: i32,
    source: Option<String>,
    message: String,
  ) -> Self {
    let code = Some(NumberOrString::Number(code_number));

    Self::new(
      range,
      Some(severity),
      code,
      source,
      StringOrMarkup::String(message),
      None,
      None,
    )
  }
}

/// The protocol currently supports the following diagnostic severities:
#[derive(
  Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize,
)]
#[serde(transparent)]
pub struct DiagnosticSeverity(i32);

lsp_enum! {
    impl DiagnosticSeverity {
        /// Reports an error.
        const ERROR = 1;
        /// Reports a warning.
        const WARNING = 2;
        /// Reports information.
        const INFORMATION = 3;
        /// Reports a hint.
        const HINT = 4;
    }
}

/// The diagnostic tags.
#[derive(Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(transparent)]
pub struct DiagnosticTag(i32);

lsp_enum! {
    impl DiagnosticTag {
        /// Unused or unnecessary code.
        /// Clients are allowed to render diagnostics with this tag faded out instead of having
        /// an error squiggle.
        const UNNECESSARY = 1;
        /// Deprecated or obsolete code.
        /// Clients are allowed to render diagnostics with this tag strike through.
        const DEPRECATED = 2;
    }
}

/// Represents a related message and source code location for a diagnostic. This
/// should be used to point to code locations that cause or related to a
/// diagnostics, e.g when duplicating a symbol in a scope.
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct DiagnosticRelatedInformation {
  /// The location of this related diagnostic information.
  pub location: Location,
  /// The message of this related diagnostic information.
  pub message:  String,
}

/// Structure to capture a description for an error code.
///
/// @since 3.16.0
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CodeDescription {
  /// A URI to open with more information about the diagnostic error.
  pub href: Uri,
}