mirror of
https://github.com/peco/peco.git
synced 2026-09-10 07:16:29 -04:00
Merge pull request #745 from peco/extract-query-package
Extract query package
This commit is contained in:
commit
7b54585c95
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/peco/peco/hub"
|
||||
"github.com/peco/peco/internal/keyseq"
|
||||
"github.com/peco/peco/line"
|
||||
"github.com/peco/peco/query"
|
||||
"github.com/peco/peco/selection"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
|
@ -265,12 +266,12 @@ func TestViewAroundActionName(t *testing.T) {
|
|||
require.True(t, ok, "peco.ViewArround must remain registered for backward compatibility")
|
||||
}
|
||||
|
||||
func expectCaretPos(t *testing.T, c *Caret, expect int) {
|
||||
func expectCaretPos(t *testing.T, c *query.Caret, expect int) {
|
||||
t.Helper()
|
||||
require.Equal(t, expect, c.Pos(), "Expected caret position %d, got %d", expect, c.Pos())
|
||||
}
|
||||
|
||||
func expectQueryString(t *testing.T, q *Query, expect string) {
|
||||
func expectQueryString(t *testing.T, q *query.Text, expect string) {
|
||||
t.Helper()
|
||||
require.Equal(t, expect, q.String(), "Expected '%s', got '%s'", expect, q.String())
|
||||
}
|
||||
|
|
|
|||
36
caret.go
36
caret.go
|
|
@ -1,36 +0,0 @@
|
|||
package peco
|
||||
|
||||
import "sync"
|
||||
|
||||
// Caret tracks the cursor position within the query line.
|
||||
type Caret struct {
|
||||
mutex sync.Mutex
|
||||
pos int
|
||||
}
|
||||
|
||||
// Pos returns the current caret position, thread-safe.
|
||||
func (c *Caret) Pos() int {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
return c.pos
|
||||
}
|
||||
|
||||
// setPosNL sets the caret position without acquiring the mutex.
|
||||
// The caller must already hold the lock.
|
||||
func (c *Caret) setPosNL(p int) {
|
||||
c.pos = p
|
||||
}
|
||||
|
||||
// SetPos sets the caret position, thread-safe.
|
||||
func (c *Caret) SetPos(p int) {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
c.setPosNL(p)
|
||||
}
|
||||
|
||||
// Move moves the caret by the given delta, thread-safe.
|
||||
func (c *Caret) Move(diff int) {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
c.setPosNL(c.pos + diff)
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
package peco
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCaretInitialPos(t *testing.T) {
|
||||
t.Parallel()
|
||||
var c Caret
|
||||
require.Equal(t, 0, c.Pos())
|
||||
}
|
||||
|
||||
func TestCaretSetPos(t *testing.T) {
|
||||
t.Parallel()
|
||||
var c Caret
|
||||
c.SetPos(5)
|
||||
require.Equal(t, 5, c.Pos())
|
||||
|
||||
c.SetPos(0)
|
||||
require.Equal(t, 0, c.Pos())
|
||||
|
||||
c.SetPos(100)
|
||||
require.Equal(t, 100, c.Pos())
|
||||
}
|
||||
|
||||
func TestCaretMove(t *testing.T) {
|
||||
t.Parallel()
|
||||
var c Caret
|
||||
c.SetPos(5)
|
||||
|
||||
c.Move(3)
|
||||
require.Equal(t, 8, c.Pos())
|
||||
|
||||
c.Move(-2)
|
||||
require.Equal(t, 6, c.Pos())
|
||||
|
||||
// Move to negative territory
|
||||
c.Move(-10)
|
||||
require.Equal(t, -4, c.Pos())
|
||||
}
|
||||
|
||||
func TestCaretMoveFromZero(t *testing.T) {
|
||||
t.Parallel()
|
||||
var c Caret
|
||||
|
||||
c.Move(1)
|
||||
require.Equal(t, 1, c.Pos())
|
||||
|
||||
c.Move(-1)
|
||||
require.Equal(t, 0, c.Pos())
|
||||
}
|
||||
|
||||
func TestCaretMultipleMoves(t *testing.T) {
|
||||
t.Parallel()
|
||||
var c Caret
|
||||
for range 10 {
|
||||
c.Move(1)
|
||||
}
|
||||
require.Equal(t, 10, c.Pos())
|
||||
|
||||
for range 5 {
|
||||
c.Move(-1)
|
||||
}
|
||||
require.Equal(t, 5, c.Pos())
|
||||
}
|
||||
9
peco.go
9
peco.go
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/peco/peco/internal/util"
|
||||
"github.com/peco/peco/line"
|
||||
"github.com/peco/peco/pipeline"
|
||||
"github.com/peco/peco/query"
|
||||
"github.com/peco/peco/selection"
|
||||
"github.com/peco/peco/sig"
|
||||
)
|
||||
|
|
@ -50,7 +51,7 @@ type Peco struct {
|
|||
|
||||
args []string
|
||||
bufferSize int
|
||||
caret Caret
|
||||
caret query.Caret
|
||||
// Config contains the values read in from config file
|
||||
config Config
|
||||
currentLineBuffer Buffer
|
||||
|
|
@ -69,7 +70,7 @@ type Peco struct {
|
|||
onCancel OnCancelBehavior
|
||||
printQuery bool
|
||||
prompt string
|
||||
query Query
|
||||
query query.Text
|
||||
queryExec QueryExecState
|
||||
readyCh chan struct{}
|
||||
resultCh chan line.Line
|
||||
|
|
@ -306,7 +307,7 @@ func (p *Peco) Filters() *filter.Set {
|
|||
return &p.filters
|
||||
}
|
||||
|
||||
func (p *Peco) Query() *Query {
|
||||
func (p *Peco) Query() *query.Text {
|
||||
return &p.query
|
||||
}
|
||||
|
||||
|
|
@ -314,7 +315,7 @@ func (p *Peco) QueryExec() *QueryExecState {
|
|||
return &p.queryExec
|
||||
}
|
||||
|
||||
func (p *Peco) Caret() *Caret {
|
||||
func (p *Peco) Caret() *query.Caret {
|
||||
return &p.caret
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,35 +1,35 @@
|
|||
package peco
|
||||
package query
|
||||
|
||||
import "sync"
|
||||
|
||||
// Query holds the current query string and an optional saved query
|
||||
// Text holds the current query string and an optional saved query
|
||||
// for restore-after-cancel behavior.
|
||||
type Query struct {
|
||||
type Text struct {
|
||||
query []rune
|
||||
savedQuery []rune
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
func (q *Query) Set(s string) {
|
||||
func (q *Text) Set(s string) {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
q.query = []rune(s)
|
||||
}
|
||||
|
||||
func (q *Query) Reset() {
|
||||
func (q *Text) Reset() {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
q.query = []rune(nil)
|
||||
}
|
||||
|
||||
func (q *Query) RestoreSavedQuery() {
|
||||
func (q *Text) RestoreSavedQuery() {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
q.query = q.savedQuery
|
||||
q.savedQuery = []rune(nil)
|
||||
}
|
||||
|
||||
func (q *Query) SaveQuery() {
|
||||
func (q *Text) SaveQuery() {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
q.savedQuery = q.query
|
||||
|
|
@ -37,7 +37,7 @@ func (q *Query) SaveQuery() {
|
|||
}
|
||||
|
||||
// DeleteRange deletes runes in the range [start, end) from the query with boundary validation.
|
||||
func (q *Query) DeleteRange(start, end int) {
|
||||
func (q *Text) DeleteRange(start, end int) {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
if start == -1 {
|
||||
|
|
@ -59,20 +59,20 @@ func (q *Query) DeleteRange(start, end int) {
|
|||
q.query = q.query[:l-(end-start)]
|
||||
}
|
||||
|
||||
func (q *Query) String() string {
|
||||
func (q *Text) String() string {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
return string(q.query)
|
||||
}
|
||||
|
||||
func (q *Query) Len() int {
|
||||
func (q *Text) Len() int {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
return len(q.query)
|
||||
}
|
||||
|
||||
// RuneSlice returns a copy of the query runes
|
||||
func (q *Query) RuneSlice() []rune {
|
||||
func (q *Text) RuneSlice() []rune {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
out := make([]rune, len(q.query))
|
||||
|
|
@ -80,7 +80,7 @@ func (q *Query) RuneSlice() []rune {
|
|||
return out
|
||||
}
|
||||
|
||||
func (q *Query) RuneAt(where int) rune {
|
||||
func (q *Text) RuneAt(where int) rune {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
if where < 0 || where >= len(q.query) {
|
||||
|
|
@ -90,7 +90,7 @@ func (q *Query) RuneAt(where int) rune {
|
|||
}
|
||||
|
||||
// InsertAt inserts a rune at the specified position in the query.
|
||||
func (q *Query) InsertAt(ch rune, where int) {
|
||||
func (q *Text) InsertAt(ch rune, where int) {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
|
|
@ -106,3 +106,36 @@ func (q *Query) InsertAt(ch rune, where int) {
|
|||
copy(buf[where+1:], sq[where:])
|
||||
q.query = buf
|
||||
}
|
||||
|
||||
// Caret tracks the cursor position within the query line.
|
||||
type Caret struct {
|
||||
mutex sync.Mutex
|
||||
pos int
|
||||
}
|
||||
|
||||
// Pos returns the current caret position, thread-safe.
|
||||
func (c *Caret) Pos() int {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
return c.pos
|
||||
}
|
||||
|
||||
// setPosNL sets the caret position without acquiring the mutex.
|
||||
// The caller must already hold the lock.
|
||||
func (c *Caret) setPosNL(p int) {
|
||||
c.pos = p
|
||||
}
|
||||
|
||||
// SetPos sets the caret position, thread-safe.
|
||||
func (c *Caret) SetPos(p int) {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
c.setPosNL(p)
|
||||
}
|
||||
|
||||
// Move moves the caret by the given delta, thread-safe.
|
||||
func (c *Caret) Move(diff int) {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
c.setPosNL(c.pos + diff)
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package peco
|
||||
package query
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
|
@ -21,7 +21,7 @@ func TestQuerySetAndString(t *testing.T) {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
var q Query
|
||||
var q Text
|
||||
q.Set(tt.input)
|
||||
require.Equal(t, tt.input, q.String())
|
||||
})
|
||||
|
|
@ -30,7 +30,7 @@ func TestQuerySetAndString(t *testing.T) {
|
|||
|
||||
func TestQueryLen(t *testing.T) {
|
||||
t.Parallel()
|
||||
var q Query
|
||||
var q Text
|
||||
require.Equal(t, 0, q.Len())
|
||||
|
||||
q.Set("hello")
|
||||
|
|
@ -43,7 +43,7 @@ func TestQueryLen(t *testing.T) {
|
|||
|
||||
func TestQueryReset(t *testing.T) {
|
||||
t.Parallel()
|
||||
var q Query
|
||||
var q Text
|
||||
q.Set("hello")
|
||||
require.Equal(t, 5, q.Len())
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ func TestQueryReset(t *testing.T) {
|
|||
|
||||
func TestQuerySaveAndRestore(t *testing.T) {
|
||||
t.Parallel()
|
||||
var q Query
|
||||
var q Text
|
||||
q.Set("original")
|
||||
|
||||
q.SaveQuery()
|
||||
|
|
@ -72,7 +72,7 @@ func TestQuerySaveAndRestore(t *testing.T) {
|
|||
|
||||
func TestQuerySaveAndRestoreEmpty(t *testing.T) {
|
||||
t.Parallel()
|
||||
var q Query
|
||||
var q Text
|
||||
// Save an empty query
|
||||
q.SaveQuery()
|
||||
require.Equal(t, "", q.String())
|
||||
|
|
@ -104,7 +104,7 @@ func TestQueryDeleteRange(t *testing.T) {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
var q Query
|
||||
var q Text
|
||||
q.Set(tt.initial)
|
||||
q.DeleteRange(tt.start, tt.end)
|
||||
require.Equal(t, tt.expected, q.String())
|
||||
|
|
@ -114,7 +114,7 @@ func TestQueryDeleteRange(t *testing.T) {
|
|||
|
||||
func TestQueryRuneSlice(t *testing.T) {
|
||||
t.Parallel()
|
||||
var q Query
|
||||
var q Text
|
||||
q.Set("hello")
|
||||
|
||||
runes := q.RuneSlice()
|
||||
|
|
@ -127,14 +127,14 @@ func TestQueryRuneSlice(t *testing.T) {
|
|||
|
||||
func TestQueryRuneSliceEmpty(t *testing.T) {
|
||||
t.Parallel()
|
||||
var q Query
|
||||
var q Text
|
||||
runes := q.RuneSlice()
|
||||
require.Empty(t, runes)
|
||||
}
|
||||
|
||||
func TestQueryRuneAt(t *testing.T) {
|
||||
t.Parallel()
|
||||
var q Query
|
||||
var q Text
|
||||
q.Set("hello")
|
||||
|
||||
require.Equal(t, 'h', q.RuneAt(0))
|
||||
|
|
@ -144,7 +144,7 @@ func TestQueryRuneAt(t *testing.T) {
|
|||
|
||||
func TestQueryRuneAtUnicode(t *testing.T) {
|
||||
t.Parallel()
|
||||
var q Query
|
||||
var q Text
|
||||
q.Set("あいう")
|
||||
|
||||
require.Equal(t, 'あ', q.RuneAt(0))
|
||||
|
|
@ -154,7 +154,7 @@ func TestQueryRuneAtUnicode(t *testing.T) {
|
|||
|
||||
func TestQueryRuneAtOutOfBounds(t *testing.T) {
|
||||
t.Parallel()
|
||||
var q Query
|
||||
var q Text
|
||||
q.Set("hello")
|
||||
|
||||
// Out-of-bounds index returns zero rune without panicking
|
||||
|
|
@ -166,7 +166,7 @@ func TestQueryRuneAtOutOfBounds(t *testing.T) {
|
|||
require.Equal(t, rune(0), q.RuneAt(-100))
|
||||
|
||||
// Empty query: any index returns zero rune
|
||||
var empty Query
|
||||
var empty Text
|
||||
require.Equal(t, rune(0), empty.RuneAt(0))
|
||||
require.Equal(t, rune(0), empty.RuneAt(-1))
|
||||
}
|
||||
|
|
@ -189,7 +189,7 @@ func TestQueryInsertAt(t *testing.T) {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
var q Query
|
||||
var q Text
|
||||
q.Set(tt.initial)
|
||||
q.InsertAt(tt.ch, tt.where)
|
||||
require.Equal(t, tt.expected, q.String())
|
||||
|
|
@ -199,7 +199,7 @@ func TestQueryInsertAt(t *testing.T) {
|
|||
|
||||
func TestQueryMultipleInserts(t *testing.T) {
|
||||
t.Parallel()
|
||||
var q Query
|
||||
var q Text
|
||||
// Build "abc" by inserting one character at a time
|
||||
q.InsertAt('a', 0)
|
||||
q.InsertAt('b', 1)
|
||||
|
|
@ -214,3 +214,63 @@ func TestQueryMultipleInserts(t *testing.T) {
|
|||
q.InsertAt('X', 2)
|
||||
require.Equal(t, "0aXbc", q.String())
|
||||
}
|
||||
|
||||
func TestCaretInitialPos(t *testing.T) {
|
||||
t.Parallel()
|
||||
var c Caret
|
||||
require.Equal(t, 0, c.Pos())
|
||||
}
|
||||
|
||||
func TestCaretSetPos(t *testing.T) {
|
||||
t.Parallel()
|
||||
var c Caret
|
||||
c.SetPos(5)
|
||||
require.Equal(t, 5, c.Pos())
|
||||
|
||||
c.SetPos(0)
|
||||
require.Equal(t, 0, c.Pos())
|
||||
|
||||
c.SetPos(100)
|
||||
require.Equal(t, 100, c.Pos())
|
||||
}
|
||||
|
||||
func TestCaretMove(t *testing.T) {
|
||||
t.Parallel()
|
||||
var c Caret
|
||||
c.SetPos(5)
|
||||
|
||||
c.Move(3)
|
||||
require.Equal(t, 8, c.Pos())
|
||||
|
||||
c.Move(-2)
|
||||
require.Equal(t, 6, c.Pos())
|
||||
|
||||
// Move to negative territory
|
||||
c.Move(-10)
|
||||
require.Equal(t, -4, c.Pos())
|
||||
}
|
||||
|
||||
func TestCaretMoveFromZero(t *testing.T) {
|
||||
t.Parallel()
|
||||
var c Caret
|
||||
|
||||
c.Move(1)
|
||||
require.Equal(t, 1, c.Pos())
|
||||
|
||||
c.Move(-1)
|
||||
require.Equal(t, 0, c.Pos())
|
||||
}
|
||||
|
||||
func TestCaretMultipleMoves(t *testing.T) {
|
||||
t.Parallel()
|
||||
var c Caret
|
||||
for range 10 {
|
||||
c.Move(1)
|
||||
}
|
||||
require.Equal(t, 10, c.Pos())
|
||||
|
||||
for range 5 {
|
||||
c.Move(-1)
|
||||
}
|
||||
require.Equal(t, 5, c.Pos())
|
||||
}
|
||||
Loading…
Reference in a new issue