test: ensure pdf export onType to work (#1865)
Some checks are pending
tinymist::ci / Duplicate Actions Detection (push) Waiting to run
tinymist::ci / Check Clippy, Formatting, Completion, Documentation, and Tests (Linux) (push) Waiting to run
tinymist::ci / Check Minimum Rust version and Tests (Windows) (push) Waiting to run
tinymist::ci / E2E Tests (darwin-arm64 on macos-latest) (push) Blocked by required conditions
tinymist::ci / E2E Tests (linux-x64 on ubuntu-22.04) (push) Blocked by required conditions
tinymist::ci / E2E Tests (linux-x64 on ubuntu-latest) (push) Blocked by required conditions
tinymist::ci / E2E Tests (win32-x64 on windows-2022) (push) Blocked by required conditions
tinymist::ci / E2E Tests (win32-x64 on windows-latest) (push) Blocked by required conditions
tinymist::ci / prepare-build (push) Waiting to run
tinymist::ci / build-binary (push) Blocked by required conditions
tinymist::ci / build-vsc-assets (push) Blocked by required conditions
tinymist::ci / build-vscode (push) Blocked by required conditions
tinymist::ci / build-vscode-others (push) Blocked by required conditions
tinymist::ci / publish-vscode (push) Blocked by required conditions
tinymist::gh_pages / build-gh-pages (push) Waiting to run

* test: ensure pdf export `onType` to work

* fix: dirty changes
This commit is contained in:
Myriad-Dreamin 2025-07-02 02:56:17 +08:00 committed by GitHub
parent 9ca77d5382
commit 4cd8c634d5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 180 additions and 14 deletions

View file

@ -4,6 +4,7 @@ use core::fmt;
use crate::{args::TaskWhen, CompilerFeat, CompilerWorld, EntryReader, TaskInputs};
use ecow::EcoString;
use serde::{Deserialize, Serialize};
use tinymist_std::typst::TypstDocument;
/// Project instance id. This is slightly different from the project ids that
@ -26,7 +27,8 @@ impl ProjectInsId {
///
/// Whether to export depends on the current state of the document and the user
/// settings.
#[derive(Debug, Clone, Copy, Default)]
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ExportSignal {
/// Whether the revision is annotated by memory events.
pub by_mem_events: bool,

View file

@ -35,6 +35,7 @@ const CONFIG_ITEMS: &[&str] = &[
"colorTheme",
"compileStatus",
"completion",
"development",
"exportPdf",
"exportTarget",
"fontPaths",
@ -75,6 +76,8 @@ pub struct Config {
/// Whether to utilize the extended `tinymist.resolveCodeAction` at client
/// side.
pub extended_code_action: bool,
/// Whether to run the server in development mode.
pub development: bool,
/// The preferred color theme for rendering.
pub color_theme: Option<String>,
@ -329,6 +332,7 @@ impl Config {
assign_config!(semantic_tokens := "semanticTokens"?: SemanticTokensMode);
assign_config!(support_html_in_markdown := "supportHtmlInMarkdown"?: bool);
assign_config!(extended_code_action := "supportExtendedCodeAction"?: bool);
assign_config!(development := "development"?: bool);
assign_config!(system_fonts := "systemFonts"?: Option<bool>);
self.notify_status = match try_(|| update.get("compileStatus")?.as_str()) {
@ -524,6 +528,7 @@ impl Config {
creation_timestamp: self.creation_timestamp(),
}),
count_words: self.notify_status,
development: self.development,
}
}

View file

@ -20,6 +20,7 @@
#![allow(missing_docs)]
use reflexo_typst::{diag::print_diagnostics, TypstDocument};
use serde::{Deserialize, Serialize};
pub use tinymist_project::*;
use std::{num::NonZeroUsize, sync::Arc};
@ -150,7 +151,7 @@ impl ServerState {
is_standalone: false,
export: export.clone(),
editor_tx: editor_tx.clone(),
client: Box::new(client.clone().to_untyped()),
client: Arc::new(client.clone().to_untyped()),
analysis: Arc::new(Analysis {
position_encoding: const_config.position_encoding,
allow_overlapping_token: const_config.tokens_overlapping_token_support,
@ -397,15 +398,16 @@ pub struct CompileHandlerImpl {
pub(crate) export: crate::task::ExportTask,
pub(crate) editor_tx: EditorSender,
pub(crate) client: Box<dyn ProjectClient>,
pub(crate) client: Arc<dyn ProjectClient>,
pub(crate) status_revision: Mutex<FxHashMap<ProjectInsId, usize>>,
pub(crate) notified_revision: Mutex<FxHashMap<ProjectInsId, usize>>,
}
pub trait ProjectClient: Send + Sync + 'static {
pub(crate) trait ProjectClient: Send + Sync + 'static {
fn interrupt(&self, event: LspInterrupt);
fn server_event(&self, event: ServerEvent);
fn dev_event(&self, event: DevEvent);
}
impl ProjectClient for LspClient {
@ -416,6 +418,10 @@ impl ProjectClient for LspClient {
fn server_event(&self, event: ServerEvent) {
self.send_event(event);
}
fn dev_event(&self, event: DevEvent) {
self.send_notification::<DevEvent>(&event);
}
}
impl ProjectClient for mpsc::UnboundedSender<LspInterrupt> {
@ -426,6 +432,12 @@ impl ProjectClient for mpsc::UnboundedSender<LspInterrupt> {
fn server_event(&self, _event: ServerEvent) {
log::warn!("ProjectClient: server_event is not implemented for mpsc::UnboundedSender<LspInterrupt>");
}
fn dev_event(&self, _event: DevEvent) {
log::warn!(
"ProjectClient: dev_event is not implemented for mpsc::UnboundedSender<LspInterrupt>"
);
}
}
impl CompileHandlerImpl {
@ -625,7 +637,7 @@ impl CompileHandler<LspCompilerFeat, ProjectInsStateExt> for CompileHandlerImpl
}
self.client.interrupt(LspInterrupt::Compiled(art.clone()));
self.export.signal(art);
self.export.signal(art, &self.client);
#[cfg(feature = "preview")]
if let Some(inner) = self.preview.get(art.id()) {
@ -640,3 +652,24 @@ impl CompileHandler<LspCompilerFeat, ProjectInsStateExt> for CompileHandlerImpl
}
pub type QuerySnapWithStat = (LspQuerySnapshot, QueryStatGuard);
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct DevExportEvent {
pub id: String,
pub when: TaskWhen,
pub need_export: bool,
pub signal: ExportSignal,
pub path: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", tag = "type")]
pub(crate) enum DevEvent {
Export(DevExportEvent),
}
impl lsp_types::notification::Notification for DevEvent {
const METHOD: &'static str = "tinymist/devEvent";
type Params = Self;
}

View file

@ -19,9 +19,9 @@ use typst::visualize::Color;
use super::{FutureFolder, SyncTaskFactory};
use crate::project::{
ApplyProjectTask, CompiledArtifact, EntryReader, ExportHtmlTask, ExportPdfTask, ExportPngTask,
ExportSvgTask, ExportTask as ProjectExportTask, ExportTeXTask, ExportTextTask,
LspCompiledArtifact, ProjectTask, QueryTask, TaskWhen,
ApplyProjectTask, CompiledArtifact, DevEvent, DevExportEvent, EntryReader, ExportHtmlTask,
ExportPdfTask, ExportPngTask, ExportSvgTask, ExportTask as ProjectExportTask, ExportTeXTask,
ExportTextTask, LspCompiledArtifact, ProjectClient, ProjectTask, QueryTask, TaskWhen,
};
use crate::{actor::editor::EditorRequest, tool::word_count};
@ -53,10 +53,14 @@ impl ExportTask {
self.factory.mutate(|data| *data = config);
}
pub fn signal(&self, snap: &LspCompiledArtifact) {
pub(crate) fn signal(
&self,
snap: &LspCompiledArtifact,
client: &std::sync::Arc<(dyn ProjectClient + 'static)>,
) {
let config = self.factory.task();
self.signal_export(snap, &config);
self.signal_export(snap, &config, client);
self.signal_count_word(snap, &config);
}
@ -64,6 +68,7 @@ impl ExportTask {
&self,
artifact: &LspCompiledArtifact,
config: &Arc<ExportUserConfig>,
client: &std::sync::Arc<(dyn ProjectClient + 'static)>,
) -> Option<()> {
let doc = artifact.doc.as_ref()?;
let s = artifact.snap.signal;
@ -77,20 +82,43 @@ impl ExportTask {
TaskWhen::OnDocumentHasTitle => s.by_fs_events && doc.info().title.is_some(),
};
let export_hook = config.development.then_some({
let client = client.clone();
let event = DevEvent::Export(DevExportEvent {
id: artifact.id().to_string(),
when: when.clone(),
need_export,
signal: s,
path: config
.task
.as_export()
.and_then(|t| t.output.clone())
.map(|p| p.to_string()),
});
move || client.dev_event(event)
});
if !need_export {
if let Some(f) = export_hook {
f()
}
return None;
}
log::info!(
"ExportTask(when={when:?}): export for {} with signal: {s:?}",
artifact.id()
);
let rev = artifact.world().revision().get();
let fut = self.export_folder.spawn(rev, || {
let task = config.task.clone();
let artifact = artifact.clone();
Box::pin(async move {
log_err(Self::do_export(task, artifact, None).await);
if let Some(f) = export_hook {
f()
}
Some(())
})
})?;
@ -362,6 +390,8 @@ pub struct ExportUserConfig {
pub export_target: ExportTarget,
pub task: ProjectTask,
pub count_words: bool,
/// Whether to run the server in development mode.
pub development: bool,
}
impl Default for ExportUserConfig {
@ -378,6 +408,7 @@ impl Default for ExportUserConfig {
creation_timestamp: None,
}),
count_words: false,
development: false,
}
}
}

View file

@ -459,7 +459,7 @@ where
is_standalone: true,
export: crate::task::ExportTask::new(handle, Some(editor_tx.clone()), opts.config.export()),
editor_tx,
client: Box::new(intr_tx.clone()),
client: Arc::new(intr_tx.clone()),
analysis: opts.analysis,
status_revision: Mutex::default(),