351 lines
6.9 KiB
Go
351 lines
6.9 KiB
Go
|
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)
|
||
|
}
|