feat(kotlin): Add the kotlin module (#2026)

Add a module to show the currently installed Kotlin version if a
.kt/.kts file is found in the current folder
This commit is contained in:
Nicola Corti 2020-12-26 15:26:50 +01:00 committed by GitHub
parent 53a08712eb
commit 208251adef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 257 additions and 0 deletions

View File

@ -206,6 +206,7 @@ $golang\
$helm\ $helm\
$java\ $java\
$julia\ $julia\
$kotlin\
$nim\ $nim\
$nodejs\ $nodejs\
$ocaml\ $ocaml\
@ -1442,6 +1443,50 @@ The module will be shown if any of the following conditions are met:
symbol = "∴ " symbol = "∴ "
``` ```
## Kotlin
The `kotlin` module shows the currently installed version of Kotlin.
The module will be shown if any of the following conditions are met:
- The current directory contains a `.kt` or a `.kts` file
### Options
| Option | Default | Description |
| --------------- | ---------------------------------- | ----------------------------------------------------------------------------- |
| `format` | `"via [$symbol$version]($style) "` | The format for the module. |
| `symbol` | `"🅺 "` | A format string representing the symbol of Kotlin. |
| `style` | `"bold blue"` | The style for the module. |
| `kotlin_binary` | `"kotlin"` | Configures the kotlin binary that Starship executes when getting the version. |
| `disabled` | `false` | Disables the `kotlin` module. |
### Variables
| Variable | Example | Description |
| -------- | --------- | ------------------------------------ |
| version | `v1.4.21` | The version of `kotlin` |
| 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
[kotlin]
symbol = "🅺 "
```
```toml
# ~/.config/starship.toml
[kotlin]
# Uses the Kotlin Compiler binary to get the installed version
kotlin_binary = "kotlinc"
```
## Kubernetes ## Kubernetes
Displays the current Kubernetes context name and, if set, the namespace from the kubeconfig file. Displays the current Kubernetes context name and, if set, the namespace from the kubeconfig file.

24
src/configs/kotlin.rs Normal file
View File

@ -0,0 +1,24 @@
use crate::config::{ModuleConfig, RootModuleConfig};
use starship_module_config_derive::ModuleConfig;
#[derive(Clone, ModuleConfig)]
pub struct KotlinConfig<'a> {
pub format: &'a str,
pub symbol: &'a str,
pub style: &'a str,
pub kotlin_binary: &'a str,
pub disabled: bool,
}
impl<'a> RootModuleConfig<'a> for KotlinConfig<'a> {
fn new() -> Self {
KotlinConfig {
format: "via [$symbol$version]($style) ",
symbol: "🅺 ",
style: "bold blue",
kotlin_binary: "kotlin",
disabled: false,
}
}
}

View File

@ -26,6 +26,7 @@ pub mod hostname;
pub mod java; pub mod java;
pub mod jobs; pub mod jobs;
pub mod julia; pub mod julia;
pub mod kotlin;
pub mod kubernetes; pub mod kubernetes;
pub mod lua; pub mod lua;
pub mod memory_usage; pub mod memory_usage;

View File

@ -38,6 +38,7 @@ pub const PROMPT_ORDER: &[&str] = &[
"helm", "helm",
"java", "java",
"julia", "julia",
"kotlin",
"lua", "lua",
"nim", "nim",
"nodejs", "nodejs",

View File

@ -36,6 +36,7 @@ pub const ALL_MODULES: &[&str] = &[
"java", "java",
"jobs", "jobs",
"julia", "julia",
"kotlin",
"kubernetes", "kubernetes",
"line_break", "line_break",
"lua", "lua",

174
src/modules/kotlin.rs Normal file
View File

@ -0,0 +1,174 @@
use super::{Context, Module, RootModuleConfig};
use crate::configs::kotlin::KotlinConfig;
use crate::formatter::StringFormatter;
use crate::utils;
use regex::Regex;
const KOTLIN_VERSION_PATTERN: &str = "(?P<version>[\\d\\.]+[\\d\\.]+[\\d\\.]+)";
/// Creates a module with the current Kotlin version
///
/// Will display the Kotlin version if any of the following criteria are met:
/// - Current directory contains a file with a `.kt` or `.kts` extension
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let is_kotlin_project = context
.try_begin_scan()?
.set_extensions(&["kt", "kts"])
.is_match();
if !is_kotlin_project {
return None;
}
let mut module = context.new_module("kotlin");
let config = KotlinConfig::try_load(module.config);
let kotlin_version = format_kotlin_version(&get_kotlin_version(&config.kotlin_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(&kotlin_version)),
_ => None,
})
.parse(None)
});
module.set_segments(match parsed {
Ok(segments) => segments,
Err(error) => {
log::warn!("Error in module `kotlin`:\n{}", error);
return None;
}
});
Some(module)
}
fn get_kotlin_version(kotlin_binary: &str) -> Option<String> {
match utils::exec_cmd(kotlin_binary, &["-version"]) {
Some(output) => {
if output.stdout.is_empty() {
Some(output.stderr)
} else {
Some(output.stdout)
}
}
None => None,
}
}
fn format_kotlin_version(kotlin_stdout: &str) -> Option<String> {
// kotlin -version output looks like this:
// Kotlin version 1.4.21-release-411 (JRE 14.0.1+7)
// kotlinc -version output looks like this:
// info: kotlinc-jvm 1.4.21 (JRE 14.0.1+7)
let re = Regex::new(KOTLIN_VERSION_PATTERN).ok()?;
let captures = re.captures(kotlin_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::File;
use std::io;
#[test]
fn folder_without_kotlin_files() -> io::Result<()> {
let dir = tempfile::tempdir()?;
let actual = ModuleRenderer::new("kotlin").path(dir.path()).collect();
let expected = None;
assert_eq!(expected, actual);
dir.close()
}
#[test]
fn folder_with_kotlin_file() -> io::Result<()> {
let dir = tempfile::tempdir()?;
File::create(dir.path().join("main.kt"))?.sync_all()?;
let actual = ModuleRenderer::new("kotlin").path(dir.path()).collect();
let expected = Some(format!("via {} ", Color::Blue.bold().paint("🅺 v1.4.21")));
assert_eq!(expected, actual);
dir.close()
}
#[test]
fn folder_with_kotlin_script_file() -> io::Result<()> {
let dir = tempfile::tempdir()?;
File::create(dir.path().join("main.kts"))?.sync_all()?;
let actual = ModuleRenderer::new("kotlin").path(dir.path()).collect();
let expected = Some(format!("via {} ", Color::Blue.bold().paint("🅺 v1.4.21")));
assert_eq!(expected, actual);
dir.close()
}
#[test]
fn kotlin_binary_is_kotlin_runtime() -> io::Result<()> {
let dir = tempfile::tempdir()?;
File::create(dir.path().join("main.kt"))?.sync_all()?;
let config = toml::toml! {
[kotlin]
kotlin_binary = "kotlin"
};
let actual = ModuleRenderer::new("kotlin")
.path(dir.path())
.config(config)
.collect();
let expected = Some(format!("via {} ", Color::Blue.bold().paint("🅺 v1.4.21")));
assert_eq!(expected, actual);
dir.close()
}
#[test]
fn kotlin_binary_is_kotlin_compiler() -> io::Result<()> {
let dir = tempfile::tempdir()?;
File::create(dir.path().join("main.kt"))?.sync_all()?;
let config = toml::toml! {
[kotlin]
kotlin_binary = "kotlinc"
};
let actual = ModuleRenderer::new("kotlin")
.path(dir.path())
.config(config)
.collect();
let expected = Some(format!("via {} ", Color::Blue.bold().paint("🅺 v1.4.21")));
assert_eq!(expected, actual);
dir.close()
}
#[test]
fn test_format_kotlin_version_from_runtime() {
let kotlin_input = "Kotlin version 1.4.21-release-411 (JRE 14.0.1+7)";
assert_eq!(
format_kotlin_version(kotlin_input),
Some("v1.4.21".to_string())
);
}
#[test]
fn test_format_kotlin_version_from_compiler() {
let kotlin_input = "info: kotlinc-jvm 1.4.21 (JRE 14.0.1+7)";
assert_eq!(
format_kotlin_version(kotlin_input),
Some("v1.4.21".to_string())
);
}
}

View File

@ -26,6 +26,7 @@ mod hostname;
mod java; mod java;
mod jobs; mod jobs;
mod julia; mod julia;
mod kotlin;
mod kubernetes; mod kubernetes;
mod line_break; mod line_break;
mod lua; mod lua;
@ -94,6 +95,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option<Module<'a>> {
"java" => java::module(context), "java" => java::module(context),
"jobs" => jobs::module(context), "jobs" => jobs::module(context),
"julia" => julia::module(context), "julia" => julia::module(context),
"kotlin" => kotlin::module(context),
"kubernetes" => kubernetes::module(context), "kubernetes" => kubernetes::module(context),
"line_break" => line_break::module(context), "line_break" => line_break::module(context),
"lua" => lua::module(context), "lua" => lua::module(context),
@ -169,6 +171,7 @@ pub fn description(module: &str) -> &'static str {
"java" => "The currently installed version of Java", "java" => "The currently installed version of Java",
"jobs" => "The current number of jobs running", "jobs" => "The current number of jobs running",
"julia" => "The currently installed version of Julia", "julia" => "The currently installed version of Julia",
"kotlin" => "The currently installed version of Kotlin",
"kubernetes" => "The current Kubernetes context name and, if set, the namespace", "kubernetes" => "The current Kubernetes context name and, if set, the namespace",
"line_break" => "Separates the prompt into two lines", "line_break" => "Separates the prompt into two lines",
"lua" => "The currently installed version of Lua", "lua" => "The currently installed version of Lua",

View File

@ -89,6 +89,14 @@ Elixir 1.10 (compiled with Erlang/OTP 22)\n",
stdout: String::from("julia version 1.4.0\n"), stdout: String::from("julia version 1.4.0\n"),
stderr: String::default(), stderr: String::default(),
}), }),
"kotlin -version" => Some(CommandOutput {
stdout: String::from("Kotlin version 1.4.21-release-411 (JRE 14.0.1+7)\n"),
stderr: String::default(),
}),
"kotlinc -version" => Some(CommandOutput {
stdout: String::from("info: kotlinc-jvm 1.4.21 (JRE 14.0.1+7)\n"),
stderr: String::default(),
}),
"lua -v" => Some(CommandOutput{ "lua -v" => Some(CommandOutput{
stdout: String::from("Lua 5.4.0 Copyright (C) 1994-2020 Lua.org, PUC-Rio\n"), stdout: String::from("Lua 5.4.0 Copyright (C) 1994-2020 Lua.org, PUC-Rio\n"),
stderr: String::default(), stderr: String::default(),