mirror of
https://github.com/Ascyii/typstar.git
synced 2026-01-01 13:34:24 -05:00
feat(anki): nvim integration
This commit is contained in:
32
lua/typstar/anki.lua
Normal file
32
lua/typstar/anki.lua
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
local M = {}
|
||||||
|
local config = require('typstar.config')
|
||||||
|
local utils = require('typstar.utils')
|
||||||
|
|
||||||
|
local cfg = config.config.anki
|
||||||
|
|
||||||
|
|
||||||
|
local function run_typstar_anki(args)
|
||||||
|
local cwd = vim.fn.getcwd()
|
||||||
|
local anki_key = ''
|
||||||
|
if cfg.ankiKey ~= nil then
|
||||||
|
anki_key = ' --anki-key ' .. cfg.ankiKey
|
||||||
|
end
|
||||||
|
local cmd = string.format(
|
||||||
|
'%s --root-dir %s --typst-cmd %s --anki-url %s %s %s',
|
||||||
|
cfg.typstarAnkiCmd, cwd, cfg.typstCmd, cfg.ankiUrl, anki_key, args)
|
||||||
|
utils.run_shell_command(cmd, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.scan()
|
||||||
|
run_typstar_anki('')
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.scan_force()
|
||||||
|
run_typstar_anki('--force-scan ' .. vim.fn.getcwd())
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.scan_force_current()
|
||||||
|
run_typstar_anki('--force-scan ' .. vim.fn.expand('%:p'))
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
@@ -2,6 +2,12 @@ local M = {}
|
|||||||
|
|
||||||
local default_config = {
|
local default_config = {
|
||||||
typstarRoot = '~/typstar',
|
typstarRoot = '~/typstar',
|
||||||
|
anki = {
|
||||||
|
typstarAnkiCmd = 'typstar-anki',
|
||||||
|
typstCmd = 'typst',
|
||||||
|
ankiUrl = 'http://127.0.0.1:8765',
|
||||||
|
ankiKey = nil,
|
||||||
|
},
|
||||||
excalidraw = {
|
excalidraw = {
|
||||||
assetsDir = 'assets',
|
assetsDir = 'assets',
|
||||||
filename = 'drawing-%Y-%m-%d-%H-%M-%S',
|
filename = 'drawing-%Y-%m-%d-%H-%M-%S',
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ local affix = [[
|
|||||||
|
|
||||||
local function launch_obsidian(path)
|
local function launch_obsidian(path)
|
||||||
print(string.format('Opening %s in Excalidraw', path))
|
print(string.format('Opening %s in Excalidraw', path))
|
||||||
utils.run_shell_command(string.format('%s "obsidian://open?path=%s"', cfg.uriOpenCommand, utils.urlencode(path)))
|
utils.run_shell_command(
|
||||||
|
string.format('%s "obsidian://open?path=%s"', cfg.uriOpenCommand, utils.urlencode(path)), false
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.insert_drawing()
|
function M.insert_drawing()
|
||||||
@@ -27,7 +29,7 @@ function M.insert_drawing()
|
|||||||
for pattern, template_path in pairs(cfg.templatePath) do
|
for pattern, template_path in pairs(cfg.templatePath) do
|
||||||
if string.match(path, pattern) then
|
if string.match(path, pattern) then
|
||||||
found_match = true
|
found_match = true
|
||||||
utils.run_shell_command(string.format('cat %s > %s', template_path, path)) -- don't copy file metadata
|
utils.run_shell_command(string.format('cat %s > %s', template_path, path), false) -- don't copy file metadata
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,11 +4,19 @@ local config = require('typstar.config')
|
|||||||
|
|
||||||
M.setup = function(args)
|
M.setup = function(args)
|
||||||
config.merge_config(args)
|
config.merge_config(args)
|
||||||
local excalidraw = require('typstar.excalidraw')
|
|
||||||
local autosnippets = require('typstar.autosnippets')
|
local autosnippets = require('typstar.autosnippets')
|
||||||
|
local excalidraw = require('typstar.excalidraw')
|
||||||
|
local anki = require('typstar.anki')
|
||||||
|
|
||||||
|
vim.api.nvim_create_user_command('TypstarToggleSnippets', autosnippets.toggle_autosnippets, {})
|
||||||
|
|
||||||
vim.api.nvim_create_user_command('TypstarInsertExcalidraw', excalidraw.insert_drawing, {})
|
vim.api.nvim_create_user_command('TypstarInsertExcalidraw', excalidraw.insert_drawing, {})
|
||||||
vim.api.nvim_create_user_command('TypstarOpenExcalidraw', excalidraw.open_drawing, {})
|
vim.api.nvim_create_user_command('TypstarOpenExcalidraw', excalidraw.open_drawing, {})
|
||||||
vim.api.nvim_create_user_command('TypstarToggleSnippets', autosnippets.toggle_autosnippets, {})
|
|
||||||
|
vim.api.nvim_create_user_command('TypstarAnkiScan', anki.scan, {})
|
||||||
|
vim.api.nvim_create_user_command('TypstarAnkiForce', anki.scan_force, {})
|
||||||
|
vim.api.nvim_create_user_command('TypstarAnkiForceCurrent', anki.scan_force_current, {})
|
||||||
|
|
||||||
autosnippets.setup()
|
autosnippets.setup()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,31 @@ function M.insert_text_block(snip)
|
|||||||
vim.api.nvim_buf_set_lines(vim.api.nvim_get_current_buf(), line_num, line_num, false, lines)
|
vim.api.nvim_buf_set_lines(vim.api.nvim_get_current_buf(), line_num, line_num, false, lines)
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.run_shell_command(cmd)
|
function M.run_shell_command(cmd, show_output)
|
||||||
vim.fn.jobstart(cmd)
|
local handle_output = function(data, err)
|
||||||
|
local msg = table.concat(data, '\n')
|
||||||
|
if not string.match(msg, '^%s*$') then
|
||||||
|
local level = err and vim.log.levels.ERROR or vim.log.levels.INFO
|
||||||
|
vim.notify(msg, level)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if show_output then
|
||||||
|
vim.fn.jobstart(
|
||||||
|
cmd,
|
||||||
|
{
|
||||||
|
on_stdout = function(_, data, _)
|
||||||
|
handle_output(data, false)
|
||||||
|
end,
|
||||||
|
on_stderr = function(_, data, _)
|
||||||
|
handle_output(data, true)
|
||||||
|
end,
|
||||||
|
stdout_buffered = false,
|
||||||
|
stderr_buffered = true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else
|
||||||
|
vim.fn.jobstart(cmd)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.char_to_hex(c)
|
function M.char_to_hex(c)
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class AnkiConnectApi:
|
|||||||
update[card.deck].append(card)
|
update[card.deck].append(card)
|
||||||
n_update += 1
|
n_update += 1
|
||||||
|
|
||||||
print(f"Pushing {n_add} new flashcards and {n_update} updated flashcards to Anki...")
|
print(f"Pushing {n_add} new flashcards and {n_update} updated flashcards to Anki...", flush=True)
|
||||||
await self._create_required_decks({*add.keys(), *update.keys()})
|
await self._create_required_decks({*add.keys(), *update.keys()})
|
||||||
await self._add_new_cards(add)
|
await self._add_new_cards(add)
|
||||||
await _gather_exceptions(
|
await _gather_exceptions(
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ async def export_flashcards(root_dir, force_scan, clear_cache, typst_cmd, anki_u
|
|||||||
# write id updates to files
|
# write id updates to files
|
||||||
parser.update_ids_in_source()
|
parser.update_ids_in_source()
|
||||||
parser.save_file_hashes()
|
parser.save_file_hashes()
|
||||||
print("Done")
|
print("Done", flush=True)
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ class FlashcardParser:
|
|||||||
else:
|
else:
|
||||||
scan_dir = force_scan
|
scan_dir = force_scan
|
||||||
|
|
||||||
print(f"Parsing flashcards in {scan_dir if single_file is None else single_file} ...")
|
print(f"Parsing flashcards in {scan_dir if single_file is None else single_file} ...", flush=True)
|
||||||
preambles = {}
|
preambles = {}
|
||||||
flashcards = []
|
flashcards = []
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@ class FlashcardParser:
|
|||||||
self.save_file_hashes()
|
self.save_file_hashes()
|
||||||
|
|
||||||
def update_ids_in_source(self):
|
def update_ids_in_source(self):
|
||||||
print("Updating ids in source...")
|
print("Updating ids in source...", flush=True)
|
||||||
for fh, cards in self.file_handlers:
|
for fh, cards in self.file_handlers:
|
||||||
file_updated = False
|
file_updated = False
|
||||||
for c in cards:
|
for c in cards:
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class TypstCompiler:
|
|||||||
card.set_svgs(front, back)
|
card.set_svgs(front, back)
|
||||||
|
|
||||||
async def compile_flashcards(self, cards: List[Flashcard]):
|
async def compile_flashcards(self, cards: List[Flashcard]):
|
||||||
print(f"Compiling {len(cards)} flashcards...")
|
print(f"Compiling {len(cards)} flashcards...", flush=True)
|
||||||
semaphore = asyncio.Semaphore(self.max_processes)
|
semaphore = asyncio.Semaphore(self.max_processes)
|
||||||
|
|
||||||
async def compile_coro(card):
|
async def compile_coro(card):
|
||||||
|
|||||||
Reference in New Issue
Block a user