First pass at filter support.
Press / to input a filter string. The proc list will be filtered to procs that contain the filter as a substring of either the command or the string representation of the PID.
This commit is contained in:
parent
1b5985860c
commit
866281cc42
|
@ -71,7 +71,7 @@ snap connect gotop-cjbassi:system-observe
|
|||
### Keybinds
|
||||
|
||||
- Quit: `q` or `<C-c>`
|
||||
- Process navigation
|
||||
- Process navigation:
|
||||
- `k` and `<Up>`: up
|
||||
- `j` and `<Down`: down
|
||||
- `<C-u>`: half page up
|
||||
|
@ -83,10 +83,15 @@ snap connect gotop-cjbassi:system-observe
|
|||
- Process actions:
|
||||
- `<Tab>`: toggle process grouping
|
||||
- `dd`: kill selected process or group of processes
|
||||
- Process sorting
|
||||
- Process sorting:
|
||||
- `c`: CPU
|
||||
- `m`: Mem
|
||||
- `p`: PID
|
||||
- Process filtering:
|
||||
- /: start editing filter
|
||||
- (while editing):
|
||||
- <Enter> accept filter
|
||||
- <C-c>: clear filter
|
||||
- CPU and Mem graph scaling:
|
||||
- `h`: scale in
|
||||
- `l`: scale out
|
||||
|
|
62
main.go
62
main.go
|
@ -12,6 +12,7 @@ import (
|
|||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
docopt "github.com/docopt/docopt.go"
|
||||
ui "github.com/gizak/termui/v3"
|
||||
|
@ -296,12 +297,8 @@ func eventLoop() {
|
|||
}
|
||||
}
|
||||
case e := <-uiEvents:
|
||||
switch e.ID {
|
||||
case "q", "<C-c>":
|
||||
return
|
||||
case "?":
|
||||
helpVisible = !helpVisible
|
||||
case "<Resize>":
|
||||
// Handle resize event always.
|
||||
if e.ID == "<Resize>" {
|
||||
payload := e.Payload.(ui.Resize)
|
||||
termWidth, termHeight := payload.Width, payload.Height
|
||||
if statusbar {
|
||||
|
@ -312,23 +309,55 @@ func eventLoop() {
|
|||
}
|
||||
help.Resize(payload.Width, payload.Height)
|
||||
ui.Clear()
|
||||
|
||||
if helpVisible {
|
||||
ui.Render(help)
|
||||
} else {
|
||||
ui.Render(grid)
|
||||
if statusbar {
|
||||
ui.Render(bar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if helpVisible {
|
||||
if proc.EditingFilter() {
|
||||
if utf8.RuneCountInString(e.ID) == 1 {
|
||||
proc.SetFilter(proc.Filter() + e.ID)
|
||||
ui.Render(proc)
|
||||
}
|
||||
switch e.ID {
|
||||
case "<C-c>":
|
||||
proc.SetFilter("")
|
||||
proc.SetEditingFilter(false)
|
||||
ui.Render(proc)
|
||||
case "<Enter>":
|
||||
proc.SetEditingFilter(false)
|
||||
ui.Render(proc)
|
||||
case "<Backspace>":
|
||||
if filter := proc.Filter(); filter != "" {
|
||||
proc.SetFilter(filter[:len(filter)-1])
|
||||
}
|
||||
ui.Render(proc)
|
||||
}
|
||||
} else if helpVisible {
|
||||
switch e.ID {
|
||||
case "q", "<C-c>":
|
||||
return
|
||||
case "?":
|
||||
ui.Clear()
|
||||
ui.Render(help)
|
||||
helpVisible = false
|
||||
ui.Render(grid)
|
||||
case "<Escape>":
|
||||
helpVisible = false
|
||||
ui.Render(grid)
|
||||
case "<Resize>":
|
||||
ui.Render(help)
|
||||
}
|
||||
} else {
|
||||
switch e.ID {
|
||||
case "q", "<C-c>":
|
||||
return
|
||||
case "?":
|
||||
ui.Render(grid)
|
||||
helpVisible = true
|
||||
ui.Clear()
|
||||
ui.Render(help)
|
||||
case "h":
|
||||
graphHorizontalScale += graphHorizontalScaleDelta
|
||||
cpu.HorizontalScale = graphHorizontalScale
|
||||
|
@ -341,11 +370,6 @@ func eventLoop() {
|
|||
mem.HorizontalScale = graphHorizontalScale
|
||||
ui.Render(cpu, mem)
|
||||
}
|
||||
case "<Resize>":
|
||||
ui.Render(grid)
|
||||
if statusbar {
|
||||
ui.Render(bar)
|
||||
}
|
||||
case "<MouseLeft>":
|
||||
payload := e.Payload.(ui.Mouse)
|
||||
proc.HandleClick(payload.X, payload.Y)
|
||||
|
@ -389,6 +413,10 @@ func eventLoop() {
|
|||
case "m", "c", "p":
|
||||
proc.ChangeProcSortMethod(w.ProcSortMethod(e.ID))
|
||||
ui.Render(proc)
|
||||
case "/":
|
||||
proc.SetFilter("")
|
||||
proc.SetEditingFilter(true)
|
||||
ui.Render(proc)
|
||||
}
|
||||
|
||||
if previousKey == e.ID {
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
const KEYBINDS = `
|
||||
Quit: q or <C-c>
|
||||
|
||||
Process navigation
|
||||
Process navigation:
|
||||
- k and <Up>: up
|
||||
- j and <Down>: down
|
||||
- <C-u>: half page up
|
||||
|
@ -24,11 +24,17 @@ Process actions:
|
|||
- <Tab>: toggle process grouping
|
||||
- dd: kill selected process or group of processes
|
||||
|
||||
Process sorting
|
||||
Process sorting:
|
||||
- c: CPU
|
||||
- m: Mem
|
||||
- p: PID
|
||||
|
||||
Process filtering:
|
||||
- /: start editing filter
|
||||
- (while editing):
|
||||
- <Enter>: accept filter
|
||||
- <C-c> clear filter
|
||||
|
||||
CPU and Mem graph scaling:
|
||||
- h: scale in
|
||||
- l: scale out
|
||||
|
@ -46,7 +52,7 @@ func NewHelpMenu() *HelpMenu {
|
|||
|
||||
func (self *HelpMenu) Resize(termWidth, termHeight int) {
|
||||
textWidth := 53
|
||||
textHeight := 22
|
||||
textHeight := strings.Count(KEYBINDS, "\n") + 1
|
||||
x := (termWidth - textWidth) / 2
|
||||
y := (termHeight - textHeight) / 2
|
||||
|
||||
|
|
|
@ -2,21 +2,26 @@ package widgets
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"log"
|
||||
"os/exec"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
psCPU "github.com/shirou/gopsutil/cpu"
|
||||
|
||||
ui "github.com/cjbassi/gotop/src/termui"
|
||||
"github.com/cjbassi/gotop/src/utils"
|
||||
tui "github.com/gizak/termui/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
UP_ARROW = "▲"
|
||||
DOWN_ARROW = "▼"
|
||||
ELLIPSIS = "…"
|
||||
)
|
||||
|
||||
type ProcSortMethod string
|
||||
|
@ -40,6 +45,8 @@ type ProcWidget struct {
|
|||
cpuCount int
|
||||
updateInterval time.Duration
|
||||
sortMethod ProcSortMethod
|
||||
filter string
|
||||
editingFilter bool
|
||||
groupedProcs []Proc
|
||||
ungroupedProcs []Proc
|
||||
showGroupedProcs bool
|
||||
|
@ -56,6 +63,8 @@ func NewProcWidget() *ProcWidget {
|
|||
cpuCount: cpuCount,
|
||||
sortMethod: ProcSortCpu,
|
||||
showGroupedProcs: true,
|
||||
filter: "",
|
||||
editingFilter: false,
|
||||
}
|
||||
self.Title = " Processes "
|
||||
self.ShowCursor = true
|
||||
|
@ -86,6 +95,71 @@ func NewProcWidget() *ProcWidget {
|
|||
return self
|
||||
}
|
||||
|
||||
func (self *ProcWidget) Filter() string {
|
||||
return self.filter
|
||||
}
|
||||
|
||||
func (self *ProcWidget) SetFilter(filter string) {
|
||||
self.filter = filter
|
||||
}
|
||||
|
||||
func (self *ProcWidget) EditingFilter() bool {
|
||||
return self.editingFilter
|
||||
}
|
||||
|
||||
func (self *ProcWidget) SetEditingFilter(editing bool) {
|
||||
self.editingFilter = editing
|
||||
if !editing {
|
||||
self.update()
|
||||
}
|
||||
}
|
||||
|
||||
func (self *ProcWidget) Draw(buf *tui.Buffer) {
|
||||
self.Table.Draw(buf)
|
||||
if self.filter != "" || self.editingFilter {
|
||||
self.drawFilter(buf)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *ProcWidget) drawFilter(buf *tui.Buffer) {
|
||||
style := self.TitleStyle
|
||||
label := "Filter: "
|
||||
if self.editingFilter {
|
||||
label = "[ Filter: "
|
||||
style = tui.NewStyle(style.Fg, style.Bg, tui.ModifierBold)
|
||||
}
|
||||
|
||||
p := image.Pt(self.Min.X+2, self.Max.Y-1)
|
||||
buf.SetString(label, style, p)
|
||||
p.X += utf8.RuneCountInString(label)
|
||||
|
||||
maxLen := self.Max.X - p.X - 4
|
||||
filter := self.filter
|
||||
if l := utf8.RuneCountInString(filter); l > maxLen {
|
||||
filter = ELLIPSIS + filter[l-maxLen+1:]
|
||||
}
|
||||
buf.SetString(filter, self.TitleStyle, p)
|
||||
p.X += utf8.RuneCountInString(filter)
|
||||
|
||||
if self.editingFilter {
|
||||
remaining := self.Max.X - 2 - p.X
|
||||
buf.SetString(fmt.Sprintf("%*s", remaining, "]"), style, p)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *ProcWidget) filterProcs(procs []Proc) []Proc {
|
||||
if self.filter == "" {
|
||||
return procs
|
||||
}
|
||||
var filtered []Proc
|
||||
for _, proc := range procs {
|
||||
if strings.Contains(proc.FullCommand, self.filter) || strings.Contains(fmt.Sprintf("%d", proc.Pid), self.filter) {
|
||||
filtered = append(filtered, proc)
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
func (self *ProcWidget) update() {
|
||||
procs, err := getProcs()
|
||||
if err != nil {
|
||||
|
@ -98,6 +172,7 @@ func (self *ProcWidget) update() {
|
|||
procs[i].Cpu /= float64(self.cpuCount)
|
||||
}
|
||||
|
||||
procs = self.filterProcs(procs)
|
||||
self.ungroupedProcs = procs
|
||||
self.groupedProcs = groupProcs(procs)
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user