laburnum 1.17.3

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.
// Copyright Two Neutron Stars Incorporated and contributors
// SPDX-License-Identifier: BlueOak-1.0.0

use crate::{
  ContentHash,
  Ident,
  SourceKey,
  database::{
    DynPartition,
    PartitionKey,
  },
  protocol::lsp::Position,
};

pub struct TextDocumentPosition;

impl PartitionKey for TextDocumentPosition {
  const KEY: crate::SpannedIdent =
    crate::partitions::known_keys::TEXT_DOCUMENT_POSITION_INDEX;
}
/// To write text document positions, create a wrapper partition with
/// [`impl_partition_for_dyn!`]:
///
/// ```rust,ignore
/// use laburnum::{impl_partition_for_dyn, partitions::TextDocumentPosition};
///
/// // Your record type must implement TextDocumentPositionRecord + Record
/// impl_partition_for_dyn!(MyPositionPartition, TextDocumentPosition, MyPosition);
///
/// // Then write using the wrapper partition
/// let sort_key = TextDocumentPositionSortKey::Position {
///   source_key, line, character, kind
/// };
/// writer.write::<MyPositionPartition>(sort_key, position.into());
/// ```
///
/// [`impl_partition_for_dyn!`]: crate::impl_partition_for_dyn
impl DynPartition for TextDocumentPosition {
  type DynSortKey = TextDocumentPositionSortKey;
  type RecordConstraint = dyn TextDocumentPositionRecord;
}

impl<R: TextDocumentPositionRecord + crate::record::Record>
  crate::database::DynPartitionRecord<TextDocumentPosition> for R
{
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum PositionKind {
  Unknown   = 0,
  Ident     = 1,
  Symbol    = 2,
  Reference = 3,
}

#[derive(Debug, Clone)]
pub enum TextDocumentPositionSortKey {
  Position {
    source_key: SourceKey,
    line:       u32,
    character:  u32,
    kind:       PositionKind,
  },
  All,
  FilePrefix {
    source_key: SourceKey,
  },
}

impl std::fmt::Display for TextDocumentPositionSortKey {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    match self {
      | TextDocumentPositionSortKey::Position {
        source_key,
        line,
        character,
        kind,
      } => {
        write!(
          f,
          "{}|{:010}|{:010}|{}",
          source_key, line, character, *kind as u8
        )
      },
      | TextDocumentPositionSortKey::All => Ok(()),
      | TextDocumentPositionSortKey::FilePrefix { source_key } => {
        write!(f, "{}", source_key)
      },
    }
  }
}

// -- Sort key ordering (ADR0011) ----------------------------------------------

#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
enum PosToken {
  Source(SourceKey),
  Line(u32),
  Char(u32),
  Kind(u8),
}

impl TextDocumentPositionSortKey {
  fn tokens(&self) -> Vec<PosToken> {
    match self {
      | TextDocumentPositionSortKey::All => Vec::new(),
      | TextDocumentPositionSortKey::FilePrefix { source_key } => {
        vec![PosToken::Source(*source_key)]
      },
      | TextDocumentPositionSortKey::Position {
        source_key,
        line,
        character,
        kind,
      } => vec![
        PosToken::Source(*source_key),
        PosToken::Line(*line),
        PosToken::Char(*character),
        PosToken::Kind(*kind as u8),
      ],
    }
  }
}

impl PartialEq for TextDocumentPositionSortKey {
  fn eq(&self, other: &Self) -> bool {
    self.tokens() == other.tokens()
  }
}
impl Eq for TextDocumentPositionSortKey {}
impl std::hash::Hash for TextDocumentPositionSortKey {
  fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
    self.tokens().hash(state);
  }
}
impl PartialOrd for TextDocumentPositionSortKey {
  fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
    Some(self.cmp(other))
  }
}
impl Ord for TextDocumentPositionSortKey {
  fn cmp(&self, other: &Self) -> std::cmp::Ordering {
    self.tokens().cmp(&other.tokens())
  }
}

impl bluegum::Bluegum for TextDocumentPositionSortKey {
  fn node(&self, b: &mut bluegum::Builder) {
    b.name("TextDocumentPositionSortKey");
  }
}

impl bluegum::BluegumWithState<dyn crate::SourceResolver>
  for TextDocumentPositionSortKey
{
  fn node_with_state(
    &self,
    b: &mut bluegum::Builder,
    resolver: &(dyn crate::SourceResolver + 'static),
  ) {
    b.name("TextDocumentPositionSortKey")
      .alt(crate::database::PartitionSortKey::resolve(self, resolver));
  }
}

impl crate::database::PartitionSortKey for TextDocumentPositionSortKey {
  fn is_prefix_of(&self, other: &Self) -> bool {
    other.tokens().starts_with(&self.tokens())
  }

  fn resolve(&self, _resolver: &dyn crate::SourceResolver) -> String {
    self.to_string()
  }
}

pub trait TextDocumentPositionRecord: Send + Sync + std::fmt::Debug {
  fn source_key(&self) -> SourceKey;
  fn position(&self) -> Position;
  fn kind(&self) -> PositionKind;

  /// Content hash of the DocumentSymbolRecord for this position.
  ///
  /// Resolve via `query_client.get_by_hash::<DocumentSymbols>(hash)`
  /// then downcast with `.as_document_symbol()`.
  fn symbol_hash(&self) -> ContentHash;

  /// Identifier of the symbol at this position.
  ///
  /// Stored inline for fast filtering (e.g. rename loop) without
  /// needing to resolve the full DocumentSymbolRecord.
  fn symbol_ident(&self) -> Ident;
}