From 0e797fea3d9fc036063cc3a858bfac6ddef7e617 Mon Sep 17 00:00:00 2001 From: Chris Cummer Date: Thu, 30 Aug 2018 07:52:59 -0700 Subject: [PATCH] Textfile module now supports multiple text files --- _site/content/modules/textfile.md | 8 +- docs/index.json | 2 +- docs/index.xml | 4 +- docs/modules/google/gspreadsheet/index.html | 15 +++ docs/modules/index.xml | 4 +- docs/modules/textfile/index.html | 8 +- docs/modules/todoist/index.html | 12 +++ .../weather_services/weather/index.html | 15 +++ git/widget.go | 48 +++++----- textfile/widget.go | 93 ++++++++++++++++--- wtf/billboard_modal.go | 5 +- wtf/utils.go | 2 + 12 files changed, 168 insertions(+), 48 deletions(-) diff --git a/_site/content/modules/textfile.md b/_site/content/modules/textfile.md index 0aed87ee..17cda058 100644 --- a/_site/content/modules/textfile.md +++ b/_site/content/modules/textfile.md @@ -28,7 +28,9 @@ wtf/textfile/ ```yaml textfile: enabled: true - filePath: "~/Desktop/notes.md" + filePaths: + - "~/Desktop/notes.md" + - "~/.config/wtf/config.yml" format: true formatStyle: "dracula" position: @@ -45,8 +47,8 @@ textfile: Determines whether or not this module is executed and if its data displayed onscreen.
Values: `true`, `false`. -`filePath`
-The path to the file to be displayed in the widget.
+`filePaths`
+An array of paths to the files to be displayed in the widget.
`format`
Whether or not to try and format and syntax highlight the displayedtext.
diff --git a/docs/index.json b/docs/index.json index 3805d4d3..573e028d 100644 --- a/docs/index.json +++ b/docs/index.json @@ -249,7 +249,7 @@ "title": "Textfile", "tags": [], "description": "", - "content": " Displays the contents of the specified text file in the widget.\nSource Code wtf/textfile/ Keyboard Commands Key: / Action: Open/close the widget\u0026rsquo;s help window.\nKey: o Action: Opens the text file in whichever text editor is associated with that file type.\nConfiguration textfile:enabled:truefilePath:\u0026#34;~/Desktop/notes.md\u0026#34;format:trueformatStyle:\u0026#34;dracula\u0026#34;position:top:5left:4height:2width:1refreshInterval:15 Attributes enabled Determines whether or not this module is executed and if its data displayed onscreen. Values: true, false.\nfilePath The path to the file to be displayed in the widget. format Whether or not to try and format and syntax highlight the displayedtext. Values: true, false. Default: false.\nformatStyle The style of syntax highlighting to format the text with. Values: See Chroma styles for all valid options. Default: vim.\nposition Defines where in the grid this module\u0026rsquo;s widget will be displayed. refreshInterval How often, in seconds, this module will update its data. Values: A positive integer, 0..n.\n" + "content": " Displays the contents of the specified text file in the widget.\nSource Code wtf/textfile/ Keyboard Commands Key: / Action: Open/close the widget\u0026rsquo;s help window.\nKey: o Action: Opens the text file in whichever text editor is associated with that file type.\nConfiguration textfile:enabled:truefilePaths:-\u0026#34;~/Desktop/notes.md\u0026#34;-\u0026#34;~/.config/wtf/config.yml\u0026#34;format:trueformatStyle:\u0026#34;dracula\u0026#34;position:top:5left:4height:2width:1refreshInterval:15 Attributes enabled Determines whether or not this module is executed and if its data displayed onscreen. Values: true, false.\nfilePaths An array of paths to the files to be displayed in the widget. format Whether or not to try and format and syntax highlight the displayedtext. Values: true, false. Default: false.\nformatStyle The style of syntax highlighting to format the text with. Values: See Chroma styles for all valid options. Default: vim.\nposition Defines where in the grid this module\u0026rsquo;s widget will be displayed. refreshInterval How often, in seconds, this module will update its data. Values: A positive integer, 0..n.\n" }, { "uri": "https://wtfutil.com/modules/todo/", diff --git a/docs/index.xml b/docs/index.xml index 0ee622b4..9373bd9d 100644 --- a/docs/index.xml +++ b/docs/index.xml @@ -419,8 +419,8 @@ Wifi Network The name of the current network Whether or not the network uses enc Displays the contents of the specified text file in the widget. Source Code wtf/textfile/ Keyboard Commands Key: / Action: Open/close the widget’s help window. Key: o Action: Opens the text file in whichever text editor is associated with that file type. -Configuration textfile:enabled:truefilePath:"~/Desktop/notes.md"format:trueformatStyle:"dracula"position:top:5left:4height:2width:1refreshInterval:15 Attributes enabled Determines whether or not this module is executed and if its data displayed onscreen. Values: true, false. -filePath The path to the file to be displayed in the widget. +Configuration textfile:enabled:truefilePaths:-"~/Desktop/notes.md"-"~/.config/wtf/config.yml"format:trueformatStyle:"dracula"position:top:5left:4height:2width:1refreshInterval:15 Attributes enabled Determines whether or not this module is executed and if its data displayed onscreen. Values: true, false. +filePaths An array of paths to the files to be displayed in the widget. diff --git a/docs/modules/google/gspreadsheet/index.html b/docs/modules/google/gspreadsheet/index.html index b14bfd67..e52f1a03 100644 --- a/docs/modules/google/gspreadsheet/index.html +++ b/docs/modules/google/gspreadsheet/index.html @@ -411,13 +411,25 @@ + + + + + + @@ -431,6 +443,9 @@ + diff --git a/docs/modules/index.xml b/docs/modules/index.xml index aa15a26e..31e6db50 100644 --- a/docs/modules/index.xml +++ b/docs/modules/index.xml @@ -269,8 +269,8 @@ Wifi Network The name of the current network Whether or not the network uses enc Displays the contents of the specified text file in the widget. Source Code wtf/textfile/ Keyboard Commands Key: / Action: Open/close the widget’s help window. Key: o Action: Opens the text file in whichever text editor is associated with that file type. -Configuration textfile:enabled:truefilePath:"~/Desktop/notes.md"format:trueformatStyle:"dracula"position:top:5left:4height:2width:1refreshInterval:15 Attributes enabled Determines whether or not this module is executed and if its data displayed onscreen. Values: true, false. -filePath The path to the file to be displayed in the widget. +Configuration textfile:enabled:truefilePaths:-"~/Desktop/notes.md"-"~/.config/wtf/config.yml"format:trueformatStyle:"dracula"position:top:5left:4height:2width:1refreshInterval:15 Attributes enabled Determines whether or not this module is executed and if its data displayed onscreen. Values: true, false. +filePaths An array of paths to the files to be displayed in the widget. diff --git a/docs/modules/textfile/index.html b/docs/modules/textfile/index.html index c87c423e..30e81a51 100644 --- a/docs/modules/textfile/index.html +++ b/docs/modules/textfile/index.html @@ -489,7 +489,9 @@

Configuration

textfile:
   enabled: true
-  filePath: "~/Desktop/notes.md"
+  filePaths:
+  - "~/Desktop/notes.md"
+  - "~/.config/wtf/config.yml"
   format: true
   formatStyle: "dracula"
   position:
@@ -504,8 +506,8 @@
 Determines whether or not this module is executed and if its data displayed onscreen. 
Values: true, false.

-

filePath
-The path to the file to be displayed in the widget.

+

filePaths
+An array of paths to the files to be displayed in the widget.

format
Whether or not to try and format and syntax highlight the displayedtext.
diff --git a/docs/modules/todoist/index.html b/docs/modules/todoist/index.html index 5560b0e9..13aaefed 100644 --- a/docs/modules/todoist/index.html +++ b/docs/modules/todoist/index.html @@ -410,13 +410,22 @@ + + + @@ -430,6 +439,9 @@ + diff --git a/docs/modules/weather_services/weather/index.html b/docs/modules/weather_services/weather/index.html index ec7c24ca..cfab6b23 100644 --- a/docs/modules/weather_services/weather/index.html +++ b/docs/modules/weather_services/weather/index.html @@ -411,13 +411,22 @@ + + + @@ -431,6 +440,12 @@ + + + + diff --git a/git/widget.go b/git/widget.go index a79b58b9..8daf4240 100644 --- a/git/widget.go +++ b/git/widget.go @@ -10,10 +10,10 @@ const HelpText = ` Keyboard commands for Git: /: Show/hide this help window + c: Checkout to branch h: Previous git repository l: Next git repository - p: Pull current git repository - c: Checkout to branch + p: Pull current git repository arrow left: Previous git repository arrow right: Next git repository @@ -51,12 +51,21 @@ func NewWidget(app *tview.Application, pages *tview.Pages) *Widget { /* -------------------- Exported Functions -------------------- */ -func (widget *Widget) Refresh() { - repoPaths := wtf.ToStrs(wtf.Config.UList("wtf.mods.git.repositories")) +func (widget *Widget) Checkout() { + form := widget.modalForm("Branch to checkout:", "") - widget.UpdateRefreshedAt() - widget.Data = widget.gitRepos(repoPaths) - widget.display() + checkoutFctn := func() { + text := form.GetFormItem(0).(*tview.InputField).GetText() + repoToCheckout := widget.Data[widget.Idx] + repoToCheckout.checkout(text) + widget.pages.RemovePage("modal") + widget.app.SetFocus(widget.View) + widget.display() + widget.Refresh() + } + + widget.addButtons(form, checkoutFctn) + widget.modalFocus(form) } func (widget *Widget) Next() { @@ -76,38 +85,33 @@ func (widget *Widget) Prev() { widget.display() } + func (widget *Widget) Pull() { repoToPull := widget.Data[widget.Idx] repoToPull.pull() widget.Refresh() } -func (widget *Widget) Checkout() { - form := widget.modalForm("Branch to checkout:", "") - checkoutFctn := func() { - text := form.GetFormItem(0).(*tview.InputField).GetText() - repoToCheckout := widget.Data[widget.Idx] - repoToCheckout.checkout(text) - widget.pages.RemovePage("modal") - widget.app.SetFocus(widget.View) - widget.display() - widget.Refresh() - } - - widget.addButtons(form, checkoutFctn) - widget.modalFocus(form) +func (widget *Widget) Refresh() { + repoPaths := wtf.ToStrs(wtf.Config.UList("wtf.mods.git.repositories")) + widget.UpdateRefreshedAt() + widget.Data = widget.gitRepos(repoPaths) + widget.display() } /* -------------------- Unexported Functions -------------------- */ + func (widget *Widget) addCheckoutButton(form *tview.Form, fctn func()) { form.AddButton("Checkout", fctn) } + func (widget *Widget) addButtons(form *tview.Form, checkoutFctn func()) { widget.addCheckoutButton(form, checkoutFctn) widget.addCancelButton(form) } + func (widget *Widget) addCancelButton(form *tview.Form) { cancelFn := func() { widget.pages.RemovePage("modal") @@ -118,6 +122,7 @@ func (widget *Widget) addCancelButton(form *tview.Form) { form.AddButton("Cancel", cancelFn) form.SetCancelFunc(cancelFn) } + func (widget *Widget) modalFocus(form *tview.Form) { frame := widget.modalFrame(form) widget.pages.AddPage("modal", frame, false, true) @@ -133,6 +138,7 @@ func (widget *Widget) modalForm(lbl, text string) *tview.Form { return form } + func (widget *Widget) modalFrame(form *tview.Form) *tview.Frame { frame := tview.NewFrame(form).SetBorders(0, 0, 0, 0, 0, 0) frame.SetRect(offscreen, offscreen, modalWidth, modalHeight) diff --git a/textfile/widget.go b/textfile/widget.go index 30d6ba9d..5194ba19 100644 --- a/textfile/widget.go +++ b/textfile/widget.go @@ -18,14 +18,20 @@ 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.TextWidget - filePath string + filePaths []string + idx int } func NewWidget(app *tview.Application, pages *tview.Pages) *Widget { @@ -33,9 +39,11 @@ func NewWidget(app *tview.Application, pages *tview.Pages) *Widget { HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText), TextWidget: wtf.NewTextWidget("TextFile", "textfile", true), - filePath: wtf.Config.UString("wtf.mods.textfile.filePath"), + idx: 0, } + widget.loadFilePaths() + widget.HelpfulWidget.SetView(widget.View) widget.View.SetWrap(true) @@ -47,28 +55,56 @@ func NewWidget(app *tview.Application, pages *tview.Pages) *Widget { /* -------------------- Exported Functions -------------------- */ +func (widget *Widget) Next() { + widget.idx = widget.idx + 1 + if widget.idx == len(widget.filePaths) { + widget.idx = 0 + } + + widget.display() +} + +func (widget *Widget) Prev() { + widget.idx = widget.idx - 1 + if widget.idx < 0 { + widget.idx = len(widget.filePaths) - 1 + } + + widget.display() +} + func (widget *Widget) Refresh() { widget.UpdateRefreshedAt() + + widget.display() +} + +/* -------------------- Unexported Functions -------------------- */ + +func (widget *Widget) currentFilePath() string { + return widget.filePaths[widget.idx] +} + +func (widget *Widget) display() { widget.View.SetTitle(widget.ContextualTitle(widget.fileName())) - var text string + text := wtf.SigilStr(len(widget.filePaths), widget.idx, widget.View) + "\n" + if wtf.Config.UBool("wtf.mods.textfile.format", false) { - text = widget.formattedText() + text = text + widget.formattedText() } else { - text = widget.plainText() + text = text + widget.plainText() } widget.View.SetText(text) } -/* -------------------- Unexported Functions -------------------- */ - func (widget *Widget) fileName() string { - return filepath.Base(widget.filePath) + return filepath.Base(widget.currentFilePath()) } func (widget *Widget) formattedText() string { - filePath, _ := wtf.ExpandHomeDir(widget.filePath) + filePath, _ := wtf.ExpandHomeDir(widget.currentFilePath()) file, err := os.Open(filePath) if err != nil { @@ -98,8 +134,24 @@ func (widget *Widget) formattedText() string { return tview.TranslateANSI(buf.String()) } +// loadFilePaths parses file paths from the config and stores them in an array +// It is backwards-compatible, supporting both the original, singular filePath and +// the current plural filePaths +func (widget *Widget) loadFilePaths() { + var emptyArray []interface{} + + filePath := wtf.Config.UString("wtf.mods.textfile.filePath", "") + filePaths := wtf.ToStrs(wtf.Config.UList("wtf.mods.textfile.filePaths", emptyArray)) + + if filePath != "" { + filePaths = append(filePaths, filePath) + } + + widget.filePaths = filePaths +} + func (widget *Widget) plainText() string { - filePath, _ := wtf.ExpandHomeDir(widget.filePath) + filePath, _ := wtf.ExpandHomeDir(widget.currentFilePath()) text, err := ioutil.ReadFile(filePath) // just pass the file name if err != nil { @@ -113,9 +165,26 @@ func (widget *Widget) keyboardIntercept(event *tcell.EventKey) *tcell.EventKey { case "/": widget.ShowHelp() return nil - case "o": - wtf.OpenFile(widget.filePath) + case "h": + widget.Prev() return nil + case "l": + widget.Next() + return nil + case "o": + wtf.OpenFile(widget.currentFilePath()) + return nil + } + + switch event.Key() { + case tcell.KeyLeft: + widget.Prev() + return nil + case tcell.KeyRight: + widget.Next() + return nil + default: + return event } return event diff --git a/wtf/billboard_modal.go b/wtf/billboard_modal.go index 70137c2a..fedc8e6d 100644 --- a/wtf/billboard_modal.go +++ b/wtf/billboard_modal.go @@ -29,12 +29,10 @@ func NewBillboardModal(text string, closeFunc func()) *tview.Frame { } textView := tview.NewTextView() + textView.SetInputCapture(keyboardIntercept) textView.SetWrap(true) textView.SetText(text) - textView.SetBackgroundColor(tview.Styles.ContrastBackgroundColor) - textView.SetInputCapture(keyboardIntercept) - frame := tview.NewFrame(textView) frame.SetRect(offscreen, offscreen, modalWidth, modalHeight) @@ -44,7 +42,6 @@ func NewBillboardModal(text string, closeFunc func()) *tview.Frame { return x, y, width, height } - frame.SetBackgroundColor(tview.Styles.ContrastBackgroundColor) frame.SetBorder(true) frame.SetBorders(1, 1, 0, 0, 1, 1) frame.SetDrawFunc(drawFunc) diff --git a/wtf/utils.go b/wtf/utils.go index 05e00183..4ebb989c 100644 --- a/wtf/utils.go +++ b/wtf/utils.go @@ -156,6 +156,7 @@ func SigilStr(len, pos int, view *tview.TextView) string { func ToInts(slice []interface{}) []int { results := []int{} + for _, val := range slice { results = append(results, val.(int)) } @@ -165,6 +166,7 @@ func ToInts(slice []interface{}) []int { func ToStrs(slice []interface{}) []string { results := []string{} + for _, val := range slice { results = append(results, val.(string)) }