github.com/wtfutil/wtf@v0.43.0/view/keyboard_widget.go (about)

     1  package view
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/gdamore/tcell/v2"
     7  	"github.com/wtfutil/wtf/cfg"
     8  	"github.com/wtfutil/wtf/utils"
     9  	"golang.org/x/text/cases"
    10  	"golang.org/x/text/language"
    11  )
    12  
    13  const helpKeyChar = "/"
    14  const refreshKeyChar = "r"
    15  
    16  type helpItem struct {
    17  	Key  string
    18  	Text string
    19  }
    20  
    21  // KeyboardWidget manages keyboard control for a widget
    22  type KeyboardWidget struct {
    23  	settings *cfg.Common
    24  
    25  	charMap  map[string]func()
    26  	keyMap   map[tcell.Key]func()
    27  	charHelp []helpItem
    28  	keyHelp  []helpItem
    29  	maxKey   int
    30  }
    31  
    32  // NewKeyboardWidget creates and returns a new instance of KeyboardWidget
    33  // func NewKeyboardWidget(tviewApp *tview.Application, pages *tview.Pages, settings *cfg.Common) *KeyboardWidget {
    34  func NewKeyboardWidget(settings *cfg.Common) *KeyboardWidget {
    35  	keyWidget := &KeyboardWidget{
    36  		settings: settings,
    37  		charMap:  make(map[string]func()),
    38  		keyMap:   make(map[tcell.Key]func()),
    39  		charHelp: []helpItem{},
    40  		keyHelp:  []helpItem{},
    41  	}
    42  
    43  	keyWidget.initializeCommonKeyboardControls()
    44  
    45  	return keyWidget
    46  }
    47  
    48  /* -------------------- Exported Functions --------------------- */
    49  
    50  // AssignedChars returns a list of all the text characters assigned to an operation
    51  func (widget *KeyboardWidget) AssignedChars() []string {
    52  	chars := []string{}
    53  
    54  	for char := range widget.charMap {
    55  		chars = append(chars, char)
    56  	}
    57  
    58  	return chars
    59  }
    60  
    61  // HelpText returns the help text and keyboard command info for this widget
    62  func (widget *KeyboardWidget) HelpText() string {
    63  	c := cases.Title(language.English)
    64  	str := " [green::b]Keyboard commands for " + c.String(widget.settings.Module.Type) + "[white]\n\n"
    65  
    66  	for _, item := range widget.charHelp {
    67  		str += fmt.Sprintf("  %s\t%s\n", item.Key, item.Text)
    68  	}
    69  
    70  	str += "\n\n"
    71  
    72  	for _, item := range widget.keyHelp {
    73  		str += fmt.Sprintf("  %-*s\t%s\n", widget.maxKey, item.Key, item.Text)
    74  	}
    75  
    76  	return str
    77  }
    78  
    79  // InitializeHelpTextKeyboardControl assigns the function that displays help text to the
    80  // common help text key value
    81  func (widget *KeyboardWidget) InitializeHelpTextKeyboardControl(helpFunc func()) {
    82  	if helpFunc != nil {
    83  		widget.SetKeyboardChar(helpKeyChar, helpFunc, "Show/hide this help prompt")
    84  	}
    85  }
    86  
    87  // InitializeRefreshKeyboardControl assigns the module's explicit refresh function to
    88  // the commom refresh key value
    89  func (widget *KeyboardWidget) InitializeRefreshKeyboardControl(refreshFunc func()) {
    90  	if refreshFunc != nil {
    91  		widget.SetKeyboardChar(refreshKeyChar, refreshFunc, "Refresh widget")
    92  	}
    93  }
    94  
    95  // InputCapture is the function passed to tview's SetInputCapture() function
    96  // This is done during the main widget's creation process using the following code:
    97  //
    98  //	widget.View.SetInputCapture(widget.InputCapture)
    99  func (widget *KeyboardWidget) InputCapture(event *tcell.EventKey) *tcell.EventKey {
   100  	if event == nil {
   101  		return nil
   102  	}
   103  
   104  	fn := widget.charMap[string(event.Rune())]
   105  	if fn != nil {
   106  		fn()
   107  		return nil
   108  	}
   109  
   110  	fn = widget.keyMap[event.Key()]
   111  	if fn != nil {
   112  		fn()
   113  		return nil
   114  	}
   115  
   116  	return event
   117  }
   118  
   119  // LaunchDocumentation opens the module docs in a browser
   120  func (widget *KeyboardWidget) LaunchDocumentation() {
   121  	path := widget.settings.DocPath
   122  	if path == "" {
   123  		path = widget.settings.Type
   124  	}
   125  
   126  	url := "https://wtfutil.com/modules/" + path
   127  	utils.OpenFile(url)
   128  }
   129  
   130  // SetKeyboardChar sets a character/function combination that responds to key presses
   131  // Example:
   132  //
   133  //	widget.SetKeyboardChar("d", widget.deleteSelectedItem)
   134  func (widget *KeyboardWidget) SetKeyboardChar(char string, fn func(), helpText string) {
   135  	if char == "" {
   136  		return
   137  	}
   138  
   139  	// Check to ensure that the key trying to be used isn't already being used for something
   140  	if _, ok := widget.charMap[char]; ok {
   141  		panic(fmt.Sprintf("Key is already mapped to a keyboard command: %s\n", char))
   142  	}
   143  
   144  	widget.charMap[char] = fn
   145  	widget.charHelp = append(widget.charHelp, helpItem{char, helpText})
   146  }
   147  
   148  // SetKeyboardKey sets a tcell.Key/function combination that responds to key presses
   149  // Example:
   150  //
   151  //	widget.SetKeyboardKey(tcell.KeyCtrlD, widget.deleteSelectedItem)
   152  func (widget *KeyboardWidget) SetKeyboardKey(key tcell.Key, fn func(), helpText string) {
   153  	widget.keyMap[key] = fn
   154  	widget.keyHelp = append(widget.keyHelp, helpItem{tcell.KeyNames[key], helpText})
   155  
   156  	if len(tcell.KeyNames[key]) > widget.maxKey {
   157  		widget.maxKey = len(tcell.KeyNames[key])
   158  	}
   159  }
   160  
   161  /* -------------------- Unexported Functions -------------------- */
   162  
   163  // initializeCommonKeyboardControls sets up the keyboard controls that are common to
   164  // all widgets that accept keyboard input
   165  func (widget *KeyboardWidget) initializeCommonKeyboardControls() {
   166  	widget.SetKeyboardChar("\\", widget.LaunchDocumentation, "Open the documentation for this module in a browser")
   167  }