Skip to content

Commit

Permalink
dev(compiler): replace diag features by CompileReporter (#413)
Browse files Browse the repository at this point in the history
* dev(compiler): add CompileReporter

* dev(compiler): retrieve status feature from stack

* dev(compiler): retrieve diag fmt from stack

* dev(compiler): remove DiagObserver

* dev(core): export ecow for downstream

* dev(compiler): unify Time type

* dev(compiler): remove DiagStatus, export CompileReport

* fix: recover from unused error
  • Loading branch information
Myriad-Dreamin authored Nov 20, 2023
1 parent 13ce66a commit a7961be
Show file tree
Hide file tree
Showing 29 changed files with 696 additions and 296 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 9 additions & 2 deletions cli/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ use std::path::Path;

use typst::doc::Document;
use typst_ts_compiler::{
service::{CompileActor, CompileDriver, CompileExporter, Compiler, DynamicLayoutCompiler},
service::{
features::{FeatureSet, DIAG_FMT_FEATURE},
CompileActor, CompileDriver, CompileExporter, Compiler, DynamicLayoutCompiler,
},
TypstSystemWorld,
};
use typst_ts_core::{config::CompileOpts, exporter_builtins::GroupExporter, path::PathClean};
Expand Down Expand Up @@ -101,10 +104,14 @@ pub fn compile_export(args: CompileArgs, exporter: GroupExporter<Document>) -> !

let watch_root = driver.world().root.as_ref().to_owned();

let feature_set =
FeatureSet::default().configure(&DIAG_FMT_FEATURE, args.diagnostic_format.into());

// CompileExporter + DynamicLayoutCompiler + WatchDriver
let driver = CompileExporter::new(driver).with_exporter(exporter);
let driver = DynamicLayoutCompiler::new(driver, output_dir).with_enable(args.dynamic_layout);
let actor = CompileActor::new(driver, watch_root).with_watch(args.watch);
let actor =
CompileActor::new_with_features(driver, watch_root, feature_set).with_watch(args.watch);

utils::async_continue(async move {
utils::logical_exit(actor.run());
Expand Down
40 changes: 40 additions & 0 deletions cli/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::fmt;
use std::path::PathBuf;

pub mod compile;
Expand Down Expand Up @@ -148,6 +149,14 @@ pub struct CompileArgs {
#[clap(long)]
pub format: Vec<String>,

/// In which format to emit diagnostics
#[clap(
long,
default_value_t = DiagnosticFormat::Human,
value_parser = clap::value_parser!(DiagnosticFormat)
)]
pub diagnostic_format: DiagnosticFormat,

/// Enable tracing.
/// Possible usage: --trace=verbosity={0..3}
/// where verbosity: {0..3} -> {warning, info, debug, trace}
Expand Down Expand Up @@ -280,6 +289,37 @@ pub struct GenPackagesDocArgs {
pub dynamic_layout: bool,
}

/// Which format to use for diagnostics.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, ValueEnum)]
pub enum DiagnosticFormat {
Human,
Short,
}

impl From<DiagnosticFormat> for typst_ts_compiler::service::DiagnosticFormat {
fn from(fmt: DiagnosticFormat) -> Self {
match fmt {
DiagnosticFormat::Human => Self::Human,
DiagnosticFormat::Short => Self::Short,
}
}
}

impl Default for DiagnosticFormat {
fn default() -> Self {
Self::Human
}
}

impl fmt::Display for DiagnosticFormat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.to_possible_value()
.expect("no values are skipped")
.get_name()
.fmt(f)
}
}

