1// Copyright 2016 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package text
6
7// TODO: do we care about "\n" vs "\r" vs "\r\n"? We only recognize "\n" for
8// now.
9
10import (
11	"bytes"
12	"errors"
13	"io"
14	"strings"
15	"unicode/utf8"
16
17	"golang.org/x/image/math/fixed"
18)
19
20// Caret is a location in a Frame's text, and is the mechanism for adding and
21// removing bytes of text. Conceptually, a Caret and a Frame's text is like an
22// int c and a []byte t such that the text before and after that Caret is t[:c]
23// and t[c:]. That byte-count location remains unchanged even when a Frame is
24// re-sized and laid out into a new tree of Paragraphs, Lines and Boxes.
25//
26// A Frame can have multiple open Carets. For example, the beginning and end of
27// a text selection can be represented by two Carets. Multiple Carets for the
28// one Frame are not safe to use concurrently, but it is valid to interleave
29// such operations sequentially. For example, if two Carets c0 and c1 for the
30// one Frame are positioned at the 10th and 20th byte, and 4 bytes are written
31// to c0, inserting what becomes the equivalent of text[10:14], then c0's
32// position is updated to be 14 but c1's position is also updated to be 24.
33type Caret struct {
34	f *Frame
35
36	// caretsIndex is the index of this Caret in the f.carets slice.
37	caretsIndex int
38
39	// seqNum is the Frame f's sequence number for which this Caret's cached p,
40	// l, b and k fields are valid. If f has been modified since then, those
41	// fields will have to be re-calculated based on the pos field (which is
42	// always valid).
43	//
44	// TODO: when re-calculating p, l, b and k, be more efficient than a linear
45	// scan from the start or end?
46	seqNum uint64
47
48	// p, l and b cache the index of the Caret's Paragraph, Line and Box. None
49	// of these values can be zero.
50	p, l, b int32
51
52	// k caches the Caret's position in the text, in Frame.text order. It is
53	// valid to index the Frame.text slice with k, analogous to the Box.i and
54	// Box.j fields. For a Caret c, letting bb := c.f.boxes[c.b], an invariant
55	// is that bb.i <= c.k && c.k <= bb.j if the cache is valid (i.e. the
56	// Caret's seqNum equals the Frame's seqNum).
57	k int32
58
59	// pos is the Caret's position in the text, in layout order. It is the "c"
60	// as in "t[:c]" in the doc comment for type Caret above. It is not valid
61	// to index the Frame.text slice with pos, since the Frame.text slice does
62	// not necessarily hold the textual content in layout order.
63	pos int32
64
65	tmp [utf8.UTFMax]byte
66}
67
68// Close closes the Caret.
69func (c *Caret) Close() error {
70	i, j := c.caretsIndex, len(c.f.carets)-1
71
72	// Swap c with the last element of c.f.carets.
73	if i != j {
74		other := c.f.carets[j]
75		other.caretsIndex = i
76		c.f.carets[i] = other
77	}
78
79	c.f.carets[j] = nil
80	c.f.carets = c.f.carets[:j]
81	*c = Caret{}
82	return nil
83}
84
85type leanResult int
86
87const (
88	// leanOK means that the lean changed the Caret's Box.
89	leanOK leanResult = iota
90	// leanFailedEOF means that the lean did not change the Caret's Box,
91	// because the Caret was already at the end / beginning of the Frame (when
92	// leaning forwards / backwards).
93	leanFailedEOF
94	// leanFailedNotEOB means that the lean did not change the Caret's Box,
95	// because the Caret was not placed at the end / beginning of the Box (when
96	// leaning forwards / backwards).
97	leanFailedNotEOB
98)
99
100// leanForwards moves the Caret from the right end of one Box to the left end
101// of the next Box, crossing Lines and Paragraphs to find that next Box. It
102// returns whether the Caret moved to a different Box.
103//
104// Diagramatically, suppose we have two adjacent boxes (shown by square
105// brackets below), with the Caret (an integer location called Caret.pos in the
106// Frame's text) in the middle of the "foo2bar3" word:
107//	[foo0 foo1 foo2]^[bar3 bar4 bar5]
108// leanForwards moves Caret.k from fooBox.j to barBox.i, also updating the
109// Caret's p, l and b. Caret.pos remains unchanged.
110func (c *Caret) leanForwards() leanResult {
111	if c.k != c.f.boxes[c.b].j {
112		return leanFailedNotEOB
113	}
114	if nextB := c.f.boxes[c.b].next; nextB != 0 {
115		c.b = nextB
116		c.k = c.f.boxes[c.b].i
117		return leanOK
118	}
119	if nextL := c.f.lines[c.l].next; nextL != 0 {
120		c.l = nextL
121		c.b = c.f.lines[c.l].firstB
122		c.k = c.f.boxes[c.b].i
123		return leanOK
124	}
125	if nextP := c.f.paragraphs[c.p].next; nextP != 0 {
126		c.p = nextP
127		c.l = c.f.paragraphs[c.p].firstL
128		c.b = c.f.lines[c.l].firstB
129		c.k = c.f.boxes[c.b].i
130		return leanOK
131	}
132	return leanFailedEOF
133}
134
135// leanBackwards is like leanForwards but in the other direction.
136func (c *Caret) leanBackwards() leanResult {
137	if c.k != c.f.boxes[c.b].i {
138		return leanFailedNotEOB
139	}
140	if prevB := c.f.boxes[c.b].prev; prevB != 0 {
141		c.b = prevB
142		c.k = c.f.boxes[c.b].j
143		return leanOK
144	}
145	if prevL := c.f.lines[c.l].prev; prevL != 0 {
146		c.l = prevL
147		c.b = c.f.lines[c.l].lastBox(c.f)
148		c.k = c.f.boxes[c.b].j
149		return leanOK
150	}
151	if prevP := c.f.paragraphs[c.p].prev; prevP != 0 {
152		c.p = prevP
153		c.l = c.f.paragraphs[c.p].lastLine(c.f)
154		c.b = c.f.lines[c.l].lastBox(c.f)
155		c.k = c.f.boxes[c.b].j
156		return leanOK
157	}
158	return leanFailedEOF
159}
160
161func (c *Caret) seekStart() {
162	c.p = c.f.firstP
163	c.l = c.f.paragraphs[c.p].firstL
164	c.b = c.f.lines[c.l].firstB
165	c.k = c.f.boxes[c.b].i
166	c.pos = 0
167}
168
169func (c *Caret) seekEnd() {
170	c.p = c.f.lastParagraph()
171	c.l = c.f.paragraphs[c.p].lastLine(c.f)
172	c.b = c.f.lines[c.l].lastBox(c.f)
173	c.k = c.f.boxes[c.b].j
174	c.pos = int32(c.f.len)
175}
176
177// calculatePLBK ensures that the Caret's cached p, l, b and k fields are
178// valid.
179func (c *Caret) calculatePLBK() {
180	if c.seqNum != c.f.seqNum {
181		c.seek(c.pos)
182	}
183}
184
185// Seek satisfies the io.Seeker interface.
186func (c *Caret) Seek(offset int64, whence int) (int64, error) {
187	switch whence {
188	case SeekSet:
189		// No-op.
190	case SeekCur:
191		offset += int64(c.pos)
192	case SeekEnd:
193		offset += int64(c.f.len)
194	default:
195		return 0, errors.New("text: invalid seek whence")
196	}
197	if offset < 0 {
198		return 0, errors.New("text: negative seek position")
199	}
200	if offset > int64(c.f.len) {
201		offset = int64(c.f.len)
202	}
203	c.seek(int32(offset))
204	return offset, nil
205}
206
207func (c *Caret) seek(off int32) {
208	delta := off - c.pos
209	// If the new offset is closer to the start or the end than to the current
210	// c.pos, or if c's cached {p,l,b,k} values are invalid, move to the start
211	// or end first. In case of a tie, we prefer to seek forwards (i.e. set
212	// delta > 0).
213	if (delta < 0 && -delta >= off) || (c.seqNum != c.f.seqNum) {
214		c.seekStart()
215		delta = off - c.pos
216	}
217	if delta > 0 && delta > int32(c.f.len)-off {
218		c.seekEnd()
219		delta = off - c.pos
220	}
221
222	if delta != 0 {
223		// Seek forwards.
224		for delta > 0 {
225			if n := c.f.boxes[c.b].j - c.k; n > 0 {
226				if n > delta {
227					n = delta
228				}
229				c.pos += n
230				c.k += n
231				delta -= n
232			} else if c.leanForwards() != leanOK {
233				panic("text: invalid state")
234			}
235		}
236
237		// Seek backwards.
238		for delta < 0 {
239			if n := c.f.boxes[c.b].i - c.k; n < 0 {
240				if n < delta {
241					n = delta
242				}
243				c.pos += n
244				c.k += n
245				delta -= n
246			} else if c.leanBackwards() != leanOK {
247				panic("text: invalid state")
248			}
249		}
250
251		// A Caret can't be placed at the end of a Paragraph, unless it is the
252		// final Paragraph. A simple way to enforce this is to lean forwards.
253		c.leanForwards()
254	}
255
256	c.seqNum = c.f.seqNum
257}
258
259// Read satisfies the io.Reader interface by copying those bytes after the
260// Caret and incrementing the Caret.
261func (c *Caret) Read(buf []byte) (n int, err error) {
262	c.calculatePLBK()
263	for len(buf) > 0 {
264		if j := c.f.boxes[c.b].j; c.k < j {
265			nn := copy(buf, c.f.text[c.k:j])
266			buf = buf[nn:]
267			n += nn
268			c.pos += int32(nn)
269			c.k += int32(nn)
270		}
271		// A Caret can't be placed at the end of a Paragraph, unless it is the
272		// final Paragraph. A simple way to enforce this is to lean forwards.
273		if c.leanForwards() == leanFailedEOF {
274			break
275		}
276	}
277	if int(c.pos) == c.f.len {
278		err = io.EOF
279	}
280	return n, err
281}
282
283// ReadByte returns the next byte after the Caret and increments the Caret.
284func (c *Caret) ReadByte() (x byte, err error) {
285	c.calculatePLBK()
286	for {
287		if j := c.f.boxes[c.b].j; c.k < j {
288			x = c.f.text[c.k]
289			c.pos++
290			c.k++
291			// A Caret can't be placed at the end of a Paragraph, unless it is
292			// the final Paragraph. A simple way to enforce this is to lean
293			// forwards.
294			c.leanForwards()
295			return x, nil
296		}
297		if c.leanForwards() == leanFailedEOF {
298			return 0, io.EOF
299		}
300	}
301}
302
303// ReadRune returns the next rune after the Caret and increments the Caret.
304func (c *Caret) ReadRune() (r rune, size int, err error) {
305	c.calculatePLBK()
306	for {
307		if c.k < c.f.boxes[c.b].j {
308			r, size, c.b, c.k = c.f.readRune(c.b, c.k)
309			c.pos += int32(size)
310			// A Caret can't be placed at the end of a Paragraph, unless it is
311			// the final Paragraph. A simple way to enforce this is to lean
312			// forwards.
313			c.leanForwards()
314			return r, size, nil
315		}
316		if c.leanForwards() == leanFailedEOF {
317			return 0, 0, io.EOF
318		}
319	}
320}
321
322// WriteByte inserts x into the Frame's text at the Caret and increments the
323// Caret.
324func (c *Caret) WriteByte(x byte) error {
325	c.tmp[0] = x
326	return c.write(c.tmp[:1], "")
327}
328
329// WriteRune inserts r into the Frame's text at the Caret and increments the
330// Caret.
331func (c *Caret) WriteRune(r rune) (size int, err error) {
332	size = utf8.EncodeRune(c.tmp[:], r)
333	if err = c.write(c.tmp[:size], ""); err != nil {
334		return 0, err
335	}
336	return size, nil
337}
338
339// WriteString inserts s into the Frame's text at the Caret and increments the
340// Caret.
341func (c *Caret) WriteString(s string) (n int, err error) {
342	for len(s) > 0 {
343		i := 1 + strings.IndexByte(s, '\n')
344		if i == 0 {
345			i = len(s)
346		}
347		if err = c.write(nil, s[:i]); err != nil {
348			break
349		}
350		n += i
351		s = s[i:]
352	}
353	return n, err
354}
355
356// Write inserts s into the Frame's text at the Caret and increments the Caret.
357func (c *Caret) Write(s []byte) (n int, err error) {
358	for len(s) > 0 {
359		i := 1 + bytes.IndexByte(s, '\n')
360		if i == 0 {
361			i = len(s)
362		}
363		if err = c.write(s[:i], ""); err != nil {
364			break
365		}
366		n += i
367		s = s[i:]
368	}
369	return n, err
370}
371
372// write inserts a []byte or string into the Frame's text at the Caret.
373//
374// Exactly one of s0 and s1 must be non-empty. That non-empty argument must
375// contain at most one '\n' and if it does contain one, it must be the final
376// byte.
377func (c *Caret) write(s0 []byte, s1 string) error {
378	if m := maxLen - len(c.f.text); len(s0) > m || len(s1) > m {
379		return errors.New("text: insufficient space for writing")
380	}
381
382	// Ensure that the Caret is at the end of its Box, and that Box's text is
383	// at the end of the Frame's buffer.
384	c.calculatePLBK()
385	for {
386		bb, n := &c.f.boxes[c.b], int32(len(c.f.text))
387		if c.k == bb.j && c.k == n {
388			break
389		}
390
391		// If the Box's text is empty, move its empty i:j range to the
392		// equivalent empty range at the end of c.f.text.
393		if bb.i == bb.j {
394			bb.i = n
395			bb.j = n
396			for _, cc := range c.f.carets {
397				if cc.b == c.b {
398					cc.k = n
399				}
400			}
401			continue
402		}
403
404		// Make the Caret be at the end of its Box.
405		if c.k != bb.j {
406			c.splitBox(true)
407			continue
408		}
409
410		// Make a new empty Box and move the Caret to it.
411		c.splitBox(true)
412		c.leanForwards()
413	}
414
415	c.f.invalidateCaches()
416	c.f.paragraphs[c.p].invalidateCaches()
417	c.f.lines[c.l].invalidateCaches()
418
419	length, nl := len(s0), false
420	if length > 0 {
421		nl = s0[length-1] == '\n'
422		c.f.text = append(c.f.text, s0...)
423	} else {
424		length = len(s1)
425		nl = s1[length-1] == '\n'
426		c.f.text = append(c.f.text, s1...)
427	}
428	c.f.len += length
429	c.f.boxes[c.b].j += int32(length)
430	c.k += int32(length)
431	for _, cc := range c.f.carets {
432		if cc.pos > c.pos {
433			cc.pos += int32(length)
434		}
435	}
436	c.pos += int32(length)
437	oldL := c.l
438
439	if nl {
440		breakParagraph(c.f, c.p, c.l, c.b)
441		c.p = c.f.paragraphs[c.p].next
442		c.l = c.f.paragraphs[c.p].firstL
443		c.b = c.f.lines[c.l].firstB
444		c.k = c.f.boxes[c.b].i
445	}
446
447	// TODO: re-layout the new c.p paragraph, if we saw '\n'.
448	layout(c.f, oldL)
449
450	c.f.seqNum++
451	return nil
452}
453
454// breakParagraph breaks the Paragraph p into two Paragraphs, just after Box b
455// in Line l in Paragraph p. b's text must end with a '\n'. The new Paragraph
456// is inserted after p.
457func breakParagraph(f *Frame, p, l, b int32) {
458	// Assert that the Box b's text ends with a '\n'.
459	if j := f.boxes[b].j; j == 0 || f.text[j-1] != '\n' {
460		panic("text: invalid state")
461	}
462
463	// Make a new, empty Paragraph after this Paragraph p.
464	newP, _ := f.newParagraph()
465	nextP := f.paragraphs[p].next
466	if nextP != 0 {
467		f.paragraphs[nextP].prev = newP
468	}
469	f.paragraphs[newP].next = nextP
470	f.paragraphs[newP].prev = p
471	f.paragraphs[p].next = newP
472
473	// Any Lines in this Paragraph after the break point's Line l move to the
474	// newP Paragraph.
475	if nextL := f.lines[l].next; nextL != 0 {
476		f.lines[l].next = 0
477		f.lines[nextL].prev = 0
478		f.paragraphs[newP].firstL = nextL
479	}
480
481	// Any Boxes in this Line after the break point's Box b move to a new Line
482	// at the start of the newP Paragraph.
483	if nextB := f.boxes[b].next; nextB != 0 {
484		f.boxes[b].next = 0
485		f.boxes[nextB].prev = 0
486		newL, _ := f.newLine()
487		f.lines[newL].firstB = nextB
488		if newPFirstL := f.paragraphs[newP].firstL; newPFirstL != 0 {
489			f.lines[newL].next = newPFirstL
490			f.lines[newPFirstL].prev = newL
491		}
492		f.paragraphs[newP].firstL = newL
493	}
494
495	// Make the newP Paragraph's first Line and first Box explicit, since
496	// Carets require an explicit p, l and b.
497	{
498		pp := &f.paragraphs[newP]
499		if pp.firstL == 0 {
500			pp.firstL, _ = f.newLine()
501		}
502		ll := &f.lines[pp.firstL]
503		if ll.firstB == 0 {
504			ll.firstB, _ = f.newBox()
505		}
506	}
507
508	// TODO: re-layout the newP paragraph.
509}
510
511// breakLine breaks the Line l at text index k in Box b. The b-and-k index must
512// not be at the start or end of the Line. Text to the right of b-and-k in the
513// Line l will be moved to the start of the next Line in the Paragraph, with
514// that next Line being created if it didn't already exist.
515func breakLine(f *Frame, l, b, k int32) {
516	// Split this Box into two if necessary, so that k equals a Box's j end.
517	bb := &f.boxes[b]
518	if k != bb.j {
519		if k == bb.i {
520			panic("TODO: degenerate split left, possibly adjusting the Line's firstB??")
521		}
522		newB, realloc := f.newBox()
523		if realloc {
524			bb = &f.boxes[b]
525		}
526		nextB := bb.next
527		if nextB != 0 {
528			f.boxes[nextB].prev = newB
529		}
530		f.boxes[newB].next = nextB
531		f.boxes[newB].prev = b
532		f.boxes[newB].i = k
533		f.boxes[newB].j = bb.j
534		bb.next = newB
535		bb.j = k
536	}
537
538	// Assert that the break point isn't already at the start or end of the Line.
539	if bb.next == 0 || (bb.prev == 0 && k == bb.i) {
540		panic("text: invalid state")
541	}
542
543	// Insert a line after this one, if one doesn't already exist.
544	ll := &f.lines[l]
545	if ll.next == 0 {
546		newL, realloc := f.newLine()
547		if realloc {
548			ll = &f.lines[l]
549		}
550		f.lines[newL].prev = l
551		ll.next = newL
552	}
553
554	// Move the remaining boxes to the next line.
555	nextB, nextL := bb.next, ll.next
556	bb.next = 0
557	f.boxes[nextB].prev = 0
558	fb := f.lines[nextL].firstB
559	f.lines[nextL].firstB = nextB
560
561	// If the next Line already contained Boxes, append them to the end of the
562	// nextB chain, and join the two newly linked Boxes if possible.
563	if fb != 0 {
564		lb := f.lines[nextL].lastBox(f)
565		lbb := &f.boxes[lb]
566		fbb := &f.boxes[fb]
567		lbb.next = fb
568		fbb.prev = lb
569		f.joinBoxes(lb, fb, lbb, fbb)
570	}
571}
572
573// layout inserts a soft return in the Line l if its text measures longer than
574// f.maxWidth and a suitable line break point is found. This may spill text
575// onto the next line, which will also be laid out, and so on recursively.
576func layout(f *Frame, l int32) {
577	if f.maxWidth <= 0 || f.face == nil {
578		return
579	}
580	f.seqNum++
581
582	for ; l != 0; l = f.lines[l].next {
583		var (
584			firstB     = f.lines[l].firstB
585			reader     = f.lineReader(firstB, f.boxes[firstB].i)
586			breakPoint bAndK
587			prevR      rune
588			prevRValid bool
589			advance    fixed.Int26_6
590		)
591		for {
592			r, _, err := reader.ReadRune()
593			if err != nil || r == '\n' {
594				return
595			}
596			if prevRValid {
597				advance += f.face.Kern(prevR, r)
598			}
599			// TODO: match all whitespace, not just ' '?
600			if r == ' ' {
601				breakPoint = reader.bAndK()
602			}
603			a, ok := f.face.GlyphAdvance(r)
604			if !ok {
605				panic("TODO: is falling back on the U+FFFD glyph the responsibility of the caller or the Face?")
606			}
607			advance += a
608			if r != ' ' && advance > f.maxWidth && breakPoint.b != 0 {
609				breakLine(f, l, breakPoint.b, breakPoint.k)
610				break
611			}
612			prevR, prevRValid = r, true
613		}
614	}
615}
616
617// Delete deletes nBytes bytes in the specified direction from the Caret's
618// location. It returns the number of bytes deleted, which can be fewer than
619// that requested if it hits the beginning or end of the Frame.
620func (c *Caret) Delete(dir Direction, nBytes int) (dBytes int) {
621	if nBytes <= 0 {
622		return 0
623	}
624
625	// Convert a backwards delete of n bytes from position p to a forwards
626	// delete of n bytes from position p-n.
627	//
628	// In general, it's easier to delete forwards than backwards. For example,
629	// when crossing paragraph boundaries, it's easier to find the first line
630	// of the next paragraph than the last line of the previous paragraph.
631	if dir == Backwards {
632		newPos := int(c.pos) - nBytes
633		if newPos < 0 {
634			newPos = 0
635			nBytes = int(c.pos)
636			if nBytes == 0 {
637				return 0
638			}
639		}
640		c.seek(int32(newPos))
641	}
642
643	if int(c.pos) == c.f.len {
644		return 0
645	}
646
647	c.calculatePLBK()
648	c.leanForwards()
649	if c.f.boxes[c.b].i != c.k && c.splitBox(false) {
650		c.leanForwards()
651	}
652	for nBytes > 0 && int(c.pos) != c.f.len {
653		bb := &c.f.boxes[c.b]
654		n := bb.j - bb.i
655		newLine := n != 0 && c.f.text[bb.j-1] == '\n'
656		if int(n) > nBytes {
657			n = int32(nBytes)
658		}
659		bb.i += n
660		c.k += n
661		dBytes += int(n)
662		nBytes -= int(n)
663		c.f.len -= int(n)
664
665		if bb.i != bb.j {
666			break
667		}
668
669		if newLine {
670			c.joinNextParagraph()
671		}
672		c.leanForwards()
673	}
674
675	// The mergeIntoOneLine will shake out any empty Boxes.
676	l := c.f.mergeIntoOneLine(c.p)
677	layout(c.f, l)
678	c.f.invalidateCaches()
679
680	// Compact c.f.text if it's large enough and the fraction of deleted text
681	// is above some threshold. The actual threshold value (25%) is arbitrary.
682	// A lower value means more frequent compactions, so less memory on average
683	// but more CPU. A higher value means the opposite.
684	if len(c.f.text) > 4096 && len(c.f.text)/4 < c.f.deletedLen() {
685		c.f.compactText()
686	}
687
688	c.f.seqNum++
689	for _, cc := range c.f.carets {
690		if cc == c {
691			continue
692		}
693		switch relPos := cc.pos - c.pos; {
694		case relPos <= 0:
695			// No-op.
696		case relPos <= int32(dBytes):
697			cc.pos = c.pos
698		default:
699			cc.pos -= int32(dBytes)
700		}
701	}
702	return dBytes
703}
704
705// DeleteRunes deletes nRunes runes in the specified direction from the Caret's
706// location. It returns the number of runes and bytes deleted, which can be
707// fewer than that requested if it hits the beginning or end of the Frame.
708func (c *Caret) DeleteRunes(dir Direction, nRunes int) (dRunes, dBytes int) {
709	// Save the current Caret position, move the Caret by nRunes runes to
710	// calculate how many bytes to delete, restore that saved Caret position,
711	// then delete that many bytes.
712	c.calculatePLBK()
713	savedC := *c
714	if dir == Forwards {
715		for dRunes < nRunes {
716			var size int
717			_, size, c.b, c.k = c.f.readRune(c.b, c.k)
718			if size != 0 {
719				dRunes++
720				dBytes += size
721			} else if c.leanForwards() != leanOK {
722				break
723			}
724		}
725	} else {
726		for dRunes < nRunes {
727			var size int
728			_, size, c.b, c.k = c.f.readLastRune(c.b, c.k)
729			if size != 0 {
730				dRunes++
731				dBytes += size
732			} else if c.leanBackwards() != leanOK {
733				break
734			}
735		}
736	}
737	*c = savedC
738	if dBytes != c.Delete(dir, dBytes) {
739		panic("text: invalid state")
740	}
741	return dRunes, dBytes
742}
743
744// joinNextParagraph joins c's current and next Paragraph. That next Paragraph
745// must exist, and c must be at the last Line of its current Paragraph.
746func (c *Caret) joinNextParagraph() {
747	pp0 := &c.f.paragraphs[c.p]
748	ll0 := &c.f.lines[c.l]
749	if pp0.next == 0 || ll0.next != 0 {
750		panic("text: invalid state")
751	}
752	pp1 := &c.f.paragraphs[pp0.next]
753	l1 := pp1.firstL
754
755	ll0.next = l1
756	c.f.lines[l1].prev = c.l
757
758	toFree := pp0.next
759	pp0.next = pp1.next
760	if pp0.next != 0 {
761		c.f.paragraphs[pp0.next].prev = c.p
762	}
763
764	c.f.freeParagraph(toFree)
765}
766
767// splitBox splits the Caret's Box into two, at the Caret's location. Unless
768// force is set, it does nothing if the Caret is at either edge of its Box. It
769// returns whether the Box was split. If so, the new Box is created after, not
770// before, the Caret's current Box.
771func (c *Caret) splitBox(force bool) bool {
772	bb := &c.f.boxes[c.b]
773	if !force && (c.k == bb.i || c.k == bb.j) {
774		return false
775	}
776	newB, realloc := c.f.newBox()
777	if realloc {
778		bb = &c.f.boxes[c.b]
779	}
780	nextB := bb.next
781	if nextB != 0 {
782		c.f.boxes[nextB].prev = newB
783	}
784	c.f.boxes[newB] = Box{
785		next: nextB,
786		prev: c.b,
787		i:    c.k,
788		j:    bb.j,
789	}
790	bb.next = newB
791	bb.j = c.k
792	return true
793}
794