123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- // SPDX-License-Identifier: Unlicense OR MIT
- package app
- import (
- "unicode"
- "unicode/utf16"
- "gioui.org/io/input"
- "gioui.org/io/key"
- )
- type editorState struct {
- input.EditorState
- compose key.Range
- }
- func (e *editorState) Replace(r key.Range, text string) {
- if r.Start > r.End {
- r.Start, r.End = r.End, r.Start
- }
- runes := []rune(text)
- newEnd := r.Start + len(runes)
- adjust := func(pos int) int {
- switch {
- case newEnd < pos && pos <= r.End:
- return newEnd
- case r.End < pos:
- diff := newEnd - r.End
- return pos + diff
- }
- return pos
- }
- e.Selection.Start = adjust(e.Selection.Start)
- e.Selection.End = adjust(e.Selection.End)
- if e.compose.Start != -1 {
- e.compose.Start = adjust(e.compose.Start)
- e.compose.End = adjust(e.compose.End)
- }
- s := e.Snippet
- if r.End < s.Start || r.Start > s.End {
- // Discard snippet if it doesn't overlap with replacement.
- s = key.Snippet{
- Range: key.Range{
- Start: r.Start,
- End: r.Start,
- },
- }
- }
- var newSnippet []rune
- snippet := []rune(s.Text)
- // Append first part of existing snippet.
- if end := r.Start - s.Start; end > 0 {
- newSnippet = append(newSnippet, snippet[:end]...)
- }
- // Append replacement.
- newSnippet = append(newSnippet, runes...)
- // Append last part of existing snippet.
- if start := r.End; start < s.End {
- newSnippet = append(newSnippet, snippet[start-s.Start:]...)
- }
- // Adjust snippet range to include replacement.
- if r.Start < s.Start {
- s.Start = r.Start
- }
- s.End = s.Start + len(newSnippet)
- s.Text = string(newSnippet)
- e.Snippet = s
- }
- // UTF16Index converts the given index in runes into an index in utf16 characters.
- func (e *editorState) UTF16Index(runes int) int {
- if runes == -1 {
- return -1
- }
- if runes < e.Snippet.Start {
- // Assume runes before sippet are one UTF-16 character each.
- return runes
- }
- chars := e.Snippet.Start
- runes -= e.Snippet.Start
- for _, r := range e.Snippet.Text {
- if runes == 0 {
- break
- }
- runes--
- chars++
- if r1, _ := utf16.EncodeRune(r); r1 != unicode.ReplacementChar {
- chars++
- }
- }
- // Assume runes after snippets are one UTF-16 character each.
- return chars + runes
- }
- // RunesIndex converts the given index in utf16 characters to an index in runes.
- func (e *editorState) RunesIndex(chars int) int {
- if chars == -1 {
- return -1
- }
- if chars < e.Snippet.Start {
- // Assume runes before offset are one UTF-16 character each.
- return chars
- }
- runes := e.Snippet.Start
- chars -= e.Snippet.Start
- for _, r := range e.Snippet.Text {
- if chars == 0 {
- break
- }
- chars--
- runes++
- if r1, _ := utf16.EncodeRune(r); r1 != unicode.ReplacementChar {
- chars--
- }
- }
- // Assume runes after snippets are one UTF-16 character each.
- return runes + chars
- }
|