1
0
mirror of https://github.com/taigrr/wtf synced 2025-01-18 04:03:14 -08:00
wtf/modules/textfile/widget.go
Sean Smith 5abd701b40 Decouple modules from global config
Rather than referencing wtc.Config, instead pass the global config
Also, look up config for the module early and pass that in sooner, to deal with fewer long paths and get rid of the
ConfigKey variable
2019-04-27 22:26:23 -04:00

205 lines
4.4 KiB
Go

package textfile
import (
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"time"
"github.com/alecthomas/chroma/formatters"
"github.com/alecthomas/chroma/lexers"
"github.com/alecthomas/chroma/styles"
"github.com/gdamore/tcell"
"github.com/radovskyb/watcher"
"github.com/rivo/tview"
"github.com/wtfutil/wtf/wtf"
)
const HelpText = `
Keyboard commands for Textfile:
/: Show/hide this help window
h: Previous text file
l: Next text file
o: Open the text file in the operating system
arrow left: Previous text file
arrow right: Next text file
`
type Widget struct {
wtf.HelpfulWidget
wtf.MultiSourceWidget
wtf.TextWidget
app *tview.Application
settings *Settings
}
func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *Widget {
widget := Widget{
HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
MultiSourceWidget: wtf.NewMultiSourceWidget(settings.common.Name, "filePath", "filePaths"),
TextWidget: wtf.NewTextWidget(app, settings.common, true),
app: app,
settings: settings,
}
// Don't use a timer for this widget, watch for filesystem changes instead
widget.settings.common.RefreshInterval = 0
widget.HelpfulWidget.SetView(widget.View)
widget.LoadSources()
widget.SetDisplayFunction(widget.display)
widget.View.SetWrap(true)
widget.View.SetWordWrap(true)
widget.View.SetInputCapture(widget.keyboardIntercept)
go widget.watchForFileChanges()
return &widget
}
/* -------------------- Exported Functions -------------------- */
// Refresh is only called once on start-up. Its job is to display the
// text files that first time. After that, the watcher takes over
func (widget *Widget) Refresh() {
widget.app.QueueUpdateDraw(func() {
widget.display()
})
}
/* -------------------- Unexported Functions -------------------- */
func (widget *Widget) display() {
title := fmt.Sprintf("[green]%s[white]", widget.CurrentSource())
title = widget.ContextualTitle(title)
_, _, width, _ := widget.View.GetRect()
text := widget.settings.common.SigilStr(len(widget.Sources), widget.Idx, width) + "\n"
if widget.settings.format {
text = text + widget.formattedText()
} else {
text = text + widget.plainText()
}
widget.View.SetTitle(title) // <- Writes to TextView's title
widget.View.SetText(text) // <- Writes to TextView's text
}
func (widget *Widget) fileName() string {
return filepath.Base(widget.CurrentSource())
}
func (widget *Widget) formattedText() string {
filePath, _ := wtf.ExpandHomeDir(widget.CurrentSource())
file, err := os.Open(filePath)
if err != nil {
return err.Error()
}
lexer := lexers.Match(filePath)
if lexer == nil {
lexer = lexers.Fallback
}
style := styles.Get(widget.settings.formatStyle)
if style == nil {
style = styles.Fallback
}
formatter := formatters.Get("terminal256")
if formatter == nil {
formatter = formatters.Fallback
}
contents, _ := ioutil.ReadAll(file)
iterator, _ := lexer.Tokenise(nil, string(contents))
var buf bytes.Buffer
formatter.Format(&buf, style, iterator)
return tview.TranslateANSI(buf.String())
}
func (widget *Widget) plainText() string {
filePath, _ := wtf.ExpandHomeDir(widget.CurrentSource())
fmt.Println(filePath)
text, err := ioutil.ReadFile(filePath)
if err != nil {
return err.Error()
}
return string(text)
}
func (widget *Widget) keyboardIntercept(event *tcell.EventKey) *tcell.EventKey {
switch string(event.Rune()) {
case "/":
widget.ShowHelp()
return nil
case "h":
widget.Prev()
return nil
case "l":
widget.Next()
return nil
case "o":
wtf.OpenFile(widget.CurrentSource())
return nil
}
switch event.Key() {
case tcell.KeyLeft:
widget.Prev()
return nil
case tcell.KeyRight:
widget.Next()
return nil
default:
return event
}
return event
}
func (widget *Widget) watchForFileChanges() {
watch := watcher.New()
watch.FilterOps(watcher.Write)
go func() {
for {
select {
case <-watch.Event:
widget.display()
case err := <-watch.Error:
log.Fatalln(err)
case <-watch.Closed:
return
}
}
}()
// Watch each textfile for changes
for _, source := range widget.Sources {
fullPath, err := wtf.ExpandHomeDir(source)
if err == nil {
if err := watch.Add(fullPath); err != nil {
log.Fatalln(err)
}
}
}
// Start the watching process - it'll check for changes every 100ms.
if err := watch.Start(time.Millisecond * 100); err != nil {
log.Fatalln(err)
}
}