summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBeni Ben zikry <bbenzikry@gmail.com>2021-03-14 21:37:00 +0200
committerGitHub <noreply@github.com>2021-03-14 20:37:00 +0100
commitdd5c62791cc96f89588af5827e014a56790ceb4c (patch)
tree4fb0ee57adf4f9db3a9beef9394457853a79defc
parent1651d11aad3f3fc41c0d2e3371f866c6e8f532fc (diff)
feat(scala): Add scala module (#2409)
* Add support for scala ( w/o sbt ) * Add scala description * Change scala color to bold red * update scala extensions in README * failed lint * cr changes ( regex, simplify parsing, imports ) * Scala readme punctuation Co-authored-by: David Knaack <davidkna@users.noreply.github.com> Co-authored-by: David Knaack <davidkna@users.noreply.github.com>
-rw-r--r--docs/config/README.md44
-rw-r--r--docs/presets/README.md3
-rw-r--r--src/configs/mod.rs1
-rw-r--r--src/configs/scala.rs28
-rw-r--r--src/configs/starship_root.rs1
-rw-r--r--src/module.rs1
-rw-r--r--src/modules/mod.rs3
-rw-r--r--src/modules/scala.rs170
-rw-r--r--src/utils.rs4
9 files changed, 255 insertions, 0 deletions
diff --git a/docs/config/README.md b/docs/config/README.md
index 926e26dc0..af580016a 100644
--- a/docs/config/README.md
+++ b/docs/config/README.md
@@ -216,6 +216,7 @@ $purescript\
$python\
$ruby\
$rust\
+$scala\
$swift\
$terraform\
$vagrant\
@@ -2272,6 +2273,49 @@ The module will be shown if any of the following conditions are met:
format = "via [⚙️ $version](red bold)"
```
+
+## Scala
+
+The `scala` module shows the currently installed version of Scala.
+By default the module will be shown if any of the following conditions are met:
+
+- The current directory contains a `build.sbt`, `.scalaenv` or `.sbtenv` file
+- The current directory contains a file with the `.scala` or `.sbt` extension
+- The current directory contains a directory named `.metals`
+
+### Options
+
+
+| Option | Default | Description |
+| ------------------- | -------------------------------------------| ----------------------------------------------- |
+| `format` | `"via [${symbol}(${version} )]($style)"` | The format for the module. |
+| `detect_extensions` | `["sbt", "scala"]` | Which extensions should trigger this module. |
+| `detect_files` | `[".scalaenv", ".sbtenv", "build.sbt"]` | Which filenames should trigger this module. |
+| `detect_folders` | `[".metals"]` | Which folders should trigger this modules. |
+| `symbol` | `"🆂 "` | A format string representing the symbol of Scala. |
+| `style` | `"red dimmed"` | The style for the module. |
+| `disabled` | `false` | Disables the `scala` module. |
+
+### Variables
+
+| Variable | Example | Description |
+| -------- | -----------| ------------------------------------ |
+| version | `2.13.5` | The version of `scala` |
+| 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
+
+[scala]
+symbol = "🌟 "
+```
+
+
## Shell
The `shell` module shows an indicator for currently used shell.
diff --git a/docs/presets/README.md b/docs/presets/README.md
index f8939242c..040cc207b 100644
--- a/docs/presets/README.md
+++ b/docs/presets/README.md
@@ -86,6 +86,9 @@ symbol = " "
[rust]
symbol = " "
+[scala]
+symbol = " "
+
[swift]
symbol = "ﯣ "
```
diff --git a/src/configs/mod.rs b/src/configs/mod.rs
index 1052a6736..4ad15699c 100644
--- a/src/configs/mod.rs
+++ b/src/configs/mod.rs
@@ -42,6 +42,7 @@ pub mod purescript;
pub mod python;
pub mod ruby;
pub mod rust;
+pub mod scala;
pub mod shell;
pub mod shlvl;
pub mod singularity;
diff --git a/src/configs/scala.rs b/src/configs/scala.rs
new file mode 100644
index 000000000..3c5fc670e
--- /dev/null
+++ b/src/configs/scala.rs
@@ -0,0 +1,28 @@
+use crate::config::{ModuleConfig, RootModuleConfig};
+
+use starship_module_config_derive::ModuleConfig;
+
+#[derive(Clone, ModuleConfig)]
+pub struct ScalaConfig<'a> {
+ pub disabled: bool,
+ pub format: &'a str,
+ pub style: &'a str,
+ pub symbol: &'a str,
+ pub detect_extensions: Vec<&'a str>,
+ pub detect_files: Vec<&'a str>,
+ pub detect_folders: Vec<&'a str>,
+}
+
+impl<'a> RootModuleConfig<'a> for ScalaConfig<'a> {
+ fn new() -> Self {
+ ScalaConfig {
+ format: "via [$symbol($version )]($style)",
+ disabled: false,
+ style: "red bold",
+ symbol: "🆂 ",
+ detect_extensions: vec!["sbt", "scala"],
+ detect_files: vec![".scalaenv", ".sbtenv", "build.sbt"],
+ detect_folders: vec![".metals"],
+ }
+ }
+}
diff --git a/src/configs/starship_root.rs b/src/configs/starship_root.rs
index a73f0229a..9064e5afe 100644
--- a/src/configs/starship_root.rs
+++ b/src/configs/starship_root.rs
@@ -50,6 +50,7 @@ pub const PROMPT_ORDER: &[&str] = &[
"python",
"ruby",
"rust",
+ "scala",
"swift",
"terraform",
"vagrant",
diff --git a/src/module.rs b/src/module.rs
index 7a6961beb..c5ca928e7 100644
--- a/src/module.rs
+++ b/src/module.rs
@@ -34,6 +34,7 @@ pub const ALL_MODULES: &[&str] = &[
"hg_branch",
"hostname",
"java",
+ "scala",
"jobs",
"julia",
"kotlin",
diff --git a/src/modules/mod.rs b/src/modules/mod.rs
index 207d4e66b..35dd4f37c 100644
--- a/src/modules/mod.rs
+++ b/src/modules/mod.rs
@@ -43,6 +43,7 @@ mod purescript;
mod python;
mod ruby;
mod rust;
+mod scala;
mod shell;
mod shlvl;
mod singularity;
@@ -114,6 +115,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option<Module<'a>> {
"python" => python::module(context),
"ruby" => ruby::module(context),
"rust" => rust::module(context),
+ "scala" => scala::module(context),
"shell" => shell::module(context),
"shlvl" => shlvl::module(context),
"singularity" => singularity::module(context),
@@ -192,6 +194,7 @@ pub fn description(module: &str) -> &'static str {
"python" => "The currently installed version of Python",
"ruby" => "The currently installed version of Ruby",
"rust" => "The currently installed version of Rust",
+ "scala" => "The currently installed version of Scala",
"swift" => "The currently installed version of Swift",
"shell" => "The currently used shell indicator",
"shlvl" => "The current value of SHLVL",
diff --git a/src/modules/scala.rs b/src/modules/scala.rs
new file mode 100644
index 000000000..f02f44cc6
--- /dev/null
+++ b/src/modules/scala.rs
@@ -0,0 +1,170 @@
+use crate::configs::scala::ScalaConfig;
+use crate::formatter::StringFormatter;
+
+use super::{Context, Module, RootModuleConfig};
+
+use regex::Regex;
+
+const SCALA_VERSION_PATTERN: &str = "version[\\s](?P<version>[^\\s]+)";
+
+pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
+ let mut module = context.new_module("scala");
+ let config: ScalaConfig = ScalaConfig::try_load(module.config);
+
+ let is_scala_project = context
+ .try_begin_scan()?
+ .set_files(&config.detect_files)
+ .set_extensions(&config.detect_extensions)
+ .set_folders(&config.detect_folders)
+ .is_match();
+
+ if !is_scala_project {
+ return None;
+ }
+
+ 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" => {
+ let scala_version = get_scala_version(context)?;
+ Some(Ok(scala_version))
+ }
+ _ => None,
+ })
+ .parse(None)
+ });
+
+ module.set_segments(match parsed {
+ Ok(segments) => segments,
+ Err(error) => {
+ log::warn!("Error in module `scala`:\n{}", error);
+ return None;
+ }
+ });
+
+ Some(module)
+}
+
+fn get_scala_version(context: &Context) -> Option<String> {
+ let output = context.exec_cmd("scalac", &["-version"])?;
+ let scala_version = if output.stdout.is_empty() {
+ output.stderr
+ } else {
+ output.stdout
+ };
+
+ parse_scala_version(&scala_version)
+}
+
+fn parse_scala_version(scala_version: &str) -> Option<String> {
+ let re = Regex::new(SCALA_VERSION_PATTERN).ok()?;
+ let captures = re.captures(scala_version)?;
+ 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 test_parse_scala_version() {
+ let scala_2_13 =
+ "Scala compiler version 2.13.5 -- Copyright 2002-2020, LAMP/EPFL and Lightbend, Inc.";
+ assert_eq!(parse_scala_version(scala_2_13), Some("v2.13.5".to_string()));
+ }
+
+ #[test]
+ fn test_parse_dotty_version() {
+ let dotty_version = "Scala compiler version 3.0.0-RC1 -- Copyright 2002-2021, LAMP/EPFL";
+ assert_eq!(
+ parse_scala_version(dotty_version),
+ Some("v3.0.0-RC1".to_string())
+ );
+ }
+
+ #[test]
+ fn folder_without_scala_file() -> io::Result<()> {
+ let dir = tempfile::tempdir()?;
+ let actual = ModuleRenderer::new("scala").path(dir.path()).collect();
+ let expected = None;
+ assert_eq!(expected, actual);
+ dir.close()
+ }
+
+ #[test]
+ fn folder_with_scala_file() -> io::Result<()> {
+ let dir = tempfile::tempdir()?;
+ File::create(dir.path().join("Test.scala"))?.sync_all()?;
+ let actual = ModuleRenderer::new("scala").path(dir.path()).collect();
+ let expected = Some(format!("via {}", Color::Red.bold().paint("🆂 v2.13.5 ")));
+ assert_eq!(expected, actual);
+ dir.close()
+ }
+
+ #[test]
+ fn folder_with_scala_file_no_scala_installed() -> io::Result<()> {
+ let dir = tempfile::tempdir()?;
+ File::create(dir.path().join("Test.scala"))?.sync_all()?;
+ let actual = ModuleRenderer::new("scala")
+ .cmd("scalac -version", None)
+ .path(dir.path())
+ .collect();
+ let expected = Some(format!("via {}", Color::Red.bold().paint("🆂 ")));
+ assert_eq!(expected, actual);
+ dir.close()
+ }
+
+ #[test]
+ fn folder_with_sbt_file() -> io::Result<()> {
+ let dir = tempfile::tempdir()?;
+ File::create(dir.path().join("build.sbt"))?.sync_all()?;
+ let actual = ModuleRenderer::new("scala").path(dir.path()).collect();
+ let expected = Some(format!("via {}", Color::Red.bold().paint("🆂 v2.13.5 ")));
+ assert_eq!(expected, actual);
+ dir.close()
+ }
+
+ #[test]
+ fn folder_with_scala_env_file() -> io::Result<()> {
+ let dir = tempfile::tempdir()?;
+ File::create(dir.path().join(".scalaenv"))?.sync_all()?;
+ let actual = ModuleRenderer::new("scala").path(dir.path()).collect();
+ let expected = Some(format!("via {}", Color::Red.bold().paint("🆂 v2.13.5 ")));
+ assert_eq!(expected, actual);
+ dir.close()
+ }
+
+ #[test]
+ fn folder_with_sbt_env_file() -> io::Result<()> {
+ let dir = tempfile::tempdir()?;
+ File::create(dir.path().join(".sbtenv"))?.sync_all()?;
+ let actual = ModuleRenderer::new("scala").path(dir.path()).collect();
+ let expected = Some(format!("via {}", Color::Red.bold().paint("🆂 v2.13.5 ")));
+ assert_eq!(expected, actual);
+ dir.close()
+ }
+
+ #[test]
+ fn folder_with_metals_dir() -> io::Result<()> {
+ let dir = tempfile::tempdir()?;
+ fs::create_dir_all(dir.path().join(".metals"))?;
+ let actual = ModuleRenderer::new("scala").path(dir.path()).collect();
+ let expected = Some(format!("via {}", Color::Red.bold().paint("🆂 v2.13.5 ")));
+ assert_eq!(expected, actual);
+ dir.close()
+ }
+}
diff --git a/src/utils.rs b/src/utils.rs
index 352efb84f..3c02ece94 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -86,6 +86,10 @@ Elixir 1.10 (compiled with Erlang/OTP 22)\n",
stdout: String::from("OpenJDK 64-Bit Server VM (13.0.2+8) for bsd-amd64 JRE (13.0.2+8), built on Feb 6 2020 02:07:52 by \"brew\" with clang 4.2.1 Compatible Apple LLVM 11.0.0 (clang-1100.0.33.17)"),
stderr: String::default(),
}),
+ "scalac -version" => Some(CommandOutput {
+ stdout: String::from("Scala compiler version 2.13.5 -- Copyright 2002-2020, LAMP/EPFL and Lightbend, Inc."),
+ stderr: String::default(),
+ }),
"julia --version" => Some(CommandOutput {
stdout: String::from("julia version 1.4.0\n"),
stderr: String::default(),