summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/configs/mod.rs3
-rw-r--r--src/configs/rlang.rs31
-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/rlang.rs159
-rw-r--r--src/utils.rs14
7 files changed, 212 insertions, 0 deletions
diff --git a/src/configs/mod.rs b/src/configs/mod.rs
index e307060da..ec5434fc3 100644
--- a/src/configs/mod.rs
+++ b/src/configs/mod.rs
@@ -47,6 +47,7 @@ pub mod php;
pub mod purescript;
pub mod python;
pub mod red;
+pub mod rlang;
pub mod ruby;
pub mod rust;
pub mod scala;
@@ -117,6 +118,7 @@ pub struct FullConfig<'a> {
php: php::PhpConfig<'a>,
purescript: purescript::PureScriptConfig<'a>,
python: python::PythonConfig<'a>,
+ rlang: rlang::RLangConfig<'a>,
red: red::RedConfig<'a>,
ruby: ruby::RubyConfig<'a>,
rust: rust::RustConfig<'a>,
@@ -186,6 +188,7 @@ impl<'a> Default for FullConfig<'a> {
purescript: Default::default(),
python: Default::default(),
red: Default::default(),
+ rlang: Default::default(),
ruby: Default::default(),
rust: Default::default(),
scala: Default::default(),
diff --git a/src/configs/rlang.rs b/src/configs/rlang.rs
new file mode 100644
index 000000000..e08852829
--- /dev/null
+++ b/src/configs/rlang.rs
@@ -0,0 +1,31 @@
+use crate::config::ModuleConfig;
+
+use serde::Serialize;
+use starship_module_config_derive::ModuleConfig;
+
+#[derive(Clone, ModuleConfig, Serialize)]
+pub struct RLangConfig<'a> {
+ pub format: &'a str,
+ pub version_format: &'a str,
+ pub style: &'a str,
+ pub symbol: &'a str,
+ pub disabled: bool,
+ pub detect_extensions: Vec<&'a str>,
+ pub detect_files: Vec<&'a str>,
+ pub detect_folders: Vec<&'a str>,
+}
+
+impl<'a> Default for RLangConfig<'a> {
+ fn default() -> Self {
+ RLangConfig {
+ format: "via [$symbol($version )]($style)",
+ version_format: "v${raw}",
+ style: "blue bold",
+ symbol: "📐 ",
+ disabled: false,
+ detect_extensions: vec!["R", "Rd", "Rmd", "Rproj", "Rsx"],
+ detect_files: vec![".Rprofile"],
+ detect_folders: vec![".Rproj.user"],
+ }
+ }
+}
diff --git a/src/configs/starship_root.rs b/src/configs/starship_root.rs
index f8cc2c62d..bf656ebea 100644
--- a/src/configs/starship_root.rs
+++ b/src/configs/starship_root.rs
@@ -52,6 +52,7 @@ pub const PROMPT_ORDER: &[&str] = &[
"php",
"purescript",
"python",
+ "rlang",
"red",
"ruby",
"rust",
diff --git a/src/module.rs b/src/module.rs
index 860ca04c9..67b0f5d02 100644
--- a/src/module.rs
+++ b/src/module.rs
@@ -52,6 +52,7 @@ pub const ALL_MODULES: &[&str] = &[
"perl",
"purescript",
"python",
+ "rlang",
"red",
"ruby",
"crystal",
diff --git a/src/modules/mod.rs b/src/modules/mod.rs
index b255a7f2a..4e06309cf 100644
--- a/src/modules/mod.rs
+++ b/src/modules/mod.rs
@@ -43,6 +43,7 @@ mod php;
mod purescript;
mod python;
mod red;
+mod rlang;
mod ruby;
mod rust;
mod scala;
@@ -118,6 +119,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option<Module<'a>> {
"php" => php::module(context),
"purescript" => purescript::module(context),
"python" => python::module(context),
+ "rlang" => rlang::module(context),
"red" => red::module(context),
"ruby" => ruby::module(context),
"rust" => rust::module(context),
@@ -201,6 +203,7 @@ pub fn description(module: &str) -> &'static str {
"php" => "The currently installed version of PHP",
"purescript" => "The currently installed version of PureScript",
"python" => "The currently installed version of Python",
+ "rlang" => "The currently installed version of R",
"red" => "The currently installed version of Red",
"ruby" => "The currently installed version of Ruby",
"rust" => "The currently installed version of Rust",
diff --git a/src/modules/rlang.rs b/src/modules/rlang.rs
new file mode 100644
index 000000000..e6cac083f
--- /dev/null
+++ b/src/modules/rlang.rs
@@ -0,0 +1,159 @@
+use super::{Context, Module, RootModuleConfig};
+use crate::formatter::VersionFormatter;
+
+use crate::configs::rlang::RLangConfig;
+use crate::formatter::StringFormatter;
+
+pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
+ let mut module = context.new_module("rlang");
+ let config: RLangConfig = RLangConfig::try_load(module.config);
+
+ let is_r_project = context
+ .try_begin_scan()?
+ .set_files(&config.detect_files)
+ .set_extensions(&config.detect_extensions)
+ .set_folders(&config.detect_folders)
+ .is_match();
+ if !is_r_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 r_version = get_r_version(context)?;
+ VersionFormatter::format_module_version(
+ module.get_name(),
+ &r_version,
+ config.version_format,
+ )
+ .map(Ok)
+ }
+ _ => None,
+ })
+ .parse(None)
+ });
+
+ module.set_segments(match parsed {
+ Ok(segments) => segments,
+ Err(error) => {
+ log::warn!("Error in module `rlang`:\n{}", error);
+ return None;
+ }
+ });
+
+ Some(module)
+}
+
+fn get_r_version(context: &Context) -> Option<String> {
+ let r_version = context.exec_cmd("R", &["--version"])?.stderr;
+ parse_version(&r_version)
+}
+
+fn parse_version(r_version: &str) -> Option<String> {
+ r_version
+ .lines()
+ // take first line
+ .next()?
+ // split into ["R", "version", "3.6.3", "(2020-02-29)", ...]
+ .split_whitespace()
+ // and pick version entry at index 2, i.e. "3.6.3".
+ .nth(2)
+ .map(ToString::to_string)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::parse_version;
+ use crate::test::ModuleRenderer;
+ use ansi_term::Color;
+ use std::fs;
+ use std::fs::File;
+ use std::io;
+
+ #[test]
+ fn test_parse_r_version() {
+ let r_v3 = r#"R version 4.1.0 (2021-05-18) -- "Camp Pontanezen"
+Copyright (C) 2021 The R Foundation for Statistical Computing
+Platform: x86_64-w64-mingw32/x64 (64-bit)\n
+
+R is free software and comes with ABSOLUTELY NO WARRANTY.
+You are welcome to redistribute it under the terms of the
+GNU General Public License versions 2 or 3.
+For more information about these matters see
+https://www.gnu.org/licenses/."#;
+ assert_eq!(parse_version(r_v3), Some(String::from("4.1.0")));
+ }
+
+ #[test]
+ fn folder_with_r_files() -> io::Result<()> {
+ let dir = tempfile::tempdir()?;
+ File::create(dir.path().join("analysis.R"))?.sync_all()?;
+ check_r_render(&dir);
+ dir.close()
+ }
+
+ #[test]
+ fn folder_with_rd_files() -> io::Result<()> {
+ let dir = tempfile::tempdir()?;
+ File::create(dir.path().join("analysis.Rd"))?.sync_all()?;
+ check_r_render(&dir);
+ dir.close()
+ }
+
+ #[test]
+ fn folder_with_rmd_files() -> io::Result<()> {
+ let dir = tempfile::tempdir()?;
+ File::create(dir.path().join("analysis.Rmd"))?.sync_all()?;
+ check_r_render(&dir);
+ dir.close()
+ }
+
+ #[test]
+ fn folder_with_rproj_files() -> io::Result<()> {
+ let dir = tempfile::tempdir()?;
+ File::create(dir.path().join("analysis.Rproj"))?.sync_all()?;
+ check_r_render(&dir);
+ dir.close()
+ }
+
+ #[test]
+ fn folder_with_rsx_files() -> io::Result<()> {
+ let dir = tempfile::tempdir()?;
+ File::create(dir.path().join("analysis.Rsx"))?.sync_all()?;
+ check_r_render(&dir);
+ dir.close()
+ }
+
+ #[test]
+ fn folder_with_rprofile_files() -> io::Result<()> {
+ let dir = tempfile::tempdir()?;
+ File::create(dir.path().join(".Rprofile"))?.sync_all()?;
+ check_r_render(&dir);
+ dir.close()
+ }
+
+ #[test]
+ fn folder_with_rproj_user_folder() -> io::Result<()> {
+ let dir = tempfile::tempdir()?;
+ let rprofile = dir.path().join(".Rproj.user");
+ fs::create_dir_all(&rprofile)?;
+ check_r_render(&dir);
+ dir.close()
+ }
+
+ fn check_r_render(dir: &tempfile::TempDir) {
+ let actual = ModuleRenderer::new("rlang").path(dir.path()).collect();
+ let expected = Some(format!("via {}", Color::Blue.bold().paint("📐 v4.1.0 ")));
+ assert_eq!(expected, actual);
+ }
+}
diff --git a/src/utils.rs b/src/utils.rs
index 2c32c09a0..67265c9c8 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -175,6 +175,20 @@ active boot switches: -d:release\n",
stdout: String::from("Python 3.8.0\n"),
stderr: String::default(),
}),
+ "R --version" => Some(CommandOutput {
+ stdout: String::default(),
+ stderr: String::from(
+ r#"R version 4.1.0 (2021-05-18) -- "Camp Pontanezen"
+Copyright (C) 2021 The R Foundation for Statistical Computing
+Platform: x86_64-w64-mingw32/x64 (64-bit)\n
+
+R is free software and comes with ABSOLUTELY NO WARRANTY.
+You are welcome to redistribute it under the terms of the
+GNU General Public License versions 2 or 3.
+For more information about these matters see
+https://www.gnu.org/licenses/."#
+ ),
+ }),
"red --version" => Some(CommandOutput {
stdout: String::from("0.6.4\n"),
stderr: String::default()