markdown icon indicating copy to clipboard operation
markdown copied to clipboard

Implement the `witiko/graphicx/http` LaTeX user theme in Lua

Open Witiko opened this issue 3 years ago • 0 comments

Since version 2.10.0, the Markdown package has supported the witiko/graphicx/http theme. Currently, the witiko/graphicx/http LaTeX user theme requires shell access and either GNU Wget or cURL to download images, which reduces security and portability. At BachoTeX 2017, Hans Hagen suggested to use the Luasocket library, which would solve both problems. An example implementation is as follows:

\ProvidesPackage{markdownthemewitiko_graphicx_http}[2021/03/22]%
\RequirePackage{catchfile}
\let\markdown@witiko@graphicx@http@oldRendererImagePrototype
  \markdownRendererImagePrototype
\newcount\markdown@witiko@graphicx@http@counter
\markdown@witiko@graphicx@http@counter=0
\newcommand\markdown@witiko@graphicx@http@filename{%
  \markdownOptionCacheDir/witiko_graphicx_http%
  .\the\markdown@witiko@graphicx@http@counter}%
\begingroup
\catcode`\%=12
\catcode`\^^A=14
\global\def\markdownRendererImagePrototype#1#2#3#4{^^A
  \begingroup
    \edef\filename{\markdown@witiko@graphicx@http@filename}^^A
    \markdownIfOption{FrozenCache}{}{^^A
      \directlua{
        local url = "#3"
        local filename = "\filename"
        if string.match(url, "^https?:") then
          local md5 = require("md5")
          local output_prefix = "\markdownOptionCacheDir"
          local output_body = md5.sumhexa(url)
          local output_suffix = string.match(url, "%.[^.]*$")
          local output = output_prefix .. "/"
                      .. output_body .. output_suffix
          local output_file = io.open(output, "r")
          if output_file == nil then
            local http = require("socket.http")
            local result, status, headers = http.request(url)
            if result == nil then
              os.remove(filename)
            else
              output_file = assert(io.open(output, "w"))
              assert(output_file:write(result))
              assert(output_file:close())
              file = assert(io.open(filename, "w"))
              assert(file:write(output))
              assert(file:close())
            end
          end
        else
          file = assert(io.open(filename, "w"))
          assert(file:write(url))
          assert(file:close())
        end
      }}^^A
    \CatchFileDef{\filename}{\filename}{}^^A
    \markdown@witiko@graphicx@http@oldRendererImagePrototype^^A
      {#1}{#2}{\filename}{#4}^^A
  \endgroup
  \global\advance\markdown@witiko@graphicx@http@counter by 1\relax}^^A
\endgroup
\endinput
%%
%% End of file `markdownthemewitiko_graphicx_http.sty'.

Here are the issues with the implementation:

  1. The http.request function does not handle redirects well. For example, it is unable to resolve the URL https://github.com/witiko/markdown/raw/master/banner.png and will always return the 301 HTTP code. Both GNU Wget and cURL can correctly resolve redirects.
  2. The \directlua command is unavailable outside LuaTeX. We would like to use an equivalent of the \markdownLuaExecute command that would not produce any output. Instead, it would just run the Lua code, either using \directlua, or by executing texlua in shell. We can easily solve this one.

Witiko avatar Jun 26 '21 23:06 Witiko