Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-term/src/health.rs')
| -rw-r--r-- | helix-term/src/health.rs | 211 |
1 files changed, 70 insertions, 141 deletions
diff --git a/helix-term/src/health.rs b/helix-term/src/health.rs index 52112bf9..5f201926 100644 --- a/helix-term/src/health.rs +++ b/helix-term/src/health.rs @@ -1,33 +1,22 @@ -use crate::config::{Config, ConfigLoadError}; -use helix_core::config::{default_lang_config, user_lang_config}; -use helix_loader::grammar::load_runtime_file; -use std::{ - collections::HashSet, - io::{IsTerminal, Write}, -}; -use termina::{ - style::{ColorSpec, StyleExt as _, Stylized}, - Terminal as _, +use crossterm::{ + style::{Color, Print, Stylize}, + tty::IsTty, }; +use helix_core::config::{default_syntax_loader, user_syntax_loader}; +use helix_loader::grammar::load_runtime_file; +use helix_view::clipboard::get_clipboard_provider; +use std::io::Write; #[derive(Copy, Clone)] pub enum TsFeature { Highlight, TextObject, AutoIndent, - Tags, - RainbowBracket, } impl TsFeature { pub fn all() -> &'static [Self] { - &[ - Self::Highlight, - Self::TextObject, - Self::AutoIndent, - Self::Tags, - Self::RainbowBracket, - ] + &[Self::Highlight, Self::TextObject, Self::AutoIndent] } pub fn runtime_filename(&self) -> &'static str { @@ -35,8 +24,6 @@ impl TsFeature { Self::Highlight => "highlights.scm", Self::TextObject => "textobjects.scm", Self::AutoIndent => "indents.scm", - Self::Tags => "tags.scm", - Self::RainbowBracket => "rainbows.scm", } } @@ -45,8 +32,6 @@ impl TsFeature { Self::Highlight => "Syntax Highlighting", Self::TextObject => "Treesitter Textobjects", Self::AutoIndent => "Auto Indent", - Self::Tags => "Code Navigation Tags", - Self::RainbowBracket => "Rainbow Brackets", } } @@ -55,8 +40,6 @@ impl TsFeature { Self::Highlight => "Highlight", Self::TextObject => "Textobject", Self::AutoIndent => "Indent", - Self::Tags => "Tags", - Self::RainbowBracket => "Rainbow", } } } @@ -70,6 +53,7 @@ pub fn general() -> std::io::Result<()> { let lang_file = helix_loader::lang_config_file(); let log_file = helix_loader::log_file(); let rt_dirs = helix_loader::runtime_dirs(); + let clipboard_provider = get_clipboard_provider(); if config_file.exists() { writeln!(stdout, "Config file: {}", config_file.display())?; @@ -108,6 +92,7 @@ pub fn general() -> std::io::Result<()> { writeln!(stdout, "{}", msg.yellow())?; } } + writeln!(stdout, "Clipboard provider: {}", clipboard_provider.name())?; Ok(()) } @@ -116,19 +101,8 @@ pub fn clipboard() -> std::io::Result<()> { let stdout = std::io::stdout(); let mut stdout = stdout.lock(); - let config = match Config::load_default() { - Ok(config) => config, - Err(ConfigLoadError::Error(err)) if err.kind() == std::io::ErrorKind::NotFound => { - Config::default() - } - Err(err) => { - writeln!(stdout, "{}", "Configuration file malformed".red())?; - writeln!(stdout, "{}", err)?; - return Ok(()); - } - }; - - match config.editor.clipboard_provider.name().as_ref() { + let board = get_clipboard_provider(); + match board.name().as_ref() { "none" => { writeln!( stdout, @@ -151,19 +125,10 @@ pub fn clipboard() -> std::io::Result<()> { } pub fn languages_all() -> std::io::Result<()> { - languages(None) -} - -pub fn languages_selection() -> std::io::Result<()> { - let selection = helix_loader::grammar::get_grammar_names().unwrap_or_default(); - languages(selection) -} - -fn languages(selection: Option<HashSet<String>>) -> std::io::Result<()> { let stdout = std::io::stdout(); let mut stdout = stdout.lock(); - let mut syn_loader_conf = match user_lang_config() { + let mut syn_loader_conf = match user_syntax_loader() { Ok(conf) => conf, Err(err) => { let stderr = std::io::stderr(); @@ -176,37 +141,39 @@ fn languages(selection: Option<HashSet<String>>) -> std::io::Result<()> { err )?; writeln!(stderr, "{}", "Using default language config".yellow())?; - default_lang_config() + default_syntax_loader() } }; - let mut headings = vec!["Language", "Language servers", "Debug adapter", "Formatter"]; + let mut headings = vec!["Language", "LSP", "DAP", "Formatter"]; for feat in TsFeature::all() { headings.push(feat.short_title()) } - let terminal_cols = termina::PlatformTerminal::new() - .and_then(|terminal| terminal.get_dimensions()) - .map(|size| size.cols) - .unwrap_or(80); + let terminal_cols = crossterm::terminal::size().map(|(c, _)| c).unwrap_or(80); let column_width = terminal_cols as usize / headings.len(); - let is_terminal = std::io::stdout().is_terminal(); + let is_terminal = std::io::stdout().is_tty(); - let fit = |s: &str| -> Stylized<'static> { - format!( - "{:column_width$}", - s.get(..column_width - 2) + let column = |item: &str, color: Color| { + let mut data = format!( + "{:width$}", + item.get(..column_width - 2) .map(|s| format!("{}…", s)) - .unwrap_or_else(|| s.to_string()) - ) - .stylized() + .unwrap_or_else(|| item.to_string()), + width = column_width, + ); + if is_terminal { + data = data.stylize().with(color).to_string(); + } + + // We can't directly use println!() because of + // https://github.com/crossterm-rs/crossterm/issues/589 + let _ = crossterm::execute!(std::io::stdout(), Print(data)); }; - let color = |s: Stylized<'static>, c: ColorSpec| if is_terminal { s.foreground(c) } else { s }; - let bold = |s: Stylized<'static>| if is_terminal { s.bold() } else { s }; for heading in headings { - write!(stdout, "{}", bold(fit(heading)))?; + column(heading, Color::White); } writeln!(stdout)?; @@ -214,66 +181,50 @@ fn languages(selection: Option<HashSet<String>>) -> std::io::Result<()> { .language .sort_unstable_by_key(|l| l.language_id.clone()); - let check_binary_with_name = |cmd: Option<(&str, &str)>| match cmd { - Some((name, cmd)) => match helix_stdx::env::which(cmd) { - Ok(_) => color(fit(&format!("✓ {}", name)), ColorSpec::BRIGHT_GREEN), - Err(_) => color(fit(&format!("✘ {}", name)), ColorSpec::BRIGHT_RED), + let check_binary = |cmd: Option<&str>| match cmd { + Some(cmd) => match helix_stdx::env::which(cmd) { + Ok(_) => column(&format!("✓ {}", cmd), Color::Green), + Err(_) => column(&format!("✘ {}", cmd), Color::Red), }, - None => color(fit("None"), ColorSpec::BRIGHT_YELLOW), + None => column("None", Color::Yellow), }; - let check_binary = |cmd: Option<&str>| check_binary_with_name(cmd.map(|cmd| (cmd, cmd))); - for lang in &syn_loader_conf.language { - if selection - .as_ref() - .is_some_and(|s| !s.contains(&lang.language_id)) - { - continue; - } - - write!(stdout, "{}", fit(&lang.language_id))?; + column(&lang.language_id, Color::Reset); let mut cmds = lang.language_servers.iter().filter_map(|ls| { syn_loader_conf .language_server .get(&ls.name) - .map(|config| (ls.name.as_str(), config.command.as_str())) + .map(|config| config.command.as_str()) }); - write!(stdout, "{}", check_binary_with_name(cmds.next()))?; + check_binary(cmds.next()); let dap = lang.debugger.as_ref().map(|dap| dap.command.as_str()); - write!(stdout, "{}", check_binary(dap))?; + check_binary(dap); let formatter = lang .formatter .as_ref() .map(|formatter| formatter.command.as_str()); - write!(stdout, "{}", check_binary(formatter))?; + check_binary(formatter); for ts_feat in TsFeature::all() { match load_runtime_file(&lang.language_id, ts_feat.runtime_filename()).is_ok() { - true => write!(stdout, "{}", color(fit("✓"), ColorSpec::BRIGHT_GREEN))?, - false => write!(stdout, "{}", color(fit("✘"), ColorSpec::BRIGHT_RED))?, + true => column("✓", Color::Green), + false => column("✘", Color::Red), } } writeln!(stdout)?; for cmd in cmds { - write!(stdout, "{}", fit(""))?; - writeln!(stdout, "{}", check_binary_with_name(Some(cmd)))?; + column("", Color::Reset); + check_binary(Some(cmd)); + writeln!(stdout)?; } } - if selection.is_some() { - writeln!( - stdout, - "\nThis list is filtered according to the 'use-grammars' option in languages.toml file.\n\ - To see the full list, use the '--health all' or '--health all-languages' option." - )?; - } - Ok(()) } @@ -283,7 +234,7 @@ pub fn language(lang_str: String) -> std::io::Result<()> { let stdout = std::io::stdout(); let mut stdout = stdout.lock(); - let syn_loader_conf = match user_lang_config() { + let syn_loader_conf = match user_syntax_loader() { Ok(conf) => conf, Err(err) => { let stderr = std::io::stderr(); @@ -296,7 +247,7 @@ pub fn language(lang_str: String) -> std::io::Result<()> { err )?; writeln!(stderr, "{}", "Using default language config".yellow())?; - default_lang_config() + default_syntax_loader() } }; @@ -329,12 +280,10 @@ pub fn language(lang_str: String) -> std::io::Result<()> { probe_protocols( "language server", - lang.language_servers.iter().filter_map(|ls| { - syn_loader_conf - .language_server - .get(&ls.name) - .map(|config| (ls.name.as_str(), config.command.as_str())) - }), + lang.language_servers + .iter() + .filter_map(|ls| syn_loader_conf.language_server.get(&ls.name)) + .map(|config| config.command.as_str()), )?; probe_protocol( @@ -349,8 +298,6 @@ pub fn language(lang_str: String) -> std::io::Result<()> { .map(|formatter| formatter.command.to_string()), )?; - probe_parser(lang.grammar.as_ref().unwrap_or(&lang.language_id))?; - for ts_feat in TsFeature::all() { probe_treesitter_feature(&lang_str, *ts_feat)? } @@ -358,20 +305,8 @@ pub fn language(lang_str: String) -> std::io::Result<()> { Ok(()) } -fn probe_parser(grammar_name: &str) -> std::io::Result<()> { - let stdout = std::io::stdout(); - let mut stdout = stdout.lock(); - - write!(stdout, "Tree-sitter parser: ")?; - - match helix_loader::grammar::get_language(grammar_name) { - Ok(Some(_)) => writeln!(stdout, "{}", "✓".green()), - Ok(None) | Err(_) => writeln!(stdout, "{}", "None".yellow()), - } -} - /// Display diagnostics about multiple LSPs and DAPs. -fn probe_protocols<'a, I: Iterator<Item = (&'a str, &'a str)> + 'a>( +fn probe_protocols<'a, I: Iterator<Item = &'a str> + 'a>( protocol_name: &str, server_cmds: I, ) -> std::io::Result<()> { @@ -386,12 +321,12 @@ fn probe_protocols<'a, I: Iterator<Item = (&'a str, &'a str)> + 'a>( } writeln!(stdout)?; - for (name, cmd) in server_cmds { - let (diag, icon) = match helix_stdx::env::which(cmd) { + for cmd in server_cmds { + let (path, icon) = match helix_stdx::env::which(cmd) { Ok(path) => (path.display().to_string().green(), "✓".green()), Err(_) => (format!("'{}' not found in $PATH", cmd).red(), "✘".red()), }; - writeln!(stdout, " {} {}: {}", icon, name, diag)?; + writeln!(stdout, " {} {}: {}", icon, cmd, path)?; } Ok(()) @@ -402,18 +337,19 @@ fn probe_protocol(protocol_name: &str, server_cmd: Option<String>) -> std::io::R let stdout = std::io::stdout(); let mut stdout = stdout.lock(); - write!(stdout, "Configured {}:", protocol_name)?; - let Some(cmd) = server_cmd else { - writeln!(stdout, "{}", " None".yellow())?; - return Ok(()); + let cmd_name = match server_cmd { + Some(ref cmd) => cmd.as_str().green(), + None => "None".yellow(), }; - writeln!(stdout)?; + writeln!(stdout, "Configured {}: {}", protocol_name, cmd_name)?; - let (diag, icon) = match helix_stdx::env::which(&cmd) { - Ok(path) => (path.display().to_string().green(), "✓".green()), - Err(_) => (format!("'{}' not found in $PATH", cmd).red(), "✘".red()), - }; - writeln!(stdout, " {} {}", icon, diag)?; + if let Some(cmd) = server_cmd { + let path = match helix_stdx::env::which(&cmd) { + Ok(path) => path.display().to_string().green(), + Err(_) => format!("'{}' not found in $PATH", cmd).red(), + }; + writeln!(stdout, "Binary for {}: {}", protocol_name, path)?; + } Ok(()) } @@ -435,16 +371,9 @@ fn probe_treesitter_feature(lang: &str, feature: TsFeature) -> std::io::Result<( pub fn print_health(health_arg: Option<String>) -> std::io::Result<()> { match health_arg.as_deref() { - Some("languages") => languages_selection()?, - Some("all-languages") => languages_all()?, + Some("languages") => languages_all()?, Some("clipboard") => clipboard()?, - None => { - general()?; - clipboard()?; - writeln!(std::io::stdout().lock())?; - languages_selection()?; - } - Some("all") => { + None | Some("all") => { general()?; clipboard()?; writeln!(std::io::stdout().lock())?; |