-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathparagraph.go
133 lines (123 loc) · 3.17 KB
/
paragraph.go
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
package main
import "unicode/utf8"
func indexPreviousBlankLine() int {
if Global.CurrentB.cy == 0 {
Global.Input = "Beginning of buffer"
return 0
}
for i := Global.CurrentB.cy - 1; 0 < i; i-- {
if Global.CurrentB.Rows[i].Size == 0 {
return i
}
}
return 0
}
func indexNextBlankLine() int {
if Global.CurrentB.cy == Global.CurrentB.NumRows {
Global.Input = "End of buffer"
return Global.CurrentB.NumRows
} else if Global.CurrentB.cy == Global.CurrentB.NumRows-1 {
return Global.CurrentB.NumRows
}
for i := Global.CurrentB.cy + 1; i < Global.CurrentB.NumRows; i++ {
if Global.CurrentB.Rows[i].Size == 0 {
return i
}
}
return Global.CurrentB.NumRows
}
func backwardParagraph() {
times := getRepeatTimes()
for i := 0; i < times; i++ {
cy := indexPreviousBlankLine()
Global.CurrentB.cy = cy
Global.CurrentB.cx = 0
}
}
func forwardParagraph() {
times := getRepeatTimes()
for i := 0; i < times; i++ {
cy := indexNextBlankLine()
Global.CurrentB.cy = cy
Global.CurrentB.cx = 0
}
}
func doAutoFillParagraph() {
buf := Global.CurrentB
if buf.NumRows == 0 {
return
}
row := buf.Rows[buf.cy]
if buf.hasMode("aggressive-fill-mode") && row.RenderSize >= Global.Fillcolumn {
doFillParagraph()
} else if buf.hasMode("auto-fill-mode") && editorRowCxToRx(row) >= Global.Fillcolumn {
startl := buf.cy
endl := startl
runeidx, space := savePointBeforeFill(startl, endl)
doFillLines(startl, endl)
restorePointAfterFill(startl, buf.cy, runeidx, space)
}
}
func doFillParagraph() {
if Global.CurrentB.NumRows == 0 {
return
}
startl := indexPreviousBlankLine()
endl := indexNextBlankLine() - 1
runeidx, space := savePointBeforeFill(startl, endl)
doFillLines(startl, endl)
restorePointAfterFill(indexPreviousBlankLine(), Global.CurrentB.cy, runeidx, space)
}
func doFillLines(startl, endl int) {
transposeRegion(Global.CurrentB, 0, Global.CurrentB.Rows[endl].Size, startl, endl, FillString)
}
func savePointBeforeFill(startl, endl int) (int, bool) {
buf := Global.CurrentB
runeidx := 0
space := false
rowloop:
for cy := startl; cy <= endl; cy++ {
for cx, rv := range buf.Rows[cy].Data {
// Spaces excluded from the count because they can be added or
// removed by the fill.
if rv != ' ' {
runeidx++
}
if cy == buf.cy && cx == buf.cx {
// Need to know if point is on a space so that it can be put
// back there. However, spaces before first non-spaces don't
// count because they are deleted.
space = rv == ' ' && runeidx > 0
break rowloop
}
}
if cy == buf.cy {
// Handle edge case where cx wasn't reached because point is at end
// of line. This is treated as a virtual space.
space = true
break
}
}
return runeidx, space
}
func restorePointAfterFill(startl, endl, runeidx int, space bool) {
buf := Global.CurrentB
cur_runeidx := 0
for cy := startl; cy <= endl; cy++ {
for cx, rv := range buf.Rows[cy].Data {
if rv != ' ' {
cur_runeidx++
}
// '>=' not '==' to handle edge case where the original paragraph
// started with a space that was deleted.
if cur_runeidx >= runeidx {
buf.cy = cy
buf.cx = cx
if space {
buf.cx += utf8.RuneLen(rv)
}
return
}
}
}
}