diff --git a/README.md b/README.md index 86b03ed..544f300 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,7 @@ Users can change that in terminal simulator(i.e. iTerm2) to `Alt`+`B` | `Ctrl`+`S` | Search forwards in history | | `Ctrl`+`T` | Transpose characters | | `Meta`+`T` | Transpose words (TODO) | -| `Ctrl`+`U` | Cut text to the beginning of line (TODO) | +| `Ctrl`+`U` | Cut text to the beginning of line | | `Ctrl`+`W` | Cut previous word | | `Backspace` | Delete previous character | | `Meta`+`Backspace` | Cut previous word | diff --git a/char.go b/char.go index 3d65824..ec6cd1d 100644 --- a/char.go +++ b/char.go @@ -18,6 +18,7 @@ const ( CharBckSearch = 18 CharFwdSearch = 19 CharTranspose = 20 + CharCtrlU = 21 CharCtrlW = 23 CharEsc = 27 CharEscapeEx = 91 diff --git a/operation.go b/operation.go index dc2cd02..7c98b80 100644 --- a/operation.go +++ b/operation.go @@ -97,6 +97,8 @@ func (o *Operation) ioloop() { case CharBckSearch: o.SearchMode(S_DIR_BCK) keepInSearchMode = true + case CharCtrlU: + o.buf.KillFront() case CharFwdSearch: o.SearchMode(S_DIR_FWD) keepInSearchMode = true @@ -185,6 +187,7 @@ func (o *Operation) ioloop() { keepInCompleteMode = true } } + if !keepInSearchMode && o.IsSearchMode() { o.ExitSearchMode(false) o.buf.Refresh(nil) diff --git a/runebuf.go b/runebuf.go index 724d6ef..d310bc7 100644 --- a/runebuf.go +++ b/runebuf.go @@ -60,20 +60,19 @@ func (r *RuneBuffer) Len() int { } func (r *RuneBuffer) MoveToLineStart() { - if r.idx == 0 { - return - } - r.Refresh(func() { + if r.idx == 0 { + return + } r.idx = 0 }) } func (r *RuneBuffer) MoveBackward() { - if r.idx == 0 { - return - } r.Refresh(func() { + if r.idx == 0 { + return + } r.idx-- }) } @@ -132,26 +131,32 @@ func (r *RuneBuffer) DeleteWord() { } func (r *RuneBuffer) MoveToPrevWord() { - if r.idx == 0 { - return - } - for i := r.idx - 1; i > 0; i-- { - if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) { - r.Refresh(func() { - r.idx = i - }) + r.Refresh(func() { + if r.idx == 0 { return } - } - r.Refresh(func() { + + for i := r.idx - 1; i > 0; i-- { + if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) { + r.idx = i + return + } + } r.idx = 0 }) } -func (r *RuneBuffer) SetIdx(idx int) (change int) { - i := r.idx - r.idx = idx - return r.idx - i +func (r *RuneBuffer) KillFront() { + r.Refresh(func() { + if r.idx == 0 { + return + } + + length := len(r.buf) - r.idx + copy(r.buf[:length], r.buf[r.idx:]) + r.idx = 0 + r.buf = r.buf[:length] + }) } func (r *RuneBuffer) Kill() { @@ -161,15 +166,15 @@ func (r *RuneBuffer) Kill() { } func (r *RuneBuffer) Transpose() { - if len(r.buf) < 2 { - if len(r.buf) == 1 { - r.Refresh(func() { - r.idx++ - }) - } - return - } r.Refresh(func() { + if len(r.buf) == 1 { + r.idx++ + } + + if len(r.buf) < 2 { + return + } + if r.idx == 0 { r.idx = 1 } else if r.idx >= len(r.buf) { @@ -181,55 +186,53 @@ func (r *RuneBuffer) Transpose() { } func (r *RuneBuffer) MoveToNextWord() { - for i := r.idx + 1; i < len(r.buf); i++ { - if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) { - r.Refresh(func() { - r.idx = i - }) - return - } - } r.Refresh(func() { + for i := r.idx + 1; i < len(r.buf); i++ { + if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) { + r.idx = i + return + } + } + r.idx = len(r.buf) }) } func (r *RuneBuffer) BackEscapeWord() { - if r.idx == 0 { - return - } - for i := r.idx - 1; i > 0; i-- { - if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) { - r.Refresh(func() { - r.buf = append(r.buf[:i], r.buf[r.idx:]...) - r.idx = i - }) + r.Refresh(func() { + if r.idx == 0 { return } - } + for i := r.idx - 1; i > 0; i-- { + if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) { + r.buf = append(r.buf[:i], r.buf[r.idx:]...) + r.idx = i + return + } + } - r.Refresh(func() { r.buf = r.buf[:0] r.idx = 0 }) } func (r *RuneBuffer) Backspace() { - if r.idx == 0 { - return - } r.Refresh(func() { + if r.idx == 0 { + return + } + r.idx-- r.buf = append(r.buf[:r.idx], r.buf[r.idx+1:]...) }) } func (r *RuneBuffer) MoveToLineEnd() { - if r.idx == len(r.buf) { - return - } - r.Refresh(func() { + if r.idx == len(r.buf) { + return + } + r.idx = len(r.buf) }) } @@ -242,9 +245,15 @@ func (r *RuneBuffer) IdxLine() int { totalWidth := RunesWidth(r.buf[:r.idx]) + r.PromptLen() w := getWidth() line := totalWidth / w - if totalWidth%w == 0 { + + // if cursor is in last colmun and not any character behind it + // the cursor will in the first line, otherwise will in the second line + // this situation only occurs in golang's Stdout + // TODO: figure out why + if totalWidth%w == 0 && len(r.buf) == r.idx { line-- } + return line }