@repokit/core 2.1.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +111 -5
- package/Cargo.toml +2 -1
- package/README.md +32 -25
- package/dist/RepoKitConfig.d.mts +2 -2
- package/dist/RepoKitConfig.mjs +3 -3
- package/dist/RepoKitTheme.d.mts +26 -26
- package/dist/RepoKitTheme.mjs +24 -24
- package/dist/index.d.mts +3 -4
- package/dist/index.mjs +1 -2
- package/dist/types.d.mts +16 -7
- package/externals/RepoKitConfig.ts +3 -3
- package/externals/RepoKitTheme.ts +26 -34
- package/externals/index.ts +0 -1
- package/externals/types.ts +20 -6
- package/installation/install.sh +9 -3
- package/internals/argv/argv.rs +133 -0
- package/internals/argv/mod.rs +1 -0
- package/internals/internal_commands/help.rs +6 -6
- package/internals/internal_commands/internal_registry.rs +5 -4
- package/internals/internal_commands/list_owners.rs +10 -10
- package/internals/internal_commands/list_themes.rs +113 -0
- package/internals/internal_commands/mod.rs +1 -0
- package/internals/internal_filesystem/internal_filesystem.rs +122 -1
- package/internals/logger/logger.rs +18 -1
- package/internals/main.rs +1 -0
- package/internals/repokit/interfaces.rs +2 -2
- package/internals/repokit/repokit.rs +5 -2
- package/internals/themes/built_in_themes/mod.rs +3 -0
- package/internals/themes/built_in_themes/money.rs +41 -0
- package/internals/themes/built_in_themes/seeing_red.rs +41 -0
- package/internals/themes/built_in_themes/the_blues.rs +41 -0
- package/internals/themes/mod.rs +3 -0
- package/internals/themes/theme.rs +48 -70
- package/internals/themes/theme_colors.rs +36 -0
- package/internals/themes/theme_inputs.rs +34 -0
- package/internals/themes/theme_registry.rs +80 -7
- package/media/list-themes.webp +0 -0
- package/package.json +2 -1
- package/dist/Themes.d.mts +0 -8
- package/dist/Themes.mjs +0 -31
- package/externals/Themes.ts +0 -31
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
use std::{collections::HashMap, env};
|
|
2
|
+
|
|
3
|
+
use crate::logger::logger::Logger;
|
|
4
|
+
|
|
5
|
+
#[derive(Clone)]
|
|
6
|
+
pub enum ArgvType {
|
|
7
|
+
String,
|
|
8
|
+
Boolean,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
#[derive(Clone)]
|
|
12
|
+
pub struct ArgvOption {
|
|
13
|
+
pub value_type: ArgvType,
|
|
14
|
+
pub short: Option<String>,
|
|
15
|
+
pub name: String,
|
|
16
|
+
pub multiple: Option<bool>,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
pub struct Argv {
|
|
20
|
+
pub values: HashMap<String, Vec<String>>,
|
|
21
|
+
lookup_table: HashMap<String, ArgvOption>,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
impl Argv {
|
|
25
|
+
pub fn new(schema: Vec<ArgvOption>, args: Option<Vec<String>>) -> Argv {
|
|
26
|
+
let mut argv = Argv {
|
|
27
|
+
values: HashMap::new(),
|
|
28
|
+
lookup_table: Argv::build_option_table(&schema),
|
|
29
|
+
};
|
|
30
|
+
argv.parse(args);
|
|
31
|
+
argv
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
pub fn has(&self, key: &str) -> bool {
|
|
35
|
+
let fallback_bucket = Vec::new();
|
|
36
|
+
let values = self.values.get(key).unwrap_or(&fallback_bucket);
|
|
37
|
+
!values.is_empty()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
pub fn get_first(&self, key: &str) -> String {
|
|
41
|
+
let fallback_bucket = Vec::new();
|
|
42
|
+
let values = self.values.get(key).unwrap_or(&fallback_bucket);
|
|
43
|
+
if values.is_empty() {
|
|
44
|
+
return "".to_string();
|
|
45
|
+
}
|
|
46
|
+
values[0].clone()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
pub fn get_all(&mut self, key: &str) -> &mut Vec<String> {
|
|
50
|
+
self.values.entry(key.to_string()).or_default()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
fn parse(&mut self, argv: Option<Vec<String>>) {
|
|
54
|
+
let args = argv.unwrap_or(env::args().collect());
|
|
55
|
+
let mut pointer = 0;
|
|
56
|
+
let length = args.len();
|
|
57
|
+
while pointer < length {
|
|
58
|
+
let arg = &args[pointer];
|
|
59
|
+
if self.lookup_table.contains_key(arg) {
|
|
60
|
+
let schema = self.lookup_table.get(arg).expect("arg exists");
|
|
61
|
+
let values = self.values.entry(schema.name.to_string()).or_default();
|
|
62
|
+
match schema.value_type {
|
|
63
|
+
ArgvType::Boolean => {
|
|
64
|
+
values.push("1".to_string());
|
|
65
|
+
pointer += 1;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
ArgvType::String => {
|
|
69
|
+
let mut current = pointer + 1;
|
|
70
|
+
while current < length {
|
|
71
|
+
let value = &args[current];
|
|
72
|
+
if self.lookup_table.contains_key(value) {
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
if values.len() == 1
|
|
76
|
+
&& (schema.multiple.is_none()
|
|
77
|
+
|| schema.multiple.is_some_and(|v| !v))
|
|
78
|
+
{
|
|
79
|
+
Logger::error(
|
|
80
|
+
format!(
|
|
81
|
+
"Recived more than one value for the option {}",
|
|
82
|
+
Logger::with_theme(|theme| theme.highlight(&schema.name))
|
|
83
|
+
)
|
|
84
|
+
.as_str(),
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
values.push(value.to_string());
|
|
88
|
+
current += 1;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
pointer += 1;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
fn build_option_table(options: &Vec<ArgvOption>) -> HashMap<String, ArgvOption> {
|
|
98
|
+
let mut table: HashMap<String, ArgvOption> = HashMap::new();
|
|
99
|
+
for option in options {
|
|
100
|
+
if option.name.len() < 2 {
|
|
101
|
+
Logger::exit_with_error("Option names must be at least 2 characters");
|
|
102
|
+
}
|
|
103
|
+
let first_char = option
|
|
104
|
+
.name
|
|
105
|
+
.chars()
|
|
106
|
+
.next()
|
|
107
|
+
.expect("already checked for emptiness")
|
|
108
|
+
.to_string();
|
|
109
|
+
let short_flag = option.short.as_ref().unwrap_or(&first_char);
|
|
110
|
+
let flags = [format!("--{}", option.name), format!("-{}", short_flag)];
|
|
111
|
+
for flag in flags {
|
|
112
|
+
if table.contains_key(&flag) {
|
|
113
|
+
Logger::error(
|
|
114
|
+
format!(
|
|
115
|
+
"I encountered the flag {} more than once.",
|
|
116
|
+
Logger::with_theme(|theme| theme.highlight(&flag)),
|
|
117
|
+
)
|
|
118
|
+
.as_str(),
|
|
119
|
+
);
|
|
120
|
+
Logger::error(
|
|
121
|
+
format!(
|
|
122
|
+
"Short flags will default to the first letter of the option's name. If two options begin with the same letter, please specify the {} option for one of them.",
|
|
123
|
+
Logger::with_theme(|theme| theme.highlight("short")),
|
|
124
|
+
)
|
|
125
|
+
.as_str(),
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
table.insert(flag, option.clone());
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
table
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pub mod argv;
|
|
@@ -101,13 +101,13 @@ impl Help {
|
|
|
101
101
|
if root_commands.is_empty() {
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
104
|
-
let sorted_commands = Help::sort_root_commands(root_commands);
|
|
105
104
|
Logger::info("Project Level Commands:");
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
105
|
+
Logger::with_surrounding_space(|| {
|
|
106
|
+
let sorted_commands = Help::sort_root_commands(root_commands);
|
|
107
|
+
for command in sorted_commands {
|
|
108
|
+
Help::log_root_command(&command);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
pub fn log_external_commands(externals: &HashMap<String, RepoKitCommand>) {
|
|
@@ -5,9 +5,9 @@ use crate::{
|
|
|
5
5
|
intenal_executable::InternalExecutable, internal_executable_definition::RepoKitScope,
|
|
6
6
|
},
|
|
7
7
|
internal_commands::{
|
|
8
|
-
list_commands::ListCommands, list_owners::ListOwners,
|
|
9
|
-
onboarder::Onboarder, register_command::RegisterCommand,
|
|
10
|
-
upgrade_repokit::UpgradeRepoKit,
|
|
8
|
+
list_commands::ListCommands, list_owners::ListOwners, list_themes::ListThemes,
|
|
9
|
+
locate_command::LocateCommand, onboarder::Onboarder, register_command::RegisterCommand,
|
|
10
|
+
search_commands::SearchCommands, upgrade_repokit::UpgradeRepoKit,
|
|
11
11
|
},
|
|
12
12
|
};
|
|
13
13
|
|
|
@@ -23,7 +23,7 @@ impl InternalRegistry {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
pub fn get_all(&self) -> HashMap<String, Box<dyn InternalExecutable>> {
|
|
26
|
-
let internals: [Box<dyn InternalExecutable>;
|
|
26
|
+
let internals: [Box<dyn InternalExecutable>; 8] = [
|
|
27
27
|
Box::new(Onboarder::new(&self.scope)),
|
|
28
28
|
Box::new(ListCommands::new(&self.scope)),
|
|
29
29
|
Box::new(SearchCommands::new(&self.scope)),
|
|
@@ -31,6 +31,7 @@ impl InternalRegistry {
|
|
|
31
31
|
Box::new(LocateCommand::new(&self.scope)),
|
|
32
32
|
Box::new(RegisterCommand::new(&self.scope)),
|
|
33
33
|
Box::new(UpgradeRepoKit::new(&self.scope)),
|
|
34
|
+
Box::new(ListThemes::new(&self.scope)),
|
|
34
35
|
];
|
|
35
36
|
HashMap::from(internals.map(|x| (x.get_definition().name.to_string(), x)))
|
|
36
37
|
}
|
|
@@ -51,17 +51,17 @@ impl InternalExecutable for ListOwners {
|
|
|
51
51
|
if owners.is_empty() {
|
|
52
52
|
return Logger::exit_with_info("No owners found");
|
|
53
53
|
}
|
|
54
|
-
println!();
|
|
55
54
|
let mut list: Vec<String> = owners.into_iter().collect();
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
55
|
+
Logger::with_surrounding_space(|| {
|
|
56
|
+
sort_str_slice(&mut list);
|
|
57
|
+
for (index, owner) in list.iter().enumerate() {
|
|
58
|
+
println!(
|
|
59
|
+
"{}{}",
|
|
60
|
+
Logger::indent(None),
|
|
61
|
+
Logger::cyan(format!("{}. {}", index + 1, &owner).as_str()),
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
fn help(&self) {
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use alphanumeric_sort::sort_str_slice;
|
|
4
|
+
use colored::Colorize;
|
|
5
|
+
|
|
6
|
+
use crate::{
|
|
7
|
+
argv::argv::{Argv, ArgvOption, ArgvType},
|
|
8
|
+
executables::{
|
|
9
|
+
intenal_executable::InternalExecutable,
|
|
10
|
+
internal_executable_definition::{
|
|
11
|
+
InternalExecutableDefinition, InternalExecutableDefinitionInput, RepoKitScope,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
internal_commands::help::Help,
|
|
15
|
+
logger::logger::Logger,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
pub struct ListThemes {
|
|
19
|
+
pub scope: RepoKitScope,
|
|
20
|
+
pub definition: InternalExecutableDefinition,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
impl ListThemes {
|
|
24
|
+
pub fn new(scope: &RepoKitScope) -> ListThemes {
|
|
25
|
+
ListThemes {
|
|
26
|
+
scope: scope.clone(),
|
|
27
|
+
definition: InternalExecutableDefinition::define(InternalExecutableDefinitionInput {
|
|
28
|
+
name: "themes",
|
|
29
|
+
description: "Lists your repositories available themes",
|
|
30
|
+
args: [(
|
|
31
|
+
"(--set | -s)",
|
|
32
|
+
"An optional flag allowing you to set your theme",
|
|
33
|
+
)],
|
|
34
|
+
}),
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
fn list_themes(&self) {
|
|
39
|
+
Logger::info("Listing available themes");
|
|
40
|
+
let themes = Logger::with_registry(|registry| registry.themes.clone());
|
|
41
|
+
let current_theme = Logger::with_theme(|theme| theme.name.clone());
|
|
42
|
+
let mut keys: Vec<&String> = themes.keys().collect();
|
|
43
|
+
sort_str_slice(&mut keys);
|
|
44
|
+
Logger::with_surrounding_space(|| {
|
|
45
|
+
let mut pointer = 1;
|
|
46
|
+
for name in &keys {
|
|
47
|
+
let mut post_fix = "";
|
|
48
|
+
let is_active_theme = name.as_str() == current_theme;
|
|
49
|
+
if is_active_theme {
|
|
50
|
+
post_fix = " <--- selected";
|
|
51
|
+
}
|
|
52
|
+
println!(
|
|
53
|
+
"{}{}{}",
|
|
54
|
+
Logger::indent(None),
|
|
55
|
+
Logger::with_theme(|theme| {
|
|
56
|
+
let name_text = if is_active_theme {
|
|
57
|
+
theme.highlight(name).bold()
|
|
58
|
+
} else {
|
|
59
|
+
theme.highlight(name)
|
|
60
|
+
};
|
|
61
|
+
format!("{}. {}", pointer.to_string().as_str(), name_text)
|
|
62
|
+
}),
|
|
63
|
+
post_fix
|
|
64
|
+
);
|
|
65
|
+
pointer += 1;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
impl InternalExecutable for ListThemes {
|
|
72
|
+
fn run(&self, args: Vec<String>, _: &HashMap<String, Box<dyn InternalExecutable>>) {
|
|
73
|
+
let argv = Argv::new(
|
|
74
|
+
vec![ArgvOption {
|
|
75
|
+
name: "set".to_string(),
|
|
76
|
+
value_type: ArgvType::String,
|
|
77
|
+
short: None,
|
|
78
|
+
multiple: None,
|
|
79
|
+
}],
|
|
80
|
+
Some(args),
|
|
81
|
+
);
|
|
82
|
+
if !argv.has("set") {
|
|
83
|
+
return self.list_themes();
|
|
84
|
+
}
|
|
85
|
+
let desired_theme = argv.get_first("set");
|
|
86
|
+
if Logger::with_registry(|registry| !registry.has(&desired_theme)) {
|
|
87
|
+
Logger::error(
|
|
88
|
+
format!(
|
|
89
|
+
"I'm not aware of a theme named {}",
|
|
90
|
+
Logger::with_theme(|theme| theme.highlight(&desired_theme))
|
|
91
|
+
)
|
|
92
|
+
.as_str(),
|
|
93
|
+
);
|
|
94
|
+
return self.list_themes();
|
|
95
|
+
}
|
|
96
|
+
Logger::with_registry(|mut registry| registry.set_theme(&self.scope.root, &desired_theme));
|
|
97
|
+
Logger::info(
|
|
98
|
+
format!(
|
|
99
|
+
"Your theme has been set to {}",
|
|
100
|
+
Logger::with_theme(|theme| theme.highlight(&desired_theme))
|
|
101
|
+
)
|
|
102
|
+
.as_str(),
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
fn help(&self) {
|
|
107
|
+
Help::log_internal_command(&self.definition);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
fn get_definition(&self) -> &InternalExecutableDefinition {
|
|
111
|
+
&self.definition
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
use normalize_path::NormalizePath;
|
|
2
|
+
|
|
3
|
+
use regex::Regex;
|
|
4
|
+
use shellexpand::tilde;
|
|
2
5
|
use std::{
|
|
3
|
-
fs::File,
|
|
6
|
+
fs::{self, File},
|
|
7
|
+
io::{BufRead, BufReader, Lines},
|
|
4
8
|
path::{Path, PathBuf},
|
|
5
9
|
};
|
|
6
10
|
|
|
@@ -58,6 +62,58 @@ impl InternalFileSystem {
|
|
|
58
62
|
root
|
|
59
63
|
}
|
|
60
64
|
|
|
65
|
+
pub fn read_theme_preference(&self) -> String {
|
|
66
|
+
let default = Logger::with_registry(|registry| registry.default_theme.clone());
|
|
67
|
+
let theme = self.read_dot_file(&mut |mut lines, _| {
|
|
68
|
+
if let Some(theme_preference) = lines.nth(1)
|
|
69
|
+
&& let Ok(preference) = theme_preference
|
|
70
|
+
{
|
|
71
|
+
return preference;
|
|
72
|
+
}
|
|
73
|
+
default.to_string()
|
|
74
|
+
});
|
|
75
|
+
theme.unwrap_or(default)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
pub fn store_theme_preference(&self, theme: &str) {
|
|
79
|
+
self.read_dot_file(&mut |lines, path| {
|
|
80
|
+
let mut content: Vec<String> = lines.map(|line| line.unwrap()).collect();
|
|
81
|
+
let theme_text = theme.to_string();
|
|
82
|
+
if content.len() >= 2 {
|
|
83
|
+
content[1] = theme_text;
|
|
84
|
+
} else {
|
|
85
|
+
content.push(theme_text);
|
|
86
|
+
}
|
|
87
|
+
fs::write(path, content.join("\n"))
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
pub fn read_dot_file<R>(
|
|
92
|
+
&self,
|
|
93
|
+
func: &mut impl FnMut(Lines<BufReader<File>>, PathBuf) -> R,
|
|
94
|
+
) -> Option<R> {
|
|
95
|
+
let file_path = self.create_dot_file_if_not_exists();
|
|
96
|
+
match file_path {
|
|
97
|
+
Some(path) => {
|
|
98
|
+
if let Ok(file) = File::open(&path) {
|
|
99
|
+
let lines = BufReader::new(file).lines();
|
|
100
|
+
return Some(func(lines, path));
|
|
101
|
+
}
|
|
102
|
+
None
|
|
103
|
+
}
|
|
104
|
+
None => None,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
pub fn home() -> Option<PathBuf> {
|
|
109
|
+
let expanded_path_str = tilde("~/");
|
|
110
|
+
let path = Path::new(expanded_path_str.as_ref()).normalize();
|
|
111
|
+
if path.is_absolute() && path.exists() {
|
|
112
|
+
return Some(path);
|
|
113
|
+
}
|
|
114
|
+
None
|
|
115
|
+
}
|
|
116
|
+
|
|
61
117
|
fn commands_directory(&self) -> PathBuf {
|
|
62
118
|
self.absolute(format!("{}/dist/commands", self.package_directory()).as_str())
|
|
63
119
|
}
|
|
@@ -80,4 +136,69 @@ impl InternalFileSystem {
|
|
|
80
136
|
.into_string()
|
|
81
137
|
.expect("Cannot construct path")
|
|
82
138
|
}
|
|
139
|
+
|
|
140
|
+
fn create_dot_file_if_not_exists(&self) -> Option<PathBuf> {
|
|
141
|
+
match InternalFileSystem::home() {
|
|
142
|
+
Some(home) => {
|
|
143
|
+
let dot_file_path = home.join(".repokit");
|
|
144
|
+
if !&dot_file_path.exists() {
|
|
145
|
+
let found_version = self.current_version();
|
|
146
|
+
found_version.as_ref()?;
|
|
147
|
+
let version_string = found_version.unwrap();
|
|
148
|
+
let result = fs::write(&dot_file_path, format!("{version_string}\n"));
|
|
149
|
+
if result.is_err() {
|
|
150
|
+
return None;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
Some(dot_file_path)
|
|
154
|
+
}
|
|
155
|
+
None => {
|
|
156
|
+
Logger::error(
|
|
157
|
+
"I encountered an issue when attempting to create a cache file on your machine",
|
|
158
|
+
);
|
|
159
|
+
Logger::error(
|
|
160
|
+
format!(
|
|
161
|
+
"Please create a file called {} in your home directory",
|
|
162
|
+
Logger::with_theme(|theme| theme.highlight(".repokit"))
|
|
163
|
+
)
|
|
164
|
+
.as_str(),
|
|
165
|
+
);
|
|
166
|
+
Logger::error(
|
|
167
|
+
"This file will be used to store settings and indicators that optimize how repokit runs in your repository",
|
|
168
|
+
);
|
|
169
|
+
None
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
pub fn current_version(&self) -> Option<String> {
|
|
175
|
+
let package_path = Path::new(&self.root)
|
|
176
|
+
.join(InternalFileSystem::package_directory(self))
|
|
177
|
+
.normalize();
|
|
178
|
+
let package_json_path = package_path.join("package.json");
|
|
179
|
+
let file = File::open(package_json_path);
|
|
180
|
+
if file.is_err() {
|
|
181
|
+
return None;
|
|
182
|
+
}
|
|
183
|
+
let lines = BufReader::new(file.unwrap()).lines();
|
|
184
|
+
let version_matcher = Regex::new(r#""([^"]*)""#).unwrap();
|
|
185
|
+
for line in lines.flatten() {
|
|
186
|
+
if line.contains("\"version\": ") {
|
|
187
|
+
let captures: Vec<String> = version_matcher
|
|
188
|
+
.captures_iter(&line)
|
|
189
|
+
.filter_map(|item| {
|
|
190
|
+
item.get(1)
|
|
191
|
+
.map(|match_text| match_text.as_str().to_string())
|
|
192
|
+
})
|
|
193
|
+
.collect();
|
|
194
|
+
let version = captures.get(1);
|
|
195
|
+
if version.is_some() {
|
|
196
|
+
return Some(version.unwrap().to_string());
|
|
197
|
+
} else {
|
|
198
|
+
return None;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
None
|
|
203
|
+
}
|
|
83
204
|
}
|
|
@@ -38,10 +38,27 @@ impl Logger {
|
|
|
38
38
|
exit(0);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
pub fn list(items: &[&str], indentation: Option<i32>) {
|
|
42
|
+
Logger::with_surrounding_space(|| {
|
|
43
|
+
let mut pointer = 0;
|
|
44
|
+
for item in items {
|
|
45
|
+
println!("{}{}. {}", Logger::indent(indentation), pointer + 1, item);
|
|
46
|
+
pointer += 1
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
41
51
|
pub fn space_around(message: &str) {
|
|
42
52
|
println!("\n{}{}\n", Logger::info_prefix(), message);
|
|
43
53
|
}
|
|
44
54
|
|
|
55
|
+
pub fn with_surrounding_space<F>(mut func: impl FnMut() -> F) -> F {
|
|
56
|
+
println!();
|
|
57
|
+
let result = func();
|
|
58
|
+
println!();
|
|
59
|
+
result
|
|
60
|
+
}
|
|
61
|
+
|
|
45
62
|
pub fn log_file_path(path: &str) {
|
|
46
63
|
println!(
|
|
47
64
|
"\n{}{}\n",
|
|
@@ -80,7 +97,7 @@ impl Logger {
|
|
|
80
97
|
}
|
|
81
98
|
|
|
82
99
|
pub fn with_theme<R>(func: impl Fn(&Theme) -> R) -> R {
|
|
83
|
-
Logger::with_registry(|registry| func(
|
|
100
|
+
Logger::with_registry(|registry| func(registry.current_theme()))
|
|
84
101
|
}
|
|
85
102
|
|
|
86
103
|
pub fn with_registry<R>(func: impl Fn(MutexGuard<'_, ThemeRegistry>) -> R) -> R {
|
package/internals/main.rs
CHANGED
|
@@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|
|
2
2
|
|
|
3
3
|
use serde::Deserialize;
|
|
4
4
|
|
|
5
|
-
use crate::themes::
|
|
5
|
+
use crate::themes::theme_inputs::RepoKitTheme;
|
|
6
6
|
|
|
7
7
|
#[derive(Debug, Deserialize, Clone)]
|
|
8
8
|
pub struct CommandDefinition {
|
|
@@ -35,7 +35,7 @@ pub struct RepoKitConfig {
|
|
|
35
35
|
pub project: String,
|
|
36
36
|
pub thirdParty: Vec<RepoKitCommand>,
|
|
37
37
|
pub commands: HashMap<String, CommandDefinition>,
|
|
38
|
-
pub
|
|
38
|
+
pub themes: Vec<RepoKitTheme>,
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
#[derive(Debug, Deserialize, Clone)]
|
|
@@ -11,6 +11,7 @@ use crate::{
|
|
|
11
11
|
},
|
|
12
12
|
executor::executor::Executor,
|
|
13
13
|
internal_commands::help::Help,
|
|
14
|
+
internal_filesystem::internal_filesystem::InternalFileSystem,
|
|
14
15
|
logger::logger::Logger,
|
|
15
16
|
repokit::interfaces::{RepoKitCommand, RepoKitConfig},
|
|
16
17
|
validations::command_validations::CommandValidations,
|
|
@@ -23,9 +24,11 @@ pub struct RepoKit {
|
|
|
23
24
|
impl RepoKit {
|
|
24
25
|
pub fn new(root: String, configuration: RepoKitConfig) -> RepoKit {
|
|
25
26
|
Logger::set_name(&configuration.project);
|
|
26
|
-
|
|
27
|
-
Logger::with_registry(|mut registry| registry.
|
|
27
|
+
for theme in &configuration.themes {
|
|
28
|
+
Logger::with_registry(|mut registry| registry.register_user_theme(theme))
|
|
28
29
|
}
|
|
30
|
+
let theme = InternalFileSystem::new(&root).read_theme_preference();
|
|
31
|
+
Logger::with_registry(|mut registry| registry.set_theme(&root, &theme));
|
|
29
32
|
RepoKit {
|
|
30
33
|
scope: RepoKitScope {
|
|
31
34
|
root,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
use colored::Color;
|
|
2
|
+
|
|
3
|
+
use crate::themes::theme_colors::ThemeColors;
|
|
4
|
+
|
|
5
|
+
pub const MONEY: ThemeColors = ThemeColors {
|
|
6
|
+
prefixColor: Color::TrueColor {
|
|
7
|
+
r: 26,
|
|
8
|
+
g: 227,
|
|
9
|
+
b: 133,
|
|
10
|
+
},
|
|
11
|
+
commandColor: Color::TrueColor {
|
|
12
|
+
r: 82,
|
|
13
|
+
g: 234,
|
|
14
|
+
b: 74,
|
|
15
|
+
},
|
|
16
|
+
subcommandColor: Color::TrueColor {
|
|
17
|
+
r: 51,
|
|
18
|
+
g: 241,
|
|
19
|
+
b: 162,
|
|
20
|
+
},
|
|
21
|
+
argColor: Color::TrueColor {
|
|
22
|
+
r: 124,
|
|
23
|
+
g: 244,
|
|
24
|
+
b: 102,
|
|
25
|
+
},
|
|
26
|
+
descriptionColor: Color::TrueColor {
|
|
27
|
+
r: 126,
|
|
28
|
+
g: 168,
|
|
29
|
+
b: 140,
|
|
30
|
+
},
|
|
31
|
+
errorPrefixColor: Color::TrueColor {
|
|
32
|
+
r: 220,
|
|
33
|
+
g: 36,
|
|
34
|
+
b: 100,
|
|
35
|
+
},
|
|
36
|
+
highlightColor: Color::TrueColor {
|
|
37
|
+
r: 25,
|
|
38
|
+
g: 206,
|
|
39
|
+
b: 91,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
use colored::Color;
|
|
2
|
+
|
|
3
|
+
use crate::themes::theme_colors::ThemeColors;
|
|
4
|
+
|
|
5
|
+
pub const SEEING_RED: ThemeColors = ThemeColors {
|
|
6
|
+
prefixColor: Color::TrueColor {
|
|
7
|
+
r: 220,
|
|
8
|
+
g: 36,
|
|
9
|
+
b: 91,
|
|
10
|
+
},
|
|
11
|
+
commandColor: Color::TrueColor {
|
|
12
|
+
r: 220,
|
|
13
|
+
g: 36,
|
|
14
|
+
b: 36,
|
|
15
|
+
},
|
|
16
|
+
subcommandColor: Color::TrueColor {
|
|
17
|
+
r: 220,
|
|
18
|
+
g: 131,
|
|
19
|
+
b: 36,
|
|
20
|
+
},
|
|
21
|
+
argColor: Color::TrueColor {
|
|
22
|
+
r: 220,
|
|
23
|
+
g: 205,
|
|
24
|
+
b: 36,
|
|
25
|
+
},
|
|
26
|
+
descriptionColor: Color::TrueColor {
|
|
27
|
+
r: 179,
|
|
28
|
+
g: 100,
|
|
29
|
+
b: 151,
|
|
30
|
+
},
|
|
31
|
+
errorPrefixColor: Color::TrueColor {
|
|
32
|
+
r: 220,
|
|
33
|
+
g: 36,
|
|
34
|
+
b: 39,
|
|
35
|
+
},
|
|
36
|
+
highlightColor: Color::TrueColor {
|
|
37
|
+
r: 237,
|
|
38
|
+
g: 175,
|
|
39
|
+
b: 41,
|
|
40
|
+
},
|
|
41
|
+
};
|