forked from omer-faruq/assistant.koplugin
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathassistant_mdparser.lua
More file actions
192 lines (169 loc) · 6.85 KB
/
Copy pathassistant_mdparser.lua
File metadata and controls
192 lines (169 loc) · 6.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
-- markdown parser wrapper module
-- This module provides a simple interface to use hoedown (C binding of full features markdown)
-- or the pure Lua implementation of markdown.lua (building on KOReader)
local Parser = nil
local logger = require("logger")
local DataStorage = require("datastorage")
local Device = require("device")
local ffi = require("ffi")
local ffiutil = require("ffi/util")
local lfs = require("libs/libkoreader-lfs")
local util = require("util")
local plugin_lib_dir = DataStorage:getDataDir() .. "/plugins/assistant.koplugin/lib"
local LibHoedown = nil
-- Kindle stock firmware historically ships soft-float; hardfp devices expose
-- /lib/ld-linux-armhf.so.3 (same heuristic used by KOReader's kindle/device.lua).
local function isHardFP()
return util.pathExists("/lib/ld-linux-armhf.so.3")
end
-- Map the running device to a subdirectory of lib/ containing a compatible
-- libhoedown.so.3. libhoedown has very few dependencies, so a single ARMv7
-- soft-float build works on virtually any EABI5 environment, and the ARMv7
-- hard-float build loads on aarch64-linux hosts too.
-- ARM Linux float ABI is detected at runtime via /lib/ld-linux-armhf.so.3,
-- so any ARM e-reader (Kobo, Kindle, PocketBook, Remarkable, etc.) is handled
-- generically without per-device branches.
local function get_platform_libdir()
if Device:isDesktop() or Device:isEmulator() then
return "x86_64"
end
if Device:isAndroid() then
if util.stringStartsWith(jit.arch, "arm") then
return (jit.arch == "arm64") and "android_arm64" or "android_armv7a"
end
return nil
end
-- Generic ARM Linux: any e-reader with an ARM CPU picks the right float ABI.
if util.stringStartsWith(jit.arch, "arm") then
return isHardFP() and "armv7_hardfp" or "armv7_softfp"
end
return nil
end
-- On Android, plugins may live on external storage where dlopen() is not
-- allowed. Stage the .so into the app's internal plugins dir and return the
-- new path. Returns nil on failure.
local function stage_android_library(source_path)
local ok, android = pcall(require, "android")
if not ok or not android or not util.fileExists(source_path) then
return nil
end
local _, filename = util.splitFilePathName(source_path)
local target_dir = android.dir .. "/plugins/assistant.koplugin/lib"
local target_path = target_dir .. "/" .. filename
local mk_ok, mk_err = util.makePath(target_dir)
if not mk_ok then
logger.warn("Assistant: failed to create staging directory", mk_err)
return nil
end
local src_attr = lfs.attributes(source_path)
local dst_attr = lfs.attributes(target_path)
local needs_copy = not (src_attr and dst_attr
and src_attr.size == dst_attr.size
and src_attr.modification == dst_attr.modification)
if needs_copy then
local copy_err = ffiutil.copyFile(source_path, target_path)
if copy_err then
logger.warn("Assistant: failed to stage Android library", copy_err)
return nil
end
end
return target_path
end
-- check if hoedown is natively available
-- mostly it's unavailable on KOReader, but available on some other platforms
local ok, _lib = pcall(ffi.loadlib, "hoedown", 3)
if ok then LibHoedown = _lib end
-- check if hoedown is available in the plugin directory
-- in order to use native hoedown, a "lib" directory containing per-platform
-- "libhoedown.so.3" files and resty-hoedown should be present in the plugin
-- directory, see documents for more details
if not LibHoedown then
local libdir = get_platform_libdir()
if libdir then
local so_path = plugin_lib_dir .. "/" .. libdir .. "/libhoedown.so.3"
if Device:isAndroid() then
so_path = stage_android_library(so_path)
end
if so_path then
local load_ok, lib_or_err = pcall(ffi.load, so_path)
if load_ok then
LibHoedown = lib_or_err
logger.info("Assistant: loaded libhoedown from lib/" .. libdir)
else
logger.warn("Assistant: failed to load libhoedown.so.3", lib_or_err)
end
end
else
logger.info("Assistant: no prebuilt libhoedown.so.3 for this platform")
end
end
if LibHoedown then
-- hook the C binding of hoedown to the resty.hoedown library
package.preload["resty.hoedown.library"] = function()
return LibHoedown
end
-- load the resty.hoedown library from the plugin's libs directory
package.path = string.format("%s;%s/?.lua", package.path, plugin_lib_dir)
local ok, hoedownMD = pcall(require, "resty.hoedown")
if ok then
Parser = function (text)
return hoedownMD(text, {
rendered = "html",
nesting = 1,
extensions = {
"space_headers", "tables", "fenced_code", "footnotes", "autolink", "strikethrough",
"underline", "highlight", "quote", "superscript", "math", "math_explicit",
},
})
end
logger.info("Using hoedown (C binding) for markdown parsing")
end
end
-- Post-processor: convert pipe-table <p> blocks that luamd passes through
-- verbatim into proper <table> HTML that CRE can render.
-- Safe for hoedown too: hoedown already emits <table> tags, so no <p>|...|</p>
-- blocks will match and this becomes a no-op.
local function render_tables(html)
return (html:gsub("<p>([%s%S]-)</p>", function(block)
if not block:match("^%s*|") then
return nil
end
local rows = {}
for line in block:gmatch("[^\r\n]+") do
local trimmed = line:match("^%s*(.-)%s*$")
if trimmed ~= "" then
rows[#rows + 1] = trimmed
end
end
if #rows < 3 then return nil end
if not rows[2]:match("^|?[%s%-:|]+|$") then return nil end
local out = { "<table>" }
for i, row in ipairs(rows) do
if i == 2 then
-- skip separator row
else
local tag = (i == 1) and "th" or "td"
local inner = row:match("^|?(.+)|?$") or ""
out[#out + 1] = "<tr>"
for cell in (inner .. "|"):gmatch("(.-)|") do
local c = cell:match("^%s*(.-)%s*$")
if c ~= "" then
out[#out + 1] = string.format("<%s>%s</%s>", tag, c, tag)
end
end
out[#out + 1] = "</tr>"
end
end
out[#out + 1] = "</table>"
return table.concat(out)
end))
end
-- fallback to pure Lua implementation
if not Parser then
local puremd = require("apps/filemanager/lib/md")
Parser = function(text)
return render_tables(puremd(text))
end
logger.info("Using markdown.lua (puremd) for markdown parsing")
end
return Parser