Example #1
0
func (o *opCompleter) CompleteRefresh() {
	if !o.inCompleteMode {
		return
	}
	lineCnt := o.op.buf.CursorLineCount()
	colWidth := 0
	for _, c := range o.candidate {
		w := runes.WidthAll(c)
		if w > colWidth {
			colWidth = w
		}
	}
	colNum := getWidth(o.op.cfg.StdoutFd) / (colWidth + o.candidateOff + 2)
	o.candidateColNum = colNum
	buf := bytes.NewBuffer(nil)
	buf.Write(bytes.Repeat([]byte("\n"), lineCnt))
	same := o.op.buf.RuneSlice(-o.candidateOff)
	colIdx := 0
	lines := 1
	buf.WriteString("\033[J")
	for idx, c := range o.candidate {
		inSelect := idx == o.candidateChoise && o.IsInCompleteSelectMode()
		if inSelect {
			buf.WriteString("\033[30;47m")
		}
		buf.WriteString(string(same))
		buf.WriteString(string(c))
		buf.Write(bytes.Repeat([]byte(" "), colWidth-len(c)))
		if inSelect {
			buf.WriteString("\033[0m")
		}

		buf.WriteString("  ")
		colIdx++
		if colIdx == colNum {
			buf.WriteString("\n")
			lines++
			colIdx = 0
		}
	}

	// move back
	fmt.Fprintf(buf, "\033[%dA\r", lineCnt-1+lines)
	fmt.Fprintf(buf, "\033[%dC", o.op.buf.idx+o.op.buf.PromptLen())
	o.w.Write(buf.Bytes())
}
func (r *RuneBuffer) IdxLine() int {
	totalWidth := runes.WidthAll(r.buf[:r.idx]) + r.PromptLen()
	w := getWidth(r.cfg.StdoutFd)
	if w <= 0 {
		return -1
	}
	line := totalWidth / w

	// 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 && !isWindows {
		line--
	}

	return line
}
func (r *RuneBuffer) PromptLen() int {
	return runes.WidthAll(runes.ColorFilter(r.prompt))
}
func (r *RuneBuffer) CurrentWidth(x int) int {
	return runes.WidthAll(r.buf[:x])
}
func (r *RuneBuffer) calWidth(m int) int {
	if m > 0 {
		return runes.WidthAll(r.buf[r.idx : r.idx+m])
	}
	return runes.WidthAll(r.buf[r.idx+m : r.idx])
}
func (r *RuneBuffer) LineCount() int {
	return LineCount(r.cfg.StdoutFd, runes.WidthAll(r.buf)+r.PromptLen())
}