Repository: typst/typst
File: crates/typst-cli/src/watch.rs (Rust)

Code before:
            if relevant || self.missing.iter().any(|path| path.exists()) {
                return Ok(());
            }
        }
    }

    /// Whether a watch event is relevant for compilation.
    fn is_event_relevant(&self, event: &notify::Event) -> bool {
        let type_relevant = match &event.kind {
            notify::EventKind::Any => true,
            notify::EventKind::Access(_) => false,
            notify::EventKind::Create(_) => true,
            notify::EventKind::Modify(kind) => match kind {
                notify::event::ModifyKind::Any => true,
                notify::event::ModifyKind::Data(_) => true,
                notify::event::ModifyKind::Metadata(_) => false,
                notify::event::ModifyKind::Name(_) => true,
                notify::event::ModifyKind::Other => false,
            },
            notify::EventKind::Remove(_) => true,
            notify::EventKind::Other => false,
        };

        // Never recompile because the output file changed.
        type_relevant
            && !event
                .paths
                .iter()
                .all(|path| is_same_file(path, &self.output).unwrap_or(false))
    }
}

/// The status in which the watcher can be.
pub enum Status {
    Compiling,
    Success(std::time::Duration),
    PartialSuccess(std::time::Duration),
    Error,
}

impl Status {
    /// Clear the terminal and render the status message.
    pub fn print(&self, config: &CompileConfig) -> io::Result<()> {
        let timestamp = chrono::offset::Local::now().format("%H:%M:%S");
        let color = self.color();

        let mut out = terminal::out();
        out.clear_screen()?;

        out.set_color(&color)?;
        write!(out, "watching")?;

Review comment (suggestion):
Relying on short-circuit here is a bit too subtle in my opinion. I'd suggest using `if !type_relevant { return false; }` above and adding a comment explaining that the order matters.

Code after:
                // FIXME: This doesn't work properly for multifile image export.
                if event
                    .paths
                    .iter()
                    .all(|path| is_same_file(path, &self.output).unwrap_or(false))
                {
                    continue;
                }

                relevant = true;
            }

            // If we found a relevant event or if any of the missing files now
            // exists, stop waiting.
            if relevant || self.missing.iter().any(|path| path.exists()) {
                return Ok(());
            }
        }
    }
}

/// Whether a kind of watch event is relevant for compilation.
fn is_relevant_event_kind(kind: &notify::EventKind) -> bool {
    match kind {
        notify::EventKind::Any => true,
        notify::EventKind::Access(_) => false,
        notify::EventKind::Create(_) => true,
        notify::EventKind::Modify(kind) => match kind {
            notify::event::ModifyKind::Any => true,
            notify::event::ModifyKind::Data(_) => true,
            notify::event::ModifyKind::Metadata(_) => false,
            notify::event::ModifyKind::Name(_) => true,
            notify::event::ModifyKind::Other => false,
        },
        notify::EventKind::Remove(_) => true,
        notify::EventKind::Other => false,
    }
}

/// The status in which the watcher can be.
pub enum Status {
    Compiling,
    Success(std::time::Duration),
    PartialSuccess(std::time::Duration),
    Error,
}

impl Status {
    /// Clear the terminal and render the status message.
    pub fn print(&self, config: &CompileConfig) -> io::Result<()> {
        let timestamp = chrono::offset::Local::now().format("%H:%M:%S");