Skip to content

Commit 467c71d

Browse files
authored
Merge pull request zyedidia#3224 from JoeKar/fix/line-synchronization
buffer: Add proper lock mechanism to lock the full `LineArray` instead of single lines
2 parents c493e14 + a3ca054 commit 467c71d

File tree

4 files changed

+64
-39
lines changed

4 files changed

+64
-39
lines changed

internal/buffer/buffer.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,7 +1180,11 @@ func (b *Buffer) Retab() {
11801180
}
11811181

11821182
l = bytes.TrimLeft(l, " \t")
1183+
1184+
b.Lock()
11831185
b.lines[i].data = append(ws, l...)
1186+
b.Unlock()
1187+
11841188
b.MarkModified(i, i)
11851189
dirty = true
11861190
}

internal/buffer/buffer_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ type operation struct {
2020

2121
func init() {
2222
ulua.L = lua.NewState()
23-
// TODO: uncomment InitRuntimeFiles once we fix races between syntax
24-
// highlighting and buffer editing.
25-
// config.InitRuntimeFiles(false)
23+
config.InitRuntimeFiles(false)
2624
config.InitGlobalSettings()
2725
config.GlobalSettings["backup"] = false
2826
config.GlobalSettings["fastdirty"] = true

internal/buffer/line_array.go

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,9 @@ type searchState struct {
4646
type Line struct {
4747
data []byte
4848

49-
state highlight.State
50-
match highlight.LineMatch
51-
rehighlight bool
52-
lock sync.Mutex
49+
state highlight.State
50+
match highlight.LineMatch
51+
lock sync.Mutex
5352

5453
// The search states for the line, used for highlighting of search matches,
5554
// separately from the syntax highlighting.
@@ -75,6 +74,7 @@ type LineArray struct {
7574
lines []Line
7675
Endings FileFormat
7776
initsize uint64
77+
lock sync.Mutex
7878
}
7979

8080
// Append efficiently appends lines together
@@ -147,20 +147,18 @@ func NewLineArray(size uint64, endings FileFormat, reader io.Reader) *LineArray
147147
if err != nil {
148148
if err == io.EOF {
149149
la.lines = Append(la.lines, Line{
150-
data: data,
151-
state: nil,
152-
match: nil,
153-
rehighlight: false,
150+
data: data,
151+
state: nil,
152+
match: nil,
154153
})
155154
}
156155
// Last line was read
157156
break
158157
} else {
159158
la.lines = Append(la.lines, Line{
160-
data: data[:dlen-1],
161-
state: nil,
162-
match: nil,
163-
rehighlight: false,
159+
data: data[:dlen-1],
160+
state: nil,
161+
match: nil,
164162
})
165163
}
166164
n++
@@ -190,22 +188,23 @@ func (la *LineArray) Bytes() []byte {
190188
// newlineBelow adds a newline below the given line number
191189
func (la *LineArray) newlineBelow(y int) {
192190
la.lines = append(la.lines, Line{
193-
data: []byte{' '},
194-
state: nil,
195-
match: nil,
196-
rehighlight: false,
191+
data: []byte{' '},
192+
state: nil,
193+
match: nil,
197194
})
198195
copy(la.lines[y+2:], la.lines[y+1:])
199196
la.lines[y+1] = Line{
200-
data: []byte{},
201-
state: la.lines[y].state,
202-
match: nil,
203-
rehighlight: false,
197+
data: []byte{},
198+
state: la.lines[y].state,
199+
match: nil,
204200
}
205201
}
206202

207203
// Inserts a byte array at a given location
208204
func (la *LineArray) insert(pos Loc, value []byte) {
205+
la.lock.Lock()
206+
defer la.lock.Unlock()
207+
209208
x, y := runeToByteIndex(pos.X, la.lines[pos.Y].data), pos.Y
210209
for i := 0; i < len(value); i++ {
211210
if value[i] == '\n' || (value[i] == '\r' && i < len(value)-1 && value[i+1] == '\n') {
@@ -233,24 +232,26 @@ func (la *LineArray) insertByte(pos Loc, value byte) {
233232

234233
// joinLines joins the two lines a and b
235234
func (la *LineArray) joinLines(a, b int) {
236-
la.insert(Loc{len(la.lines[a].data), a}, la.lines[b].data)
235+
la.lines[a].data = append(la.lines[a].data, la.lines[b].data...)
237236
la.deleteLine(b)
238237
}
239238

240239
// split splits a line at a given position
241240
func (la *LineArray) split(pos Loc) {
242241
la.newlineBelow(pos.Y)
243-
la.insert(Loc{0, pos.Y + 1}, la.lines[pos.Y].data[pos.X:])
242+
la.lines[pos.Y+1].data = append(la.lines[pos.Y+1].data, la.lines[pos.Y].data[pos.X:]...)
244243
la.lines[pos.Y+1].state = la.lines[pos.Y].state
245244
la.lines[pos.Y].state = nil
246245
la.lines[pos.Y].match = nil
247246
la.lines[pos.Y+1].match = nil
248-
la.lines[pos.Y].rehighlight = true
249247
la.deleteToEnd(Loc{pos.X, pos.Y})
250248
}
251249

252250
// removes from start to end
253251
func (la *LineArray) remove(start, end Loc) []byte {
252+
la.lock.Lock()
253+
defer la.lock.Unlock()
254+
254255
sub := la.Substr(start, end)
255256
startX := runeToByteIndex(start.X, la.lines[start.Y].data)
256257
endX := runeToByteIndex(end.X, la.lines[end.Y].data)
@@ -327,11 +328,11 @@ func (la *LineArray) End() Loc {
327328
}
328329

329330
// LineBytes returns line n as an array of bytes
330-
func (la *LineArray) LineBytes(n int) []byte {
331-
if n >= len(la.lines) || n < 0 {
331+
func (la *LineArray) LineBytes(lineN int) []byte {
332+
if lineN >= len(la.lines) || lineN < 0 {
332333
return []byte{}
333334
}
334-
return la.lines[n].data
335+
return la.lines[lineN].data
335336
}
336337

337338
// State gets the highlight state for the given line number
@@ -362,16 +363,14 @@ func (la *LineArray) Match(lineN int) highlight.LineMatch {
362363
return la.lines[lineN].match
363364
}
364365

365-
func (la *LineArray) Rehighlight(lineN int) bool {
366-
la.lines[lineN].lock.Lock()
367-
defer la.lines[lineN].lock.Unlock()
368-
return la.lines[lineN].rehighlight
366+
// Locks the whole LineArray
367+
func (la *LineArray) Lock() {
368+
la.lock.Lock()
369369
}
370370

371-
func (la *LineArray) SetRehighlight(lineN int, on bool) {
372-
la.lines[lineN].lock.Lock()
373-
defer la.lines[lineN].lock.Unlock()
374-
la.lines[lineN].rehighlight = on
371+
// Unlocks the whole LineArray
372+
func (la *LineArray) Unlock() {
373+
la.lock.Unlock()
375374
}
376375

377376
// SearchMatch returns true if the location `pos` is within a match

pkg/highlight/highlighter.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ type LineStates interface {
7777
State(lineN int) State
7878
SetState(lineN int, s State)
7979
SetMatch(lineN int, m LineMatch)
80+
Lock()
81+
Unlock()
8082
}
8183

8284
// A Highlighter contains the information needed to highlight a string
@@ -303,7 +305,13 @@ func (h *Highlighter) HighlightString(input string) []LineMatch {
303305

304306
// HighlightStates correctly sets all states for the buffer
305307
func (h *Highlighter) HighlightStates(input LineStates) {
306-
for i := 0; i < input.LinesNum(); i++ {
308+
for i := 0; ; i++ {
309+
input.Lock()
310+
if i >= input.LinesNum() {
311+
input.Unlock()
312+
break
313+
}
314+
307315
line := input.LineBytes(i)
308316
// highlights := make(LineMatch)
309317

@@ -316,6 +324,7 @@ func (h *Highlighter) HighlightStates(input LineStates) {
316324
curState := h.lastRegion
317325

318326
input.SetState(i, curState)
327+
input.Unlock()
319328
}
320329
}
321330

@@ -324,7 +333,9 @@ func (h *Highlighter) HighlightStates(input LineStates) {
324333
// This assumes that all the states are set correctly
325334
func (h *Highlighter) HighlightMatches(input LineStates, startline, endline int) {
326335
for i := startline; i <= endline; i++ {
336+
input.Lock()
327337
if i >= input.LinesNum() {
338+
input.Unlock()
328339
break
329340
}
330341

@@ -339,6 +350,7 @@ func (h *Highlighter) HighlightMatches(input LineStates, startline, endline int)
339350
}
340351

341352
input.SetMatch(i, match)
353+
input.Unlock()
342354
}
343355
}
344356

@@ -350,9 +362,17 @@ func (h *Highlighter) ReHighlightStates(input LineStates, startline int) int {
350362

351363
h.lastRegion = nil
352364
if startline > 0 {
365+
input.Lock()
353366
h.lastRegion = input.State(startline - 1)
367+
input.Unlock()
354368
}
355-
for i := startline; i < input.LinesNum(); i++ {
369+
for i := startline; ; i++ {
370+
input.Lock()
371+
if i >= input.LinesNum() {
372+
input.Unlock()
373+
break
374+
}
375+
356376
line := input.LineBytes(i)
357377
// highlights := make(LineMatch)
358378

@@ -366,6 +386,7 @@ func (h *Highlighter) ReHighlightStates(input LineStates, startline int) int {
366386
lastState := input.State(i)
367387

368388
input.SetState(i, curState)
389+
input.Unlock()
369390

370391
if curState == lastState {
371392
return i
@@ -377,6 +398,9 @@ func (h *Highlighter) ReHighlightStates(input LineStates, startline int) int {
377398

378399
// ReHighlightLine will rehighlight the state and match for a single line
379400
func (h *Highlighter) ReHighlightLine(input LineStates, lineN int) {
401+
input.Lock()
402+
defer input.Unlock()
403+
380404
line := input.LineBytes(lineN)
381405
highlights := make(LineMatch)
382406

0 commit comments

Comments
 (0)