Below is a draft for implementing branching (control multiple lists with one script). It works similar to git branching.
"""
File: todo.py
------------------
BETA new version of Lemnos with branching.
Simple command-line to-do list manager. See README.md for getting started
and how to use the program.
"""
import sys
import os
import glob
from os.path import exists
curr_dir_path = os.path.dirname(os.path.realpath(__file__))
BASE_PATH = os.path.join(curr_dir_path, "lists")
LIST_PATH = "grfs.txt"
LIST_FILE_PATH = os.path.join(BASE_PATH, LIST_PATH)
def show_branches():
"""
Note to self: didn't do indexing yet.
Function to show current branches stored in ./lists.
Activated by 'branch' or 'b'.
"""
txt_files = glob.glob(BASE_PATH + '/*.txt', recursive=True)
#txt_files.sort()
#idx = 0
for file_path in txt_files:
#idx += 1
branch_name = file_path[file_path.rfind("/") + 1:file_path.rfind(".")]
file = "- " + branch_name
#file = str(idx) + ". " + branch_name
if (branch_name + ".txt") == LIST_PATH:
file = file + " (current branch)"
print(file)
def current_branch():
"""
Show current branch name.
Activated by 'branch current' or 'bc'.
"""
txt_files = glob.glob(BASE_PATH + '/*.txt', recursive=True)
txt_files.sort()
for file_path in txt_files:
branch_name = file_path[file_path.rfind("/") + 1:file_path.rfind(".")]
file = "- " + branch_name
if (branch_name + ".txt") == LIST_PATH:
print(branch_name)
def delete_branch(branch_name):
"""
Function to delete a branch.
Activated by 'branch delete' or 'bd'.
"""
assert (branch_name + ".txt") != LIST_PATH, "cannot delete current branch"
txt_files = glob.glob(BASE_PATH + '/*.txt', recursive=True)
txt_files.sort()
for file_path in txt_files:
curr_branch = file_path[file_path.rfind("/") + 1:file_path.rfind(".")]
if branch_name == curr_branch:
branch_path = os.path.join(BASE_PATH, branch_name + ".txt")
if os.path.exists(branch_path):
#os.remove(branch_path)
subpath = os.path.join(BASE_PATH, "archived", branch_name + ".txt")
if os.path.exists(subpath):
subpath = os.path.join(BASE_PATH, "archived", branch_name + "1.txt")
os.rename(branch_path, subpath)
else:
print("The branch does not exist")
print(f"'{branch_name}' archived successfully")
sys.exit()
print("Error: branch does not exist")
def switch_branches(branch_name):
"""
Function to switch branches stored in ./lists.
Activated by 'branch switch' or 'bs'.
"""
txt_files = glob.glob(BASE_PATH + '/*.txt', recursive=True)
txt_files.sort()
branch_exists = False
for file_path in txt_files:
file = file_path[file_path.rfind("/") + 1:file_path.rfind(".")]
if file == branch_name:
branch_exists = True
if branch_exists == False:
print("Error: branch does not exist")
sys.exit()
f = open(__file__, 'r')
lines = f.readlines()
list_path_idx = -1
idx = 0
for l in lines:
l = l.strip()
template_string = f'LIST_PATH = "{LIST_PATH}"'
if l == template_string:
list_path_idx = idx
break
idx += 1
new_string = branch_name + '.txt'
lines[list_path_idx] = f'LIST_PATH = "{new_string}"' + '\n'
with open(__file__, "w") as f:
contents = "".join(lines)
f.write(contents)
print(f"Switched to branch '{branch_name}'")
def new_branch(branch_name):
"""
Function to make a new branch.
Activated by "branch new" or "bn".
"""
path_string = branch_name + ".txt"
new_path = os.path.join(BASE_PATH, path_string)
assert not exists(new_path), "branch already exists"
f = open(new_path, "x")
print(f"'{branch_name}' branch created")
switch_branches(branch_name)
def length(file_obj):
"""
Function that takes in the file object
(pointing to list.txt) and returns the number of
items in the list.
"""
count = 0
for line in file_obj:
count += 1
return count
def add(item_string):
"""
Function that appends the item based on what the
user specified as a command line argument to list.txt.
"""
curr_num_items = length(open(LIST_FILE_PATH))
curr_index = curr_num_items + 1
og_string = item_string # for printing purposes
item_string = str(curr_index) + ". " + item_string + '\n'
file = open(LIST_FILE_PATH, "a")
file.write(item_string)
file.close()
print('Added "' + og_string + '" to the to-do list.')
def show():
"""
Function that prints out the list. It also displays
the number of items in the list.
"""
file = open(LIST_FILE_PATH)
branch_str = LIST_PATH[:LIST_PATH.rfind(".")]
for line in file:
print(line, end='') # use end to avoid printing \n
print(f"Number of items (branch: {branch_str}):", length(open(LIST_FILE_PATH)))
def search(query):
"""
Function that searches the list for the query. Looks
for exact match in the list. If query is not found,
it prints nothing.
"""
file = open(LIST_FILE_PATH)
for line in file:
line_list = line.split()
for elem in line_list:
if str(query) == str(elem):
print(line, end = '')
def show_priority():
"""
Function that prints out prioritized items in the list.
It also displays the number of prioritized items in the
list.
"""
file = open(LIST_FILE_PATH)
count = 0
for line in file:
if "*" in line:
count += 1
print(line, end='') # use end to avoid printing \n
print("Number of prioritized items:", count)
def make_prioritized(idx):
"""
Function that prioritizes the element at idx.
"""
# store list of lines to use later (since we will overwrite these lines)
temp_file_obj = open(LIST_FILE_PATH, "r")
line_list = temp_file_obj.readlines()
temp_file_obj.close()
updated_list = open(LIST_FILE_PATH, "w")
i = 1
for line in line_list:
if i == idx:
dot_idx = line.find(".")
line = line[:dot_idx + 1] + " *" + line[dot_idx + 2:]
updated_list.write(line)
i += 1
updated_list.close()
def unprioritize(idx):
"""
Function that un-prioritizes the element at idx.
"""
# store list of lines to use later (since we will overwrite these lines)
temp_file_obj = open(LIST_FILE_PATH, "r")
line_list = temp_file_obj.readlines()
temp_file_obj.close()
updated_list = open(LIST_FILE_PATH, "w")
i = 1
for line in line_list:
if i == idx:
line = line.replace("*", "")
updated_list.write(line)
i += 1
updated_list.close()
def complete(idx):
"""
Function that completes (deletes) the line (item) at the
specified index from the list.
"""
# store list of lines to use later (since we will overwrite these lines)
temp_file_obj = open(LIST_FILE_PATH, "r")
line_list = temp_file_obj.readlines()
temp_file_obj.close()
updated_list = open(LIST_FILE_PATH, "w")
curr_idx = 1
line_count = 0 # num lines appended to new list
for line in line_list:
if curr_idx < idx:
updated_list.write(line)
line_count += 1
if curr_idx > idx:
line_count += 1
dot_idx = line.find(".")
line = str(line_count) + line[dot_idx:]
updated_list.write(line)
curr_idx += 1
def erase():
"""
Function that erases the contents of the list.
"""
file = open(LIST_FILE_PATH, "w")
file.close()
def main():
user_arguments = sys.argv[1:]
arg_count = len(user_arguments) # num user arguments
# print out list if no argument was specified
if arg_count == 0:
show() # show the list
sys.exit()
# add item to list if 'add' argument is specified
if (user_arguments[0] == "add" or user_arguments[0] == "a") and arg_count > 1:
add(' '.join(user_arguments[1:]))
# search the list with given argument as query if 'search' argument is specified
if (user_arguments[0] == "search" or user_arguments[0] == "s") and arg_count > 1:
search(' '.join(user_arguments[1:]))
# print out list if 'show' argument is specified
if user_arguments[0] == "show":
show()
# print out prioritized items from list
if (user_arguments[0] == "priority" or user_arguments[0] == "p") and arg_count == 1:
show_priority()
# prioritize element
if (user_arguments[0] == "prioritize" or user_arguments[0] == "p") and arg_count == 2:
specified_idx = int(user_arguments[1])
if specified_idx > length(open(LIST_FILE_PATH)) or specified_idx <= 0:
print("Item index out of bounds")
sys.exit()
make_prioritized(specified_idx)
# un-prioritize element
if (user_arguments[0] == "unprioritize" or user_arguments[0] == "u") and arg_count == 2:
specified_idx = int(user_arguments[1])
if specified_idx > length(open(LIST_FILE_PATH)) or specified_idx <= 0:
print("Item index out of bounds")
sys.exit()
unprioritize(specified_idx)
# print out num items in list if 'len' argument is specified
if user_arguments[0] == "len" or user_arguments[0] == "l":
print("Number of items:", length(open(LIST_FILE_PATH)))
# complete (delete) specific item from list
if (user_arguments[0] == "complete" or user_arguments[0] == "c") and arg_count == 2:
specified_idx = int(user_arguments[1])
if specified_idx > length(open(LIST_FILE_PATH)) or specified_idx <= 0:
print("Item index out of bounds")
sys.exit()
complete(specified_idx)
# erase items from list
if user_arguments[0] == "erase" or user_arguments[0] == "e":
erase()
# branch runner code
# print out branches if 'branch' argument is specified
if (user_arguments[0] == "branch" or user_arguments[0] == "b") and (len(user_arguments) < 2):
show_branches()
elif (user_arguments[0] == "branch new") or (user_arguments[0] == "bn"):
# create new branch
assert len(user_arguments) > 1, "must provide branch name"
new_branch(user_arguments[1])
elif (user_arguments[0] == "branch switch") or (user_arguments[0] == "bs"):
# switch branches
assert len(user_arguments) > 1, "must provide branch name"
switch_branches(user_arguments[1])
elif (user_arguments[0] == "branch current") or (user_arguments[0] == "bc"):
# get current branch
current_branch()
elif (user_arguments[0] == "branch delete") or (user_arguments[0] == "bd"):
# switch branches
assert len(user_arguments) > 1, "must provide branch name"
delete_branch(user_arguments[1])
elif (len(user_arguments) > 1):
if (user_arguments[0] == "branch") and (user_arguments[1] == "current"):
current_branch()
elif (user_arguments[0] == "branch") and (user_arguments[1] == "new"):
assert len(user_arguments) > 2, "must provide branch name"
new_branch(user_arguments[2])
elif (user_arguments[0] == "branch") and (user_arguments[1] == "switch"):
assert len(user_arguments) > 2, "must provide branch name"
switch_branches(user_arguments[2])
elif (user_arguments[0] == "branch") and (user_arguments[1] == "delete"):
assert len(user_arguments) > 2, "must provide branch name"
delete_branch(user_arguments[2])
if __name__ == '__main__':
main()