use crate::{chunk::Chunk, options::Options};
use phf::phf_map;
use smallvec::SmallVec;
use smol_str::{format_smolstr, SmolStr, SmolStrBuilder};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum MatchKind {
Generic,
Indicator,
ProjectManifest,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Language {
Agda,
Assembly,
Awk,
CCpp,
CSharp,
Chapel,
Clojure,
Cobol,
CoffeeScript,
CommonLisp,
Config,
Css,
D,
Dart,
Dhall,
Eiffel,
Elixir,
Elm,
Erlang,
FSharp,
Forth,
Fortran,
Go,
Haskell,
Haxe,
Html,
Idris,
Java,
JavaScript,
Julia,
Kotlin,
LaTeX,
Lua,
Nim,
Nix,
Nmap,
ObjectiveC,
OCaml,
Pascal,
Perl,
Php,
PowerShell,
Prolog,
Python,
R,
Racket,
Ruby,
Rust,
Scala,
Shell,
SmallTalk,
Swift,
Tcl,
TypeScript,
Unison,
Vala,
Verilog,
Vhdl,
Zig,
}
#[allow(dead_code)]
pub struct LanguageInfo {
pub icon: &'static str,
pub color: &'static str,
pub cterm_color: &'static str,
pub name: &'static str,
pub lang: Language,
pub kind: MatchKind,
}
static MANIFEST_MAP: phf::Map<&'static str, LanguageInfo> = phf_map! {
".agda" => LanguageInfo { icon: "A", color: "#F1D352", cterm_color: "221", name: "Agda", lang: Language::Agda, kind: MatchKind::Indicator },
".lagda" => LanguageInfo { icon: "A", color: "#F1D352", cterm_color: "221", name: "Agda", lang: Language::Agda, kind: MatchKind::Indicator },
".asm" => LanguageInfo { icon: "", color: "#6E8493", cterm_color: "102", name: "Assembly", lang: Language::Assembly, kind: MatchKind::Generic },
".awk" => LanguageInfo { icon: "", color: "#E5E5E5", cterm_color: "254", name: "Awk", lang: Language::Awk, kind: MatchKind::Indicator },
".mawk" => LanguageInfo { icon: "", color: "#E5E5E5", cterm_color: "254", name: "Awk", lang: Language::Awk, kind: MatchKind::Indicator },
".gawk" => LanguageInfo { icon: "", color: "#E5E5E5", cterm_color: "254", name: "Awk", lang: Language::Awk, kind: MatchKind::Indicator },
"Makefile" => LanguageInfo { icon: "", color: "#6792c9", cterm_color: "67", name: "C/C++", lang: Language::CCpp, kind: MatchKind::Generic },
"Makefile.am" => LanguageInfo { icon: "", color: "#6792c9", cterm_color: "67", name: "C/C++", lang: Language::CCpp, kind: MatchKind::Generic },
"CMakeLists.txt" => LanguageInfo { icon: "", color: "#6792c9", cterm_color: "67", name: "C/C++", lang: Language::CCpp, kind: MatchKind::ProjectManifest },
"meson.build" => LanguageInfo { icon: "", color: "#6792c9", cterm_color: "67", name: "C/C++", lang: Language::CCpp, kind: MatchKind::Generic },
"autogen.sh" => LanguageInfo { icon: "", color: "#6792c9", cterm_color: "67", name: "C/C++", lang: Language::CCpp, kind: MatchKind::Generic },
"configure.ac" => LanguageInfo { icon: "", color: "#6792c9", cterm_color: "67", name: "C/C++", lang: Language::CCpp, kind: MatchKind::Generic },
".c" => LanguageInfo { icon: "", color: "#6792c9", cterm_color: "67", name: "C/C++", lang: Language::CCpp, kind: MatchKind::Indicator },
".h" => LanguageInfo { icon: "", color: "#6792c9", cterm_color: "67", name: "C/C++", lang: Language::CCpp, kind: MatchKind::Indicator },
".inc" => LanguageInfo { icon: "", color: "#B3B3B3", cterm_color: "249", name: "C/C++ Header", lang: Language::CCpp, kind: MatchKind::Generic },
".cpp" => LanguageInfo { icon: "", color: "#6792c9", cterm_color: "67", name: "C/C++", lang: Language::CCpp, kind: MatchKind::Indicator },
".hpp" => LanguageInfo { icon: "", color: "#6792c9", cterm_color: "67", name: "C/C++", lang: Language::CCpp, kind: MatchKind::Indicator },
".cxx" => LanguageInfo { icon: "", color: "#6792c9", cterm_color: "67", name: "C++", lang: Language::CCpp, kind: MatchKind::Indicator },
".cc" => LanguageInfo { icon: "", color: "#6792c9", cterm_color: "67", name: "C++", lang: Language::CCpp, kind: MatchKind::Indicator },
".csproj" => LanguageInfo { icon: "", color: "#5a29a4", cterm_color: "99", name: "C#", lang: Language::CSharp, kind: MatchKind::ProjectManifest},
".cs" => LanguageInfo { icon: "", color: "#5a29a4", cterm_color: "99", name: "C#", lang: Language::CSharp, kind: MatchKind::Indicator },
".chpl" => LanguageInfo { icon: "C", color: "#8dc63f", cterm_color: "113", name: "Chapel", lang: Language::Chapel, kind: MatchKind::Indicator },
".clj" => LanguageInfo { icon: "", color: "#82b131", cterm_color: "106", name: "Clojure", lang: Language::Clojure, kind: MatchKind::Indicator },
".cljs" => LanguageInfo { icon: "", color: "#82b131", cterm_color: "106", name: "ClojureScript", lang: Language::Clojure, kind: MatchKind::Indicator },
".cljc" => LanguageInfo { icon: "", color: "#82b131", cterm_color: "106", name: "Clojure", lang: Language::Clojure, kind: MatchKind::Indicator },
".edn" => LanguageInfo { icon: "", color: "#82b131", cterm_color: "106", name: "EDN", lang: Language::Clojure, kind: MatchKind::Generic },
".cbl" => LanguageInfo { icon: "C", color: "#005ca5", cterm_color: "25", name: "COBOL", lang: Language::Cobol, kind: MatchKind::Indicator},
"Cakefile" => LanguageInfo { icon: "", color: "#244776", cterm_color: "24", name: "CoffeeScript", lang: Language::CoffeeScript, kind: MatchKind::Indicator },
".coffee" => LanguageInfo { icon: "", color: "#244776", cterm_color: "24", name: "CoffeeScript", lang: Language::CoffeeScript, kind: MatchKind::Indicator },
".asd" => LanguageInfo { icon: "", color: "#b31a23", cterm_color: "124", name: "Common Lisp", lang: Language::CommonLisp, kind: MatchKind::ProjectManifest},
".lisp" => LanguageInfo { icon: "", color: "#b31a23", cterm_color: "124", name: "Lisp", lang: Language::CommonLisp, kind: MatchKind::Indicator },
".cl" => LanguageInfo { icon: "", color: "#b31a23", cterm_color: "124", name: "Common Lisp", lang: Language::CommonLisp, kind: MatchKind::Indicator },
".config" => LanguageInfo { icon: "", color: "#A0A0A0", cterm_color: "247", name: "Config", lang: Language::Config, kind: MatchKind::Generic },
".conf" => LanguageInfo { icon: "", color: "#A0A0A0", cterm_color: "247", name: "Config", lang: Language::Config, kind: MatchKind::Generic },
".cfg" => LanguageInfo { icon: "", color: "#A0A0A0", cterm_color: "247", name: "Config", lang: Language::Config, kind: MatchKind::Generic },
".ini" => LanguageInfo { icon: "", color: "#A0A0A0", cterm_color: "247", name: "INI", lang: Language::Config, kind: MatchKind::Generic },
".toml" => LanguageInfo { icon: "", color: "#A0A0A0", cterm_color: "247", name: "TOML", lang: Language::Config, kind: MatchKind::Generic },
".yaml" => LanguageInfo { icon: "", color: "#A0A0A0", cterm_color: "247", name: "YAML", lang: Language::Config, kind: MatchKind::Generic },
".yml" => LanguageInfo { icon: "", color: "#A0A0A0", cterm_color: "247", name: "YAML", lang: Language::Config, kind: MatchKind::Generic },
".json" => LanguageInfo { icon: "", color: "#E5E5E5", cterm_color: "254", name: "JSON", lang: Language::Config, kind: MatchKind::Generic },
".css" => LanguageInfo { icon: "", color: "#563d7c", cterm_color: "98", name: "CSS", lang: Language::Css, kind: MatchKind::Indicator },
"dub.json" => LanguageInfo { icon: "D", color: "#ba595e", cterm_color: "131", name: "D", lang: Language::D, kind: MatchKind::ProjectManifest},
"dub.sdl" => LanguageInfo { icon: "D", color: "#ba595e", cterm_color: "131", name: "D", lang: Language::D, kind: MatchKind::ProjectManifest},
".d" => LanguageInfo { icon: "D", color: "#ba595e", cterm_color: "131", name: "D", lang: Language::D, kind: MatchKind::Indicator },
"pubspec.yaml" => LanguageInfo { icon: "", color: "#0175c2", cterm_color: "32", name: "Dart", lang: Language::Dart, kind: MatchKind::ProjectManifest},
".dart" => LanguageInfo { icon: "", color: "#0175c2", cterm_color: "32", name: "Dart", lang: Language::Dart, kind: MatchKind::Indicator },
".dhall" => LanguageInfo { icon: "D", color: "#174B59", cterm_color: "23", name: "Dhall", lang: Language::Dhall, kind: MatchKind::Indicator },
".ecf" => LanguageInfo { icon: "E", color: "#0C8B95", cterm_color: "30", name: "Eiffel", lang: Language::Eiffel, kind: MatchKind::ProjectManifest},
"mix.exs" => LanguageInfo { icon: "", color: "#4b275f", cterm_color: "54", name: "Elixir", lang: Language::Elixir, kind: MatchKind::ProjectManifest},
".ex" => LanguageInfo { icon: "", color: "#4b275f", cterm_color: "54", name: "Elixir", lang: Language::Elixir, kind: MatchKind::Indicator },
".exs" => LanguageInfo { icon: "", color: "#4b275f", cterm_color: "54", name: "Elixir", lang: Language::Elixir, kind: MatchKind::Indicator },
"elm.json" => LanguageInfo { icon: "", color: "#60b5cc", cterm_color: "74", name: "Elm", lang: Language::Elm, kind: MatchKind::ProjectManifest},
".erl" => LanguageInfo { icon: "", color: "#b83998", cterm_color: "133", name: "Erlang", lang: Language::Erlang, kind: MatchKind::Indicator },
".hrl" => LanguageInfo { icon: "", color: "#b83998", cterm_color: "133", name: "Erlang", lang: Language::Erlang, kind: MatchKind::Indicator},
".fsproj" => LanguageInfo { icon: "", color: "#378bba", cterm_color: "38", name: "F#", lang: Language::FSharp, kind: MatchKind::ProjectManifest},
".fs" => LanguageInfo { icon: "", color: "#378bba", cterm_color: "38", name: "F#", lang: Language::FSharp, kind: MatchKind::Indicator },
".fsx" => LanguageInfo { icon: "", color: "#378bba", cterm_color: "38", name: "F#", lang: Language::FSharp, kind: MatchKind::Indicator },
".fth" => LanguageInfo { icon: "F", color: "#341708", cterm_color: "52", name: "Forth", lang: Language::Forth, kind: MatchKind::Generic },
".f90" => LanguageInfo { icon: "", color: "#734f96", cterm_color: "98", name: "Fortran", lang: Language::Fortran, kind: MatchKind::Indicator},
".f95" => LanguageInfo { icon: "", color: "#734f96", cterm_color: "98", name: "Fortran", lang: Language::Fortran, kind: MatchKind::Indicator},
".f" => LanguageInfo { icon: "", color: "#734f96", cterm_color: "98", name: "Fortran", lang: Language::Fortran, kind: MatchKind::Indicator},
"go.mod" => LanguageInfo { icon: "", color: "#00add8", cterm_color: "38", name: "Go", lang: Language::Go, kind: MatchKind::ProjectManifest},
".go" => LanguageInfo { icon: "", color: "#00add8", cterm_color: "38", name: "Go", lang: Language::Go, kind: MatchKind::Indicator },
".cabal" => LanguageInfo { icon: "", color: "#5e5086", cterm_color: "61", name: "Haskell", lang: Language::Haskell, kind: MatchKind::ProjectManifest},
"stack.yaml" => LanguageInfo { icon: "", color: "#5e5086", cterm_color: "61", name: "Haskell", lang: Language::Haskell, kind: MatchKind::ProjectManifest},
"Setup.hs" => LanguageInfo { icon: "", color: "#5e5086", cterm_color: "61", name: "Haskell", lang: Language::Haskell, kind: MatchKind::Indicator },
".hs" => LanguageInfo { icon: "", color: "#5e5086", cterm_color: "61", name: "Haskell", lang: Language::Haskell, kind: MatchKind::Indicator },
".lhs" => LanguageInfo { icon: "", color: "#5e5086", cterm_color: "61", name: "Haskell", lang: Language::Haskell, kind: MatchKind::Indicator },
"haxelib.json" => LanguageInfo { icon: "H", color: "#DF7900", cterm_color: "208", name: "Haxe", lang: Language::Haxe, kind: MatchKind::ProjectManifest},
".hxml" => LanguageInfo { icon: "H", color: "#DF7900", cterm_color: "208", name: "Haxe", lang: Language::Haxe, kind: MatchKind::Indicator },
".html" => LanguageInfo { icon: "", color: "#e34c26", cterm_color: "196", name: "HTML", lang: Language::Html, kind: MatchKind::Indicator },
".htm" => LanguageInfo { icon: "", color: "#e34c26", cterm_color: "196", name: "HTML", lang: Language::Html, kind: MatchKind::Indicator },
".idr" => LanguageInfo { icon: "I", color: "#1F232D", cterm_color: "235", name: "Idris", lang: Language::Idris, kind: MatchKind::Indicator },
".lidr" => LanguageInfo { icon: "I", color: "#1F232D", cterm_color: "235", name: "Idris", lang: Language::Idris, kind: MatchKind::Indicator },
"pom.xml" => LanguageInfo { icon: "", color: "#cc0000", cterm_color: "160", name: "Java/JVM", lang: Language::Java, kind: MatchKind::ProjectManifest},
"build.gradle" => LanguageInfo { icon: "", color: "#cc0000", cterm_color: "160", name: "Java/JVM", lang: Language::Java, kind: MatchKind::ProjectManifest },
".java" => LanguageInfo { icon: "", color: "#cc0000", cterm_color: "160", name: "Java", lang: Language::Java, kind: MatchKind::Indicator },
"package.json" => LanguageInfo { icon: "", color: "#f0db4f", cterm_color: "220", name: "JavaScript/Node", lang: Language::JavaScript, kind: MatchKind::ProjectManifest},
"tsconfig.json" => LanguageInfo { icon: "", color: "#3178c6", cterm_color: "39", name: "TypeScript", lang: Language::TypeScript, kind: MatchKind::ProjectManifest},
"Project.toml" => LanguageInfo { icon: "", color: "#a270ba", cterm_color: "140", name: "Julia", lang: Language::Julia, kind: MatchKind::ProjectManifest},
"build.gradle.kts" => LanguageInfo { icon: "", color: "#7f52ff", cterm_color: "99", name: "Kotlin", lang: Language::Kotlin, kind: MatchKind::ProjectManifest},
".kt" => LanguageInfo { icon: "", color: "#7f52ff", cterm_color: "99", name: "Kotlin", lang: Language::Kotlin, kind: MatchKind::Indicator },
".kts" => LanguageInfo { icon: "", color: "#7f52ff", cterm_color: "99", name: "Kotlin", lang: Language::Kotlin, kind: MatchKind::Indicator },
".tex" => LanguageInfo { icon: "", color: "#008080", cterm_color: "30", name: "LaTeX", lang: Language::LaTeX, kind: MatchKind::Indicator},
".latex" => LanguageInfo { icon: "", color: "#008080", cterm_color: "30", name: "LaTeX", lang: Language::LaTeX, kind: MatchKind::Indicator},
".rockspec" => LanguageInfo { icon: "", color: "#2c2d72", cterm_color: "18", name: "Lua", lang: Language::Lua, kind: MatchKind::ProjectManifest},
".lua" => LanguageInfo { icon: "", color: "#2c2d72", cterm_color: "18", name: "Lua", lang: Language::Lua, kind: MatchKind::Indicator},
".nimble" => LanguageInfo { icon: "", color: "#ffc200", cterm_color: "220", name: "Nim", lang: Language::Nim, kind: MatchKind::ProjectManifest},
".nim" => LanguageInfo { icon: "", color: "#ffc200", cterm_color: "220", name: "Nim", lang: Language::Nim, kind: MatchKind::Indicator },
"flake.nix" => LanguageInfo { icon: "", color: "#7E76D4", cterm_color: "104", name: "Nix", lang: Language::Nix, kind: MatchKind::ProjectManifest},
".nse" => LanguageInfo { icon: "N", color: "#404040", cterm_color: "238", name: "Nmap Script", lang: Language::Nmap, kind: MatchKind::Indicator },
"project.pbxproj" => LanguageInfo { icon: "", color: "#6792c9", cterm_color: "67", name: "Objective-C", lang: Language::ObjectiveC, kind: MatchKind::Generic },
".m" => LanguageInfo { icon: "", color: "#6792c9", cterm_color: "67", name: "Objective-C", lang: Language::ObjectiveC, kind: MatchKind::Generic },
"dune-project" => LanguageInfo { icon: "", color: "#ec6813", cterm_color: "166", name: "OCaml", lang: Language::OCaml, kind: MatchKind::ProjectManifest},
"opam" => LanguageInfo { icon: "", color: "#ec6813", cterm_color: "166", name: "OCaml", lang: Language::OCaml, kind: MatchKind::ProjectManifest},
".opam" => LanguageInfo { icon: "", color: "#ec6813", cterm_color: "166", name: "OCaml", lang: Language::OCaml, kind: MatchKind::ProjectManifest},
".ml" => LanguageInfo { icon: "", color: "#ec6813", cterm_color: "166", name: "OCaml", lang: Language::OCaml, kind: MatchKind::Indicator },
".mli" => LanguageInfo { icon: "", color: "#ec6813", cterm_color: "166", name: "OCaml", lang: Language::OCaml, kind: MatchKind::Indicator },
".dpr" => LanguageInfo { icon: "P", color: "#e32b2f", cterm_color: "196", name: "Delphi/Pascal", lang: Language::Pascal, kind: MatchKind::Indicator },
".lpr" => LanguageInfo { icon: "P", color: "#EEDD34", cterm_color: "184", name: "Lazarus/Pascal", lang: Language::Pascal, kind: MatchKind::Indicator },
".pl" => LanguageInfo { icon: "", color: "#39457e", cterm_color: "61", name: "Perl", lang: Language::Perl, kind: MatchKind::Indicator},
".pm" => LanguageInfo { icon: "", color: "#39457e", cterm_color: "61", name: "Perl", lang: Language::Perl, kind: MatchKind::Indicator },
"composer.json" => LanguageInfo { icon: "", color: "#8892be", cterm_color: "103", name: "PHP", lang: Language::Php, kind: MatchKind::ProjectManifest},
".php" => LanguageInfo { icon: "", color: "#8892be", cterm_color: "103", name: "PHP", lang: Language::Php, kind: MatchKind::Indicator },
".psd1" => LanguageInfo { icon: "", color: "#012456", cterm_color: "18", name: "PowerShell", lang: Language::PowerShell, kind: MatchKind::Indicator },
".pro" => LanguageInfo { icon: "P", color: "#880000", cterm_color: "88", name: "Prolog", lang: Language::Prolog, kind: MatchKind::Generic },
"pyproject.toml" => LanguageInfo { icon: "", color: "#f6c43b", cterm_color: "203", name: "Python", lang: Language::Python, kind: MatchKind::ProjectManifest},
"setup.cfg" => LanguageInfo { icon: "", color: "#f6c43b", cterm_color: "203", name: "Python", lang: Language::Python, kind: MatchKind::ProjectManifest},
"Pipfile" => LanguageInfo { icon: "", color: "#f6c43b", cterm_color: "203", name: "Python", lang: Language::Python, kind: MatchKind::ProjectManifest},
".py" => LanguageInfo { icon: "", color: "#f6c43b", cterm_color: "203", name: "Python", lang: Language::Python, kind: MatchKind::Indicator },
".pyx" => LanguageInfo { icon: "", color: "#f6c43b", cterm_color: "203", name: "Cython", lang: Language::Python, kind: MatchKind::Indicator },
".r" => LanguageInfo { icon: "", color: "#276dc2", cterm_color: "33", name: "R", lang: Language::R, kind: MatchKind::Indicator },
"info.rkt" => LanguageInfo { icon: "R", color: "#394FAC", cterm_color: "61", name: "Racket", lang: Language::Racket, kind: MatchKind::ProjectManifest},
"Gemfile" => LanguageInfo { icon: "", color: "#cc342d", cterm_color: "160", name: "Ruby", lang: Language::Ruby, kind: MatchKind::ProjectManifest},
".gemspec" => LanguageInfo { icon: "", color: "#cc342d", cterm_color: "160", name: "Ruby", lang: Language::Ruby, kind: MatchKind::ProjectManifest},
".rb" => LanguageInfo { icon: "", color: "#cc342d", cterm_color: "160", name: "Ruby", lang: Language::Ruby, kind: MatchKind::Indicator },
"Cargo.toml" => LanguageInfo { icon: "", color: "#dea584", cterm_color: "173", name: "Rust", lang: Language::Rust, kind: MatchKind::ProjectManifest},
".rs" => LanguageInfo { icon: "", color: "#dea584", cterm_color: "173", name: "Rust", lang: Language::Rust, kind: MatchKind::Indicator },
"build.sbt" => LanguageInfo { icon: "", color: "#c22d40", cterm_color: "160", name: "Scala", lang: Language::Scala, kind: MatchKind::ProjectManifest},
".sh" => LanguageInfo { icon: "", color: "#89E051", cterm_color: "113", name: "Shell", lang: Language::Shell, kind: MatchKind::Indicator},
".bash" => LanguageInfo { icon: "", color: "#89E051", cterm_color: "113", name: "Bash", lang: Language::Shell, kind: MatchKind::Indicator },
".csh" => LanguageInfo { icon: "", color: "#89E051", cterm_color: "113", name: "Csh", lang: Language::Shell, kind: MatchKind::Indicator },
".tcsh" => LanguageInfo { icon: "", color: "#89E051", cterm_color: "113", name: "Tcsh", lang: Language::Shell, kind: MatchKind::Indicator },
".fish" => LanguageInfo { icon: "", color: "#89E051", cterm_color: "113", name: "Fish", lang: Language::Shell, kind: MatchKind::Indicator },
".ksh" => LanguageInfo { icon: "", color: "#89E051", cterm_color: "113", name: "Ksh", lang: Language::Shell, kind: MatchKind::Indicator },
".zsh" => LanguageInfo { icon: "", color: "#89E051", cterm_color: "113", name: "Zsh", lang: Language::Shell, kind: MatchKind::Indicator },
".st" => LanguageInfo { icon: "S", color: "#596700", cterm_color: "58", name: "SmallTalk", lang: Language::SmallTalk, kind: MatchKind::Indicator },
"Package.swift" => LanguageInfo { icon: "", color: "#ffac45", cterm_color: "215", name: "Swift", lang: Language::Swift, kind: MatchKind::ProjectManifest},
".tcl" => LanguageInfo { icon: "T", color: "#1D529D", cterm_color: "25", name: "Tcl", lang: Language::Tcl, kind: MatchKind::Indicator},
".u" => LanguageInfo { icon: "U", color: "#FF7A62", cterm_color: "209", name: "Unison", lang: Language::Unison, kind: MatchKind::Indicator },
".vala" => LanguageInfo { icon: "", color: "#7239B3", cterm_color: "98", name: "Vala", lang: Language::Vala, kind: MatchKind::Indicator},
".v" => LanguageInfo { icon: "V", color: "#000080", cterm_color: "18", name: "Verilog", lang: Language::Verilog, kind: MatchKind::Generic },
".vh" => LanguageInfo { icon: "V", color: "#000080", cterm_color: "18", name: "Verilog", lang: Language::Verilog, kind: MatchKind::Generic },
".sv" => LanguageInfo { icon: "V", color: "#000080", cterm_color: "18", name: "Verilog", lang: Language::Verilog, kind: MatchKind::Generic},
".vhd" => LanguageInfo { icon: "V", color: "#AD0000", cterm_color: "88", name: "VHDL", lang: Language::Vhdl, kind: MatchKind::Indicator},
".vhdl" => LanguageInfo { icon: "V", color: "#AD0000", cterm_color: "88", name: "VHDL", lang: Language::Vhdl, kind: MatchKind::Indicator},
"build.zig.zon" => LanguageInfo { icon: "", color: "#f7a41d", cterm_color: "214", name: "Zig", lang: Language::Zig, kind: MatchKind::ProjectManifest},
"build.zig" => LanguageInfo { icon: "", color: "#f7a41d", cterm_color: "214", name: "Zig", lang: Language::Zig, kind: MatchKind::ProjectManifest},
".zig" => LanguageInfo { icon: "", color: "#f7a41d", cterm_color: "214", name: "Zig", lang: Language::Zig, kind: MatchKind::Indicator },
};
#[derive(Clone, Copy)]
enum VersionStrategy {
KeyValueQuoted(&'static str, &'static str),
KeyValueUnquoted(&'static str, &'static str),
LinePrefixQuoted(&'static str),
LinePrefixUnquoted(&'static str),
XmlBetween(&'static str, &'static str),
CMakeVersion,
MSBuildVersion,
RubyGemspec,
}
fn project_version_strategy(lang: Language, key: &str) -> Option<VersionStrategy> {
use Language::*;
match (lang, key) {
(Rust, _) | (Julia, _) | (Nim, _) => Some(VersionStrategy::LinePrefixQuoted("version")),
(Python, "pyproject.toml") => Some(VersionStrategy::KeyValueQuoted("version", "=")),
(Python, "setup.cfg") => Some(VersionStrategy::KeyValueUnquoted("version", "=")),
(Lua, ".rockspec") => Some(VersionStrategy::LinePrefixQuoted("version")),
(CCpp, "CMakeLists.txt") => Some(VersionStrategy::CMakeVersion),
(D, "dub.sdl") => Some(VersionStrategy::LinePrefixQuoted("version")),
(D, "dub.json") => Some(VersionStrategy::KeyValueQuoted("\"version\"", ":")),
(OCaml, "opam") | (OCaml, ".opam") => Some(VersionStrategy::LinePrefixQuoted("version")),
(OCaml, "dune-project") => Some(VersionStrategy::LinePrefixUnquoted("(version ")),
(Elixir, _) => Some(VersionStrategy::KeyValueQuoted("version", ":")),
(JavaScript, _) | (Php, _) | (Haxe, _) | (Elm, _) => {
Some(VersionStrategy::KeyValueQuoted("\"version\"", ":"))
}
(Ruby, ".gemspec") => Some(VersionStrategy::RubyGemspec),
(Scala, _) => Some(VersionStrategy::KeyValueQuoted("version", ":=")),
(CommonLisp, _) => Some(VersionStrategy::LinePrefixQuoted(":version")),
(Racket, _) => Some(VersionStrategy::LinePrefixQuoted("(define version")),
(Haskell, ".cabal") | (Dart, _) => Some(VersionStrategy::LinePrefixUnquoted("version:")),
(Java, "pom.xml") => Some(VersionStrategy::XmlBetween("<version>", "</version>")),
(Java, "build.gradle") => Some(VersionStrategy::KeyValueQuoted("version", "=")),
(Kotlin, "build.gradle.kts") => Some(VersionStrategy::KeyValueQuoted("version", "=")),
(CSharp, _) | (FSharp, _) => Some(VersionStrategy::MSBuildVersion),
(Zig, "build.zig.zon") => Some(VersionStrategy::KeyValueQuoted(".version", "=")),
_ => None,
}
}
#[inline]
fn extract_first_quoted(s: &str) -> Option<SmolStr> {
let q_open = s.find(['"', '\''])?;
let quote_char = s.as_bytes()[q_open] as char;
let rest = &s[q_open + 1..];
let q_end = rest.find(quote_char)?;
let v = &rest[..q_end];
(!v.is_empty()).then(|| SmolStr::new(v))
}
fn extract_version(strategy: VersionStrategy, content: &str) -> Option<SmolStr> {
match strategy {
VersionStrategy::KeyValueQuoted(key, sep) => {
for line in content.lines() {
let line = line.trim_start();
if let Some(rest) = line.strip_prefix(key) {
let rest = rest.trim_start();
if let Some(rest) = rest.strip_prefix(sep) {
if let Some(v) = extract_first_quoted(rest.trim_start()) {
return Some(v);
}
}
}
}
None
}
VersionStrategy::KeyValueUnquoted(key, sep) => {
for line in content.lines() {
let line = line.trim_start();
if let Some(rest) = line.strip_prefix(key) {
let rest = rest.trim_start();
if let Some(rest) = rest.strip_prefix(sep) {
let rest = rest.trim_start();
let end = rest
.find(|c: char| c.is_whitespace() || c == ')' || c == '#')
.unwrap_or(rest.len());
let v = &rest[..end];
if !v.is_empty() {
return Some(SmolStr::new(v));
}
}
}
}
None
}
VersionStrategy::LinePrefixQuoted(prefix) => {
for line in content.lines() {
let line = line.trim_start();
if !line.starts_with(prefix) {
continue;
}
if let Some(v) = extract_first_quoted(line) {
return Some(v);
}
}
None
}
VersionStrategy::LinePrefixUnquoted(prefix) => {
for line in content.lines() {
let line = line.trim_start();
if !line.starts_with(prefix) {
continue;
}
let rest = line[prefix.len()..].trim_start();
let end = rest
.find(|c: char| c.is_whitespace() || c == ')' || c == '#')
.unwrap_or(rest.len());
let v = &rest[..end];
if !v.is_empty() {
return Some(SmolStr::new(v));
}
}
None
}
VersionStrategy::XmlBetween(open, close) => {
let start = content.find(open)? + open.len();
let rest = &content[start..];
let end = rest.find(close)?;
let v = rest[..end].trim();
(!v.is_empty()).then(|| SmolStr::new(v))
}
VersionStrategy::CMakeVersion => {
let project_idx = content
.find("project(")
.or_else(|| content.find("project ("))?;
let rest = &content[project_idx..];
let end_idx = rest.find(')')?;
let project_decl = &rest[..end_idx];
let version_idx = project_decl.find("VERSION")?;
let mut parts = project_decl[version_idx + "VERSION".len()..].split_whitespace();
let v = parts.next()?;
Some(SmolStr::new(v))
}
VersionStrategy::MSBuildVersion => {
for tag in &["<Version>", "<PackageVersion>"] {
if let Some(start) = content.find(tag) {
let start = start + tag.len();
let rest = &content[start..];
if let Some(end) = rest.find('<') {
let v = rest[..end].trim();
if !v.is_empty() {
return Some(SmolStr::new(v));
}
}
}
}
None
}
VersionStrategy::RubyGemspec => {
for line in content.lines() {
let line = line.trim_start();
if let Some(idx) = line.find(".version") {
let rest = line[idx + ".version".len()..].trim_start();
if let Some(rest) = rest.strip_prefix('=') {
if let Some(v) = extract_first_quoted(rest.trim_start()) {
return Some(v);
}
}
}
}
None
}
}
}
async fn version_from_file(path: &std::path::Path, lang: Language, key: &str) -> Option<SmolStr> {
let strategy = project_version_strategy(lang, key)?;
let content = tokio::fs::read_to_string(path).await.ok()?;
extract_version(strategy, &content)
}
const CACHE_TTL_SECS: u64 = 10;
fn get_cache_path() -> &'static std::path::Path {
static CACHE_PATH: std::sync::OnceLock<std::path::PathBuf> = std::sync::OnceLock::new();
CACHE_PATH.get_or_init(|| {
#[cfg(unix)]
let id = unsafe { libc::getuid() }.to_string();
#[cfg(not(unix))]
let id = std::env::var("USER")
.or_else(|_| std::env::var("USERNAME"))
.unwrap_or_else(|_| "default".to_string());
std::env::temp_dir().join(format!("auraline-manifest-cache-{id}.txt"))
})
}
fn cache_key_for_lang(lang: Language) -> SmolStr {
use std::hash::{Hash, Hasher};
let mut hasher = std::collections::hash_map::DefaultHasher::new();
if let Ok(cwd) = std::env::current_dir() {
cwd.hash(&mut hasher);
}
if let Ok(venv) = std::env::var("VIRTUAL_ENV") {
venv.hash(&mut hasher);
}
if let Some(path) = std::env::var_os("PATH") {
path.hash(&mut hasher);
}
format_smolstr!("{:?}@{:x}", lang, hasher.finish())
}
fn read_cached_version(lang: Language) -> Option<SmolStr> {
let cache_path = get_cache_path();
let content = std::fs::read_to_string(cache_path).ok()?;
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.ok()?
.as_secs();
let key = cache_key_for_lang(lang);
for line in content.lines() {
let mut parts = line.splitn(3, ':');
let name = parts.next()?;
let version = parts.next()?;
let timestamp_str = parts.next()?;
if name == key.as_str() {
let timestamp: u64 = timestamp_str.parse().ok()?;
if now >= timestamp && now - timestamp < CACHE_TTL_SECS {
return Some(SmolStr::new(version));
}
}
}
None
}
fn write_cached_version(lang: Language, version: &str) -> Option<()> {
let cache_path = get_cache_path();
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.ok()?
.as_secs();
let key = cache_key_for_lang(lang);
let mut lines = Vec::new();
if let Ok(content) = std::fs::read_to_string(cache_path) {
for line in content.lines() {
let mut parts = line.splitn(3, ':');
if let Some(name) = parts.next() {
if name != key.as_str() {
lines.push(line.to_string());
}
}
}
}
lines.push(format!("{}:{}:{}", key, version, now));
let temp_path = cache_path.with_extension(format!("tmp.{}", std::process::id()));
std::fs::write(&temp_path, lines.join("\n")).ok()?;
if std::fs::rename(&temp_path, cache_path).is_err() {
let _ = std::fs::remove_file(&temp_path);
return None;
}
Some(())
}
async fn build_system_version(lang: Language) -> Option<SmolStr> {
if let Some(cached) = read_cached_version(lang) {
return Some(cached);
}
let version = build_system_version_uncached(lang).await?;
write_cached_version(lang, &version);
Some(version)
}
async fn build_system_version_uncached(lang: Language) -> Option<SmolStr> {
use crate::cmd::CMD;
match lang {
Language::Rust => {
let out = CMD.exec("rustc", ["--version"]).await?;
let v = out.split_whitespace().nth(1)?;
Some(SmolStr::new(v))
}
Language::Go => {
let out = CMD.exec("go", ["version"]).await?;
let v = out.split_whitespace().nth(2)?;
Some(SmolStr::new(v.strip_prefix("go").unwrap_or(v)))
}
Language::Python => {
let out = match CMD.exec("python", ["--version"]).await {
Some(out) => out,
None => CMD.exec("python3", ["--version"]).await?,
};
let v = out.split_whitespace().nth(1)?;
Some(SmolStr::new(v))
}
Language::JavaScript | Language::TypeScript => {
let out = CMD.exec("node", ["--version"]).await?;
Some(SmolStr::new(out.strip_prefix('v').unwrap_or(&out)))
}
Language::Java => {
let out = CMD.exec("javac", ["--version"]).await?;
let v = out.split_whitespace().nth(1)?;
Some(SmolStr::new(v))
}
Language::Ruby => {
let out = CMD.exec("ruby", ["--version"]).await?;
let v = out.split_whitespace().nth(1)?;
Some(SmolStr::new(v))
}
Language::Php => {
let out = CMD.exec("php", ["--version"]).await?;
let v = out.split_whitespace().nth(1)?;
Some(SmolStr::new(v))
}
Language::Dart => {
let out = CMD.exec("dart", ["--version"]).await?;
let v = out.split_whitespace().nth(3)?;
Some(SmolStr::new(v))
}
Language::Julia => {
let out = CMD.exec("julia", ["--version"]).await?;
let v = out.split_whitespace().nth(2)?;
Some(SmolStr::new(v))
}
Language::Zig => {
let out = CMD.exec("zig", ["version"]).await?;
Some(out)
}
Language::Nim => {
let out = CMD.exec("nim", ["--version"]).await?;
let v = out.split_whitespace().nth(3)?;
Some(SmolStr::new(v))
}
Language::Elixir => {
let out = CMD.exec("elixir", ["--version"]).await?;
let v = out.split_whitespace().last()?;
Some(SmolStr::new(v))
}
Language::CSharp | Language::FSharp => {
let out = CMD.exec("dotnet", ["--version"]).await?;
Some(SmolStr::new(out))
}
Language::CCpp => {
let out = CMD.exec("cmake", ["--version"]).await?;
let v = out.split_whitespace().nth(2)?;
Some(SmolStr::new(v))
}
Language::Haskell => {
let out = CMD.exec("ghc", ["--numeric-version"]).await?;
Some(SmolStr::new(out))
}
Language::OCaml => {
let out = CMD.exec("ocamlc", ["--version"]).await?;
Some(SmolStr::new(out))
}
Language::Kotlin => {
let out = CMD.exec("kotlin", ["-version"]).await?;
let v = out.split_whitespace().nth(2)?;
Some(SmolStr::new(v.strip_suffix("-jre").unwrap_or(v)))
}
Language::Scala => {
let out = CMD.exec("scala", ["-version"]).await?;
let v = out.split_whitespace().nth(4)?;
Some(SmolStr::new(v))
}
Language::Lua => {
let out = CMD.exec("lua", ["-v"]).await?;
let v = out.split_whitespace().nth(1)?;
Some(SmolStr::new(v))
}
Language::D => {
let out = CMD.exec("dmd", ["--version"]).await?;
let v = out.split_whitespace().nth(3)?;
Some(SmolStr::new(v))
}
_ => None,
}
}
pub async fn show(opts: &Options) -> Option<Chunk<SmolStr>> {
if !opts.nerd_font || !opts.manifest {
return None;
}
let mut entries = tokio::fs::read_dir(".").await.ok()?;
let mut top_kind: Option<MatchKind> = None;
let mut top_icons: SmallVec<[&'static str; 8]> = SmallVec::new();
let mut manifests: SmallVec<[(std::path::PathBuf, Language, SmolStr); 4]> = SmallVec::new();
while let Some(entry) = entries.next_entry().await.ok()? {
let file_name = entry.file_name();
let Some(name) = file_name.to_str() else {
continue;
};
if name.starts_with('.') {
continue;
}
let matched = if let Some(lang) = MANIFEST_MAP.get(name) {
Some((lang, name))
} else if let Some(dot_idx) = name.rfind('.') {
let ext_key = &name[dot_idx..];
MANIFEST_MAP.get(ext_key).map(|lang| (lang, ext_key))
} else {
None
};
if let Some((lang, key)) = matched {
if lang.kind == MatchKind::ProjectManifest {
manifests.push((entry.path(), lang.lang, SmolStr::new(key)));
}
match top_kind {
None => {
top_kind = Some(lang.kind);
top_icons.push(lang.icon);
}
Some(cur_top) if lang.kind > cur_top => {
top_kind = Some(lang.kind);
top_icons.clear();
top_icons.push(lang.icon);
}
Some(cur_top) if lang.kind == cur_top => {
if !top_icons.contains(&lang.icon) {
top_icons.push(lang.icon);
}
}
_ => {}
}
}
}
let top_kind = top_kind?;
top_icons.sort_unstable();
let mut builder = SmolStrBuilder::new();
for icon in &top_icons {
builder.push_str(icon);
}
let icons = builder.finish();
let version = if top_kind == MatchKind::ProjectManifest && !manifests.is_empty() {
let primary_lang = manifests[0].1;
let tool_version_fut = build_system_version(primary_lang);
let found_fut = async {
for (path, lang, key) in &manifests {
if let Some(v) = version_from_file(path, *lang, key).await {
return Some(v);
}
}
None
};
let (tool_version, found) = tokio::join!(tool_version_fut, found_fut);
match (tool_version, found) {
(Some(tv), Some(pv)) => Some(format_smolstr!("{} ↦ v{}", tv, pv)),
(Some(tv), None) => Some(tv),
(None, Some(pv)) => Some(format_smolstr!("v{}", pv)),
(None, None) => None,
}
} else {
None
};
Some(match version {
Some(ver) => Chunk::new(icons, ver),
None => Chunk::icon(icons),
})
}
#[cfg(test)]
mod tests {
use super::{extract_version, VersionStrategy};
#[test]
fn test_extract_version_utf8_before_quote() {
let content = "version = /* versione 🚀 */ \"1.2.3\"\n";
assert_eq!(
extract_version(VersionStrategy::LinePrefixQuoted("version"), content).as_deref(),
Some("1.2.3")
);
assert_eq!(
extract_version(VersionStrategy::KeyValueQuoted("version", "="), content).as_deref(),
Some("1.2.3")
);
}
}