7 // The Cursor struct stores the location of the cursor in the view
11 // We need three variables here because we insert text at loc but
12 // display the cursor at x, y
17 // Start of the selection in charNum
20 // We store the x, y of the start because when the user deletes the selection
21 // the cursor needs to go back to the start, and this is the simplest way
25 // End of the selection in charNum
26 // We don't need to store the x, y here because when if the user is selecting backwards
27 // and they delete the selection, the cursor is already in the right place
31 // ResetSelection resets the user's selection
32 func (c *Cursor) ResetSelection() {
37 // HasSelection returns whether or not the user has selected anything
38 func (c *Cursor) HasSelection() bool {
39 return c.selectionEnd != c.selectionStart
42 // DeleteSelection deletes the currently selected text
43 func (c *Cursor) DeleteSelection() {
44 if c.selectionStart > c.selectionEnd {
45 c.v.eh.Remove(c.selectionEnd, c.selectionStart+1)
46 // Since the cursor is already at the selection start we don't need to move
48 c.v.eh.Remove(c.selectionStart, c.selectionEnd+1)
49 c.loc -= c.selectionEnd - c.selectionStart
50 c.x = c.selectionStartX
51 c.y = c.selectionStartY
55 // GetSelection returns the cursor's selection
56 func (c *Cursor) GetSelection() string {
57 if c.selectionStart > c.selectionEnd {
58 return string([]rune(c.v.buf.text)[c.selectionEnd : c.selectionStart+1])
60 return string([]rune(c.v.buf.text)[c.selectionStart : c.selectionEnd+1])
63 // RuneUnder returns the rune under the cursor
64 func (c *Cursor) RuneUnder() rune {
65 line := c.v.buf.lines[c.y]
66 if c.x >= Count(line) {
69 return []rune(line)[c.x]
72 // Up moves the cursor up one line (if possible)
73 func (c *Cursor) Up() {
75 c.loc -= Count(c.v.buf.lines[c.y][:c.x])
80 if c.x > Count(c.v.buf.lines[c.y]) {
81 c.x = Count(c.v.buf.lines[c.y])
84 c.loc -= Count(c.v.buf.lines[c.y][c.x:])
88 // Down moves the cursor down one line (if possible)
89 func (c *Cursor) Down() {
90 if c.y < len(c.v.buf.lines)-1 {
91 c.loc += Count(c.v.buf.lines[c.y][c.x:])
96 if c.x > Count(c.v.buf.lines[c.y]) {
97 c.x = Count(c.v.buf.lines[c.y])
100 c.loc += Count(c.v.buf.lines[c.y][:c.x])
104 // Left moves the cursor left one cell (if possible) or to the last line if it is at the beginning
105 func (c *Cursor) Left() {
118 // Right moves the cursor right one cell (if possible) or to the next line if it is at the end
119 func (c *Cursor) Right() {
120 if c.loc == c.v.buf.Len() {
123 if c.x < Count(c.v.buf.lines[c.y]) {
132 // End moves the cursor to the end of the line it is on
133 func (c *Cursor) End() {
134 c.loc += Count(c.v.buf.lines[c.y][c.x:])
135 c.x = Count(c.v.buf.lines[c.y])
138 // Start moves the cursor to the start of the line it is on
139 func (c *Cursor) Start() {
140 c.loc -= Count(c.v.buf.lines[c.y][:c.x])
144 // GetCharPosInLine gets the char position of a visual x y coordinate (this is necessary because tabs are 1 char but 4 visual spaces)
145 func (c *Cursor) GetCharPosInLine(lineNum, visualPos int) int {
146 visualLine := strings.Replace(c.v.buf.lines[lineNum], "\t", "\t"+EmptyString(tabSize-1), -1)
147 if visualPos > Count(visualLine) {
148 visualPos = Count(visualLine)
150 numTabs := NumOccurences(visualLine[:visualPos], '\t')
151 if visualPos >= (tabSize-1)*numTabs {
152 return visualPos - (tabSize-1)*numTabs
154 return visualPos / tabSize
157 // GetVisualX returns the x value of the cursor in visual spaces
158 func (c *Cursor) GetVisualX() int {
159 return c.x + NumOccurences(c.v.buf.lines[c.y][:c.x], '\t')*(tabSize-1)
162 // Distance returns the distance between the cursor and x, y in runes
163 func (c *Cursor) Distance(x, y int) int {
171 distance += Count(c.v.buf.lines[c.y][c.x:])
176 distance += Count(c.v.buf.lines[c.y+i])
181 if x < Count(c.v.buf.lines[y]) {
182 distance += Count(c.v.buf.lines[y][:x])
184 distance += Count(c.v.buf.lines[y])
189 distance -= Count(c.v.buf.lines[c.y][:c.x])
194 distance -= Count(c.v.buf.lines[c.y-i])
200 distance -= Count(c.v.buf.lines[y][x:])
205 // Display draws the cursor to the screen at the correct position
206 func (c *Cursor) Display() {
207 if c.y-c.v.topline < 0 || c.y-c.v.topline > c.v.height-1 {
210 c.v.s.ShowCursor(c.GetVisualX()+c.v.lineNumOffset, c.y-c.v.topline)
211 // cursorStyle := tcell.StyleDefault.Reverse(true)
212 // c.v.s.SetContent(c.x+voffset, c.y-c.v.topline, c.runeUnder(), nil, cursorStyle)