├── readme.md └── latexrender.lua /readme.md: -------------------------------------------------------------------------------- 1 | ## Whatisit ? 2 | A way to have Latex rendered inside nvim 3 | 4 | ## Example 5 | ![fig](https://user-images.githubusercontent.com/58146965/224890491-c4fbb91e-f366-4790-994d-87bf51bba7ee.png) 6 | 7 | 8 | ## Requirements 9 | * Requires [hologram.nvim](https://github.com/edluffy/hologram.nvim) setup. 10 | * Only works in [kitty](https://sw.kovidgoyal.net/kitty/) 11 | * You must have texlive with `dvipng` binary on your system. 12 | if you're on Arch , [texlive-bin](https://archlinux.org/packages/extra/x86_64/texlive-bin/) should suffice 13 | * Only works on linux (ymmv on mac , and erm Windows) 14 | 15 | ## How to use ? 16 | 17 | ### Install 18 | It's fairly bairbones as of now , 19 | copy latexrenderer.lua into your computer and load it 20 | with `luafile /path/to/latexrenderer.lua` in your init.vim . 21 | 22 | I'll (hopefully) make this a plugin someday , but for now i'm mostly trying 23 | out things for myself. 24 | 25 | ### Render all math 26 | If succesfully loaded you should have two commands 27 | `RenderLatex ` , which will scan through your buffer, 28 | treating everything between pairs of `$$` as Latex and render it below that line ( does not support inline math), `` specifies the size of the png to render 29 | 30 | ### Render math at cursor 31 | If the cursor is at an equation you can render the current equation only with `RenderLatexAtCursor `. 32 | 33 | ### Remove all renderings 34 | `RemoveLatex` will remove the rendered pngs 35 | 36 | ## Bugs 37 | For some reason the math cant be the first or the last line :( , 38 | 39 | ## Misc 40 | Colors are hardcoded (for fg of gruvbox dark) , you can change it in the line (`-fg 'cmyk 0.00 0.04 0.21 0.02'`) where dvipng is called. 41 | -------------------------------------------------------------------------------- /latexrender.lua: -------------------------------------------------------------------------------- 1 | local vim = vim 2 | 3 | function printtable(t) 4 | --for debug 5 | for k,v in pairs(t) do 6 | print(k,v) 7 | end 8 | end 9 | 10 | function counttable(t) 11 | --returns number of elements in table 12 | count=0 13 | for _ in pairs(t) do 14 | count=count+1 15 | end 16 | return count 17 | end 18 | 19 | local random = math.random 20 | math.randomseed(os.time()) 21 | local function uuid() 22 | local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' 23 | return string.gsub(template, '[xy]', function (c) 24 | local v = (c == 'x') and random(0, 0xf) or random(8, 0xb) 25 | return string.format('%x', v) 26 | end) 27 | end 28 | 29 | 30 | function find_equations() 31 | --returns a list , every element of list is table {lno,cno} pair 32 | lines = vim.api.nvim_buf_get_lines(0,0,-1,false) 33 | positions = {} 34 | -- read through all of them 35 | for lno,line in pairs(lines) do 36 | st = 1 37 | while true do 38 | local x,y=string.find(line,"$$",st,true) 39 | if x==nil then break end 40 | table.insert(positions,{lno,x}) 41 | st=y+1 42 | end 43 | end 44 | if (counttable(positions)%2)~=0 then 45 | print("unmatched $$") 46 | end 47 | return positions 48 | end 49 | 50 | function iszeropos(pos) 51 | return (pos[1] == 0 and pos[2] == 0) 52 | end 53 | 54 | function latex_topng(fnames,size) 55 | --renders the latex as png's in /tmp 56 | latexjobids = {} 57 | dvijobids = {} 58 | for k,fname in pairs(fnames) do 59 | jobid = vim.fn.jobstart("latex --interaction=nonstopmode --output-dir=/tmp --output-format=dvi LATEXFILE" .. fname, {cwd="/tmp",on_stdout = function (j,d,e) print() end,on_stderr=function (j,d,e) print() end}) 60 | table.insert(latexjobids,jobid) 61 | end 62 | vim.fn.jobwait(latexjobids) 63 | for k,fname in pairs(fnames) do 64 | jobid = vim.fn.jobstart("dvipng -D "..tonumber(size).. " -T tight -bg Transparent -fg 'cmyk 0.00 0.04 0.21 0.02' -o /tmp/LATEXFILE"..fname..".png".." ".."/tmp/LATEXFILE"..fname..".dvi",{cwd="/tmp",on_stdout = function (j,d,e) print() end}) 65 | table.insert(dvijobids,jobid) 66 | end 67 | vim.fn.jobwait(dvijobids) 68 | end 69 | 70 | function get_lstrings(positions) 71 | --gets list os strings between positions 72 | --positions is a list of pairs of lno,cno (lineno , columno) 73 | lstrings = {} 74 | for i=1,counttable(positions),2 do 75 | lstring = "" 76 | start = positions[i] 77 | stop = positions[i+1] 78 | for k,v in pairs(vim.api.nvim_buf_get_text(0,start[1]-1,start[2]+1,stop[1]-1,stop[2]-1,{nil})) do 79 | lstring = lstring .. v 80 | end 81 | table.insert(lstrings,lstring) 82 | end 83 | return lstrings 84 | end 85 | local pre = "\\documentclass[12pt]{standalone}\n \\usepackage{amsmath}\n \\usepackage{amssymb} \n \\begin{document}\n \\begin{align} " 86 | local post = "\\end{align} \n \\end{document}" 87 | 88 | function write_texfiles(lstrings) 89 | fnames = {} 90 | for k,v in pairs(lstrings) do 91 | fname = uuid() 92 | filehandle = io.open("/tmp/LATEXFILE"..fname, "w") 93 | filehandle:write(pre..v.."\n"..post) 94 | filehandle:close() 95 | table.insert(fnames,fname) 96 | end 97 | return fnames 98 | end 99 | 100 | local imgs = {} 101 | function insertpngs(eqpos,fnames,size) 102 | findex = 1 103 | for i=1,counttable(eqpos),2 do 104 | source = "/tmp/LATEXFILE"..fnames[findex]..".png" 105 | buf = vim.api.nvim_get_current_buf() 106 | table.insert(imgs,require('hologram.image'):new(source, {})) 107 | imgs[findex]:display(eqpos[i+1][1], 0, buf, {}) 108 | findex = findex+1 109 | end 110 | end 111 | 112 | function RenderLatex(opts) 113 | RemoveLatex() 114 | eqpos = find_equations() 115 | lstrings = get_lstrings(eqpos) 116 | fnames = write_texfiles(lstrings) 117 | latex_topng(fnames,opts.fargs[1]) 118 | insertpngs(eqpos,fnames) 119 | end 120 | 121 | function inbetween(curpos,pos1,pos2) 122 | --checks if curpos is b/w pos1 and pos2 123 | --assumes pos2 isafter pos1 124 | if pos1[1]==pos2[1] then 125 | --is pos1 and pos2 on same line, check column 126 | if curpos[1]==pos1[1] and pos1[2]