Compare commits

...

3 commits

3 changed files with 69 additions and 6 deletions

View file

@ -1,6 +1,9 @@
# 0.7.6 # 0.7.6
* Add .desktop file for Debian * Add .desktop file for Debian
* Fix Pomodoro timer rounding so it rounds up to 0.25, but rounds to closest quarter (up or down) for minutes higher than that, instead of always up to next quarter.
* Allow setting a code block on a line that already has text (it will start a newline for the codeblock)
* Retain indentation when tab is used to indent a line, unless enter is pressed twice or user deletes the indentation
# 0.7.5 # 0.7.5

View file

@ -89,6 +89,12 @@ class MarkdownEditor(QTextEdit):
# Track current list type for smart enter handling # Track current list type for smart enter handling
self._last_enter_was_empty = False self._last_enter_was_empty = False
# Track "double-enter" behavior for indentation retention.
# If we auto-insert indentation on a new line, the next Enter on that
# now-empty indented line should remove the indentation and return to
# column 0 (similar to how lists exit on a second Enter).
self._last_enter_was_empty_indent = False
# Track if we're currently updating text programmatically # Track if we're currently updating text programmatically
self._updating = False self._updating = False
@ -919,8 +925,10 @@ class MarkdownEditor(QTextEdit):
before = line[:pos_in_block] before = line[:pos_in_block]
# "before" currently contains whatever's before the *third* backtick. # "before" currently contains whatever's before the *third* backtick.
# We trigger only when the line is (whitespace + "``") before the caret. # Trigger when the user types a *third consecutive* backtick anywhere on the line.
if before.endswith("``") and before.strip() == "``": # (We require the run immediately before the caret to be exactly two backticks,
# so we don't trigger on 4+ backticks.)
if before.endswith("``") and (len(before) < 3 or before[-3] != "`"):
doc = self.document() doc = self.document()
if doc is not None: if doc is not None:
# Remove the two backticks that were already typed # Remove the two backticks that were already typed
@ -1126,6 +1134,10 @@ class MarkdownEditor(QTextEdit):
cursor = self.textCursor() cursor = self.textCursor()
current_line = self._get_current_line() current_line = self._get_current_line()
# Leading indentation (tabs/spaces) on the current line.
m_indent = re.match(r"^([ \t]*)", current_line)
line_indent = m_indent.group(1) if m_indent else ""
# Check if we're in a code block # Check if we're in a code block
current_block = cursor.block() current_block = cursor.block()
line_text = current_block.text() line_text = current_block.text()
@ -1215,13 +1227,43 @@ class MarkdownEditor(QTextEdit):
# Insert newline and continue the list # Insert newline and continue the list
super().keyPressEvent(event) super().keyPressEvent(event)
cursor = self.textCursor() cursor = self.textCursor()
cursor.insertText(prefix) # Preserve any leading indentation so nested lists keep their level.
cursor.insertText(line_indent + prefix)
self._last_enter_was_empty_indent = False
return return
else: else:
# Not a list: support indentation retention. If a line starts
# with indentation (tabs/spaces), carry that indentation to the
# next line. A *second* Enter on an empty indented line resets
# back to column 0.
if line_indent:
rest = current_line[len(line_indent) :]
indent_only = rest.strip() == ""
if indent_only and self._last_enter_was_empty_indent:
# Second Enter on an empty indented line: remove the
# indentation-only line and start a fresh, unindented line.
cursor.select(QTextCursor.SelectionType.LineUnderCursor)
cursor.removeSelectedText()
cursor.insertText("\n")
self._last_enter_was_empty_indent = False
self._last_enter_was_empty = False
return
# First Enter (or a non-empty indented line): keep the indent.
super().keyPressEvent(event)
cursor = self.textCursor()
cursor.insertText(line_indent)
self._last_enter_was_empty_indent = True
self._last_enter_was_empty = False
return
self._last_enter_was_empty = False self._last_enter_was_empty = False
self._last_enter_was_empty_indent = False
else: else:
# Any other key resets the empty enter flag # Any other key resets the empty enter flag
self._last_enter_was_empty = False self._last_enter_was_empty = False
self._last_enter_was_empty_indent = False
# Default handling # Default handling
super().keyPressEvent(event) super().keyPressEvent(event)

View file

@ -111,6 +111,25 @@ class PomodoroManager:
self._parent = parent_window self._parent = parent_window
self._active_timer: Optional[PomodoroTimer] = None self._active_timer: Optional[PomodoroTimer] = None
@staticmethod
def _seconds_to_logged_hours(elapsed_seconds: int) -> float:
"""Convert elapsed seconds to decimal hours for logging.
Rules:
- For very short runs (< 15 minutes), always round up to 0.25h (15 minutes).
- Otherwise, round to the closest 0.25h (15-minute) increment.
Halfway cases (e.g., 22.5 minutes) round up.
"""
if elapsed_seconds < 0:
elapsed_seconds = 0
# 15 minutes = 900 seconds
if elapsed_seconds < 900:
return 0.25
quarters = int(math.floor((elapsed_seconds / 900.0) + 0.5))
return quarters * 0.25
def start_timer_for_line(self, line_text: str, date_iso: str): def start_timer_for_line(self, line_text: str, date_iso: str):
""" """
Start a new timer for the given line of text and embed it into the Start a new timer for the given line of text and embed it into the
@ -156,9 +175,8 @@ class PomodoroManager:
def _on_timer_stopped(self, elapsed_seconds: int, task_text: str, date_iso: str): def _on_timer_stopped(self, elapsed_seconds: int, task_text: str, date_iso: str):
"""Handle timer stop - open time log dialog with pre-filled data.""" """Handle timer stop - open time log dialog with pre-filled data."""
# Convert seconds to decimal hours, rounding up to the nearest 0.25 hour (15 minutes) # Convert seconds to decimal hours, and handle rounding up or down
quarter_hours = math.ceil(elapsed_seconds / 900) hours = self._seconds_to_logged_hours(elapsed_seconds)
hours = quarter_hours * 0.25
# Ensure minimum of 0.25 hours # Ensure minimum of 0.25 hours
if hours < 0.25: if hours < 0.25: