208 lines
6.1 KiB
Python
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)
|