~ubuntu-branches/ubuntu/utopic/retext/utopic

« back to all changes in this revision

Viewing changes to ReText/tablemode.py

  • Committer: Package Import Robot
  • Author(s): Dmitry Shachnev
  • Date: 2014-07-26 12:38:59 UTC
  • mfrom: (20.1.3 sid)
  • Revision ID: package-import@ubuntu.com-20140726123859-49z5c24mluzkpui1
Tags: 5.0.0-1
* New upstream release.
* Update debian/copyright.
* Run upstream tests during build.
* Wrap-and-sort debian/control.
* Update debian/watch to point to PyPI.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# vim: noexpandtab:ts=4:sw=4
 
2
# This file is part of ReText
 
3
# Copyright: Maurice van der Pot 2014
 
4
# License: GNU GPL v2 or higher
 
5
 
 
6
import sys
 
7
from ReText import DOCTYPE_MARKDOWN, DOCTYPE_REST
 
8
 
 
9
from PyQt5.QtGui import QTextCursor
 
10
 
 
11
LARGER_THAN_ANYTHING = sys.maxsize
 
12
 
 
13
class Row:
 
14
        def __init__(self, block=None, text=None, separatorline=False, paddingchar=' '):
 
15
                self.block = block
 
16
                self.text = text
 
17
                self.separatorline = separatorline
 
18
                self.paddingchar = paddingchar
 
19
 
 
20
        def __repr__(self):
 
21
                return "<Row '%s' %s '%s'>" % (self.text, self.separatorline, self.paddingchar)
 
22
 
 
23
def _getTableLines(doc, pos, docType):
 
24
        startblock = doc.findBlock(pos)
 
25
        editedlineindex = 0
 
26
        offset = pos - startblock.position()
 
27
 
 
28
        rows = [ Row(block = startblock,
 
29
                     text = startblock.text()) ]
 
30
 
 
31
        block = startblock.previous()
 
32
        while any(c in block.text() for c in '+|'):
 
33
                rows.insert(0, Row(block = block,
 
34
                                   text = block.text()))
 
35
                editedlineindex += 1
 
36
                block = block.previous()
 
37
 
 
38
        block = startblock.next()
 
39
        while any(c in block.text() for c in '+|'):
 
40
                rows.append(Row(block = block,
 
41
                                text = block.text()))
 
42
                block = block.next()
 
43
 
 
44
        if docType == DOCTYPE_MARKDOWN:
 
45
                for i, row in enumerate(rows):
 
46
                        if i == 1:
 
47
                                row.separatorline = True
 
48
                                row.paddingchar = '-'
 
49
        elif docType == DOCTYPE_REST:
 
50
                for i, row in enumerate(rows):
 
51
                        if i & 1 == 0: # i is even
 
52
                                row.separatorline = True
 
53
                                row.paddingchar = '=' if (i == 2) else '-'
 
54
                                row.text = row.text.replace('+', '|')
 
55
 
 
56
        return rows, editedlineindex, offset
 
57
 
 
58
def _sortaUndoEdit(rows, editedlineindex, editsize):
 
59
        aftertext = rows[editedlineindex].text
 
60
        if editsize < 0:
 
61
                beforetext = ' ' * -editsize + aftertext
 
62
        else:
 
63
                beforetext = aftertext[editsize:]
 
64
 
 
65
        rows[editedlineindex].text = beforetext
 
66
 
 
67
def _determineRoomInCell(row, edge, shrinking, startposition=0):
 
68
        if edge >= len(row.text) or row.text[edge] != '|':
 
69
                room = LARGER_THAN_ANYTHING
 
70
        else:
 
71
                clearance = 0
 
72
                cellwidth = 0
 
73
                afterContent = True
 
74
                for i in range(edge - 1, startposition - 1, -1):
 
75
                        if row.text[i] == '|':
 
76
                                break
 
77
                        else:
 
78
                                if row.text[i] == row.paddingchar and afterContent:
 
79
                                        clearance += 1
 
80
                                else:
 
81
                                        afterContent = False
 
82
                                cellwidth += 1
 
83
 
 
84
                if row.separatorline:
 
85
                        if shrinking:
 
86
                                # do not shrink separator cells below 3
 
