examples: support unicode in the text_editor.v buffer (#13269)

pull/13275/head
Larpon 2022-01-25 14:39:35 +01:00 committed by GitHub
parent 28ddd8440a
commit 95d86324c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 55 additions and 31 deletions

View File

@ -6,6 +6,9 @@ import strings
import os import os
import math import math
import term.ui as tui import term.ui as tui
import encoding.utf8
const rune_digits = [`0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`]
enum Movement { enum Movement {
up up
@ -131,7 +134,7 @@ fn (b Buffer) raw() string {
} }
fn (b Buffer) view(from int, to int) View { fn (b Buffer) view(from int, to int) View {
l := b.cur_line() l := b.cur_line().runes()
mut x := 0 mut x := 0
for i := 0; i < b.cursor.pos_x && i < l.len; i++ { for i := 0; i < b.cursor.pos_x && i < l.len; i++ {
if l[i] == `\t` { if l[i] == `\t` {
@ -174,7 +177,7 @@ fn (b Buffer) cursor_index() int {
i += b.cursor.pos_x i += b.cursor.pos_x
break break
} }
i += line.len + 1 i += line.runes().len + 1
} }
return i return i
} }
@ -185,22 +188,22 @@ fn (mut b Buffer) put(s string) {
if b.lines.len == 0 { if b.lines.len == 0 {
b.lines.prepend('') b.lines.prepend('')
} }
line := b.lines[y] line := b.lines[y].runes()
l, r := line[..x], line[x..] l, r := line[..x].string(), line[x..].string()
if has_line_ending { if has_line_ending {
mut lines := s.split('\n') mut lines := s.split('\n')
lines[0] = l + lines[0] lines[0] = l + lines[0]
lines[lines.len - 1] += r lines[lines.len - 1] += r
b.lines.delete(y) b.lines.delete(y)
b.lines.insert(y, lines) b.lines.insert(y, lines)
last := lines[lines.len - 1] last := lines[lines.len - 1].runes()
b.cursor.set(last.len, y + lines.len - 1) b.cursor.set(last.len, y + lines.len - 1)
if s == '\n' { if s == '\n' {
b.cursor.set(0, b.cursor.pos_y) b.cursor.set(0, b.cursor.pos_y)
} }
} else { } else {
b.lines[y] = l + s + r b.lines[y] = l + s + r
b.cursor.set(x + s.len, y) b.cursor.set(x + s.runes().len, y)
} }
$if debug { $if debug {
flat := s.replace('\n', r'\n') flat := s.replace('\n', r'\n')
@ -217,24 +220,35 @@ fn (mut b Buffer) del(amount int) string {
if x == 0 && y == 0 { if x == 0 && y == 0 {
return '' return ''
} }
} else if x >= b.cur_line().len && y >= b.lines.len - 1 { } else if x >= b.cur_line().runes().len && y >= b.lines.len - 1 {
return '' return ''
} }
mut removed := '' mut removed := ''
if amount < 0 { // backspace (backward) if amount < 0 { // backspace (backward)
i := b.cursor_index() i := b.cursor_index()
removed = b.raw()[i + amount..i] raw_runes := b.raw().runes()
removed = raw_runes[i + amount..i].string()
mut left := amount * -1 mut left := amount * -1
for li := y; li >= 0 && left > 0; li-- { for li := y; li >= 0 && left > 0; li-- {
ln := b.lines[li] ln := b.lines[li].runes()
if left > ln.len { if left == ln.len + 1 { // All of the line + 1 - since we're going backwards the "+1" is the line break delimiter.
b.lines.delete(li)
left = 0
if y == 0 {
return ''
}
line_above := b.lines[li - 1].runes()
b.cursor.pos_x = line_above.len
b.cursor.pos_y--
break
} else if left > ln.len {
b.lines.delete(li) b.lines.delete(li)
if ln.len == 0 { // line break delimiter if ln.len == 0 { // line break delimiter
left-- left--
if y == 0 { if y == 0 {
return '' return ''
} }
line_above := b.lines[li - 1] line_above := b.lines[li - 1].runes()
b.cursor.pos_x = line_above.len b.cursor.pos_x = line_above.len
} else { } else {
left -= ln.len left -= ln.len
@ -245,22 +259,23 @@ fn (mut b Buffer) del(amount int) string {
if y == 0 { if y == 0 {
return '' return ''
} }
line_above := b.lines[li - 1] line_above := b.lines[li - 1].runes()
if ln.len == 0 { // at line break if ln.len == 0 { // at line break
b.lines.delete(li) b.lines.delete(li)
b.cursor.pos_y-- b.cursor.pos_y--
b.cursor.pos_x = line_above.len b.cursor.pos_x = line_above.len
} else { } else {
b.lines[li - 1] = line_above + ln b.lines[li - 1] = line_above.string() + ln.string()
b.lines.delete(li) b.lines.delete(li)
b.cursor.pos_y-- b.cursor.pos_y--
b.cursor.pos_x = line_above.len b.cursor.pos_x = line_above.len
} }
} else if x == 1 { } else if x == 1 {
b.lines[li] = b.lines[li][left..] runes := b.lines[li].runes()
b.lines[li] = runes[left..].string()
b.cursor.pos_x = 0 b.cursor.pos_x = 0
} else { } else {
b.lines[li] = ln[..x - left] + ln[x..] b.lines[li] = ln[..x - left].string() + ln[x..].string()
b.cursor.pos_x -= left b.cursor.pos_x -= left
} }
left = 0 left = 0
@ -269,13 +284,20 @@ fn (mut b Buffer) del(amount int) string {
} }
} else { // delete (forward) } else { // delete (forward)
i := b.cursor_index() + 1 i := b.cursor_index() + 1
removed = b.raw()[i - amount..i] raw_buffer := b.raw().runes()
from_i := i
mut to_i := i + amount
if to_i > raw_buffer.len {
to_i = raw_buffer.len
}
removed = raw_buffer[from_i..to_i].string()
mut left := amount mut left := amount
for li := y; li >= 0 && left > 0; li++ { for li := y; li >= 0 && left > 0; li++ {
ln := b.lines[li] ln := b.lines[li].runes()
if x == ln.len { // at line end if x == ln.len { // at line end
if y + 1 <= b.lines.len { if y + 1 <= b.lines.len {
b.lines[li] = ln + b.lines[y + 1] b.lines[li] = ln.string() + b.lines[y + 1]
b.lines.delete(y + 1) b.lines.delete(y + 1)
left-- left--
b.del(left) b.del(left)
@ -284,7 +306,7 @@ fn (mut b Buffer) del(amount int) string {
b.lines.delete(li) b.lines.delete(li)
left -= ln.len left -= ln.len
} else { } else {
b.lines[li] = ln[..x] + ln[x + left..] b.lines[li] = ln[..x].string() + ln[x + left..].string()
left = 0 left = 0
} }
} }
@ -309,7 +331,7 @@ fn (mut b Buffer) free() {
fn (mut b Buffer) move_updown(amount int) { fn (mut b Buffer) move_updown(amount int) {
b.cursor.move(0, amount) b.cursor.move(0, amount)
// Check the move // Check the move
line := b.cur_line() line := b.cur_line().runes()
if b.cursor.pos_x > line.len { if b.cursor.pos_x > line.len {
b.cursor.set(line.len, b.cursor.pos_y) b.cursor.set(line.len, b.cursor.pos_y)
} }
@ -317,7 +339,7 @@ fn (mut b Buffer) move_updown(amount int) {
// move_cursor will navigate the cursor within the buffer bounds // move_cursor will navigate the cursor within the buffer bounds
fn (mut b Buffer) move_cursor(amount int, movement Movement) { fn (mut b Buffer) move_cursor(amount int, movement Movement) {
cur_line := b.cur_line() cur_line := b.cur_line().runes()
match movement { match movement {
.up { .up {
if b.cursor.pos_y - amount >= 0 { if b.cursor.pos_y - amount >= 0 {
@ -341,7 +363,7 @@ fn (mut b Buffer) move_cursor(amount int, movement Movement) {
if b.cursor.pos_x - amount >= 0 { if b.cursor.pos_x - amount >= 0 {
b.cursor.move(-amount, 0) b.cursor.move(-amount, 0)
} else if b.cursor.pos_y > 0 { } else if b.cursor.pos_y > 0 {
b.cursor.set(b.line(b.cursor.pos_y - 1).len, b.cursor.pos_y - 1) b.cursor.set(b.line(b.cursor.pos_y - 1).runes().len, b.cursor.pos_y - 1)
} }
} }
.right { .right {
@ -362,25 +384,26 @@ fn (mut b Buffer) move_cursor(amount int, movement Movement) {
fn (mut b Buffer) move_to_word(movement Movement) { fn (mut b Buffer) move_to_word(movement Movement) {
a := if movement == .left { -1 } else { 1 } a := if movement == .left { -1 } else { 1 }
mut line := b.cur_line()
mut line := b.cur_line().runes()
mut x, mut y := b.cursor.pos_x, b.cursor.pos_y mut x, mut y := b.cursor.pos_x, b.cursor.pos_y
if x + a < 0 && y > 0 { if x + a < 0 && y > 0 {
y-- y--
line = b.line(b.cursor.pos_y - 1) line = b.line(b.cursor.pos_y - 1).runes()
x = line.len x = line.len
} else if x + a >= line.len && y + 1 < b.lines.len { } else if x + a >= line.len && y + 1 < b.lines.len {
y++ y++
line = b.line(b.cursor.pos_y + 1) line = b.line(b.cursor.pos_y + 1).runes()
x = 0 x = 0
} }
// first, move past all non-`a-zA-Z0-9_` characters // first, move past all non-`a-zA-Z0-9_` characters
for x + a >= 0 && x + a < line.len && !(line[x + a].is_letter() for x + a >= 0 && x + a < line.len && !(utf8.is_letter(line[x + a])
|| line[x + a].is_digit() || line[x + a] == `_`) { || line[x + a] in rune_digits || line[x + a] == `_`) {
x += a x += a
} }
// then, move past all the letters and numbers // then, move past all the letters and numbers
for x + a >= 0 && x + a < line.len && (line[x + a].is_letter() for x + a >= 0 && x + a < line.len && (utf8.is_letter(line[x + a])
|| line[x + a].is_digit() || line[x + a] == `_`) { || line[x + a] in rune_digits || line[x + a] == `_`) {
x += a x += a
} }
// if the cursor is out of bounds, move it to the next/previous line // if the cursor is out of bounds, move it to the next/previous line
@ -457,7 +480,7 @@ fn (a &App) view_height() int {
fn (mut a App) magnet_cursor_x() { fn (mut a App) magnet_cursor_x() {
mut buffer := a.ed mut buffer := a.ed
if buffer.cursor.pos_x < a.magnet_x { if buffer.cursor.pos_x < a.magnet_x {
if a.magnet_x < buffer.cur_line().len { if a.magnet_x < buffer.cur_line().runes().len {
move_x := a.magnet_x - buffer.cursor.pos_x move_x := a.magnet_x - buffer.cursor.pos_x
buffer.move_cursor(move_x, .right) buffer.move_cursor(move_x, .right)
} }
@ -555,7 +578,8 @@ fn event(e &tui.Event, x voidptr) {
return return
} }
} }
buffer.put(e.utf8.bytes().bytestr())
buffer.put(e.utf8)
} }
} }
} else if e.typ == .mouse_scroll { } else if e.typ == .mouse_scroll {