summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/lualatex/luahttp/luahttp-display.lua
blob: 1a41cfb22ca793da575fdf4d5b36e53b4f9d34b2 (plain)
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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
--[[
-- This module is part of the LuaHTTP package
-- The purpose of this module is to correctly display the data reveived from the fetch module.
]]

local moduleName = display
local M = {}

---------- Dependencies ------------------------
local fetch = require("luahttp-fetch")

---------- Local variables ---------------------
local tmp_image_counter = 0 -- Counter for image names

---------- Helper functions --------------------

--- Displays an image using LuaTeX img.write function.
-- The image has to be saved first in order to be written to the PDF-Document using LuaTeX.
-- @param data image data
-- @param width optional width in cm
-- @param height optional height in cm
-- @see search_and_escape
local function display_image(data, width, height)
    local tmp_image_name = '/tmp/tmp_image' -- filename of image saved temporarly
    tmp_image_name = tmp_image_name .. tmp_image_counter

    local width = width or nil
    local height = height or nil
    local f = assert(io.open(tmp_image_name, 'wb'))
    f:write(data)
    f:close()

    -- LuaTeX does not provide built-in image scaling functions
    local image = img.new({filename = tmp_image_name, width = width, height = height})
    if image then
        img.write(image)
        tmp_image_counter = tmp_image_counter + 1
    end
end

--- Prompts the user to display an image.
-- If an image-URL is detected the user is asked to display the image or the plain URL.
-- @see is_image_url
local function prompt_user()
    while true do
        print("Do you want to display the image? (y/n)")
        local answer = io.read()

        if answer == 'y' then
            return true
        elseif answer == 'n' then
            return false
        else
            print("Invalid answer. Please enter 'y' or 'n'.")
        end
    end
end

--- Searches the given URL for image extensions.
-- @param url some URL
-- @return true if an image extension was found, false otherwise
-- @see search_and_escape
local function is_image_url(url)
    local image_extensions = { "jpg", "jpeg", "png", "gif" }
    for _, ext in ipairs(image_extensions) do
        if string.match(url, "%." .. ext) then
            return true
        end
    end
    return false
end

--- Searches the given value for special characters that cause problems in LaTeX-Documents.
-- @param value single value of a table
-- @return if no special characters where found the value is retured unchanged,
-- if special characters where found the escaped value is returned,
-- if an image-URL is detected and the user chooses to display that image nil is returned
-- @see is_image_url, prompt_user
local function search_and_escape(value)
    local value = tostring(value)
    if string.find(value, "^http") then
        if is_image_url(value) then
            print("\nLooks like this URL leads to an image: " .. value)
            if prompt_user() then
                local body = fetch.image(value)
                display_image(body, "5cm")
                return nil
            else
                print("\nEscaping URL: " .. value)
                value = [[\url{]] .. value .. [[}]]
            end
        else
            print("\nEscaping URL: " .. value)
            value = [[\url{]] .. value .. [[}]]
        end
    else
        local latex_special_chars = '([%%$%{%}&%#_%^%~])'
        value = value:gsub(latex_special_chars, "\\%1")
    end
    return value
end

--- Prints a table to stdout.
-- @param t tagle to print
-- @param indent optional string used for indents
local function print_table(t, indent)
    indent = indent or ""
    for k, v in pairs(t) do
        if type(v) == "table" then
            print(indent .. k .. ":")
            print_table(v, indent .. "  ")
        else
            print(indent .. k .. ": " .. tostring(v))
        end
    end
end

--- Converts a table to text which can be written to the PDF-Document
-- The values of the table are first searched for special characters.
-- @param tbl table to be converted
-- @return text
-- @see search_and_escape
local function table_to_text(tbl)
    local results = {}
    for k, v in pairs(tbl) do
        if type(v) == "table" then
            table.insert(results, table_to_text(v))
        else
            v = search_and_escape(v)
            if v then
                table.insert(results, v .. " \\\\ ")
            end
        end
    end
    return table.concat(results, " \\ ")
end

