Compare commits
3 commits
d0c6c94e9d
...
4ff4d24b42
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ff4d24b42 | |||
| 0a64dc525d | |||
| b925d2e89e |
3 changed files with 69 additions and 6 deletions
|
|
@ -1,6 +1,9 @@
|
|||
# 0.7.6
|
||||
|
||||
* 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
|
||||
|
||||
|
|
|
|||
|
|
@ -89,6 +89,12 @@ class MarkdownEditor(QTextEdit):
|
|||
# Track current list type for smart enter handling
|
||||
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
|
||||
self._updating = False
|
||||
|
||||
|
|
@ -919,8 +925,10 @@ class MarkdownEditor(QTextEdit):
|
|||
before = line[:pos_in_block]
|
||||
|
||||
# "before" currently contains whatever's before the *third* backtick.
|
||||
# We trigger only when the line is (whitespace + "``") before the caret.
|
||||
if before.endswith("``") and before.strip() == "``":
|
||||
# Trigger when the user types a *third consecutive* backtick anywhere on the line.
|
||||
# (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()
|
||||
if doc is not None:
|
||||
# Remove the two backticks that were already typed
|
||||
|
|
@ -1126,6 +1134,10 @@ class MarkdownEditor(QTextEdit):
|
|||
cursor = self.textCursor()
|
||||
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
|
||||
current_block = cursor.block()
|
||||
line_text = current_block.text()
|
||||
|
|
@ -1215,13 +1227,43 @@ class MarkdownEditor(QTextEdit):
|
|||
# Insert newline and continue the list
|
||||
super().keyPressEvent(event)
|
||||
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
|
||||
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_indent = False
|
||||
else:
|
||||
# Any other key resets the empty enter flag
|
||||
self._last_enter_was_empty = False
|
||||
self._last_enter_was_empty_indent = False
|
||||
|
||||
# Default handling
|
||||
super().keyPressEvent(event)
|
||||
|
|
|
|||
|
|
@ -111,6 +111,25 @@ class PomodoroManager:
|
|||
self._parent = parent_window
|
||||
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):
|
||||
"""
|
||||
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):
|
||||
"""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)
|
||||
quarter_hours = math.ceil(elapsed_seconds / 900)
|
||||
hours = quarter_hours * 0.25
|
||||
# Convert seconds to decimal hours, and handle rounding up or down
|
||||
hours = self._seconds_to_logged_hours(elapsed_seconds)
|
||||
|
||||
# Ensure minimum of 0.25 hours
|
||||
if hours < 0.25:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue