aboutsummaryrefslogtreecommitdiff
path: root/ttt.jai
diff options
context:
space:
mode:
authordam <dam@gudinoff>2023-04-16 17:34:26 +0100
committerdam <dam@gudinoff>2023-04-16 17:34:26 +0100
commit7ad87637467a4757accae3fd4ad09c7ddb0b289e (patch)
tree74d026cea7ed45c28817760c9a643ded4bda3c68 /ttt.jai
parent2a893df3b65bfd01e666c0df0498dba1694ebebe (diff)
downloadtask-time-tracker-7ad87637467a4757accae3fd4ad09c7ddb0b289e.tar.zst
task-time-tracker-7ad87637467a4757accae3fd4ad09c7ddb0b289e.zip
Ported all features to jai.
Diffstat (limited to 'ttt.jai')
-rw-r--r--ttt.jai248
1 files changed, 120 insertions, 128 deletions
diff --git a/ttt.jai b/ttt.jai
index 08b2ea4..bc81901 100644
--- a/ttt.jai
+++ b/ttt.jai
@@ -36,8 +36,12 @@ NAME_SIZE :: 72; // TODO Use this instead of Task.name.count ?
APP_FOLDER_NAME :: ".task_time_tracker_v2"; // TODO Using _v2 to avoid erasing my work data.
DB_FILE_NAME :: "database.bin";
AR_FILE_NAME :: "archive.csv";
-
DB_FILE_SIGN_STR :: "TTT:B:02";
+
+ASSERT_NOT_NULL :: "Parameter '%' is null.";
+ASSERT_NOT_EMPTY :: "Parameter '%' is empty.";
+ASSERT_NOT_CONTAIN :: "'%' does not contain '%'.";
+
SECONDS_IN_MINUTE :: cast(s64)60;
SECONDS_IN_HOUR :: cast(s64)60*SECONDS_IN_MINUTE;
SECONDS_IN_DAY :: cast(s64)24*SECONDS_IN_HOUR;
@@ -181,8 +185,8 @@ number_size :: (number: s64, base: s64 = 10) -> s64 {
// WIP TODO Ues compiler time code to see the auto bake being used... just for fun, once! :D
truncate_string :: (str: string, length: s64, $encoding: Text_Encoding = .UTF8) -> length: s64 #no_abc { // TODO Should I use #no_abc ?
- assert(str.data != null);
- assert(str.count >= length);
+ assert(str.data != null, ASSERT_NOT_NULL, "str");
+ assert(str.count >= length, "'str.count' should be equal or greater to 'length'.");
data := str.data;
count := str.count;
@@ -236,40 +240,44 @@ is_empty_string :: (str: string) -> bool {
// Prints, on row y and column x, the time using 5 characters centered on space.
// Returns the result of a call to mvprintw.
-mvprintw_time :: (y: s32, x: s32, time: s64, space: s32) -> int {
+mvprintw_time :: (y: s32, x: s32, time: s64, space: s32) -> int { // BUG Setting a timer to 99.9y shows 100y.
TIME_CHARS :: 5;
assert(space >= TIME_CHARS);
+ mul_f64_s64 :: inline (a: float64, b: s64) -> s64 {
+ return cast(s64)(a * cast(float64)b);
+ }
+
left_padding := (space - TIME_CHARS) / 2;
right_padding := space - TIME_CHARS - left_padding;
- if (time < 0) {
+ if time < 0 {
return mvprintw(y, x, "%*s - %*s", left_padding, "", right_padding, "");
}
- else if (time == 0) {
+ else if time == 0 {
return mvprintw(y, x, "%*s 0 %*s", left_padding, "", right_padding, "");
}
- else if (time < SECONDS_IN_MINUTE) {
+ else if time < SECONDS_IN_MINUTE {
return mvprintw(y, x, "%*s%3jds %*s", left_padding, "", time, right_padding, "");
}
- else if (time < 100 * SECONDS_IN_HOUR) {
+ else if time < #run mul_f64_s64(100, SECONDS_IN_HOUR) {
hours := time / SECONDS_IN_HOUR;
minutes := (time - (hours * SECONDS_IN_HOUR) ) / SECONDS_IN_MINUTE;
return mvprintw(y, x, "%*s%02jd:%02jd%*s", left_padding, "", hours, minutes, right_padding, "");
}
- else if (time < xx (9999.5 * SECONDS_IN_DAY)) {
+ else if time < #run mul_f64_s64(9999.5, SECONDS_IN_DAY) {
value := cast(float64) time / SECONDS_IN_DAY;
decimals :=
- ifx time >= xx 99.95 * SECONDS_IN_DAY then 0 else
- ifx time >= xx 9.995 * SECONDS_IN_DAY then 1 else
+ ifx time >= #run mul_f64_s64(99.95, SECONDS_IN_DAY) then 0 else
+ ifx time >= #run mul_f64_s64(9.995, SECONDS_IN_DAY) then 1 else
2;
return mvprintw(y, x, "%*s%4.*fd%*s", left_padding, "", decimals, value, right_padding, "");
}
- else if (time < xx (9999.5 * SECONDS_IN_YEAR)) {
+ else if time < #run mul_f64_s64(9999.5, SECONDS_IN_YEAR) {
value := cast(float64) time / SECONDS_IN_YEAR;
decimals :=
- ifx time >= xx 99.95 * SECONDS_IN_YEAR then 0 else
- ifx time >= xx 9.995 * SECONDS_IN_YEAR then 1 else
+ ifx time >= #run mul_f64_s64(99.95, SECONDS_IN_YEAR) then 0 else
+ ifx time >= #run mul_f64_s64(9.995, SECONDS_IN_YEAR) then 1 else
2;
return mvprintw(y, x, "%*s%4.*fy%*s", left_padding, "", decimals, value, right_padding, "");
}
@@ -310,7 +318,7 @@ contains_task :: inline (db: Database, task: *Task) -> bool {
// Adds a task to the database and returns it.
// If necessary, expands database capacity.
add_task :: (db: *Database, task: Task = .{}) -> task: *Task {
- assert(db != null, "Parameter 'db' is null.");
+ assert(db != null, ASSERT_NOT_NULL, "db");
array_add(*db.tasks, task);
for * db.total_times {
@@ -324,10 +332,9 @@ add_task :: (db: *Database, task: Task = .{}) -> task: *Task {
// If possible, shrinks the database capacity.
// Returns success.
delete_task :: (db: *Database, task: *Task) -> bool {
-
- assert(db != null);
- assert(task != null);
- assert(contains_task(db, task));
+ assert(db != null, ASSERT_NOT_NULL, "db");
+ assert(task != null, ASSERT_NOT_NULL, "task");
+ assert(contains_task(db, task), ASSERT_NOT_CONTAIN, "db", "task");
// Remove task timer values from total timers.
for task.times {
@@ -387,9 +394,9 @@ delete_task :: (db: *Database, task: *Task) -> bool {
// Moves task to index.
// Index gets clamped to [0, db->count[.
move_task_to_index :: (db: *Database, task: *Task, index: s64) {
- assert(db != null, "Parameter 'db' is null.");
- assert(task != null, "Parameter 'task' is null.");
- assert(contains_task(db, task), "Database does not contain task.");
+ assert(db != null, ASSERT_NOT_NULL, "db");
+ assert(task != null, ASSERT_NOT_NULL, "task");
+ assert(contains_task(db, task), ASSERT_NOT_CONTAIN, "db", "task");
target_index := clamp(index, 0, db.tasks.count-1);
target_task := *db.tasks[target_index];
@@ -430,7 +437,7 @@ move_task_to_index :: (db: *Database, task: *Task, index: s64) {
// Updates the times on the active task (and adjusts database totals).
update_times :: (db: *Database) {
- assert(db != null);
+ assert(db != null, ASSERT_NOT_NULL, "db");
if db.active_idx < 0 return;
@@ -467,7 +474,7 @@ update_times :: (db: *Database) {
// Recalculates database totals.
update_total_times :: (db: *Database) {
- assert(db != null);
+ assert(db != null, ASSERT_NOT_NULL, "db");
totals: []s64 = db.total_times;
memset(totals.data, 0, NUM_WEEK_DAYS * size_of(s64));
@@ -485,9 +492,9 @@ update_total_times :: (db: *Database) {
// Resets the times of the provided task (and adjusts database totals).
reset_task_times :: (db: *Database, task: *Task) {
- assert(db != null);
- assert(task != null);
- assert(contains_task(db, task));
+ assert(db != null, ASSERT_NOT_NULL, "db");
+ assert(task != null, ASSERT_NOT_NULL, "task");
+ assert(contains_task(db, task), ASSERT_NOT_CONTAIN, "db", "task");
// Make sure we sync before applying the changes.
update_times(db);
@@ -497,40 +504,36 @@ reset_task_times :: (db: *Database, task: *Task) {
<<it = 0;
}
}
-/*
+
// Sets the time on the day and task provided (and adjusts database totals).
-void set_task_time(database_st *db, task_st *task, int day, int64_t time) {
- assert(db != NULL);
- assert(task != NULL);
- assert(task >= db->tasks && task - db->tasks < db->count);
+set_task_time :: (db: *Database, task: *Task, day: int, time: s64) {
+ assert(db != null, ASSERT_NOT_NULL, "db");
+ assert(task != null, ASSERT_NOT_NULL, "task");
+ assert(contains_task(db, task), ASSERT_NOT_CONTAIN, "db", "task");
// Make sure we sync before applying the changes.
update_times(db);
- int64_t *timer = &task->times[day];
- int64_t *total = &db->total_times[day];
- *total = sub_int64(*total, *timer);
- *timer = time;
- *total = add_int64(*total, *timer);
+ db.total_times[day] = add_int64(db.total_times[day], time - task.times[day]);
+ task.times[day] = time;
}
// Adds the time on the day and task provided (and adjusts database totals).
-void add_task_time(database_st *db, task_st *task, int day, int64_t time) {
- assert(db != NULL);
- assert(task != NULL);
- assert(task >= db->tasks && task - db->tasks < db->count);
+add_task_time :: (db: *Database, task: *Task, day: int, time: s64) {
+ assert(db != null, ASSERT_NOT_NULL, "db");
+ assert(task != null, ASSERT_NOT_NULL, "task");
+ assert(contains_task(db, task), ASSERT_NOT_CONTAIN, "db", "task");
// Make sure we sync before applying the changes.
update_times(db);
- task->times[day] = add_int64(task->times[day], time);
- db->total_times[day] = add_int64(db->total_times[day], time);
+ db.total_times[day] = add_int64(db.total_times[day], time);
+ task.times[day] = add_int64(task.times[day], time);
}
-*/
// Resets database to the initial state and deallocates all memory taken by tasks.
reset_database :: (db: *Database) {
- assert(db != null, "Parameter 'db' is null.");
+ assert(db != null, ASSERT_NOT_NULL, "db");
array_reset(*db.tasks);
<<db = .{};
}
@@ -538,7 +541,7 @@ reset_database :: (db: *Database) {
// Stores data from database into binary file.
// Returns success.
store_database :: (db: Database, path: string) -> success: bool {
- assert(xx path, "Parameter 'path' is empty.");
+ assert(xx path, ASSERT_NOT_EMPTY, "path");
// Open file.
file, open_success := file_open(path, for_writing = true); // log_errors: bool = true
@@ -558,8 +561,8 @@ store_database :: (db: Database, path: string) -> success: bool {
// Loads data from binary file into database.
// Returns success.
load_database :: (db: *Database, path: string) -> success: bool {
- assert(db != null, "Parameter 'db' is null.");
- assert(xx path, "Parameter 'path' is empty.");
+ assert(db != null, ASSERT_NOT_NULL, "db");
+ assert(xx path, ASSERT_NOT_EMPTY, "path");
// Open file.
file, open_success := file_open(path); // log_errors: bool = true
@@ -607,7 +610,7 @@ load_database :: (db: *Database, path: string) -> success: bool {
// Exports data into CSV file.
// Returns success.
export_to_csv :: (db: Database, path: string) -> success: bool {
- assert(xx path, "Parameter 'path' is empty.");
+ assert(xx path, ASSERT_NOT_EMPTY, "path");
// TODO Make sure (IN ALL PROCEDURES) we're not receiving an empty path.
@@ -637,8 +640,8 @@ export_to_csv :: (db: Database, path: string) -> success: bool {
// Returns success.
import_from_csv :: (db: *Database, path: string) -> bool {
// TODO Review code.
- assert(db != null, "Parameter 'db' is null.");
- assert(xx path, "Parameter 'path' is empty.");
+ assert(db != null, ASSERT_NOT_NULL, "db");
+ assert(xx path, ASSERT_NOT_EMPTY, "path");
error_code: s64;
// Check file size TODO Read based on file size
@@ -750,6 +753,9 @@ import_from_csv :: (db: *Database, path: string) -> bool {
// }
}
}
+
+ // Adjust selected task.
+ if (db.selected_idx < 0) db.selected_idx = 0;
return true;
}
@@ -757,7 +763,7 @@ import_from_csv :: (db: *Database, path: string) -> bool {
// Appends task to the end of the CSV file.
// Returns success.
append_to_csv :: (task: Task, path: string) -> success: bool {
- assert(xx path, "Parameter 'path' is empty.");
+ assert(xx path, ASSERT_NOT_EMPTY, "path");
file, file_success := file_open(path, true, true);
defer file_close(*file);
@@ -785,7 +791,7 @@ append_to_csv :: (task: Task, path: string) -> success: bool {
// Selects task by index.
// Index gets clamped to [0, db->count[.
select_task_by_index :: (db: *Database, index: s64) {
- assert(db != null);
+ assert(db != null, ASSERT_NOT_NULL, "db");
db.selected_idx = ifx db.tasks.count == 0 then -1 else
ifx index < 0 then 0 else
ifx index >= db.tasks.count then db.tasks.count - 1 else
@@ -794,7 +800,7 @@ select_task_by_index :: (db: *Database, index: s64) {
// Selects task by delta relative to currently selected task.
select_task_by_delta :: (db: *Database, delta: s64) {
- assert(db != null);
+ assert(db != null, ASSERT_NOT_NULL, "db");
// TODO I bet there's a better way to do this... maybe use a clamp or range or something.
idx :=
ifx (delta > 0 && db.selected_idx > S64_MAX - delta) then S64_MAX else
@@ -803,19 +809,22 @@ select_task_by_delta :: (db: *Database, delta: s64) {
select_task_by_index(db, idx);
}
+
+
// Selects task.
select_task :: (db: *Database, task: *Task) {
- assert(db != null);
- assert(task != null);
- assert(task >= db.tasks.data && task - db.tasks.data < db.tasks.count);
+ assert(db != null, ASSERT_NOT_NULL, "db");
+ assert(task != null, ASSERT_NOT_NULL, "task");
+ assert(contains_task(db, task), ASSERT_NOT_CONTAIN, "db", "task");
db.selected_idx = task - db.tasks.data;
}
// Set active task.
// Passing task as NULL de-activates any previously active task.
set_active_task :: (db: *Database, task: *Task) {
- assert(db != null);
- assert(task == null || (task >= db.tasks.data && task <= *db.tasks[db.tasks.count-1])); // TODO Improve this check.
+ assert(db != null, ASSERT_NOT_NULL, "db");
+ if task != null
+ assert(contains_task(db, task), ASSERT_NOT_CONTAIN, "db", "task");
update_times(db);
db.active_idx = ifx (task == null) then -1 else task - db.tasks.data;
}
@@ -1160,7 +1169,7 @@ read_input_int :: (row: int, style: s32, message: string) -> value: int, success
// Retuns true if user presses enter, false otherwise.
read_enter_confirmation :: (row: int, style: int, message: string) -> bool {
- assert(message.data != null);
+ assert(message.data != null, ASSERT_NOT_NULL, "message"); // TODO Improve this check?
attron(xx style);
move(xx row, 1);
@@ -1451,93 +1460,76 @@ main :: () {
delete_task(db, selected_task);
trigger_autosave();
}
-/*
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7': {
- if (selected_task == NULL) {
- break;
- }
+
+ case #char "1"; #through;
+ case #char "2"; #through;
+ case #char "3"; #through;
+ case #char "4"; #through;
+ case #char "5"; #through;
+ case #char "6"; #through;
+ case #char "7";
+ if (selected_task == null) continue;
// Prepare position to input time operation.
- int selected_day = key - '1';
- int input_width = layout->columns[L_DAYS_IDX + selected_day].width;
- int input_pos_x = 1 + layout->columns[L_TITLE_IDX].width;
- for (int col = 0; col < selected_day; col++) {
- input_pos_x += 1 + layout->columns[L_DAYS_IDX + col].width;
+ selected_day := key - #char "1";
+ input_width := layout.columns[L_DAYS_IDX + selected_day].width;
+ input_pos_x := 1 + layout.columns[L_TITLE_IDX].width;
+
+ for 0..selected_day-1 {
+ input_pos_x += 1 + layout.columns[L_DAYS_IDX + it].width;
}
- input_pos_x++;
+ input_pos_x += 1;
// Get input string.
- read_input_to_string_buffer(selected_task_row, input_pos_x, action_style, input_width);
- char *input = string_buffer;
+ input := read_input_string(selected_task_row, input_pos_x, action_style, input_width); // TODO Temp stringzes.
// Abort if input if empty.
- if (is_empty_string(input) == true) {
- break;
- }
+ if is_empty_string(input) continue;
- // Search for assign '=' operator and discard everything before (if found).
- char *assign_str = strchr(input, '=');
- bool is_assign = assign_str != NULL;
- if (is_assign == true) {
- input = assign_str + 1;
- }
+ // Search for assign '=' operator and discard everything before it.
+ assign_idx := find_index_from_left(input, "=");
+ is_assign := assign_idx >= 0;
+ if is_assign advance(*input, assign_idx + 1);
// Try to parse a number and abort if it fails.
- char *parser;
- long double input_float = strtold(input, &parser);
- if (parser == input) {
- break;
- }
- input = parser;
+ input_float, parse_success := string_to_float64(input);
+ if parse_success == false continue;
// Try to parse a character representing the time multiplier.
- long double multiplier = 1.0;
- for (int i=0; i < strlen(input); i++) {
- char ch = input[i];
- if (ch == 'm' || ch == 'M') {
- multiplier = SECONDS_IN_MINUTE;
- break;
- }
- else if (ch == 'h' || ch == 'H') {
- multiplier = SECONDS_IN_HOUR;
- break;
- }
- else if (ch == 'd' || ch == 'D') {
- multiplier = SECONDS_IN_DAY;
- break;
- }
- else if (ch == 'y' || ch == 'Y') {
- multiplier = SECONDS_IN_YEAR;
- break;
+ multiplier: float64 = 1.0;
+ for 0..input.count-1 {
+ ch := to_lower(input[it]);
+ if ch == {
+ case #char "m";
+ multiplier = xx SECONDS_IN_MINUTE;
+ break;
+
+ case #char "h";
+ multiplier = xx SECONDS_IN_HOUR;
+ break;
+
+ case #char "d";
+ multiplier = xx SECONDS_IN_DAY;
+ break;
+
+ case #char "y";
+ multiplier = xx SECONDS_IN_YEAR;
+ break;
}
}
// Process input and check if it's valid.
- long double input_time = input_float * multiplier;
- bool is_result_valid = (input_time >= (long double)INT64_MIN && input_time <= (long double)INT64_MAX);
- if (is_result_valid == false) {
- break;
- }
+ input_time := input_float * multiplier;
+ if (input_time > xx S64_MAX || input_time < xx S64_MIN) continue;
// Apply changes.
- int64_t time = input_time;
- int day = (selected_day + FIRST_DAY_OF_WEEK) % NUM_WEEK_DAYS;
- if (is_assign == true) {
- set_task_time(db, selected_task, day, time);
- }
- else {
- add_task_time(db, selected_task, day, time);
- }
+ time := cast(s64)input_time;
+ day := (selected_day + FIRST_DAY_OF_WEEK) % NUM_WEEK_DAYS;
+ if is_assign set_task_time(db, selected_task, day, time);
+ else add_task_time(db, selected_task, day, time);
+
trigger_autosave();
- break;
- }
-*/
+
case #char "m"; #through;
case #char "M";
if selected_task == null continue;