aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Powers <mark@marks.kitchen>2021-02-26 20:23:46 -0600
committerMark Powers <mark@marks.kitchen>2021-02-26 20:23:46 -0600
commitd78b6d188eb9ba206c8769b41c8021e7ba52ef98 (patch)
tree7a8905bbe777b6ce53929c4702e8cf740b192260
parent7169b622c805f966709b1861a5b58ad74d0aea69 (diff)
Add beta TUI client
-rw-r--r--README.md15
-rwxr-xr-xmain.py32
-rwxr-xr-xncurses.py106
3 files changed, 141 insertions, 12 deletions
diff --git a/README.md b/README.md
index 23ee894..8dfd022 100644
--- a/README.md
+++ b/README.md
@@ -54,6 +54,21 @@ example, if your wiki is at `wiki.example.com`, the url field should be set to
Run `main.py` in order to use the program.
+Example uses:
+- Create a page `./main.py create 2021/02/26 "February 26"`
+- Edit a page `./main.py edit 2021/02/26`
+
+## Ncurses TUI
+A ncurses TUI beta client also is provided, though it is still a work in
+progress. It is run through the file `ncurses.py`
+
+Keys:
+- `j`/down: move down
+- `k`/up: move up
+- `t`: create/edit page for today
+- `c`: create a page
+- `e`: edit page selected
+- `q`: quit
## TODO
- Include options to always answer yes or no
diff --git a/main.py b/main.py
index 32ace0e..5e25498 100755
--- a/main.py
+++ b/main.py
@@ -20,14 +20,15 @@ def today(args):
args: used
"""
- today = datetime.datetime.now()
- path = today.strftime("journal/%Y/%b/%d").lower()
+ print(args)
+ t = datetime.datetime.now()
+ path = t.strftime("journal/%Y/%b/%d").lower()
if get_single_page(path) is not None:
edit({"path": path})
else:
- date_int = int(today.strftime("%d"))
- title = today.strftime("%B ") + str(date_int)
- create([path, title])
+ date_int = int(t.strftime("%d"))
+ title = t.strftime("%B ") + str(date_int)
+ create({"path": path, "title": title})
def create(args):
"""
@@ -46,7 +47,7 @@ def create(args):
return
title = args["title"]
path = args["path"]
- if "content" in args:
+ if "content" not in args:
content = open_editor("create", path, "")
else:
content = args["content"]
@@ -57,6 +58,16 @@ def create(args):
sys.exit(1)
print(result["message"])
+def get_tree(regex):
+ response = graphql_queries.get_tree()
+ regex = " ".join(regex)
+ pages = []
+ for item in response["data"]["pages"]["list"]:
+ if not re.search(regex, item["path"]):
+ continue
+ pages.append(item)
+ return pages
+
def tree(args):
"""
Finds pages based on a path search
@@ -64,11 +75,7 @@ def tree(args):
args is a dictionary with the following keys:
regex: the regex to search paths with
"""
- response = graphql_queries.get_tree()
- regex = " ".join(args["regex"])
- for item in response["data"]["pages"]["list"]:
- if not re.search(regex, item["path"]):
- continue
+ for item in get_tree(args["regex"]):
print_item(item)
def get_single_page(path):
@@ -154,6 +161,7 @@ def edit(args):
args is a dictionary with the following keys:
path: the path of the page to edit
+ save (optional): include with any value to save without any prompt
"""
page = get_single_page(args["path"])
if page is None:
@@ -172,7 +180,7 @@ def edit(args):
print("-" * 80)
print(new_body)
print("-" * 80)
- if input("Save changes? (y/n) ") == "y":
+ if "save" in args or input("Save changes? (y/n) ") == "y":
response = graphql_queries.edit_page(page["id"], new_body, page["title"], page["path"])
result = response["data"]["pages"]["update"]["responseResult"]
if not result["succeeded"]:
diff --git a/ncurses.py b/ncurses.py
new file mode 100755
index 0000000..073ad50
--- /dev/null
+++ b/ncurses.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python3
+import main
+import curses
+from curses import wrapper
+
+def pager(stdscr, lst):
+ '''
+ Runs a pager for each string item in lst
+ '''
+ cols = stdscr.getmaxyx()[1]
+ rows = stdscr.getmaxyx()[0]
+ offset = 0
+ selected = 0
+ while True:
+ stdscr.clear()
+ for i in range(min(rows-1, len(lst))):
+ x = lst[i+offset]
+ if i+offset == selected:
+ stdscr.addstr(i, 0, x[:cols], curses.A_UNDERLINE)
+ else:
+ stdscr.addstr(i, 0, x[:cols])
+ if offset == 0:
+ stdscr.addstr(rows-1, 0, "--top--", curses.A_REVERSE)
+ elif offset + rows <= len(lst):
+ stdscr.addstr(rows-1, 0, "--more--", curses.A_REVERSE)
+ else:
+ stdscr.addstr(rows-1, 0, "--end--", curses.A_REVERSE)
+ k = stdscr.getch()
+ if k == curses.KEY_DOWN or k == ord('j'):
+ selected = min(len(lst), selected+1)
+ if (selected - offset) > (2 * rows / 3):
+ offset = min(len(lst)-rows+1, offset+1)
+ elif k == curses.KEY_UP or k == ord('k'):
+ selected = max(0, selected-1)
+ if (selected - offset) < (rows / 3):
+ offset = max(0, offset-1)
+ elif k == curses.KEY_NPAGE:
+ offset = min(len(lst)-rows+1, offset+rows-2)
+ selected = min(len(lst)-rows+1, selected+rows-2)
+ elif k == curses.KEY_PPAGE:
+ offset = max(0, offset-rows+2)
+ selected = max(0, selected-rows+2)
+ elif k == curses.KEY_HOME:
+ offset = 0
+ selected = 0
+ elif k == curses.KEY_END:
+ offset = len(lst)-rows+1
+ selected = len(lst)-1
+ elif k == curses.KEY_ENTER or k == 10:
+ return {"index": selected, "action": "select"}
+ elif k == ord('q'):
+ return {"index": selected, "action": "quit"}
+ elif k == ord('e'):
+ return {"index": selected, "action": "edit"}
+ elif k == ord('c'):
+ return {"index": selected, "action": "create"}
+ elif k == ord('t'):
+ return {"index": selected, "action": "today"}
+ stdscr.refresh()
+
+def enter_value(stdscr, prefix, row):
+ """
+ Creates a prompt to enter a value on the given row
+ """
+ title = ""
+ stdscr.addstr(row,0, prefix + title)
+ k = stdscr.getch()
+ while k != 10 and k != curses.KEY_ENTER:
+ if k in (curses.KEY_BACKSPACE, '\b', '\x7f'):
+ if len(title) > 0:
+ title = title[:-1]
+ else:
+ title += chr(k)
+ stdscr.deleteln()
+ stdscr.addstr(row,0, prefix + title)
+ k = stdscr.getch()
+ return title
+
+def m(stdscr):
+ """
+ The main method for the ncurses wrapper
+ """
+ items = main.get_tree("")
+ while True:
+ ret = pager(stdscr, [x["path"] + "\t" + x["title"] for x in items])
+ if ret["action"] == "select":
+ selected = items[ret["index"]]
+ ret = pager(stdscr, main.get_single_page(selected["path"])["content"].split("\n"))
+ elif ret["action"] == "edit":
+ selected = items[ret["index"]]
+ main.edit({"path":selected["path"], "save": True})
+ elif ret["action"] == "create":
+ stdscr.clear()
+ title = enter_value(stdscr, "Enter title: ", 0)
+ path = enter_value(stdscr, "Enter path: ", 1)
+ main.create({"path": path, "title": title})
+ elif ret["action"] == "today":
+ main.today({})
+ else:
+ break
+
+# Run the ncurses wrapper
+try:
+ wrapper(m)
+except Exception as e:
+ raise e