mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-30 14:47:16 +09:00
Add word selection with double click
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
12
src/util.go
12
src/util.go
@@ -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 == '_')
|
||||||
|
}
|
||||||
|
|||||||
@@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user