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.rs180
1 files changed, 59 insertions, 121 deletions
diff --git a/helix-term/src/health.rs b/helix-term/src/health.rs
index 52112bf9..54789b89 100644
--- a/helix-term/src/health.rs
+++ b/helix-term/src/health.rs
@@ -1,33 +1,22 @@
use crate::config::{Config, ConfigLoadError};
+use crossterm::{
+ style::{Color, Print, Stylize},
+ tty::IsTty,
+};
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 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",
}
}
}
@@ -151,15 +134,6 @@ 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();
@@ -186,27 +160,29 @@ fn languages(selection: Option<HashSet<String>>) -> std::io::Result<()> {
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 +190,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(())
}
@@ -329,12 +289,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 +307,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 +314,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 +330,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 +346,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 +380,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())?;