mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-08-04 02:08:17 +00:00
feat: allow to disable lint or lint on save (#1658)
* feat: allow to disable lint or lint on save * fix: description
This commit is contained in:
parent
39d13c83f6
commit
2709aaf429
7 changed files with 140 additions and 33 deletions
|
@ -12,7 +12,7 @@ use tinymist_analysis::stats::AllocStats;
|
|||
use tinymist_analysis::ty::term_value;
|
||||
use tinymist_analysis::{analyze_expr_, analyze_import_};
|
||||
use tinymist_lint::LintInfo;
|
||||
use tinymist_project::{LspComputeGraph, LspWorld};
|
||||
use tinymist_project::{LspComputeGraph, LspWorld, TaskWhen};
|
||||
use tinymist_std::hash::{hash128, FxDashMap};
|
||||
use tinymist_std::typst::TypstDocument;
|
||||
use tinymist_world::debug_loc::DataSource;
|
||||
|
@ -69,6 +69,8 @@ pub struct Analysis {
|
|||
pub completion_feat: CompletionFeat,
|
||||
/// The editor's color theme.
|
||||
pub color_theme: ColorTheme,
|
||||
/// When to trigger the lint.
|
||||
pub lint: TaskWhen,
|
||||
/// The periscope provider.
|
||||
pub periscope: Option<Arc<dyn PeriscopeProvider + Send + Sync>>,
|
||||
/// The global worker resources for analysis.
|
||||
|
|
|
@ -42,21 +42,8 @@ impl ExportTimings {
|
|||
timing: Option<TaskWhen>,
|
||||
docs: Option<&D>,
|
||||
) -> Option<bool> {
|
||||
let s = snap.signal;
|
||||
let when = timing.unwrap_or(TaskWhen::Never);
|
||||
if !matches!(when, TaskWhen::Never) && s.by_entry_update {
|
||||
return Some(true);
|
||||
}
|
||||
|
||||
match when {
|
||||
TaskWhen::Never => Some(false),
|
||||
TaskWhen::OnType => Some(s.by_mem_events),
|
||||
TaskWhen::OnSave => Some(s.by_fs_events),
|
||||
TaskWhen::OnDocumentHasTitle if s.by_fs_events => {
|
||||
docs.map(|doc| doc.info().title.is_some())
|
||||
}
|
||||
TaskWhen::OnDocumentHasTitle => Some(false),
|
||||
}
|
||||
snap.signal
|
||||
.should_run_task(timing.unwrap_or_default(), docs)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use core::fmt;
|
||||
|
||||
use crate::{CompilerFeat, CompilerWorld, EntryReader, TaskInputs};
|
||||
use crate::{args::TaskWhen, CompilerFeat, CompilerWorld, EntryReader, TaskInputs};
|
||||
use ecow::EcoString;
|
||||
use tinymist_std::typst::TypstDocument;
|
||||
|
||||
|
@ -43,6 +43,38 @@ impl ExportSignal {
|
|||
self.by_fs_events |= other.by_fs_events;
|
||||
self.by_entry_update |= other.by_entry_update;
|
||||
}
|
||||
|
||||
pub fn should_run_task_dyn(
|
||||
&self,
|
||||
when: TaskWhen,
|
||||
docs: Option<&TypstDocument>,
|
||||
) -> Option<bool> {
|
||||
match docs {
|
||||
Some(TypstDocument::Paged(doc)) => self.should_run_task(when, Some(doc.as_ref())),
|
||||
Some(TypstDocument::Html(doc)) => self.should_run_task(when, Some(doc.as_ref())),
|
||||
None => self.should_run_task::<typst::layout::PagedDocument>(when, None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn should_run_task<D: typst::Document>(
|
||||
&self,
|
||||
when: TaskWhen,
|
||||
docs: Option<&D>,
|
||||
) -> Option<bool> {
|
||||
if !matches!(when, TaskWhen::Never) && self.by_entry_update {
|
||||
return Some(true);
|
||||
}
|
||||
|
||||
match when {
|
||||
TaskWhen::Never => Some(false),
|
||||
TaskWhen::OnType => Some(self.by_mem_events),
|
||||
TaskWhen::OnSave => Some(self.by_fs_events),
|
||||
TaskWhen::OnDocumentHasTitle if self.by_fs_events => {
|
||||
docs.map(|doc| doc.info().title.is_some())
|
||||
}
|
||||
TaskWhen::OnDocumentHasTitle => Some(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A snapshot of the project and compilation state.
|
||||
|
|
|
@ -90,6 +90,8 @@ pub struct Config {
|
|||
pub completion: CompletionFeat,
|
||||
/// Tinymist's preview features.
|
||||
pub preview: PreviewFeat,
|
||||
/// When to trigger the lint checks.
|
||||
pub lint: LintFeat,
|
||||
|
||||
/// Specifies the cli font options
|
||||
pub font_opts: CompileFontArgs,
|
||||
|
@ -318,6 +320,7 @@ impl Config {
|
|||
assign_config!(formatter_indent_size := "formatterIndentSize"?: Option<u32>);
|
||||
assign_config!(output_path := "outputPath"?: PathPattern);
|
||||
assign_config!(preview := "preview"?: PreviewFeat);
|
||||
assign_config!(lint := "preview"?: LintFeat);
|
||||
assign_config!(semantic_tokens := "semanticTokens"?: SemanticTokensMode);
|
||||
assign_config!(support_html_in_markdown := "supportHtmlInMarkdown"?: bool);
|
||||
assign_config!(system_fonts := "systemFonts"?: Option<bool>);
|
||||
|
@ -788,6 +791,26 @@ pub struct PreviewFeat {
|
|||
pub background: BackgroundPreviewOpts,
|
||||
}
|
||||
|
||||
/// The lint features.
|
||||
#[derive(Debug, Default, Clone, Deserialize)]
|
||||
pub struct LintFeat {
|
||||
/// Whether to enable linting.
|
||||
pub enabled: Option<bool>,
|
||||
/// When to trigger the lint checks.
|
||||
pub when: Option<TaskWhen>,
|
||||
}
|
||||
|
||||
impl LintFeat {
|
||||
/// When to trigger the lint checks.
|
||||
pub fn when(&self) -> TaskWhen {
|
||||
if matches!(self.enabled, Some(false)) {
|
||||
return TaskWhen::Never;
|
||||
}
|
||||
|
||||
self.when.unwrap_or(TaskWhen::OnSave)
|
||||
}
|
||||
}
|
||||
|
||||
/// Options for browsing preview.
|
||||
#[derive(Debug, Default, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
|
|
@ -161,6 +161,7 @@ impl ServerState {
|
|||
Some("dark") => tinymist_query::ColorTheme::Dark,
|
||||
_ => tinymist_query::ColorTheme::Light,
|
||||
},
|
||||
lint: config.lint.when(),
|
||||
periscope: periscope_args.map(|args| {
|
||||
let r = TypstPeriscopeProvider(PeriscopeRenderer::new(args));
|
||||
Arc::new(r) as Arc<dyn PeriscopeProvider + Send + Sync>
|
||||
|
@ -429,36 +430,54 @@ impl CompileHandlerImpl {
|
|||
.log_error("failed to send diagnostics");
|
||||
}
|
||||
|
||||
fn notify_diagnostics(&self, snap: &LspCompiledArtifact) {
|
||||
fn notify_diagnostics(&self, art: &LspCompiledArtifact) {
|
||||
let dv = ProjVersion {
|
||||
id: snap.id().clone(),
|
||||
revision: snap.world().revision().get(),
|
||||
id: art.id().clone(),
|
||||
revision: art.world().revision().get(),
|
||||
};
|
||||
// todo: better way to remove diagnostics
|
||||
let valid = !snap.world().entry_state().is_inactive();
|
||||
let valid = !art.world().entry_state().is_inactive();
|
||||
if !valid {
|
||||
self.push_diagnostics(dv, None);
|
||||
return;
|
||||
}
|
||||
|
||||
let snap = snap.clone();
|
||||
let editor_tx = self.editor_tx.clone();
|
||||
let analysis = self.analysis.clone();
|
||||
rayon::spawn(move || {
|
||||
let world = snap.world().clone();
|
||||
let mut ctx = analysis.enter(world);
|
||||
let should_lint = art
|
||||
.snap
|
||||
.signal
|
||||
.should_run_task_dyn(self.analysis.lint, art.doc.as_ref())
|
||||
.unwrap_or_default();
|
||||
|
||||
// todo: check all errors in this file
|
||||
let Some(diagnostics) = CheckRequest { snap }.request(&mut ctx) else {
|
||||
return;
|
||||
};
|
||||
if !should_lint {
|
||||
let enc = self.analysis.position_encoding;
|
||||
let diagnostics =
|
||||
tinymist_query::convert_diagnostics(art.world(), art.diagnostics(), enc);
|
||||
|
||||
log::trace!("notify diagnostics({dv:?}): {diagnostics:#?}");
|
||||
|
||||
editor_tx
|
||||
self.editor_tx
|
||||
.send(EditorRequest::Diag(dv, Some(diagnostics)))
|
||||
.log_error("failed to send diagnostics");
|
||||
});
|
||||
} else {
|
||||
let snap = art.clone();
|
||||
let editor_tx = self.editor_tx.clone();
|
||||
let analysis = self.analysis.clone();
|
||||
rayon::spawn(move || {
|
||||
let world = snap.world().clone();
|
||||
let mut ctx = analysis.enter(world);
|
||||
|
||||
// todo: check all errors in this file
|
||||
let Some(diagnostics) = CheckRequest { snap }.request(&mut ctx) else {
|
||||
return;
|
||||
};
|
||||
|
||||
log::trace!("notify diagnostics({dv:?}): {diagnostics:#?}");
|
||||
|
||||
editor_tx
|
||||
.send(EditorRequest::Diag(dv, Some(diagnostics)))
|
||||
.log_error("failed to send diagnostics");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue