aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatias Linares <matias@deprecated.org>2025-03-05 17:48:23 -0300
committerMatias Linares <matias@deprecated.org>2025-03-05 17:48:23 -0300
commit99a8e02c5fd26be5ac80efa35c33b550df9c0ee9 (patch)
tree70faa7b35a385d6a096d023584ee44e890a02b31
parentf2305655d86728e3fa8fb3214dd9acf10fce6372 (diff)
downloadkodereviewer-99a8e02c5fd26be5ac80efa35c33b550df9c0ee9.tar.gz
Add DiffFileModel
-rw-r--r--kodereviewer/app.py3
-rw-r--r--kodereviewer/models/file.py142
-rw-r--r--kodereviewer/qml/FilesChangedPage.qml5
3 files changed, 147 insertions, 3 deletions
diff --git a/kodereviewer/app.py b/kodereviewer/app.py
index e188923..fbcc7b8 100644
--- a/kodereviewer/app.py
+++ b/kodereviewer/app.py
@@ -13,7 +13,7 @@ from PySide6.QtQuickControls2 import QQuickStyle
from rich.logging import RichHandler
from kodereviewer.data import PullRequest
-from kodereviewer.models.file import FileModel
+from kodereviewer.models.file import DiffFileModel, FileModel
from kodereviewer.network_manager import NetworkManager
from kodereviewer.models import (
CommentModel, TreeFileModel, LabelModel, LineModel, PullRequestModel,
@@ -55,6 +55,7 @@ def main():
qmlRegisterType(CommentModel, "org.deprecated.kodereviewer", 1, 0, "CommentModel")
qmlRegisterType(FileModel, "org.deprecated.kodereviewer", 1, 0, "FileModel")
+ qmlRegisterType(DiffFileModel, "org.deprecated.kodereviewer", 1, 0, "DiffFileModel")
qmlRegisterType(TreeFileModel, "org.deprecated.kodereviewer", 1, 0, "TreeFileModel")
qmlRegisterType(LabelModel, "org.deprecated.kodereviewer", 1, 0, "LabelModel")
qmlRegisterType(LineModel, "org.deprecated.kodereviewer", 1, 0, "LineModel")
diff --git a/kodereviewer/models/file.py b/kodereviewer/models/file.py
index 2e00755..ce47bcc 100644
--- a/kodereviewer/models/file.py
+++ b/kodereviewer/models/file.py
@@ -1,9 +1,10 @@
+from collections.abc import Sequence
import logging
from copy import copy
from dataclasses import dataclass, field
from enum import IntEnum, auto
from pathlib import Path
-from typing import Any, Optional, Self
+from typing import Any, Optional, Self, override
from PySide6.QtCore import (
QAbstractListModel, QAbstractItemModel, QByteArray, QModelIndex, QObject,
@@ -11,6 +12,7 @@ from PySide6.QtCore import (
)
from PySide6.QtQml import QmlElement
+from kodereviewer.diff_parser import GithubDiffParser
from kodereviewer.project import Project
from kodereviewer.data import ChangedFile, Label, PullRequest
@@ -130,7 +132,7 @@ class TreeFileModel(QAbstractItemModel):
self.endResetModel()
def index(self, row: int, column: int,
- parent: QModelIndex = QModelIndex()) -> QModelIndex:
+ parent: QModelIndex | QPersistentModelIndex = QModelIndex()) -> QModelIndex:
"""Returns the index of the item in the model specified by the given row, column and parent index."""
if not self.hasIndex(row, column, parent):
return QModelIndex()
@@ -204,6 +206,142 @@ class TreeFileModel(QAbstractItemModel):
}
+@dataclass
+class DiffFileItem:
+ text: str
+ parent: Self | None = None
+ children: list[Self] = field(default_factory=list)
+
+ def append(self, child: Self) -> None:
+ self.children.append(child)
+
+ def child(self, row: int) -> Self | None:
+ if row >= 0and row < len(self.children):
+ return self.children[row]
+ return None
+
+ def row(self) -> int:
+ if self.parent is None:
+ return 0
+ for i, child in enumerate(self.parent.children):
+ if self is child:
+ return i
+ raise Exception('Should not happen!')
+
+ def column_count(self) -> int:
+ """Only text"""
+ return 1
+
+ def __str__(self) -> str:
+ return f'DiffFileItem: "self.text"'
+
+
+@QmlElement
+class DiffFileModel(QAbstractItemModel):
+ items: Sequence[DiffFileItem]
+ _diff: str
+
+ class Roles(IntEnum):
+ Text = Qt.ItemDataRole.UserRole + 1
+
+ def __init__(self):
+ super().__init__()
+ self.root_node = DiffFileItem(text='')
+ self._diff = ''
+
+ def parse_file(self, diff: str):
+ logger.info('Parsing with github diff parser')
+ parser = GithubDiffParser(diff)
+ for hunk in parser.hunks():
+ logger.info('loading hunk with context %s', hunk.context)
+ context = hunk.context
+ text = '\n'.join(hunk.lines)
+
+ context_item = DiffFileItem(text=context, parent=self.root_node)
+ self.root_node.append(context_item)
+ diff_item = DiffFileItem(text=text, parent=context_item)
+ context_item.append(diff_item)
+
+ def get_diff(self) -> str:
+ return self._diff
+
+ def set_diff(self, diff: str) -> None:
+ if not diff:
+ return
+
+ if diff == self._diff:
+ return
+
+ self.beginResetModel()
+ self._diff = diff
+ self.parse_file(self._diff)
+ self.endResetModel()
+
+ diffChanged = Signal()
+ diff = Property(str, fget=get_diff, fset=set_diff, notify=diffChanged)
+
+ def index(
+ self, row: int, column: int,
+ parent: QModelIndex | QPersistentModelIndex = QModelIndex()
+ ) -> QModelIndex:
+ if not self.hasIndex(row, column, parent):
+ return QModelIndex()
+
+ item: DiffFileItem
+ if parent.isValid():
+ item = parent.internalPointer()
+ else:
+ item = self.root_node
+
+ if item.child(row):
+ return self.createIndex(row, column, item.child(row))
+
+ return QModelIndex()
+
+ def parent(self, index: QModelIndex) -> QModelIndex:
+ if not index.isValid():
+ return QModelIndex()
+
+ item: DiffFileItem = index.internalPointer()
+ parent: DiffFileItem | None = item.parent
+
+ if parent is None or parent == self.root_node:
+ return QModelIndex()
+
+ return self.createIndex(parent.row(), 0, parent)
+
+
+ def rowCount(self, parent: QModelIndex | QPersistentModelIndex = QModelIndex()) -> int:
+ node: DiffFileItem
+ if parent.isValid():
+ node = parent.internalPointer()
+ else:
+ node = self.root_node
+
+ return len(node.children)
+
+ def columnCount(self, parent: QModelIndex | QPersistentModelIndex = QModelIndex()) -> int:
+ return 1
+
+ def data(
+ self, index: QModelIndex | QPersistentModelIndex,
+ role: int = Qt.ItemDataRole.DisplayRole
+ ) -> Any:
+ if not index.isValid():
+ return ''
+ item: DiffFileItem = index.internalPointer()
+ if role == Qt.ItemDataRole.DisplayRole:
+ return item.text
+ if role == self.Roles.Text:
+ return item.text
+
+ return None
+
+ def roleNames(self) -> dict[int, QByteArray]:
+ return {
+ self.Roles.Text: QByteArray(b'text'),
+ }
+
@QmlElement
class FileModel(QAbstractListModel):
diff --git a/kodereviewer/qml/FilesChangedPage.qml b/kodereviewer/qml/FilesChangedPage.qml
index 25c1164..f1ee031 100644
--- a/kodereviewer/qml/FilesChangedPage.qml
+++ b/kodereviewer/qml/FilesChangedPage.qml
@@ -27,6 +27,11 @@ Kirigami.ScrollablePage {
property string currentFile: ""
property string currentText: ""
+ DiffFileModel {
+ id: diffFileModel
+ diff: root.currentText
+ }
+
onPullRequestChanged: {
root.currentFile = ""
root.currentText = ""