mirror of
https://github.com/bcicen/ctop.git
synced 2024-08-30 18:23:19 +00:00
Merge pull request #108 from HotelsDotCom/master
line wrapping in log view, closes #106
This commit is contained in:
commit
75f4a91f11
@ -1,8 +1,6 @@
|
|||||||
package widgets
|
package widgets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
ui "github.com/gizak/termui"
|
ui "github.com/gizak/termui"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,7 +16,7 @@ type TextView struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewTextView(lines <-chan string) *TextView {
|
func NewTextView(lines <-chan string) *TextView {
|
||||||
i := &TextView{
|
t := &TextView{
|
||||||
Block: *ui.NewBlock(),
|
Block: *ui.NewBlock(),
|
||||||
inputStream: lines,
|
inputStream: lines,
|
||||||
render: make(chan bool),
|
render: make(chan bool),
|
||||||
@ -29,68 +27,83 @@ func NewTextView(lines <-chan string) *TextView {
|
|||||||
padding: Padding{4, 2},
|
padding: Padding{4, 2},
|
||||||
}
|
}
|
||||||
|
|
||||||
i.BorderFg = ui.ThemeAttr("menu.border.fg")
|
t.BorderFg = ui.ThemeAttr("menu.border.fg")
|
||||||
i.BorderLabelFg = ui.ThemeAttr("menu.label.fg")
|
t.BorderLabelFg = ui.ThemeAttr("menu.label.fg")
|
||||||
|
t.Height = ui.TermHeight()
|
||||||
|
t.Width = ui.TermWidth()
|
||||||
|
|
||||||
i.Resize()
|
t.readInputLoop()
|
||||||
|
t.renderLoop()
|
||||||
i.readInputLoop()
|
return t
|
||||||
i.renderLoop()
|
|
||||||
return i
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *TextView) Resize() {
|
func (t *TextView) Resize() {
|
||||||
ui.Clear()
|
ui.Clear()
|
||||||
i.Height = ui.TermHeight()
|
t.Height = ui.TermHeight()
|
||||||
i.Width = ui.TermWidth()
|
t.Width = ui.TermWidth()
|
||||||
|
t.render <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *TextView) Buffer() ui.Buffer {
|
func (t *TextView) Buffer() ui.Buffer {
|
||||||
|
|
||||||
var cell ui.Cell
|
var cell ui.Cell
|
||||||
buf := i.Block.Buffer()
|
buf := t.Block.Buffer()
|
||||||
|
|
||||||
x := i.Block.X + i.padding[0]
|
x := t.Block.X + t.padding[0]
|
||||||
y := i.Block.Y + i.padding[1]
|
y := t.Block.Y + t.padding[1]
|
||||||
|
|
||||||
maxWidth := i.Width - (i.padding[0] * 2)
|
for _, line := range t.TextOut {
|
||||||
|
|
||||||
for _, line := range i.TextOut {
|
|
||||||
// truncate lines longer than maxWidth
|
|
||||||
if len(line) > maxWidth {
|
|
||||||
line = fmt.Sprintf("%s...", line[:maxWidth-3])
|
|
||||||
}
|
|
||||||
for _, ch := range line {
|
for _, ch := range line {
|
||||||
cell = ui.Cell{Ch: ch, Fg: i.TextFgColor, Bg: i.TextBgColor}
|
cell = ui.Cell{Ch: ch, Fg: t.TextFgColor, Bg: t.TextBgColor}
|
||||||
buf.Set(x, y, cell)
|
buf.Set(x, y, cell)
|
||||||
x++
|
x++
|
||||||
}
|
}
|
||||||
x = i.Block.X + i.padding[0]
|
x = t.Block.X + t.padding[0]
|
||||||
y++
|
y++
|
||||||
}
|
}
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *TextView) renderLoop() {
|
func (t *TextView) renderLoop() {
|
||||||
go func() {
|
go func() {
|
||||||
for range i.render {
|
for range t.render {
|
||||||
size := i.Height - (i.padding[1] * 2)
|
maxWidth := t.Width - (t.padding[0] * 2)
|
||||||
if size > len(i.Text) {
|
height := t.Height - (t.padding[1] * 2)
|
||||||
size = len(i.Text)
|
t.TextOut = []string{}
|
||||||
|
for i := len(t.Text) - 1; i >= 0; i-- {
|
||||||
|
lines := splitLine(t.Text[i], maxWidth)
|
||||||
|
t.TextOut = append(lines, t.TextOut...)
|
||||||
|
if len(t.TextOut) > height {
|
||||||
|
t.TextOut = t.TextOut[:height]
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
i.TextOut = i.Text[len(i.Text)-size:]
|
ui.Render(t)
|
||||||
|
|
||||||
ui.Render(i)
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *TextView) readInputLoop() {
|
func (t *TextView) readInputLoop() {
|
||||||
go func() {
|
go func() {
|
||||||
for line := range i.inputStream {
|
for line := range t.inputStream {
|
||||||
i.Text = append(i.Text, line)
|
t.Text = append(t.Text, line)
|
||||||
i.render <- true
|
t.render <- true
|
||||||
}
|
}
|
||||||
close(i.render)
|
close(t.render)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func splitLine(line string, lineSize int) []string {
|
||||||
|
if line == "" {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var lines []string
|
||||||
|
for {
|
||||||
|
if len(line) <= lineSize {
|
||||||
|
lines = append(lines, line)
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
lines = append(lines, line[:lineSize])
|
||||||
|
line = line[lineSize:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
35
widgets/view_test.go
Normal file
35
widgets/view_test.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package widgets
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestSplitEmptyLine(t *testing.T) {
|
||||||
|
|
||||||
|
result := splitLine("", 5)
|
||||||
|
if len(result) != 0 {
|
||||||
|
t.Errorf("expected: 0 lines, got: %d", len(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitLineShorterThanLimit(t *testing.T) {
|
||||||
|
|
||||||
|
result := splitLine("hello", 7)
|
||||||
|
if len(result) != 1 {
|
||||||
|
t.Errorf("expected: 0 lines, got: %d", len(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitLineLongerThanLimit(t *testing.T) {
|
||||||
|
|
||||||
|
result := splitLine("hello", 3)
|
||||||
|
if len(result) != 2 {
|
||||||
|
t.Errorf("expected: 0 lines, got: %d", len(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitLineSameAsLimit(t *testing.T) {
|
||||||
|
|
||||||
|
result := splitLine("hello", 5)
|
||||||
|
if len(result) != 1 {
|
||||||
|
t.Errorf("expected: 0 lines, got: %d", len(result))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user