mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
CmdRunner now updates view while running
This commit is contained in:
parent
c5b36d8f6d
commit
45b9555633
@ -7,17 +7,21 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultFocusable = false
|
defaultFocusable = true
|
||||||
defaultTitle = "CmdRunner"
|
defaultTitle = "CmdRunner"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Settings for the cmdrunner widget
|
||||||
type Settings struct {
|
type Settings struct {
|
||||||
common *cfg.Common
|
common *cfg.Common
|
||||||
|
|
||||||
args []string `help:"The arguments to the command, with each item as an element in an array. Example: for curl -I cisco.com, the arguments array would be ['-I', 'cisco.com']."`
|
args []string `help:"The arguments to the command, with each item as an element in an array. Example: for curl -I cisco.com, the arguments array would be ['-I', 'cisco.com']."`
|
||||||
cmd string `help:"The terminal command to be run, withouth the arguments. Ie: ping, whoami, curl."`
|
cmd string `help:"The terminal command to be run, withouth the arguments. Ie: ping, whoami, curl."`
|
||||||
|
tail bool `help:"Automatically scroll to the end of the command output."`
|
||||||
|
maxLines int `help:"Maximum number of lines kept in the buffer."`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewSettingsFromYAML loads the cmdrunner portion of the WTF config
|
||||||
func NewSettingsFromYAML(name string, moduleConfig *config.Config, globalConfig *config.Config) *Settings {
|
func NewSettingsFromYAML(name string, moduleConfig *config.Config, globalConfig *config.Config) *Settings {
|
||||||
|
|
||||||
settings := Settings{
|
settings := Settings{
|
||||||
@ -25,6 +29,8 @@ func NewSettingsFromYAML(name string, moduleConfig *config.Config, globalConfig
|
|||||||
|
|
||||||
args: utils.ToStrs(moduleConfig.UList("args")),
|
args: utils.ToStrs(moduleConfig.UList("args")),
|
||||||
cmd: moduleConfig.UString("cmd"),
|
cmd: moduleConfig.UString("cmd"),
|
||||||
|
tail: moduleConfig.UBool("tail"),
|
||||||
|
maxLines: moduleConfig.UInt("maxLines", -1),
|
||||||
}
|
}
|
||||||
|
|
||||||
return &settings
|
return &settings
|
||||||
|
@ -1,21 +1,25 @@
|
|||||||
package cmdrunner
|
package cmdrunner
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/rivo/tview"
|
"github.com/rivo/tview"
|
||||||
"github.com/wtfutil/wtf/utils"
|
|
||||||
"github.com/wtfutil/wtf/view"
|
"github.com/wtfutil/wtf/view"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Widget contains the data for this widget
|
||||||
type Widget struct {
|
type Widget struct {
|
||||||
view.TextWidget
|
view.TextWidget
|
||||||
|
|
||||||
args []string
|
|
||||||
cmd string
|
|
||||||
settings *Settings
|
settings *Settings
|
||||||
|
|
||||||
|
m sync.Mutex
|
||||||
|
buffer *bytes.Buffer
|
||||||
|
running bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWidget creates a new instance of the widget
|
// NewWidget creates a new instance of the widget
|
||||||
@ -23,18 +27,18 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
|
|||||||
widget := Widget{
|
widget := Widget{
|
||||||
TextWidget: view.NewTextWidget(app, settings.common),
|
TextWidget: view.NewTextWidget(app, settings.common),
|
||||||
|
|
||||||
args: settings.args,
|
|
||||||
cmd: settings.cmd,
|
|
||||||
settings: settings,
|
settings: settings,
|
||||||
|
buffer: &bytes.Buffer{},
|
||||||
}
|
}
|
||||||
|
|
||||||
widget.View.SetWrap(true)
|
widget.View.SetWrap(true)
|
||||||
|
widget.View.SetScrollable(true)
|
||||||
|
|
||||||
return &widget
|
return &widget
|
||||||
}
|
}
|
||||||
|
|
||||||
func (widget *Widget) content() (string, string, bool) {
|
func (widget *Widget) content() (string, string, bool) {
|
||||||
result := widget.execute()
|
result := widget.buffer.String()
|
||||||
|
|
||||||
ansiTitle := tview.TranslateANSI(widget.CommonSettings().Title)
|
ansiTitle := tview.TranslateANSI(widget.CommonSettings().Title)
|
||||||
if ansiTitle == defaultTitle {
|
if ansiTitle == defaultTitle {
|
||||||
@ -47,23 +51,86 @@ func (widget *Widget) content() (string, string, bool) {
|
|||||||
|
|
||||||
// Refresh executes the command and updates the view with the results
|
// Refresh executes the command and updates the view with the results
|
||||||
func (widget *Widget) Refresh() {
|
func (widget *Widget) Refresh() {
|
||||||
|
widget.m.Lock()
|
||||||
|
defer widget.m.Unlock()
|
||||||
|
|
||||||
|
widget.execute()
|
||||||
widget.Redraw(widget.content)
|
widget.Redraw(widget.content)
|
||||||
|
if widget.settings.tail {
|
||||||
|
widget.View.ScrollToEnd()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the string representation of the widget
|
// String returns the string representation of the widget
|
||||||
func (widget *Widget) String() string {
|
func (widget *Widget) String() string {
|
||||||
args := strings.Join(widget.args, " ")
|
args := strings.Join(widget.settings.args, " ")
|
||||||
|
|
||||||
if args != "" {
|
if args != "" {
|
||||||
return fmt.Sprintf(" %s %s ", widget.cmd, args)
|
return fmt.Sprintf(" %s %s ", widget.settings.cmd, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf(" %s ", widget.cmd)
|
return fmt.Sprintf(" %s ", widget.settings.cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (widget *Widget) Write(p []byte) (n int, err error) {
|
||||||
|
widget.m.Lock()
|
||||||
|
defer widget.m.Unlock()
|
||||||
|
|
||||||
|
// Write the new data into the buffer
|
||||||
|
n, err = widget.buffer.Write(p)
|
||||||
|
|
||||||
|
// Remove lines that exceed maxLines
|
||||||
|
lines := widget.countLines()
|
||||||
|
if lines > widget.settings.maxLines {
|
||||||
|
widget.drainLines(lines - widget.settings.maxLines)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redraw the widget
|
||||||
|
widget.Redraw(widget.content)
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------- Unexported Functions -------------------- */
|
/* -------------------- Unexported Functions -------------------- */
|
||||||
|
|
||||||
func (widget *Widget) execute() string {
|
func (widget *Widget) execute() {
|
||||||
cmd := exec.Command(widget.cmd, widget.args...)
|
// Make sure the command is not already running
|
||||||
return utils.ExecuteCommand(cmd)
|
if widget.running {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the buffer
|
||||||
|
widget.buffer.Reset()
|
||||||
|
|
||||||
|
// Indicate that the command is running
|
||||||
|
widget.running = true
|
||||||
|
|
||||||
|
// Setup the command to run
|
||||||
|
cmd := exec.Command(widget.settings.cmd, widget.settings.args...)
|
||||||
|
cmd.Stdout = widget
|
||||||
|
|
||||||
|
// Run the command and wait for it to exit in another Go-routine
|
||||||
|
go func() {
|
||||||
|
err := cmd.Run()
|
||||||
|
|
||||||
|
// The command has exited, print any error messages
|
||||||
|
widget.m.Lock()
|
||||||
|
if err != nil {
|
||||||
|
widget.buffer.WriteString(err.Error())
|
||||||
|
}
|
||||||
|
widget.running = false
|
||||||
|
widget.m.Unlock()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// countLines counts the lines of data in the buffer
|
||||||
|
func (widget *Widget) countLines() int {
|
||||||
|
return bytes.Count(widget.buffer.Bytes(), []byte{'\n'})
|
||||||
|
}
|
||||||
|
|
||||||
|
// drainLines removed the first n lines from the buffer
|
||||||
|
func (widget *Widget) drainLines(n int) {
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
widget.buffer.ReadBytes('\n')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user