purge history file on overwrite
[gemini.koplugin.git] / geminidocument.lua
blob7a26de952450de8ba9f90b70f3db3bccf328d40e
1 local CreDocument = require("document/credocument")
2 local FileManager = require("apps/filemanager/filemanager")
3 local url = require("socket.url")
4 local util = require("util")
5 local logger = require("logger")
6 local _ = require("gettext")
7 local T = require("ffi/util").template
9 local GeminiDocument = CreDocument:extend{}
11 local function convertGmi(i, o)
12 local pre = false
13 local function parseLine(line)
14 -- strip ANSI CSI sequences (used in some gemtext documents for
15 -- colour, which we do not try to support)
16 line = line:gsub("%\x1b%[[ -?]*[@-~]","")
18 local alt = line:match("^```%s*(.*)$")
19 if alt then
20 if not pre then
21 pre = true
22 -- use <small> to improve chance that wide ascii art will fit
23 -- on the screen
24 return "<small><pre>", false
25 else
26 pre = false
27 return "</pre></small>", false
28 end
29 end
30 if pre then
31 return util.htmlEscape(line), false
32 end
34 if line:match("^%s*$") then
35 return "<br/>", false
36 end
38 local link, desc
39 link = line:match('^=>%s*([^%s]+)%s*$')
40 if not link then
41 link,desc = line:match('^=>%s*([^%s]+)%s+(.+)$')
42 end
43 if link then
44 local purl = url.parse(link)
45 desc = desc or link
46 desc = util.htmlEscape(desc)
47 if purl.scheme and purl.scheme ~= "gemini" then
48 desc = desc .. T(" <em>[%1]</em>", purl.scheme)
49 end
50 return '<li><a href="' .. link .. '">' .. desc .. '</a></li>', true
51 end
53 local headers, text
54 headers,text = line:match('^(#+)%s*(.*)$')
55 if headers then
56 local level = headers:len()
57 if level <= 3 then
58 -- Avoid <h1> for level 1 headings, because it causes a
59 -- newpage in the default stylesheet epub.css
60 return "<h" .. level + 1 .. ">" .. util.htmlEscape(text) .. "</h" .. level .. ">", false
61 end
62 end
64 text = line:match("^%*%s+(.*)$")
65 if text then
66 return "<li>" .. util.htmlEscape(text) .. "</li>", true
67 end
69 text = line:match('^>(.*)$')
70 if text then
71 return "<blockquote>" .. util.htmlEscape(text) .. "</blockquote>", true
72 end
74 return "<p>" .. util.htmlEscape(line) .. "</p>"
75 end
77 o:write("<html><body>\n")
78 local in_list = false
79 local list
80 local written_line = false
81 for line in i:lines() do
82 line, list = parseLine(line)
83 if list and not in_list then
84 line = "<ul>" .. line
85 elseif in_list and not list then
86 line = "</ul>\n" .. line
87 end
88 in_list = list
89 o:write(line .. "\n")
90 written_line = true
91 end
92 i:close()
93 if not written_line then
94 -- work around CRE not rendering empty html documents properly
95 o:write(_("[Empty gemini document]\n"))
96 end
97 o:write("</body></html>")
98 end
100 function GeminiDocument:init()
101 self.tmp_html_file = os.tmpname() .. ".html"
102 if not self.tmp_html_file then
103 error(_("Failed to create temporary file for gmi -> html conversion."))
105 local i = io.open(self.file, "r")
106 local o = io.open(self.tmp_html_file, "w")
107 convertGmi(i, o)
108 o:close()
109 local gemfile = self.file
110 self.file = self.tmp_html_file
111 CreDocument.init(self)
112 self.file = gemfile
114 -- XXX: hack; uses that only these methods read self.file
115 for _i,method in ipairs({"loadDocument","getNativePageDimensions","_readMetadata","getFullPageHash","renderPage"}) do
116 self[method] = function(slf, ...)
117 slf.file = slf.tmp_html_file
118 local ok, re = pcall(CreDocument[method], slf, ...)
119 slf.file = gemfile
120 if ok then
121 return re
122 else
123 logger.err("wrapped credocument call failed", method, re)
124 return false
130 function GeminiDocument:close()
131 CreDocument.close(self)
132 FileManager:deleteFile(self.tmp_html_file, true)
135 return GeminiDocument