Compare commits

..

21 commits

Author SHA1 Message Date
2f42d4de91
clippy 2022-08-23 17:53:57 +02:00
642387dcd3
fix semester detection and rollback debug 2022-08-23 17:53:57 +02:00
0e714fd4d3
works! kinda.. 2022-08-23 17:53:57 +02:00
ff32a67ce6
wip: done 2022-08-23 17:53:57 +02:00
b7581584dc
wip 2022-08-23 17:53:57 +02:00
8b1d7c5b57
fix hour column with big cell 2022-08-23 17:53:57 +02:00
aa287b87c2
WIP: table 2022-08-23 17:53:57 +02:00
526cd46747
verbose translation to fr 2022-08-23 17:53:57 +02:00
3fe5529842
support bigcell format 2022-08-23 17:53:57 +02:00
f62c8498ca
unreachable code removal 2022-08-23 17:53:57 +02:00
c771c249c5
helper line 2022-08-23 17:53:57 +02:00
95bd3a53a9
support skip 2022-08-23 17:53:57 +02:00
07caadc77f
old comment 2022-08-23 17:53:57 +02:00
5bc1ddb64d
move enum to other file 2022-08-23 17:53:57 +02:00
e4aa7c624c
Add stuff to build the table 2022-08-23 17:53:57 +02:00
ab416848ef
remove debug 2022-08-23 17:53:57 +02:00
fa51950060
uppercase the letter 2022-08-23 17:53:57 +02:00
ac6dbcf54c
print separator 2022-08-23 17:53:57 +02:00
7e5461ed81
don't use special dependencie for table format 2022-08-23 17:53:57 +02:00
29117f7e28
show days 2022-08-23 17:53:57 +02:00
f6b6972ee5
wip 2022-08-23 17:53:57 +02:00
5 changed files with 230 additions and 12 deletions

View file

