mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-07-23 12:45:04 +00:00
feat: implements experimental/onEnter
(#328)
* feat: implements `experimental/onEnter` * docs: update readme * dev: update snapshot * dev: allow configuration
This commit is contained in:
parent
8d753d8c56
commit
95a68d2559
11 changed files with 373 additions and 3 deletions
|
@ -65,6 +65,8 @@ pub(crate) mod signature_help;
|
|||
pub use signature_help::*;
|
||||
pub(crate) mod symbol;
|
||||
pub use symbol::*;
|
||||
pub(crate) mod on_enter;
|
||||
pub use on_enter::*;
|
||||
pub(crate) mod prepare_rename;
|
||||
pub use prepare_rename::*;
|
||||
pub(crate) mod references;
|
||||
|
@ -222,6 +224,8 @@ mod polymorphic {
|
|||
SelectionRange(SelectionRangeRequest),
|
||||
InteractCodeContext(InteractCodeContextRequest),
|
||||
|
||||
OnEnter(OnEnterRequest),
|
||||
|
||||
DocumentMetrics(DocumentMetricsRequest),
|
||||
ServerInfo(ServerInfoRequest),
|
||||
}
|
||||
|
@ -255,6 +259,8 @@ mod polymorphic {
|
|||
CompilerQueryRequest::SelectionRange(..) => ContextFreeUnique,
|
||||
CompilerQueryRequest::InteractCodeContext(..) => PinnedFirst,
|
||||
|
||||
CompilerQueryRequest::OnEnter(..) => ContextFreeUnique,
|
||||
|
||||
CompilerQueryRequest::DocumentMetrics(..) => PinnedFirst,
|
||||
CompilerQueryRequest::ServerInfo(..) => Mergeable,
|
||||
}
|
||||
|
@ -286,6 +292,7 @@ mod polymorphic {
|
|||
CompilerQueryRequest::FoldingRange(req) => &req.path,
|
||||
CompilerQueryRequest::SelectionRange(req) => &req.path,
|
||||
CompilerQueryRequest::InteractCodeContext(req) => &req.path,
|
||||
CompilerQueryRequest::OnEnter(req) => &req.path,
|
||||
|
||||
CompilerQueryRequest::DocumentMetrics(req) => &req.path,
|
||||
CompilerQueryRequest::ServerInfo(..) => return None,
|
||||
|
@ -320,6 +327,8 @@ mod polymorphic {
|
|||
SelectionRange(Option<Vec<SelectionRange>>),
|
||||
InteractCodeContext(Option<Vec<InteractCodeContextResponse>>),
|
||||
|
||||
OnEnter(Option<Vec<TextEdit>>),
|
||||
|
||||
DocumentMetrics(Option<DocumentMetricsResponse>),
|
||||
ServerInfo(Option<HashMap<String, ServerInfoResponse>>),
|
||||
}
|
||||
|
|
98
crates/tinymist-query/src/on_enter.rs
Normal file
98
crates/tinymist-query/src/on_enter.rs
Normal file
|
@ -0,0 +1,98 @@
|
|||
//! <https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#on-enter>
|
||||
|
||||
use crate::{prelude::*, SyntaxRequest};
|
||||
|
||||
/// The [`experimental/onEnter`] request is sent from client to server to handle
|
||||
/// the <kbd>Enter</kbd> key press.
|
||||
///
|
||||
/// - kbd:[Enter] inside triple-slash comments automatically inserts `///`
|
||||
/// - kbd:[Enter] in the middle or after a trailing space in `//` inserts `//`
|
||||
/// - kbd:[Enter] inside `//!` doc comments automatically inserts `//!`
|
||||
///
|
||||
/// [`experimental/onEnter`]: https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#on-enter
|
||||
///
|
||||
/// # Compatibility
|
||||
///
|
||||
/// This request was introduced in specification version 3.10.0.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct OnEnterRequest {
|
||||
/// The path of the document to get folding ranges for.
|
||||
pub path: PathBuf,
|
||||
/// The source code position to request for.
|
||||
pub position: LspPosition,
|
||||
}
|
||||
|
||||
impl SyntaxRequest for OnEnterRequest {
|
||||
type Response = Vec<TextEdit>;
|
||||
|
||||
fn request(
|
||||
self,
|
||||
source: &Source,
|
||||
position_encoding: PositionEncoding,
|
||||
) -> Option<Self::Response> {
|
||||
let root = LinkedNode::new(source.root());
|
||||
let cursor = lsp_to_typst::position(self.position, position_encoding, source)?;
|
||||
let leaf = root.leaf_at(cursor)?;
|
||||
|
||||
let worker = OnEnterWorker {
|
||||
source,
|
||||
position_encoding,
|
||||
};
|
||||
|
||||
if matches!(leaf.kind(), SyntaxKind::LineComment) {
|
||||
return worker.enter_line_doc_comment(&leaf, cursor);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
struct OnEnterWorker<'a> {
|
||||
source: &'a Source,
|
||||
position_encoding: PositionEncoding,
|
||||
}
|
||||
|
||||
impl OnEnterWorker<'_> {
|
||||
fn enter_line_doc_comment(&self, leaf: &LinkedNode, cursor: usize) -> Option<Vec<TextEdit>> {
|
||||
let skipper = |n: &LinkedNode| {
|
||||
matches!(
|
||||
n.kind(),
|
||||
SyntaxKind::Space | SyntaxKind::Linebreak | SyntaxKind::LineComment
|
||||
)
|
||||
};
|
||||
let parent = leaf.parent()?;
|
||||
let till_curr = parent.children().take(leaf.index());
|
||||
let first_index = till_curr.rev().take_while(skipper).count();
|
||||
let comment_group_cnt = parent
|
||||
.children()
|
||||
.skip(leaf.index().saturating_sub(first_index))
|
||||
.take_while(skipper)
|
||||
.filter(|e| matches!(e.kind(), SyntaxKind::LineComment))
|
||||
.count();
|
||||
|
||||
let comment_prefix = {
|
||||
let mut p = unscanny::Scanner::new(leaf.text());
|
||||
p.eat_while('/');
|
||||
p.eat_if('!');
|
||||
p.before()
|
||||
};
|
||||
|
||||
// Continuing single-line non-doc comments (like this one :) ) is annoying
|
||||
if comment_group_cnt <= 1 && comment_prefix == "//" {
|
||||
return None;
|
||||
}
|
||||
|
||||
// todo: indent
|
||||
let indent = "";
|
||||
// todo: remove_trailing_whitespace
|
||||
|
||||
let rng = cursor..cursor;
|
||||
|
||||
let edit = TextEdit {
|
||||
range: typst_to_lsp::range(rng, self.source, self.position_encoding),
|
||||
new_text: format!("\n{indent}{comment_prefix} $0"),
|
||||
};
|
||||
|
||||
Some(vec![edit])
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue