Skip to content

Commit 23a23a7

Browse files
committed
support third party renderer
1 parent 520964d commit 23a23a7

File tree

6 files changed

+694
-67
lines changed

6 files changed

+694
-67
lines changed

codes.go

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ const (
6565
// The functions inside the map link the state, color and background colors strings detected in templates to a Styler
6666
// function that applies the given style using the corresponding constant.
6767
var FuncMap = template.FuncMap{
68+
"default": Styler(reset),
6869
"black": Styler(FGBlack),
6970
"red": Styler(FGRed),
7071
"green": Styler(FGGreen),

go.mod

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@ go 1.12
44

55
require (
66
github.com/chzyer/readline v1.5.1
7-
golang.org/x/sys v0.10.0 // indirect
7+
github.com/mattn/go-runewidth v0.0.15
8+
github.com/rivo/uniseg v0.4.4 // indirect
9+
golang.org/x/sys v0.16.0 // indirect
810
)

go.sum

+9-10
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
2-
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
1+
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
32
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
4-
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
5-
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
63
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
74
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
8-
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
9-
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
5+
github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
106
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
11-
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b h1:MQE+LT/ABUuuvEZ+YQAMSXindAdUh7slEmAkup74op4=
12-
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
7+
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
8+
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
9+
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
10+
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
11+
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
1312
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
14-
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
15-
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
13+
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
14+
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

screenbuf/screenbuf.go

+13
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,19 @@ func (s *ScreenBuf) Write(b []byte) (int, error) {
110110
}
111111
}
112112

113+
// WriteLines writes multiple lines to the underlining buffer.
114+
func (s *ScreenBuf) WriteLines(b []byte) (int, error) {
115+
total := 0
116+
for _, d := range bytes.Split(b, []byte("\n")) {
117+
n, err := s.Write(d)
118+
if err != nil {
119+
return total + n, err
120+
}
121+
total += n
122+
}
123+
return total, nil
124+
}
125+
113126
// Flush writes any buffered data to the underlying io.Writer, ensuring that any pending data is displayed.
114127
func (s *ScreenBuf) Flush() error {
115128
for i := s.cursor; i < s.height; i++ {

select.go

+73-56
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"io"
77
"os"
88
"strings"
9-
"text/tabwriter"
109
"text/template"
1110

1211
"github.com/chzyer/readline"
@@ -184,6 +183,15 @@ type SelectTemplates struct {
184183
// Keywords is a text/template for the search keywords.
185184
Keywords string
186185

186+
// HideLabel sets whether to hide the label.
187+
HideLabel bool
188+
189+
// ItemsRenderer is a custom rendering visible items function.
190+
ItemsRenderer func(items []interface{}, idx int) string
191+
192+
// DetailsRenderer is a custom rendering active item function.
193+
DetailsRenderer func(item interface{}) string
194+
187195
// FuncMap is a map of helper functions that can be used inside of templates according to the text/template
188196
// documentation.
189197
//
@@ -252,6 +260,44 @@ func (s *Select) getKeywords(keywords string) string {
252260
return s.Keywords + " " + keywords
253261
}
254262

263+
func (s *Select) renderItems(items []interface{}, idx int, top rune) []byte {
264+
last := len(items) - 1
265+
266+
var buf bytes.Buffer
267+
w := NewWriter(&buf, 0, 0, 2, ' ', 0)
268+
for i, item := range items {
269+
page := " "
270+
271+
switch i {
272+
case 0:
273+
if s.list.CanPageUp() {
274+
page = "↑"
275+
} else {
276+
page = string(top)
277+
}
278+
case last:
279+
if s.list.CanPageDown() {
280+
page = "↓"
281+
}
282+
}
283+
284+
output := []byte(page + " ")
285+
286+
if i == idx {
287+
output = append(output, render(s.Templates.active, item)...)
288+
} else {
289+
output = append(output, render(s.Templates.inactive, item)...)
290+
}
291+
292+
w.Write(output)
293+
if i != last {
294+
w.Write([]byte("\n"))
295+
}
296+
}
297+
w.Flush()
298+
return buf.Bytes()
299+
}
300+
255301
func (s *Select) innerRun(cursorPos, scroll int, top rune) (int, string, error) {
256302
c := &readline.Config{
257303
Stdin: s.Stdin,
@@ -369,55 +415,27 @@ func (s *Select) innerRun(cursorPos, scroll int, top rune) (int, string, error)
369415
sb.Write(render(s.Templates.keywords, s.Keywords))
370416
}
371417

372-
label := render(s.Templates.label, s.Label)
373-
sb.Write(label)
418+
if !s.Templates.HideLabel {
419+
label := render(s.Templates.label, s.Label)
420+
sb.WriteLines(label)
421+
}
374422

375423
items, idx := s.list.Items()
376-
last := len(items) - 1
377-
378-
var buf bytes.Buffer
379-
w := tabwriter.NewWriter(&buf, 0, 0, 2, ' ', 0)
380-
for i, item := range items {
381-
page := " "
382-
383-
switch i {
384-
case 0:
385-
if s.list.CanPageUp() {
386-
page = "↑"
387-
} else {
388-
page = string(top)
389-
}
390-
case last:
391-
if s.list.CanPageDown() {
392-
page = "↓"
393-
}
394-
}
395-
396-
output := []byte(page + " ")
397-
398-
if i == idx {
399-
output = append(output, render(s.Templates.active, item)...)
400-
} else {
401-
output = append(output, render(s.Templates.inactive, item)...)
402-
}
403-
404-
w.Write(output)
405-
w.Write([]byte("\n"))
406-
}
407-
w.Flush()
408-
for _, d := range bytes.Split(buf.Bytes(), []byte("\n")) {
409-
sb.Write(d)
424+
if s.Templates.ItemsRenderer != nil {
425+
sb.WriteLines([]byte(s.Templates.ItemsRenderer(items, idx)))
426+
} else {
427+
sb.WriteLines(s.renderItems(items, idx, top))
410428
}
411429

412430
if idx == list.NotFound {
413431
sb.WriteString("")
414432
sb.WriteString("No results")
415433
} else {
416434
active := items[idx]
417-
418-
details := s.renderDetails(active)
419-
for _, d := range details {
420-
sb.Write(d)
435+
if s.Templates.DetailsRenderer != nil {
436+
sb.WriteLines([]byte(s.Templates.DetailsRenderer(active)))
437+
} else {
438+
sb.WriteLines(s.renderDetails(active))
421439
}
422440
}
423441

@@ -508,22 +526,24 @@ func (s *Select) prepareTemplates() error {
508526
tpls.FuncMap = FuncMap
509527
}
510528

511-
if tpls.Label == "" {
512-
tpls.Label = fmt.Sprintf("%s {{.}}: ", IconInitial)
513-
}
529+
if !tpls.HideLabel {
530+
if tpls.Label == "" {
531+
tpls.Label = fmt.Sprintf("%s {{.}}: ", IconInitial)
532+
}
514533

515-
tpl, err := template.New("").Funcs(tpls.FuncMap).Parse(tpls.Label)
516-
if err != nil {
517-
return err
518-
}
534+
tpl, err := template.New("").Funcs(tpls.FuncMap).Parse(tpls.Label)
535+
if err != nil {
536+
return err
537+
}
519538

520-
tpls.label = tpl
539+
tpls.label = tpl
540+
}
521541

522542
if tpls.Active == "" {
523543
tpls.Active = fmt.Sprintf("%s {{ . | underline }}", IconSelect)
524544
}
525545

526-
tpl, err = template.New("").Funcs(tpls.FuncMap).Parse(tpls.Active)
546+
tpl, err := template.New("").Funcs(tpls.FuncMap).Parse(tpls.Active)
527547
if err != nil {
528548
return err
529549
}
@@ -699,25 +719,22 @@ func (s *Select) setKeys() {
699719
}
700720
}
701721

702-
func (s *Select) renderDetails(item interface{}) [][]byte {
722+
func (s *Select) renderDetails(item interface{}) []byte {
703723
if s.Templates.details == nil {
704724
return nil
705725
}
706726

707727
var buf bytes.Buffer
708728

709-
w := tabwriter.NewWriter(&buf, 0, 0, 2, ' ', 0)
729+
w := NewWriter(&buf, 0, 0, 2, ' ', 0)
710730

711731
err := s.Templates.details.Execute(w, item)
712732
if err != nil {
713733
fmt.Fprintf(w, "%v", item)
714734
}
715735

716736
w.Flush()
717-
718-
output := buf.Bytes()
719-
720-
return bytes.Split(output, []byte("\n"))
737+
return buf.Bytes()
721738
}
722739

723740
func (s *Select) renderHelp(b bool) []byte {

0 commit comments

Comments
 (0)