anktui/main.py

208 lines
6.1 KiB
Python

import os
import sys
import tty
import termios
import signal
import traceback
import shutil
from subprocess import call
from tempfile import NamedTemporaryFile
from keys import *
from menu import Menu
from ankiconnect import *
from preview import previewCard, update
def preview(data, template, style, content, side='Back'):
# Get size in pixels
sys.stdout.write('\x1b[16t')
sys.stdout.flush()
report = ''
c = sys.stdin.read(1)
while c != 't':
report += c
c = sys.stdin.read(1)
report = report[2:].split(';')
size = shutil.get_terminal_size((80, 20))
h = int(report[1])*(size[1] - 1)
data['w'] = int(report[2])*(size[0]//2 - 1)
previewCard(template[side], style, content, width=data['w'], height=h, img=data['img'], htmlWidth=data['w'], frontSide=template['Front'])
def redraw(data):
sys.stdout.write('\x1b[2J')
data['menu'].draw()
sys.stdout.flush()
def process(char, data):
def previewSide(side='Back'):
card = getCards(current['modelName'])[0]
template, style = getTemplate(current['modelName'], card)
preview(data, template, style, current['fields'], side)
def changeView(view):
data['view'] = view
if view == 'selectTags':
menu.setItems(getTags())
menu.setMarked(current['tags'])
elif view == 'selectDeck':
menu.setItems(getDecks())
elif view == 'selectNoteType':
menu.setItems(getNoteTypes())
elif view == 'addNote':
menu.setItems(getFields(current['modelName']))
menu.setMarked(data['pinned'])
menu = data['menu']
current = data['current']
if char == SELECT_NOTE_TYPE:
changeView('selectNoteType')
elif char == SELECT_DECK:
changeView('selectDeck')
elif char == SELECT_TAGS:
changeView('selectTags')
elif char == PIN_FIELD:
if data['view'] == 'addNote':
menu.toggleMark()
if menu.isCurrentMarked():
data['pinned'].append(menu.selected())
else:
data['pinned'].remove(menu.selected())
elif char == ENTER:
if data['view'] == 'selectTags':
menu.toggleMark()
if menu.isCurrentMarked():
current['tags'].append(menu.selected())
else:
current['tags'].remove(menu.selected())
elif data['view'] == 'selectDeck':
current['deckName'] = menu.selected()
changeView('addNote')
elif data['view'] == 'selectNoteType':
current['modelName'] = menu.selected()
data['pinned'] = []
changeView('addNote')
previewSide()
elif data['view'] == 'addNote':
# Open editor
if menu.selected() in current['fields']:
content = current['fields'][menu.selected()]
else:
content = ''
with NamedTemporaryFile(prefix=menu.selected(), suffix='.html') as tf:
tf.write(bytes(content, encoding='utf-8'))
tf.flush()
call([data['EDITOR'], tf.name])
tf.seek(0)
current['fields'][menu.selected()] = tf.read().decode('utf-8')
sys.stdout.write('\x1b[?25l')
sys.stdout.flush()
previewSide()
elif char == PREVIEW:
previewSide('Front')
elif char == PREVIEW_BACK:
previewSide()
elif char == ADD:
addNote(current)
for field in current['fields']:
if field not in data['pinned']:
current['fields'][field] = ''
previewSide()
elif char == PREV:
menu.prev()
elif char == NEXT:
menu.next()
elif char == ESCAPE:
changeView('addNote')
if data['view'] == 'selectTags':
head = {'Selecting': 'Tags'}
elif data['view'] == 'selectDeck':
head = {'Selecting': 'Deck'}
elif data['view'] == 'selectNoteType':
head = {'Selecting': 'Note type'}
else:
head = {
'Note Type': current['modelName'],
'Deck': current['deckName'],
'Tags': ' '.join(current['tags'])
}
menu.setHead(head)
#sys.stdout.write(f'\x1b[1;1H{repr(char)}')
lastModified = os.path.getmtime(data['img'].name)
if lastModified > data['lastModified']:
update(data['w'], data['img'])
data['lastModified'] = lastModified
sys.stdout.flush()
def reset(data):
data['EDITOR'] = os.environ.get('EDITOR', 'vim')
head = {
'Note Type': 'Basic',
'Deck': 'Default',
'Tags': ''
}
data['noteType'] = 'Basic'
data['deck'] = 'Default'
data['view'] = 'addNote' # selectNoteType selectDeck selectTags
data['pinned'] = []
fields = getFields('Basic')
data['current'] = {
'deckName': 'Default',
'modelName': 'Basic',
'fields': {field: '' for field in fields},
'tags': [],
}
data['menu'] = Menu(fields, head=head)
data['img'] = NamedTemporaryFile(suffix='.png')
card = getCards(data['current']['modelName'])[0]
template, style = getTemplate(data['current']['modelName'], card)
preview(data, template, style, data['current']['fields'])
data['lastModified'] = os.path.getmtime(data['img'].name)
if __name__ == '__main__':
# Setup raw mode
fd = sys.stdin.fileno()
oldSettings = termios.tcgetattr(fd)
tty.setraw(sys.stdin)
try:
# Hide the cursor and clear the screen
sys.stdout.write('\x1b[?25l\x1b[2J')
sys.stdout.flush()
# Data
data = {}
reset(data)
# Redraw on resize
signal.signal(signal.SIGWINCH, lambda signum, frame: redraw(data))
# Read input
process('', data)
while True:
char = sys.stdin.read(1)
if char == QUIT:
break
process(char, data)
# Avoid breaking the terminal after a crash
except Exception:
tb = traceback.format_exc()
else:
tb = '\x1b[2J\x1b[1;1H'
# Restore terminal settings
sys.stdout.write('\x1b[?25h\n\r')
termios.tcsetattr(fd, termios.TCSADRAIN, oldSettings)
print(tb)