diff options
| author | dam <dam@gudinoff> | 2023-04-18 01:29:19 +0100 |
|---|---|---|
| committer | dam <dam@gudinoff> | 2023-04-18 01:29:19 +0100 |
| commit | 36c91454f2c5678bb648c23bcbc58feb12a006f7 (patch) | |
| tree | 4c5405d995d14a9a873ee6c3ff51f2ff35020029 | |
| parent | f0d4c9a424c2346da6209fad19dde88905cb012a (diff) | |
| download | task-time-tracker-36c91454f2c5678bb648c23bcbc58feb12a006f7.tar.zst task-time-tracker-36c91454f2c5678bb648c23bcbc58feb12a006f7.zip | |
Using task index instead of pointer on helper functions.
| -rw-r--r-- | ttt.jai | 219 |
1 files changed, 99 insertions, 120 deletions
@@ -41,6 +41,7 @@ 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 '%'."; +ASSERT_INVALID_INDEX:: "Invalid index '%'."; SECONDS_IN_MINUTE :: cast(s64)60; SECONDS_IN_HOUR :: cast(s64)60*SECONDS_IN_MINUTE; @@ -282,7 +283,10 @@ mvprintw_time :: (y: s32, x: s32, time: s64, space: s32) -> int { // BUG Setting return mvprintw(y, x, "%*s%4.*fy%*s", left_padding, "", decimals, value, right_padding, ""); } else { - return mvprintw(y, x, "%*s ∞ %*s", left_padding, "", right_padding, ""); + // TODO Solve unicode emoji gone wild. + //return mvprintw(y, x, "%*s ∞ %*s", left_padding, "", right_padding, ""); + //return mvprintw(y, x, "%*s \xE2\x99\xBE %*s", left_padding, "", right_padding, ""); + return mvprintw(y, x, "%*s inf %*s", left_padding, "", right_padding, ""); } } @@ -310,14 +314,11 @@ get_selected_task :: inline (db: Database) -> *Task { return ifx db.selected_idx >= 0 then *db.tasks[db.selected_idx] else null; } -// TODO Add description. -contains_task :: inline (db: Database, task: *Task) -> bool { - return task >= db.tasks.data && task - db.tasks.data < db.tasks.count; -} +is_valid_index :: inline(db: Database, index: s64) -> bool { return index >= 0 && index < db.tasks.count; } // Adds a task to the database and returns it. // If necessary, expands database capacity. -add_task :: (db: *Database, task: Task = .{}) -> task: *Task { +add_task :: (db: *Database, task: Task = .{}) -> task: *Task, index: s64 { assert(db != null, ASSERT_NOT_NULL, "db"); array_add(*db.tasks, task); @@ -325,47 +326,46 @@ add_task :: (db: *Database, task: Task = .{}) -> task: *Task { <<it = add_int64(<<it, task.times[it_index]); } - return *db.tasks[db.tasks.count-1]; + idx := db.tasks.count-1; + return *db.tasks[idx], idx; } // Deletes task from database. // If possible, shrinks the database capacity. // Returns success. -delete_task :: (db: *Database, task: *Task) -> bool { +delete_task :: (using db: *Database, index: s64) -> bool { // TODO Maybe use `using db`. assert(db != null, ASSERT_NOT_NULL, "db"); - assert(task != null, ASSERT_NOT_NULL, "task"); - assert(contains_task(db, task), ASSERT_NOT_CONTAIN, "db", "task"); + assert(is_valid_index(db, index), ASSERT_INVALID_INDEX, index); // Remove task timer values from total timers. - for task.times { - db.total_times[it_index] = sub_int64(db.total_times[it_index], it); + for tasks[index].times { + total_times[it_index] = sub_int64(total_times[it_index], it); } // Move tasks after the index position to their new positions. - index := task - db.tasks.data; - for index..db.tasks.count-2 - db.tasks[it] = db.tasks[it+1]; - db.tasks.count -= 1; + for index..tasks.count-2 + tasks[it] = tasks[it+1]; + tasks.count -= 1; // Adjust selected task. - if (db.selected_idx >= db.tasks.count) { - db.selected_idx -= 1; + if (selected_idx >= tasks.count) { + selected_idx -= 1; } // Adjust active task. - if (db.active_idx > index) { - db.active_idx -= 1; + if (active_idx > index) { + active_idx -= 1; } - else if (db.active_idx == index) { - db.active_idx = -1; + else if (active_idx == index) { + active_idx = -1; } // If possible, shrink database capacity. // TODO Do we really want to make this fuss? - current_capacity := db.tasks.allocated; - if (db.tasks.count < (current_capacity >> 2)) { - new_capacity := 1 << (get_msb(db.tasks.count) + 2); - my_array_reserve_nonpoly(xx *db.tasks, new_capacity, SIZE_OF_TASK); + current_capacity := tasks.allocated; + if (tasks.count < (current_capacity >> 2)) { + new_capacity := 1 << (get_msb(tasks.count) + 2); + my_array_reserve_nonpoly(xx *tasks, new_capacity, SIZE_OF_TASK); } get_msb :: (value: s64) -> msb: s64, found: bool { @@ -391,48 +391,42 @@ delete_task :: (db: *Database, task: *Task) -> bool { return true; } -// Moves task to index. -// Index gets clamped to [0, db->count[. -move_task_to_index :: (db: *Database, task: *Task, index: s64) { +// Moves task from source to target. +// Source and target get clamped to database size. +move_task :: (db: *Database, source: s64, target: s64) { // TODO Maybe `using db` 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]; - - if (target_task == task) return; - - // Move task to new location. - temp_task := <<task; - if target_task > task { - //memmove(task, task + 1, (target_task - task) * SIZEOF_TASK_ST); TODO Maybe simplify this moves. - offset := task - db.tasks.data; - size := target_task - task; - for 0..size-1 - db.tasks[offset + it] = db.tasks[offset + it + 1]; + + source = clamp(source, 0, db.tasks.count-1); + target = clamp(target, 0, db.tasks.count-1); + + if (source == target) return; + + // Move task to new location, but first, shift the others to allow some space. + temp_task := db.tasks[source]; + move_size := abs(target - source); + + if target > source { + for 0..move_size-1 + db.tasks[source + it] = db.tasks[source + it + 1]; } else { - //memmove(target_task + 1, target_task, (task - target_task) * SIZEOF_TASK_ST); TODO Maybe simplify this moves. - offset := target_task - db.tasks.data; - size := task - target_task; - for < size-1..0 - db.tasks[offset + it + 1] = db.tasks[offset + it]; + for < move_size-1..0 + db.tasks[target + it + 1] = db.tasks[target + it]; } - <<target_task = temp_task; + + db.tasks[target] = temp_task; // Adjust active and selected tasks. - source_index := task - db.tasks.data; - if (db.active_idx == source_index) { - db.active_idx = target_index; + if (db.active_idx == source) { + db.active_idx = target; } - else if (source_index < db.active_idx && db.active_idx <= target_index) { + else if (source < db.active_idx && db.active_idx <= target) { db.active_idx -= 1; } - else if (target_index <= db.active_idx && db.active_idx < source_index) { + else if (target <= db.active_idx && db.active_idx < source) { db.active_idx += 1; } - db.selected_idx = target_index; + db.selected_idx = target; } // Updates the times on the active task (and adjusts database totals). @@ -491,44 +485,41 @@ update_total_times :: (db: *Database) { } // Resets the times of the provided task (and adjusts database totals). -reset_task_times :: (db: *Database, task: *Task) { +reset_task_times :: (db: *Database, index: 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"); + assert(is_valid_index(db, index), ASSERT_INVALID_INDEX, index); // Make sure we sync before applying the changes. update_times(db); - for * task.times { + for * db.tasks[index].times { db.total_times[it_index] = sub_int64(db.total_times[it_index], <<it); <<it = 0; } } // Sets the time on the day and task provided (and adjusts database totals). -set_task_time :: (db: *Database, task: *Task, day: int, time: s64) { +set_task_time :: (db: *Database, index: s64, 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"); + assert(is_valid_index(db, index), ASSERT_INVALID_INDEX, index); // Make sure we sync before applying the changes. update_times(db); - db.total_times[day] = add_int64(db.total_times[day], time - task.times[day]); - task.times[day] = time; + db.total_times[day] = add_int64(db.total_times[day], time - db.tasks[index].times[day]); + db.tasks[index].times[day] = time; } // Adds the time on the day and task provided (and adjusts database totals). -add_task_time :: (db: *Database, task: *Task, day: int, time: s64) { +add_task_time :: (db: *Database, index: s64, 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"); + assert(is_valid_index(db, index), ASSERT_INVALID_INDEX, index); // Make sure we sync before applying the changes. update_times(db); db.total_times[day] = add_int64(db.total_times[day], time); - task.times[day] = add_int64(task.times[day], time); + db.tasks[index].times[day] = add_int64(db.tasks[index].times[day], time); } // Resets database to the initial state and deallocates all memory taken by tasks. @@ -790,43 +781,28 @@ 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) { +select_task :: (db: *Database, index: s64) { 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 - index; + db.selected_idx = ifx db.tasks.count == 0 then -1 else clamp(index, 0, db.tasks.count-1); } // Selects task by delta relative to currently selected task. select_task_by_delta :: (db: *Database, delta: s64) { 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 ifx (delta < 0 && db.selected_idx < S64_MIN - delta) then S64_MIN else db.selected_idx + delta; - select_task_by_index(db, idx); -} - - - -// Selects task. -select_task :: (db: *Database, task: *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"); - db.selected_idx = task - db.tasks.data; + select_task(db, idx); } // Set active task. -// Passing task as NULL de-activates any previously active task. -set_active_task :: (db: *Database, task: *Task) { +// Passing -1 de-activates any previously active task. +set_active_task :: (db: *Database, index: s64) { assert(db != null, ASSERT_NOT_NULL, "db"); - if task != null - assert(contains_task(db, task), ASSERT_NOT_CONTAIN, "db", "task"); + assert(index == -1 || is_valid_index(db, index), ASSERT_INVALID_INDEX, index); update_times(db); - db.active_idx = ifx (task == null) then -1 else task - db.tasks.data; + db.active_idx = index; } // Returns true when database is full. @@ -1377,17 +1353,23 @@ main :: () { if key == #char "q" || key == #char "Q" break; update_times(*database); timeout(INPUT_AWAIT_INF); - - active_task := get_active_task(db); + + // TODO WIP Remove `selected_task` and `active_task` and helper functions. selected_task := get_selected_task(db); - action_style := A_BOLD | COLOR_PAIR(xx ifx selected_task == active_task && selected_task != null - then Styles.ACTIVE - else Styles.SELECTED_INVERTED); - error_style := A_BOLD | COLOR_PAIR(xx Styles.ERROR); - selected_task_row : int = ifx is_terminal_too_small then 0 - else ifx (db.selected_idx < 0) then 1 - else (db.selected_idx % layout_tasks_rows) + NUM_HEADER_ROWS; - + active_task := get_active_task(db); + action_style: s32; + error_style: s32; + selected_task_row: int; + { // TODO Recheck this code. + using db; + action_style = A_BOLD | COLOR_PAIR(xx + ifx selected_idx == active_idx && selected_idx != -1 then Styles.ACTIVE + else Styles.SELECTED_INVERTED); + error_style = A_BOLD | COLOR_PAIR(xx Styles.ERROR); + selected_task_row = ifx is_terminal_too_small then 0 + else ifx (selected_idx < 0) then 1 + else (selected_idx % layout_tasks_rows) + NUM_HEADER_ROWS; + } if key == { // When getch() times out. @@ -1422,11 +1404,11 @@ main :: () { now_utc := current_time_consensus(); now_local := to_calendar(now_utc, .LOCAL); name := calendar_to_iso_string(now_local); - new_task := add_task(db); - memcpy(new_task.name.data, name.data, min(Task.name.count, name.count)); + task, index := add_task(db); + memcpy(task.name.data, name.data, min(Task.name.count, name.count)); // Select new task. - select_task(db, new_task); + select_task(db, index); selected_task = get_selected_task(db); trigger_autosave(); @@ -1449,7 +1431,7 @@ main :: () { if (selected_task == null) continue; if (read_enter_confirmation(selected_task_row, action_style, " Press enter to reset task. ") == true) { - reset_task_times(db, selected_task); + reset_task_times(db, db.selected_idx); trigger_autosave(); } @@ -1457,7 +1439,7 @@ main :: () { if (selected_task == null || selected_task == active_task) continue; if (read_enter_confirmation(selected_task_row, action_style, " Press enter to delete task. ") == true) { - delete_task(db, selected_task); + delete_task(db, db.selected_idx); trigger_autosave(); } @@ -1525,8 +1507,8 @@ main :: () { // Apply changes. 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); + if is_assign set_task_time(db, db.selected_idx, day, time); + else add_task_time(db, db.selected_idx, day, time); trigger_autosave(); @@ -1536,9 +1518,7 @@ main :: () { value, success := read_input_int(selected_task_row, action_style, " Move to: "); if success == false continue; - - target_index := clamp(value, 1, MAX_DATABASE_TASKS) - 1; - move_task_to_index(db, selected_task, target_index); + move_task(db, db.selected_idx, value-1); // -1 to adjust for zero based index trigger_autosave(); case #char "g"; #through; @@ -1547,9 +1527,8 @@ main :: () { value, success := read_input_int(selected_task_row, action_style, " Go to: "); if success == false continue; - target_index := clamp(value, 1, MAX_DATABASE_TASKS) - 1; - select_task_by_index(db, target_index); + select_task(db, target_index); case #char "d"; #through; case #char "D"; @@ -1571,12 +1550,12 @@ main :: () { case #char "t"; #through; case #char "T"; if (active_task == null) continue; - select_task(db, active_task); + select_task(db, db.active_idx); case #char "\n"; #through; case #char " "; if (db != *database || selected_task == null) continue; - set_active_task(db, ifx (active_task == selected_task) then null else selected_task); + set_active_task(db, ifx db.active_idx == db.selected_idx then -1 else db.selected_idx); active_task = get_active_task(db); trigger_autosave(); @@ -1606,7 +1585,7 @@ main :: () { print_error("Failed to archive entry."); continue; } - delete_task(*database, selected_task); + delete_task(db, db.selected_idx); trigger_autosave(); case #char "r"; #through; @@ -1622,11 +1601,11 @@ main :: () { print_error("Failed to restore entry."); continue; } - delete_task(*archive, selected_task); + delete_task(db, db.selected_idx); trigger_autosave(); case KEY_HOME; - select_task_by_index(db, 0); + select_task(db, 0); case KEY_UP; select_task_by_delta(db, -1); @@ -1635,7 +1614,7 @@ main :: () { select_task_by_delta(db, -layout_tasks_rows); case KEY_END; - select_task_by_index(db, db.tasks.count-1); + select_task(db, db.tasks.count-1); case KEY_DOWN; select_task_by_delta(db, 1); |
