1use std::{
10 fs::{OpenOptions},
11 io::{Write},
12};
13use crate::read_ebml::Process;
14use crate::read_ebml::SubStep;
17
18
19pub struct Language {
33
34 name: String,
36
37 first: String,
39
40 c_open: String,
42
43 c_close:String,
45
46 last: String,
48
49 ext: String,
51
52 wait: String,
54
55 p_open: String,
57
58 p_close:String,
60}
61
62pub fn learn(lang:&str) -> Language {
128
129 match lang.split_whitespace().collect::<Vec<_>>().join("").to_uppercase().as_str() {
131 "ACTIONSCRIPT" | "AS3" => Language{
132 name: String::from("ActionScript"),
133 first: String::from("#!/usr/bin/as3shebang //\nimport shell.Program;\nimport flash.system.System;"),
134 c_open: String::from("// "),
135 c_close:String::from(""),
136 last: String::from("function onKeyPress(event:KeyboardEvent):void\n{\n if (event.keyCode == Keyboard.ENTER)\n { stage.removeEventListener(KeyboardEvent.KEY_UP, onKeyPress);\n trace(\"Enter key pressed! Proceeding...\");\n play();\n }\n}\n\nreturn;"),
137 ext: String::from(".asc"),
138 wait: String::from("stop();\nstage.addEventListener(KeyboardEvent.KEY_UP, onKeyPress);"),
139 p_open: String::from("System.output(\""),
140 p_close:String::from("\n\");"),
141 },
142 "APPLESCRIPT" | "APPLE" => Language{
143 name: String::from("AppleScript"),
144 first: String::from("#!/usr/bin/osascript"),
145 c_open: String::from("-- "),
146 c_close:String::from(""),
147 last: String::from(""),
148 ext: String::from(".command"),
149 wait: String::from("read -p \"Press Enter to continue...\""),
150 p_open: String::from("echo '"),
151 p_close:String::from("'"),
152 },
153 "BASH" | "BOURNEAGAINSHELL" | "BORNAGAINSHELL" => Language{
154 name: String::from("bash"),
155 first: String::from("#!/bin/bash"),
156 c_open: String::from("# "),
157 c_close:String::from(""),
158 last: String::from("exit 0"),
159 ext: String::from(".sh"),
160 wait: String::from("read -p \"Press Enter to continue...\""),
161 p_open: String::from("echo '"),
162 p_close:String::from("'"),
163 },
164 "COFFEESCRIPT" | "COFFEE" => Language{
165 name: String::from("CoffeeScript"),
166 first: String::from("#!/usr/bin/env coffee\n\nreadline = require 'readline'\n\nwaitForEnter = ->\n new Promise (resolve) ->\n rl = readline.createInterface\n input: process.stdin\n output: process.stdout\n rl.question 'Press Enter to continue...', ->\n rl.close()\n resolve()\n\n"),
167 c_open: String::from("# "),
168 c_close:String::from(""),
169 last: String::from("process.exit(1)"),
170 ext: String::from(".coffee"),
171 wait: String::from("await waitForEnter()"),
172 p_open: String::from("console.log \""),
173 p_close:String::from("\""),
174 },
175 "DART" => Language{
176 name: String::from("Dart"),
177 first: String::from("#!/usr/bin/env dart\nimport 'dart:io';\nvoid main() {"),
178 c_open: String::from("// "),
179 c_close:String::from(""),
180 last: String::from("exit(0);\n}"),
181 ext: String::from(".dart"),
182 wait: String::from("print('Press Enter to continue...');\nstdin.readLineSync();"),
183 p_open: String::from("print('"),
184 p_close:String::from("');"),
185 },
186 "ELIXIR" | "EXS" => Language{
187 name: String::from("Elixir"),
188 first: String::from("#!/usr/bin/env elixir"),
189 c_open: String::from("# "),
190 c_close:String::from(""),
191 last: String::from("Process.exit(self, :normal)"),
192 ext: String::from(".exs"),
193 wait: String::from("IO.gets(\"Press Enter to continue...\")"),
194 p_open: String::from("IO.puts(\""),
195 p_close:String::from("\")"),
196 },
197 "JAVASCRIPT" | "JS" | "NODE.JS" => Language{
198 name: String::from("JavaScript"),
199 first: String::from("#!/usr/bin/env node"),
200 c_open: String::from("// "),
201 c_close:String::from(""),
202 last: String::from("process.exit(0)"),
203 ext: String::from(".js"),
204 wait: String::from(""),
205 p_open: String::from("console.log(\""),
206 p_close:String::from("\");"),
207 },
208 "JULIA" | "JL" => Language{
209 name: String::from("Julia"),
210 first: String::from("#!/usr/bin/env -S julia --color=yes --startup-file=no"),
211 c_open: String::from("# "),
212 c_close:String::from(""),
213 last: String::from("exit(0)"),
214 ext: String::from(".jl"),
215 wait: String::from("Base.prompt(\"Press Enter to continue...\")"),
216 p_open: String::from("println(\""),
217 p_close:String::from("\")"),
218 },
219 "LUA" => Language{
220 name: String::from("Lua"),
221 first: String::from("#!/usr/bin/env lua"),
222 c_open: String::from("-- "),
223 c_close:String::from(""),
224 last: String::from("return"),
225 ext: String::from(".lua"),
226 wait: String::from("print(\"Press Enter to continue...\")\nio.read()"),
227 p_open: String::from("println(\""),
228 p_close:String::from("\")"),
229 },
230 "MATLAB" | "MATHWORKS" | "MAT" | "M" => Language{
231 name: String::from("MATLAB"),
232 first: String::from("% no shebang statement for MATLAB"),
233 c_open: String::from("% "),
234 c_close:String::from(""),
235 last: String::from("exit(0)"),
236 ext: String::from(".m"),
237 wait: String::from("disp('Press Enter to continue...'); input('');"),
238 p_open: String::from("disp('"),
239 p_close:String::from("');"),
240 },
241 "PERL" | "PL" => Language{
242 name: String::from("Perl"),
243 first: String::from("#!/usr/bin/env perl"),
244 c_open: String::from("# "),
245 c_close:String::from(""),
246 last: String::from("exit 1;"),
247 ext: String::from(".pl"),
248 wait: String::from("print \"Press Enter to continue...\";\n<STDIN>;"),
249 p_open: String::from("print \""),
250 p_close:String::from("\";"),
251 },
252 "PHP" | "HYPERTEXTPREPROCESSOR" => Language{
253 name: String::from("PHP"),
254 first: String::from("#!/usr/bin/env php"),
255 c_open: String::from("// "),
256 c_close:String::from(""),
257 last: String::from("exit(0);"),
258 ext: String::from(".php"),
259 wait: String::from("readline(\"Press Enter to proceed...\");"),
260 p_open: String::from("echo \""),
261 p_close:String::from("\";"),
262 },
263 "POWERSHELL" | "PS" | "PS1" => Language{
264 name: String::from("PowerShell"),
265 first: String::from("#!/usr/bin/env pwsh"),
266 c_open: String::from("# "),
267 c_close:String::from(""),
268 last: String::from("exit 0"),
269 ext: String::from(".ps1"),
270 wait: String::from("Read-Host -Prompt \"Press Enter to continue...\""),
271 p_open: String::from("Write-Host \""),
272 p_close:String::from("\""),
273 },
274 "PYTHON" | "PYTHON3" | "PY" => Language{
275 name: String::from("Python 3"),
276 first: String::from("#!/usr/bin/python3"),
277 c_open: String::from("-- "),
278 c_close:String::from(""),
279 last: String::from(""),
280 ext: String::from(".py"),
281 wait: String::from("input(\"Press Enter to continue...\")"),
282 p_open: String::from("print(\""),
283 p_close:String::from("\")"),
284 },
285 "R" => Language{
286 name: String::from("R"),
287 first: String::from("#!/usr/bin/env Rscript"),
288 c_open: String::from("# "),
289 c_close:String::from(""),
290 last: String::from("quit()"),
291 ext: String::from(".R"),
292 wait: String::from("readline(prompt = \"Press Enter to continue...\")"),
293 p_open: String::from("print(\""),
294 p_close:String::from("\")"),
295 },
296 "RUBY" | "RB" => Language{
297 name: String::from("Ruby"),
298 first: String::from("#!/usr/bin/env ruby"),
299 c_open: String::from("// "),
300 c_close:String::from(""),
301 last: String::from("exit(0)"),
302 ext: String::from(".rb"),
303 wait: String::from("puts \"Press Enter to continue...\"\ngets"),
304 p_open: String::from("puts \""),
305 p_close:String::from("\""),
306 },
307 "TYPESCRIPT" | "TS" => Language{
308 name: String::from("TypeScript"),
309 first: String::from("#!/usr/bin/env tsx"),
310 c_open: String::from("# "),
311 c_close:String::from(""),
312 last: String::from("process.exit(0)"),
313 ext: String::from(".ts"),
314 wait: String::from(""),
315 p_open: String::from("console.log(\""),
316 p_close:String::from("\")"),
317 },
318 "VB.NET" | "VBNET" | "VB" | "VISUALBASIC" => Language{
319 name: String::from("VB.NET"),
320 first: String::from("#!/usr/bin/env dotnet run"),
321 c_open: String::from("' "),
322 c_close:String::from(""),
323 last: String::from("Return"),
324 ext: String::from(".vb"),
325 wait: String::from("Console.WriteLine(\"Press Enter to continue...\")\nConsole.ReadLine()"),
326 p_open: String::from("Console.WriteLine(\""),
327 p_close:String::from("\""),
328 },
329 _ => Language{
330 name: String::from("Unknown"),
331 first: String::from("#!/bin/sh"),
332 c_open: String::from("# "),
333 c_close:String::from(""),
334 last: String::from("exit 0"),
335 ext: String::from(".sh"),
336 wait: String::from("read -p \"Press Enter to continue...\""),
337 p_open: String::from("echo '"),
338 p_close:String::from("'"),
339 },
340 }
341}
342
343pub fn script_file_from_process(p:Process,lang:Language,wait:bool) {
352
353 let mut script_lines:Vec<String> = vec![];
355
356 script_lines.push(lang.first.to_owned());
358
359 script_lines.push(comment_to_file(&("=============================================================".to_string()),&lang));
361 script_lines.push(comment_to_file(&(p.get_number().to_owned() + " Rev " + &p.get_revision() + " " + &p.get_title()),&lang));
362 script_lines.push(comment_to_file(&("Author: ".to_owned() + &p.get_author()),&lang));
363 script_lines.push(comment_to_file(&("Reviewer: ".to_owned() + &p.get_reviewer()),&lang));
364 script_lines.push(comment_to_file(&("".to_string()),&lang));
365 script_lines.push(comment_to_file(&(lang.name.to_owned()+ " generated by stanhope " + env!("CARGO_PKG_VERSION")),&lang));
366 script_lines.push(comment_to_file(&("=============================================================".to_string()),&lang));
367
368 script_lines.push("".to_string());
369
370 script_lines.push(print_to_stdout(&(p.get_number().to_owned() + " Rev " + &p.get_revision() + " " + &p.get_title()),&lang));
371 script_lines.push(print_to_stdout(&("".to_string()),&lang));
372 script_lines.push(print_to_stdout(&("Author: ".to_owned() + &p.get_author()),&lang));
373 script_lines.push(print_to_stdout(&("Reviewer: ".to_owned() + &p.get_reviewer()),&lang));
374 script_lines.push(print_to_stdout(&("".to_string()),&lang));
375
376 script_lines.push("".to_string());
377
378 if wait { script_lines.push(lang.wait.to_owned()) };
380
381 script_lines.push("".to_string());
382
383 let mut secnum:u16 = 0;
385 for section in p.get_all_sections() {
386 secnum += 1;
387 let mut stpnum:u16 = 0;
388
389 script_lines.push(comment_to_file(&("=============================================================".to_string()),&lang));
391 script_lines.push(comment_to_file(&("Section ".to_string() + &secnum.to_string() + ": " + §ion.get_title()),&lang));
392 script_lines.push(comment_to_file(&("=============================================================".to_string()),&lang));
393 script_lines.push("".to_string());
394
395 for step in section.get_all_steps() {
397 stpnum += 1;
398 script_lines.push(print_to_stdout(&("Step ".to_string() + &secnum.to_string() + "." + &stpnum.to_string()),&lang));
400 script_lines.push(print_to_stdout(&(step.get_text().trim().to_string()),&lang));
401 script_lines.push(print_to_stdout(&("".to_string()),&lang));
402
403 for substep in step.get_all_sub_steps() {
405 match substep {
406
407 SubStep::Context(txt) => { script_lines.push(comment_to_file(&(txt.trim().to_string()),&lang)); },
410
411 SubStep::Command(txt) => {
412 script_lines.push(txt.trim().to_string());
414 if wait { script_lines.push(lang.wait.to_owned()) };
418 },
419
420 SubStep::Objective(txt) => {
425 script_lines.push(print_to_stdout(&("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *".to_string()),&lang));
426 script_lines.push(print_to_stdout(&("* Objective Achieved!".to_string()),&lang));
427 script_lines.push(print_to_stdout(&("* ".to_owned()+&txt.trim()),&lang));
428 script_lines.push(print_to_stdout(&("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *".to_string()),&lang));
429 script_lines.push(print_to_stdout(&("".to_string()),&lang));
430 },
431
432 _ => {},
435 }
436 }
437 script_lines.push(print_to_stdout(&("".to_string()),&lang));
439 script_lines.push("".to_string());
440 }
441 script_lines.push("".to_string());
443 }
444
445 script_lines.push(lang.last.to_owned());
447
448 let path_to_file = "./".to_string() + p.get_number() + " - " + p.get_title() + "/" + p.get_number() + " - " + p.get_title() + &lang.ext;
452
453 let mut file = OpenOptions::new()
455 .read(true)
456 .write(true)
457 .create(true)
458 .truncate(true)
459 .open(&path_to_file)
460 .expect("Could not open the file!");
461
462 for line in script_lines {
463 file.write((line + "\n").as_bytes()).expect("Could not write template line into new file!");
464 }
465
466 println!("You will need to make the script file executable if it isn't already. For example, you might need to run:\n\x1b[36mchmod +x \"{}\"\x1b[0m",&path_to_file);
467
468}
469
470fn comment_to_file(txt:&String,lang:&Language) -> String { lang.c_open.to_owned() + txt + &lang.c_close }
472
473fn print_to_stdout(txt:&String,lang:&Language) -> String {
475 let txt_san = txt.replace('"',"").replace("'","");
476 lang.p_open.to_owned() + &txt_san + &lang.p_close
477}
478
479
480#[cfg(test)]
493mod tests {
494
495 use super::*;
496
497 #[test]
498 fn test_new_language_struct() {
499 let mut test_language:Language = Language{
500 name: String::from("NAME"),
501 first: String::from("FIRST LINE(S)"),
502 c_open: String::from("SINGLE-LINE COMMENT OPENER"),
503 c_close:String::from("SINGLE-LINE COMMENT CLOSER"),
504 last: String::from("LAST LINE(S)"),
505 ext: String::from("FILE EXTENSION"),
506 wait: String::from("WAIT FOR THE USER TO PRESS ENTER"),
507 p_open: String::from("PRINT TO STDOUT OPENER"),
508 p_close:String::from("PRINT TO STDOUT CLOSER"),
509 };
510 println!("We successfully created a new Language struct.");
511
512 test_language.name = String::from("A NEW AND IMPROVED NAME");
513 println!("Although it's not really best practices, we've proved we can poke Language fields (within this module anyway).")
514 }
515
516 #[test]
517 fn test_learn_language_names() {
518
519 println!("\n=== ActionScript ===");
520 name_tester("a c t ion SC RIP t","ActionScript");
521 name_tester("as3","ActionScript");
522 name_tester(" action script ","ActionScript");
523 name_tester(" A S 3 ","ActionScript");
524
525 println!("\n=== AppleScript ===");
526 name_tester("applescript","AppleScript");
527 name_tester("apple","AppleScript");
528 name_tester(" a p p l e s CRIPT","AppleScript");
529 name_tester("APP LESC RIPT ","AppleScript");
530
531 println!("\n=== bash ===");
532 name_tester("bash","bash");
533 name_tester(" b a s h ","bash");
534 name_tester(" bourne again shell ","bash");
535 name_tester(" born again shell ","bash");
536
537 println!("\n=== CoffeeScript ===");
538 name_tester("coffee","CoffeeScript");
539 name_tester(" c o f fee ","CoffeeScript");
540 name_tester("coffee script ","CoffeeScript");
541 name_tester(" C off EE S crip T","CoffeeScript");
542
543 println!("\n=== Dart ===");
544 name_tester("dart","Dart");
545 name_tester(" d ar T ","Dart");
546 name_tester("DA rt","Dart");
547 name_tester(" dar T ","Dart");
548
549 println!("\n=== Elixir ===");
550 name_tester("elixir","Elixir");
551 name_tester(" e LIX ir ","Elixir");
552 name_tester(" e x s ","Elixir");
553 name_tester(" E XS ","Elixir");
554
555 println!("\n=== JavaScript ===");
556 name_tester("JAVA S crip T","JavaScript");
557 name_tester(" j s ","JavaScript");
558 name_tester("node.js","JavaScript");
559 name_tester(" no de . j s","JavaScript");
560
561 println!("\n=== Julia ===");
562 name_tester(" julia ","Julia");
563 name_tester(" j u l i a ","Julia");
564 name_tester(" jl ","Julia");
565 name_tester(" j L ","Julia");
566
567 println!("\n=== Lua ===");
568 name_tester(" lua ","Lua");
569 name_tester(" l u a ","Lua");
570 name_tester(" L ua ","Lua");
571 name_tester(" LU a","Lua");
572
573 println!("\n=== MATLAB ===");
574 name_tester(" m a t l a b ","MATLAB");
575 name_tester(" m a t h w o r k s ","MATLAB");
576 name_tester(" m a t ","MATLAB");
577 name_tester(" m ","MATLAB");
578
579 println!("\n=== Perl ===");
580 name_tester(" perl ","Perl");
581 name_tester(" p e r l ","Perl");
582 name_tester(" pl ","Perl");
583 name_tester(" p l ","Perl");
584
585 println!("\n=== PHP ===");
586 name_tester(" php ","PHP");
587 name_tester(" p h p ","PHP");
588 name_tester(" hypertext preprocessor ","PHP");
589 name_tester(" h y p e r t e x t p r e p r o c e s s o r ","PHP");
590
591 println!("\n=== Python 3 ===");
592 name_tester(" python ","Python 3");
593 name_tester(" p y t h o n 3 ","Python 3");
594 name_tester(" P Y ","Python 3");
595 name_tester(" p y ","Python 3");
596
597 println!("\n=== R ===");
598 name_tester(" r ","R");
599 name_tester(" R ","R");
600
601 println!("\n=== Ruby ===");
602 name_tester(" ruby ","Ruby");
603 name_tester(" r u b y ","Ruby");
604 name_tester(" rb ","Ruby");
605 name_tester(" r b ","Ruby");
606
607 println!("\n=== TypeScript ===");
608 name_tester(" typescript ","TypeScript");
609 name_tester(" t y p e s c r i p t ","TypeScript");
610 name_tester(" ts ","TypeScript");
611 name_tester(" t s ","TypeScript");
612
613 println!("\n=== VB.NET ===");
614 name_tester(" vb . net ","VB.NET");
615 name_tester(" v b n e t ","VB.NET");
616 name_tester(" v b ","VB.NET");
617 name_tester(" v i s u a l b a s i c ","VB.NET");
618
619 fn name_tester(in_str:&str,out_str:&str) {
620 print!("Checking if user wants to script in \"{}\" that they get \"{}\" ... ",in_str,out_str);
621 assert_eq!(learn(in_str).name,String::from(out_str));
622 print!("Success!\n")
623 }
624 }
625
626 #[test]
627 fn test_learn_language_comments() {
628
629 comment_tester(vec!("AppleScript","Lua","Python 3"),"-- ","");
630 comment_tester(vec!("ActionScript","Dart","JavaScript","PHP","Ruby"),"// ","");
631 comment_tester(vec!("bash","CoffeeScript","Elixir","Julia","Perl","PowerShell","R","TypeScript"),"# ","");
632 comment_tester(vec!("MATLAB"),"% ","");
633 comment_tester(vec!("VB.NET"),"' ","");
634
635 fn comment_tester(langs:Vec<&str>,c_start:&str,c_end:&str) {
636
637 println!("############################################");
638 println!("# Languages with \"{}\" type comments",c_start);
639 println!("############################################");
640
641 for lang in langs {
642 print!("Checking if {} comments start with \"{}\" and end with \"{}\" ... ",lang,c_start,c_end);
643 let eval_lang = learn(lang);
644 assert_eq!(&eval_lang.c_open,c_start);
645 assert_eq!(&eval_lang.c_close,c_end);
646 print!("Success!\n");
647 }
648
649 println!("");
650 }
651 }
652
653 }