--- Check if a table contains a certain value.
-- @param table input table
-- @param target_value value to be searched
-- @return true if value was found, false otherwise
local function table_contains(table, target_value)
    for _, value in pairs(table) do
        if type(value) == "table" then
            table_contains(value, target_value)
        elseif value == target_value then
            return true
        end
    end
    return false
end

--- Filter out table entries that are not in the provided target keys.
-- @param input_table
-- @param target_keys array of target keys
-- @param results used for recursion
-- @return return a new table containing only the target keys and their values
local function filter_table(input_table, target_keys, results)
    local results = results or {}

    for _, target_key in ipairs(target_keys) do
        for key, value in pairs(input_table) do
            if type(value) == "table" then
                filter_table(value, target_keys, results)
            elseif tostring(key) == target_key then
                if not table_contains(results, value) then
                    table.insert(results, value)
                    break
                end
            end
        end
    end
    return results
end

--- Converts a string containing a comma seperated list of elements to an array (ipairs).
-- @param str input string
-- @return table containing the elements as values
local function string_to_ipairs(str)
    local t = {}
    for value in string.gmatch(str, "([^,]+)") do
        table.insert(t, value)
    end
    return t
end

---------- Module functions --------------------

--- Reads the contents of a JSON-file, filters the response and prints the result to the PDF-Document.
-- @param json_file_path path to the JSON-file
-- @param keys optional keys to filter out the relevant values from the response
function M.json_using_file(json_file_path, keys)
    local data = fetch.json_using_file(json_file_path)
    print_table(data)
    if keys then
        local keys = string_to_ipairs(tostring(keys))
        local values = filter_table(data, keys)
        tex.sprint(table_to_text(values))
    else
        tex.sprint(table_to_text(data))
    end
end

--- Prints the response filtered by the keys to the PDF-Document.
-- @param url URL of the API
-- @param keys optional keys to filter out the relevant values from the response
function M.json(url, keys)
    local data = fetch.json(tostring(url))
    print_table(data)
    if keys then
        local keys = string_to_ipairs(tostring(keys))
        local values = filter_table(data, keys)
        tex.sprint(table_to_text(values))
    else
        tex.sprint(table_to_text(data))
    end
end

--- Print an image to the PDF-Document.
-- @param url URL of the image
-- @param width optional width in cm
-- @param height optional height in cm
function M.image(url, width, height)
    local data = fetch.image(tostring(url))
    display_image(data, width, height)
end

--- Print values from an rss-feed to the PDF-Document.
-- @param url URL of the feed
-- @param limit limits the amount of entries that get printed to the PDF-Document
-- @param feed_info_keys keys used to filter the feed information
-- @param entry_keys keys used to filter the feed entries
function M.rss(url, limit, feed_info_keys, entry_keys)
    local data = fetch.rss(tostring(url))

    if feed_info_keys then
        local feed_info_keys = string_to_ipairs(tostring(feed_info_keys))
        local feed = data.feed
        local feed_info_filtered = filter_table(feed, feed_info_keys)

        tex.sprint(table_to_text(feed_info_filtered))
    end

    local entries = {}

    for i = 1, limit do
        if data.entries[i] then
            table.insert(entries, data.entries[i])
        end
    end

    if entry_keys then
        local entry_keys = string_to_ipairs(tostring(entry_keys))
        local entries_filtered = filter_table(entries, entry_keys)

        print_table(entries_filtered)
        tex.sprint(table_to_text(entries_filtered))
    else
        tex.sprint(table_to_text(entries))
    end
end

--- Print the reponse from a request using query parameters to the PDF-Document.
-- @param url URL of the API
-- @param keys keys to filter out the relevant values
-- @param ... multiple optional query parameters used in the request
function M.json_using_query(url, keys, ...)
    local query_parameters = { ... }
    local data = fetch.json_using_query(url, query_parameters)

    print_table(data)

    local keys = string_to_ipairs(tostring(keys))
    local values = filter_table(data, keys)
    tex.sprint(table_to_text(values))
end

return M