mirror of
https://github.com/typst/typst
synced 2025-05-15 17:45:27 +08:00
initial attached comment detection
This commit is contained in:
parent
f8958961cb
commit
fe860f8b6b
@ -80,6 +80,19 @@ impl<'a> Markup<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node! {
|
||||||
|
/// A comment: `// something`.
|
||||||
|
LineComment
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LineComment<'a> {
|
||||||
|
/// The comment's contents, excluding the initial '//' marker.
|
||||||
|
pub fn content(self) -> &'a str {
|
||||||
|
let text = self.0.text();
|
||||||
|
text.strip_prefix("//").unwrap_or(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An expression in markup, math or code.
|
/// An expression in markup, math or code.
|
||||||
#[derive(Debug, Copy, Clone, Hash)]
|
#[derive(Debug, Copy, Clone, Hash)]
|
||||||
pub enum Expr<'a> {
|
pub enum Expr<'a> {
|
||||||
|
@ -773,13 +773,17 @@ impl<'a> LinkedNode<'a> {
|
|||||||
self.parent.as_deref()
|
self.parent.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the first previous non-trivia sibling node.
|
fn prev_sibling_inner(&self) -> Option<Self> {
|
||||||
pub fn prev_sibling(&self) -> Option<Self> {
|
|
||||||
let parent = self.parent()?;
|
let parent = self.parent()?;
|
||||||
let index = self.index.checked_sub(1)?;
|
let index = self.index.checked_sub(1)?;
|
||||||
let node = parent.node.children().nth(index)?;
|
let node = parent.node.children().nth(index)?;
|
||||||
let offset = self.offset - node.len();
|
let offset = self.offset - node.len();
|
||||||
let prev = Self { node, parent: self.parent.clone(), index, offset };
|
Some(Self { node, parent: self.parent.clone(), index, offset })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the first previous non-trivia sibling node.
|
||||||
|
pub fn prev_sibling(&self) -> Option<Self> {
|
||||||
|
let prev = self.prev_sibling_inner()?;
|
||||||
if prev.kind().is_trivia() {
|
if prev.kind().is_trivia() {
|
||||||
prev.prev_sibling()
|
prev.prev_sibling()
|
||||||
} else {
|
} else {
|
||||||
@ -787,6 +791,38 @@ impl<'a> LinkedNode<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the first sibling comment node at the line above this node.
|
||||||
|
/// This is done by moving backwards until the rightmost newline, and then
|
||||||
|
/// checking for comments before the previous newline.
|
||||||
|
pub fn prev_attached_comment(&self) -> Option<Self> {
|
||||||
|
if self.kind() == SyntaxKind::Parbreak
|
||||||
|
|| self.kind() == SyntaxKind::Space && self.text().contains('\n')
|
||||||
|
{
|
||||||
|
// We hit a newline, so let's check for comments before the next
|
||||||
|
// newline.
|
||||||
|
let mut sibling_before_newline = self.prev_sibling_inner()?;
|
||||||
|
while sibling_before_newline.kind().is_trivia()
|
||||||
|
&& !matches!(
|
||||||
|
sibling_before_newline.kind(),
|
||||||
|
SyntaxKind::Space | SyntaxKind::LineComment | SyntaxKind::Parbreak
|
||||||
|
)
|
||||||
|
{
|
||||||
|
sibling_before_newline = sibling_before_newline.prev_sibling_inner()?;
|
||||||
|
}
|
||||||
|
if sibling_before_newline.kind() == SyntaxKind::LineComment {
|
||||||
|
// Found a comment on the previous line
|
||||||
|
Some(sibling_before_newline)
|
||||||
|
} else {
|
||||||
|
// No comments on the previous line
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.prev_sibling_inner()
|
||||||
|
.as_ref()
|
||||||
|
.and_then(Self::prev_attached_comment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the next non-trivia sibling node.
|
/// Get the next non-trivia sibling node.
|
||||||
pub fn next_sibling(&self) -> Option<Self> {
|
pub fn next_sibling(&self) -> Option<Self> {
|
||||||
let parent = self.parent()?;
|
let parent = self.parent()?;
|
||||||
|
@ -7,10 +7,10 @@ use comemo::{Track, Tracked, TrackedMut, Validate};
|
|||||||
use ecow::EcoVec;
|
use ecow::EcoVec;
|
||||||
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
|
||||||
|
|
||||||
use crate::diag::{SourceDiagnostic, SourceResult};
|
use crate::diag::{Severity, SourceDiagnostic, SourceResult};
|
||||||
use crate::foundations::{Styles, Value};
|
use crate::foundations::{Styles, Value};
|
||||||
use crate::introspection::Introspector;
|
use crate::introspection::Introspector;
|
||||||
use crate::syntax::{FileId, Span};
|
use crate::syntax::{ast, FileId, Span};
|
||||||
use crate::World;
|
use crate::World;
|
||||||
|
|
||||||
/// Holds all data needed during compilation.
|
/// Holds all data needed during compilation.
|
||||||
@ -160,6 +160,19 @@ impl Sink {
|
|||||||
pub fn values(self) -> EcoVec<(Value, Option<Styles>)> {
|
pub fn values(self) -> EcoVec<(Value, Option<Styles>)> {
|
||||||
self.values
|
self.values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Apply warning suppression.
|
||||||
|
pub fn suppress_warnings(&mut self, world: &dyn World) {
|
||||||
|
self.warnings.retain(|diag| {
|
||||||
|
// Only retain warnings which weren't locally suppressed where they
|
||||||
|
// were emitted or at any of their tracepoints.
|
||||||
|
diag.severity != Severity::Warning
|
||||||
|
|| (!check_warning_suppressed(diag.span, world, &diag.message)
|
||||||
|
&& !diag.trace.iter().any(|tracepoint| {
|
||||||
|
check_warning_suppressed(tracepoint.span, world, &diag.message)
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[comemo::track]
|
#[comemo::track]
|
||||||
@ -202,6 +215,41 @@ impl Sink {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if a given warning is suppressed given one span it has a tracepoint
|
||||||
|
/// in. If one of the ancestors of the node where the warning occurred has a
|
||||||
|
/// warning suppression decorator sibling right before it suppressing this
|
||||||
|
/// particular warning, the warning is considered suppressed.
|
||||||
|
fn check_warning_suppressed(
|
||||||
|
span: Span,
|
||||||
|
world: &dyn World,
|
||||||
|
_message: &ecow::EcoString,
|
||||||
|
) -> bool {
|
||||||
|
let Some(file) = span.id() else {
|
||||||
|
// Don't suppress detached warnings.
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The source must exist if a warning occurred in the file,
|
||||||
|
// or has a tracepoint in the file.
|
||||||
|
let source = world.source(file).unwrap();
|
||||||
|
// The span must point to this source file, so we unwrap.
|
||||||
|
let mut node = &source.find(span).unwrap();
|
||||||
|
|
||||||
|
// Walk the parent nodes to check for a warning suppression.
|
||||||
|
while let Some(parent) = node.parent() {
|
||||||
|
if let Some(sibling) = parent.prev_attached_comment() {
|
||||||
|
if let Some(comment) = sibling.cast::<ast::LineComment>() {
|
||||||
|
let _text = comment.content();
|
||||||
|
// Find comment, return true if this warning was suppressed
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// The route the engine took during compilation. This is used to detect
|
/// The route the engine took during compilation. This is used to detect
|
||||||
/// cyclic imports and excessive nesting.
|
/// cyclic imports and excessive nesting.
|
||||||
pub struct Route<'a> {
|
pub struct Route<'a> {
|
||||||
|
@ -86,6 +86,8 @@ pub fn compile(world: &dyn World) -> Warned<SourceResult<Document>> {
|
|||||||
let mut sink = Sink::new();
|
let mut sink = Sink::new();
|
||||||
let output = compile_inner(world.track(), Traced::default().track(), &mut sink)
|
let output = compile_inner(world.track(), Traced::default().track(), &mut sink)
|
||||||
.map_err(deduplicate);
|
.map_err(deduplicate);
|
||||||
|
|
||||||
|
sink.suppress_warnings(world);
|
||||||
Warned { output, warnings: sink.warnings() }
|
Warned { output, warnings: sink.warnings() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user