@devaloop/devalang 0.0.1-alpha.13 → 0.0.1-alpha.15
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/.devalang +2 -3
- package/Cargo.toml +58 -54
- package/README.md +59 -27
- package/docs/CHANGELOG.md +99 -2
- package/docs/CONTRIBUTING.md +1 -0
- package/docs/ROADMAP.md +3 -3
- package/docs/TODO.md +5 -4
- package/examples/automation.deva +44 -0
- package/examples/bank.deva +2 -4
- package/examples/function.deva +15 -0
- package/examples/index.deva +41 -11
- package/examples/plugin.deva +15 -0
- package/out-tsc/bin/devalang.exe +0 -0
- package/package.json +6 -6
- package/project-version.json +3 -3
- package/rust/cli/bank.rs +16 -16
- package/rust/cli/build.rs +69 -30
- package/rust/cli/check.rs +46 -6
- package/rust/cli/driver.rs +40 -28
- package/rust/cli/install.rs +22 -7
- package/rust/cli/login.rs +134 -0
- package/rust/cli/mod.rs +2 -1
- package/rust/cli/play.rs +44 -19
- package/rust/cli/update.rs +1 -1
- package/rust/common/api.rs +5 -0
- package/rust/common/cdn.rs +3 -9
- package/rust/common/mod.rs +3 -1
- package/rust/common/sso.rs +5 -0
- package/rust/config/driver.rs +19 -1
- package/rust/config/loader.rs +56 -10
- package/rust/core/audio/engine.rs +314 -63
- package/rust/core/audio/evaluator.rs +101 -0
- package/rust/core/audio/interpreter/arrow_call.rs +60 -15
- package/rust/core/audio/interpreter/automate.rs +18 -0
- package/rust/core/audio/interpreter/call.rs +4 -4
- package/rust/core/audio/interpreter/condition.rs +3 -3
- package/rust/core/audio/interpreter/driver.rs +68 -30
- package/rust/core/audio/interpreter/let_.rs +14 -7
- package/rust/core/audio/interpreter/loop_.rs +39 -6
- package/rust/core/audio/interpreter/mod.rs +2 -1
- package/rust/core/audio/interpreter/sleep.rs +2 -4
- package/rust/core/audio/interpreter/spawn.rs +4 -4
- package/rust/core/audio/loader/trigger.rs +2 -5
- package/rust/core/audio/mod.rs +2 -1
- package/rust/core/audio/renderer.rs +1 -1
- package/rust/core/audio/special/easing.rs +120 -0
- package/rust/core/audio/special/env.rs +41 -0
- package/rust/core/audio/special/math.rs +92 -0
- package/rust/core/audio/special/mod.rs +9 -0
- package/rust/core/audio/special/modulator.rs +120 -0
- package/rust/core/builder/mod.rs +11 -6
- package/rust/core/debugger/store.rs +1 -1
- package/rust/core/error/mod.rs +4 -1
- package/rust/core/lexer/handler/arrow.rs +60 -9
- package/rust/core/lexer/handler/at.rs +4 -4
- package/rust/core/lexer/handler/brace.rs +8 -8
- package/rust/core/lexer/handler/colon.rs +4 -4
- package/rust/core/lexer/handler/comment.rs +2 -2
- package/rust/core/lexer/handler/dot.rs +4 -4
- package/rust/core/lexer/handler/driver.rs +42 -13
- package/rust/core/lexer/handler/identifier.rs +5 -4
- package/rust/core/lexer/handler/indent.rs +16 -2
- package/rust/core/lexer/handler/newline.rs +1 -1
- package/rust/core/lexer/handler/number.rs +3 -3
- package/rust/core/lexer/handler/operator.rs +3 -1
- package/rust/core/lexer/handler/parenthesis.rs +8 -8
- package/rust/core/lexer/handler/slash.rs +5 -5
- package/rust/core/lexer/handler/string.rs +1 -1
- package/rust/core/lexer/mod.rs +1 -1
- package/rust/core/lexer/token.rs +4 -0
- package/rust/core/mod.rs +2 -1
- package/rust/core/parser/driver.rs +134 -11
- package/rust/core/parser/handler/arrow_call.rs +141 -65
- package/rust/core/parser/handler/at.rs +1 -1
- package/rust/core/parser/handler/bank.rs +35 -7
- package/rust/core/parser/handler/dot.rs +43 -22
- package/rust/core/parser/handler/identifier/automate.rs +194 -0
- package/rust/core/parser/handler/identifier/function.rs +2 -3
- package/rust/core/parser/handler/identifier/let_.rs +16 -0
- package/rust/core/parser/handler/identifier/mod.rs +14 -10
- package/rust/core/parser/handler/identifier/print.rs +29 -0
- package/rust/core/parser/handler/identifier/sleep.rs +1 -1
- package/rust/core/parser/handler/identifier/synth.rs +7 -9
- package/rust/core/parser/handler/loop_.rs +60 -43
- package/rust/core/parser/statement.rs +5 -0
- package/rust/core/plugin/loader.rs +48 -0
- package/rust/core/plugin/mod.rs +1 -0
- package/rust/core/preprocessor/loader.rs +7 -5
- package/rust/core/preprocessor/processor.rs +4 -4
- package/rust/core/preprocessor/resolver/bank.rs +1 -2
- package/rust/core/preprocessor/resolver/call.rs +19 -18
- package/rust/core/preprocessor/resolver/driver.rs +7 -5
- package/rust/core/preprocessor/resolver/function.rs +3 -13
- package/rust/core/preprocessor/resolver/loop_.rs +31 -1
- package/rust/core/preprocessor/resolver/spawn.rs +3 -22
- package/rust/core/preprocessor/resolver/tempo.rs +1 -1
- package/rust/core/preprocessor/resolver/trigger.rs +2 -3
- package/rust/core/preprocessor/resolver/value.rs +6 -12
- package/rust/core/shared/bank.rs +1 -1
- package/rust/core/utils/path.rs +1 -1
- package/rust/core/utils/validation.rs +0 -1
- package/rust/installer/addon.rs +80 -0
- package/rust/installer/bank.rs +25 -15
- package/rust/installer/mod.rs +4 -1
- package/rust/installer/plugin.rs +55 -0
- package/rust/main.rs +32 -10
- package/rust/utils/error.rs +51 -0
- package/rust/utils/logger.rs +20 -0
- package/rust/utils/mod.rs +1 -44
- package/rust/utils/spinner.rs +3 -5
package/rust/cli/bank.rs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
use std::fs;
|
|
2
2
|
|
|
3
|
-
use serde::
|
|
3
|
+
use serde::Deserialize;
|
|
4
4
|
use crate::{
|
|
5
5
|
common::cdn::get_cdn_url,
|
|
6
6
|
config::loader::{ load_config, remove_bank_from_config, update_bank_version_in_config },
|
|
@@ -102,7 +102,7 @@ pub async fn handle_update_bank_command(name: Option<String>) -> Result<(), Stri
|
|
|
102
102
|
);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
let
|
|
105
|
+
let config = load_config(Some(&config_path)).ok_or_else(||
|
|
106
106
|
format!("Failed to load config from '{}'", config_path.display())
|
|
107
107
|
)?;
|
|
108
108
|
|
|
@@ -255,8 +255,8 @@ pub async fn handle_remove_bank_command(name: String) -> Result<(), String> {
|
|
|
255
255
|
pub async fn handle_bank_available_command() -> Result<(), String> {
|
|
256
256
|
let bank_list = match list_external_banks().await {
|
|
257
257
|
Ok(list) => list,
|
|
258
|
-
|
|
259
|
-
eprintln!("❌ Error fetching bank list
|
|
258
|
+
Err(_err) => {
|
|
259
|
+
eprintln!("❌ Error fetching bank list");
|
|
260
260
|
return Err("Failed to fetch bank list".into());
|
|
261
261
|
}
|
|
262
262
|
};
|
|
@@ -283,7 +283,7 @@ pub async fn handle_bank_info_command(
|
|
|
283
283
|
|
|
284
284
|
let response = match reqwest::get(&url).await {
|
|
285
285
|
Ok(resp) => resp,
|
|
286
|
-
|
|
286
|
+
Err(_err) => {
|
|
287
287
|
return Err("Failed to fetch bank info".into());
|
|
288
288
|
}
|
|
289
289
|
};
|
|
@@ -294,8 +294,8 @@ pub async fn handle_bank_info_command(
|
|
|
294
294
|
|
|
295
295
|
let bytes = match response.bytes().await {
|
|
296
296
|
Ok(b) => b,
|
|
297
|
-
|
|
298
|
-
eprintln!("❌ Error reading response body
|
|
297
|
+
Err(_err) => {
|
|
298
|
+
eprintln!("❌ Error reading response body");
|
|
299
299
|
return Err("Failed to read response body".into());
|
|
300
300
|
}
|
|
301
301
|
};
|
|
@@ -314,8 +314,8 @@ pub async fn handle_bank_info_command(
|
|
|
314
314
|
pub async fn handle_bank_list_command() -> Result<(), String> {
|
|
315
315
|
let bank_list = match list_installed_banks().await {
|
|
316
316
|
Ok(list) => list,
|
|
317
|
-
|
|
318
|
-
eprintln!("❌ Error fetching bank list
|
|
317
|
+
Err(_err) => {
|
|
318
|
+
eprintln!("❌ Error fetching bank list");
|
|
319
319
|
return Err("Failed to fetch bank list".into());
|
|
320
320
|
}
|
|
321
321
|
};
|
|
@@ -325,11 +325,10 @@ pub async fn handle_bank_list_command() -> Result<(), String> {
|
|
|
325
325
|
for bank_toml in bank_list {
|
|
326
326
|
let latest_version = match fetch_latest_version(bank_toml.bank.name.clone()).await {
|
|
327
327
|
Ok(version) => version,
|
|
328
|
-
|
|
328
|
+
Err(_err) => {
|
|
329
329
|
eprintln!(
|
|
330
|
-
"❌ Error fetching latest version for '{}'
|
|
331
|
-
bank_toml.bank.name
|
|
332
|
-
err
|
|
330
|
+
"❌ Error fetching latest version for '{}'",
|
|
331
|
+
bank_toml.bank.name
|
|
333
332
|
);
|
|
334
333
|
continue;
|
|
335
334
|
}
|
|
@@ -398,6 +397,7 @@ async fn list_installed_banks() -> Result<Vec<BankFile>, String> {
|
|
|
398
397
|
return Ok(banks); // No banks installed
|
|
399
398
|
}
|
|
400
399
|
|
|
400
|
+
// TODO: Verify installed banks in files
|
|
401
401
|
// let installed_banks = std::fs
|
|
402
402
|
// ::read_dir(bank_dir)
|
|
403
403
|
// .map_err(|e| format!("Failed to read bank directory: {}", e))?;
|
|
@@ -416,7 +416,7 @@ async fn list_installed_banks() -> Result<Vec<BankFile>, String> {
|
|
|
416
416
|
);
|
|
417
417
|
}
|
|
418
418
|
|
|
419
|
-
let
|
|
419
|
+
let config = load_config(Some(&config_path)).ok_or_else(||
|
|
420
420
|
format!("Failed to load config from '{}'", config_path.display())
|
|
421
421
|
)?;
|
|
422
422
|
|
|
@@ -440,8 +440,8 @@ async fn list_installed_banks() -> Result<Vec<BankFile>, String> {
|
|
|
440
440
|
|
|
441
441
|
match toml::from_str::<BankFile>(&content) {
|
|
442
442
|
Ok(bank_info) => banks.push(bank_info),
|
|
443
|
-
Err(
|
|
444
|
-
eprintln!("❌ Error parsing bank info for '{}'
|
|
443
|
+
Err(_err) => {
|
|
444
|
+
eprintln!("❌ Error parsing bank info for '{}'", bank_name);
|
|
445
445
|
}
|
|
446
446
|
}
|
|
447
447
|
} else {
|
package/rust/cli/build.rs
CHANGED
|
@@ -21,7 +21,9 @@ pub fn handle_build_command(
|
|
|
21
21
|
config: Option<Config>,
|
|
22
22
|
entry: Option<String>,
|
|
23
23
|
output: Option<String>,
|
|
24
|
-
watch: bool
|
|
24
|
+
watch: bool,
|
|
25
|
+
debug: bool,
|
|
26
|
+
compress: bool
|
|
25
27
|
) {
|
|
26
28
|
let fetched_entry = if entry.is_none() {
|
|
27
29
|
config
|
|
@@ -77,7 +79,7 @@ pub fn handle_build_command(
|
|
|
77
79
|
|
|
78
80
|
// SECTION Begin build
|
|
79
81
|
if fetched_watch {
|
|
80
|
-
begin_build(entry_file.clone(), fetched_output.clone());
|
|
82
|
+
begin_build(entry_file.clone(), fetched_output.clone(), debug, compress);
|
|
81
83
|
|
|
82
84
|
logger.log_message(
|
|
83
85
|
LogLevel::Watcher,
|
|
@@ -87,14 +89,14 @@ pub fn handle_build_command(
|
|
|
87
89
|
watch_directory(entry_file.clone(), move || {
|
|
88
90
|
logger.log_message(LogLevel::Watcher, "Detected changes, re-building...");
|
|
89
91
|
|
|
90
|
-
begin_build(entry_file.clone(), fetched_output.clone());
|
|
92
|
+
begin_build(entry_file.clone(), fetched_output.clone(), debug, compress);
|
|
91
93
|
}).unwrap();
|
|
92
94
|
} else {
|
|
93
|
-
begin_build(entry_file.clone(), fetched_output.clone());
|
|
95
|
+
begin_build(entry_file.clone(), fetched_output.clone(), debug, compress);
|
|
94
96
|
}
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
fn begin_build(entry: String, output: String) {
|
|
99
|
+
fn begin_build(entry: String, output: String, debug: bool, compress: bool) {
|
|
98
100
|
let spinner = with_spinner("Building...", || {
|
|
99
101
|
thread::sleep(Duration::from_millis(800));
|
|
100
102
|
});
|
|
@@ -112,49 +114,86 @@ fn begin_build(entry: String, output: String) {
|
|
|
112
114
|
let (modules_tokens, modules_statements) = module_loader.load_all_modules(&mut global_store);
|
|
113
115
|
|
|
114
116
|
// SECTION Write logs
|
|
115
|
-
|
|
116
|
-
|
|
117
|
+
if debug {
|
|
118
|
+
for (module_path, module) in global_store.modules.clone() {
|
|
119
|
+
write_module_variable_log_file(
|
|
120
|
+
&normalized_output_dir,
|
|
121
|
+
&module_path,
|
|
122
|
+
&module.variable_table
|
|
123
|
+
);
|
|
124
|
+
write_module_function_log_file(
|
|
125
|
+
&normalized_output_dir,
|
|
126
|
+
&module_path,
|
|
127
|
+
&module.function_table
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
write_lexer_log_file(&normalized_output_dir, "lexer_tokens.log", modules_tokens.clone());
|
|
132
|
+
write_preprocessor_log_file(
|
|
117
133
|
&normalized_output_dir,
|
|
118
|
-
|
|
119
|
-
|
|
134
|
+
"resolved_statements.log",
|
|
135
|
+
modules_statements.clone()
|
|
120
136
|
);
|
|
121
|
-
|
|
137
|
+
write_variables_log_file(
|
|
122
138
|
&normalized_output_dir,
|
|
123
|
-
|
|
124
|
-
|
|
139
|
+
"global_variables.log",
|
|
140
|
+
global_store.variables.clone()
|
|
141
|
+
);
|
|
142
|
+
write_function_log_file(
|
|
143
|
+
&normalized_output_dir,
|
|
144
|
+
"global_functions.log",
|
|
145
|
+
global_store.functions.clone()
|
|
125
146
|
);
|
|
126
147
|
}
|
|
127
148
|
|
|
128
|
-
write_lexer_log_file(&normalized_output_dir, "lexer_tokens.log", modules_tokens.clone());
|
|
129
|
-
write_preprocessor_log_file(
|
|
130
|
-
&normalized_output_dir,
|
|
131
|
-
"resolved_statements.log",
|
|
132
|
-
modules_statements.clone()
|
|
133
|
-
);
|
|
134
|
-
write_variables_log_file(
|
|
135
|
-
&normalized_output_dir,
|
|
136
|
-
"global_variables.log",
|
|
137
|
-
global_store.variables.clone()
|
|
138
|
-
);
|
|
139
|
-
write_function_log_file(
|
|
140
|
-
&normalized_output_dir,
|
|
141
|
-
"global_functions.log",
|
|
142
|
-
global_store.functions.clone()
|
|
143
|
-
);
|
|
144
|
-
|
|
145
149
|
// SECTION Building AST and Audio
|
|
146
150
|
let builder = Builder::new();
|
|
147
|
-
builder.build_ast(&modules_statements, &normalized_output_dir);
|
|
151
|
+
builder.build_ast(&modules_statements, &normalized_output_dir, compress);
|
|
148
152
|
builder.build_audio(&modules_statements, &normalized_output_dir, &mut global_store);
|
|
149
153
|
|
|
150
154
|
// SECTION Logging
|
|
151
155
|
let logger = Logger::new();
|
|
152
156
|
|
|
157
|
+
if debug {
|
|
158
|
+
let modules_loaded = global_store.modules
|
|
159
|
+
.iter()
|
|
160
|
+
.map(|(k, _)| k)
|
|
161
|
+
.collect::<Vec<_>>();
|
|
162
|
+
let global_variables_loaded = global_store.variables.variables.keys().collect::<Vec<_>>();
|
|
163
|
+
let global_functions_loaded = global_store.functions.functions.keys().collect::<Vec<_>>();
|
|
164
|
+
|
|
165
|
+
logger.log_message_with_trace(
|
|
166
|
+
LogLevel::Debug,
|
|
167
|
+
&format!("Modules loaded: {}", global_store.modules.len()),
|
|
168
|
+
modules_loaded
|
|
169
|
+
.iter()
|
|
170
|
+
.map(|s| s.as_str())
|
|
171
|
+
.collect()
|
|
172
|
+
);
|
|
173
|
+
logger.log_message_with_trace(
|
|
174
|
+
LogLevel::Debug,
|
|
175
|
+
&format!("Global variables: {}", global_store.variables.variables.len()),
|
|
176
|
+
global_variables_loaded
|
|
177
|
+
.iter()
|
|
178
|
+
.map(|s| s.as_str())
|
|
179
|
+
.collect()
|
|
180
|
+
);
|
|
181
|
+
logger.log_message_with_trace(
|
|
182
|
+
LogLevel::Debug,
|
|
183
|
+
&format!("Global functions: {}", global_store.functions.functions.len()),
|
|
184
|
+
global_functions_loaded
|
|
185
|
+
.iter()
|
|
186
|
+
.map(|s| s.as_str())
|
|
187
|
+
.collect()
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
153
191
|
let success_message = format!(
|
|
154
192
|
"Build completed successfully in {:.2?}. Output files written to: '{}'",
|
|
155
193
|
duration.elapsed(),
|
|
156
194
|
normalized_output_dir
|
|
157
195
|
);
|
|
158
196
|
|
|
197
|
+
spinner.finish_and_clear();
|
|
159
198
|
logger.log_message(LogLevel::Success, &success_message);
|
|
160
199
|
}
|
package/rust/cli/check.rs
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
use crate::{
|
|
2
2
|
config::driver::Config,
|
|
3
3
|
core::{
|
|
4
|
+
debugger::{
|
|
5
|
+
lexer::write_lexer_log_file,
|
|
6
|
+
module::{ write_module_function_log_file, write_module_variable_log_file },
|
|
7
|
+
preprocessor::write_preprocessor_log_file,
|
|
8
|
+
store::{ write_function_log_file, write_variables_log_file },
|
|
9
|
+
},
|
|
4
10
|
preprocessor::loader::ModuleLoader,
|
|
5
11
|
store::global::GlobalStore,
|
|
6
12
|
utils::path::{ find_entry_file, normalize_path },
|
|
7
13
|
},
|
|
8
14
|
utils::{
|
|
9
|
-
collect_errors_recursively,
|
|
15
|
+
error::collect_errors_recursively,
|
|
10
16
|
logger::{ LogLevel, Logger },
|
|
11
17
|
spinner::with_spinner,
|
|
12
18
|
watcher::watch_directory,
|
|
@@ -19,7 +25,8 @@ pub fn handle_check_command(
|
|
|
19
25
|
config: Option<Config>,
|
|
20
26
|
entry: Option<String>,
|
|
21
27
|
output: Option<String>,
|
|
22
|
-
watch: bool
|
|
28
|
+
watch: bool,
|
|
29
|
+
debug: bool
|
|
23
30
|
) {
|
|
24
31
|
let fetched_entry = if entry.is_none() {
|
|
25
32
|
config
|
|
@@ -75,7 +82,7 @@ pub fn handle_check_command(
|
|
|
75
82
|
|
|
76
83
|
// SECTION Begin check
|
|
77
84
|
if fetched_watch {
|
|
78
|
-
begin_check(entry_file.clone(), fetched_output.clone());
|
|
85
|
+
begin_check(entry_file.clone(), fetched_output.clone(), debug);
|
|
79
86
|
|
|
80
87
|
logger.log_message(
|
|
81
88
|
LogLevel::Watcher,
|
|
@@ -85,14 +92,14 @@ pub fn handle_check_command(
|
|
|
85
92
|
watch_directory(entry_file.clone(), move || {
|
|
86
93
|
logger.log_message(LogLevel::Watcher, "Detected changes, re-checking...");
|
|
87
94
|
|
|
88
|
-
begin_check(entry_file.clone(), fetched_output.clone());
|
|
95
|
+
begin_check(entry_file.clone(), fetched_output.clone(), debug);
|
|
89
96
|
}).unwrap();
|
|
90
97
|
} else {
|
|
91
|
-
begin_check(entry_file.clone(), fetched_output.clone());
|
|
98
|
+
begin_check(entry_file.clone(), fetched_output.clone(), debug);
|
|
92
99
|
}
|
|
93
100
|
}
|
|
94
101
|
|
|
95
|
-
fn begin_check(entry: String, output: String) {
|
|
102
|
+
fn begin_check(entry: String, output: String, debug: bool) {
|
|
96
103
|
let spinner = with_spinner("Checking...", || {
|
|
97
104
|
thread::sleep(Duration::from_millis(800));
|
|
98
105
|
});
|
|
@@ -116,6 +123,38 @@ fn begin_check(entry: String, output: String) {
|
|
|
116
123
|
logger.log_message(LogLevel::Info, &format!("- {}", module_name));
|
|
117
124
|
}
|
|
118
125
|
|
|
126
|
+
if debug {
|
|
127
|
+
for (module_path, module) in global_store.modules.clone() {
|
|
128
|
+
write_module_variable_log_file(
|
|
129
|
+
&normalized_output_dir,
|
|
130
|
+
&module_path,
|
|
131
|
+
&module.variable_table
|
|
132
|
+
);
|
|
133
|
+
write_module_function_log_file(
|
|
134
|
+
&normalized_output_dir,
|
|
135
|
+
&module_path,
|
|
136
|
+
&module.function_table
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
write_lexer_log_file(&normalized_output_dir, "lexer_tokens.log", modules.0.clone());
|
|
141
|
+
write_preprocessor_log_file(
|
|
142
|
+
&normalized_output_dir,
|
|
143
|
+
"resolved_statements.log",
|
|
144
|
+
modules.1.clone()
|
|
145
|
+
);
|
|
146
|
+
write_variables_log_file(
|
|
147
|
+
&normalized_output_dir,
|
|
148
|
+
"global_variables.log",
|
|
149
|
+
global_store.variables.clone()
|
|
150
|
+
);
|
|
151
|
+
write_function_log_file(
|
|
152
|
+
&normalized_output_dir,
|
|
153
|
+
"global_functions.log",
|
|
154
|
+
global_store.functions.clone()
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
119
158
|
let mut all_errors = Vec::new();
|
|
120
159
|
for (_, statements) in &modules.1 {
|
|
121
160
|
all_errors.extend(collect_errors_recursively(statements));
|
|
@@ -136,5 +175,6 @@ fn begin_check(entry: String, output: String) {
|
|
|
136
175
|
normalized_output_dir
|
|
137
176
|
);
|
|
138
177
|
|
|
178
|
+
spinner.finish_and_clear();
|
|
139
179
|
logger.log_message(LogLevel::Success, &success_message);
|
|
140
180
|
}
|
package/rust/cli/driver.rs
CHANGED
|
@@ -21,6 +21,14 @@ pub enum InstallCommand {
|
|
|
21
21
|
Bank {
|
|
22
22
|
name: String,
|
|
23
23
|
},
|
|
24
|
+
/// Installs a plugin.
|
|
25
|
+
Plugin {
|
|
26
|
+
name: String,
|
|
27
|
+
},
|
|
28
|
+
/// Installs a preset.
|
|
29
|
+
Preset {
|
|
30
|
+
name: String,
|
|
31
|
+
},
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
#[derive(Subcommand)]
|
|
@@ -103,10 +111,12 @@ pub enum Commands {
|
|
|
103
111
|
/// - `entry` - The entry point of the program to build. Defaults to "./src".
|
|
104
112
|
/// - `output` - The directory where the output files will be generated. Defaults to "./output".
|
|
105
113
|
/// - `watch` - Whether to watch for changes and rebuild. Defaults to "true".
|
|
114
|
+
/// - `debug` - Whether to print debug information. Defaults to "false".
|
|
115
|
+
/// - `compress` - Whether to compress the output files. Defaults to "false".
|
|
106
116
|
///
|
|
107
117
|
/// ### Example
|
|
108
118
|
/// ```bash
|
|
109
|
-
/// devalang build --entry ./src --output ./output --watch true
|
|
119
|
+
/// devalang build --entry ./src --output ./output --watch true --debug false --compress false
|
|
110
120
|
/// ```
|
|
111
121
|
///
|
|
112
122
|
Build {
|
|
@@ -128,19 +138,6 @@ pub enum Commands {
|
|
|
128
138
|
///
|
|
129
139
|
watch: bool,
|
|
130
140
|
|
|
131
|
-
#[arg(long, default_value = "real-time")]
|
|
132
|
-
/// The mode of compilation.
|
|
133
|
-
///
|
|
134
|
-
/// ### Default value
|
|
135
|
-
/// - `real-time`
|
|
136
|
-
///
|
|
137
|
-
/// ### Possible values
|
|
138
|
-
/// - `real-time` - Compiles files as soon as possible.
|
|
139
|
-
/// - `batch` - Compiles files one by one.
|
|
140
|
-
/// - `check` - Analyzes the code without compiling it.
|
|
141
|
-
///
|
|
142
|
-
compilation_mode: String,
|
|
143
|
-
|
|
144
141
|
#[arg(short, long, default_value_t = false)]
|
|
145
142
|
/// Whether to print debug information.
|
|
146
143
|
///
|
|
@@ -164,9 +161,13 @@ pub enum Commands {
|
|
|
164
161
|
/// - `entry` - The entry point of the program to analyze. Defaults to "./src".
|
|
165
162
|
/// - `output` - The directory where the output files will be generated. Defaults to "./output".
|
|
166
163
|
/// - `watch` - Whether to watch for changes and re-analyze. Defaults to "true".
|
|
167
|
-
/// - `compilation_mode` - The mode of compilation. Defaults to "real-time".
|
|
168
164
|
/// - `debug` - Whether to print debug information. Defaults to "false".
|
|
169
165
|
///
|
|
166
|
+
/// ### Example
|
|
167
|
+
/// ```bash
|
|
168
|
+
/// devalang check --entry ./src --output ./output --watch true --debug false
|
|
169
|
+
/// ```
|
|
170
|
+
///
|
|
170
171
|
Check {
|
|
171
172
|
#[arg(short, long)]
|
|
172
173
|
/// The entry point of the program to analyze.
|
|
@@ -184,19 +185,6 @@ pub enum Commands {
|
|
|
184
185
|
///
|
|
185
186
|
watch: bool,
|
|
186
187
|
|
|
187
|
-
#[arg(short, long, default_value = "real-time")]
|
|
188
|
-
/// The mode of compilation.
|
|
189
|
-
///
|
|
190
|
-
/// ### Default value
|
|
191
|
-
/// - `real-time`
|
|
192
|
-
///
|
|
193
|
-
/// ### Possible values
|
|
194
|
-
/// - `real-time` - Analyzes files as soon as possible.
|
|
195
|
-
/// - `batch` - Analyzes files one by one.
|
|
196
|
-
/// - `check` - Analyzes the code without compiling it.
|
|
197
|
-
///
|
|
198
|
-
compilation_mode: String,
|
|
199
|
-
|
|
200
188
|
#[arg(short, long, default_value_t = false)]
|
|
201
189
|
/// Whether to print debug information.
|
|
202
190
|
///
|
|
@@ -213,6 +201,14 @@ pub enum Commands {
|
|
|
213
201
|
/// - `output` - The directory where the output files will be generated. Defaults to "./output".
|
|
214
202
|
/// - `watch` - Whether to watch for changes and re-play. Defaults to "false".
|
|
215
203
|
/// - `repeat` - Whether to replay the program after it finishes. Defaults to "false".
|
|
204
|
+
/// - `debug` - Whether to print debug information. Defaults to "false".
|
|
205
|
+
///
|
|
206
|
+
/// Note: `--repeat` and `--watch` cannot be used together. Instead use `repeat` to watch for changes and replay the program.
|
|
207
|
+
///
|
|
208
|
+
/// ### Example
|
|
209
|
+
/// ```bash
|
|
210
|
+
/// devalang play --entry ./src --output ./output --repeat true --debug false
|
|
211
|
+
/// ```
|
|
216
212
|
///
|
|
217
213
|
Play {
|
|
218
214
|
#[arg(short, long)]
|
|
@@ -238,6 +234,14 @@ pub enum Commands {
|
|
|
238
234
|
/// - `false`
|
|
239
235
|
///
|
|
240
236
|
repeat: bool,
|
|
237
|
+
|
|
238
|
+
#[arg(short, long, default_value_t = false)]
|
|
239
|
+
/// Whether to print debug information.
|
|
240
|
+
///
|
|
241
|
+
/// ### Default value
|
|
242
|
+
/// - `false`
|
|
243
|
+
///
|
|
244
|
+
debug: bool,
|
|
241
245
|
},
|
|
242
246
|
|
|
243
247
|
/// Update the Devalang CLI to the latest version.
|
|
@@ -277,4 +281,12 @@ pub enum Commands {
|
|
|
277
281
|
#[command(subcommand)]
|
|
278
282
|
command: BankCommand,
|
|
279
283
|
},
|
|
284
|
+
|
|
285
|
+
/// Log in to your Devaloop account.
|
|
286
|
+
///
|
|
287
|
+
Login {},
|
|
288
|
+
|
|
289
|
+
/// Log out of your Devaloop account.
|
|
290
|
+
///
|
|
291
|
+
Logout {},
|
|
280
292
|
}
|
package/rust/cli/install.rs
CHANGED
|
@@ -1,16 +1,31 @@
|
|
|
1
|
-
use crate::installer::
|
|
1
|
+
use crate::installer::addon::{ install_addon, AddonType };
|
|
2
2
|
|
|
3
|
+
/// Handles the installation command for a given addon type and name.
|
|
3
4
|
#[cfg(feature = "cli")]
|
|
4
|
-
pub async fn
|
|
5
|
+
pub async fn handle_install_command(name: String, addon_type: AddonType) -> Result<(), String> {
|
|
6
|
+
use crate::utils::{ logger::{ LogLevel, Logger }, spinner::with_spinner };
|
|
7
|
+
use std::{ thread, time::Duration };
|
|
8
|
+
|
|
9
|
+
let logger = Logger::new();
|
|
5
10
|
let deva_dir = std::path::Path::new("./.deva/");
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
let spinner = with_spinner("Installing...", || {
|
|
13
|
+
thread::sleep(Duration::from_millis(800));
|
|
14
|
+
});
|
|
9
15
|
|
|
10
|
-
if let Err(e) =
|
|
11
|
-
|
|
16
|
+
if let Err(e) = install_addon(addon_type.clone(), name.as_str(), deva_dir).await {
|
|
17
|
+
spinner.finish_and_clear();
|
|
18
|
+
logger.log_message_with_trace(
|
|
19
|
+
LogLevel::Error,
|
|
20
|
+
&format!("Error installing {:?} '{}'", addon_type, name),
|
|
21
|
+
vec![&e]
|
|
22
|
+
);
|
|
12
23
|
} else {
|
|
13
|
-
|
|
24
|
+
spinner.finish_and_clear();
|
|
25
|
+
logger.log_message(
|
|
26
|
+
LogLevel::Success,
|
|
27
|
+
&format!("{:?} '{}' installed successfully!", addon_type, name)
|
|
28
|
+
);
|
|
14
29
|
}
|
|
15
30
|
|
|
16
31
|
Ok(())
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
use std::fs;
|
|
2
|
+
use tiny_http::{ Server, Response };
|
|
3
|
+
use webbrowser;
|
|
4
|
+
use serde::{ Serialize, Deserialize };
|
|
5
|
+
use dirs::home_dir;
|
|
6
|
+
use crate::common::sso::get_sso_url;
|
|
7
|
+
use std::{ thread, time::Duration };
|
|
8
|
+
use tiny_http::Header;
|
|
9
|
+
use std::str::FromStr;
|
|
10
|
+
|
|
11
|
+
#[derive(Serialize, Deserialize)]
|
|
12
|
+
struct UserConfig {
|
|
13
|
+
token: String,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/// Handle the login command
|
|
17
|
+
/// This function initiates the login process by opening the browser and waiting for the callback.
|
|
18
|
+
#[cfg(feature = "cli")]
|
|
19
|
+
pub async fn handle_login_command() -> Result<(), String> {
|
|
20
|
+
use crate::utils::spinner::with_spinner;
|
|
21
|
+
use crate::utils::logger::Logger;
|
|
22
|
+
use crate::utils::logger::LogLevel;
|
|
23
|
+
|
|
24
|
+
let logger = Logger::new();
|
|
25
|
+
|
|
26
|
+
let mut listener_port = 7878;
|
|
27
|
+
|
|
28
|
+
let test_port_already_in_use = format!("127.0.0.1:{}", listener_port);
|
|
29
|
+
while std::net::TcpListener::bind(&test_port_already_in_use).is_err() {
|
|
30
|
+
listener_port += 1;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let redirect_uri = format!("http://127.0.0.1:{}/callback", listener_port);
|
|
34
|
+
let login_url = format!(
|
|
35
|
+
"{}/?response_type=code&referer=cli&redirect_uri={}",
|
|
36
|
+
get_sso_url(),
|
|
37
|
+
redirect_uri
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if webbrowser::open(&login_url).is_ok() {
|
|
41
|
+
logger.log_message(LogLevel::Info, "Opening browser for login...");
|
|
42
|
+
logger.log_message(
|
|
43
|
+
LogLevel::Info,
|
|
44
|
+
&format!("If the browser does not open, please visit the following URL: {}", login_url)
|
|
45
|
+
);
|
|
46
|
+
} else {
|
|
47
|
+
logger.log_message(
|
|
48
|
+
LogLevel::Info,
|
|
49
|
+
"Please open the following URL in your browser to login:"
|
|
50
|
+
);
|
|
51
|
+
logger.log_message(LogLevel::Info, &login_url);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let server = Server::http(format!("127.0.0.1:{}", listener_port)).unwrap();
|
|
55
|
+
|
|
56
|
+
let spinner = with_spinner("Waiting for authentication...", || {
|
|
57
|
+
thread::sleep(Duration::from_millis(800));
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
for request in server.incoming_requests() {
|
|
61
|
+
let query = request.url().to_string();
|
|
62
|
+
if request.url().starts_with("/callback") {
|
|
63
|
+
if query.contains("session=") || query.contains("error=") {
|
|
64
|
+
let token = query.split("session=").nth(1).unwrap_or("").to_string();
|
|
65
|
+
|
|
66
|
+
if token.len() > 0 {
|
|
67
|
+
let response_html =
|
|
68
|
+
r#"
|
|
69
|
+
<html>
|
|
70
|
+
<body>
|
|
71
|
+
<h1>Authentication Successful</h1>
|
|
72
|
+
<h2>You can now close this window.</h2>
|
|
73
|
+
</body>
|
|
74
|
+
</html>
|
|
75
|
+
"#;
|
|
76
|
+
|
|
77
|
+
let response = Response::from_string(response_html)
|
|
78
|
+
.with_status_code(200)
|
|
79
|
+
.with_header(Header::from_str("Content-Type: text/html").unwrap());
|
|
80
|
+
|
|
81
|
+
request.respond(response).unwrap();
|
|
82
|
+
|
|
83
|
+
save_token(&token);
|
|
84
|
+
|
|
85
|
+
spinner.finish_and_clear();
|
|
86
|
+
|
|
87
|
+
logger.log_message(
|
|
88
|
+
LogLevel::Success,
|
|
89
|
+
"Authentication successful. Token saved to ~/.devalang/session_token.json"
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
break;
|
|
93
|
+
} else {
|
|
94
|
+
spinner.finish_and_clear();
|
|
95
|
+
logger.log_message(LogLevel::Error, "Invalid session token.");
|
|
96
|
+
request.respond(Response::from_string("Invalid session token.")).unwrap();
|
|
97
|
+
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
println!("Invalid callback: {}", request.url());
|
|
102
|
+
|
|
103
|
+
spinner.finish_and_clear();
|
|
104
|
+
logger.log_message(LogLevel::Error, "Invalid callback.");
|
|
105
|
+
request.respond(Response::from_string("Invalid callback.")).unwrap();
|
|
106
|
+
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
} else if request.url().starts_with("/favicon.ico") {
|
|
110
|
+
// Ignore favicon requests
|
|
111
|
+
} else {
|
|
112
|
+
spinner.finish_and_clear();
|
|
113
|
+
logger.log_message(LogLevel::Error, "Invalid request.");
|
|
114
|
+
request.respond(Response::from_string("Invalid request.")).unwrap();
|
|
115
|
+
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
Ok(())
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/// Save the session token to a file in the user's home directory
|
|
124
|
+
fn save_token(token: &str) {
|
|
125
|
+
let config = UserConfig { token: token.to_string() };
|
|
126
|
+
let json = serde_json::to_string(&config).unwrap();
|
|
127
|
+
|
|
128
|
+
let mut path = home_dir().unwrap();
|
|
129
|
+
path.push(".devalang");
|
|
130
|
+
fs::create_dir_all(&path).unwrap();
|
|
131
|
+
|
|
132
|
+
path.push("session_token.json");
|
|
133
|
+
fs::write(path, json).unwrap();
|
|
134
|
+
}
|
package/rust/cli/mod.rs
CHANGED