87
                                room = max(0, cellwidth - 3)
 
88
                        else:
 
89
                                # start expanding the cell if only the space for a right-align marker is left
 
90
                                room = max(0, cellwidth - 1)
 
91
                else:
 
92
                        room = clearance
 
93
 
 
94
        return room
 
95
 
 
96
def _performShift(row, rowShift, edge, shift):
 
97
        editlist = []
 
98
 
 
99
        if len(row.text) > edge and row.text[edge] == '|' and rowShift != shift:
 
100
                editsize = -(rowShift - shift)
 
101
                rowShift = shift
 
102
 
 
103
                # Insert one position further to the left on separator lines, because
 
104
                # there may be a space (for esthetical reasons) or an alignment marker
 
105
                # on the last position before the edge and that should stay next to the
 
106
                # edge.
 
107
                if row.separatorline:
 
108
                        edge -= 1
 
109
 
 
110
                editlist.append((edge, editsize))
 
111
 
 
112
        return editlist, rowShift
 
113
 
 
114
def _determineNextEdge(rows, rowShifts, offset):
 
115
        nextedge = None
 
116
        for row, rowShift in zip(rows, rowShifts):
 
117
                if rowShift != 0:
 
118
                        edge = row.text.find('|', offset)
 
119
                        if edge != -1 and (nextedge == None or edge < nextedge):
 
120
                                nextedge = edge
 
121
        return nextedge
 
122
 
 
123
def _determineEditLists(rows, editedlineindex, offset, editsize):
 
124
        rowShifts = [0 for _ in rows]
 
125
        rowShifts[editedlineindex] = editsize
 
126
 
 
127
        editLists = [[] for _ in rows]
 
128
 
 
129
        currentedge = _determineNextEdge(rows, rowShifts, offset)
 
130
        firstEdge = True
 
131
 
 
132
 
 
133
        while currentedge:
 
134
 
 
135
                if editsize < 0:
 
136
                        leastLeftShift = min((-rowShift + _determineRoomInCell(row, currentedge, True)
 
137
                                for row, rowShift in zip(rows, rowShifts)))
 
138
 
 
139
                        shift = max(editsize, -leastLeftShift)
 
140
                else:
 
141
                        if firstEdge:
 
142
                                room = _determineRoomInCell(rows[editedlineindex], currentedge, False, offset)
 
143
                                shift = max(0, editsize - room)
 
144
 
 
145
                for i, row in enumerate(rows):
 
146
                        editList, newRowShift = _performShift(row, rowShifts[i], currentedge, shift)
 
147
                        rowShifts[i] = newRowShift
 
148
                        editLists[i].extend(editList)
 
149
 
 
150
                currentedge = _determineNextEdge(rows, rowShifts, currentedge + 1)
 
151
                firstEdge = False
 
152
 
 
153
        return editLists
 
154
 
 
155
def _performEdits(cursor, rows, editLists, linewithoffset, offset):
 
156
        cursor.joinPreviousEditBlock()
 
157
        for i, (row, editList) in enumerate(zip(rows, editLists)):
 
158
 
 
159
                for editpos, editsize in sorted(editList, reverse=True):
 
160
 
 
161
                        if i == linewithoffset:
 
162
                                editpos += offset
 
163
 
 
164
                        cursor.setPosition(row.block.position() + editpos)
 
165
                        if editsize > 0:
 
166
                                cursor.insertText(editsize * row.paddingchar)
 
167
                        else:
 
168
                                for _ in range(-editsize):
 
169
                                        cursor.deletePreviousChar()
 
170
        cursor.endEditBlock()
 
171
 
 
172
def adjustTableToChanges(doc, pos, editsize, docType):
 
173
        if docType in (DOCTYPE_MARKDOWN, DOCTYPE_REST):
 
174
                rows, editedlineindex, offset = _getTableLines(doc, pos, docType)
 
175
 
 
176
                _sortaUndoEdit(rows, editedlineindex, editsize)
 
177
 
 
178
                editLists = _determineEditLists(rows, editedlineindex, offset, editsize)
 
179
 
 
180
                cursor = QTextCursor(doc)
 
181
                _performEdits(cursor, rows, editLists, editedlineindex, editsize)