Merge branch 'dev' into index-confilicts-readable-typst

This commit is contained in:
Linus
2025-01-25 18:46:56 +01:00
committed by GitHub
14 changed files with 348 additions and 70 deletions

View File

@@ -22,8 +22,14 @@ end
function M.scan() run_typstar_anki('') end
function M.scan_reimport() run_typstar_anki('--reimport') end
function M.scan_force() run_typstar_anki('--force-scan ' .. vim.fn.getcwd()) end
function M.scan_force_reimport() run_typstar_anki('--reimport --force-scan ' .. vim.fn.getcwd()) end
function M.scan_force_current() run_typstar_anki('--force-scan ' .. vim.fn.expand('%:p')) end
function M.scan_force_current_reimport() run_typstar_anki('--reimport --force-scan ' .. vim.fn.expand('%:p')) end
return M

View File

@@ -46,12 +46,13 @@ end
function M.snip(trigger, expand, insert, condition, priority, wordTrig)
priority = priority or 1000
if wordTrig == nil then wordTrig = true end
return luasnip.snippet(
{
trig = trigger,
trigEngine = M.engine,
trigEngineOpts = { condition = condition },
wordTrig = wordTrig,
trigEngineOpts = { condition = condition, wordTrig = wordTrig },
wordTrig = false,
priority = priority,
snippetType = 'autosnippet',
},
@@ -68,6 +69,17 @@ end
function M.engine(trigger, opts)
local base_engine = lsengines.ecma(trigger, opts)
-- determine possibly fixed length of trigger
local fixed_length
if not trigger:match('[%+%*%?%]%[|]') then
fixed_length = #trigger
- utils.count_string(trigger, '\\')
- utils.count_string(trigger, '%(')
- utils.count_string(trigger, '%)')
end
-- cache preanalysis results
local condition = function()
local cached = lexical_result_cache[opts.condition]
if cached ~= nil and cached[1] == last_keystroke_time then return cached[2] end
@@ -75,9 +87,28 @@ function M.engine(trigger, opts)
lexical_result_cache[opts.condition] = { last_keystroke_time, result }
return result
end
-- matching
return function(line, trig)
if not M.snippets_toggle or not condition() then return nil end
return base_engine(line, trig)
if fixed_length ~= nil then
local first_idx = #line - fixed_length -- include additional char for wordtrig
if first_idx < 0 then
return nil
elseif first_idx > 0 then
if string.byte(line, first_idx) > 127 then return nil end
end
line = line:sub(first_idx)
end
local whole, captures = base_engine(line, trig)
if whole == nil then return nil end
-- custom word trig
local from = #line - #whole + 1
if opts.wordTrig and from ~= 1 and string.match(string.sub(line, from - 1, from - 1), '[%w.]') ~= nil then
return nil
end
return whole, captures
end
end

View File

@@ -1,7 +1,7 @@
local M = {}
local default_config = {
typstarRoot = '~/typstar',
typstarRoot = nil,
anki = {
typstarAnkiCmd = 'typstar-anki',
typstCmd = 'typst',
@@ -30,6 +30,9 @@ local default_config = {
function M.merge_config(args)
M.config = vim.tbl_deep_extend('force', default_config, args or {})
M.config.typstarRoot = M.config.typstarRoot
or debug.getinfo(1).source:match('^@(.*)/lua/typstar/config%.lua$')
or '~/typstar'
M.config.excalidraw.templatePath = M.config.excalidraw.templatePath
or {
['%.excalidraw%.md$'] = M.config.typstarRoot .. '/res/excalidraw_template.excalidraw.md',

View File

@@ -14,8 +14,11 @@ M.setup = function(args)
vim.api.nvim_create_user_command('TypstarOpenExcalidraw', excalidraw.open_drawing, {})
vim.api.nvim_create_user_command('TypstarAnkiScan', anki.scan, {})
vim.api.nvim_create_user_command('TypstarAnkiReimport', anki.scan_reimport, {})
vim.api.nvim_create_user_command('TypstarAnkiForce', anki.scan_force, {})
vim.api.nvim_create_user_command('TypstarAnkiForceReimport', anki.scan_force_reimport, {})
vim.api.nvim_create_user_command('TypstarAnkiForceCurrent', anki.scan_force_current, {})
vim.api.nvim_create_user_command('TypstarAnkiForceCurrentReimport', anki.scan_force_current_reimport, {})
autosnippets.setup()
end

View File

@@ -1,5 +1,6 @@
local ls = require('luasnip')
local d = ls.dynamic_node
local i = ls.insert_node
local s = ls.snippet_node
local t = ls.text_node
local helper = require('typstar.autosnippets')
@@ -8,15 +9,15 @@ local cap = helper.cap
local math = helper.in_math
local markup = helper.in_markup
local letter_snippets = {}
local greek_letters_map = {
['a'] = 'alpha',
['b'] = 'beta',
['c'] = 'chi',
['d'] = 'delta',
['e'] = 'epsilon',
['f'] = 'phi',
['g'] = 'gamma',
['h'] = 'phi',
['h'] = 'eta',
['i'] = 'iotta',
['j'] = 'theta',
['k'] = 'kappa',
@@ -41,6 +42,8 @@ local common_indices = { '\\d+', '[i-n]' }
-- buitins and caligraphic letters from github.com/lentilus/readable-typst
local index_conflicts = { 'in', 'ln', 'pi', 'xi', 'Ii', 'Jj', 'Kk', 'Ll', 'Mm', 'Nn' }
local index_conflicts_set = {}
local punctuation_prepend_space = { ',', ';' }
local punctuation_prepend_space_set = {}
local trigger_greek = ''
local trigger_index_pre = ''
local trigger_index_post = ''
@@ -59,10 +62,15 @@ for latin, greek in pairs(greek_letters_map) do
table.insert(greek_keys, latin:upper())
end
for _, conflict in ipairs(index_conflicts) do
index_conflicts_set[conflict] = true
local generate_bool_set = function(arr, target)
for _, val in ipairs(arr) do
target[val] = true
end
end
generate_bool_set(index_conflicts, index_conflicts_set)
generate_bool_set(punctuation_prepend_space, punctuation_prepend_space_set)
greek_letters_map = greek_full
trigger_greek = table.concat(greek_keys, '|')
trigger_index_pre = '[A-Za-z]' .. '|' .. table.concat(greek_letters_set, '|')
@@ -70,31 +78,62 @@ trigger_index_post = table.concat(common_indices, '|')
local get_greek = function(_, snippet) return s(nil, t(greek_letters_map[snippet.captures[1]])) end
local get_index = function(_, snippet)
local letter, index = snippet.captures[1], snippet.captures[2]
local get_index = function(_, snippet, _, idx1, idx2)
local letter, index = snippet.captures[idx1], snippet.captures[idx2]
local trigger = letter .. index
if index_conflicts_set[trigger] then return s(nil, t(trigger)) end
return s(nil, t(letter .. '_' .. index))
end
table.insert(letter_snippets, snip(':([A-Za-z0-9])', '$<>$ ', { cap(1) }, markup))
table.insert(letter_snippets, snip(';(' .. trigger_greek .. ')', '$<>$ ', { d(1, get_greek) }, markup))
table.insert(letter_snippets, snip(';(' .. trigger_greek .. ')', '<>', { d(1, get_greek) }, math))
table.insert(
letter_snippets,
snip(
'\\$(' .. trigger_index_pre .. ')\\$' .. '(' .. trigger_index_post .. ') ',
'$<>$ ',
{ d(1, get_index) },
markup,
500
)
)
table.insert(
letter_snippets,
snip('(' .. trigger_index_pre .. ')' .. '(' .. trigger_index_post .. ') ', '<> ', { d(1, get_index) }, math, 200)
)
local get_series = function(_, snippet)
local letter, target = snippet.captures[1], snippet.captures[2]
local target_num = tonumber(target)
local result
if target_num then
local res = {}
for n = 1, target_num do
table.insert(res, string.format('%s_%d', letter, n))
if n ~= target_num then table.insert(res, ', ') end
end
result = table.concat(res, '')
else
result = string.format('%s_1, %s_2, ..., %s_%s', letter, letter, letter, target)
end
return s(nil, t(result))
end
local prepend_space = function(_, snippet, _, idx)
local punc = snippet.captures[idx]
if punctuation_prepend_space_set[punc] then punc = punc .. ' ' end
return s(nil, t(punc))
end
return {
unpack(letter_snippets),
-- latin/greek
snip(':([A-Za-z0-9])', '$<>$ ', { cap(1) }, markup),
snip(';(' .. trigger_greek .. ')', '$<>$ ', { d(1, get_greek) }, markup),
snip(';(' .. trigger_greek .. ')', '<>', { d(1, get_greek) }, math),
-- indices
snip(
'\\$(' .. trigger_index_pre .. ')\\$' .. '(' .. trigger_index_post .. ')([^\\w])',
'$<>$<>',
{ d(1, get_index, {}, { user_args = { 1, 2 } }), d(2, prepend_space, {}, { user_args = { 3 } }) },
markup,
500
),
snip(
'(' .. trigger_index_pre .. ')' .. '(' .. trigger_index_post .. ')([^\\w])',
'<><>',
{ d(1, get_index, {}, { user_args = { 1, 2 } }), d(2, prepend_space, {}, { user_args = { 3 } }) },
math,
200
),
-- series of numbered letters
snip('(' .. trigger_index_pre .. ') ot ', '<>_1, <>_2, ... ', { cap(1), cap(1) }, math), -- a_1, a_2, ...
snip('(' .. trigger_index_pre .. ') ot(\\w+) ', '<> ', { d(1, get_series) }, math), -- a_1, a_2, ... a_j or a_1, a_2, a_2, a_3, a_4, a_5
-- misc
snip('(' .. trigger_index_pre .. ')bl', 'B_<> (<>)', { cap(1), i(1, 'x_0') }, math),
}

View File

@@ -36,26 +36,35 @@ return {
-- operators
snip('ak([^k ])', '+ <>', { cap(1) }, math, 100, false),
snip('sk([^k ])', '- <>', { cap(1) }, math, 100, false),
snip('oak', 'plus.circle ', {}, math, 1100),
snip('bak', 'plus.square ', {}, math, 1100),
snip('mak', 'plus.minus ', {}, math, 1100),
snip('xx', 'times ', {}, math),
snip('oak', 'plus.circle ', {}, math),
snip('bak', 'plus.square ', {}, math),
snip('mak', 'plus.minus ', {}, math),
snip('xx', 'times ', {}, math, 900),
snip('oxx', 'times.circle ', {}, math),
snip('bxx', 'times.square ', {}, math),
snip('ff', '(<>) / (<>) <>', { i(1, 'a'), i(2, 'b'), i(3) }, math),
-- exponents
snip('iv', '^(-1) ', {}, math, 500, false),
snip('sr', '^2 ', {}, math, 500, false),
snip('cb', '^3 ', {}, math, 500, false),
snip('jj', '_(<>) ', { i(1, 'n') }, math, 500, false),
snip('kk', '^(<>) ', { i(1, 'n') }, math, 500, false),
snip('ep', 'exp(<>) ', { i(1, '1') }, math),
-- sets
-- 'st' to '{<>} in ./visual.lua
snip('set', '{<> | <>}', { i(1), i(2) }, math),
snip('es', 'emptyset ', {}, math),
snip('es', 'emptyset ', {}, math, 900),
snip('ses', '{emptyset} ', {}, math),
snip('sp', 'supset ', {}, math),
snip('sb', 'subset ', {}, math),
snip('sep', 'supset.eq ', {}, math),
snip('seb', 'subset.eq ', {}, math),
snip('nn', 'sect ', {}, math),
snip('uu', 'union ', {}, math),
snip('bnn', 'sect.big ', {}, math, 1100),
snip('buu', 'union.big ', {}, math, 1100),
snip('nn', 'sect ', {}, math, 900),
snip('uu', 'union ', {}, math, 900),
snip('bnn', 'sect.big ', {}, math),
snip('buu', 'union.big ', {}, math),
snip('swo', 'without ', {}, math),
-- misc
@@ -63,28 +72,22 @@ return {
snip('mt', '|->> ', {}, math),
snip('Oo', 'compose ', {}, math),
snip('iso', 'tilde.equiv ', {}, math),
snip('ep', 'exp(<>) ', { i(1, '1') }, math),
snip('cc', 'cases(\n\t<>\n)\\', { i(1, '1') }, math),
snip('(K|M|N|Q|R|S|Z)([\\dn]) ', '<><>^<> ', { cap(1), cap(1), cap(2) }, math),
snip('(.*)iv', '<>^(-1)', { cap(1) }, math),
snip('(.*)sr', '<>^2', { cap(1) }, math),
snip('(.*)cb', '<>^3', { cap(1) }, math),
snip('(.*)jj', '<>_(<>)', { cap(1), i(1, 'n') }, math),
snip('(.*)kk', '<>^(<>)', { cap(1), i(1, 'n') }, math),
snip('ddx', '(d <>)(d <>)', { i(1, 'f'), i(2, 'x') }, math),
snip('it', 'integral', {}, math),
snip('int', 'integral_(<>)^(<>)', { i(1, 'a'), i(2, 'b') }, math),
snip('oit', 'integral_Omega', {}, math),
snip('dit', 'integral_(<>)', { i(1, 'Omega') }, math),
snip('ddx', '(d <>)(d <>) ', { i(1, 'f'), i(2, 'x') }, math),
snip('it', 'integral ', {}, math, 900),
snip('int', 'integral_(<>)^(<>) ', { i(1, 'a'), i(2, 'b') }, math),
snip('oit', 'integral_Omega ', {}, math),
snip('dit', 'integral_(<>) ', { i(1, 'Omega') }, math),
snip('sm', 'sum ', {}, math),
snip('sum', 'sum_(<>)^(<>)', { i(1, 'i=0'), i(2, 'oo') }, math),
snip('osm', 'sum_Omega', {}, math),
snip('dsm', 'sum_(<>)', { i(1, 'I') }, math),
snip('sm', 'sum ', {}, math, 900),
snip('sum', 'sum_(<>)^(<>) ', { i(1, 'i=0'), i(2, 'oo') }, math),
snip('osm', 'sum_Omega ', {}, math),
snip('dsm', 'sum_(<>) ', { i(1, 'I') }, math),
snip('lm', 'lim <>', { i(1, 'a_n') }, math),
snip('lim', 'lim_(<> ->> <>) <>', { i(1, 'n'), i(2, 'oo'), i(3, 'a_n') }, math),
snip('lim (sup|inf)', 'lim<> <>', { cap(1), i(1, 'a_n') }, math),
snip('lim(_.*-.*) (sup|inf)', 'lim<><> <>', { cap(2), cap(1), i(1, 'a_n') }, math),
snip('lm', 'lim ', {}, math),
snip('lim', 'lim_(<> ->> <>) ', { i(1, 'n'), i(2, 'oo') }, math),
snip('lim (sup|inf)', 'lim<> ', { cap(1) }, math),
snip('lim(_\\(\\s?\\w+\\s?->\\s?\\w+\\s?\\)) (sup|inf)', 'lim<><> ', { cap(2), cap(1) }, math),
}

View File

@@ -81,7 +81,7 @@ local smart_wrap = function(args, parent, old_state, expand)
end
for _, val in pairs(operations) do
table.insert(snippets, snip(val[1], '<>', { d(1, smart_wrap, {}, { user_args = { val } }) }, math, 1000, false))
table.insert(snippets, snip(val[1], '<>', { d(1, smart_wrap, {}, { user_args = { val } }) }, math, 1500, false))
end
return {

View File

@@ -46,6 +46,11 @@ function M.run_shell_command(cmd, show_output)
end
end
function M.count_string(str, tocount)
local _, count = str:gsub(tocount, '')
return count
end
function M.char_to_hex(c) return string.format('%%%02X', string.byte(c)) end
function M.urlencode(url)