init
This commit is contained in:
commit
87266e7d54
8 changed files with 296 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "boxon"
|
||||
version = "0.1.0"
|
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "boxon"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# boxon
|
||||
|
||||
Utility to convert ascii boxes into ansi boxes inside text files.
|
2
rustfmt.toml
Normal file
2
rustfmt.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
hard_tabs = true
|
||||
max_width = 120
|
235
src/main.rs
Normal file
235
src/main.rs
Normal file
|
@ -0,0 +1,235 @@
|
|||
use std::{env::args, fs};
|
||||
|
||||
fn main() {
|
||||
let file = args().nth(1).expect("Usage : boxon <file>");
|
||||
let content = fs::read_to_string(&file).unwrap_or_else(|_| panic!("Could not read file '{file}'."));
|
||||
let mut grid = Grid::from(content);
|
||||
grid.fix();
|
||||
let content: String = grid.into();
|
||||
fs::write(&file, content).unwrap_or_else(|_| panic!("Could not write result to file '{file}'."));
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Grid(Vec<Vec<char>>);
|
||||
|
||||
impl<T: AsRef<str>> From<T> for Grid {
|
||||
fn from(value: T) -> Self {
|
||||
Self(value.as_ref().lines().map(str::chars).map(Iterator::collect).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Grid> for String {
|
||||
fn from(val: Grid) -> Self {
|
||||
val.0
|
||||
.iter()
|
||||
.map(|l| l.iter().collect::<String>())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
impl Grid {
|
||||
fn fix(&mut self) -> usize {
|
||||
let mut result = 0;
|
||||
let copy = self.clone();
|
||||
for (y, line) in self.0.iter_mut().enumerate() {
|
||||
for (x, character) in line.iter_mut().enumerate() {
|
||||
if let Some(cross) = copy.cross_at(x as i32, y as i32) {
|
||||
let new_char = match cross {
|
||||
Cross(
|
||||
((), MM, ()), //
|
||||
(MM, MM, MM), //
|
||||
((), MM, ()), //
|
||||
) => '┼',
|
||||
Cross(
|
||||
((), MM, ()), //
|
||||
(F_, MM, MM), //
|
||||
((), MM, ()), //
|
||||
) => '├',
|
||||
Cross(
|
||||
((), MM, ()), //
|
||||
(MM, MM, F_), //
|
||||
((), MM, ()), //
|
||||
) => '┤',
|
||||
Cross(
|
||||
((), MM, ()), //
|
||||
(MM, MM, MM), //
|
||||
((), F_, ()), //
|
||||
) => '┴',
|
||||
Cross(
|
||||
((), F_, ()), //
|
||||
(MM, MM, MM), //
|
||||
((), MM, ()), //
|
||||
) => '┬',
|
||||
Cross(
|
||||
((), F_, ()), //
|
||||
(MM, MM, MM), //
|
||||
((), F_, ()), //
|
||||
) => '─',
|
||||
Cross(
|
||||
((), MM, ()), //
|
||||
(F_, MM, F_), //
|
||||
((), MM, ()), //
|
||||
) => '│',
|
||||
Cross(
|
||||
((), MM, ()), //
|
||||
(MM, MM, F_), //
|
||||
((), F_, ()), //
|
||||
) => '┘',
|
||||
Cross(
|
||||
((), F_, ()), //
|
||||
(MM, MM, F_), //
|
||||
((), MM, ()), //
|
||||
) => '┐',
|
||||
Cross(
|
||||
((), F_, ()), //
|
||||
(F_, MM, MM), //
|
||||
((), MM, ()), //
|
||||
) => '┌',
|
||||
Cross(
|
||||
((), MM, ()), //
|
||||
(F_, MM, MM), //
|
||||
((), F_, ()), //
|
||||
) => '└',
|
||||
_ => continue,
|
||||
};
|
||||
*character = new_char;
|
||||
result += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn cross_at(&self, x: i32, y: i32) -> Option<Cross> {
|
||||
fn at(g: &Grid, x: i32, y: i32) -> Option<Cross> {
|
||||
if x < 0 || y < 0 {
|
||||
None
|
||||
} else {
|
||||
Some(connects(*g.0.get(y as usize)?.get(x as usize)?))
|
||||
}
|
||||
}
|
||||
let get = |x: i32, y: i32| -> Cross {
|
||||
at(self, x, y).unwrap_or(connects(' '))
|
||||
};
|
||||
let c = get(x, y);
|
||||
let its_y = y;
|
||||
Some(Cross(
|
||||
( (), get(x, y - 1).d() && c.u(), ()),
|
||||
(get(x - 1, y).r() && c.l(), get(x, its_y).c(), get(x + 1, y).l() && c.r()),
|
||||
( (), get(x, y + 1).u() && c.d(), ()),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn connects(c: char) -> Cross {
|
||||
match c {
|
||||
'-' => Cross(
|
||||
((), F_, ()), //
|
||||
(MM, MM, MM), //
|
||||
((), F_, ()), //
|
||||
),
|
||||
'|' => Cross(
|
||||
((), MM, ()), //
|
||||
(F_, MM, F_), //
|
||||
((), MM, ()), //
|
||||
),
|
||||
'+' => Cross(
|
||||
((), MM, ()), //
|
||||
(MM, MM, MM), //
|
||||
((), MM, ()), //
|
||||
),
|
||||
'┼' => Cross(
|
||||
((), MM, ()), //
|
||||
(MM, MM, MM), //
|
||||
((), MM, ()), //
|
||||
),
|
||||
'├' => Cross(
|
||||
((), MM, ()), //
|
||||
(F_, MM, MM), //
|
||||
((), MM, ()), //
|
||||
),
|
||||
'┤' => Cross(
|
||||
((), MM, ()), //
|
||||
(MM, MM, F_), //
|
||||
((), MM, ()), //
|
||||
),
|
||||
'┴' => Cross(
|
||||
((), MM, ()), //
|
||||
(MM, MM, MM), //
|
||||
((), F_, ()), //
|
||||
),
|
||||
'┬' => Cross(
|
||||
((), F_, ()), //
|
||||
(MM, MM, MM), //
|
||||
((), MM, ()), //
|
||||
),
|
||||
'─' => Cross(
|
||||
((), F_, ()), //
|
||||
(MM, MM, MM), //
|
||||
((), F_, ()), //
|
||||
),
|
||||
'│' => Cross(
|
||||
((), MM, ()), //
|
||||
(F_, MM, F_), //
|
||||
((), MM, ()), //
|
||||
),
|
||||
'┘' => Cross(
|
||||
((), MM, ()), //
|
||||
(MM, MM, F_), //
|
||||
((), F_, ()), //
|
||||
),
|
||||
'┐' => Cross(
|
||||
((), F_, ()), //
|
||||
(MM, MM, F_), //
|
||||
((), MM, ()), //
|
||||
),
|
||||
'┌' => Cross(
|
||||
((), F_, ()), //
|
||||
(F_, MM, MM), //
|
||||
((), MM, ()), //
|
||||
),
|
||||
'└' => Cross(
|
||||
((), MM, ()), //
|
||||
(F_, MM, MM), //
|
||||
((), F_, ()), //
|
||||
),
|
||||
_ => Cross(
|
||||
((), F_, ()), //
|
||||
(F_, F_, F_), //
|
||||
((), F_, ()), //
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
const F_: bool = false;
|
||||
const MM: bool = true;
|
||||
type Empt = ();
|
||||
struct Cross(
|
||||
(Empt, bool, Empt), //
|
||||
(bool, bool, bool), //
|
||||
(Empt, bool, Empt), //
|
||||
);
|
||||
|
||||
impl Cross {
|
||||
fn u(&self) -> bool {
|
||||
self.0.1
|
||||
}
|
||||
|
||||
fn d(&self) -> bool {
|
||||
self.2.1
|
||||
}
|
||||
|
||||
fn l(&self) -> bool {
|
||||
self.1.0
|
||||
}
|
||||
|
||||
fn r(&self) -> bool {
|
||||
self.1.2
|
||||
}
|
||||
|
||||
fn c(&self) -> bool {
|
||||
self.1.1
|
||||
}
|
||||
}
|
21
test/out.txt
Normal file
21
test/out.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
|
||||
this is a normalized data table diagram.
|
||||
|
||||
+----------------+
|
||||
|USERS BY EMAIL |
|
||||
+--+-----+-------+
|
||||
|id|email|user_id|
|
||||
+--+-----+-------+
|
||||
| 1|b@o.b| 1|
|
||||
| 2|c@r.l| 2|
|
||||
+--+-----+-------+
|
||||
+---------------+
|
||||
|USERS |
|
||||
+--+--------+---+
|
||||
|id| name|age|
|
||||
+--+--------+---+
|
||||
| 1| bob| 19|
|
||||
| 2| charlie| 23|
|
||||
+--+--------+---+
|
||||
|
||||
|
21
test/source.txt
Normal file
21
test/source.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
|
||||
this is a normalized data table diagram.
|
||||
|
||||
+----------------+
|
||||
|USERS BY EMAIL |
|
||||
+--+-----+-------+
|
||||
|id|email|user_id|
|
||||
+--+-----+-------+
|
||||
| 1|b@o.b| 1|
|
||||
| 2|c@r.l| 2|
|
||||
+--+-----+-------+
|
||||
+---------------+
|
||||
|USERS |
|
||||
+--+--------+---+
|
||||
|id| name|age|
|
||||
+--+--------+---+
|
||||
| 1| bob| 19|
|
||||
| 2| charlie| 23|
|
||||
+--+--------+---+
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue