colorchat/colorchat.py

147 lines
4.4 KiB
Python

#!/usr/bin/env python3
from textwrap import TextWrapper as wrap
from threading import Thread
import signal
from time import sleep, time
import os.path as path
from os.path import getmtime as gt
import curses
from curses import wrapper
import curses.textpad as textpad
import sys
import re
class Viewport:
def __init__(self, screen):
curses.curs_set(0)
self.user_path = path.expanduser('~')
self.username = path.split(self.user_path)[-1]
self.screen = screen
self.width = curses.COLS - 1
self.height = curses.LINES - 1
self.last_update = 0.0
self.last_msg = ''
self.update = False
self.path = '/home/sloum/Documents/code/python/colorchat/chatlog'
self.screen.nodelay(True)
self.screen.clear()
self.c_out = self.screen.subwin(self.height - 3, self.width,0,0)
self.c_in = self.screen.subwin(3,self.width,self.height - 3,0)
self.text_buffer = ''
self.watcher = Thread(target=self.watch, args=(self.path,), daemon=True)
self.main()
def main(self):
self.watcher.start()
while True:
self.text_input()
if self.update:
self.flash_log()
self.update = False
sleep(0.05)
def watch(self,filepath):
while True:
filetime = gt(filepath)
elapsedtime = self.elapsed_time(filetime)
if elapsedtime:
self.last_msg = elapsedtime
if filetime > self.last_update:
self.last_update = filetime
self.update = True
else:
self.update = False
sleep(0.5)
def flash_log(self):
with open(self.path, 'r') as f:
temp = f.read()
temp_list = self.wrap_text(temp)
rows = len(temp_list)
max_rows = self.height - 2
self.c_out.erase()
self.c_out.hline(0,0,'.',self.width)
title = '_colorchat_'
position = self.width // 2 - len(title) // 2
self.c_out.addstr(0,position,title)
if rows < max_rows:
for x in range(rows - 1):
self.c_out.addstr(max_rows - rows + x, 0, temp_list[x])
else:
counter = 1
for x in temp_list[-(max_rows-2):]:
self.c_out.addstr(counter, 0, x)
counter += 1
self.c_out.refresh()
# takes in a string and outputs a list of strings
def wrap_text(self, string):
ob = wrap(width=self.width - 2, tabsize=4, replace_whitespace=False)
text = [ob.fill(x) for x in string.split('\n')]
text = '\n'.join(text).split('\n')
return text
def text_input(self):
self.c_in.erase()
c = self.screen.getch()
if c in (curses.KEY_ENTER, 10, 13):
self.send_msg()
elif c == curses.KEY_BACKSPACE:
if len(self.text_buffer) > 0:
self.text_buffer = self.text_buffer[:-1]
elif c != -1 and not c in [curses.KEY_UP, curses.KEY_LEFT, curses.KEY_DOWN, curses.KEY_RIGHT]:
character = chr(c)
if re.match(r'^[\S ]+$',character):
self.text_buffer += chr(c)
self.c_in.hline(0,0,'-',self.width)
self.c_in.addstr(1,1,self.text_buffer[-(self.width * 2 - 10):] + '_')
self.c_in.addstr(2,self.width - 1 - len(self.last_msg),self.last_msg)
self.c_in.refresh()
def send_msg(self):
if self.text_buffer in ['q','quit','exit']:
sys.exit(0)
with open(self.path, 'a') as f:
f.write('{} > {}\n'.format(self.username,self.text_buffer))
self.text_buffer = ''
def elapsed_time(self,last_time):
if not last_time:
return False
current = time()
elapsed = int(current - last_time)
unit = 's'
if elapsed >= 60:
elapsed = elapsed // 60
unit = 'm'
if elapsed >= 60:
elapsed = elapsed // 60
unit = 'h'
if elapsed >= 24:
elapsed = elapsed // 24
unit = 'd'
return 'Time since last post: {}{}'.format(elapsed,unit)
if __name__ == '__main__':
signal.signal(signal.SIGINT,signal.SIG_IGN)
try:
wrapper(Viewport)
except KeyboardInterrupt:
curses.echo()
curses.nocbreak()
curses.endwin()
finally:
sys.exit(1)