pub fn get_cli(sub_command_required: bool) -> Command {
let cli = Command::new("$").disable_version_flag(true);
Opts::augment_args(cli).subcommand_required(sub_command_required)
Expand Down
49 changes: 35 additions & 14 deletions cli/src/query_repl.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::borrow::Cow::{self, Owned};
use std::cell::RefCell;
use typst_ts_compiler::service::{CompileDriver, Compiler, DiagObserver};
use typst_ts_compiler::ShadowApi;
use std::cell::{RefCell, RefMut};
use std::sync::Arc;

use typst::diag::SourceDiagnostic;
use typst::World;
use typst_ide::autocomplete;

use rustyline::completion::{Completer, Pair};
use rustyline::error::ReadlineError;
Expand All @@ -10,14 +13,14 @@ use rustyline::hint::{Hinter, HistoryHinter};
use rustyline::validate::MatchingBracketValidator;
use rustyline::{Cmd, CompletionType, Config, EditMode, Editor, KeyEvent};
use rustyline::{Helper, Validator};
use typst_ts_core::TakeAs;

use typst_ts_compiler::service::{CompileDriver, CompileReport, Compiler, ConsoleDiagReporter};
use typst_ts_compiler::{ShadowApi, TypstSystemWorld};
use typst_ts_core::{typst::prelude::*, GenericExporter, TakeAs};

use crate::query::serialize;
use crate::CompileOnceArgs;

use typst::World;
use typst_ide::autocomplete;

#[derive(Helper, Validator)]
struct ReplContext {
#[rustyline(Validator)]
Expand All @@ -28,6 +31,7 @@ struct ReplContext {

// typst world state
driver: RefCell<CompileDriver>,
reporter: ConsoleDiagReporter<TypstSystemWorld>,
}

impl ReplContext {
Expand All @@ -37,6 +41,7 @@ impl ReplContext {
hinter: HistoryHinter {},
validator: MatchingBracketValidator::new(),
driver: RefCell::new(driver),
reporter: ConsoleDiagReporter::default(),
}
}
}
Expand Down Expand Up @@ -228,14 +233,30 @@ pub fn start_repl_test(args: CompileOnceArgs) -> rustyline::Result<()> {
}

impl ReplContext {
fn process_err(
&self,
driver: &RefMut<CompileDriver>,
err: EcoVec<SourceDiagnostic>,
) -> Result<(), ()> {
let rep = CompileReport::CompileError(driver.main_id(), err, Default::default());
let _ = self.reporter.export(driver.world(), Arc::new(rep));
Ok(())
}

fn repl_process_line(&mut self, line: String) {
let compiled = self.driver.borrow_mut().with_stage_diag::<false, _>(
"compiling",
|driver: &mut CompileDriver| {
let doc = driver.compile(&mut Default::default())?;
driver.query(line, &doc)
},
);
let compiled = {
let mut driver = self.driver.borrow_mut();
let doc = driver
.compile(&mut Default::default())
.map_err(|err| self.process_err(&driver, err))
.ok();
doc.and_then(|doc| {
driver
.query(line, &doc)
.map_err(|err| self.process_err(&driver, err))
.ok()
})
};

if let Some(compiled) = compiled {
let serialized = serialize(&compiled, "json").unwrap();
Expand Down
1 change: 0 additions & 1 deletion compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ parking_lot.workspace = true
hex.workspace = true
sha2.workspace = true
flate2.workspace = true
ecow.workspace = true
instant.workspace = true
strum.workspace = true
rayon = { workspace = true, optional = true }
Expand Down
8 changes: 5 additions & 3 deletions compiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,11 @@ use typst::{
diag::{At, FileResult, SourceResult},
syntax::Span,
};
use typst_ts_core::{Bytes, ImmutPath, TypstFileId};
use typst_ts_core::{typst::prelude::*, Bytes, ImmutPath, TypstFileId};
use vfs::notify::FilesystemEvent;

pub use time::Time;

/// Latest version of the shadow api, which is in beta.
pub trait ShadowApi {
fn _shadow_map_id(&self, _file_id: TypstFileId) -> FileResult<PathBuf> {
Expand Down Expand Up @@ -100,7 +102,7 @@ pub trait ShadowApi {
f: impl FnOnce(&mut Self) -> SourceResult<T>,
) -> SourceResult<T> {
self.map_shadow(file_path, content).at(Span::detached())?;
let res: Result<T, ecow::EcoVec<typst::diag::SourceDiagnostic>> = f(self);
let res: Result<T, EcoVec<typst::diag::SourceDiagnostic>> = f(self);
self.unmap_shadow(file_path).at(Span::detached())?;
res
}
Expand Down Expand Up @@ -138,7 +140,7 @@ pub trait ShadowApi {

/// Latest version of the notify api, which is in beta.
pub trait NotifyApi {
fn iter_dependencies<'a>(&'a self, f: &mut dyn FnMut(&'a ImmutPath, instant::SystemTime));
fn iter_dependencies<'a>(&'a self, f: &mut dyn FnMut(&'a ImmutPath, crate::Time));

fn notify_fs_event(&mut self, event: FilesystemEvent);
}
47 changes: 32 additions & 15 deletions compiler/src/service/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use typst::{
};

use crate::{
service::features::WITH_COMPILING_STATUS_FEATURE,
vfs::notify::{FilesystemEvent, MemoryEvent, NotifyMessage},
world::{CompilerFeat, CompilerWorld},
ShadowApi,
Expand All @@ -27,7 +28,10 @@ use typst_ts_core::{
TypstDocument, TypstFileId,
};

use super::{Compiler, DiagObserver, WorkspaceProvider, WorldExporter};
use super::{
features::FeatureSet, CompileEnv, CompileReporter, Compiler, ConsoleDiagReporter,
WorkspaceProvider, WorldExporter,
};

/// A task that can be sent to the context (compiler thread)
///
Expand Down Expand Up @@ -66,7 +70,7 @@ struct TaggedMemoryEvent {
/// The compiler thread.
pub struct CompileActor<C: Compiler> {
/// The underlying compiler.
pub compiler: C,
pub compiler: CompileReporter<C>,
/// The root path of the workspace.
pub root: PathBuf,
/// Whether to enable file system watching.
Expand All @@ -81,6 +85,10 @@ pub struct CompileActor<C: Compiler> {
estimated_shadow_files: HashSet<Arc<Path>>,
/// The latest compiled document.
latest_doc: Option<Arc<TypstDocument>>,
/// feature set for compile_once mode.
once_feature_set: FeatureSet,
/// Shared feature set for watch mode.
watch_feature_set: Arc<FeatureSet>,

/// Internal channel for stealing the compiler thread.
steal_send: mpsc::UnboundedSender<BorrowTask<Self>>,
Expand All @@ -95,13 +103,19 @@ impl<C: Compiler + ShadowApi + WorldExporter + Send + 'static> CompileActor<C>
where
C::World: for<'files> codespan_reporting::files::Files<'files, FileId = TypstFileId>,
{
/// Create a new compiler thread.
pub fn new(compiler: C, root: PathBuf) -> Self {
pub fn new_with_features(compiler: C, root: PathBuf, feature_set: FeatureSet) -> Self {
let (steal_send, steal_recv) = mpsc::unbounded_channel();
let (memory_send, memory_recv) = mpsc::unbounded_channel();

let watch_feature_set = Arc::new(
feature_set
.clone()
.configure(&WITH_COMPILING_STATUS_FEATURE, true),
);

Self {
compiler,
compiler: CompileReporter::new(compiler)
.with_generic_reporter(ConsoleDiagReporter::default()),
root,

logical_tick: 1,
Expand All @@ -110,6 +124,8 @@ where

estimated_shadow_files: Default::default(),
latest_doc: None,
once_feature_set: feature_set,
watch_feature_set,

steal_send,
steal_recv,
Expand All @@ -119,6 +135,11 @@ where
}
}

/// Create a new compiler thread.
pub fn new(compiler: C, root: PathBuf) -> Self {
Self::new_with_features(compiler, root, FeatureSet::default())
}

/// Run the compiler thread synchronously.
pub fn run(self) -> bool {
use tokio::runtime::Handle;
Expand All @@ -137,10 +158,8 @@ where
if !self.enable_watch {
let compiled = self
.compiler
.with_stage_diag::<false, _>("compiling", |driver| {
driver.compile(&mut Default::default())
});
return compiled.is_some();
.compile(&mut CompileEnv::default().configure(self.once_feature_set));
return compiled.is_ok();
}

if let Some(h) = self.spawn().await {
Expand All @@ -156,9 +175,8 @@ where
pub async fn spawn(mut self) -> Option<JoinHandle<()>> {
if !self.enable_watch {
self.compiler
.with_stage_diag::<false, _>("compiling", |driver| {
driver.compile(&mut Default::default())
});
.compile(&mut CompileEnv::default().configure(self.once_feature_set))
.ok();
return None;
}

Expand Down Expand Up @@ -230,9 +248,8 @@ where
// Compile the document.
self.latest_doc = self
.compiler
.with_stage_diag::<true, _>("compiling", |driver| {
driver.compile(&mut Default::default())
});
.compile(&mut CompileEnv::default().configure_shared(self.watch_feature_set.clone()))
.ok();

// Evict compilation cache.
comemo::evict(30);
Expand Down
Loading

0 comments on commit a7961be

Please sign in to comment.