From 4f244a62d1ef13b1385ff40b6182cedac6fbd6bc Mon Sep 17 00:00:00 2001 From: sloumdrone Date: Sat, 15 Dec 2018 11:54:15 -0800 Subject: [PATCH] Initial commit of functional chat --- .gitignore | 1 + colorchat.py | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 .gitignore create mode 100644 colorchat.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..65d0aa6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +chatlog diff --git a/colorchat.py b/colorchat.py new file mode 100644 index 0000000..e73dc24 --- /dev/null +++ b/colorchat.py @@ -0,0 +1,146 @@ +#!/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) +