From 5d8d032808de1c665f5fd60b4d3e599249a692c8 Mon Sep 17 00:00:00 2001 From: vilmibm Date: Tue, 8 Nov 2022 11:44:43 -0800 Subject: [PATCH 01/17] move help to its own window --- pkg/cmd/extension/browse/browse.go | 64 ++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/pkg/cmd/extension/browse/browse.go b/pkg/cmd/extension/browse/browse.go index be605ef9c..1f83ba212 100644 --- a/pkg/cmd/extension/browse/browse.go +++ b/pkg/cmd/extension/browse/browse.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/MakeNowJust/heredoc" "github.com/charmbracelet/glamour" "github.com/cli/cli/v2/git" "github.com/cli/cli/v2/internal/config" @@ -365,9 +366,7 @@ func ExtBrowse(opts ExtBrowseOpts) error { readme.SetBorder(true).SetBorderColor(tcell.ColorPurple) help := tview.NewTextView() - help.SetText( - "/: filter i/r: install/remove w: open in browser pgup/pgdn: scroll readme q: quit") - help.SetTextAlign(tview.AlignCenter) + help.SetText("?: help q: quit") ui := uiRegistry{ App: app, @@ -436,13 +435,65 @@ func ExtBrowse(opts ExtBrowseOpts) error { app.SetAfterDrawFunc(nil) }) + helpActive := false + app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { if filter.HasFocus() { return event } switch event.Rune() { + case '?': + if helpActive { + helpActive = false + app.SetRoot(outerFlex, true) + return nil + } + helpActive = true + helpBig := tview.NewTextView() + helpBig.SetDynamicColors(true) + helpBig.SetBorderPadding(0, 0, 2, 0) + helpBig.SetText(heredoc.Doc(` + [::b]= Application =[-:-:-] + + ?: toggle help + q: quit + + [::b]= Navigating =[-:-:-] + + ↓, j: scroll list of extensions down by 1 + ↑, k: scroll list of extensions up by 1 + + shift+j, space: scroll list of extensions down by 25 + shift+k, ctrl+space (mac), shift+space (windows): scroll list of extensions up by 25 + + [::b]= Extension Management =[-:-:-] + + i: install highlighted extension + r: remove highlighted extension + w: open highlighted extension in web browser + + [::b]= Filtering =[-:-:-] + + /: focus filter + enter: finish filtering and go back to list + escape: clear filter and reset list + + [::b]= Readmes =[-:-:-] + + page down: scroll readme pane down + page up: scroll readme pane up + + (On a mac, page down and page up are fn+down arrow and fn+up arrow) + + `)) + app.SetRoot(helpBig, true) case 'q': + if helpActive { + helpActive = false + app.SetRoot(outerFlex, true) + return nil + } app.Stop() case 'k': extList.ScrollUp() @@ -488,10 +539,15 @@ func ExtBrowse(opts ExtBrowseOpts) error { go loadSelectedReadme() return nil case tcell.KeyEscape: + if helpActive { + helpActive = false + app.SetRoot(outerFlex, true) + return nil + } filter.SetText("") extList.Reset() case tcell.KeyCtrlSpace: - // The ctrl check works on windows/mac and not windows: + // The ctrl check works on linux/mac and not windows: extList.PageUp() go loadSelectedReadme() case tcell.KeyCtrlJ: From 2f42196fbe85708215b55188edd2fdd9776d3981 Mon Sep 17 00:00:00 2001 From: vilmibm Date: Tue, 8 Nov 2022 11:59:48 -0800 Subject: [PATCH 02/17] these were bad --- pkg/cmd/extension/browse/browse.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pkg/cmd/extension/browse/browse.go b/pkg/cmd/extension/browse/browse.go index 1f83ba212..4cf84d4bc 100644 --- a/pkg/cmd/extension/browse/browse.go +++ b/pkg/cmd/extension/browse/browse.go @@ -454,12 +454,12 @@ func ExtBrowse(opts ExtBrowseOpts) error { helpBig.SetDynamicColors(true) helpBig.SetBorderPadding(0, 0, 2, 0) helpBig.SetText(heredoc.Doc(` - [::b]= Application =[-:-:-] + [::b]Application[-:-:-] ?: toggle help q: quit - [::b]= Navigating =[-:-:-] + [::b]Navigation[-:-:-] ↓, j: scroll list of extensions down by 1 ↑, k: scroll list of extensions up by 1 @@ -467,25 +467,24 @@ func ExtBrowse(opts ExtBrowseOpts) error { shift+j, space: scroll list of extensions down by 25 shift+k, ctrl+space (mac), shift+space (windows): scroll list of extensions up by 25 - [::b]= Extension Management =[-:-:-] + [::b]Extension Management[-:-:-] i: install highlighted extension r: remove highlighted extension w: open highlighted extension in web browser - [::b]= Filtering =[-:-:-] + [::b]Filtering[-:-:-] /: focus filter enter: finish filtering and go back to list escape: clear filter and reset list - [::b]= Readmes =[-:-:-] + [::b]Readmes[-:-:-] page down: scroll readme pane down page up: scroll readme pane up (On a mac, page down and page up are fn+down arrow and fn+up arrow) - `)) app.SetRoot(helpBig, true) case 'q': From 69a1f0aba2015a2724186527a31dd3c30971279c Mon Sep 17 00:00:00 2001 From: vilmibm Date: Tue, 13 Dec 2022 15:32:28 -0800 Subject: [PATCH 03/17] use Pages to render help --- pkg/cmd/extension/browse/browse.go | 88 ++++++++++++++++-------------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/pkg/cmd/extension/browse/browse.go b/pkg/cmd/extension/browse/browse.go index 4cf84d4bc..91fa484a1 100644 --- a/pkg/cmd/extension/browse/browse.go +++ b/pkg/cmd/extension/browse/browse.go @@ -421,7 +421,49 @@ func ExtBrowse(opts ExtBrowseOpts) error { outerFlex.AddItem(innerFlex, 0, 1, true) outerFlex.AddItem(help, 1, -1, false) - app.SetRoot(outerFlex, true) + // TODO better name + helpBig := tview.NewTextView() + helpBig.SetDynamicColors(true) + helpBig.SetBorderPadding(0, 0, 2, 0) + helpBig.SetText(heredoc.Doc(` + [::b]Application[-:-:-] + + ?: toggle help + q: quit + + [::b]Navigation[-:-:-] + + ↓, j: scroll list of extensions down by 1 + ↑, k: scroll list of extensions up by 1 + + shift+j, space: scroll list of extensions down by 25 + shift+k, ctrl+space (mac), shift+space (windows): scroll list of extensions up by 25 + + [::b]Extension Management[-:-:-] + + i: install highlighted extension + r: remove highlighted extension + w: open highlighted extension in web browser + + [::b]Filtering[-:-:-] + + /: focus filter + enter: finish filtering and go back to list + escape: clear filter and reset list + + [::b]Readmes[-:-:-] + + page down: scroll readme pane down + page up: scroll readme pane up + + (On a mac, page down and page up are fn+down arrow and fn+up arrow) + `)) + + pages := tview.NewPages() + pages.AddPage("main", outerFlex, true, true) + pages.AddPage("help", helpBig, true, false) + + app.SetRoot(pages, true) // Force fetching of initial readme by loading it just prior to the first // draw. The callback is removed immediately after draw. @@ -437,6 +479,8 @@ func ExtBrowse(opts ExtBrowseOpts) error { helpActive := false + // TODO filter should not be activated when helpActive is true + app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { if filter.HasFocus() { return event @@ -445,52 +489,16 @@ func ExtBrowse(opts ExtBrowseOpts) error { switch event.Rune() { case '?': if helpActive { + pages.SwitchToPage("main") helpActive = false - app.SetRoot(outerFlex, true) return nil } helpActive = true - helpBig := tview.NewTextView() - helpBig.SetDynamicColors(true) - helpBig.SetBorderPadding(0, 0, 2, 0) - helpBig.SetText(heredoc.Doc(` - [::b]Application[-:-:-] - - ?: toggle help - q: quit - - [::b]Navigation[-:-:-] - - ↓, j: scroll list of extensions down by 1 - ↑, k: scroll list of extensions up by 1 - - shift+j, space: scroll list of extensions down by 25 - shift+k, ctrl+space (mac), shift+space (windows): scroll list of extensions up by 25 - - [::b]Extension Management[-:-:-] - - i: install highlighted extension - r: remove highlighted extension - w: open highlighted extension in web browser - - [::b]Filtering[-:-:-] - - /: focus filter - enter: finish filtering and go back to list - escape: clear filter and reset list - - [::b]Readmes[-:-:-] - - page down: scroll readme pane down - page up: scroll readme pane up - - (On a mac, page down and page up are fn+down arrow and fn+up arrow) - `)) - app.SetRoot(helpBig, true) + pages.SwitchToPage("help") case 'q': if helpActive { helpActive = false - app.SetRoot(outerFlex, true) + pages.SwitchToPage("main") return nil } app.Stop() From d42744fb04db61b645e5cde5ab1cff62b36b6e73 Mon Sep 17 00:00:00 2001 From: vilmibm Date: Tue, 13 Dec 2022 15:35:08 -0800 Subject: [PATCH 04/17] freeze input when help active --- pkg/cmd/extension/browse/browse.go | 45 +++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/pkg/cmd/extension/browse/browse.go b/pkg/cmd/extension/browse/browse.go index 91fa484a1..b24202785 100644 --- a/pkg/cmd/extension/browse/browse.go +++ b/pkg/cmd/extension/browse/browse.go @@ -425,6 +425,7 @@ func ExtBrowse(opts ExtBrowseOpts) error { helpBig := tview.NewTextView() helpBig.SetDynamicColors(true) helpBig.SetBorderPadding(0, 0, 2, 0) + // TODO clean this text up helpBig.SetText(heredoc.Doc(` [::b]Application[-:-:-] @@ -503,14 +504,23 @@ func ExtBrowse(opts ExtBrowseOpts) error { } app.Stop() case 'k': + if helpActive { + return nil + } extList.ScrollUp() readme.SetText("...fetching readme...") go loadSelectedReadme() case 'j': + if helpActive { + return nil + } extList.ScrollDown() readme.SetText("...fetching readme...") go loadSelectedReadme() case 'w': + if helpActive { + return nil + } ee, ix := extList.FindSelected() if ix < 0 { opts.Logger.Println("failed to find selected entry") @@ -521,10 +531,19 @@ func ExtBrowse(opts ExtBrowseOpts) error { opts.Logger.Println(fmt.Errorf("could not open browser for '%s': %w", ee.URL, err)) } case 'i': + if helpActive { + return nil + } extList.InstallSelected() case 'r': + if helpActive { + return nil + } extList.RemoveSelected() case ' ': + if helpActive { + return nil + } // The shift check works on windows and not linux/mac: if event.Modifiers()&tcell.ModShift != 0 { extList.PageUp() @@ -533,43 +552,67 @@ func ExtBrowse(opts ExtBrowseOpts) error { } go loadSelectedReadme() case '/': + if helpActive { + return nil + } app.SetFocus(filter) return nil } switch event.Key() { case tcell.KeyUp: + if helpActive { + return nil + } extList.ScrollUp() go loadSelectedReadme() return nil case tcell.KeyDown: + if helpActive { + return nil + } extList.ScrollDown() go loadSelectedReadme() return nil case tcell.KeyEscape: if helpActive { helpActive = false - app.SetRoot(outerFlex, true) + pages.SwitchToPage("main") return nil } filter.SetText("") extList.Reset() case tcell.KeyCtrlSpace: + if helpActive { + return nil + } // The ctrl check works on linux/mac and not windows: extList.PageUp() go loadSelectedReadme() case tcell.KeyCtrlJ: + if helpActive { + return nil + } extList.PageDown() go loadSelectedReadme() case tcell.KeyCtrlK: + if helpActive { + return nil + } extList.PageUp() go loadSelectedReadme() case tcell.KeyPgUp: + if helpActive { + return nil + } row, col := readme.GetScrollOffset() if row > 0 { readme.ScrollTo(row-2, col) } return nil case tcell.KeyPgDn: + if helpActive { + return nil + } row, col := readme.GetScrollOffset() readme.ScrollTo(row+2, col) return nil From 0a82a57eeb0dbd27d765fce43186fe4d8e1cd8f4 Mon Sep 17 00:00:00 2001 From: vilmibm Date: Wed, 14 Dec 2022 14:51:32 -0800 Subject: [PATCH 05/17] WIP on single column support --- pkg/cmd/extension/browse/browse.go | 42 +++++++++++++++++++++--------- pkg/cmd/extension/command.go | 19 ++++++++------ 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/pkg/cmd/extension/browse/browse.go b/pkg/cmd/extension/browse/browse.go index b24202785..3ae04ef3e 100644 --- a/pkg/cmd/extension/browse/browse.go +++ b/pkg/cmd/extension/browse/browse.go @@ -26,16 +26,17 @@ import ( const pagingOffset = 24 type ExtBrowseOpts struct { - Cmd *cobra.Command - Browser ibrowser - IO *iostreams.IOStreams - Searcher search.Searcher - Em extensions.ExtensionManager - Client *http.Client - Logger *log.Logger - Cfg config.Config - Rg *readmeGetter - Debug bool + Cmd *cobra.Command + Browser ibrowser + IO *iostreams.IOStreams + Searcher search.Searcher + Em extensions.ExtensionManager + Client *http.Client + Logger *log.Logger + Cfg config.Config + Rg *readmeGetter + Debug bool + SingleColumn bool } type ibrowser interface { @@ -49,7 +50,7 @@ type uiRegistry struct { App *tview.Application Outerflex *tview.Flex List *tview.List - Readme *tview.TextView + Pages *tview.Pages } type extEntry struct { @@ -97,6 +98,12 @@ func newExtList(opts ExtBrowseOpts, ui uiRegistry, extEntries []extEntry) *extLi ui.List.SetSelectedBackgroundColor(tcell.ColorWhite) ui.List.SetWrapAround(false) ui.List.SetBorderPadding(1, 1, 1, 1) + if opts.SingleColumn { + ui.List.SetSelectedFunc(func(ix int, _, _ string, _ rune) { + + // TODO switch to readme page + }) + } el := &extList{ ui: ui, @@ -109,6 +116,7 @@ func newExtList(opts ExtBrowseOpts, ui uiRegistry, extEntries []extEntry) *extLi return el } +// TODO use pages for this func (el *extList) createModal() *tview.Modal { m := tview.NewModal() m.SetBackgroundColor(tcell.ColorPurple) @@ -368,10 +376,13 @@ func ExtBrowse(opts ExtBrowseOpts) error { help := tview.NewTextView() help.SetText("?: help q: quit") + pages := tview.NewPages() + ui := uiRegistry{ App: app, Outerflex: outerFlex, List: list, + Pages: pages, } extList := newExtList(opts, ui, extEntries) @@ -413,7 +424,9 @@ func ExtBrowse(opts ExtBrowseOpts) error { innerFlex.SetDirection(tview.FlexColumn) innerFlex.AddItem(list, 0, 1, true) - innerFlex.AddItem(readme, 0, 1, false) + if !opts.SingleColumn { + innerFlex.AddItem(readme, 0, 1, false) + } outerFlex.SetDirection(tview.FlexRow) outerFlex.AddItem(header, 1, -1, false) @@ -460,10 +473,13 @@ func ExtBrowse(opts ExtBrowseOpts) error { (On a mac, page down and page up are fn+down arrow and fn+up arrow) `)) - pages := tview.NewPages() pages.AddPage("main", outerFlex, true, true) pages.AddPage("help", helpBig, true, false) + if opts.SingleColumn { + pages.AddPage("readme", readme, true, false) + } + app.SetRoot(pages, true) // Force fetching of initial readme by loading it just prior to the first diff --git a/pkg/cmd/extension/command.go b/pkg/cmd/extension/command.go index 3bfd8cfe8..f47d09d37 100644 --- a/pkg/cmd/extension/command.go +++ b/pkg/cmd/extension/command.go @@ -410,6 +410,7 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command { }, func() *cobra.Command { var debug bool + var singleColumn bool cmd := &cobra.Command{ Use: "browse", Short: "Enter a UI for browsing, adding, and removing extensions", @@ -460,20 +461,22 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command { searcher := search.NewSearcher(api.NewCachedHTTPClient(client, time.Hour*24), host) opts := browse.ExtBrowseOpts{ - Cmd: cmd, - IO: io, - Browser: browser, - Searcher: searcher, - Em: m, - Client: client, - Cfg: cfg, - Debug: debug, + Cmd: cmd, + IO: io, + Browser: browser, + Searcher: searcher, + Em: m, + Client: client, + Cfg: cfg, + Debug: debug, + SingleColumn: singleColumn, } return browse.ExtBrowse(opts) }, } cmd.Flags().BoolVar(&debug, "debug", false, "log to /tmp/extBrowse-*") + cmd.Flags().BoolVarP(&singleColumn, "single-column", "s", false, "Render TUI with only one column of text") return cmd }(), &cobra.Command{ From bcc0d2b838cc11377dea67a689d866a73c836565 Mon Sep 17 00:00:00 2001 From: vilmibm Date: Thu, 26 Jan 2023 12:02:51 -0800 Subject: [PATCH 06/17] clean up some key handling --- pkg/cmd/extension/browse/browse.go | 99 +++++++++--------------------- 1 file changed, 29 insertions(+), 70 deletions(-) diff --git a/pkg/cmd/extension/browse/browse.go b/pkg/cmd/extension/browse/browse.go index 3ae04ef3e..3c246184b 100644 --- a/pkg/cmd/extension/browse/browse.go +++ b/pkg/cmd/extension/browse/browse.go @@ -494,8 +494,6 @@ func ExtBrowse(opts ExtBrowseOpts) error { app.SetAfterDrawFunc(nil) }) - helpActive := false - // TODO filter should not be activated when helpActive is true app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { @@ -503,40 +501,49 @@ func ExtBrowse(opts ExtBrowseOpts) error { return event } + curPage, _ := pages.GetFrontPage() + + if curPage != "main" { + if event.Rune() == 'q' || event.Key() == tcell.KeyEscape { + pages.SwitchToPage("main") + return nil + } + switch curPage { + case "readme": + switch event.Key() { + case tcell.KeyPgUp: + row, col := readme.GetScrollOffset() + if row > 0 { + readme.ScrollTo(row-2, col) + } + case tcell.KeyPgDn: + row, col := readme.GetScrollOffset() + readme.ScrollTo(row+2, col) + } + case "help": + switch event.Rune() { + case '?': + pages.SwitchToPage("main") + } + } + return nil + } + switch event.Rune() { case '?': - if helpActive { - pages.SwitchToPage("main") - helpActive = false - return nil - } - helpActive = true pages.SwitchToPage("help") + return nil case 'q': - if helpActive { - helpActive = false - pages.SwitchToPage("main") - return nil - } app.Stop() case 'k': - if helpActive { - return nil - } extList.ScrollUp() readme.SetText("...fetching readme...") go loadSelectedReadme() case 'j': - if helpActive { - return nil - } extList.ScrollDown() readme.SetText("...fetching readme...") go loadSelectedReadme() case 'w': - if helpActive { - return nil - } ee, ix := extList.FindSelected() if ix < 0 { opts.Logger.Println("failed to find selected entry") @@ -547,19 +554,10 @@ func ExtBrowse(opts ExtBrowseOpts) error { opts.Logger.Println(fmt.Errorf("could not open browser for '%s': %w", ee.URL, err)) } case 'i': - if helpActive { - return nil - } extList.InstallSelected() case 'r': - if helpActive { - return nil - } extList.RemoveSelected() case ' ': - if helpActive { - return nil - } // The shift check works on windows and not linux/mac: if event.Modifiers()&tcell.ModShift != 0 { extList.PageUp() @@ -568,70 +566,31 @@ func ExtBrowse(opts ExtBrowseOpts) error { } go loadSelectedReadme() case '/': - if helpActive { - return nil - } app.SetFocus(filter) return nil } switch event.Key() { case tcell.KeyUp: - if helpActive { - return nil - } extList.ScrollUp() go loadSelectedReadme() return nil case tcell.KeyDown: - if helpActive { - return nil - } extList.ScrollDown() go loadSelectedReadme() return nil case tcell.KeyEscape: - if helpActive { - helpActive = false - pages.SwitchToPage("main") - return nil - } filter.SetText("") extList.Reset() case tcell.KeyCtrlSpace: - if helpActive { - return nil - } // The ctrl check works on linux/mac and not windows: extList.PageUp() go loadSelectedReadme() case tcell.KeyCtrlJ: - if helpActive { - return nil - } extList.PageDown() go loadSelectedReadme() case tcell.KeyCtrlK: - if helpActive { - return nil - } extList.PageUp() go loadSelectedReadme() - case tcell.KeyPgUp: - if helpActive { - return nil - } - row, col := readme.GetScrollOffset() - if row > 0 { - readme.ScrollTo(row-2, col) - } - return nil - case tcell.KeyPgDn: - if helpActive { - return nil - } - row, col := readme.GetScrollOffset() - readme.ScrollTo(row+2, col) - return nil } return event From 868af11b9dc87350352e6ada5b5003736c89e30a Mon Sep 17 00:00:00 2001 From: vilmibm Date: Thu, 26 Jan 2023 16:05:32 -0800 Subject: [PATCH 07/17] WIP on using pages --- pkg/cmd/extension/browse/browse.go | 62 +++++++++++++++--------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/pkg/cmd/extension/browse/browse.go b/pkg/cmd/extension/browse/browse.go index 3c246184b..09d3bd343 100644 --- a/pkg/cmd/extension/browse/browse.go +++ b/pkg/cmd/extension/browse/browse.go @@ -51,6 +51,7 @@ type uiRegistry struct { Outerflex *tview.Flex List *tview.List Pages *tview.Pages + CmdFlex *tview.Flex } type extEntry struct { @@ -98,12 +99,9 @@ func newExtList(opts ExtBrowseOpts, ui uiRegistry, extEntries []extEntry) *extLi ui.List.SetSelectedBackgroundColor(tcell.ColorWhite) ui.List.SetWrapAround(false) ui.List.SetBorderPadding(1, 1, 1, 1) - if opts.SingleColumn { - ui.List.SetSelectedFunc(func(ix int, _, _ string, _ rune) { - - // TODO switch to readme page - }) - } + ui.List.SetSelectedFunc(func(ix int, _, _ string, _ rune) { + ui.Pages.SwitchToPage("readme") + }) el := &extList{ ui: ui, @@ -118,10 +116,11 @@ func newExtList(opts ExtBrowseOpts, ui uiRegistry, extEntries []extEntry) *extLi // TODO use pages for this func (el *extList) createModal() *tview.Modal { + // TODO this should be put on a page and the page should be switched to and away from m := tview.NewModal() m.SetBackgroundColor(tcell.ColorPurple) m.SetDoneFunc(func(_ int, _ string) { - el.ui.App.SetRoot(el.ui.Outerflex, true) + el.ui.Pages.SwitchToPage("main") el.Refresh() }) @@ -129,6 +128,7 @@ func (el *extList) createModal() *tview.Modal { } func (el *extList) InstallSelected() { + // TODO do not try to install if installed ee, ix := el.FindSelected() if ix < 0 { el.opts.Logger.Println("failed to find selected entry") @@ -141,24 +141,28 @@ func (el *extList) InstallSelected() { } modal := el.createModal() - modal.SetText(fmt.Sprintf("Installing %s...", ee.FullName)) - el.ui.App.SetRoot(modal, true) - // I could eliminate this with a goroutine but it seems to be working fine - el.app.ForceDraw() - err = el.opts.Em.Install(repo, "") - if err != nil { - modal.SetText(fmt.Sprintf("Failed to install %s: %s", ee.FullName, err.Error())) - } else { - modal.SetText(fmt.Sprintf("Installed %s!", ee.FullName)) - modal.AddButtons([]string{"ok"}) - el.ui.App.SetFocus(modal) - } - - el.toggleInstalled(ix) + el.ui.CmdFlex.AddItem(modal, 0, 1, true) + go func() { + el.app.QueueUpdateDraw(func() { + el.ui.Pages.SwitchToPage("command") + err = el.opts.Em.Install(repo, "") + if err != nil { + modal.SetText(fmt.Sprintf("Failed to install %s: %s", ee.FullName, err.Error())) + } else { + modal.SetText(fmt.Sprintf("Installed %s!", ee.FullName)) + modal.AddButtons([]string{"ok"}) + el.app.SetFocus(modal) + el.toggleInstalled(ix) + } + }) + }() + // TODO ideally this is not required + //el.app.ForceDraw() } func (el *extList) RemoveSelected() { + // TODO do not try and remove if not installed ee, ix := el.FindSelected() if ix < 0 { el.opts.Logger.Println("failed to find selected extension") @@ -376,6 +380,8 @@ func ExtBrowse(opts ExtBrowseOpts) error { help := tview.NewTextView() help.SetText("?: help q: quit") + cmdFlex := tview.NewFlex() + pages := tview.NewPages() ui := uiRegistry{ @@ -383,6 +389,7 @@ func ExtBrowse(opts ExtBrowseOpts) error { Outerflex: outerFlex, List: list, Pages: pages, + CmdFlex: cmdFlex, } extList := newExtList(opts, ui, extEntries) @@ -467,6 +474,7 @@ func ExtBrowse(opts ExtBrowseOpts) error { [::b]Readmes[-:-:-] + enter: open highlighted extension's readme full screen page down: scroll readme pane down page up: scroll readme pane up @@ -475,10 +483,8 @@ func ExtBrowse(opts ExtBrowseOpts) error { pages.AddPage("main", outerFlex, true, true) pages.AddPage("help", helpBig, true, false) - - if opts.SingleColumn { - pages.AddPage("readme", readme, true, false) - } + pages.AddPage("readme", readme, true, false) + pages.AddPage("command", cmdFlex, true, false) app.SetRoot(pages, true) @@ -494,8 +500,6 @@ func ExtBrowse(opts ExtBrowseOpts) error { app.SetAfterDrawFunc(nil) }) - // TODO filter should not be activated when helpActive is true - app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { if filter.HasFocus() { return event @@ -596,10 +600,6 @@ func ExtBrowse(opts ExtBrowseOpts) error { return event }) - // Without this redirection, the git client inside of the extension manager - // will dump git output to the terminal. - opts.IO.ErrOut = io.Discard - if err := app.Run(); err != nil { return err } From fec1f115b0c29f4a792d2a155dc0a15a1dfc89ca Mon Sep 17 00:00:00 2001 From: vilmibm Date: Thu, 26 Jan 2023 16:05:41 -0800 Subject: [PATCH 08/17] remove unused args from installGit --- pkg/cmd/extension/manager.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/cmd/extension/manager.go b/pkg/cmd/extension/manager.go index 21c2120ae..4f0e6a9fb 100644 --- a/pkg/cmd/extension/manager.go +++ b/pkg/cmd/extension/manager.go @@ -350,7 +350,7 @@ func (m *Manager) Install(repo ghrepo.Interface, target string) error { return errors.New("extension is not installable: missing executable") } - return m.installGit(repo, target, m.io.Out, m.io.ErrOut) + return m.installGit(repo, target) } func (m *Manager) installBin(repo ghrepo.Interface, target string) error { @@ -453,7 +453,7 @@ func (m *Manager) installBin(repo ghrepo.Interface, target string) error { return nil } -func (m *Manager) installGit(repo ghrepo.Interface, target string, stdout, stderr io.Writer) error { +func (m *Manager) installGit(repo ghrepo.Interface, target string) error { protocol, _ := m.config.GetOrDefault(repo.RepoHost(), "git_protocol") cloneURL := ghrepo.FormatRemoteURL(repo, protocol) From c2c4d8c3f8ddd7d9945a6cb18664b881bbc8ab29 Mon Sep 17 00:00:00 2001 From: vilmibm Date: Thu, 26 Jan 2023 16:08:08 -0800 Subject: [PATCH 09/17] fix silencing git output --- pkg/cmd/extension/command.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/cmd/extension/command.go b/pkg/cmd/extension/command.go index 1412d0ab4..548e190a8 100644 --- a/pkg/cmd/extension/command.go +++ b/pkg/cmd/extension/command.go @@ -3,6 +3,7 @@ package extension import ( "errors" "fmt" + gio "io" "os" "strings" "time" @@ -24,6 +25,7 @@ import ( func NewCmdExtension(f *cmdutil.Factory) *cobra.Command { m := f.ExtensionManager io := f.IOStreams + gc := f.GitClient prompter := f.Prompter config := f.Config browser := f.Browser @@ -460,6 +462,8 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command { searcher := search.NewSearcher(api.NewCachedHTTPClient(client, time.Hour*24), host) + gc.Stderr = gio.Discard + opts := browse.ExtBrowseOpts{ Cmd: cmd, IO: io, From f60970ffa9b56c689321682a6311d0961ef9703a Mon Sep 17 00:00:00 2001 From: vilmibm Date: Thu, 26 Jan 2023 16:32:22 -0800 Subject: [PATCH 10/17] clean up command screen --- pkg/cmd/extension/browse/browse.go | 65 ++++++++++++++++++------------ 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/pkg/cmd/extension/browse/browse.go b/pkg/cmd/extension/browse/browse.go index 09d3bd343..fd5f5e402 100644 --- a/pkg/cmd/extension/browse/browse.go +++ b/pkg/cmd/extension/browse/browse.go @@ -127,6 +127,7 @@ func (el *extList) createModal() *tview.Modal { return m } +// TODO consolidate these two functions func (el *extList) InstallSelected() { // TODO do not try to install if installed ee, ix := el.FindSelected() @@ -142,49 +143,58 @@ func (el *extList) InstallSelected() { modal := el.createModal() modal.SetText(fmt.Sprintf("Installing %s...", ee.FullName)) + el.ui.CmdFlex.Clear() el.ui.CmdFlex.AddItem(modal, 0, 1, true) go func() { el.app.QueueUpdateDraw(func() { el.ui.Pages.SwitchToPage("command") - err = el.opts.Em.Install(repo, "") - if err != nil { - modal.SetText(fmt.Sprintf("Failed to install %s: %s", ee.FullName, err.Error())) - } else { - modal.SetText(fmt.Sprintf("Installed %s!", ee.FullName)) - modal.AddButtons([]string{"ok"}) - el.app.SetFocus(modal) - el.toggleInstalled(ix) - } + go func() { + el.app.QueueUpdateDraw(func() { + err = el.opts.Em.Install(repo, "") + if err != nil { + modal.SetText(fmt.Sprintf("Failed to install %s: %s", ee.FullName, err.Error())) + } else { + modal.SetText(fmt.Sprintf("Installed %s!", ee.FullName)) + modal.AddButtons([]string{"ok"}) + el.app.SetFocus(modal) + el.toggleInstalled(ix) + } + }) + }() }) }() - // TODO ideally this is not required - //el.app.ForceDraw() } func (el *extList) RemoveSelected() { // TODO do not try and remove if not installed ee, ix := el.FindSelected() if ix < 0 { - el.opts.Logger.Println("failed to find selected extension") + el.opts.Logger.Println("failed to find selected entry") return } modal := el.createModal() - modal.SetText(fmt.Sprintf("Removing %s...", ee.FullName)) - el.ui.App.SetRoot(modal, true) - // I could eliminate this with a goroutine but it seems to be working fine - el.ui.App.ForceDraw() - - err := el.opts.Em.Remove(strings.TrimPrefix(ee.Name, "gh-")) - if err != nil { - modal.SetText(fmt.Sprintf("Failed to remove %s: %s", ee.FullName, err.Error())) - } else { - modal.SetText(fmt.Sprintf("Removed %s.", ee.FullName)) - modal.AddButtons([]string{"ok"}) - el.ui.App.SetFocus(modal) - } - el.toggleInstalled(ix) + el.ui.CmdFlex.Clear() + el.ui.CmdFlex.AddItem(modal, 0, 1, true) + go func() { + el.app.QueueUpdateDraw(func() { + el.ui.Pages.SwitchToPage("command") + go func() { + el.app.QueueUpdateDraw(func() { + err := el.opts.Em.Remove(strings.TrimPrefix(ee.Name, "gh-")) + if err != nil { + modal.SetText(fmt.Sprintf("Failed to remove %s: %s", ee.FullName, err.Error())) + } else { + modal.SetText(fmt.Sprintf("Removed %s!", ee.FullName)) + modal.AddButtons([]string{"ok"}) + el.app.SetFocus(modal) + el.toggleInstalled(ix) + } + }) + }() + }) + }() } func (el *extList) toggleInstalled(ix int) { @@ -508,6 +518,9 @@ func ExtBrowse(opts ExtBrowseOpts) error { curPage, _ := pages.GetFrontPage() if curPage != "main" { + if curPage == "command" { + return event + } if event.Rune() == 'q' || event.Key() == tcell.KeyEscape { pages.SwitchToPage("main") return nil From 3af8e56c07ff0e36eabfb547eaf68e3c28eb2b91 Mon Sep 17 00:00:00 2001 From: vilmibm Date: Thu, 26 Jan 2023 16:33:14 -0800 Subject: [PATCH 11/17] TODOs --- pkg/cmd/extension/browse/browse.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/cmd/extension/browse/browse.go b/pkg/cmd/extension/browse/browse.go index fd5f5e402..ae294b3f9 100644 --- a/pkg/cmd/extension/browse/browse.go +++ b/pkg/cmd/extension/browse/browse.go @@ -114,9 +114,7 @@ func newExtList(opts ExtBrowseOpts, ui uiRegistry, extEntries []extEntry) *extLi return el } -// TODO use pages for this func (el *extList) createModal() *tview.Modal { - // TODO this should be put on a page and the page should be switched to and away from m := tview.NewModal() m.SetBackgroundColor(tcell.ColorPurple) m.SetDoneFunc(func(_ int, _ string) { @@ -451,11 +449,9 @@ func ExtBrowse(opts ExtBrowseOpts) error { outerFlex.AddItem(innerFlex, 0, 1, true) outerFlex.AddItem(help, 1, -1, false) - // TODO better name helpBig := tview.NewTextView() helpBig.SetDynamicColors(true) helpBig.SetBorderPadding(0, 0, 2, 0) - // TODO clean this text up helpBig.SetText(heredoc.Doc(` [::b]Application[-:-:-] From ba725d7af20d6848d65e70e20c9965747f058d30 Mon Sep 17 00:00:00 2001 From: vilmibm Date: Thu, 26 Jan 2023 16:38:30 -0800 Subject: [PATCH 12/17] update doc --- pkg/cmd/extension/command.go | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/pkg/cmd/extension/command.go b/pkg/cmd/extension/command.go index 548e190a8..722163dd2 100644 --- a/pkg/cmd/extension/command.go +++ b/pkg/cmd/extension/command.go @@ -418,28 +418,19 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command { Short: "Enter a UI for browsing, adding, and removing extensions", Long: heredoc.Doc(` This command will take over your terminal and run a fully interactive - interface for browsing, adding, and removing gh extensions. + interface for browsing, adding, and removing gh extensions. A terminal + width greater than 100 columns is recommended. - The extension list is navigated with the arrow keys or with j/k. - Space and control+space (or control + j/k) page the list up and down. - Extension readmes can be scrolled with page up/page down keys - (fn + arrow up/down on a mac keyboard). - - For highlighted extensions, you can press: - - - w to open the extension in your web browser - - i to install the extension - - r to remove the extension - - Press / to focus the filter input. Press enter to scroll the results. - Press Escape to clear the filter and return to the full list. + To learn how to control this interface, press ? after running to see + the help text. Press q to quit. - The output of this command may be difficult to navigate for screen reader - users, users operating at high zoom and other users of assistive technology. It - is also not advised for automation scripts. We advise those users to use the - alternative command: + Running this command with --single-column should make this command + more intelligible for users who rely on assistive technology like screen + readers or high zoom. + + For a more traditional way to discover extensions, see: gh ext search From 3ab72f44d3599d206fbcfeeab00d148e7e2b580f Mon Sep 17 00:00:00 2001 From: vilmibm Date: Thu, 26 Jan 2023 16:40:54 -0800 Subject: [PATCH 13/17] WIP: fixing tests --- pkg/cmd/extension/browse/browse_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/cmd/extension/browse/browse_test.go b/pkg/cmd/extension/browse/browse_test.go index 8cec46607..9d2cd5ff3 100644 --- a/pkg/cmd/extension/browse/browse_test.go +++ b/pkg/cmd/extension/browse/browse_test.go @@ -274,11 +274,13 @@ func Test_extList(t *testing.T) { }, }, } + cmdFlex := tview.NewFlex() app := tview.NewApplication() list := tview.NewList() ui := uiRegistry{ - List: list, - App: app, + List: list, + App: app, + CmdFlex: cmdFlex, } extEntries := []extEntry{ { From 37eee304110dede62aaf2ce5bdf73fa8f0636d73 Mon Sep 17 00:00:00 2001 From: vilmibm Date: Tue, 31 Jan 2023 12:06:32 -0800 Subject: [PATCH 14/17] WIP fixing tests --- pkg/cmd/extension/browse/browse.go | 30 ++++++++++++++++++------- pkg/cmd/extension/browse/browse_test.go | 8 +++++++ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/pkg/cmd/extension/browse/browse.go b/pkg/cmd/extension/browse/browse.go index ae294b3f9..9f0a75669 100644 --- a/pkg/cmd/extension/browse/browse.go +++ b/pkg/cmd/extension/browse/browse.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "strings" + "sync" "time" "github.com/MakeNowJust/heredoc" @@ -86,11 +87,12 @@ func (e extEntry) Description() string { } type extList struct { - ui uiRegistry - extEntries []extEntry - app *tview.Application - filter string - opts ExtBrowseOpts + ui uiRegistry + extEntries []extEntry + app *tview.Application + filter string + opts ExtBrowseOpts + QueueUpdateDraw func(func()) } func newExtList(opts ExtBrowseOpts, ui uiRegistry, extEntries []extEntry) *extList { @@ -108,6 +110,9 @@ func newExtList(opts ExtBrowseOpts, ui uiRegistry, extEntries []extEntry) *extLi extEntries: extEntries, app: ui.App, opts: opts, + QueueUpdateDraw: func(f func()) { + ui.App.QueueUpdateDraw(f) + }, } el.Reset() @@ -143,11 +148,15 @@ func (el *extList) InstallSelected() { modal.SetText(fmt.Sprintf("Installing %s...", ee.FullName)) el.ui.CmdFlex.Clear() el.ui.CmdFlex.AddItem(modal, 0, 1, true) + wg := sync.WaitGroup{} + wg.Add(1) go func() { - el.app.QueueUpdateDraw(func() { + el.QueueUpdateDraw(func() { el.ui.Pages.SwitchToPage("command") + wg.Add(1) + wg.Done() go func() { - el.app.QueueUpdateDraw(func() { + el.QueueUpdateDraw(func() { err = el.opts.Em.Install(repo, "") if err != nil { modal.SetText(fmt.Sprintf("Failed to install %s: %s", ee.FullName, err.Error())) @@ -155,12 +164,17 @@ func (el *extList) InstallSelected() { modal.SetText(fmt.Sprintf("Installed %s!", ee.FullName)) modal.AddButtons([]string{"ok"}) el.app.SetFocus(modal) - el.toggleInstalled(ix) } + wg.Done() }) }() }) }() + + wg.Wait() + if err == nil { + el.toggleInstalled(ix) + } } func (el *extList) RemoveSelected() { diff --git a/pkg/cmd/extension/browse/browse_test.go b/pkg/cmd/extension/browse/browse_test.go index 9d2cd5ff3..9801684c7 100644 --- a/pkg/cmd/extension/browse/browse_test.go +++ b/pkg/cmd/extension/browse/browse_test.go @@ -277,10 +277,12 @@ func Test_extList(t *testing.T) { cmdFlex := tview.NewFlex() app := tview.NewApplication() list := tview.NewList() + pages := tview.NewPages() ui := uiRegistry{ List: list, App: app, CmdFlex: cmdFlex, + Pages: pages, } extEntries := []extEntry{ { @@ -315,6 +317,10 @@ func Test_extList(t *testing.T) { extList := newExtList(opts, ui, extEntries) + extList.QueueUpdateDraw = func(f func()) { + f() + } + extList.Filter("cool") assert.Equal(t, 1, extList.ui.List.GetItemCount()) @@ -324,6 +330,8 @@ func Test_extList(t *testing.T) { extList.InstallSelected() assert.True(t, extList.extEntries[0].Installed) + // so I think the goroutines are causing a later failure because the toggleInstalled isn't seen. + extList.Refresh() assert.Equal(t, 1, extList.ui.List.GetItemCount()) From 300bc2cb698c7c76e4eeb552c24a7c605ea5db54 Mon Sep 17 00:00:00 2001 From: vilmibm Date: Tue, 31 Jan 2023 14:42:34 -0800 Subject: [PATCH 15/17] fix tests --- pkg/cmd/extension/browse/browse.go | 118 ++++++++++++++---------- pkg/cmd/extension/browse/browse_test.go | 6 +- 2 files changed, 73 insertions(+), 51 deletions(-) diff --git a/pkg/cmd/extension/browse/browse.go b/pkg/cmd/extension/browse/browse.go index 9f0a75669..d5f8b660f 100644 --- a/pkg/cmd/extension/browse/browse.go +++ b/pkg/cmd/extension/browse/browse.go @@ -8,7 +8,6 @@ import ( "net/http" "os" "strings" - "sync" "time" "github.com/MakeNowJust/heredoc" @@ -92,9 +91,22 @@ type extList struct { app *tview.Application filter string opts ExtBrowseOpts - QueueUpdateDraw func(func()) + QueueUpdateDraw func(func()) *tview.Application + WaitGroup wGroup } +type wGroup interface { + Add(int) + Done() + Wait() +} + +type fakeGroup struct{} + +func (w *fakeGroup) Add(int) {} +func (w *fakeGroup) Done() {} +func (w *fakeGroup) Wait() {} + func newExtList(opts ExtBrowseOpts, ui uiRegistry, extEntries []extEntry) *extList { ui.List.SetTitleColor(tcell.ColorWhite) ui.List.SetSelectedTextColor(tcell.ColorBlack) @@ -106,13 +118,12 @@ func newExtList(opts ExtBrowseOpts, ui uiRegistry, extEntries []extEntry) *extLi }) el := &extList{ - ui: ui, - extEntries: extEntries, - app: ui.App, - opts: opts, - QueueUpdateDraw: func(f func()) { - ui.App.QueueUpdateDraw(f) - }, + ui: ui, + extEntries: extEntries, + app: ui.App, + opts: opts, + QueueUpdateDraw: ui.App.QueueUpdateDraw, + WaitGroup: &fakeGroup{}, } el.Reset() @@ -130,26 +141,52 @@ func (el *extList) createModal() *tview.Modal { return m } -// TODO consolidate these two functions -func (el *extList) InstallSelected() { - // TODO do not try to install if installed +func (el *extList) toggleSelected(verb string) { ee, ix := el.FindSelected() if ix < 0 { el.opts.Logger.Println("failed to find selected entry") return } - repo, err := ghrepo.FromFullName(ee.FullName) - if err != nil { - el.opts.Logger.Println(fmt.Errorf("failed to install '%s't: %w", ee.FullName, err)) + modal := el.createModal() + + if (ee.Installed && verb == "install") || (!ee.Installed && verb == "remove") { return } - modal := el.createModal() - modal.SetText(fmt.Sprintf("Installing %s...", ee.FullName)) + var action func() error + + if !ee.Installed { + modal.SetText(fmt.Sprintf("Installing %s...", ee.FullName)) + action = func() error { + repo, err := ghrepo.FromFullName(ee.FullName) + if err != nil { + el.opts.Logger.Println(fmt.Errorf("failed to install '%s': %w", ee.FullName, err)) + return err + } + err = el.opts.Em.Install(repo, "") + if err != nil { + return fmt.Errorf("failed to install %s: %w", ee.FullName, err) + } + return nil + } + } else { + modal.SetText(fmt.Sprintf("Removing %s...", ee.FullName)) + action = func() error { + name := strings.TrimPrefix(ee.Name, "gh-") + err := el.opts.Em.Remove(name) + if err != nil { + return fmt.Errorf("failed to remove %s: %w", ee.FullName, err) + } + return nil + } + } + el.ui.CmdFlex.Clear() el.ui.CmdFlex.AddItem(modal, 0, 1, true) - wg := sync.WaitGroup{} + var err error + wg := el.WaitGroup wg.Add(1) + go func() { el.QueueUpdateDraw(func() { el.ui.Pages.SwitchToPage("command") @@ -157,11 +194,15 @@ func (el *extList) InstallSelected() { wg.Done() go func() { el.QueueUpdateDraw(func() { - err = el.opts.Em.Install(repo, "") + err = action() if err != nil { - modal.SetText(fmt.Sprintf("Failed to install %s: %s", ee.FullName, err.Error())) + modal.SetText(err.Error()) } else { - modal.SetText(fmt.Sprintf("Installed %s!", ee.FullName)) + modalText := fmt.Sprintf("Installed %s!", ee.FullName) + if verb == "remove" { + modalText = fmt.Sprintf("Removed %s!", ee.FullName) + } + modal.SetText(modalText) modal.AddButtons([]string{"ok"}) el.app.SetFocus(modal) } @@ -171,42 +212,19 @@ func (el *extList) InstallSelected() { }) }() + // TODO blocking the app's thread and deadlocking wg.Wait() if err == nil { el.toggleInstalled(ix) } } -func (el *extList) RemoveSelected() { - // TODO do not try and remove if not installed - ee, ix := el.FindSelected() - if ix < 0 { - el.opts.Logger.Println("failed to find selected entry") - return - } +func (el *extList) InstallSelected() { + el.toggleSelected("install") +} - modal := el.createModal() - modal.SetText(fmt.Sprintf("Removing %s...", ee.FullName)) - el.ui.CmdFlex.Clear() - el.ui.CmdFlex.AddItem(modal, 0, 1, true) - go func() { - el.app.QueueUpdateDraw(func() { - el.ui.Pages.SwitchToPage("command") - go func() { - el.app.QueueUpdateDraw(func() { - err := el.opts.Em.Remove(strings.TrimPrefix(ee.Name, "gh-")) - if err != nil { - modal.SetText(fmt.Sprintf("Failed to remove %s: %s", ee.FullName, err.Error())) - } else { - modal.SetText(fmt.Sprintf("Removed %s!", ee.FullName)) - modal.AddButtons([]string{"ok"}) - el.app.SetFocus(modal) - el.toggleInstalled(ix) - } - }) - }() - }) - }() +func (el *extList) RemoveSelected() { + el.toggleSelected("remove") } func (el *extList) toggleInstalled(ix int) { diff --git a/pkg/cmd/extension/browse/browse_test.go b/pkg/cmd/extension/browse/browse_test.go index 9801684c7..aacfb37b5 100644 --- a/pkg/cmd/extension/browse/browse_test.go +++ b/pkg/cmd/extension/browse/browse_test.go @@ -6,6 +6,7 @@ import ( "log" "net/http" "net/url" + "sync" "testing" "time" @@ -317,10 +318,13 @@ func Test_extList(t *testing.T) { extList := newExtList(opts, ui, extEntries) - extList.QueueUpdateDraw = func(f func()) { + extList.QueueUpdateDraw = func(f func()) *tview.Application { f() + return app } + extList.WaitGroup = &sync.WaitGroup{} + extList.Filter("cool") assert.Equal(t, 1, extList.ui.List.GetItemCount()) From c9590f36d9ac62ac5df44d61d4292710f64d1aad Mon Sep 17 00:00:00 2001 From: vilmibm Date: Thu, 2 Feb 2023 12:18:13 -0800 Subject: [PATCH 16/17] longer small help --- pkg/cmd/extension/browse/browse.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/cmd/extension/browse/browse.go b/pkg/cmd/extension/browse/browse.go index d5f8b660f..3993f3c70 100644 --- a/pkg/cmd/extension/browse/browse.go +++ b/pkg/cmd/extension/browse/browse.go @@ -418,7 +418,8 @@ func ExtBrowse(opts ExtBrowseOpts) error { readme.SetBorder(true).SetBorderColor(tcell.ColorPurple) help := tview.NewTextView() - help.SetText("?: help q: quit") + help.SetDynamicColors(true) + help.SetText("[::b]?[-:-:-]: help [::b]j/k[-:-:-]: move [::b]i[-:-:-]: install [::b]r[-:-:-]: remove [::b]w[-:-:-]: web [::b]q[-:-:-]: quit") cmdFlex := tview.NewFlex() From b8a6c1daa75ebab463240dcb5e9c9b4c80ad4e94 Mon Sep 17 00:00:00 2001 From: vilmibm Date: Thu, 2 Feb 2023 13:15:10 -0800 Subject: [PATCH 17/17] include readme viewing in small help --- pkg/cmd/extension/browse/browse.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cmd/extension/browse/browse.go b/pkg/cmd/extension/browse/browse.go index 3993f3c70..247d43c5b 100644 --- a/pkg/cmd/extension/browse/browse.go +++ b/pkg/cmd/extension/browse/browse.go @@ -419,7 +419,7 @@ func ExtBrowse(opts ExtBrowseOpts) error { help := tview.NewTextView() help.SetDynamicColors(true) - help.SetText("[::b]?[-:-:-]: help [::b]j/k[-:-:-]: move [::b]i[-:-:-]: install [::b]r[-:-:-]: remove [::b]w[-:-:-]: web [::b]q[-:-:-]: quit") + help.SetText("[::b]?[-:-:-]: help [::b]j/k[-:-:-]: move [::b]i[-:-:-]: install [::b]r[-:-:-]: remove [::b]w[-:-:-]: web [::b]↵[-:-:-]: view readme [::b]q[-:-:-]: quit") cmdFlex := tview.NewFlex()