~clicompanion-devs/clicompanion/clicomp-glade

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/env python
# psax.py; illustration of curses library
# runs the shell command ps ax and saves the last lines of its output,
# as many as the window will fit; allows the user to move up and down
# within the window, killing those processes
# run line:
#python psax.py
# user commands:
''''u':
move highlight up a line
'd':
move highlight down a line
'k':
kill process in currently highlighted line
'r':
re-run 'ps ax' for update
'q':
quit'''
# possible extensions: allowing scrolling, so that the user could go
# through all the ps ax output; allow wraparound for long lines; ask
# user to confirm before killing a process

import curses, os, sys, traceback

# global variables
class gb:
    scrn = None # will point to Curses window object
    cmdoutlines = [] # output of 'ps ax' (including the lines we don't

# use, for possible future extension)

winrow = None # current row position in screen
startrow = None # index of first row in cmdoutlines to be displayed
def runpsax():
    p = os.popen('ps ax','r')
    gb.cmdoutlines = []
    row = 0

    for ln in p:
    # don't allow line wraparound, so truncate long lines
        ln = ln[:curses.COLS]

# remove EOLN if it is still there
    if ln[-1] == '\n': ln = ln[:-1]

    gb.cmdoutlines.append(ln)
    p.close()

# display last part of command output (as much as fits in screen)
def showlastpart():
    # clear screen
    gb.scrn.clear()
    # prepare to paint the (last part of the) 'ps ax' output on the screen
    gb.winrow = 0
    ncmdlines = len(gb.cmdoutlines)
    # two cases, depending on whether there is more output than screen rows
    if ncmdlines <= curses.LINES:
        gb.startrow = 0
        nwinlines = ncmdlines
        gb.startrow = ncmdlines - curses.LINES - 1
        nwinlines = curses.LINES
        lastrow = gb.startrow + nwinlines - 1

# now paint the rows
    for ln in gb.cmdoutlines[gb.startrow:lastrow]:
        gb.scrn.addstr(gb.winrow,0,ln)



        gb.winrow += 1
        # last line highlighted
        gb.scrn.addstr(gb.winrow,0,gb.cmdoutlines[lastrow],curses.A_BOLD)
        gb.scrn.refresh()

# move highlight up/down one line
def updown(inc):
    tmp = gb.winrow + inc
# ignore attempts to go off the edge of the screen
    if tmp >= 0 and tmp < curses.LINES:
# unhighlight the current line by rewriting it in default attributes
        gb.scrn.addstr(gb.winrow,0,gb.cmdoutlines[gb.startrow+gb.winrow])
# highlight the previous/next line
        gb.winrow = tmp
        ln = gb.cmdoutlines[gb.startrow+gb.winrow]
        gb.scrn.addstr(gb.winrow,0,ln,curses.A_BOLD)
        gb.scrn.refresh()

# kill the highlighted process
def kill():
    ln = gb.cmdoutlines[gb.startrow+gb.winrow]
    pid = int(ln.split()[0])
    os.kill(pid,9)

# run/re-run 'ps ax'
    def rerun():
        runpsax()
        showlastpart()

def main():
# window setup
    gb.scrn = curses.initscr()
    curses.noecho()
    curses.cbreak()
    # rpdb.set_trace() (I used RPDB for debugging)
    # run 'ps ax' and process the output
    gb.psax = runpsax()
    # display in the window
    showlastpart()
    # user command loop
    while True:
        # get user command
        c = gb.scrn.getch()
        c = chr(c)
        if c == 'u': updown(-1)
        elif c == 'd': updown(1)
        elif c == 'r': rerun()
        elif c == 'k': kill()
        else: break

    restorescreen()

    def restorescreen():
        curses.nocbreak()
        curses.echo()
        curses.endwin()

if __name__ =='__main__':
    main()
    restorescreen()

    # print error message re exception
    traceback.print_exc()