diff --git a/.GitImages/texturetile01.png b/.GitImages/texturetile01.png new file mode 100644 index 0000000..495af77 Binary files /dev/null and b/.GitImages/texturetile01.png differ diff --git a/.GitImages/texturetile02.png b/.GitImages/texturetile02.png new file mode 100644 index 0000000..c0298e0 Binary files /dev/null and b/.GitImages/texturetile02.png differ diff --git a/.GitImages/texturetile03.png b/.GitImages/texturetile03.png new file mode 100644 index 0000000..9b0c73a Binary files /dev/null and b/.GitImages/texturetile03.png differ diff --git a/.GitImages/toddo01.png b/.GitImages/toddo01.png new file mode 100644 index 0000000..cd545c6 Binary files /dev/null and b/.GitImages/toddo01.png differ diff --git a/ArchiveIt/archive_it.py b/ArchiveIt/archive_it.py new file mode 100644 index 0000000..2a90320 --- /dev/null +++ b/ArchiveIt/archive_it.py @@ -0,0 +1,54 @@ +import requests +import sys +import traceback + +HEADERS = {'User-Agent': 'archive_it commandline tool for archive.is submissions v1.1', + 'Referer': 'http://archive.is/', + 'Origin': 'http://archive.is'} +URL_SUBMIT = 'https://archive.is/submit/' + +def archive(url, anyway=0): + data = {'url': url} + if anyway is 1: + data[anyway] = 1 + response = requests.post(URL_SUBMIT, data=data, headers=HEADERS) + try: + if 'link' in response.headers: + time = extract_timestamp(response.headers['link']) + raise Exception(''' + Link already archived: %s + Pass parameter `anyway=1` to overwrite. + ''' % time) + response = response.headers['refresh'] + response = response.split(';') + for item in response: + if 'archive.is' in item: + return item.split('=')[1] + except: + return response + +def extract_timestamp(link): + times = link.split(';') + d = {} + for item in times: + if '=' in item: + x = items.split('=') + d[x[0]] = x[1] + return d.get('from', d) + +if __name__ == '__main__': + if len(sys.argv) == 1: + print('Use: > archive_it.py http://www.website.com/page') + quit() + url = sys.argv[1] + try: + response = archive(url) + if isinstance(response, str): + print(response) + elif isinstance(response, requests.models.Response): + print('Did not get the expected response. Here\'s what we got:') + print(response) + print(response.headers) + print(response.text) + except: + traceback.print_exc() \ No newline at end of file diff --git a/BaseGame/basegame.py b/BaseGame/basegame.py index 41e3b98..e2c9c71 100644 --- a/BaseGame/basegame.py +++ b/BaseGame/basegame.py @@ -35,20 +35,23 @@ def changebase(number, frombase, tobase): result = int(number, frombase) return basex(result, tobase) -def intinput(prompt, greaterthan=None): +def intinput(prompt, greaterthan=None, notequal=None): ''' Prompt for input until the user enters an int ''' while True: result = input(prompt) try: i = int(result) - if greaterthan is None or i > greaterthan: - return i + if isinstance(notequal, int) and i == notequal: + continue + if isinstance(greaterthan, int) and i < greaterthan: + continue + return i except ValueError: pass def configuration(): frombase = intinput(' From base: ', 1) - tobase = intinput(' To base: ', 1) + tobase = intinput(' To base: ', 1, frombase) lower = intinput('Lower bound: ') upper = intinput('Upper bound: ', lower) return { diff --git a/DailyProgrammer/222.md b/DailyProgrammer/d222_balance.md similarity index 100% rename from DailyProgrammer/222.md rename to DailyProgrammer/d222_balance.md diff --git a/DailyProgrammer/222_balance.py b/DailyProgrammer/d222_balance.py similarity index 100% rename from DailyProgrammer/222_balance.py rename to DailyProgrammer/d222_balance.py diff --git a/Datapoint/datapoint.py b/Datapoint/datapoint.py index befc4f0..53d6bfc 100644 --- a/Datapoint/datapoint.py +++ b/Datapoint/datapoint.py @@ -9,6 +9,7 @@ class DataPoint: self.color_outbound = '#999' self.color_crossbar = '#bbb' self.color_point = '#000' + self.color_point_out = '#000' self.crossbar_count = 10 self.point_diameter = 4 self.margin = 0.10 @@ -27,6 +28,7 @@ class DataPoint: self.countdown = -1 self.lastbump = 0 + self.resized = True self.t.configure(bg='#f00') self.t.bind('', self.movereplot) self.c = tkinter.Canvas(self.t) @@ -35,6 +37,8 @@ class DataPoint: self.reset() self.previous_w = self.w self.previous_h = self.h + self.previous_x = self.windowx + self.previous_y = self.windowy self.clear_screen() self.draw_margin() self._started = autostart @@ -59,6 +63,14 @@ class DataPoint: return self.h return self.t.winfo_height() + @property + def margin_x(self): + return self.window_width * self.margin + + @property + def margin_y(self): + return self.window_height * self.margin + def mainloop(self): self._started = True self.t.mainloop() @@ -68,8 +80,8 @@ class DataPoint: When the user expands the window, replot the graph after a short delay. ''' - previous = (self.previous_w, self.previous_h) - current = (self.window_width, self.window_height) + previous = (self.previous_w, self.previous_h, self.previous_x, self.previous_y) + current = (self.window_width, self.window_height, self.t.winfo_x(), self.t.winfo_y()) now = time.time() if now - self.lastbump < 0.2: # Go away. @@ -78,8 +90,12 @@ class DataPoint: # Set. self.previous_w = current[0] self.previous_h = current[1] + self.previous_x = current[2] + self.previous_y = current[3] self.countdown = 1 self.lastbump = now + if previous[:2] != current[:2]: + self.resized = False self.t.after(500, self.movereplot) return if self.countdown > -1: @@ -89,7 +105,9 @@ class DataPoint: self.t.after(500, self.movereplot) if self.countdown == 0: # Plot. - self.plotpoints([]) + if not self.resized: + self.plot_points([]) + self.resized = True return def reset(self): @@ -105,8 +123,6 @@ class DataPoint: self.span_y = None self.drawable_w = None self.drawable_h = None - self.margin_x = self.window_width * self.margin - self.margin_y = self.window_height * self.margin self.clear_screen() self.draw_margin() @@ -161,6 +177,9 @@ class DataPoint: hi_x = hi[0] hi_y = hi[1] + if self.crossbar_count < 1: + self.crossbar_count = 1 + if self.highest_x != self.lowest_x: # LOW X self.c.create_text(low_x+5, low_y+5, @@ -170,8 +189,6 @@ class DataPoint: text=str(round(self.highest_x, 4)), anchor='nw') increment_x = (self.highest_x - self.lowest_x) / self.crossbar_count - # crossbartop = (self.window_height - self.margin_y) - 5 - # crossbarbot = (self.window_height - self.margin_y) + 5 crossbartop = self.margin_y crossbarbot = self.window_height - self.margin_y for x in range(1, self.crossbar_count): @@ -190,8 +207,6 @@ class DataPoint: self.c.create_text(low_x-5, hi_y, text=str(round(self.highest_y, 4)), anchor='e') increment_y = (self.highest_y - self.lowest_y) / self.crossbar_count - # crossbarlef = self.margin_x - 5 - # crossbarrgt = self.margin_x + 5 crossbarlef = self.margin_x crossbarrgt = self.window_width - self.margin_x for y in range(1, self.crossbar_count): @@ -215,19 +230,24 @@ class DataPoint: or vice-versa. ''' if not reverse: - if len(self.POINTS) == 1: - return (self.window_width/2, self.window_height/2) - # Get percentage of the span - x = ((x) - self.lowest_x) / self.span_x - y = ((y) - self.lowest_y) / self.span_y - # Flip y - y = 1 - y - # Use the percentage to get a location on the board - x *= self.drawable_w - y *= self.drawable_h - # Put into drawing area - x += self.margin_x - y += self.margin_y + if self.highest_x == self.lowest_x: + x = self.window_width / 2 + else: + # Get percentage of the span + x = ((x) - self.lowest_x) / self.span_x + # Use the percentage to get a location on the board + x *= self.drawable_w + # Put into drawing area + x += self.margin_x + + if self.highest_y == self.lowest_y: + y = self.window_height / 2 + else: + y = ((y) - self.lowest_y) / self.span_y + # Flip y + y = 1 - y + y *= self.drawable_h + y += self.margin_y else: if self.highest_x != self.lowest_x: @@ -247,12 +267,13 @@ class DataPoint: return (x, y) - def plotpoints(self, points=[]): + def plot_points(self, points=[]): ''' Plot points onto the canvas. var points = list, where each element is a 2-length tuple, where [0] is x and [1] is y coordinate. ''' + original_len = len(self.POINTS) for point in points: self.POINTS.add(tuple(point)) @@ -292,19 +313,19 @@ class DataPoint: outline=self.color_point) self.c.update() - def plotpoint(self, x, y): - self.plotpoints([[x, y]]) + def plot_point(self, x, y): + self.plot_points([[x, y]]) def set_origin(self, x, y): self.origin = (x, y) - self.plotpoints([]) + self.plot_points([]) def example(function): dp = DataPoint() points = list(range(100)) points = [[p, function(p)] for p in points] - dp.plotpoints(points) + dp.plot_points(points) dp.mainloop() @@ -330,10 +351,9 @@ def example2(): (94, 22320), (95, 23703), (96, 40752), (97, 21730), (98, 27637), (99, 45931), (100, 18443), (101, 20048), (102, 18097), (103, 11430) ] - dp.plotpoints(points) + dp.plot_points(points) dp.mainloop() - def examplefunction(x): x -= 50 x *= 0.1 diff --git a/TKCube/README.md b/TKCube/README.md new file mode 100644 index 0000000..2b7dacc --- /dev/null +++ b/TKCube/README.md @@ -0,0 +1,4 @@ +TKCube +========= + +Not done yet. \ No newline at end of file diff --git a/TKCube/tkcube.py b/TKCube/tkcube.py new file mode 100644 index 0000000..a5197fc --- /dev/null +++ b/TKCube/tkcube.py @@ -0,0 +1,117 @@ +import copy +import math +import random +import tkinter + +class TKCube: + def __init__(self): + self.t = tkinter.Tk() + self.FACES = [ + [[2, 2, 1], [2, -2, 1], [-2, -2, 1], [-2, 2, 1]], + [[2, -2, 1], [-2, -2, -1], [-2, 2, -1], [2, 2, -1]], + [[-2, -2, 1], [2, -2, 1], [2, -2, -1], [-2, -2, -1]], + [[-2, 2, 1], [2, 2, 1], [2, 2, -1], [-2, 2, -1]], + [[-2, -2, -1], [-2, 2, -1], [-2, 2, 1], [-2, -2, -1]], + [[2, -2, 1], [2, 2, 1], [2, 2, -1], [2, -2, -1]], + ] + self.INFLATE_SCALE = 8 + + self.c = tkinter.Canvas(self.t, width=600, height=600, bg='#444') + self.c.pack(fill='both', expand=True) + self.t.bind('', self.render) + self.is_mouse_down = False + self.prev_mouse_x = None + self.prev_mouse_y = None + self.t.bind('', self.mouse_down) + self.t.bind('', self.mouse_up) + self.t.bind('', self.mouse_motion) + self.t.bind('', lambda event: self.arbitrarymove(0, -1)) + self.t.bind('', lambda event: self.arbitrarymove(0, 1)) + self.t.bind('', lambda event: self.arbitrarymove(-1, 0)) + self.t.bind('', lambda event: self.arbitrarymove(1, 0)) + self.render() + self.t.mainloop() + + def arbitrarymove(self, deltax, deltay): + for face in self.FACES: + for point in face: + point[0] += deltax + point[1] += deltay + self.render() + + def mouse_down(self, event): + self.is_mouse_down = True + + def mouse_up(self, event): + self.is_mouse_down = False + + def mouse_motion(self, event): + if not self.is_mouse_down: + return + if self.prev_mouse_x is None: + self.prev_mouse_x = event.x + self.prev_mouse_y = event.y + distance = math.sqrt( ((event.x - self.prev_mouse_x) ** 2) + ((event.y - self.prev_mouse_y) ** 2) ) + self.prev_mouse_x = event.x + self.prev_mouse_y = event.y + print(distance) + + def center_of_square(self, face): + x = 0; y = 0; z = 0 + for point in face: + x += point[0] + y += point[1] + z += point[2] + return [x/4, y/4, z/4] + + def plot_point_screen(self, x, y, diameter=4): + radius = diameter / 2 + x1 = x - radius + y1 = y - radius + x2 = x + radius + y2 = y + radius + self.c.create_oval(x1, y1, x2, y2, fill='#000') + + def render(self, *event): + self.c.delete('all') + rendered_faces = copy.deepcopy(self.FACES) + + # Sort by depth from camera + # The sort key is the z value of the coordinate + # in the center of the face + rendered_faces.sort(key=lambda face: self.center_of_square(face)[2]) + + canvas_width_half = self.c.winfo_width() / 2 + canvas_height_half = self.c.winfo_height() / 2 + highest_z = max([max([point[2] for point in face]) for face in rendered_faces]) + for face in self.FACES: + for point in face: + x = point[0] + y = point[1] + z = point[2] + + # Push everything away from the camera so all z are <= 0 + z -= highest_z + + # Create vanishing point. + distance_camera = math.sqrt((x**2) + (y**2) + (z**2)) + #if z != 0: + # factor = (abs(z) ** 0.2) - 1 + # print(factor) + #else: + # factor = 0 + x += x * factor + y += y * factor + + # Inflate for display + x *= self.INFLATE_SCALE + y *= self.INFLATE_SCALE + z *= self.INFLATE_SCALE + + # Shift the coordinates into the screen + x += canvas_width_half + y += canvas_height_half + self.plot_point_screen(x, y) + + #print(rendered_faces) +t = TKCube() \ No newline at end of file diff --git a/TextureTile/README.md b/TextureTile/README.md new file mode 100644 index 0000000..8180e5d --- /dev/null +++ b/TextureTile/README.md @@ -0,0 +1,21 @@ +Texture Tile +============ + +Requires `pip install pillow` + +  + +Make it big! +

+ texture tile +

+ +Make it small! +

+ texture tile +

+ +Make it any size at all! +

+ texture tile +

\ No newline at end of file diff --git a/TextureTile/examples/example1.png b/TextureTile/examples/example1.png new file mode 100644 index 0000000..aa83a72 Binary files /dev/null and b/TextureTile/examples/example1.png differ diff --git a/TextureTile/examples/example2.png b/TextureTile/examples/example2.png new file mode 100644 index 0000000..03ec4d1 Binary files /dev/null and b/TextureTile/examples/example2.png differ diff --git a/TextureTile/texturetile.pyw b/TextureTile/texturetile.pyw new file mode 100644 index 0000000..9ea5c85 --- /dev/null +++ b/TextureTile/texturetile.pyw @@ -0,0 +1,82 @@ +import os +from PIL import Image +from PIL import ImageTk +import tkinter + +class TextureTile: + def __init__(self): + self.windowtitle = 'Texture Tile' + + self.t = tkinter.Tk() + self.t.title(self.windowtitle) + self.w = 450 + self.h = 475 + self.screenwidth = self.t.winfo_screenwidth() + self.screenheight = self.t.winfo_screenheight() + self.windowwidth = self.w + self.windowheight = self.h + self.windowx = (self.screenwidth-self.windowwidth) / 2 + self.windowy = ((self.screenheight-self.windowheight) / 2) - 27 + self.geometrystring = '%dx%d+%d+%d' % (self.windowwidth, self.windowheight, self.windowx, self.windowy) + self.t.geometry(self.geometrystring) + + self.entry_filename = tkinter.Entry(self.t, font=('Consolas', 12)) + self.button_load = tkinter.Button(self.t, text='Load', command=self.file_load_display) + self.frame_filearea = tkinter.Frame(self.t) + self.label_image = tkinter.Label(self.frame_filearea, bg='#222') + + self.t.columnconfigure(0, weight=1) + self.t.rowconfigure(1, weight=1) + self.entry_filename.grid(row=0, column=0, sticky='ew') + self.button_load.grid(row=0, column=1, sticky='ne') + self.frame_filearea.grid(row=1, column=0, columnspan=2, sticky='nsew') + self.label_image.pack(expand=True, fill='both') + #self.entry_filename.pack(fill='x') + #self.button_load.pack() + #self.label_image.pack() + + self.entry_filename.insert(0, os.getcwd()) + self.entry_filename.bind('', self.file_load_display) + self.entry_filename.focus_set() + + self.t.mainloop() + + def file_load_display(self, *event): + filename = self.entry_filename.get() + # Open file or turn red + try: + image = Image.open(filename) + self.entry_filename.configure(bg='#fff') + except FileNotFoundError: + self.entry_filename.configure(bg='#f00') + return + + # 9x the image + w = image.size[0] + h = image.size[1] + expanded = image.copy() + expanded = expanded.resize((w * 3, h * 3)) + for x in range(3): + for y in range(3): + expanded.paste(image, (w*x, h*y)) + + # Resize 9x'ed image into frame + w = expanded.size[0] + h = expanded.size[1] + fw = self.label_image.winfo_width() + fh = self.label_image.winfo_height() + ratio = min(fw/w, fh/h) + + w = int(w * ratio) + h = int(h * ratio) + + expanded = expanded.resize((w, h)) + image = ImageTk.PhotoImage(expanded) + self.label_image.configure(image=image) + self.label_image.dont_garbage_me_bro = image + r'C:\Users\Owner\AppData\Roaming\.MinecraftMulti\instances\Chocolate\minecraft\texturepacks\SixtyFox\textures\blocks\melon_top.png' + r'C:\users\owner\desktop\pi\imergers\ear.jpg' + + +if __name__ == '__main__': + t = TextureTile() \ No newline at end of file diff --git a/Toddo/README.md b/Toddo/README.md new file mode 100644 index 0000000..b52bc10 --- /dev/null +++ b/Toddo/README.md @@ -0,0 +1,9 @@ +Toddo +====== + +Commandline to-do-list manager. + + +

+ to-do list manager +

\ No newline at end of file diff --git a/Toddo/toddo.db b/Toddo/toddo.db new file mode 100644 index 0000000..d0b7891 Binary files /dev/null and b/Toddo/toddo.db differ diff --git a/Toddo/toddo.py b/Toddo/toddo.py new file mode 100644 index 0000000..55834d2 --- /dev/null +++ b/Toddo/toddo.py @@ -0,0 +1,314 @@ +import datetime +import shutil +import sqlite3 +import sys +import textwrap + +SQL_ID = 0 +SQL_TODOTABLE = 1 +SQL_CREATED = 2 +SQL_MESSAGE = 3 + +HELP_FULL = [ +('> toddo', 'Display the todos from the current table'), +('> toddo all', 'Display the todos from all tables'), +('> toddo 4', 'Display the todo with ID 4'), +('> toddo add', 'Add a new todo via multi-line typing prompt'), +('> toddo add "message"', 'Add a new todo with this message'), +('> toddo remove 8', 'Remove the todo with ID 8'), +('> toddo table', 'Display the name of the current table'), +('> toddo table name', 'Switch to the table named "name"') +] + +HELP_NOENTRIES = '''Your todo list is empty! +Use `toddo add` or `toddo add "message"` to make entries.''' + +HELP_NOACTIVE = '''Table `%s` has no entries! +Use `toddo all` to see if there are entries for other tables.''' + +HELP_REMOVE = '''Provide an ID number to remove.''' + +class ToddoExc(Exception): + pass + +class Toddo(): + def __init__(self, dbname='C:/git/else/toddo/toddo.db'): + self.sql = sqlite3.connect(dbname) + self.cur = self.sql.cursor() + self.cur.execute('CREATE TABLE IF NOT EXISTS meta(key TEXT, val TEXT)') + self.cur.execute('CREATE TABLE IF NOT EXISTS todos(id INT, todotable TEXT, created INT, message TEXT)') + self.cur.execute('CREATE INDEX IF NOT EXISTS todoindex on todos(id)') + + def add_todo(self, message=None): + ''' + Create new entry in the database on the active todotable. + ''' + if message is None: + message = multi_line_input() + message = str(message) + if message is '': + raise ToddoExc('Todos cannot be blank.') + + todoid = self.increment_lastid() + todotable = self.get_todotable() + created = int(datetime.datetime.now(datetime.timezone.utc).timestamp()) + + self.cur.execute('INSERT INTO todos VALUES(?, ?, ?, ?)', [todoid, todotable, created, message]) + self.sql.commit() + return todoid + + def remove_todo(self, idnumber): + ''' + Drop todo from the database. + ''' + idnumber = int(idnumber) + self.cur.execute('SELECT * FROM todos WHERE id=?', [idnumber]) + todo = self.cur.fetchone() + if todo is None: + raise ToddoExc('Todo %d does not exist.' % idnumber) + activetable = self.get_todotable() + requestedtable = todo[SQL_TODOTABLE] + if requestedtable.lower() != activetable.lower(): + raise ToddoExc('Todo %d is not part of the active table `%s`. It belongs to `%s`.' % (idnumber, activetable, requestedtable)) + self.cur.execute('DELETE FROM todos WHERE id=?', [idnumber]) + self.sql.commit() + return idnumber + + def display_one_todo(self, idnumber): + ''' + Make a nice display that shows a todo's entire contents. + ''' + self.cur.execute('SELECT * FROM todos WHERE id=?', [idnumber]) + todo = self.cur.fetchone() + if todo is None: + raise ToddoExc('Todo %d does not exist.' % idnumber) + + message = todo[SQL_MESSAGE] + messageleft = len('Message: ') + width = shutil.get_terminal_size()[0] - (messageleft + 1) + message = nicewrap(message, width, messageleft) + + return 'ID: %d\nTable: %s\nCreated: %s\nMessage: %s' % ( + todo[SQL_ID], todo[SQL_TODOTABLE], human(todo[SQL_CREATED]), message) + + def display_active_todos(self): + ''' + Pass the active table name into display_todos_from_table + ''' + todotable = self.get_todotable() + return self.display_todos_from_table(todotable) + + def display_todos_from_table(self, todotable): + ''' + Make a nice display from the database. + ''' + if todotable is None: + self.cur.execute('SELECT * FROM todos ORDER BY id ASC') + else: + self.cur.execute('SELECT * FROM todos WHERE todotable=? ORDER BY id ASC', [todotable]) + todos = self.cur.fetchall() + if len(todos) == 0: + return None + + todos = [list(x) for x in todos] + + longest_id = max(len(str(x[SQL_ID])) for x in todos) + longest_table = max(len(str(x[SQL_TODOTABLE])) for x in todos) + + display = [] + for todo in todos: + todoid = str(todo[SQL_ID]) + todoid = (' '*(longest_id-len(todoid))) + todoid + + timestamp = human(todo[SQL_CREATED]) + + todotable = todo[SQL_TODOTABLE] + todotable = (' '*(longest_table-len(todotable))) + todotable + + message = todo[SQL_MESSAGE] + if '\n' in message: + message = message.split('\n')[0] + ' ...' + + total = '%s : %s : %s : %s' % (todoid, todotable, timestamp, message) + terminal_width = shutil.get_terminal_size()[0] + if len(total) > terminal_width: + total = total[:(terminal_width-(len(total)+4))] + '...' + display.append(total) + + return '\n'.join(display) + + def switch_todotable(self, newtable=None): + ''' + Update the meta with `newtable` as the new active todotable. + ''' + self.cur.execute('SELECT val FROM meta WHERE key="todotable"') + activetable = self.cur.fetchone() + if not activetable: + activetable = self._install_default_todotable() + else: + activetable = activetable[0] + if newtable is None: + return activetable + self.cur.execute('UPDATE meta SET val=? WHERE key="todotable"', [newtable]) + self.sql.commit() + return newtable + + def increment_lastid(self, increment=False): + ''' + Increment the lastid in the meta table, THEN return it. + ''' + self.cur.execute('SELECT val FROM meta WHERE key="lastid"') + lastid = self.cur.fetchone() + if lastid is None: + self._install_default_lastid() + return 1 + else: + lastid = int(lastid[0]) + 1 + self.cur.execute('UPDATE meta SET val=? WHERE key="lastid"', [lastid]) + return lastid + + def get_todotable(self): + self.cur.execute('SELECT val FROM meta WHERE key="todotable"') + todotable = self.cur.fetchone() + if todotable is None: + self._install_default_todotable() + todotable = 'default' + else: + todotable = todotable[0] + return todotable + + def _install_default_lastid(self): + ''' + This method assumes that "lastid" does not already exist. + If it does, it's your fault for calling this. + ''' + self.cur.execute('INSERT INTO meta VALUES("lastid", 1)') + self.sql.commit() + return 1 + + def _install_default_todotable(self): + ''' + This method assumes that "todotable" does not already exist. + If it does, it's your fault for calling this. + ''' + self.cur.execute('INSERT INTO meta VALUES("todotable", "default")') + self.sql.commit() + return 'default' + +def human(timestamp): + timestamp = datetime.datetime.utcfromtimestamp(timestamp) + timestamp = datetime.datetime.strftime(timestamp, '%d %b %Y %H:%M') + return timestamp + +def multi_line_input(): + print('Submit a ctrl+z to finish typing.') + userinput = '' + ctrlz = '\x1a' + while True: + try: + additional = input('- ') + except EOFError: + # If you only enter a ctrlz + return userinput + + if ctrlz in additional: + additional = additional.split(ctrlz)[0] + userinput += additional + break + + userinput += additional + '\n' + + return userinput.strip() + +def nicewrap(message, width, paddingleft): + # http://stackoverflow.com/a/26538082 ########################## + message = '\n'.join(['\n'.join(textwrap.wrap(line, width,####### + break_long_words=True, replace_whitespace=False))########## + for line in message.split('\n')])########################## + ################################################################ + message = message.strip() + message = message.replace('\n', '\n' + (' '*paddingleft)) + return message + +def fullhelp(): + longestleft = max(len(x[0]) for x in HELP_FULL) + width = shutil.get_terminal_size()[0] - 1 + message = [] + for item in HELP_FULL: + pad = width - (longestleft+ 3) + item = '%s : %s' % (item[0] + (' '*(longestleft - len(item[0]))), nicewrap(item[1], pad, longestleft + 3)) + message.append(item) + message = '\n'.join(message) + return message + + +if __name__ == '__main__': + toddo = Toddo() + + # Look, no more IndexErrors + sys.argv += [None]*10 + + if isinstance(sys.argv[1], str): + sys.argv[1] = sys.argv[1].lower() + + if sys.argv[1] is None: + message = toddo.display_active_todos() + if message is None: + table = toddo.get_todotable() + print(HELP_NOACTIVE % table) + else: + print(message) + + elif sys.argv[1] == 'all': + message = toddo.display_todos_from_table(None) + if message is None: + print(HELP_NOENTRIES) + else: + print(message) + + elif sys.argv[1] == 'add': + args = list(filter(None, sys.argv)) + args = args[2:] + args = ' '.join(args) + if args == '': + args = None + message = toddo.add_todo(args) + if isinstance(message, int): + print('Added %d' % message) + + elif sys.argv[1] == 'remove': + idnumber = sys.argv[2] + if idnumber is None or not idnumber.replace(',', '').isdigit(): + print(HELP_REMOVE) + else: + message = [] + ids = [int(x) for x in idnumber.split(',')] + for x in ids: + try: + t = toddo.remove_todo(x) + message.append('Removed %d' % t) + except ToddoExc as e: + message.append(e.args[0]) + print('\n'.join(message)) + + elif sys.argv[1] == 'table': + currenttable = toddo.get_todotable() + message = toddo.switch_todotable(sys.argv[2]) + if currenttable == message: + print('You are on table `%s`' % message) + else: + print('Switched to table `%s`' % message) + + elif sys.argv[1].isdigit(): + try: + message = toddo.display_one_todo(int(sys.argv[1])) + print(message) + except ToddoExc as e: + print(e.args[0]) + + elif sys.argv[1] == 'help': + print(fullhelp()) + + else: + print('Command not recognized.') + print(fullhelp())