File: selection.py

package info (click to toggle)
git-cola 4.18.2-1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 7,036 kB
  • sloc: python: 40,107; sh: 298; makefile: 223; xml: 121; tcl: 62
file content (133 lines) | stat: -rw-r--r-- 4,065 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
"""Provides a selection model to handle selection."""
from __future__ import annotations
import collections
from typing import Any

from qtpy import QtCore
from qtpy.QtCore import Signal

from .main import MainModel


State = collections.namedtuple('State', 'staged unmerged modified untracked')


def create() -> SelectionModel:
    """Create a SelectionModel"""
    return SelectionModel()


def pick(selection: State) -> list[Any]:
    """Choose the first list from stage, unmerged, modified, untracked"""
    if selection.staged:
        files = selection.staged
    elif selection.unmerged:
        files = selection.unmerged
    elif selection.modified:
        files = selection.modified
    elif selection.untracked:
        files = selection.untracked
    else:
        files = []
    return files


def union(selection: State) -> list[Any]:
    """Return the union of all selected items in a sorted list"""
    values = set(
        selection.staged + selection.unmerged + selection.modified + selection.untracked
    )
    return list(sorted(values))


def _filter(values: list[str | Any], remove: list[str | Any]) -> None:
    """Filter a list in-place by removing items"""
    remove_set = set(remove)
    values_copy = list(values)
    last = len(values_copy) - 1
    for idx, value in enumerate(reversed(values)):
        if value not in remove_set:
            values.pop(last - idx)


class SelectionModel(QtCore.QObject):
    """Provides information about selected file paths."""

    selection_changed = Signal()

    # These properties wrap the individual selection items
    # to provide higher-level pseudo-selections.
    unstaged = property(lambda self: self.unmerged + self.modified + self.untracked)

    def __init__(self) -> None:
        super().__init__()
        self.staged = []
        self.unmerged = []
        self.modified = []
        self.untracked = []
        self.line_number = None

    def reset(self, emit: bool = False) -> None:
        self.staged = []
        self.unmerged = []
        self.modified = []
        self.untracked = []
        self.line_number = None
        if emit:
            self.selection_changed.emit()

    def is_empty(self) -> bool:
        return not (
            bool(self.staged or self.unmerged or self.modified or self.untracked)
        )

    def set_selection(self, s: State) -> None:
        """Set the new selection."""
        self.staged = s.staged
        self.unmerged = s.unmerged
        self.modified = s.modified
        self.untracked = s.untracked
        self.selection_changed.emit()

    def update(self, other: MainModel) -> None:
        _filter(self.staged, other.staged)
        _filter(self.unmerged, other.unmerged)
        _filter(self.modified, other.modified)
        _filter(self.untracked, other.untracked)
        self.selection_changed.emit()

    def selection(self) -> State:
        return State(self.staged, self.unmerged, self.modified, self.untracked)

    def single_selection(self) -> State:
        """Scan across staged, modified, etc. and return a single item."""
        staged = None
        modified = None
        unmerged = None
        untracked = None
        if self.staged:
            staged = self.staged[0]
        elif self.modified:
            modified = self.modified[0]
        elif self.unmerged:
            unmerged = self.unmerged[0]
        elif self.untracked:
            untracked = self.untracked[0]
        return State(staged, unmerged, modified, untracked)

    def filename(self) -> str | None:
        """Return the currently selected filename"""
        paths = [path for path in self.single_selection() if path is not None]
        if paths:
            filename = paths[0]
        else:
            filename = None
        return filename

    def group(self) -> list[Any]:
        """A list of selected files in various states of being"""
        return pick(self.selection())

    def union(self) -> list[Any]:
        """Return the union of all selected items in a sorted list"""
        return union(self)