diff --git a/docs/config/README.md b/docs/config/README.md index fcfab550..49879f21 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -229,6 +229,7 @@ $crystal\ $cmd_duration\ $custom\ $line_break\ +$lua\ $jobs\ $battery\ $time\ @@ -1494,6 +1495,44 @@ The `line_break` module separates the prompt into two lines. disabled = true ``` +## Lua + +The `lua` module shows the currently installed version of Lua. +The module will be shown if any of the following conditions are met: + +- The current directory contains a `.lua-version` file +- The current directory contains a `lua` directory +- The current directory contains a file with the `.lua` extension + +### Options + +| Option | Default | Description | +| ------------ | ---------------------------------- | ----------------------------------------------------------------------------- | +| `format` | `"via [$symbol$version]($style) "` | The format for the module. | +| `symbol` | `"🌙 "` | A format string representing the symbol of Lua. | +| `style` | `"bold blue"` | The style for the module. | +| `lua_binary` | `"lua"` | Configures the lua binary that Starship executes when getting the version. | +| `disabled` | `false` | Disables the `lua` module. | + +### Variables + +| Variable | Example | Description | +| -------- | --------- | ------------------------------------ | +| version | `v5.4.0` | The version of `lua` | +| symbol | | Mirrors the value of option `symbol` | +| style\* | | Mirrors the value of option `style` | + +\*: This variable can only be used as a part of a style string + +### Example + +```toml +# ~/.config/starship.toml + +[lua] +format = "via [🌕 $version](bold blue) " +``` + ## Memory Usage The `memory_usage` module shows current system memory and swap usage. diff --git a/src/configs/lua.rs b/src/configs/lua.rs new file mode 100644 index 00000000..fb715f47 --- /dev/null +++ b/src/configs/lua.rs @@ -0,0 +1,24 @@ +use crate::config::{ModuleConfig, RootModuleConfig}; + +use starship_module_config_derive::ModuleConfig; + +#[derive(Clone, ModuleConfig)] +pub struct LuaConfig<'a> { + pub format: &'a str, + pub symbol: &'a str, + pub style: &'a str, + pub lua_binary: &'a str, + pub disabled: bool, +} + +impl<'a> RootModuleConfig<'a> for LuaConfig<'a> { + fn new() -> Self { + LuaConfig { + format: "via [$symbol$version]($style) ", + symbol: "🌙 ", + style: "bold blue", + lua_binary: "lua", + disabled: false, + } + } +} diff --git a/src/configs/mod.rs b/src/configs/mod.rs index 26770a42..19da4f47 100644 --- a/src/configs/mod.rs +++ b/src/configs/mod.rs @@ -27,6 +27,7 @@ pub mod java; pub mod jobs; pub mod julia; pub mod kubernetes; +pub mod lua; pub mod memory_usage; pub mod nim; pub mod nix_shell; diff --git a/src/configs/starship_root.rs b/src/configs/starship_root.rs index 85171c9f..24bd09a2 100644 --- a/src/configs/starship_root.rs +++ b/src/configs/starship_root.rs @@ -38,6 +38,7 @@ pub const PROMPT_ORDER: &[&str] = &[ "helm", "java", "julia", + "lua", "nim", "nodejs", "ocaml", diff --git a/src/module.rs b/src/module.rs index 86d44405..b65184a2 100644 --- a/src/module.rs +++ b/src/module.rs @@ -38,6 +38,7 @@ pub const ALL_MODULES: &[&str] = &[ "julia", "kubernetes", "line_break", + "lua", "memory_usage", "nim", "nix_shell", diff --git a/src/modules/lua.rs b/src/modules/lua.rs new file mode 100644 index 00000000..9bea9266 --- /dev/null +++ b/src/modules/lua.rs @@ -0,0 +1,166 @@ +use super::{Context, Module, RootModuleConfig}; + +use crate::configs::lua::LuaConfig; +use crate::formatter::StringFormatter; +use crate::utils; + +use regex::Regex; +const LUA_VERSION_PATERN: &str = "(?P[\\d\\.]+[a-z\\-]*[1-9]*)[^\\s]*"; + +/// Creates a module with the current Lua version +/// +/// Will display the Lua version if any of the following criteria are met: +/// - Current directory contains a `.lua-version` file +/// - Current directory contains a `lua` directory +/// - Current directory contains a file with the `.lua` extension +pub fn module<'a>(context: &'a Context) -> Option> { + let is_lua_project = context + .try_begin_scan()? + .set_files(&[".lua-version"]) + .set_folders(&["lua"]) + .set_extensions(&["lua"]) + .is_match(); + + if !is_lua_project { + return None; + } + + let mut module = context.new_module("lua"); + let config = LuaConfig::try_load(module.config); + let lua_version = format_lua_version(&get_lua_version(&config.lua_binary)?)?; + let parsed = StringFormatter::new(config.format).and_then(|formatter| { + formatter + .map_meta(|var, _| match var { + "symbol" => Some(config.symbol), + _ => None, + }) + .map_style(|variable| match variable { + "style" => Some(Ok(config.style)), + _ => None, + }) + .map(|variable| match variable { + "version" => Some(Ok(&lua_version)), + _ => None, + }) + .parse(None) + }); + + module.set_segments(match parsed { + Ok(segments) => segments, + Err(error) => { + log::warn!("Error in module `lua`:\n{}", error); + return None; + } + }); + + Some(module) +} + +fn get_lua_version(lua_binary: &str) -> Option { + match utils::exec_cmd(lua_binary, &["-v"]) { + Some(output) => { + if output.stdout.is_empty() { + Some(output.stderr) + } else { + Some(output.stdout) + } + } + None => None, + } +} + +fn format_lua_version(lua_stdout: &str) -> Option { + // lua -v output looks like this: + // Lua 5.4.0 Copyright (C) 1994-2020 Lua.org, PUC-Rio + + // luajit -v output looks like this: + // LuaJIT 2.0.5 -- Copyright (C) 2005-2017 Mike Pall. http://luajit.org/ + let re = Regex::new(LUA_VERSION_PATERN).ok()?; + let captures = re.captures(lua_stdout)?; + let version = &captures["version"]; + Some(format!("v{}", version)) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::test::ModuleRenderer; + use ansi_term::Color; + use std::fs::{self, File}; + use std::io; + + #[test] + fn folder_without_lua_files() -> io::Result<()> { + let dir = tempfile::tempdir()?; + let actual = ModuleRenderer::new("lua").path(dir.path()).collect(); + let expected = None; + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn folder_with_lua_file() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("main.lua"))?.sync_all()?; + let actual = ModuleRenderer::new("lua").path(dir.path()).collect(); + let expected = Some(format!("via {} ", Color::Blue.bold().paint("🌙 v5.4.0"))); + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn folder_with_lua_version() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join(".lua-version"))?.sync_all()?; + + let actual = ModuleRenderer::new("lua").path(dir.path()).collect(); + let expected = Some(format!("via {} ", Color::Blue.bold().paint("🌙 v5.4.0"))); + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn folder_with_lua_folder() -> io::Result<()> { + let dir = tempfile::tempdir()?; + let lua_dir = dir.path().join("lua"); + fs::create_dir_all(&lua_dir)?; + + let actual = ModuleRenderer::new("lua").path(dir.path()).collect(); + let expected = Some(format!("via {} ", Color::Blue.bold().paint("🌙 v5.4.0"))); + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn lua_binary_is_luajit() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("main.lua"))?.sync_all()?; + + let config = toml::toml! { + [lua] + lua_binary = "luajit" + }; + + let actual = ModuleRenderer::new("lua") + .path(dir.path()) + .config(config) + .collect(); + + let expected = Some(format!("via {} ", Color::Blue.bold().paint("🌙 v2.0.5"))); + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn test_format_lua_version() { + let lua_input = "Lua 5.4.0 Copyright (C) 1994-2020 Lua.org, PUC-Rio"; + assert_eq!(format_lua_version(lua_input), Some("v5.4.0".to_string())); + + let luajit_input = + "LuaJIT 2.1.0-beta3 -- Copyright (C) 2005-2017 Mike Pall. http://luajit.org/"; + assert_eq!( + format_lua_version(luajit_input), + Some("v2.1.0-beta3".to_string()) + ); + } +} diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 7215f8b0..ba7196d8 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -28,6 +28,7 @@ mod jobs; mod julia; mod kubernetes; mod line_break; +mod lua; mod memory_usage; mod nim; mod nix_shell; @@ -95,6 +96,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option> { "julia" => julia::module(context), "kubernetes" => kubernetes::module(context), "line_break" => line_break::module(context), + "lua" => lua::module(context), "memory_usage" => memory_usage::module(context), "nim" => nim::module(context), "nix_shell" => nix_shell::module(context), @@ -169,6 +171,7 @@ pub fn description(module: &str) -> &'static str { "julia" => "The currently installed version of Julia", "kubernetes" => "The current Kubernetes context name and, if set, the namespace", "line_break" => "Separates the prompt into two lines", + "lua" => "The currently installed version of Lua", "memory_usage" => "Current system memory and swap usage", "nim" => "The currently installed version of Nim", "nix_shell" => "The nix-shell environment", diff --git a/src/utils.rs b/src/utils.rs index 10834251..428d1098 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -88,6 +88,14 @@ Elixir 1.10 (compiled with Erlang/OTP 22)\n", stdout: String::from("julia version 1.4.0\n"), stderr: String::default(), }), + "lua -v" => Some(CommandOutput{ + stdout: String::from("Lua 5.4.0 Copyright (C) 1994-2020 Lua.org, PUC-Rio\n"), + stderr: String::default(), + }), + "luajit -v" => Some(CommandOutput{ + stdout: String::from("LuaJIT 2.0.5 -- Copyright (C) 2005-2017 Mike Pall. http://luajit.org/\n"), + stderr: String::default(), + }), "nim --version" => Some(CommandOutput { stdout: String::from( "\