Skip to content

Instantly share code, notes, and snippets.

@impiaaa impiaaa/watchfile.py
Created Mar 24, 2020

Embed
What would you like to do?
import curses, sys, difflib
import time, os.path
import watchdog.events, watchdog.observers
class Handler(watchdog.events.FileSystemEventHandler):
def __init__(self, path):
self.path = os.path.abspath(path)
self.matcher = difflib.SequenceMatcher(isjunk=lambda s: s.isspace())
self.contents = None
self.first = True
self.read()
def read(self):
old = self.contents
self.contents = open(self.path).read().splitlines()
if old is not None:
self.matcher.set_seqs(old, self.contents)
self.first = False
def draw(self):
win.erase()
height, width = win.getmaxyx()
if not self.first and curses.has_colors():
for tag, i1, i2, j1, j2 in self.matcher.get_opcodes():
for i in range(j1, j2):
if i-yoffset < 0: continue
if i-yoffset >= height: break
win.attrset(curses.color_pair({'replace': 1,
'insert': 2,
'equal': 0
}[tag]))
win.addnstr(i-yoffset, 0, self.contents[i][xoffset:], width)
else:
for i, line in enumerate(self.contents):
if i-yoffset < 0: continue
if i-yoffset >= height: break
win.addnstr(i-yoffset, 0, line[xoffset:], width)
win.refresh()
def on_deleted(self, event):
if self.path is None or event.src_path != self.path: return
self.path = None
exit()
def on_modified(self, event):
if self.path is None or event.src_path != self.path: return
self.read()
self.draw()
def on_moved(self, event):
if self.path is None or event.src_path != self.path: return
self.path = event.dest_path
# TODO: restart the observer if it moved to a different directory
event_handler = Handler(sys.argv[1])
observer = watchdog.observers.Observer()
observer.schedule(event_handler, os.path.dirname(event_handler.path))
xoffset = yoffset = 0
win = curses.initscr()
curses.curs_set(0)
curses.cbreak()
curses.noecho()
if curses.has_colors():
curses.start_color()
curses.init_pair(1, 0, curses.COLOR_BLUE)
curses.init_pair(2, 0, curses.COLOR_GREEN)
curses.init_pair(3, 0, curses.COLOR_RED)
win.keypad(True)
try:
event_handler.draw()
observer.start()
while event_handler.path is not None:
c = win.getch()
height, width = win.getmaxyx()
if 0 < c < 256 and chr(c) in 'Qq':
break
elif c == curses.KEY_UP:
if yoffset > 0:
yoffset -= 1
else:
curses.beep()
elif c == curses.KEY_DOWN:
if yoffset+height < len(event_handler.contents):
yoffset += 1
else:
curses.beep()
elif c == curses.KEY_LEFT:
if xoffset > 0:
xoffset -= 1
else:
curses.beep()
elif c == curses.KEY_RIGHT:
xoffset += 1
event_handler.draw()
finally:
win.keypad(False)
curses.curs_set(1)
curses.nocbreak()
curses.echo()
curses.endwin()
observer.stop()
observer.join()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.