Refactor query and caretPos

This commit is contained in:
Daisuke Maki 2014-08-27 15:26:48 +09:00
parent 3b2b1fe07a
commit 11dfa1b426
4 changed files with 131 additions and 87 deletions

137
action.go
View file

@ -151,16 +151,12 @@ func doAcceptChar(i *Input, ev termbox.Event) {
}
if ev.Ch > 0 {
if len(i.query) == i.caretPos {
i.query = append(i.query, ev.Ch)
if i.QueryLen() == i.CaretPos().Int() {
i.AppendQuery(ev.Ch)
} else {
buf := make([]rune, len(i.query)+1)
copy(buf, i.query[:i.caretPos])
buf[i.caretPos] = ev.Ch
copy(buf[i.caretPos+1:], i.query[i.caretPos:])
i.query = buf
i.InsertQueryAt(ev.Ch, i.CaretPos().Int())
}
i.caretPos++
i.MoveCaretPos(1)
i.ExecQuery()
}
}
@ -284,22 +280,23 @@ func doToggleSelectionAndSelectNext(i *Input, ev termbox.Event) {
}
func doDeleteBackwardWord(i *Input, _ termbox.Event) {
if i.caretPos == 0 {
if i.CaretPos() == 0 {
return
}
for pos := i.caretPos - 1; pos >= 0; pos-- {
for pos := i.CaretPos().Int() - 1; pos >= 0; pos-- {
q := i.Query()
if pos == 0 {
i.query = i.query[i.caretPos:]
i.SetQuery(q[i.CaretPos().Int():])
break
}
if unicode.IsSpace(i.query[pos]) {
buf := make([]rune, len(i.query)-(i.caretPos-pos))
copy(buf, i.query[:pos])
copy(buf[pos:], i.query[i.caretPos:])
i.query = buf
i.caretPos = pos
if unicode.IsSpace(q[pos]) {
buf := make([]rune, q.QueryLen()-(i.CaretPos().Int()-pos))
copy(buf, q[:pos])
copy(buf[pos:], q[i.CaretPos().Int():])
i.SetQuery(buf)
i.SetCaretPos(pos)
break
}
}
@ -313,16 +310,16 @@ func doDeleteBackwardWord(i *Input, _ termbox.Event) {
}
func doForwardWord(i *Input, _ termbox.Event) {
if i.caretPos >= len(i.query) {
if i.CaretPos().Int() >= i.QueryLen() {
return
}
foundSpace := false
for pos := i.caretPos; pos < len(i.query); pos++ {
r := i.query[pos]
for pos := i.CaretPos().Int(); pos < i.QueryLen(); pos++ {
r := i.Query()[pos]
if foundSpace {
if !unicode.IsSpace(r) {
i.caretPos = pos
i.SetCaretPos(pos)
i.DrawMatches(nil)
return
}
@ -334,28 +331,28 @@ func doForwardWord(i *Input, _ termbox.Event) {
}
// not found. just move to the end of the buffer
i.caretPos = len(i.query)
i.SetCaretPos(i.QueryLen())
i.DrawMatches(nil)
}
func doBackwardWord(i *Input, _ termbox.Event) {
if i.caretPos == 0 {
if i.CaretPos().Int() == 0 {
return
}
if i.caretPos >= len(i.query) {
i.caretPos--
if i.CaretPos().Int() >= i.QueryLen() {
i.MoveCaretPos(-1)
}
// if we start from a whitespace-ish position, we should
// rewind to the end of the previous word, and then do the
// search all over again
SEARCH_PREV_WORD:
if unicode.IsSpace(i.query[i.caretPos]) {
for pos := i.caretPos; pos > 0; pos-- {
if !unicode.IsSpace(i.query[pos]) {
i.caretPos = pos
if unicode.IsSpace(i.Query()[i.CaretPos().Int()]) {
for pos := i.CaretPos().Int(); pos > 0; pos-- {
if !unicode.IsSpace(i.Query()[pos]) {
i.SetCaretPos(pos)
break
}
}
@ -363,57 +360,57 @@ SEARCH_PREV_WORD:
// if we start from the first character of a word, we
// should attempt to move back and search for the previous word
if i.caretPos > 0 && unicode.IsSpace(i.query[i.caretPos-1]) {
i.caretPos--
if i.CaretPos() > 0 && unicode.IsSpace(i.Query()[i.CaretPos()-1]) {
i.MoveCaretPos(-1)
goto SEARCH_PREV_WORD
}
// Now look for a space
for pos := i.caretPos; pos > 0; pos-- {
if unicode.IsSpace(i.query[pos]) {
i.caretPos = pos + 1
for pos := i.CaretPos(); pos > 0; pos-- {
if unicode.IsSpace(i.Query()[pos]) {
i.SetCaretPos(int(pos + 1))
i.DrawMatches(nil)
return
}
}
// not found. just move to the beginning of the buffer
i.caretPos = 0
i.SetCaretPos(0)
i.DrawMatches(nil)
}
func doForwardChar(i *Input, _ termbox.Event) {
if i.caretPos >= len(i.query) {
if i.CaretPos().Int() >= i.QueryLen() {
return
}
i.caretPos++
i.MoveCaretPos(1)
i.DrawMatches(nil)
}
func doBackwardChar(i *Input, _ termbox.Event) {
if i.caretPos <= 0 {
if i.CaretPos() <= 0 {
return
}
i.caretPos--
i.MoveCaretPos(-1)
i.DrawMatches(nil)
}
func doDeleteForwardWord(i *Input, _ termbox.Event) {
if len(i.query) <= i.caretPos {
if i.QueryLen() <= i.CaretPos().Int() {
return
}
for pos := i.caretPos; pos < len(i.query); pos++ {
if pos == len(i.query)-1 {
i.query = i.query[:i.caretPos]
for pos := i.CaretPos().Int(); pos < i.QueryLen(); pos++ {
if pos == i.QueryLen()-1 {
i.SetQuery(i.Query()[:i.CaretPos()])
break
}
if unicode.IsSpace(i.query[pos]) {
buf := make([]rune, len(i.query)-(pos-i.caretPos))
copy(buf, i.query[:i.caretPos])
copy(buf[i.caretPos:], i.query[pos:])
i.query = buf
if unicode.IsSpace(i.Query()[pos]) {
buf := make([]rune, i.QueryLen()-(pos-i.CaretPos().Int()))
copy(buf, i.Query()[:i.CaretPos()])
copy(buf[i.CaretPos():], i.Query()[pos:])
i.SetQuery(buf)
break
}
}
@ -427,17 +424,17 @@ func doDeleteForwardWord(i *Input, _ termbox.Event) {
}
func doBeginningOfLine(i *Input, _ termbox.Event) {
i.caretPos = 0
i.SetCaretPos(0)
i.DrawMatches(nil)
}
func doEndOfLine(i *Input, _ termbox.Event) {
i.caretPos = len(i.query)
i.SetCaretPos(i.QueryLen())
i.DrawMatches(nil)
}
func doEndOfFile(i *Input, ev termbox.Event) {
if len(i.query) > 0 {
if i.QueryLen() > 0 {
doDeleteForwardChar(i, ev)
} else {
doCancel(i, ev)
@ -445,8 +442,8 @@ func doEndOfFile(i *Input, ev termbox.Event) {
}
func doKillBeginningOfLine(i *Input, _ termbox.Event) {
i.query = i.query[i.caretPos:]
i.caretPos = 0
i.SetQuery(i.Query()[i.CaretPos():])
i.SetCaretPos(0)
if i.ExecQuery() {
return
}
@ -455,11 +452,11 @@ func doKillBeginningOfLine(i *Input, _ termbox.Event) {
}
func doKillEndOfLine(i *Input, _ termbox.Event) {
if len(i.query) <= i.caretPos {
if i.QueryLen() <= i.CaretPos().Int() {
return
}
i.query = i.query[0:i.caretPos]
i.SetQuery(i.Query()[0:i.CaretPos()])
if i.ExecQuery() {
return
}
@ -468,20 +465,20 @@ func doKillEndOfLine(i *Input, _ termbox.Event) {
}
func doDeleteAll(i *Input, _ termbox.Event) {
i.query = make([]rune, 0)
i.SetQuery(make([]rune, 0))
i.current = nil
i.DrawMatches(nil)
}
func doDeleteForwardChar(i *Input, _ termbox.Event) {
if len(i.query) <= i.caretPos {
if i.QueryLen() <= i.CaretPos().Int() {
return
}
buf := make([]rune, len(i.query)-1)
copy(buf, i.query[:i.caretPos])
copy(buf[i.caretPos:], i.query[i.caretPos+1:])
i.query = buf
buf := make([]rune, i.QueryLen()-1)
copy(buf, i.Query()[:i.CaretPos()])
copy(buf[i.CaretPos():], i.Query()[i.CaretPos()+1:])
i.SetQuery(buf)
if i.ExecQuery() {
return
@ -492,23 +489,23 @@ func doDeleteForwardChar(i *Input, _ termbox.Event) {
}
func doDeleteBackwardChar(i *Input, ev termbox.Event) {
if len(i.query) <= 0 {
if i.QueryLen() <= 0 {
return
}
switch i.caretPos {
switch i.CaretPos().Int() {
case 0:
// No op
return
case len(i.query):
i.query = i.query[:len(i.query)-1]
case i.QueryLen():
i.SetQuery(i.Query()[:i.QueryLen()-1])
default:
buf := make([]rune, len(i.query)-1)
copy(buf, i.query[:i.caretPos])
copy(buf[i.caretPos-1:], i.query[i.caretPos:])
i.query = buf
buf := make([]rune, i.QueryLen()-1)
copy(buf, i.Query()[:i.CaretPos()])
copy(buf[i.CaretPos()-1:], i.Query()[i.CaretPos():])
i.SetQuery(buf)
}
i.caretPos--
i.MoveCaretPos(-1)
if i.ExecQuery() {
return

61
ctx.go
View file

@ -37,15 +37,60 @@ type PageInfo struct {
perPage int
}
type CaretPosition int
func (p CaretPosition) Int() int {
return int(p)
}
func (p CaretPosition) CaretPos() CaretPosition {
return p
}
func (p *CaretPosition) SetCaretPos(where int) {
*p = CaretPosition(where)
}
func (p *CaretPosition) MoveCaretPos(offset int) {
*p = CaretPosition(p.Int() + offset)
}
type FilterQuery []rune
func (q FilterQuery) Query() FilterQuery {
return q
}
func (q FilterQuery) String() string {
return string(q)
}
func (q FilterQuery) QueryLen() int {
return len(q)
}
func (q *FilterQuery) AppendQuery(r rune) {
*q = FilterQuery(append([]rune(*q), r))
}
func (q *FilterQuery) InsertQueryAt(ch rune, where int) {
sq := []rune(*q)
buf := make([]rune, q.QueryLen()+1)
copy(buf, sq[:where])
buf[where] = ch
copy(buf[where+1:], sq[where:])
*q = FilterQuery(buf)
}
// Ctx contains all the important data. while you can easily access
// data in this struct from anwyehre, only do so via channels
type Ctx struct {
*Hub
CaretPosition
FilterQuery
enableSep bool
result []Match
mutex sync.Mutex
query []rune
caretPos int
currentLine int
currentPage *PageInfo
maxPage int
@ -66,10 +111,10 @@ type Ctx struct {
func NewCtx(o CtxOptions) *Ctx {
c := &Ctx{
Hub: NewHub(),
CaretPosition: 0,
FilterQuery: FilterQuery{},
result: []Match{},
mutex: sync.Mutex{},
query: []rune{},
caretPos: 0,
currentPage: &PageInfo{0, 1, 0},
maxPage: 0,
selection: Selection([]int{}),
@ -174,8 +219,8 @@ func (c *Ctx) WaitDone() {
}
func (c *Ctx) ExecQuery() bool {
if len(c.query) > 0 {
c.SendQuery(string(c.query))
if c.QueryLen() > 0 {
c.SendQuery(c.Query().String())
return true
}
return false
@ -222,8 +267,8 @@ func (c *Ctx) NewInput() *Input {
}
func (c *Ctx) SetQuery(q []rune) {
c.query = q
c.caretPos = len(q)
c.FilterQuery = FilterQuery(q)
c.SetCaretPos(c.QueryLen())
}
func (c *Ctx) Matcher() Matcher {

View file

@ -144,19 +144,19 @@ func (u UserPrompt) Draw() {
// print "QUERY>"
printScreen(0, location, u.config.Style.BasicFG(), u.config.Style.BasicBG(), u.prefix, false)
if u.caretPos <= 0 {
u.caretPos = 0 // sanity
if u.CaretPos() <= 0 { // XXX Do we really need this?
u.SetCaretPos(0) // sanity
}
if u.caretPos > len(u.query) {
u.caretPos = len(u.query)
if u.CaretPos().Int() > u.QueryLen() { // XXX Do we really need this?
u.SetCaretPos(u.QueryLen())
}
if u.caretPos == len(u.query) {
if u.CaretPos().Int() == u.QueryLen() {
// the entire string + the caret after the string
fg := u.config.Style.QueryFG()
bg := u.config.Style.QueryBG()
qs := string(u.query)
qs := u.Query().String()
ql := runewidth.StringWidth(qs)
printScreen(u.prefixLen+1, location, fg, bg, qs, false)
printScreen(u.prefixLen+1+ql, location, fg|termbox.AttrReverse, bg|termbox.AttrReverse, " ", false)
@ -166,8 +166,8 @@ func (u UserPrompt) Draw() {
prev := 0
fg := u.config.Style.QueryFG()
bg := u.config.Style.QueryBG()
for i, r := range u.query {
if i == u.caretPos {
for i, r := range []rune(u.Query()) {
if i == u.CaretPos().Int() {
fg |= termbox.AttrReverse
bg |= termbox.AttrReverse
}
@ -383,7 +383,7 @@ CALCULATE_PAGE:
}
if l.maxPage < currentPage.index {
if len(targets) == 0 && len(l.query) == 0 {
if len(targets) == 0 && l.QueryLen() == 0 {
// wait for targets
return fmt.Errorf("no targets or query. nothing to do")
}

View file

@ -35,6 +35,8 @@ func (t Termbox) PollEvent() chan termbox.Event {
// safe from being stuck.
evCh := make(chan termbox.Event)
go func() {
defer func() { recover() }()
defer func() { close(evCh) }()
for {
evCh <- termbox.PollEvent()
}