use serde::{Deserialize, Serialize};
use super::*;
pub struct InitLogOpts {
pub verbose: bool,
pub filter: Option<String>,
pub output: Option<LspClient>,
}
pub fn init_log(
InitLogOpts {
verbose,
filter,
output,
}: InitLogOpts,
) -> anyhow::Result<()> {
use log::LevelFilter::*;
let base_level = if verbose { Info } else { Warn };
let mut builder = env_logger::builder();
if let Some(output) = output {
builder.target(LogNotification::create(output));
}
#[cfg(target_arch = "wasm32")]
{
builder.format(|f, record| {
use std::io::Write;
let ts = tinymist_std::time::utc_now();
write!(f, "[")?;
ts.format_into(f, &tinymist_std::time::Rfc3339)
.map_err(std::io::Error::other)?;
writeln!(
f,
" {level:<5} {module_path} {file_path}:{line} {target}] {args}",
level = record.level(),
module_path = record.module_path().unwrap_or("unknown"),
file_path = record.file().unwrap_or("unknown"),
line = record.line().unwrap_or(0),
target = record.target(),
args = record.args()
)
});
}
builder
.filter_module("tinymist", base_level)
.filter_module("tinymist_preview", base_level)
.filter_module("typlite", base_level)
.filter_module("reflexo", base_level)
.filter_module("sync_ls", base_level)
.filter_module("reflexo_typst2vec::pass::span2vec", Error)
.filter_module("reflexo_typst::diag::console", base_level);
if let Some(f) = filter {
builder.parse_filters(&f);
}
Ok(builder.try_init()?)
}
struct LogNotification(LspClient, Vec<u8>);
impl LogNotification {
fn create(output: LspClient) -> env_logger::Target {
env_logger::Target::Pipe(Box::new(Self(output, vec![])))
}
}
impl std::io::Write for LogNotification {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
if buf.is_empty() {
return Ok(0);
}
self.1.extend_from_slice(buf);
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
let data = String::from_utf8_lossy(self.1.as_slice()).to_string();
self.1.clear();
self.0.send_notification::<Log>(&Log { data });
Ok(())
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct Log {
data: String,
}
impl lsp_types::notification::Notification for Log {
const METHOD: &'static str = "tmLog";
type Params = Self;
}