Add word selection with double click

This commit is contained in:
Zachary Yedidia
2016-03-28 08:43:08 -04:00
parent 4d9e45bfca
commit a6764a04bc
5 changed files with 127 additions and 26 deletions

View File

@@ -42,7 +42,11 @@ type Cursor struct {
x int x int
y int y int
curSelection [2]int // The current selection as a range of character numbers (inclusive)
curSelection [2]int
// The original selection as a range of character numbers
// This is used for line and word selection where it is necessary
// to know what the original selection was
origSelection [2]int origSelection [2]int
} }
@@ -97,43 +101,93 @@ func (c *Cursor) SelectLine() {
c.End() c.End()
c.curSelection[1] = c.Loc() c.curSelection[1] = c.Loc()
c.origSelection[0] = c.curSelection[0] c.origSelection = c.curSelection
c.origSelection[1] = c.curSelection[1]
} }
// AddLineToSelection adds the current line to the selection // AddLineToSelection adds the current line to the selection
func (c *Cursor) AddLineToSelection() { func (c *Cursor) AddLineToSelection() {
loc := c.Loc() loc := c.Loc()
if loc < c.origSelection[0] {
c.Start()
c.curSelection[0] = c.Loc()
c.curSelection[1] = c.origSelection[1]
}
if loc > c.origSelection[1] {
c.End()
c.curSelection[1] = c.Loc()
c.curSelection[0] = c.origSelection[0]
}
if loc < c.origSelection[1] && loc > c.origSelection[0] {
c.curSelection = c.origSelection
}
}
// SelectWord selects the word the cursor is currently on
func (c *Cursor) SelectWord() {
if !IsWordChar(string(c.RuneUnder(c.x))) {
return
}
forward, backward := c.x, c.x
for backward > 0 && IsWordChar(string(c.RuneUnder(backward-1))) {
backward--
}
c.curSelection[0] = ToCharPos(backward, c.y, c.v.buf)
c.origSelection[0] = c.curSelection[0]
for forward < Count(c.v.buf.lines[c.y])-1 && IsWordChar(string(c.RuneUnder(forward+1))) {
forward++
}
c.curSelection[1] = ToCharPos(forward, c.y, c.v.buf)
c.origSelection[1] = c.curSelection[1]
}
// AddWordToSelection adds the word the cursor is currently on to the selection
func (c *Cursor) AddWordToSelection() {
loc := c.Loc()
if loc > c.origSelection[0] && loc < c.origSelection[1] { if loc > c.origSelection[0] && loc < c.origSelection[1] {
c.curSelection = c.origSelection c.curSelection = c.origSelection
return return
} }
if loc < c.origSelection[0] { if loc < c.origSelection[0] {
c.Start() backward := c.x
c.curSelection[0] = c.Loc()
} else if loc > c.origSelection[1] { for backward > 0 && IsWordChar(string(c.RuneUnder(backward-1))) {
c.End() backward--
c.curSelection[1] = c.Loc() }
c.curSelection[0] = ToCharPos(backward, c.y, c.v.buf)
c.curSelection[1] = c.origSelection[1]
} }
if loc < c.curSelection[0] { if loc > c.origSelection[1] {
c.Start() forward := c.x
c.curSelection[0] = c.Loc()
} else if loc > c.curSelection[1] { for forward < Count(c.v.buf.lines[c.y])-1 && IsWordChar(string(c.RuneUnder(forward+1))) {
c.End() forward++
c.curSelection[1] = c.Loc() }
c.curSelection[1] = ToCharPos(forward, c.y, c.v.buf)
c.curSelection[0] = c.origSelection[0]
} }
} }
// RuneUnder returns the rune under the cursor // RuneUnder returns the rune under the given x position
func (c *Cursor) RuneUnder() rune { func (c *Cursor) RuneUnder(x int) rune {
line := c.v.buf.lines[c.y] line := []rune(c.v.buf.lines[c.y])
if c.x >= Count(line) { if x >= len(line) {
return ' ' x = len(line) - 1
} else if x < 0 {
x = 0
} }
return []rune(line)[c.x] return line[x]
} }
// Up moves the cursor up one line (if possible) // Up moves the cursor up one line (if possible)

View File

@@ -48,3 +48,15 @@ func Max(a, b int) int {
} }
return b return b
} }
// IsWordChar returns whether or not the string is a 'word character'
// If it is a unicode character, then it does not match
// Word characters are defined as [A-Za-z0-9_]
func IsWordChar(str string) bool {
if len(str) > 1 {
// Unicode
return false
}
c := str[0]
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c == '_')
}

View File

@@ -33,3 +33,33 @@ func TestSpaces(t *testing.T) {
} }
} }
} }
func TestIsWordChar(t *testing.T) {
if IsWordChar("t") == false {
t.Errorf("IsWordChar(t) = false")
}
if IsWordChar("T") == false {
t.Errorf("IsWordChar(T) = false")
}
if IsWordChar("5") == false {
t.Errorf("IsWordChar(5) = false")
}
if IsWordChar("_") == false {
t.Errorf("IsWordChar(_) = false")
}
if IsWordChar("~") == true {
t.Errorf("IsWordChar(~) = true")
}
if IsWordChar(" ") == true {
t.Errorf("IsWordChar( ) = true")
}
if IsWordChar("ß") == true {
t.Errorf("IsWordChar(ß) = true")
}
if IsWordChar(")") == true {
t.Errorf("IsWordChar()) = true")
}
if IsWordChar("\n") == true {
t.Errorf("IsWordChar(\n)) = true")
}
}

View File

@@ -456,14 +456,19 @@ func (v *View) HandleEvent(event tcell.Event) {
if v.doubleClick { if v.doubleClick {
// Triple click // Triple click
v.lastClickTime = time.Now() v.lastClickTime = time.Now()
v.tripleClick = true v.tripleClick = true
v.doubleClick = false v.doubleClick = false
v.cursor.SelectLine() v.cursor.SelectLine()
} else { } else {
// Double click // Double click
v.lastClickTime = time.Now()
v.doubleClick = true v.doubleClick = true
v.tripleClick = false v.tripleClick = false
v.lastClickTime = time.Now()
v.cursor.SelectWord()
} }
} else { } else {
v.doubleClick = false v.doubleClick = false
@@ -478,7 +483,7 @@ func (v *View) HandleEvent(event tcell.Event) {
if v.tripleClick { if v.tripleClick {
v.cursor.AddLineToSelection() v.cursor.AddLineToSelection()
} else if v.doubleClick { } else if v.doubleClick {
v.cursor.AddWordToSelection()
} else { } else {
v.cursor.curSelection[1] = v.cursor.Loc() v.cursor.curSelection[1] = v.cursor.Loc()
} }

View File

@@ -8,10 +8,6 @@
- [ ] Search and replace - [ ] Search and replace
- [ ] Better selection
- [ ] Double click selects current word
- [x] Triple click enables line selection
- [ ] More keybindings - [ ] More keybindings
- [x] Page up and page down - [x] Page up and page down
- [x] CtrlA for select all - [x] CtrlA for select all
@@ -40,6 +36,10 @@
- [x] Help screen which lists keybindings and commands - [x] Help screen which lists keybindings and commands
- [x] Opened with Ctrl-h - [x] Opened with Ctrl-h
- [x] Better selection
- [x] Double click selects current word
- [x] Triple click enables line selection
- [x] Options - [x] Options
- [x] Colorscheme - [x] Colorscheme
- [x] tab size - [x] tab size