vibefpmgui.edit_cards
The edits the AI proposes, one card each, in the Review panel: a diff of the change (made from the file, so it's right whatever the model wrote) with Accept and Reject, and Accept All / Reject All below them.
The cards only show vibefpmgui.ai_edits.Edit objects and say what the
user chose; vibefpmgui.window.ai_chat changes the editor's text.
1"""The edits the AI proposes, one card each, in the Review panel: a diff 2of the change (made from the file, so it's right whatever the model wrote) 3with Accept and Reject, and Accept All / Reject All below them. 4 5The cards only show `vibefpmgui.ai_edits.Edit` objects and say what the 6user chose; `vibefpmgui.window.ai_chat` changes the editor's text. 7""" 8 9from __future__ import annotations 10 11import difflib 12import html 13 14from qtpy.QtCore import Qt, Signal 15from qtpy.QtWidgets import ( 16 QFrame, 17 QHBoxLayout, 18 QLabel, 19 QPushButton, 20 QScrollArea, 21 QVBoxLayout, 22 QWidget, 23) 24 25from . import ai_edits as ed 26 27CONTEXT_LINES = 2 # unchanged lines shown around a change 28DIFF_COLORS = { # (background, text) of removed and added lines 29 "light": {"-": ("#ffebe9", "#82071e"), "+": ("#dafbe1", "#116329")}, 30 "dark": {"-": ("#3d1d20", "#ffa198"), "+": ("#12261e", "#7ee787")}, 31} 32 33 34def diff_rows(file_text: str, edit: ed.Edit) -> list[tuple[str, str]]: 35 """The change as (" " | "-" | "+", line) rows, with a few unchanged lines 36 around it; for an edit that wasn't found, the model's own text.""" 37 if edit.diff is not None: # (made or turned down: as it was then) 38 return edit.diff 39 if not edit.located: 40 return ([("-", line) for line in edit.search.split("\n")] 41 + [("+", line) for line in edit.replace.split("\n")]) 42 old = file_text.split("\n") 43 new = ed.apply(file_text, edit).split("\n") 44 first = max(0, edit.line - 1 - CONTEXT_LINES) 45 grown = edit.new_text.count("\n") - file_text.count("\n", edit.start, edit.end) 46 last_old = min(len(old), edit.end_line + CONTEXT_LINES) 47 last_new = min(len(new), last_old + grown) 48 rows = [] 49 for line in difflib.ndiff(old[first:last_old], new[first:last_new]): 50 if line[:1] in " -+": 51 rows.append((line[0], line[2:])) 52 return rows 53 54 55class EditCard(QFrame): 56 """One proposed edit.""" 57 58 accept = Signal() 59 reject = Signal() 60 clicked = Signal() 61 62 def __init__(self, parent=None): 63 super().__init__(parent) 64 self.setObjectName("EditCard") 65 self.setCursor(Qt.PointingHandCursor) 66 self.title = QLabel() 67 self.state = QLabel() 68 self.accept_button = QPushButton("Accept") 69 self.accept_button.clicked.connect(self.accept) 70 self.reject_button = QPushButton("Reject") 71 self.reject_button.clicked.connect(self.reject) 72 self.show_button = QPushButton("Show") 73 self.show_button.setCheckable(True) 74 self.show_button.setToolTip("The block as the model wrote it") 75 self.show_button.toggled.connect(lambda on: self.diff.setVisible(on)) 76 header = QHBoxLayout() 77 header.setSpacing(8) 78 header.addWidget(self.title) 79 header.addStretch(1) 80 header.addWidget(self.state) 81 header.addWidget(self.show_button) 82 header.addWidget(self.reject_button) 83 header.addWidget(self.accept_button) 84 self.diff = QLabel() 85 self.diff.setTextFormat(Qt.RichText) 86 self.diff.setTextInteractionFlags(Qt.TextSelectableByMouse) 87 layout = QVBoxLayout(self) 88 layout.setContentsMargins(10, 8, 10, 8) 89 layout.setSpacing(6) 90 layout.addLayout(header) 91 layout.addWidget(self.diff) 92 93 def mousePressEvent(self, event): 94 if event.button() == Qt.LeftButton: 95 self.clicked.emit() 96 super().mousePressEvent(event) 97 98 def show_edit(self, number: int, edit: ed.Edit, file_text: str, name: str, colors: dict, 99 muted: str, font_family: str): 100 where = (f"line {edit.line}" if edit.line == edit.end_line else f"lines {edit.line}–{edit.end_line}") \ 101 if edit.located else "not applied" 102 note = {"spacing": "spacing ignored", "indentation": "indentation adjusted", 103 "line numbers": "line numbers taken out"}.get(edit.how, "") 104 extra = f" <span style='color:{muted}'>· {note}</span>" if note else "" 105 self.title.setText(f"<b>{number}.</b> {html.escape(name)} · {where}{extra}") 106 pending = edit.status == ed.PENDING and edit.located 107 self.accept_button.setVisible(pending) 108 self.reject_button.setVisible(pending) 109 self.show_button.setVisible(edit.status == ed.FAILED) 110 state = {ed.APPLIED: "✓ applied", ed.REJECTED: "rejected", 111 ed.STALE: "⚠ the code changed since: not applied", 112 ed.FAILED: f"⚠ {edit.problem}"}.get(edit.status, "") 113 self.state.setText(f"<span style='color:{muted}'>{html.escape(state)}</span>" if state else "") 114 rows = [] 115 for kind, line in diff_rows(file_text, edit): 116 text = html.escape(line) or " " 117 if kind == " ": 118 rows.append(f"<div style='color:{muted}'> {text}</div>") 119 else: 120 background, color = colors[kind] 121 rows.append(f"<div style='background:{background}; color:{color}'>{kind} {text}</div>") 122 self.diff.setText(f"<div style='font-family:\"{font_family}\"; white-space:pre'>{''.join(rows)}</div>") 123 self.diff.setVisible(edit.status != ed.FAILED or self.show_button.isChecked()) 124 self.setEnabled(True) 125 dim = edit.status in (ed.REJECTED, ed.STALE) 126 self.diff.setStyleSheet("color: gray;" if dim else "") 127 128 129class EditList(QWidget): 130 """The cards, and Accept All / Reject All (with ``scrolling`` False, as 131 tall as the cards: in something that scrolls itself).""" 132 133 accept_requested = Signal(int) 134 reject_requested = Signal(int) 135 accept_all_requested = Signal() 136 reject_all_requested = Signal() 137 edit_clicked = Signal(int) 138 139 def __init__(self, parent=None, scrolling: bool = True): 140 super().__init__(parent) 141 self.cards: list[EditCard] = [] 142 self.is_light = True 143 self.muted = "#8b949e" 144 self.font_family = "Menlo" 145 self.container = QWidget() 146 self.container.setObjectName("EditCards") 147 self.cards_layout = QVBoxLayout(self.container) 148 self.cards_layout.setContentsMargins(0, 0, 0, 0) 149 self.cards_layout.setSpacing(6) 150 if scrolling: 151 self.cards_layout.addStretch(1) 152 self.scroll = QScrollArea() 153 self.scroll.setWidgetResizable(True) 154 self.scroll.setFrameShape(QFrame.NoFrame) 155 self.scroll.setWidget(self.container) 156 self.summary = QLabel() 157 self.accept_all = QPushButton("Accept All") 158 self.accept_all.setToolTip("Make every pending edit (one step to undo)") 159 self.accept_all.clicked.connect(self.accept_all_requested) 160 self.reject_all = QPushButton("Reject All") 161 self.reject_all.clicked.connect(self.reject_all_requested) 162 footer = QHBoxLayout() 163 footer.addWidget(self.summary, 1) 164 footer.addWidget(self.reject_all) 165 footer.addWidget(self.accept_all) 166 layout = QVBoxLayout(self) 167 layout.setContentsMargins(0, 0, 0, 0) 168 layout.setSpacing(6) 169 layout.addWidget(self.scroll if scrolling else self.container, 1) 170 layout.addLayout(footer) 171 172 def set_palette(self, pal: dict, is_light: bool): 173 self.is_light = is_light 174 self.muted = pal["muted"] 175 self.setStyleSheet(f"#EditCard {{ border: 1px solid {pal['line']}; border-radius: 6px; " 176 f"background: {pal['bg']}; }}" 177 f"QScrollArea, #EditCards {{ background: {pal['bg']}; border: none; }}") 178 179 def show_edits(self, edits: list[ed.Edit], file_text: str, name: str, font_family: str): 180 """Show ``edits`` (located in ``file_text``, the editor's text).""" 181 self.font_family = font_family 182 while len(self.cards) < len(edits): 183 card = EditCard() 184 i = len(self.cards) 185 card.accept.connect(lambda i=i: self.accept_requested.emit(i)) 186 card.reject.connect(lambda i=i: self.reject_requested.emit(i)) 187 card.clicked.connect(lambda i=i: self.edit_clicked.emit(i)) 188 self.cards_layout.insertWidget(len(self.cards), card) 189 self.cards.append(card) 190 while len(self.cards) > len(edits): 191 self.cards.pop().deleteLater() 192 colors = DIFF_COLORS["light" if self.is_light else "dark"] 193 for i, (card, edit) in enumerate(zip(self.cards, edits, strict=True)): 194 card.show_edit(i + 1, edit, file_text, name, colors, self.muted, font_family) 195 pending = sum(e.status == ed.PENDING and e.located for e in edits) 196 counts = {s: sum(e.status == s for e in edits) for s in (ed.APPLIED, ed.REJECTED, ed.FAILED, ed.STALE)} 197 parts = [f"{len(edits)} edit{'s' * (len(edits) != 1)} proposed"] 198 parts += [f"{n} {word}" for word, n in (("applied", counts[ed.APPLIED]), ("rejected", counts[ed.REJECTED]), 199 ("not found", counts[ed.FAILED]), ("out of date", counts[ed.STALE])) 200 if n] 201 self.summary.setText(f"<span style='color:{self.muted}'>{' · '.join(parts)}</span>") 202 self.accept_all.setEnabled(pending > 0) 203 self.accept_all.setText(f"Accept All ({pending})" if pending else "Accept All") 204 self.reject_all.setEnabled(pending > 0) 205 self.setVisible(bool(edits))
35def diff_rows(file_text: str, edit: ed.Edit) -> list[tuple[str, str]]: 36 """The change as (" " | "-" | "+", line) rows, with a few unchanged lines 37 around it; for an edit that wasn't found, the model's own text.""" 38 if edit.diff is not None: # (made or turned down: as it was then) 39 return edit.diff 40 if not edit.located: 41 return ([("-", line) for line in edit.search.split("\n")] 42 + [("+", line) for line in edit.replace.split("\n")]) 43 old = file_text.split("\n") 44 new = ed.apply(file_text, edit).split("\n") 45 first = max(0, edit.line - 1 - CONTEXT_LINES) 46 grown = edit.new_text.count("\n") - file_text.count("\n", edit.start, edit.end) 47 last_old = min(len(old), edit.end_line + CONTEXT_LINES) 48 last_new = min(len(new), last_old + grown) 49 rows = [] 50 for line in difflib.ndiff(old[first:last_old], new[first:last_new]): 51 if line[:1] in " -+": 52 rows.append((line[0], line[2:])) 53 return rows
The change as (" " | "-" | "+", line) rows, with a few unchanged lines around it; for an edit that wasn't found, the model's own text.
56class EditCard(QFrame): 57 """One proposed edit.""" 58 59 accept = Signal() 60 reject = Signal() 61 clicked = Signal() 62 63 def __init__(self, parent=None): 64 super().__init__(parent) 65 self.setObjectName("EditCard") 66 self.setCursor(Qt.PointingHandCursor) 67 self.title = QLabel() 68 self.state = QLabel() 69 self.accept_button = QPushButton("Accept") 70 self.accept_button.clicked.connect(self.accept) 71 self.reject_button = QPushButton("Reject") 72 self.reject_button.clicked.connect(self.reject) 73 self.show_button = QPushButton("Show") 74 self.show_button.setCheckable(True) 75 self.show_button.setToolTip("The block as the model wrote it") 76 self.show_button.toggled.connect(lambda on: self.diff.setVisible(on)) 77 header = QHBoxLayout() 78 header.setSpacing(8) 79 header.addWidget(self.title) 80 header.addStretch(1) 81 header.addWidget(self.state) 82 header.addWidget(self.show_button) 83 header.addWidget(self.reject_button) 84 header.addWidget(self.accept_button) 85 self.diff = QLabel() 86 self.diff.setTextFormat(Qt.RichText) 87 self.diff.setTextInteractionFlags(Qt.TextSelectableByMouse) 88 layout = QVBoxLayout(self) 89 layout.setContentsMargins(10, 8, 10, 8) 90 layout.setSpacing(6) 91 layout.addLayout(header) 92 layout.addWidget(self.diff) 93 94 def mousePressEvent(self, event): 95 if event.button() == Qt.LeftButton: 96 self.clicked.emit() 97 super().mousePressEvent(event) 98 99 def show_edit(self, number: int, edit: ed.Edit, file_text: str, name: str, colors: dict, 100 muted: str, font_family: str): 101 where = (f"line {edit.line}" if edit.line == edit.end_line else f"lines {edit.line}–{edit.end_line}") \ 102 if edit.located else "not applied" 103 note = {"spacing": "spacing ignored", "indentation": "indentation adjusted", 104 "line numbers": "line numbers taken out"}.get(edit.how, "") 105 extra = f" <span style='color:{muted}'>· {note}</span>" if note else "" 106 self.title.setText(f"<b>{number}.</b> {html.escape(name)} · {where}{extra}") 107 pending = edit.status == ed.PENDING and edit.located 108 self.accept_button.setVisible(pending) 109 self.reject_button.setVisible(pending) 110 self.show_button.setVisible(edit.status == ed.FAILED) 111 state = {ed.APPLIED: "✓ applied", ed.REJECTED: "rejected", 112 ed.STALE: "⚠ the code changed since: not applied", 113 ed.FAILED: f"⚠ {edit.problem}"}.get(edit.status, "") 114 self.state.setText(f"<span style='color:{muted}'>{html.escape(state)}</span>" if state else "") 115 rows = [] 116 for kind, line in diff_rows(file_text, edit): 117 text = html.escape(line) or " " 118 if kind == " ": 119 rows.append(f"<div style='color:{muted}'> {text}</div>") 120 else: 121 background, color = colors[kind] 122 rows.append(f"<div style='background:{background}; color:{color}'>{kind} {text}</div>") 123 self.diff.setText(f"<div style='font-family:\"{font_family}\"; white-space:pre'>{''.join(rows)}</div>") 124 self.diff.setVisible(edit.status != ed.FAILED or self.show_button.isChecked()) 125 self.setEnabled(True) 126 dim = edit.status in (ed.REJECTED, ed.STALE) 127 self.diff.setStyleSheet("color: gray;" if dim else "")
One proposed edit.
63 def __init__(self, parent=None): 64 super().__init__(parent) 65 self.setObjectName("EditCard") 66 self.setCursor(Qt.PointingHandCursor) 67 self.title = QLabel() 68 self.state = QLabel() 69 self.accept_button = QPushButton("Accept") 70 self.accept_button.clicked.connect(self.accept) 71 self.reject_button = QPushButton("Reject") 72 self.reject_button.clicked.connect(self.reject) 73 self.show_button = QPushButton("Show") 74 self.show_button.setCheckable(True) 75 self.show_button.setToolTip("The block as the model wrote it") 76 self.show_button.toggled.connect(lambda on: self.diff.setVisible(on)) 77 header = QHBoxLayout() 78 header.setSpacing(8) 79 header.addWidget(self.title) 80 header.addStretch(1) 81 header.addWidget(self.state) 82 header.addWidget(self.show_button) 83 header.addWidget(self.reject_button) 84 header.addWidget(self.accept_button) 85 self.diff = QLabel() 86 self.diff.setTextFormat(Qt.RichText) 87 self.diff.setTextInteractionFlags(Qt.TextSelectableByMouse) 88 layout = QVBoxLayout(self) 89 layout.setContentsMargins(10, 8, 10, 8) 90 layout.setSpacing(6) 91 layout.addLayout(header) 92 layout.addWidget(self.diff)
__init__(self, /, parent: PySide6.QtWidgets.QWidget | None = None, f: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags), *, frameShape: PySide6.QtWidgets.QFrame.Shape | None = None, frameShadow: PySide6.QtWidgets.QFrame.Shadow | None = None, lineWidth: int | None = None, midLineWidth: int | None = None, frameWidth: int | None = None, frameRect: PySide6.QtCore.QRect | None = None) -> None
Initialize self. See help(type(self)) for accurate signature.
94 def mousePressEvent(self, event): 95 if event.button() == Qt.LeftButton: 96 self.clicked.emit() 97 super().mousePressEvent(event)
mousePressEvent(self, event: PySide6.QtGui.QMouseEvent, /) -> None
99 def show_edit(self, number: int, edit: ed.Edit, file_text: str, name: str, colors: dict, 100 muted: str, font_family: str): 101 where = (f"line {edit.line}" if edit.line == edit.end_line else f"lines {edit.line}–{edit.end_line}") \ 102 if edit.located else "not applied" 103 note = {"spacing": "spacing ignored", "indentation": "indentation adjusted", 104 "line numbers": "line numbers taken out"}.get(edit.how, "") 105 extra = f" <span style='color:{muted}'>· {note}</span>" if note else "" 106 self.title.setText(f"<b>{number}.</b> {html.escape(name)} · {where}{extra}") 107 pending = edit.status == ed.PENDING and edit.located 108 self.accept_button.setVisible(pending) 109 self.reject_button.setVisible(pending) 110 self.show_button.setVisible(edit.status == ed.FAILED) 111 state = {ed.APPLIED: "✓ applied", ed.REJECTED: "rejected", 112 ed.STALE: "⚠ the code changed since: not applied", 113 ed.FAILED: f"⚠ {edit.problem}"}.get(edit.status, "") 114 self.state.setText(f"<span style='color:{muted}'>{html.escape(state)}</span>" if state else "") 115 rows = [] 116 for kind, line in diff_rows(file_text, edit): 117 text = html.escape(line) or " " 118 if kind == " ": 119 rows.append(f"<div style='color:{muted}'> {text}</div>") 120 else: 121 background, color = colors[kind] 122 rows.append(f"<div style='background:{background}; color:{color}'>{kind} {text}</div>") 123 self.diff.setText(f"<div style='font-family:\"{font_family}\"; white-space:pre'>{''.join(rows)}</div>") 124 self.diff.setVisible(edit.status != ed.FAILED or self.show_button.isChecked()) 125 self.setEnabled(True) 126 dim = edit.status in (ed.REJECTED, ed.STALE) 127 self.diff.setStyleSheet("color: gray;" if dim else "")
130class EditList(QWidget): 131 """The cards, and Accept All / Reject All (with ``scrolling`` False, as 132 tall as the cards: in something that scrolls itself).""" 133 134 accept_requested = Signal(int) 135 reject_requested = Signal(int) 136 accept_all_requested = Signal() 137 reject_all_requested = Signal() 138 edit_clicked = Signal(int) 139 140 def __init__(self, parent=None, scrolling: bool = True): 141 super().__init__(parent) 142 self.cards: list[EditCard] = [] 143 self.is_light = True 144 self.muted = "#8b949e" 145 self.font_family = "Menlo" 146 self.container = QWidget() 147 self.container.setObjectName("EditCards") 148 self.cards_layout = QVBoxLayout(self.container) 149 self.cards_layout.setContentsMargins(0, 0, 0, 0) 150 self.cards_layout.setSpacing(6) 151 if scrolling: 152 self.cards_layout.addStretch(1) 153 self.scroll = QScrollArea() 154 self.scroll.setWidgetResizable(True) 155 self.scroll.setFrameShape(QFrame.NoFrame) 156 self.scroll.setWidget(self.container) 157 self.summary = QLabel() 158 self.accept_all = QPushButton("Accept All") 159 self.accept_all.setToolTip("Make every pending edit (one step to undo)") 160 self.accept_all.clicked.connect(self.accept_all_requested) 161 self.reject_all = QPushButton("Reject All") 162 self.reject_all.clicked.connect(self.reject_all_requested) 163 footer = QHBoxLayout() 164 footer.addWidget(self.summary, 1) 165 footer.addWidget(self.reject_all) 166 footer.addWidget(self.accept_all) 167 layout = QVBoxLayout(self) 168 layout.setContentsMargins(0, 0, 0, 0) 169 layout.setSpacing(6) 170 layout.addWidget(self.scroll if scrolling else self.container, 1) 171 layout.addLayout(footer) 172 173 def set_palette(self, pal: dict, is_light: bool): 174 self.is_light = is_light 175 self.muted = pal["muted"] 176 self.setStyleSheet(f"#EditCard {{ border: 1px solid {pal['line']}; border-radius: 6px; " 177 f"background: {pal['bg']}; }}" 178 f"QScrollArea, #EditCards {{ background: {pal['bg']}; border: none; }}") 179 180 def show_edits(self, edits: list[ed.Edit], file_text: str, name: str, font_family: str): 181 """Show ``edits`` (located in ``file_text``, the editor's text).""" 182 self.font_family = font_family 183 while len(self.cards) < len(edits): 184 card = EditCard() 185 i = len(self.cards) 186 card.accept.connect(lambda i=i: self.accept_requested.emit(i)) 187 card.reject.connect(lambda i=i: self.reject_requested.emit(i)) 188 card.clicked.connect(lambda i=i: self.edit_clicked.emit(i)) 189 self.cards_layout.insertWidget(len(self.cards), card) 190 self.cards.append(card) 191 while len(self.cards) > len(edits): 192 self.cards.pop().deleteLater() 193 colors = DIFF_COLORS["light" if self.is_light else "dark"] 194 for i, (card, edit) in enumerate(zip(self.cards, edits, strict=True)): 195 card.show_edit(i + 1, edit, file_text, name, colors, self.muted, font_family) 196 pending = sum(e.status == ed.PENDING and e.located for e in edits) 197 counts = {s: sum(e.status == s for e in edits) for s in (ed.APPLIED, ed.REJECTED, ed.FAILED, ed.STALE)} 198 parts = [f"{len(edits)} edit{'s' * (len(edits) != 1)} proposed"] 199 parts += [f"{n} {word}" for word, n in (("applied", counts[ed.APPLIED]), ("rejected", counts[ed.REJECTED]), 200 ("not found", counts[ed.FAILED]), ("out of date", counts[ed.STALE])) 201 if n] 202 self.summary.setText(f"<span style='color:{self.muted}'>{' · '.join(parts)}</span>") 203 self.accept_all.setEnabled(pending > 0) 204 self.accept_all.setText(f"Accept All ({pending})" if pending else "Accept All") 205 self.reject_all.setEnabled(pending > 0) 206 self.setVisible(bool(edits))
The cards, and Accept All / Reject All (with scrolling False, as
tall as the cards: in something that scrolls itself).
140 def __init__(self, parent=None, scrolling: bool = True): 141 super().__init__(parent) 142 self.cards: list[EditCard] = [] 143 self.is_light = True 144 self.muted = "#8b949e" 145 self.font_family = "Menlo" 146 self.container = QWidget() 147 self.container.setObjectName("EditCards") 148 self.cards_layout = QVBoxLayout(self.container) 149 self.cards_layout.setContentsMargins(0, 0, 0, 0) 150 self.cards_layout.setSpacing(6) 151 if scrolling: 152 self.cards_layout.addStretch(1) 153 self.scroll = QScrollArea() 154 self.scroll.setWidgetResizable(True) 155 self.scroll.setFrameShape(QFrame.NoFrame) 156 self.scroll.setWidget(self.container) 157 self.summary = QLabel() 158 self.accept_all = QPushButton("Accept All") 159 self.accept_all.setToolTip("Make every pending edit (one step to undo)") 160 self.accept_all.clicked.connect(self.accept_all_requested) 161 self.reject_all = QPushButton("Reject All") 162 self.reject_all.clicked.connect(self.reject_all_requested) 163 footer = QHBoxLayout() 164 footer.addWidget(self.summary, 1) 165 footer.addWidget(self.reject_all) 166 footer.addWidget(self.accept_all) 167 layout = QVBoxLayout(self) 168 layout.setContentsMargins(0, 0, 0, 0) 169 layout.setSpacing(6) 170 layout.addWidget(self.scroll if scrolling else self.container, 1) 171 layout.addLayout(footer)
__init__(self, /, parent: PySide6.QtWidgets.QWidget | None = None, f: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags), *, modal: bool | None = None, windowModality: PySide6.QtCore.Qt.WindowModality | None = None, enabled: bool | None = None, geometry: PySide6.QtCore.QRect | None = None, frameGeometry: PySide6.QtCore.QRect | None = None, normalGeometry: PySide6.QtCore.QRect | None = None, x: int | None = None, y: int | None = None, pos: PySide6.QtCore.QPoint | None = None, frameSize: PySide6.QtCore.QSize | None = None, size: PySide6.QtCore.QSize | None = None, width: int | None = None, height: int | None = None, rect: PySide6.QtCore.QRect | None = None, childrenRect: PySide6.QtCore.QRect | None = None, childrenRegion: PySide6.QtGui.QRegion | None = None, sizePolicy: PySide6.QtWidgets.QSizePolicy | None = None, minimumSize: PySide6.QtCore.QSize | None = None, maximumSize: PySide6.QtCore.QSize | None = None, minimumWidth: int | None = None, minimumHeight: int | None = None, maximumWidth: int | None = None, maximumHeight: int | None = None, sizeIncrement: PySide6.QtCore.QSize | None = None, baseSize: PySide6.QtCore.QSize | None = None, palette: PySide6.QtGui.QPalette | None = None, font: PySide6.QtGui.QFont | None = None, cursor: PySide6.QtGui.QCursor | None = None, mouseTracking: bool | None = None, tabletTracking: bool | None = None, isActiveWindow: bool | None = None, focusPolicy: PySide6.QtCore.Qt.FocusPolicy | None = None, focus: bool | None = None, contextMenuPolicy: PySide6.QtCore.Qt.ContextMenuPolicy | None = None, updatesEnabled: bool | None = None, visible: bool | None = None, minimized: bool | None = None, maximized: bool | None = None, fullScreen: bool | None = None, sizeHint: PySide6.QtCore.QSize | None = None, minimumSizeHint: PySide6.QtCore.QSize | None = None, acceptDrops: bool | None = None, windowTitle: str | None = None, windowIcon: PySide6.QtGui.QIcon | None = None, windowIconText: str | None = None, windowOpacity: float | None = None, windowModified: bool | None = None, toolTip: str | None = None, toolTipDuration: int | None = None, statusTip: str | None = None, whatsThis: str | None = None, accessibleName: str | None = None, accessibleDescription: str | None = None, accessibleIdentifier: str | None = None, layoutDirection: PySide6.QtCore.Qt.LayoutDirection | None = None, autoFillBackground: bool | None = None, styleSheet: str | None = None, locale: PySide6.QtCore.QLocale | None = None, windowFilePath: str | None = None, inputMethodHints: PySide6.QtCore.Qt.InputMethodHint | None = None) -> None
Initialize self. See help(type(self)) for accurate signature.
173 def set_palette(self, pal: dict, is_light: bool): 174 self.is_light = is_light 175 self.muted = pal["muted"] 176 self.setStyleSheet(f"#EditCard {{ border: 1px solid {pal['line']}; border-radius: 6px; " 177 f"background: {pal['bg']}; }}" 178 f"QScrollArea, #EditCards {{ background: {pal['bg']}; border: none; }}")
180 def show_edits(self, edits: list[ed.Edit], file_text: str, name: str, font_family: str): 181 """Show ``edits`` (located in ``file_text``, the editor's text).""" 182 self.font_family = font_family 183 while len(self.cards) < len(edits): 184 card = EditCard() 185 i = len(self.cards) 186 card.accept.connect(lambda i=i: self.accept_requested.emit(i)) 187 card.reject.connect(lambda i=i: self.reject_requested.emit(i)) 188 card.clicked.connect(lambda i=i: self.edit_clicked.emit(i)) 189 self.cards_layout.insertWidget(len(self.cards), card) 190 self.cards.append(card) 191 while len(self.cards) > len(edits): 192 self.cards.pop().deleteLater() 193 colors = DIFF_COLORS["light" if self.is_light else "dark"] 194 for i, (card, edit) in enumerate(zip(self.cards, edits, strict=True)): 195 card.show_edit(i + 1, edit, file_text, name, colors, self.muted, font_family) 196 pending = sum(e.status == ed.PENDING and e.located for e in edits) 197 counts = {s: sum(e.status == s for e in edits) for s in (ed.APPLIED, ed.REJECTED, ed.FAILED, ed.STALE)} 198 parts = [f"{len(edits)} edit{'s' * (len(edits) != 1)} proposed"] 199 parts += [f"{n} {word}" for word, n in (("applied", counts[ed.APPLIED]), ("rejected", counts[ed.REJECTED]), 200 ("not found", counts[ed.FAILED]), ("out of date", counts[ed.STALE])) 201 if n] 202 self.summary.setText(f"<span style='color:{self.muted}'>{' · '.join(parts)}</span>") 203 self.accept_all.setEnabled(pending > 0) 204 self.accept_all.setText(f"Accept All ({pending})" if pending else "Accept All") 205 self.reject_all.setEnabled(pending > 0) 206 self.setVisible(bool(edits))
Show edits (located in file_text, the editor's text).