mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Move deco, pass and feedback into diagnostics module ↩
This commit is contained in:
parent
537545e7f8
commit
d2e220245d
@ -7,11 +7,12 @@ use std::rc::Rc;
|
||||
use fontdock::fs::{FsIndex, FsProvider};
|
||||
use futures_executor::block_on;
|
||||
|
||||
use typstc::diag::{Feedback, Pass};
|
||||
use typstc::eval::State;
|
||||
use typstc::export::pdf;
|
||||
use typstc::font::FontLoader;
|
||||
use typstc::parse::LineMap;
|
||||
use typstc::{typeset, Feedback, Pass};
|
||||
use typstc::typeset;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<_> = std::env::args().collect();
|
||||
|
79
src/diag.rs
79
src/diag.rs
@ -1,11 +1,71 @@
|
||||
//! Diagnostics for source code.
|
||||
//! Diagnostics and decorations for source code.
|
||||
//!
|
||||
//! There are no fatal errors. The document will always compile and yield a
|
||||
//! layout on a best effort process, but diagnostics are nevertheless generated
|
||||
//! for incorrect things.
|
||||
|
||||
use crate::syntax::SpanVec;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
/// The result of some pass: Some output `T` and [feedback] data.
|
||||
///
|
||||
/// [feedback]: struct.Feedback.html
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Pass<T> {
|
||||
/// The output of this compilation pass.
|
||||
pub output: T,
|
||||
/// User feedback data accumulated in this pass.
|
||||
pub feedback: Feedback,
|
||||
}
|
||||
|
||||
impl<T> Pass<T> {
|
||||
/// Create a new pass from output and feedback data.
|
||||
pub fn new(output: T, feedback: Feedback) -> Self {
|
||||
Self { output, feedback }
|
||||
}
|
||||
|
||||
/// Create a new pass with empty feedback.
|
||||
pub fn okay(output: T) -> Self {
|
||||
Self { output, feedback: Feedback::new() }
|
||||
}
|
||||
|
||||
/// Map the output type and keep the feedback data.
|
||||
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Pass<U> {
|
||||
Pass {
|
||||
output: f(self.output),
|
||||
feedback: self.feedback,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Diagnostic and semantic syntax highlighting data.
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq)]
|
||||
pub struct Feedback {
|
||||
/// Diagnostics about the source code.
|
||||
pub diags: SpanVec<Diag>,
|
||||
/// Decorations of the source code for semantic syntax highlighting.
|
||||
pub decos: SpanVec<Deco>,
|
||||
}
|
||||
|
||||
impl Feedback {
|
||||
/// Create a new feedback instance without errors and decos.
|
||||
pub fn new() -> Self {
|
||||
Self { diags: vec![], decos: vec![] }
|
||||
}
|
||||
|
||||
/// Merge two feedbacks into one.
|
||||
pub fn join(mut a: Self, b: Self) -> Self {
|
||||
a.extend(b);
|
||||
a
|
||||
}
|
||||
|
||||
/// Add other feedback data to this feedback.
|
||||
pub fn extend(&mut self, more: Self) {
|
||||
self.diags.extend(more.diags);
|
||||
self.decos.extend(more.decos);
|
||||
}
|
||||
}
|
||||
|
||||
/// A diagnostic that arose in parsing or layouting.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
|
||||
@ -41,6 +101,23 @@ impl Display for Level {
|
||||
}
|
||||
}
|
||||
|
||||
/// Decorations for semantic syntax highlighting.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
|
||||
pub enum Deco {
|
||||
/// Emphasized text.
|
||||
Emph,
|
||||
/// Strong text.
|
||||
Strong,
|
||||
/// A valid, successfully resolved name.
|
||||
Resolved,
|
||||
/// An invalid, unresolved name.
|
||||
Unresolved,
|
||||
/// A key in a dictionary.
|
||||
DictKey,
|
||||
}
|
||||
|
||||
/// Construct a diagnostic with [`Error`] level.
|
||||
///
|
||||
/// ```
|
||||
|
@ -18,17 +18,15 @@ use std::any::Any;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use fontdock::FontStyle;
|
||||
|
||||
use crate::diag::Diag;
|
||||
use crate::geom::Size;
|
||||
use crate::diag::{Deco, Feedback, Pass};
|
||||
use crate::layout::nodes::{
|
||||
Document, LayoutNode, Pad, Pages, Par, Softness, Spacing, Stack, Text,
|
||||
};
|
||||
use crate::layout::{Gen2, Spec2, Switch};
|
||||
use crate::syntax::*;
|
||||
use crate::{Feedback, Pass};
|
||||
|
||||
/// Evaluate a syntax tree into a document.
|
||||
///
|
||||
|
@ -5,7 +5,7 @@ use std::rc::Rc;
|
||||
use fontdock::{fallback, FallbackTree, FontStretch, FontStyle, FontVariant, FontWeight};
|
||||
|
||||
use super::Scope;
|
||||
use crate::geom::{Insets, Linear, Size};
|
||||
use crate::geom::{Linear, Size};
|
||||
use crate::layout::{Dir, Gen2, GenAlign, Sides};
|
||||
use crate::length::Length;
|
||||
use crate::paper::{Paper, PaperClass, PAPER_A4};
|
||||
|
@ -7,8 +7,7 @@ use std::rc::Rc;
|
||||
use super::{Args, Dict, Eval, EvalContext, SpannedEntry};
|
||||
use crate::color::RgbaColor;
|
||||
use crate::geom::Linear;
|
||||
use crate::syntax::{Ident, Span, SpanWith, Spanned, SynNode, SynTree};
|
||||
use crate::DynFuture;
|
||||
use crate::syntax::{Ident, SynTree};
|
||||
|
||||
/// A computational value.
|
||||
#[derive(Clone, PartialEq)]
|
||||
|
@ -7,11 +7,9 @@ pub use primitive::*;
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::eval::{PageState, State, TextState};
|
||||
use crate::font::SharedFontLoader;
|
||||
use crate::geom::{Insets, Point, Rect, Size, SizeExt};
|
||||
use crate::geom::{Point, Rect, Size, SizeExt};
|
||||
use crate::shaping::Shaped;
|
||||
use crate::syntax::SynTree;
|
||||
|
||||
use nodes::Document;
|
||||
|
||||
|
@ -182,20 +182,6 @@ impl LineLayouter {
|
||||
usable
|
||||
}
|
||||
|
||||
/// Update the layouting spaces.
|
||||
///
|
||||
/// If `replace_empty` is true, the current space is replaced if there are
|
||||
/// no boxes laid out into it yet. Otherwise, the followup spaces are
|
||||
/// replaced.
|
||||
fn set_spaces(&mut self, spaces: Vec<LayoutSpace>, replace_empty: bool) {
|
||||
self.stack.set_spaces(spaces, replace_empty && self.line_is_empty());
|
||||
}
|
||||
|
||||
/// Update the line spacing.
|
||||
fn set_line_spacing(&mut self, line_spacing: f64) {
|
||||
self.ctx.line_spacing = line_spacing;
|
||||
}
|
||||
|
||||
/// The remaining inner spaces. If something is laid out into these spaces,
|
||||
/// it will fit into this layouter's underlying stack.
|
||||
fn remaining(&self) -> Vec<LayoutSpace> {
|
||||
|
@ -13,8 +13,8 @@ pub struct Spacing {
|
||||
impl Layout for Spacing {
|
||||
async fn layout(
|
||||
&self,
|
||||
ctx: &mut LayoutContext,
|
||||
constraints: LayoutConstraints,
|
||||
_: &mut LayoutContext,
|
||||
_: LayoutConstraints,
|
||||
) -> Vec<LayoutItem> {
|
||||
vec![LayoutItem::Spacing(self.amount)]
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
use super::*;
|
||||
use crate::geom::Linear;
|
||||
|
||||
/// A node that stacks and aligns its children.
|
||||
///
|
||||
@ -158,21 +157,6 @@ impl StackLayouter {
|
||||
*self.space.usable.get_mut(self.ctx.dirs.main.axis()) -= added.main;
|
||||
}
|
||||
|
||||
/// Update the layouting spaces.
|
||||
///
|
||||
/// If `replace_empty` is true, the current space is replaced if there are
|
||||
/// no boxes laid out into it yet. Otherwise, the followup spaces are
|
||||
/// replaced.
|
||||
pub fn set_spaces(&mut self, spaces: Vec<LayoutSpace>, replace_empty: bool) {
|
||||
if replace_empty && self.space_is_empty() {
|
||||
self.ctx.spaces = spaces;
|
||||
self.start_space(0, self.space.hard);
|
||||
} else {
|
||||
self.ctx.spaces.truncate(self.space.index + 1);
|
||||
self.ctx.spaces.extend(spaces);
|
||||
}
|
||||
}
|
||||
|
||||
/// Move to the first space that can fit the given size or do nothing
|
||||
/// if no space is capable of that.
|
||||
pub fn skip_to_fitting_space(&mut self, size: Size) {
|
||||
@ -208,11 +192,6 @@ impl StackLayouter {
|
||||
self.space.used == Size::ZERO && self.space.layouts.is_empty()
|
||||
}
|
||||
|
||||
/// Whether the current layout space is the last in the followup list.
|
||||
pub fn space_is_last(&self) -> bool {
|
||||
self.space.index == self.ctx.spaces.len() - 1
|
||||
}
|
||||
|
||||
/// Finish everything up and return the final collection of boxes.
|
||||
pub fn finish(mut self) -> Vec<BoxLayout> {
|
||||
if self.space.hard || !self.space_is_empty() {
|
||||
|
80
src/lib.rs
80
src/lib.rs
@ -28,11 +28,8 @@
|
||||
//! [export]: export/index.html
|
||||
//! [_PDF_]: export/pdf/index.html
|
||||
|
||||
#![allow(unused)]
|
||||
|
||||
#[macro_use]
|
||||
pub mod diag;
|
||||
|
||||
pub mod color;
|
||||
pub mod eval;
|
||||
pub mod export;
|
||||
@ -47,17 +44,12 @@ pub mod prelude;
|
||||
pub mod shaping;
|
||||
pub mod syntax;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
||||
use crate::diag::Diag;
|
||||
use crate::diag::{Feedback, Pass};
|
||||
use crate::eval::State;
|
||||
use crate::font::SharedFontLoader;
|
||||
use crate::layout::BoxLayout;
|
||||
use crate::syntax::{Deco, Offset, Pos, SpanVec};
|
||||
|
||||
/// Process source code directly into a collection of layouts.
|
||||
/// Process _Typst_ source code directly into a collection of layouts.
|
||||
pub async fn typeset(
|
||||
src: &str,
|
||||
state: State,
|
||||
@ -68,71 +60,3 @@ pub async fn typeset(
|
||||
let layouts = layout::layout(&document, loader).await;
|
||||
Pass::new(layouts, Feedback::join(f1, f2))
|
||||
}
|
||||
|
||||
/// A dynamic future type which allows recursive invocation of async functions
|
||||
/// when used as the return type.
|
||||
pub type DynFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
|
||||
|
||||
/// The result of some pass: Some output `T` and feedback data.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Pass<T> {
|
||||
/// The output of this compilation pass.
|
||||
pub output: T,
|
||||
/// User feedback data accumulated in this pass.
|
||||
pub feedback: Feedback,
|
||||
}
|
||||
|
||||
impl<T> Pass<T> {
|
||||
/// Create a new pass from output and feedback data.
|
||||
pub fn new(output: T, feedback: Feedback) -> Self {
|
||||
Self { output, feedback }
|
||||
}
|
||||
|
||||
/// Create a new pass with empty feedback.
|
||||
pub fn okay(output: T) -> Self {
|
||||
Self { output, feedback: Feedback::new() }
|
||||
}
|
||||
|
||||
/// Map the output type and keep the feedback data.
|
||||
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Pass<U> {
|
||||
Pass {
|
||||
output: f(self.output),
|
||||
feedback: self.feedback,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Diagnostic and semantic syntax highlighting data.
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq)]
|
||||
pub struct Feedback {
|
||||
/// Diagnostics about the source code.
|
||||
pub diags: SpanVec<Diag>,
|
||||
/// Decorations of the source code for semantic syntax highlighting.
|
||||
pub decos: SpanVec<Deco>,
|
||||
}
|
||||
|
||||
impl Feedback {
|
||||
/// Create a new feedback instance without errors and decos.
|
||||
pub fn new() -> Self {
|
||||
Self { diags: vec![], decos: vec![] }
|
||||
}
|
||||
|
||||
/// Merge two feedbacks into one.
|
||||
pub fn join(mut a: Self, b: Self) -> Self {
|
||||
a.extend(b);
|
||||
a
|
||||
}
|
||||
|
||||
/// Add other feedback data to this feedback.
|
||||
pub fn extend(&mut self, more: Self) {
|
||||
self.diags.extend(more.diags);
|
||||
self.decos.extend(more.decos);
|
||||
}
|
||||
|
||||
/// Add more feedback whose spans are local and need to be translated by an
|
||||
/// `offset` to be correct in this feedback's context.
|
||||
pub fn extend_offset(&mut self, more: Self, offset: Pos) {
|
||||
self.diags.extend(more.diags.offset(offset));
|
||||
self.decos.extend(more.decos.offset(offset));
|
||||
}
|
||||
}
|
||||
|
@ -20,8 +20,6 @@ use crate::prelude::*;
|
||||
/// - `bottom`: The bottom margin (length or relative to height).
|
||||
/// - `flip`: Flips custom or paper-defined width and height (boolean).
|
||||
pub fn page(mut args: Args, ctx: &mut EvalContext) -> Value {
|
||||
let snapshot = ctx.state.clone();
|
||||
|
||||
if let Some(paper) = args.find::<Paper>() {
|
||||
ctx.state.page.class = paper.class;
|
||||
ctx.state.page.size = paper.size();
|
||||
@ -71,7 +69,7 @@ pub fn page(mut args: Args, ctx: &mut EvalContext) -> Value {
|
||||
}
|
||||
|
||||
/// `pagebreak`: Starts a new page.
|
||||
pub fn pagebreak(mut args: Args, ctx: &mut EvalContext) -> Value {
|
||||
pub fn pagebreak(args: Args, ctx: &mut EvalContext) -> Value {
|
||||
args.done(ctx);
|
||||
ctx.end_page_group();
|
||||
ctx.start_page_group(true);
|
||||
|
@ -15,9 +15,9 @@ pub use tokens::*;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::color::RgbaColor;
|
||||
use crate::diag::{Deco, Pass};
|
||||
use crate::eval::DictKey;
|
||||
use crate::syntax::*;
|
||||
use crate::Pass;
|
||||
|
||||
/// Parse a string of source code.
|
||||
pub fn parse(src: &str) -> Pass<SynTree> {
|
||||
@ -56,6 +56,8 @@ fn node(p: &mut Parser, at_start: bool) -> Option<Spanned<SynNode>> {
|
||||
SynNode::Parbreak
|
||||
}
|
||||
}
|
||||
|
||||
// Text.
|
||||
Token::Text(text) => SynNode::Text(text.into()),
|
||||
|
||||
// Comments.
|
||||
|
@ -2,8 +2,8 @@ use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
use super::{Scanner, TokenMode, Tokens};
|
||||
use crate::diag::Diag;
|
||||
use crate::syntax::{Deco, Pos, Span, SpanWith, Spanned, Token};
|
||||
use crate::Feedback;
|
||||
use crate::diag::{Deco, Feedback};
|
||||
use crate::syntax::{Pos, Span, SpanWith, Spanned, Token};
|
||||
|
||||
/// A convenient token-based parser.
|
||||
pub struct Parser<'s> {
|
||||
|
@ -6,6 +6,7 @@ use std::fmt::Debug;
|
||||
|
||||
use super::parse;
|
||||
use crate::color::RgbaColor;
|
||||
use crate::diag::Deco;
|
||||
use crate::eval::DictKey;
|
||||
use crate::length::Length;
|
||||
use crate::syntax::*;
|
||||
|
@ -1,9 +1,10 @@
|
||||
//! A prelude for building custom functions.
|
||||
|
||||
pub use crate::diag::{Feedback, Pass};
|
||||
#[doc(no_inline)]
|
||||
pub use crate::eval::{Args, Dict, Eval, EvalContext, Value, ValueDict};
|
||||
pub use crate::layout::nodes::LayoutNode;
|
||||
pub use crate::layout::primitive::*;
|
||||
#[doc(no_inline)]
|
||||
pub use crate::syntax::{Span, Spanned, SynTree};
|
||||
pub use crate::{Feedback, Pass};
|
||||
pub use crate::{error, warning};
|
||||
|
@ -10,20 +10,3 @@ pub use ast::*;
|
||||
pub use ident::*;
|
||||
pub use span::*;
|
||||
pub use token::*;
|
||||
|
||||
/// Decorations for semantic syntax highlighting.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
|
||||
pub enum Deco {
|
||||
/// Emphasized text.
|
||||
Emph,
|
||||
/// Strong text.
|
||||
Strong,
|
||||
/// A valid, successfully resolved name.
|
||||
Resolved,
|
||||
/// An invalid, unresolved name.
|
||||
Unresolved,
|
||||
/// A key in a dictionary.
|
||||
DictKey,
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ use futures_executor::block_on;
|
||||
use raqote::{DrawTarget, PathBuilder, SolidSource, Source, Transform, Vector};
|
||||
use ttf_parser::OutlineBuilder;
|
||||
|
||||
use typstc::diag::{Feedback, Pass};
|
||||
use typstc::eval::State;
|
||||
use typstc::export::pdf;
|
||||
use typstc::font::{FontLoader, SharedFontLoader};
|
||||
@ -18,7 +19,7 @@ use typstc::geom::{Point, Vec2};
|
||||
use typstc::layout::{BoxLayout, LayoutElement};
|
||||
use typstc::parse::LineMap;
|
||||
use typstc::shaping::Shaped;
|
||||
use typstc::{typeset, Feedback, Pass};
|
||||
use typstc::typeset;
|
||||
|
||||
const TEST_DIR: &str = "tests";
|
||||
const OUT_DIR: &str = "tests/out";
|
||||
|
Loading…
x
Reference in New Issue
Block a user