improved check: formatting system
This commit is contained in:
parent
c6baef23c2
commit
95b2ab4662
9 changed files with 170 additions and 26 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -147,12 +147,19 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diff"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "epitls-pi"
|
name = "epitls-pi"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
|
"diff",
|
||||||
"glob",
|
"glob",
|
||||||
"notify",
|
"notify",
|
||||||
"notify-debouncer-mini",
|
"notify-debouncer-mini",
|
||||||
|
|
|
@ -10,6 +10,7 @@ path = "src/main.rs"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = "0.4.22"
|
chrono = "0.4.22"
|
||||||
clap = { version = "3.2.22", features = ["clap_derive", "derive"] }
|
clap = { version = "3.2.22", features = ["clap_derive", "derive"] }
|
||||||
|
diff = "0.1.13"
|
||||||
glob = "0.3.0"
|
glob = "0.3.0"
|
||||||
notify = "5.0.0"
|
notify = "5.0.0"
|
||||||
notify-debouncer-mini = "0.2.1"
|
notify-debouncer-mini = "0.2.1"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
int a;
|
int a;
|
||||||
printf("hello, world!! %d\n", a);
|
printf("hello, world!! %d\n", a);
|
||||||
}
|
}
|
||||||
|
|
78
src/check.rs
78
src/check.rs
|
@ -1,3 +1,77 @@
|
||||||
pub fn main(_files: Vec<String>) {
|
use std::fs;
|
||||||
todo!()
|
|
||||||
|
use termion::color;
|
||||||
|
|
||||||
|
use crate::{tasks::FormatTask, utils::log_failure};
|
||||||
|
|
||||||
|
const FORMAT_CONFIG: &str = r#"{BasedOnStyle: llvm}"#;
|
||||||
|
|
||||||
|
mod testables;
|
||||||
|
|
||||||
|
pub enum Diff {
|
||||||
|
ToRemove { index: usize, content: String },
|
||||||
|
ToAdd { index: usize, content: String },
|
||||||
|
Keep { index: usize, content: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main(files: Vec<String>) {
|
||||||
|
for file in files {
|
||||||
|
let content = fs::read_to_string(&file).unwrap();
|
||||||
|
let formatted = FormatTask::new(file, FORMAT_CONFIG.into()).run();
|
||||||
|
let mut line_number = 0usize;
|
||||||
|
let mut invalid = false;
|
||||||
|
let differences = diff::lines(&content, &formatted)
|
||||||
|
.into_iter()
|
||||||
|
.map(|change| {
|
||||||
|
match change {
|
||||||
|
diff::Result::Left(_) | diff::Result::Both(_, _) => {
|
||||||
|
line_number += 1;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
(line_number, change)
|
||||||
|
})
|
||||||
|
.map(|(index, d)| match d {
|
||||||
|
diff::Result::Left(content) => {
|
||||||
|
invalid = true;
|
||||||
|
Diff::ToRemove {
|
||||||
|
index,
|
||||||
|
content: content.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff::Result::Both(content, _) => Diff::Keep {
|
||||||
|
index,
|
||||||
|
content: content.into(),
|
||||||
|
},
|
||||||
|
diff::Result::Right(content) => {
|
||||||
|
invalid = true;
|
||||||
|
Diff::ToAdd {
|
||||||
|
index,
|
||||||
|
content: content.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if invalid {
|
||||||
|
log_failure("invalid formatting:");
|
||||||
|
let red = color::Fg(color::Red);
|
||||||
|
let green = color::Fg(color::Green);
|
||||||
|
let reset = color::Fg(color::Reset);
|
||||||
|
|
||||||
|
for difference in differences {
|
||||||
|
match difference {
|
||||||
|
Diff::ToRemove { index, content } => {
|
||||||
|
println!("{red} {index} - | {content}{reset}")
|
||||||
|
}
|
||||||
|
Diff::ToAdd { index, content } => {
|
||||||
|
println!("{green} {index} + | {content}{reset}")
|
||||||
|
}
|
||||||
|
Diff::Keep { index, content } => {
|
||||||
|
println!(" {index} | {content}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
38
src/check/testables.rs
Normal file
38
src/check/testables.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
fn ends_with_newline(source: String) -> Result<(), String> {
|
||||||
|
if !source.ends_with("\n") {
|
||||||
|
Err("source does not end with newline".into())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Rule {
|
||||||
|
name: String,
|
||||||
|
test: Box<dyn Fn(String) -> Result<(), String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rule {
|
||||||
|
pub fn new<'a>(
|
||||||
|
name: impl ToString,
|
||||||
|
test: impl 'static + Fn(String) -> Result<(), String>,
|
||||||
|
) -> Self {
|
||||||
|
let name = name.to_string();
|
||||||
|
let test = Box::new(test);
|
||||||
|
Self { name, test }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn test(&self, source: String) -> Result<(), String> {
|
||||||
|
(self.test)(source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tests() -> Vec<Rule> {
|
||||||
|
vec![
|
||||||
|
// rules
|
||||||
|
Rule::new("ends_with_newline", ends_with_newline),
|
||||||
|
]
|
||||||
|
}
|
11
src/main.rs
11
src/main.rs
|
@ -120,18 +120,18 @@ fn main() {
|
||||||
append_includes(&mut files);
|
append_includes(&mut files);
|
||||||
let args = compilation_args();
|
let args = compilation_args();
|
||||||
let tests = (!tests.is_empty()).then_some(tests);
|
let tests = (!tests.is_empty()).then_some(tests);
|
||||||
test::main(capture, files, tests)
|
test::main(capture, files, args, tests)
|
||||||
}
|
}
|
||||||
Commands::watch {
|
Commands::watch {
|
||||||
command: WatchSubcommand::run { mut files },
|
command: WatchSubcommand::run { mut files },
|
||||||
} => {
|
} => {
|
||||||
append_includes(&mut files);
|
append_includes(&mut files);
|
||||||
let args = compilation_args();
|
let args = compilation_args();
|
||||||
let files = files.clone();
|
watch::main(files.clone(), move || {
|
||||||
watch::main(files, move || {
|
|
||||||
run::main(files.clone(), args.clone());
|
run::main(files.clone(), args.clone());
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Commands::watch {
|
Commands::watch {
|
||||||
command: WatchSubcommand::test {
|
command: WatchSubcommand::test {
|
||||||
mut files,
|
mut files,
|
||||||
|
@ -141,8 +141,9 @@ fn main() {
|
||||||
} => {
|
} => {
|
||||||
append_includes(&mut files);
|
append_includes(&mut files);
|
||||||
let args = compilation_args();
|
let args = compilation_args();
|
||||||
watch::main(files, move || {
|
let tests = (!tests.is_empty()).then_some(tests);
|
||||||
run::main(files.clone(), args.clone());
|
watch::main(files.clone(), move || {
|
||||||
|
test::main(capture, files.clone(), args.clone(), tests.clone());
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
32
src/tasks.rs
32
src/tasks.rs
|
@ -1,7 +1,7 @@
|
||||||
use std::{
|
use std::{
|
||||||
fs,
|
fs,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
process::{Command, ExitStatus},
|
process::{Command, ExitStatus, Stdio},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
|
@ -15,8 +15,6 @@ pub struct CompileTask {
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: split compile & compile raw
|
|
||||||
|
|
||||||
impl CompileTask {
|
impl CompileTask {
|
||||||
pub fn new(files: Vec<PathBuf>) -> Self {
|
pub fn new(files: Vec<PathBuf>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -51,7 +49,6 @@ impl CompileTask {
|
||||||
|
|
||||||
pub fn gen_source(&self) -> PathBuf {
|
pub fn gen_source(&self) -> PathBuf {
|
||||||
let mut output_path = tmp_file_path();
|
let mut output_path = tmp_file_path();
|
||||||
// TODO: make use of supplement
|
|
||||||
output_path.set_extension("c");
|
output_path.set_extension("c");
|
||||||
fs::write(&output_path, "").unwrap();
|
fs::write(&output_path, "").unwrap();
|
||||||
output_path
|
output_path
|
||||||
|
@ -124,8 +121,33 @@ impl GenTask {
|
||||||
|
|
||||||
pub fn run(self) -> PathBuf {
|
pub fn run(self) -> PathBuf {
|
||||||
let output_path = tmp_file_path().apply(|o| o.set_extension("c"));
|
let output_path = tmp_file_path().apply(|o| o.set_extension("c"));
|
||||||
let content = self.content.clone();
|
let content = self.content;
|
||||||
fs::write(&output_path, &content).unwrap();
|
fs::write(&output_path, &content).unwrap();
|
||||||
output_path
|
output_path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct FormatTask {
|
||||||
|
file: String,
|
||||||
|
config: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FormatTask {
|
||||||
|
pub fn new(file: String, config: String) -> Self {
|
||||||
|
Self { config, file }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(self) -> String {
|
||||||
|
let config = self.config;
|
||||||
|
let mut command = Command::new("clang-format");
|
||||||
|
command
|
||||||
|
.arg(self.file)
|
||||||
|
.arg(format!("-style={config}"))
|
||||||
|
.stdout(Stdio::null())
|
||||||
|
.stderr(Stdio::null());
|
||||||
|
command.status().unwrap();
|
||||||
|
|
||||||
|
let result = command.output().unwrap().stdout;
|
||||||
|
String::from_utf8(result).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
18
src/test.rs
18
src/test.rs
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
utils::{log_failure, log_process},
|
utils::{log_failure, log_process},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main(_capture: bool, files: Vec<String>, _test: Option<Vec<String>>) {
|
pub fn main(_capture: bool, files: Vec<String>, args: Vec<String>, _test: Option<Vec<String>>) {
|
||||||
// let includes = files
|
// let includes = files
|
||||||
// .iter()
|
// .iter()
|
||||||
// .cloned()
|
// .cloned()
|
||||||
|
@ -23,10 +23,14 @@ pub fn main(_capture: bool, files: Vec<String>, _test: Option<Vec<String>>) {
|
||||||
thread::sleep(Duration::from_millis(100));
|
thread::sleep(Duration::from_millis(100));
|
||||||
|
|
||||||
// compile with all files
|
// compile with all files
|
||||||
//let files = includes.clone().apply(|v| v.insert(0, generated_code));
|
let mut task = CompileTask::new(vec![generated_code]);
|
||||||
let generated_bin = CompileTask::new(vec![generated_code]).run().unwrap();
|
for flag in args.clone() {
|
||||||
|
task = task.with_flag(flag);
|
||||||
|
}
|
||||||
|
let generated_bin = task.run().unwrap();
|
||||||
|
|
||||||
// run
|
// run
|
||||||
if let Err(_) = RunTask::new(generated_bin).run() {
|
if RunTask::new(generated_bin).run().is_err() {
|
||||||
log_failure("test failed");
|
log_failure("test failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,16 +48,16 @@ pub fn find_tests(source: String) -> Vec<String> {
|
||||||
pub fn gen_test_main(path: &str, test: &str) -> String {
|
pub fn gen_test_main(path: &str, test: &str) -> String {
|
||||||
format!(
|
format!(
|
||||||
"
|
"
|
||||||
void ____test();
|
void __pi_test();
|
||||||
|
|
||||||
int main(int _argc, char** _argv) {{
|
int main(int _argc, char** _argv) {{
|
||||||
____test();
|
__pi_test();
|
||||||
return 0;
|
return 0;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#include \"{path}\"
|
#include \"{path}\"
|
||||||
|
|
||||||
void ____test() {{
|
void __pi_test() {{
|
||||||
{test}();
|
{test}();
|
||||||
}}
|
}}
|
||||||
"
|
"
|
||||||
|
|
|
@ -2,10 +2,7 @@ use std::{path::Path, sync::mpsc, time::Duration};
|
||||||
|
|
||||||
use notify_debouncer_mini::new_debouncer;
|
use notify_debouncer_mini::new_debouncer;
|
||||||
|
|
||||||
use crate::{
|
use crate::utils::log_process;
|
||||||
tasks::{CompileTask, RunTask},
|
|
||||||
utils::{log_failure, log_process, log_success},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Repeater {
|
pub struct Repeater {
|
||||||
op: Box<dyn Fn()>,
|
op: Box<dyn Fn()>,
|
||||||
|
@ -40,7 +37,7 @@ pub fn main(files: Vec<String>, op: impl Fn() + 'static) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for events in rec {
|
for events in rec {
|
||||||
for _ in events.unwrap() {
|
for _event in events.unwrap() {
|
||||||
repeater.repeat();
|
repeater.repeat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue