package tui import ( "fmt" "b612.me/apps/b612/gdu/pkg/fs" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) func (ui *UI) keyPressed(key *tcell.EventKey) *tcell.EventKey { if ui.handleCtrlZ(key) == nil { return nil } if ui.pages.HasPage("file") || ui.pages.HasPage("export") { return key // send event to primitive } if ui.filtering { return key } key = ui.handleClosingModals(key) if key == nil { return nil } key = ui.handleInfoPageEvents(key) if key == nil { return nil } key = ui.handleQuit(key) if key == nil { return nil } if ui.pages.HasPage("confirm") { return ui.handleConfirmation(key) } if ui.pages.HasPage("progress") || ui.pages.HasPage("deleting") || ui.pages.HasPage("emptying") { return key } key = ui.handleHelp(key) if key == nil { return nil } if ui.pages.HasPage("help") { return key } key = ui.handleShell(key) if key == nil { return nil } key = ui.handleLeftRight(key) if key == nil { return nil } key = ui.handleFiltering(key) if key == nil { return nil } return ui.handleMainActions(key) } func (ui *UI) handleClosingModals(key *tcell.EventKey) *tcell.EventKey { if key.Key() == tcell.KeyEsc || key.Rune() == 'q' { if ui.pages.HasPage("help") { ui.pages.RemovePage("help") ui.app.SetFocus(ui.table) return nil } if ui.pages.HasPage("info") { ui.pages.RemovePage("info") ui.app.SetFocus(ui.table) return nil } } return key } func (ui *UI) handleConfirmation(key *tcell.EventKey) *tcell.EventKey { if key.Rune() == 'h' { return tcell.NewEventKey(tcell.KeyLeft, 0, 0) } if key.Rune() == 'l' { return tcell.NewEventKey(tcell.KeyRight, 0, 0) } return key } func (ui *UI) handleInfoPageEvents(key *tcell.EventKey) *tcell.EventKey { if ui.pages.HasPage("info") { switch key.Rune() { case 'i': ui.pages.RemovePage("info") ui.app.SetFocus(ui.table) return nil case '?': return nil } if key.Key() == tcell.KeyUp || key.Key() == tcell.KeyDown || key.Rune() == 'j' || key.Rune() == 'k' { row, column := ui.table.GetSelection() if (key.Key() == tcell.KeyUp || key.Rune() == 'k') && row > 0 { row-- } else if (key.Key() == tcell.KeyDown || key.Rune() == 'j') && row+1 < ui.table.GetRowCount() { row++ } ui.table.Select(row, column) } ui.showInfo() // refresh file info after any change } return key } // handle ctrl+z job control func (ui *UI) handleCtrlZ(key *tcell.EventKey) *tcell.EventKey { if key.Key() == tcell.KeyCtrlZ { ui.app.Suspend(func() { termApp := ui.app.(*tview.Application) termApp.Lock() defer termApp.Unlock() err := stopProcess() if err != nil { ui.showErr("Error sending STOP signal", err) } }) return nil } return key } func (ui *UI) handleQuit(key *tcell.EventKey) *tcell.EventKey { switch key.Rune() { case 'Q': ui.app.Stop() fmt.Fprintf(ui.output, "%s\n", ui.currentDirPath) return nil case 'q': ui.app.Stop() return nil } return key } func (ui *UI) handleHelp(key *tcell.EventKey) *tcell.EventKey { if key.Rune() == '?' { if ui.pages.HasPage("help") { ui.pages.RemovePage("help") ui.app.SetFocus(ui.table) return nil } ui.showHelp() return nil } return key } func (ui *UI) handleShell(key *tcell.EventKey) *tcell.EventKey { if key.Rune() == 'b' { ui.spawnShell() return nil } return key } func (ui *UI) handleLeftRight(key *tcell.EventKey) *tcell.EventKey { if key.Rune() == 'h' || key.Key() == tcell.KeyLeft { ui.handleLeft() return nil } if key.Rune() == 'l' || key.Key() == tcell.KeyRight { ui.handleRight() return nil } return key } func (ui *UI) handleFiltering(key *tcell.EventKey) *tcell.EventKey { if key.Key() == tcell.KeyTab && ui.filteringInput != nil { ui.filtering = true ui.app.SetFocus(ui.filteringInput) return nil } return key } // nolint: funlen // Why: there's a lot of options to handle func (ui *UI) handleMainActions(key *tcell.EventKey) *tcell.EventKey { switch key.Rune() { case 'd': ui.handleDelete(false) case 'e': ui.handleDelete(true) case 'v': ui.showFile() case 'o': ui.openItem() case 'i': ui.showInfo() case 'a': ui.ShowApparentSize = !ui.ShowApparentSize if ui.currentDir != nil { row, column := ui.table.GetSelection() ui.showDir() ui.table.Select(row, column) } case 'B': ui.ShowRelativeSize = !ui.ShowRelativeSize if ui.currentDir != nil { row, column := ui.table.GetSelection() ui.showDir() ui.table.Select(row, column) } case 'c': ui.showItemCount = !ui.showItemCount if ui.currentDir != nil { row, column := ui.table.GetSelection() ui.showDir() ui.table.Select(row, column) } case 'm': ui.showMtime = !ui.showMtime if ui.currentDir != nil { row, column := ui.table.GetSelection() ui.showDir() ui.table.Select(row, column) } case 'r': if ui.currentDir != nil { ui.rescanDir() } case 'E': ui.confirmExport() return nil case 's': ui.setSorting("size") case 'C': ui.setSorting("itemCount") case 'n': ui.setSorting("name") case 'M': ui.setSorting("mtime") case '/': ui.showFilterInput() return nil case ' ': ui.handleMark() case 'I': ui.ignoreItem() } return key } func (ui *UI) handleLeft() { if ui.currentDirPath == ui.topDirPath { if ui.devices != nil { ui.currentDir = nil err := ui.ListDevices(ui.getter) if err != nil { ui.showErr("Error listing devices", err) } } return } if ui.currentDir != nil { ui.fileItemSelected(0, 0) } } func (ui *UI) handleRight() { row, column := ui.table.GetSelection() if ui.currentDirPath != ui.topDirPath && row == 0 { // do not select /.. return } if ui.currentDir != nil { ui.fileItemSelected(row, column) } else { ui.deviceItemSelected(row, column) } } func (ui *UI) handleDelete(shouldEmpty bool) { if ui.currentDir == nil { return } // do not allow deleting parent dir row, column := ui.table.GetSelection() selectedFile, ok := ui.table.GetCell(row, column).GetReference().(fs.Item) if !ok || selectedFile == ui.currentDir.GetParent() { return } if ui.askBeforeDelete { ui.confirmDeletion(shouldEmpty) } else { ui.delete(shouldEmpty) } } func (ui *UI) handleMark() { if ui.currentDir == nil { return } // do not allow deleting parent dir row, column := ui.table.GetSelection() selectedFile, ok := ui.table.GetCell(row, column).GetReference().(fs.Item) if !ok || selectedFile == ui.currentDir.GetParent() { return } ui.fileItemMarked(row) } func (ui *UI) ignoreItem() { if ui.currentDir == nil { return } // do not allow ignoring parent dir row, column := ui.table.GetSelection() selectedFile, ok := ui.table.GetCell(row, column).GetReference().(fs.Item) if !ok || selectedFile == ui.currentDir.GetParent() { return } if _, ok := ui.ignoredRows[row]; ok { delete(ui.ignoredRows, row) } else { ui.ignoredRows[row] = struct{}{} } ui.showDir() // select next row if possible ui.table.Select(min(row+1, ui.table.GetRowCount()-1), 0) }