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::{
  Ident,
  SourceKey,
  database::{
    DynPartition,
    PartitionKey,
  },
  protocol::lsp::SymbolKind,
};

pub struct DocumentSymbols;

impl PartitionKey for DocumentSymbols {
  const KEY: crate::SpannedIdent =
    crate::partitions::known_keys::DOCUMENT_SYMBOLS;
}
/// To write document symbols, create a wrapper partition with
/// [`impl_partition_for_dyn!`]:
///
/// ```rust,ignore
/// use laburnum::{impl_partition_for_dyn, partitions::DocumentSymbols};
///
/// // Your record type must implement DocumentSymbolRecord + Record
/// impl_partition_for_dyn!(MyDocumentSymbolsPartition, DocumentSymbols, MySymbol);
///
/// // Then write using the wrapper partition
/// let sort_key = DocumentSymbolSortKey::Symbol { source_key, symbol_kind, ident };
/// writer.write::<MyDocumentSymbolsPartition>(sort_key, symbol.into());
/// ```
///
/// [`impl_partition_for_dyn!`]: crate::impl_partition_for_dyn
impl DynPartition for DocumentSymbols {
  type DynSortKey = DocumentSymbolSortKey;
  type RecordConstraint = dyn DocumentSymbolRecord;
}

impl<R: DocumentSymbolRecord + crate::record::Record>
  crate::database::DynPartitionRecord<DocumentSymbols> for R
{
}

#[derive(Debug, Clone)]
pub enum DocumentSymbolSortKey {
  Symbol {
    source_key:  SourceKey,
    symbol_kind: SymbolKind,
    ident:       Ident,
  },
  All,
  FilePrefix {
    source_key: SourceKey,
  },
}

impl std::fmt::Display for DocumentSymbolSortKey {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    match self {
      | DocumentSymbolSortKey::Symbol {
        source_key,
        symbol_kind,
        ident,
      } => write!(f, "{}|{}|{}", source_key, symbol_kind, ident),
      | DocumentSymbolSortKey::All => Ok(()),
      | DocumentSymbolSortKey::FilePrefix { source_key } => {
        write!(f, "{}", source_key)
      },
    }
  }
}

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

#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
enum DocSymToken {
  Source(SourceKey),
  Kind(SymbolKind),
  Ident(Ident),
}

impl DocumentSymbolSortKey {
  fn tokens(&self) -> Vec<DocSymToken> {
    match self {
      | DocumentSymbolSortKey::All => Vec::new(),
      | DocumentSymbolSortKey::FilePrefix { source_key } => {
        vec![DocSymToken::Source(*source_key)]
      },
      | DocumentSymbolSortKey::Symbol {
        source_key,
        symbol_kind,
        ident,
      } => vec![
        DocSymToken::Source(*source_key),
        DocSymToken::Kind(*symbol_kind),
        DocSymToken::Ident(*ident),
      ],
    }
  }
}

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

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

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

impl crate::database::PartitionSortKey for DocumentSymbolSortKey {
  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()
  }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymbolKindVariant {
  Symbol,
  Reference,
}

pub trait DocumentSymbolRecord: Send + Sync + std::fmt::Debug {
  fn get_ident(&self) -> Ident;

  fn get_ident_path(&self) -> Vec<Ident>;

  fn get_ident_range(&self) -> crate::protocol::lsp::Range;

  fn source_key(&self) -> SourceKey;

  fn span(&self) -> crate::source::Span;

  fn symbol_kind(&self) -> SymbolKind;

  fn target_source_key(&self) -> Option<SourceKey> {
    None
  }

  fn symbol_kind_variant(&self) -> SymbolKindVariant {
    SymbolKindVariant::Symbol
  }

  fn to_document_symbol(
    &self,
    source_cache: &crate::source::cache::reporter::SourceCacheReader,
    encoding: &crate::protocol::lsp::PositionEncodingKind,
  ) -> crate::protocol::lsp::DocumentSymbol;

  fn definition_location(
    &self,
    _source_cache: &crate::source::cache::reporter::SourceCacheReader,
    _encoding: &crate::protocol::lsp::PositionEncodingKind,
  ) -> Option<crate::protocol::lsp::Location> {
    None
  }

  fn hover_info(
    &self,
    _source_cache: &crate::source::cache::reporter::SourceCacheReader,
    _encoding: &crate::protocol::lsp::PositionEncodingKind,
  ) -> Option<crate::protocol::lsp::Hover> {
    None
  }

  fn rename_range(
    &self,
    _source_cache: &crate::source::cache::reporter::SourceCacheReader,
    _encoding: &crate::protocol::lsp::PositionEncodingKind,
  ) -> Option<crate::protocol::lsp::Range> {
    None
  }
}