aboutsummaryrefslogtreecommitdiff
path: root/_extensions/quarto-ext/include-code-files/include-code-files.lua
blob: c74aa536a36a8f49482a7226b43ef6430cc02bc9 (plain)
  1. --- include-code-files.lua – filter to include code from source files
  2. ---
  3. --- Copyright: © 2020 Bruno BEAUFILS
  4. --- License: MIT – see LICENSE file for details
  5. --- Dedent a line
  6. local function dedent(line, n)
  7. return line:sub(1, n):gsub(" ", "") .. line:sub(n + 1)
  8. end
  9. --- Find snippet start and end.
  10. --
  11. -- Use this to populate startline and endline.
  12. -- This should work like pandocs snippet functionality: https://github.com/owickstrom/pandoc-include-code/tree/master
  13. local function snippet(cb, fh)
  14. if not cb.attributes.snippet then
  15. return
  16. end
  17. -- Cannot capture enum: http://lua-users.org/wiki/PatternsTutorial
  18. local comment
  19. local comment_stop = ""
  20. if
  21. string.match(cb.attributes.include, ".py$")
  22. or string.match(cb.attributes.include, ".jl$")
  23. or string.match(cb.attributes.include, ".r$")
  24. then
  25. comment = "#"
  26. elseif string.match(cb.attributes.include, ".o?js$") or string.match(cb.attributes.include, ".css$") then
  27. comment = "//"
  28. elseif string.match(cb.attributes.include, ".lua$") then
  29. comment = "--"
  30. elseif string.match(cb.attributes.include, ".html$") then
  31. comment = "<!%-%-"
  32. comment_stop = " *%-%->"
  33. else
  34. -- If not known assume that it is something one or two long and not alphanumeric.
  35. comment = "%W%W?"
  36. end
  37. local p_start = string.format("^ *%s start snippet %s%s", comment, cb.attributes.snippet, comment_stop)
  38. local p_stop = string.format("^ *%s end snippet %s%s", comment, cb.attributes.snippet, comment_stop)
  39. local start, stop = nil, nil
  40. -- Cannot use pairs.
  41. local line_no = 1
  42. for line in fh:lines() do
  43. if start == nil then
  44. if string.match(line, p_start) then
  45. start = line_no + 1
  46. end
  47. elseif stop == nil then
  48. if string.match(line, p_stop) then
  49. stop = line_no - 1
  50. end
  51. else
  52. break
  53. end
  54. line_no = line_no + 1
  55. end
  56. -- Reset so nothing is broken later on.
  57. fh:seek("set")
  58. -- If start and stop not found, just continue
  59. if start == nil or stop == nil then
  60. return nil
  61. end
  62. cb.attributes.startLine = tostring(start)
  63. cb.attributes.endLine = tostring(stop)
  64. end
  65. --- Filter function for code blocks
  66. local function transclude(cb)
  67. if cb.attributes.include then
  68. local content = ""
  69. local fh = io.open(cb.attributes.include)
  70. if not fh then
  71. io.stderr:write("Cannot open file " .. cb.attributes.include .. " | Skipping includes\n")
  72. else
  73. local number = 1
  74. local start = 1
  75. -- change hyphenated attributes to PascalCase
  76. for i, pascal in pairs({ "startLine", "endLine" }) do
  77. local hyphen = pascal:gsub("%u", "-%0"):lower()
  78. if cb.attributes[hyphen] then
  79. cb.attributes[pascal] = cb.attributes[hyphen]
  80. cb.attributes[hyphen] = nil
  81. end
  82. end
  83. -- Overwrite startLine and stopLine with the snippet if any.
  84. snippet(cb, fh)
  85. if cb.attributes.startLine then
  86. cb.attributes.startFrom = cb.attributes.startLine
  87. start = tonumber(cb.attributes.startLine)
  88. end
  89. for line in fh:lines("L") do
  90. if cb.attributes.dedent then
  91. line = dedent(line, cb.attributes.dedent)
  92. end
  93. if number >= start then
  94. if not cb.attributes.endLine or number <= tonumber(cb.attributes.endLine) then
  95. content = content .. line
  96. end
  97. end
  98. number = number + 1
  99. end
  100. fh:close()
  101. end
  102. -- remove key-value pair for used keys
  103. cb.attributes.include = nil
  104. cb.attributes.startLine = nil
  105. cb.attributes.endLine = nil
  106. cb.attributes.dedent = nil
  107. -- return final code block
  108. return pandoc.CodeBlock(content, cb.attr)
  109. end
  110. end
  111. return {
  112. { CodeBlock = transclude },
  113. }