use std::{net::SocketAddr, time::Duration};
use log::{Level, LevelFilter};
use lsp_types::{ClientCapabilities, MarkupKind};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[non_exhaustive]
pub struct LspServerConfig {
pub multi_thread: bool,
pub scripts_runner: bool,
pub health_check: Option<Duration>,
pub language_id: &'static str,
pub file_ext: &'static str,
pub logger: LspLoggerConfig,
pub capabilities: LspCapabilities,
}
impl Default for LspServerConfig {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl LspServerConfig {
#[inline(always)]
pub const fn new() -> Self {
let multi_thread;
let scripts_runtime;
let health_check;
#[cfg(not(target_family = "wasm"))]
{
multi_thread = true;
scripts_runtime = true;
health_check = Some(Duration::from_secs(5));
}
#[cfg(target_family = "wasm")]
{
multi_thread = false;
scripts_runtime = false;
health_check = None;
}
Self {
multi_thread,
scripts_runner: scripts_runtime,
health_check,
language_id: "adastra",
file_ext: "adastra",
logger: LspLoggerConfig::new(),
capabilities: LspCapabilities::new(),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[non_exhaustive]
pub struct LspCapabilities {
pub publish_diagnostics: bool,
pub inlay_hints: bool,
pub formatting: bool,
pub completion: bool,
pub completion_markdown: bool,
pub completion_snippets: bool,
pub hover: bool,
pub hover_markdown: bool,
pub goto_definition: bool,
pub document_highlight: bool,
pub goto_implementation: bool,
pub code_action: bool,
pub signature_help: bool,
pub signature_help_markdown: bool,
pub rename: bool,
pub rename_prepare: bool,
pub linked_editing_range: bool,
pub code_lens: bool,
pub execute_command: bool,
}
impl Default for LspCapabilities {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl LspCapabilities {
#[inline(always)]
pub const fn new() -> Self {
Self {
publish_diagnostics: true,
inlay_hints: true,
formatting: true,
completion: true,
completion_markdown: true,
completion_snippets: true,
hover: true,
hover_markdown: true,
goto_definition: true,
document_highlight: true,
goto_implementation: true,
code_action: true,
signature_help: true,
signature_help_markdown: true,
rename: true,
rename_prepare: true,
linked_editing_range: true,
code_lens: true,
execute_command: true,
}
}
#[inline(always)]
pub const fn none() -> Self {
Self {
publish_diagnostics: false,
inlay_hints: false,
formatting: false,
completion: false,
completion_markdown: false,
completion_snippets: false,
hover: false,
hover_markdown: false,
goto_definition: false,
document_highlight: false,
goto_implementation: false,
code_action: false,
signature_help: false,
signature_help_markdown: false,
rename: false,
rename_prepare: false,
linked_editing_range: false,
code_lens: false,
execute_command: false,
}
}
pub(super) fn from_client(capabilities: &ClientCapabilities) -> Self {
let mut result = Self::none();
if let Some(text_document) = &capabilities.text_document {
result.publish_diagnostics = text_document.publish_diagnostics.is_some();
result.inlay_hints = text_document.inlay_hint.is_some();
result.formatting = text_document.formatting.is_some();
if let Some(completion) = &text_document.completion {
result.completion = true;
if let Some(completion_item) = &completion.completion_item {
if let Some(documentation_format) = &completion_item.documentation_format {
result.completion_markdown = documentation_format
.iter()
.any(|kind| kind == &MarkupKind::Markdown);
}
result.completion_snippets = completion_item
.snippet_support
.filter(|flag| *flag == true)
.is_some()
}
}
if let Some(hover) = &text_document.hover {
result.hover = true;
if let Some(content_format) = &hover.content_format {
result.hover_markdown = content_format
.iter()
.any(|kind| kind == &MarkupKind::Markdown);
}
}
result.goto_definition = text_document.definition.is_some();
result.document_highlight = text_document.document_highlight.is_some();
result.goto_implementation = text_document.implementation.is_some();
result.code_action = text_document.code_action.is_some();
if let Some(signature_help) = &text_document.signature_help {
result.signature_help = true;
if let Some(signature_information) = &signature_help.signature_information {
if let Some(documentation_format) = &signature_information.documentation_format
{
result.signature_help_markdown = documentation_format
.iter()
.any(|kind| kind == &MarkupKind::Markdown);
}
}
}
if let Some(rename) = &text_document.rename {
result.rename = true;
result.rename_prepare = rename.prepare_support.filter(|flag| *flag).is_some()
}
result.linked_editing_range = text_document.linked_editing_range.is_some();
result.code_lens = text_document.code_lens.is_some();
}
if let Some(workspace) = &capabilities.workspace {
result.execute_command = workspace.execute_command.is_some();
}
result
}
#[inline(always)]
pub(super) fn intersect(&mut self, other: Self) {
self.publish_diagnostics = self.publish_diagnostics && other.publish_diagnostics;
self.inlay_hints = self.inlay_hints && other.inlay_hints;
self.formatting = self.formatting && other.formatting;
self.completion = self.completion && other.completion;
self.completion_markdown = self.completion_markdown && other.completion_markdown;
self.completion_snippets = self.completion_snippets && other.completion_snippets;
self.hover = self.hover && other.hover;
self.hover_markdown = self.hover_markdown && other.hover_markdown;
self.goto_definition = self.goto_definition && other.goto_definition;
self.document_highlight = self.document_highlight && other.document_highlight;
self.goto_implementation = self.goto_implementation && other.goto_implementation;
self.code_action = self.code_action && other.code_action;
self.signature_help = self.signature_help && other.signature_help;
self.signature_help_markdown =
self.signature_help_markdown && other.signature_help_markdown;
self.rename = self.rename && other.rename;
self.rename_prepare = self.rename_prepare && other.rename_prepare;
self.linked_editing_range = self.linked_editing_range && other.linked_editing_range;
self.code_lens = self.code_lens && other.code_lens;
self.execute_command = self.execute_command && other.execute_command;
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[non_exhaustive]
pub enum LspTransportConfig {
Stdio,
TcpClient(SocketAddr),
TcpServer(SocketAddr),
}
impl Default for LspTransportConfig {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl LspTransportConfig {
#[inline(always)]
pub const fn new() -> Self {
Self::Stdio
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[non_exhaustive]
pub struct LspLoggerConfig {
pub enabled: bool,
pub level: LevelFilter,
pub client: LspLoggerClientConfig,
pub server: LspLoggerServerConfig,
}
impl Default for LspLoggerConfig {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl LspLoggerConfig {
#[inline(always)]
pub const fn new() -> Self {
#[cfg(debug_assertions)]
let level = LevelFilter::Debug;
#[cfg(not(debug_assertions))]
let level = LevelFilter::Info;
Self {
enabled: true,
level,
client: LspLoggerClientConfig::new(),
server: LspLoggerServerConfig::new(),
}
}
#[inline(always)]
pub const fn disabled() -> Self {
Self {
enabled: false,
..Self::new()
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[non_exhaustive]
pub enum LspLoggerClientConfig {
Off,
Trace,
Window,
}
impl Default for LspLoggerClientConfig {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl LspLoggerClientConfig {
#[inline(always)]
pub const fn new() -> Self {
Self::Window
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[non_exhaustive]
pub enum LspLoggerServerConfig {
Off,
Stderr,
Syslog,
Custom(fn(Level, String)),
}
impl Default for LspLoggerServerConfig {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl LspLoggerServerConfig {
#[inline(always)]
pub const fn new() -> Self {
return Self::Stderr;
}
}