This commit is contained in:
Cheney 2015-09-27 10:33:19 +08:00
parent 6a53e6406c
commit 092d0fe477
1 changed files with 61 additions and 55 deletions

View File

@ -7,7 +7,13 @@ import (
) )
type AutoCompleter interface { type AutoCompleter interface {
Do(line []rune, pos int) (newLine [][]rune, offset int) // Readline will pass the whole line and current offset to it
// Completer need to pass all the candidates, and how long they shared the same characters in line
// Example:
// Do("g", 1) => ["o", "it", "it-shell", "rep"], 1
// Do("gi", 2) => ["t", "t-shell"], 1
// Do("git", 3) => ["", "-shell"], 0
Do(line []rune, pos int) (newLine [][]rune, length int)
} }
type opCompleter struct { type opCompleter struct {
@ -17,11 +23,11 @@ type opCompleter struct {
inCompleteMode bool inCompleteMode bool
inSelectMode bool inSelectMode bool
candicate [][]rune candidate [][]rune
candicateSource []rune candidateSource []rune
candicateOff int candidateOff int
candicateChoise int candidateChoise int
candicateColNum int candidateColNum int
} }
func newOpCompleter(w io.Writer, op *Operation) *opCompleter { func newOpCompleter(w io.Writer, op *Operation) *opCompleter {
@ -33,20 +39,20 @@ func newOpCompleter(w io.Writer, op *Operation) *opCompleter {
} }
func (o *opCompleter) doSelect() { func (o *opCompleter) doSelect() {
if len(o.candicate) == 1 { if len(o.candidate) == 1 {
o.op.buf.WriteRunes(o.candicate[0]) o.op.buf.WriteRunes(o.candidate[0])
o.ExitCompleteMode(false) o.ExitCompleteMode(false)
return return
} }
o.nextCandicate(1) o.nextCandidate(1)
o.CompleteRefresh() o.CompleteRefresh()
} }
func (o *opCompleter) nextCandicate(i int) { func (o *opCompleter) nextCandidate(i int) {
o.candicateChoise += i o.candidateChoise += i
o.candicateChoise = o.candicateChoise % len(o.candicate) o.candidateChoise = o.candidateChoise % len(o.candidate)
if o.candicateChoise < 0 { if o.candidateChoise < 0 {
o.candicateChoise = len(o.candicate) + o.candicateChoise o.candidateChoise = len(o.candidate) + o.candidateChoise
} }
} }
@ -59,21 +65,21 @@ func (o *opCompleter) OnComplete() {
buf := o.op.buf buf := o.op.buf
rs := buf.Runes() rs := buf.Runes()
if o.IsInCompleteMode() && EqualRunes(rs, o.candicateSource) { if o.IsInCompleteMode() && EqualRunes(rs, o.candidateSource) {
o.EnterCompleteSelectMode() o.EnterCompleteSelectMode()
o.doSelect() o.doSelect()
return return
} }
o.ExitCompleteSelectMode() o.ExitCompleteSelectMode()
o.candicateSource = rs o.candidateSource = rs
newLines, offset := o.ac.Do(rs, buf.idx) newLines, offset := o.ac.Do(rs, buf.idx)
if len(newLines) == 0 { if len(newLines) == 0 {
o.ExitCompleteMode(false) o.ExitCompleteMode(false)
return return
} }
// only Aggregate candicates in non-complete mode // only Aggregate candidates in non-complete mode
if !o.IsInCompleteMode() { if !o.IsInCompleteMode() {
if len(newLines) == 1 { if len(newLines) == 1 {
buf.WriteRunes(newLines[0]) buf.WriteRunes(newLines[0])
@ -105,16 +111,16 @@ func (o *opCompleter) HandleCompleteSelect(r rune) bool {
switch r { switch r {
case CharEnter, CharCtrlJ: case CharEnter, CharCtrlJ:
next = false next = false
o.op.buf.WriteRunes(o.op.candicate[o.op.candicateChoise]) o.op.buf.WriteRunes(o.op.candidate[o.op.candidateChoise])
o.ExitCompleteMode(false) o.ExitCompleteMode(false)
case CharLineStart: case CharLineStart:
num := o.candicateChoise % o.candicateColNum num := o.candidateChoise % o.candidateColNum
o.nextCandicate(-num) o.nextCandidate(-num)
case CharLineEnd: case CharLineEnd:
num := o.candicateColNum - o.candicateChoise%o.candicateColNum - 1 num := o.candidateColNum - o.candidateChoise%o.candidateColNum - 1
o.candicateChoise += num o.candidateChoise += num
if o.candicateChoise >= len(o.candicate) { if o.candidateChoise >= len(o.candidate) {
o.candicateChoise = len(o.candicate) - 1 o.candidateChoise = len(o.candidate) - 1
} }
case CharBackspace: case CharBackspace:
o.ExitCompleteSelectMode() o.ExitCompleteSelectMode()
@ -125,25 +131,25 @@ func (o *opCompleter) HandleCompleteSelect(r rune) bool {
o.ExitCompleteMode(true) o.ExitCompleteMode(true)
next = false next = false
case CharNext: case CharNext:
tmpChoise := o.candicateChoise + o.candicateColNum tmpChoise := o.candidateChoise + o.candidateColNum
if tmpChoise >= o.getMatrixSize() { if tmpChoise >= o.getMatrixSize() {
tmpChoise -= o.getMatrixSize() tmpChoise -= o.getMatrixSize()
} else if tmpChoise >= len(o.candicate) { } else if tmpChoise >= len(o.candidate) {
tmpChoise += o.candicateColNum tmpChoise += o.candidateColNum
tmpChoise -= o.getMatrixSize() tmpChoise -= o.getMatrixSize()
} }
o.candicateChoise = tmpChoise o.candidateChoise = tmpChoise
case CharBackward: case CharBackward:
o.nextCandicate(-1) o.nextCandidate(-1)
case CharPrev: case CharPrev:
tmpChoise := o.candicateChoise - o.candicateColNum tmpChoise := o.candidateChoise - o.candidateColNum
if tmpChoise < 0 { if tmpChoise < 0 {
tmpChoise += o.getMatrixSize() tmpChoise += o.getMatrixSize()
if tmpChoise >= len(o.candicate) { if tmpChoise >= len(o.candidate) {
tmpChoise -= o.candicateColNum tmpChoise -= o.candidateColNum
} }
} }
o.candicateChoise = tmpChoise o.candidateChoise = tmpChoise
default: default:
next = false next = false
o.ExitCompleteSelectMode() o.ExitCompleteSelectMode()
@ -156,11 +162,11 @@ func (o *opCompleter) HandleCompleteSelect(r rune) bool {
} }
func (o *opCompleter) getMatrixSize() int { func (o *opCompleter) getMatrixSize() int {
line := len(o.candicate) / o.candicateColNum line := len(o.candidate) / o.candidateColNum
if len(o.candicate)%o.candicateColNum != 0 { if len(o.candidate)%o.candidateColNum != 0 {
line++ line++
} }
return line * o.candicateColNum return line * o.candidateColNum
} }
func (o *opCompleter) CompleteRefresh() { func (o *opCompleter) CompleteRefresh() {
@ -169,22 +175,22 @@ func (o *opCompleter) CompleteRefresh() {
} }
lineCnt := o.op.buf.CursorLineCount() lineCnt := o.op.buf.CursorLineCount()
colWidth := 0 colWidth := 0
for _, c := range o.candicate { for _, c := range o.candidate {
w := RunesWidth(c) w := RunesWidth(c)
if w > colWidth { if w > colWidth {
colWidth = w colWidth = w
} }
} }
colNum := getWidth() / (colWidth + o.candicateOff + 2) colNum := getWidth() / (colWidth + o.candidateOff + 2)
o.candicateColNum = colNum o.candidateColNum = colNum
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
buf.Write(bytes.Repeat([]byte("\n"), lineCnt)) buf.Write(bytes.Repeat([]byte("\n"), lineCnt))
same := o.op.buf.RuneSlice(-o.candicateOff) same := o.op.buf.RuneSlice(-o.candidateOff)
colIdx := 0 colIdx := 0
lines := 1 lines := 1
buf.WriteString("\033[J") buf.WriteString("\033[J")
for idx, c := range o.candicate { for idx, c := range o.candidate {
inSelect := idx == o.candicateChoise && o.IsInCompleteSelectMode() inSelect := idx == o.candidateChoise && o.IsInCompleteSelectMode()
if inSelect { if inSelect {
buf.WriteString("\033[30;47m") buf.WriteString("\033[30;47m")
} }
@ -210,14 +216,14 @@ func (o *opCompleter) CompleteRefresh() {
o.w.Write(buf.Bytes()) o.w.Write(buf.Bytes())
} }
func (o *opCompleter) aggCandicate(candicate [][]rune) int { func (o *opCompleter) aggCandidate(candidate [][]rune) int {
offset := 0 offset := 0
for i := 0; i < len(candicate[0]); i++ { for i := 0; i < len(candidate[0]); i++ {
for j := 0; j < len(candicate)-1; j++ { for j := 0; j < len(candidate)-1; j++ {
if i > len(candicate[j]) { if i > len(candidate[j]) {
goto aggregate goto aggregate
} }
if candicate[j][i] != candicate[j+1][i] { if candidate[j][i] != candidate[j+1][i] {
goto aggregate goto aggregate
} }
} }
@ -229,23 +235,23 @@ aggregate:
func (o *opCompleter) EnterCompleteSelectMode() { func (o *opCompleter) EnterCompleteSelectMode() {
o.inSelectMode = true o.inSelectMode = true
o.candicateChoise = -1 o.candidateChoise = -1
o.CompleteRefresh() o.CompleteRefresh()
} }
func (o *opCompleter) EnterCompleteMode(offset int, candicate [][]rune) { func (o *opCompleter) EnterCompleteMode(offset int, candidate [][]rune) {
o.inCompleteMode = true o.inCompleteMode = true
o.candicate = candicate o.candidate = candidate
o.candicateOff = offset o.candidateOff = offset
o.CompleteRefresh() o.CompleteRefresh()
} }
func (o *opCompleter) ExitCompleteSelectMode() { func (o *opCompleter) ExitCompleteSelectMode() {
o.inSelectMode = false o.inSelectMode = false
o.candicate = nil o.candidate = nil
o.candicateChoise = -1 o.candidateChoise = -1
o.candicateOff = -1 o.candidateOff = -1
o.candicateSource = nil o.candidateSource = nil
} }
func (o *opCompleter) ExitCompleteMode(revent bool) { func (o *opCompleter) ExitCompleteMode(revent bool) {