Allow deleting code blocks
Some checks failed
CI / test (push) Failing after 5m30s
Lint / test (push) Successful in 33s
Trivy / test (push) Successful in 24s

This commit is contained in:
Miguel Jacq 2025-11-29 10:41:18 +11:00
parent 57f11abb99
commit dc1046632c
Signed by: mig5
GPG key ID: 59B3F0C24135C6A9
4 changed files with 90 additions and 3 deletions

View file

@ -13,7 +13,9 @@ from . import strings
class CodeBlockEditorDialog(QDialog):
def __init__(self, code: str, language: str | None, parent=None):
def __init__(
self, code: str, language: str | None, parent=None, allow_delete: bool = False
):
super().__init__(parent)
self.setWindowTitle(strings._("edit_code_block"))
@ -21,6 +23,9 @@ class CodeBlockEditorDialog(QDialog):
self._code_edit = QPlainTextEdit(self)
self._code_edit.setPlainText(code)
# Track whether the user clicked "Delete"
self._delete_requested = False
# Language selector (optional)
self._lang_combo = QComboBox(self)
languages = [
@ -44,12 +49,28 @@ class CodeBlockEditorDialog(QDialog):
buttons.accepted.connect(self.accept)
buttons.rejected.connect(self.reject)
if allow_delete:
delete_btn = buttons.addButton(
strings._("delete_code_block"),
QDialogButtonBox.ButtonRole.DestructiveRole,
)
delete_btn.clicked.connect(self._on_delete_clicked)
layout = QVBoxLayout(self)
layout.addWidget(QLabel(strings._("locale") + ":", self))
layout.addWidget(self._lang_combo)
layout.addWidget(self._code_edit)
layout.addWidget(buttons)
def _on_delete_clicked(self) -> None:
"""Mark this dialog as 'delete requested' and close as Accepted."""
self._delete_requested = True
self.accept()
def was_deleted(self) -> bool:
"""Return True if the user chose to delete the code block."""
return self._delete_requested
def code(self) -> str:
return self._code_edit.toPlainText()

View file

@ -365,3 +365,7 @@ class CodeBlockMetadata:
self._block_languages[int(block_num)] = lang
except ValueError:
pass
def clear_language(self, block_number: int):
"""Remove any stored language for a given block, if present."""
self._block_languages.pop(block_number, None)

View file

@ -290,5 +290,6 @@
"saturday": "Saturday",
"sunday": "Sunday",
"day": "Day",
"edit_code_block": "Edit code block"
"edit_code_block": "Edit code block",
"delete_code_block": "Delete code block"
}

View file

@ -372,12 +372,17 @@ class MarkdownEditor(QTextEdit):
code_text = self._get_code_block_text(open_block, close_block)
dlg = CodeBlockEditorDialog(code_text, lang, parent=self)
dlg = CodeBlockEditorDialog(code_text, lang, parent=self, allow_delete=True)
result = dlg.exec()
if result != QDialog.DialogCode.Accepted:
# Dialog was shown but user cancelled; event is "handled".
return True
# If the user requested deletion, remove the whole block
if hasattr(dlg, "was_deleted") and dlg.was_deleted():
self._delete_code_block(open_block)
return True
new_code = dlg.code()
new_lang = dlg.language()
@ -396,6 +401,58 @@ class MarkdownEditor(QTextEdit):
return True
def _delete_code_block(self, block: QTextBlock) -> bool:
"""Delete the fenced code block containing `block`.
Returns True if a block was deleted, False otherwise.
"""
bounds = self._find_code_block_bounds(block)
if not bounds:
return False
open_block, close_block = bounds
doc = self.document()
if doc is None:
return False
# Remove from the opening fence down to just before the block after
# the closing fence (so we also remove the trailing blank line).
start_pos = open_block.position()
after_block = close_block.next()
if after_block.isValid():
end_pos = after_block.position()
else:
end_pos = close_block.position() + len(close_block.text())
cursor = QTextCursor(doc)
cursor.beginEditBlock()
cursor.setPosition(start_pos)
cursor.setPosition(end_pos, QTextCursor.MoveMode.KeepAnchor)
cursor.removeSelectedText()
cursor.endEditBlock()
# Clear language metadata for this block, if supported
if hasattr(self, "_code_metadata"):
clear = getattr(self._code_metadata, "clear_language", None)
if clear is not None:
clear(open_block.blockNumber())
# Refresh visuals (spacing + backgrounds + syntax)
if hasattr(self, "_apply_code_block_spacing"):
self._apply_code_block_spacing()
if hasattr(self, "_update_code_block_row_backgrounds"):
self._update_code_block_row_backgrounds()
if hasattr(self, "highlighter"):
self.highlighter.rehighlight()
# Move caret to where the block used to be
cursor = self.textCursor()
cursor.setPosition(start_pos)
self.setTextCursor(cursor)
self.setFocus()
return True
def _apply_line_spacing(self, height: float = 125.0):
"""Apply proportional line spacing to the whole document."""
doc = self.document()
@ -1619,6 +1676,10 @@ class MarkdownEditor(QTextEdit):
edit_action.triggered.connect(lambda: self._edit_code_block(block))
menu.addAction(edit_action)
delete_action = QAction(strings._("delete_code_block"), self)
delete_action.triggered.connect(lambda: self._delete_code_block(block))
menu.addAction(delete_action)
menu.addSeparator()
# Add standard context menu actions