Skip to content

Commit 35630aa

Browse files
authored
Merge pull request zyedidia#2665 from masmu/feature/sub-words
Implemented sub-word cursor movement
2 parents 9176508 + 78fcf2f commit 35630aa

File tree

6 files changed

+289
-15
lines changed

6 files changed

+289
-15
lines changed

internal/action/actions.go

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,22 @@ func (h *BufPane) WordLeft() bool {
283283
return true
284284
}
285285

286+
// SubWordRight moves the cursor one sub-word to the right
287+
func (h *BufPane) SubWordRight() bool {
288+
h.Cursor.Deselect(false)
289+
h.Cursor.SubWordRight()
290+
h.Relocate()
291+
return true
292+
}
293+
294+
// SubWordLeft moves the cursor one sub-word to the left
295+
func (h *BufPane) SubWordLeft() bool {
296+
h.Cursor.Deselect(true)
297+
h.Cursor.SubWordLeft()
298+
h.Relocate()
299+
return true
300+
}
301+
286302
// SelectUp selects up one line
287303
func (h *BufPane) SelectUp() bool {
288304
if !h.Cursor.HasSelection() {
@@ -359,6 +375,28 @@ func (h *BufPane) SelectWordLeft() bool {
359375
return true
360376
}
361377

378+
// SelectSubWordRight selects the sub-word to the right of the cursor
379+
func (h *BufPane) SelectSubWordRight() bool {
380+
if !h.Cursor.HasSelection() {
381+
h.Cursor.OrigSelection[0] = h.Cursor.Loc
382+
}
383+
h.Cursor.SubWordRight()
384+
h.Cursor.SelectTo(h.Cursor.Loc)
385+
h.Relocate()
386+
return true
387+
}
388+
389+
// SelectSubWordLeft selects the sub-word to the left of the cursor
390+
func (h *BufPane) SelectSubWordLeft() bool {
391+
if !h.Cursor.HasSelection() {
392+
h.Cursor.OrigSelection[0] = h.Cursor.Loc
393+
}
394+
h.Cursor.SubWordLeft()
395+
h.Cursor.SelectTo(h.Cursor.Loc)
396+
h.Relocate()
397+
return true
398+
}
399+
362400
// StartOfText moves the cursor to the start of the text of the line
363401
func (h *BufPane) StartOfText() bool {
364402
h.Cursor.Deselect(true)
@@ -622,6 +660,28 @@ func (h *BufPane) DeleteWordLeft() bool {
622660
return true
623661
}
624662

663+
// DeleteSubWordRight deletes the sub-word to the right of the cursor
664+
func (h *BufPane) DeleteSubWordRight() bool {
665+
h.SelectSubWordRight()
666+
if h.Cursor.HasSelection() {
667+
h.Cursor.DeleteSelection()
668+
h.Cursor.ResetSelection()
669+
}
670+
h.Relocate()
671+
return true
672+
}
673+
674+
// DeleteSubWordLeft deletes the sub-word to the left of the cursor
675+
func (h *BufPane) DeleteSubWordLeft() bool {
676+
h.SelectSubWordLeft()
677+
if h.Cursor.HasSelection() {
678+
h.Cursor.DeleteSelection()
679+
h.Cursor.ResetSelection()
680+
}
681+
h.Relocate()
682+
return true
683+
}
684+
625685
// Delete deletes the next character
626686
func (h *BufPane) Delete() bool {
627687
if h.Cursor.HasSelection() {
@@ -745,8 +805,8 @@ func (h *BufPane) Autocomplete() bool {
745805
}
746806
r := h.Cursor.RuneUnder(h.Cursor.X)
747807
prev := h.Cursor.RuneUnder(h.Cursor.X - 1)
748-
if !util.IsAutocomplete(prev) || !util.IsNonAlphaNumeric(r) {
749-
// don't autocomplete if cursor is on alpha numeric character (middle of a word)
808+
if !util.IsAutocomplete(prev) || util.IsWordChar(r) {
809+
// don't autocomplete if cursor is within a word
750810
return false
751811
}
752812

internal/action/bufpane.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,10 +746,16 @@ var BufKeyActions = map[string]BufKeyAction{
746746
"SelectRight": (*BufPane).SelectRight,
747747
"WordRight": (*BufPane).WordRight,
748748
"WordLeft": (*BufPane).WordLeft,
749+
"SubWordRight": (*BufPane).SubWordRight,
750+
"SubWordLeft": (*BufPane).SubWordLeft,
749751
"SelectWordRight": (*BufPane).SelectWordRight,
750752
"SelectWordLeft": (*BufPane).SelectWordLeft,
753+
"SelectSubWordRight": (*BufPane).SelectSubWordRight,
754+
"SelectSubWordLeft": (*BufPane).SelectSubWordLeft,
751755
"DeleteWordRight": (*BufPane).DeleteWordRight,
752756
"DeleteWordLeft": (*BufPane).DeleteWordLeft,
757+
"DeleteSubWordRight": (*BufPane).DeleteSubWordRight,
758+
"DeleteSubWordLeft": (*BufPane).DeleteSubWordLeft,
753759
"SelectLine": (*BufPane).SelectLine,
754760
"SelectToStartOfLine": (*BufPane).SelectToStartOfLine,
755761
"SelectToStartOfText": (*BufPane).SelectToStartOfText,
@@ -876,10 +882,16 @@ var MultiActions = map[string]bool{
876882
"SelectRight": true,
877883
"WordRight": true,
878884
"WordLeft": true,
885+
"SubWordRight": true,
886+
"SubWordLeft": true,
879887
"SelectWordRight": true,
880888
"SelectWordLeft": true,
889+
"SelectSubWordRight": true,
890+
"SelectSubWordLeft": true,
881891
"DeleteWordRight": true,
882892
"DeleteWordLeft": true,
893+
"DeleteSubWordRight": true,
894+
"DeleteSubWordLeft": true,
883895
"SelectLine": true,
884896
"SelectToStartOfLine": true,
885897
"SelectToStartOfText": true,

internal/buffer/autocomplete.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,11 @@ func (b *Buffer) GetWord() ([]byte, int) {
7373
return []byte{}, -1
7474
}
7575

76-
if util.IsNonAlphaNumeric(b.RuneAt(c.Loc.Move(-1, b))) {
76+
if util.IsNonWordChar(b.RuneAt(c.Loc.Move(-1, b))) {
7777
return []byte{}, c.X
7878
}
7979

80-
args := bytes.FieldsFunc(l, util.IsNonAlphaNumeric)
80+
args := bytes.FieldsFunc(l, util.IsNonWordChar)
8181
input := args[len(args)-1]
8282
return input, c.X - util.CharacterCount(input)
8383
}
@@ -166,7 +166,7 @@ func BufferComplete(b *Buffer) ([]string, []string) {
166166
var suggestions []string
167167
for i := c.Y; i >= 0; i-- {
168168
l := b.LineBytes(i)
169-
words := bytes.FieldsFunc(l, util.IsNonAlphaNumeric)
169+
words := bytes.FieldsFunc(l, util.IsNonWordChar)
170170
for _, w := range words {
171171
if bytes.HasPrefix(w, input) && util.CharacterCount(w) > inputLen {
172172
strw := string(w)
@@ -179,7 +179,7 @@ func BufferComplete(b *Buffer) ([]string, []string) {
179179
}
180180
for i := c.Y + 1; i < b.LinesNum(); i++ {
181181
l := b.LineBytes(i)
182-
words := bytes.FieldsFunc(l, util.IsNonAlphaNumeric)
182+
words := bytes.FieldsFunc(l, util.IsNonWordChar)
183183
for _, w := range words {
184184
if bytes.HasPrefix(w, input) && util.CharacterCount(w) > inputLen {
185185
strw := string(w)

internal/buffer/cursor.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,17 @@ func (c *Cursor) WordRight() {
410410
}
411411
c.Right()
412412
}
413+
if util.IsNonWordChar(c.RuneUnder(c.X)) && !util.IsWhitespace(c.RuneUnder(c.X)) &&
414+
util.IsNonWordChar(c.RuneUnder(c.X+1)) {
415+
for util.IsNonWordChar(c.RuneUnder(c.X)) && !util.IsWhitespace(c.RuneUnder(c.X)) {
416+
if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) {
417+
c.Right()
418+
return
419+
}
420+
c.Right()
421+
}
422+
return
423+
}
413424
c.Right()
414425
for util.IsWordChar(c.RuneUnder(c.X)) {
415426
if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) {
@@ -428,6 +439,17 @@ func (c *Cursor) WordLeft() {
428439
}
429440
c.Left()
430441
}
442+
if util.IsNonWordChar(c.RuneUnder(c.X)) && !util.IsWhitespace(c.RuneUnder(c.X)) &&
443+
util.IsNonWordChar(c.RuneUnder(c.X-1)) {
444+
for util.IsNonWordChar(c.RuneUnder(c.X)) && !util.IsWhitespace(c.RuneUnder(c.X)) {
445+
if c.X == 0 {
446+
return
447+
}
448+
c.Left()
449+
}
450+
c.Right()
451+
return
452+
}
431453
c.Left()
432454
for util.IsWordChar(c.RuneUnder(c.X)) {
433455
if c.X == 0 {
@@ -438,6 +460,127 @@ func (c *Cursor) WordLeft() {
438460
c.Right()
439461
}
440462

463+
// SubWordRight moves the cursor one sub-word to the right
464+
func (c *Cursor) SubWordRight() {
465+
if util.IsWhitespace(c.RuneUnder(c.X)) {
466+
for util.IsWhitespace(c.RuneUnder(c.X)) {
467+
if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) {
468+
c.Right()
469+
return
470+
}
471+
c.Right()
472+
}
473+
return
474+
}
475+
if util.IsNonWordChar(c.RuneUnder(c.X)) && !util.IsWhitespace(c.RuneUnder(c.X)) {
476+
for util.IsNonWordChar(c.RuneUnder(c.X)) && !util.IsWhitespace(c.RuneUnder(c.X)) {
477+
if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) {
478+
c.Right()
479+
return
480+
}
481+
c.Right()
482+
}
483+
return
484+
}
485+
if util.IsSubwordDelimiter(c.RuneUnder(c.X)) {
486+
for util.IsSubwordDelimiter(c.RuneUnder(c.X)) {
487+
if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) {
488+
c.Right()
489+
return
490+
}
491+
c.Right()
492+
}
493+
if util.IsWhitespace(c.RuneUnder(c.X)) {
494+
return
495+
}
496+
}
497+
if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) {
498+
return
499+
}
500+
if util.IsUpperLetter(c.RuneUnder(c.X)) &&
501+
util.IsUpperLetter(c.RuneUnder(c.X+1)) {
502+
for util.IsUpperAlphanumeric(c.RuneUnder(c.X)) {
503+
if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) {
504+
return
505+
}
506+
c.Right()
507+
}
508+
if util.IsLowerAlphanumeric(c.RuneUnder(c.X)) {
509+
c.Left()
510+
}
511+
} else {
512+
c.Right()
513+
for util.IsLowerAlphanumeric(c.RuneUnder(c.X)) {
514+
if c.X == util.CharacterCount(c.buf.LineBytes(c.Y)) {
515+
return
516+
}
517+
c.Right()
518+
}
519+
}
520+
}
521+
522+
// SubWordLeft moves the cursor one sub-word to the left
523+
func (c *Cursor) SubWordLeft() {
524+
c.Left()
525+
if util.IsWhitespace(c.RuneUnder(c.X)) {
526+
for util.IsWhitespace(c.RuneUnder(c.X)) {
527+
if c.X == 0 {
528+
return
529+
}
530+
c.Left()
531+
}
532+
c.Right()
533+
return
534+
}
535+
if util.IsNonWordChar(c.RuneUnder(c.X)) && !util.IsWhitespace(c.RuneUnder(c.X)) {
536+
for util.IsNonWordChar(c.RuneUnder(c.X)) && !util.IsWhitespace(c.RuneUnder(c.X)) {
537+
if c.X == 0 {
538+
return
539+
}
540+
c.Left()
541+
}
542+
c.Right()
543+
return
544+
}
545+
if util.IsSubwordDelimiter(c.RuneUnder(c.X)) {
546+
for util.IsSubwordDelimiter(c.RuneUnder(c.X)) {
547+
if c.X == 0 {
548+
return
549+
}
550+
c.Left()
551+
}
552+
if util.IsWhitespace(c.RuneUnder(c.X)) {
553+
c.Right()
554+
return
555+
}
556+
}
557+
if c.X == 0 {
558+
return
559+
}
560+
if util.IsUpperLetter(c.RuneUnder(c.X)) &&
561+
util.IsUpperLetter(c.RuneUnder(c.X-1)) {
562+
for util.IsUpperAlphanumeric(c.RuneUnder(c.X)) {
563+
if c.X == 0 {
564+
return
565+
}
566+
c.Left()
567+
}
568+
if !util.IsUpperAlphanumeric(c.RuneUnder(c.X)) {
569+
c.Right()
570+
}
571+
} else {
572+
for util.IsLowerAlphanumeric(c.RuneUnder(c.X)) {
573+
if c.X == 0 {
574+
return
575+
}
576+
c.Left()
577+
}
578+
if !util.IsAlphanumeric(c.RuneUnder(c.X)) {
579+
c.Right()
580+
}
581+
}
582+
}
583+
441584
// RuneUnder returns the rune under the given x position
442585
func (c *Cursor) RuneUnder(x int) rune {
443586
line := c.buf.LineBytes(c.Y)

0 commit comments

Comments
 (0)