forked from c-bata/go-prompt
-
Notifications
You must be signed in to change notification settings - Fork 2
/
position.go
109 lines (93 loc) · 1.92 KB
/
position.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package prompt
import (
istrings "github.com/elk-language/go-prompt/strings"
"github.com/rivo/uniseg"
)
// Position stores the coordinates
// of a p.
//
// (0, 0) represents the top-left corner of the prompt,
// while (n, n) the bottom-right corner.
type Position struct {
X istrings.Width
Y int
}
// Join two positions and return a new position.
func (p Position) Join(other Position) Position {
if other.Y == 0 {
p.X += other.X
} else {
p.X = other.X
p.Y += other.Y
}
return p
}
// Add two positions and return a new position.
func (p Position) Add(other Position) Position {
return Position{
X: p.X + other.X,
Y: p.Y + other.Y,
}
}
// Subtract two positions and return a new position.
func (p Position) Subtract(other Position) Position {
return Position{
X: p.X - other.X,
Y: p.Y - other.Y,
}
}
// positionAtEndOfString calculates the position of the
// p at the end of the given string.
func positionAtEndOfStringLine(str string, columns istrings.Width, line int) Position {
var down int
var right istrings.Width
g := uniseg.NewGraphemes(str)
charLoop:
for g.Next() {
runes := g.Runes()
if len(runes) == 1 && runes[0] == '\n' {
if down == line {
break charLoop
}
down++
right = 0
}
right += istrings.Width(g.Width())
if right > columns {
if down == line {
right = columns - 1
break charLoop
}
right = istrings.Width(g.Width())
down++
}
}
return Position{
X: right,
Y: down,
}
}
// positionAtEndOfString calculates the position
// at the end of the given string.
func positionAtEndOfString(str string, columns istrings.Width) Position {
var down int
var right istrings.Width
g := uniseg.NewGraphemes(str)
for g.Next() {
runes := g.Runes()
if len(runes) == 1 && runes[0] == '\n' {
down++
right = 0
continue
}
right += istrings.Width(g.Width())
if right == columns {
right = 0
down++
}
}
return Position{
X: right,
Y: down,
}
}