@ -24,11 +24,12 @@ $ cargo build --release && cd target/release/
$ ./cal8tor --help
```
## ***WIP:*** See the calendar in your terminal
## See the calendar in your terminal
For the L2-X, run:
```bash
$ ./cal8tor l2-X
```
> The rendering can sometimes be unreadable and/or hard to read.
## Export the calendar in .ics format
For the L1-A, run:

View file

@ -41,26 +41,34 @@ async fn main() {
.name("letter")
.map(|c| c.as_str().chars().next().expect("Error in letter"));
// Show a separator only if we need one
let seperator = match letter {
Some(_) => "-",
None => "",
};
println!(
"Fetch the timetable for L{}{}...",
"Récupération de l'emploi du temps des L{}{}{}...",
year,
letter.unwrap_or_default()
seperator,
letter.unwrap_or_default().to_uppercase()
);
let timetable = timetable::timetable(year, args.semester, letter).await;
println!("Fetch informations about the year...");
println!("Récupération des informations par rapport à l'année...");
let info = info::info().await;
if args.export.is_some() {
// Export the calendar
let filename = args.export.unwrap();
println!("Build the ICS file at {}...", filename);
println!("Fichier .ICS construit et exporté ici : {}...", filename);
let builded_timetable = timetable::build(timetable, info);
ics::export(builded_timetable, filename);
} else {
// Show the calendar
println!("Displaying...");
timetable::display();
println!("Affichage...");
timetable::display(timetable);
println!("Vous devrez peut-être mettre votre terminal en plein écran si ce n'est pas déjà le cas.");
}
}

View file

@ -1,6 +1,12 @@
use chrono::{Datelike, Duration, TimeZone, Utc};
use regex::Regex;
use scraper::{Html, Selector};
use std::collections::HashMap;
use crate::utils::{
self,
models::{Position, TabChar},
};
pub mod models;
@ -175,7 +181,7 @@ async fn get_webpage(
}
/// Check if the timetable is well built
fn check_consistency(schedules: &Vec<String>, timetable: &Vec<models::Day>) -> bool {
fn check_consistency(schedules: &[String], timetable: &Vec<models::Day>) -> bool {
let mut checker = true;
for day in timetable {
let mut i = 0;
@ -211,7 +217,7 @@ type T = (
(usize, Vec<models::Day>),
);
// Data builded in the info webpage
type D = std::collections::HashMap<
type D = HashMap<
// Semester
usize,
// List of start and repetition of course weeks
@ -299,7 +305,7 @@ fn get_semester(semester: Option<i8>, letter: Option<char>) -> i8 {
None => match letter {
// Based on letter (kinda accurate)
Some(c) => {
if c as i8 > 77 {
if c.to_ascii_uppercase() as i8 > 77 {
// If letter is N or after
2
} else {
@ -322,6 +328,89 @@ fn get_semester(semester: Option<i8>, letter: Option<char>) -> i8 {
}
/// Display the timetable
pub fn display() {
todo!("WIP")
pub fn display(timetable: (Vec<String>, (usize, Vec<models::Day>))) {
// Cell length
let cl = 35;
// Cell length for hours
let clh = 11;
// Cell number
let cn = 6;
let sep = TabChar::Bv.val();
// Top of the tab
utils::line_table(clh, cl, cn, Position::Top, HashMap::new());
// First empty case
print!("{}{:^clh$}{}", sep, "", sep);
// Print day's of the week
let mut days = HashMap::new();
for (i, data) in (&timetable.1 .1).iter().enumerate() {
days.insert(i, &data.name);
print!("{:^cl$}{}", &data.name, sep);
}
// Store the data of the course for utils::line_table
let mut next_skip = HashMap::new();
// For each hours -- i the hour's number
for (i, hour) in timetable.0.into_iter().enumerate() {
// Draw separator line
utils::line_table(clh, cl, cn, Position::Middle, next_skip);
// Reset
next_skip = HashMap::new();
// Print hour
print!("{}{:^clh$}", sep, hour);
// For all the days - `j` the day's number
for (j, day) in (&timetable.1 .1).iter().enumerate() {
// True if we found something about the slot we are looking for
let mut info_slot = false;
// For all the courses of each days - `k` the possible course.start
for (k, course_opt) in (&day.courses).iter().enumerate() {
match course_opt {
// If there is a course
Some(course) => {
// Check the course's hour
if i == course.start {
if course.size > 1 {
// If the course uses more than one time slot
next_skip.insert(j, &course.name);
print!("{}{:^cl$}", sep, "");
info_slot = true;
break;
} else {
// Else simply print the course
print!("{}{:^cl$}", sep, &course.name);
info_slot = true;
break;
}
}
}
// If no course was found
None => {
// Verify the "no course" is in the correct day and hour
if *days.get(&j).unwrap() == &day.name.to_string() && k == i {
// If yes print empty row because there is no course
print!("{}{:^cl$}", sep, "");
info_slot = true;
break;
}
// Else it was a course of another day/time
}
};
}
if !info_slot {
// We found nothing about the slot because the precedent course
// takes more place than one slot
print!("{}{:^cl$}", sep, "");
}
}
print!("{}", sep);
}
// Bottom of the table
utils::line_table(clh, cl, cn, Position::Bottom, HashMap::new());
}

View file

@ -1,3 +1,5 @@
pub mod models;
/// Panic if an error happened
pub fn check_errors(html: &String, loc: &str) {
match html {
@ -13,3 +15,70 @@ pub fn check_errors(html: &String, loc: &str) {
fn err_code(code: i32) -> String {
format!("HTTP Code : {}", code)
}
/// Print a line for the table
pub fn line_table(
cell_length_hours: usize,
cell_length: usize,
number_cell: usize,
pos: models::Position,
skip_with: std::collections::HashMap<usize, &str>,
) {
// Left side
let ls = match pos {
models::Position::Top => models::TabChar::Jtl.val(),
models::Position::Middle => models::TabChar::Jl.val(),
models::Position::Bottom => models::TabChar::Jbl.val(),
};
// Middle
let ms = match pos {
models::Position::Top => models::TabChar::Jtb.val(),
models::Position::Middle => models::TabChar::Jm.val(),
models::Position::Bottom => models::TabChar::Jtt.val(),
};
// Right side
let rs = match pos {
models::Position::Top => models::TabChar::Jtr.val(),
models::Position::Middle => models::TabChar::Jr.val(),
models::Position::Bottom => models::TabChar::Jbr.val(),
};
// Right side before big cell
let rs_bbc = models::TabChar::Jr.val();
// Right side big cell before big cell
let rsbc_bbc = models::TabChar::Bv.val();
// Right side big cell
let rsbc = models::TabChar::Jl.val();
let line = models::TabChar::Bh.val().to_string().repeat(cell_length);
let line_h = models::TabChar::Bh
.val()
.to_string()
.repeat(cell_length_hours);
// Hours column
match skip_with.get(&0) {
Some(_) => print!("\n{}{}{}", ls, line_h, rs_bbc),
None => print!("\n{}{}{}", ls, line_h, ms),
};
// Courses columns
for i in 0..number_cell - 2 {
// Check if it's a big cell
match skip_with.get(&i) {
Some(text) => match skip_with.get(&(i + 1)) {
// Match check if the next cell will be big
Some(_) => print!("{:^cell_length$}{}", text, rsbc_bbc),
None => print!("{:^cell_length$}{}", text, rsbc),
},
None => match skip_with.get(&(i + 1)) {
// Match check if the next cell will be big
Some(_) => print!("{}{}", line, rs_bbc),
None => print!("{}{}", line, ms),
},
}
}
println!("{}{}", line, rs);
}

51
src/utils/models.rs Normal file
View file

@ -0,0 +1,51 @@
/// Collection of char for the table
pub enum TabChar {
/// Vertical bar
Bv,
/// Horizontal bar
Bh,
/// Joint left
Jl,
/// Joint right
Jr,
/// Joint bottom left
Jbl,
/// Joint bottom right
Jbr,
/// Joint top left
Jtl,
/// Joint top right
Jtr,
/// Joint to top
Jtt,
/// Joint to bottom
Jtb,
/// Joint of the middle
Jm,
}
impl TabChar {
/// Value of the element
pub fn val(&self) -> char {
match *self {
Self::Bv => '│',
Self::Bh => '─',
Self::Jl => '├',
Self::Jr => '┤',
Self::Jbl => '└',
Self::Jbr => '┘',
Self::Jtl => '┌',
Self::Jtr => '┐',
Self::Jtt => '┴',
Self::Jtb => '┬',
Self::Jm => '┼',
}
}
}
/// Position for lines inside the table
pub enum Position {
Top,
Middle,
Bottom
}