src

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

cursor.go (3479B)


      1 package buffer
      2 
      3 import (
      4 	"unicode/utf8"
      5 
      6 	"code.dwrz.net/src/pkg/editor/buffer/glyph"
      7 )
      8 
      9 type Cursor struct {
     10 	glyph int
     11 	index int
     12 	line  int
     13 }
     14 
     15 func (b *Buffer) Cursor() Cursor {
     16 	return *b.cursor
     17 }
     18 
     19 func (c Cursor) Glyph() int {
     20 	return c.glyph
     21 }
     22 
     23 func (c Cursor) Index() int {
     24 	return c.index
     25 }
     26 
     27 func (c Cursor) Line() int {
     28 	return c.line
     29 }
     30 
     31 func (b *Buffer) CursorDown() {
     32 	b.log.Debug.Printf("↓ before: %#v", b.cursor)
     33 	defer b.log.Debug.Printf("↓ after: %#v", b.cursor)
     34 
     35 	// If we're on the last line, don't move down.
     36 	if b.cursor.line >= len(b.lines)-1 {
     37 		return
     38 	}
     39 
     40 	// Move to the next line.
     41 	b.cursor.line++
     42 
     43 	// Adjust the column.
     44 	var (
     45 		line   = b.CursorLine()
     46 		length = line.Length()
     47 		width  = line.Width()
     48 	)
     49 	switch {
     50 	// If we've moved to a shorter line, snap to its end.
     51 	case b.cursor.glyph > width:
     52 		b.cursor.index = length
     53 		b.cursor.glyph = width
     54 
     55 	default:
     56 		b.cursor.index, b.cursor.glyph = line.FindGlyphIndex(
     57 			b.cursor.glyph,
     58 		)
     59 	}
     60 }
     61 
     62 func (b *Buffer) CursorLeft() {
     63 	b.log.Debug.Printf("← before: %#v", b.cursor)
     64 	defer b.log.Debug.Printf("← after: %#v", b.cursor)
     65 
     66 	switch {
     67 	// If we're at the beginning of the line, move to the line above;
     68 	// unless we're at the start of the buffer.
     69 	case b.cursor.index == 0 && b.cursor.line > 0:
     70 		b.cursor.line--
     71 
     72 		line := b.CursorLine()
     73 		b.cursor.index = line.Length()
     74 		b.cursor.glyph = line.Width()
     75 
     76 	// Move left by one rune.
     77 	case b.cursor.index > 0:
     78 		var (
     79 			line = b.CursorLine()
     80 			r    rune
     81 			size int
     82 		)
     83 		// Reverse until we hit the start of a rune.
     84 		for i := b.cursor.index - 1; i >= 0; i-- {
     85 			r, size = line.DecodeRune(i)
     86 			if r != utf8.RuneError {
     87 				b.cursor.index -= size
     88 				b.cursor.glyph -= glyph.Width(r)
     89 				break
     90 			}
     91 		}
     92 	}
     93 }
     94 
     95 func (b *Buffer) CursorRight() {
     96 	b.log.Debug.Printf("→ before: %#v", b.cursor)
     97 	defer b.log.Debug.Printf("→ after: %#v", b.cursor)
     98 
     99 	var (
    100 		line   = b.CursorLine()
    101 		length = line.Length()
    102 	)
    103 
    104 	switch {
    105 	// If we're at the end of the line, move to the line below;
    106 	// unless we're at the end of the buffer.
    107 	case b.cursor.index == length && b.cursor.line < len(b.lines)-1:
    108 		b.cursor.line++
    109 		b.cursor.index = 0
    110 		b.cursor.glyph = 0
    111 
    112 	// Move the index right by one rune.
    113 	case b.cursor.index < length:
    114 		r, size := line.DecodeRune(b.cursor.index)
    115 		if r == utf8.RuneError {
    116 			b.cursor.index++
    117 			b.cursor.glyph += glyph.Width(r)
    118 		}
    119 
    120 		b.cursor.index += size
    121 		b.cursor.glyph += glyph.Width(r)
    122 	}
    123 }
    124 
    125 func (b *Buffer) CursorUp() {
    126 	b.log.Debug.Printf("↑ before: %#v", b.cursor)
    127 	defer b.log.Debug.Printf("↑ after: %#v", b.cursor)
    128 
    129 	// If we're on the first line, don't move up.
    130 	if b.cursor.line == 0 {
    131 		return
    132 	}
    133 
    134 	b.cursor.line--
    135 
    136 	// Adjust the column.
    137 	var (
    138 		line   = b.CursorLine()
    139 		length = line.Length()
    140 		width  = line.Width()
    141 	)
    142 	switch {
    143 	case b.cursor.glyph > width:
    144 		b.cursor.index = length
    145 		b.cursor.glyph = width
    146 
    147 	default:
    148 		b.cursor.index, b.cursor.glyph = line.FindGlyphIndex(
    149 			b.cursor.glyph,
    150 		)
    151 	}
    152 }
    153 
    154 func (b *Buffer) PageDown(height int) {
    155 	if b.cursor.line+height > len(b.lines) {
    156 		b.cursor.line = len(b.lines) - 1
    157 	} else {
    158 		b.cursor.line += height
    159 	}
    160 }
    161 
    162 func (b *Buffer) PageUp(height int) {
    163 	if b.cursor.line-height > 0 {
    164 		b.cursor.line -= height
    165 	} else {
    166 		b.cursor.line = 0
    167 	}
    168 }
    169 
    170 func (b *Buffer) CursorHome() {
    171 	b.cursor.glyph = 0
    172 	b.cursor.index = 0
    173 }
    174 
    175 func (b *Buffer) CursorEnd() {
    176 	var line = b.CursorLine()
    177 
    178 	b.cursor.index = line.Length()
    179 	b.cursor.glyph = line.Width()
    180 }