From 1bd589e3ac7ce62122ba9b9bb0fbbf9d8a44bf3f Mon Sep 17 00:00:00 2001 From: James Turk Date: Sun, 5 Jan 2025 01:49:46 -0600 Subject: [PATCH] from editor --- src/tt/controller.py | 4 ++++ src/tt/tui.py | 48 ++++++++++++++++++++++++++++---------------- src/tt/utils.py | 21 +++++++++++++++++++ 3 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/tt/controller.py b/src/tt/controller.py index f1bfb93..500796c 100644 --- a/src/tt/controller.py +++ b/src/tt/controller.py @@ -12,6 +12,10 @@ def category_lookup(category): return category.id +def get_task(task_id: int) -> Task: + return Task.get_by_id(task_id) + + def add_task( text: str, category: str, diff --git a/src/tt/tui.py b/src/tt/tui.py index a06d1a2..6eba192 100644 --- a/src/tt/tui.py +++ b/src/tt/tui.py @@ -12,6 +12,7 @@ from textual.containers import Container from datetime import datetime from .controller import ( + get_task, get_tasks, add_task, update_task, @@ -27,6 +28,7 @@ from .utils import ( get_colored_category, get_colored_status, get_colored_date, + get_text_from_editor, ) DEFAULT_CATEGORY = "main" @@ -102,7 +104,8 @@ class TT(App): ("s", "start_sort", "sort tasks"), ("escape", "cancel_edit", "Cancel Edit"), # edits - ("c", "start_edit", "edit current cell"), + ("c", "start_change", "change current cell"), + ("e", "start_edit", "open cell in editor"), ("a", "add_task", "add task"), ("t", "toggle_cell", "toggle status"), ("d", "delete_task", "delete (must be on row mode)"), @@ -203,7 +206,7 @@ class TT(App): self.table.add_row( str(task.id), - task.text, + task.text.split("\n")[0], # first line status, task.type, due, @@ -245,7 +248,7 @@ class TT(App): ) self.refresh_tasks(restore_cursor=False) self.move_cursor_to_task(new_task.id) - self.action_start_edit() + self.action_start_change() def action_toggle_cell(self): cur_row = self.table.cursor_row @@ -289,20 +292,11 @@ class TT(App): self.mode = mode self.input_bar.display = True self.input_widget.value = start_value - if mode == "search": - self.input_label.update("search: ") - elif mode == "edit": - self.input_label.update("edit: ") - elif mode == "sort": - self.input_label.update("sort: ") - elif mode == "filter": - self.input_label.update("filter: ") - elif mode == "save-view": - self.input_label.update("view name: ") - elif mode == "load-view": - self.input_label.update("view name: ") + if mode.endswith("-view"): + mode_input_label = "view name: " else: - raise ValueError(f"unknown mode: {mode}") + mode_input_label = f"{mode}: " + self.input_label.update(mode_input_label) self.set_focus(self.input_widget) def _hide_input(self): @@ -339,7 +333,7 @@ class TT(App): def _save_cursor(self): self.saved_cursor_pos = (self.table.cursor_row, self.table.cursor_column) - def action_start_edit(self): + def action_start_change(self): if self.table.cursor_row is None or self.table.cursor_column == 0: return @@ -350,6 +344,26 @@ class TT(App): current_value = remove_rich_tag(current_value) self._show_input("edit", current_value) + def action_start_edit(self): + cur_col = self.table.cursor_column + + if self.table.cursor_row is None or cur_col != 1: + return + + self._save_cursor() + task_id = self.table.get_cell_at((self.table.cursor_row, 0)) + # get task from db so we can see 100% of the text + task = get_task(task_id) + + # found at https://github.com/Textualize/textual/discussions/1654 + self._driver.stop_application_mode() + new_text = get_text_from_editor(task.text) + self.refresh() + self._driver.start_application_mode() + if new_text is not None: + update_task(task_id, text=new_text) + self.refresh_tasks() + def on_input_submitted(self, event: Input.Submitted): if self.mode == "search": self.search_query = event.value diff --git a/src/tt/utils.py b/src/tt/utils.py index 9522995..b417c57 100644 --- a/src/tt/utils.py +++ b/src/tt/utils.py @@ -1,5 +1,8 @@ import re +import os import datetime +import tempfile +import subprocess def filter_to_string(filters, search_query): @@ -74,3 +77,21 @@ def get_colored_date(date: datetime.date) -> str: color_index = weeks color = colors[color_index] return f"[{color}]{as_str}[/]" + + +def get_text_from_editor(initial_text: str = "") -> str | None: + editor = os.environ.get("EDITOR", "vim") + + with tempfile.NamedTemporaryFile(suffix=".txt", mode="w+", delete=True) as tf: + tf.write(initial_text) + tf.flush() + + initial_mtime = os.path.getmtime(tf.name) + subprocess.call([editor, tf.name]) + + if os.path.getmtime(tf.name) == initial_mtime: + return None + + with open(tf.name, "r") as f: # Open fresh to get new content + edited_text = f.read() + return edited_text