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
)
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*(.*)$")
22 -- use <small> to improve chance that wide ascii art will fit
24 return "<small><pre>", false
27 return "</pre></small>", false
31 return util
.htmlEscape(line
), false
34 if line
:match("^%s*$") then
39 link
= line
:match('^=>%s*([^%s]+)%s*$')
41 link
,desc
= line
:match('^=>%s*([^%s]+)%s+(.+)$')
44 local purl
= url
.parse(link
)
46 desc
= util
.htmlEscape(desc
)
47 if purl
.scheme
and purl
.scheme
~= "gemini" then
48 desc
= desc
.. T(" <em>[%1]</em>", purl
.scheme
)
50 return '<li><a href="' .. link
.. '">' .. desc
.. '</a></li>', true
54 headers
,text
= line
:match('^(#+)%s*(.*)$')
56 local level
= headers
:len()
58 return "<h" .. level
.. ">" .. util
.htmlEscape(text
) .. "</h" .. level
.. ">", false
62 text
= line
:match("^%*%s+(.*)$")
64 return "<li>" .. util
.htmlEscape(text
) .. "</li>", true
67 text
= line
:match('^>(.*)$')
69 return "<blockquote>" .. util
.htmlEscape(text
) .. "</blockquote>", true
72 return "<p>" .. util
.htmlEscape(line
) .. "</p>"
76 -- Override css to not require page breaks on headers,
77 -- and improve contrast for links.
81 page-break-before: auto;
84 text-decoration: underline; color: #505050;
91 local written_line
= false
92 for line
in i
:lines() do
93 line
, list
= parseLine(line
)
94 if list
and not in_list
then
96 elseif in_list
and not list
then
97 line
= "</ul>\n" .. line
100 o
:write(line
.. "\n")
104 if not written_line
then
105 -- work around CRE not rendering empty html documents properly
106 o
:write(_("[Empty gemini document]\n"))
108 o
:write("</body></html>")
111 function GeminiDocument
:init()
112 local tmpname = os
.tmpname()
113 if util
.fileExists(tmpname) then
114 local ok
, err
= os
.rename(tmpname, tmpname .. ".html")
116 error(T(_("Error on moving tmpfile: %1"), err
))
119 self
.tmp_html_file
= tmpname .. ".html"
120 local i
= io
.open(self
.file
, "r")
121 local o
= io
.open(self
.tmp_html_file
, "w")
124 local gemfile
= self
.file
125 self
.file
= self
.tmp_html_file
126 CreDocument
.init(self
)
129 -- XXX: hack; uses that only these methods read self.file
130 for _i
,method
in ipairs({"loadDocument","getNativePageDimensions","_readMetadata","getFullPageHash","renderPage"}) do
131 self
[method
] = function(slf
, ...)
132 slf
.file
= slf
.tmp_html_file
133 local ok
, re
= pcall(CreDocument
[method
], slf
, ...)
138 logger
.err("wrapped credocument call failed", method
, re
)
145 function GeminiDocument
:close()
146 CreDocument
.close(self
)
147 FileManager
:deleteFile(self
.tmp_html_file
, true)
150 return GeminiDocument