src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

line.go (1839B)


      1 package line
      2 
      3 import (
      4 	"strings"
      5 	"unicode/utf8"
      6 
      7 	"code.dwrz.net/src/pkg/editor/buffer/glyph"
      8 )
      9 
     10 type Line struct {
     11 	data string
     12 }
     13 
     14 func New(s string) *Line {
     15 	return &Line{data: s}
     16 }
     17 
     18 func (l *Line) DecodeRune(index int) (r rune, size int) {
     19 	return utf8.DecodeRuneInString(l.data[index:])
     20 }
     21 
     22 // GlyphIndex attempts to find the preceding index for a target glyph.
     23 func (l *Line) FindGlyphIndex(target int) (index, g int) {
     24 	var li, lg int
     25 	for i, r := range l.data {
     26 		// We've reached the target.
     27 		if g == target {
     28 
     29 			return i, g
     30 		}
     31 		// We've gone too far.
     32 		// Return the preceding index and glyph.
     33 		if g > target {
     34 			return li, lg
     35 		}
     36 
     37 		// Otherwise, we haven't reached the target.
     38 		// Save this index and glyph.
     39 		li = i
     40 		lg = g
     41 
     42 		// Then increment the glyph.
     43 		g += glyph.Width(r)
     44 	}
     45 	// Target falls in-between the last glyph and the end of the line.
     46 	// Use the last glyph.
     47 	if target >= lg && target < g {
     48 		return li, lg
     49 	}
     50 
     51 	// We weren't able to find the glyph.
     52 	// Return the last possible index and glyph.
     53 	return len(l.data), g
     54 }
     55 
     56 func (l *Line) Length() int {
     57 	return len(l.data)
     58 }
     59 
     60 func (l *Line) Render(offset, width int) string {
     61 	var text = strings.ReplaceAll(l.data, "\t", "        ")
     62 	if offset < 0 || offset > len(text) {
     63 		return ""
     64 	}
     65 
     66 	var str strings.Builder
     67 	for _, r := range text {
     68 		rw := glyph.Width(r)
     69 		if offset > 0 {
     70 			offset -= rw
     71 			continue
     72 		}
     73 		if r == utf8.RuneError {
     74 			continue
     75 		}
     76 
     77 		// Exhausted column zero.
     78 		if width-rw < -1 {
     79 			break
     80 		}
     81 
     82 		str.WriteRune(r)
     83 		width -= rw
     84 	}
     85 
     86 	return str.String()
     87 }
     88 
     89 func (l *Line) Runes() []rune {
     90 	return []rune(l.data)
     91 }
     92 
     93 func (l *Line) String() string {
     94 	return l.data
     95 }
     96 
     97 func (l *Line) Width() (count int) {
     98 	for _, r := range l.data {
     99 		rw := glyph.Width(r)
    100 		if r == utf8.RuneError {
    101 			continue
    102 		}
    103 		count += rw
    104 	}
    105 
    106 	return count
    107 }