157 lines
4.6 KiB
Python
Executable file
157 lines
4.6 KiB
Python
Executable file
#!/usr/bin/python
|
|
"""
|
|
Based on the code that
|
|
Lyle Scott, III wrote.
|
|
lyle@digitalfoo.net
|
|
|
|
Watches the output of a command in a
|
|
scrollable curses window.
|
|
"""
|
|
import curses
|
|
import sys
|
|
import random
|
|
import locale
|
|
import threading
|
|
import subprocess
|
|
import time
|
|
locale.setlocale(locale.LC_ALL,"")
|
|
|
|
class UnixWatchCommand:
|
|
DOWN = 1
|
|
UP = -1
|
|
SPACE_KEY = 32
|
|
ESC_KEY = 27
|
|
|
|
PREFIX_SELECTED = '-'
|
|
PREFIX_DESELECTED = ''
|
|
|
|
outputLines = []
|
|
screen = None
|
|
|
|
def __init__(self, command):
|
|
self.stop = threading.Event()
|
|
self.timer=threading.Thread(target=self.display)
|
|
self.command = ' '.join(command)
|
|
self.screen = curses.initscr()
|
|
curses.noecho()
|
|
curses.cbreak()
|
|
self.screen.keypad(1)
|
|
self.screen.border(0)
|
|
self.topLineNum = 0
|
|
self.highlightLineNum = 0
|
|
self.markedLineNums = []
|
|
self.getOutputLines()
|
|
self.timer.start()
|
|
self.run()
|
|
self.timer.join()
|
|
|
|
def display(self):
|
|
while not self.stop.is_set():
|
|
try:
|
|
self.displayScreen()
|
|
time.sleep(1)
|
|
except:
|
|
break
|
|
|
|
def run(self):
|
|
while True:
|
|
try:
|
|
self.displayScreen()
|
|
# get user command
|
|
c = self.screen.getch()
|
|
if c == curses.KEY_UP:
|
|
self.updown(self.UP)
|
|
elif c == curses.KEY_DOWN:
|
|
self.updown(self.DOWN)
|
|
elif c == self.SPACE_KEY:
|
|
self.markLine()
|
|
elif c == self.ESC_KEY:
|
|
self.stop.set()
|
|
break
|
|
except:
|
|
self.stop.set()
|
|
break
|
|
|
|
|
|
def markLine(self):
|
|
linenum = self.topLineNum + self.highlightLineNum
|
|
if linenum in self.markedLineNums:
|
|
self.markedLineNums.remove(linenum)
|
|
else:
|
|
self.markedLineNums.append(linenum)
|
|
|
|
def check_output(self, command):
|
|
|
|
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
universal_newlines=True)
|
|
output,stderr = process.communicate()
|
|
retcode = process.poll()
|
|
|
|
if retcode:
|
|
raise subprocess.CalledProcessError(retcode, command,
|
|
output=output[0])
|
|
return output.splitlines()
|
|
|
|
def getOutputLines(self):
|
|
self.outputLines = self.check_output(self.command)
|
|
self.nOutputLines = len(self.outputLines)
|
|
|
|
def displayScreen(self):
|
|
# clear screen
|
|
self.screen.clear()
|
|
self.getOutputLines()
|
|
# now paint the rows
|
|
top = self.topLineNum
|
|
bottom = self.topLineNum+curses.LINES
|
|
for (index,line,) in enumerate(self.outputLines[top:bottom]):
|
|
linenum = self.topLineNum + index
|
|
if linenum in self.markedLineNums:
|
|
prefix = self.PREFIX_SELECTED
|
|
else:
|
|
prefix = self.PREFIX_DESELECTED
|
|
|
|
#line = '%s %s' % (prefix, line,)
|
|
# highlight current line
|
|
if index != self.highlightLineNum:
|
|
self.screen.addstr(index, 0, line)
|
|
else:
|
|
self.screen.addstr(index, 0, line, curses.A_BOLD)
|
|
self.screen.refresh()
|
|
|
|
# move highlight up/down one line
|
|
def updown(self, increment):
|
|
nextLineNum = self.highlightLineNum + increment
|
|
|
|
# paging
|
|
if increment == self.UP and self.highlightLineNum == 0\
|
|
and self.topLineNum != 0:
|
|
self.topLineNum += self.UP
|
|
return
|
|
elif increment == self.DOWN and nextLineNum == curses.LINES\
|
|
and (self.topLineNum+curses.LINES) != self.nOutputLines:
|
|
self.topLineNum += self.DOWN
|
|
return
|
|
|
|
# scroll highlight line
|
|
if increment == self.UP and (self.topLineNum != 0 or\
|
|
self.highlightLineNum != 0):
|
|
self.highlightLineNum = nextLineNum
|
|
elif increment == self.DOWN and\
|
|
(self.topLineNum+self.highlightLineNum+1) != self.nOutputLines\
|
|
and self.highlightLineNum != curses.LINES:
|
|
self.highlightLineNum = nextLineNum
|
|
|
|
def restoreScreen(self):
|
|
curses.initscr()
|
|
curses.nocbreak()
|
|
curses.echo()
|
|
curses.endwin()
|
|
|
|
# catch any weird termination situations
|
|
def __del__(self):
|
|
self.restoreScreen()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
ih = UnixWatchCommand(sys.argv[1:])
|