File: prettify.lua

package info (click to toggle)
lua-ldoc 1.5.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 928 kB
  • sloc: makefile: 63; ansic: 56
file content (150 lines) | stat: -rw-r--r-- 3,982 bytes parent folder | download
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
-- Making Lua source code look pretty.
-- A simple scanner based prettifier, which scans comments for @{ref} and code
-- for known modules and functions.
-- A module reference to an example `test-fun.lua` would look like
-- `@{example:test-fun}`.
local List = require 'pl.List'
local tablex = require 'pl.tablex'
local globals = require 'ldoc.builtin.globals'
local prettify = {}

local user_keywords = {}

local function_arg_delimiters = {
   ['('] = true,
   ['{'] = true,
   ['"'] = true,
   ["'"] = true
}

local escaped_chars = {
   ['&'] = '&',
   ['<'] = '&lt;',
   ['>'] = '&gt;',
}
local escape_pat = '[&<>]'

local function escape(str)
   return (str:gsub(escape_pat,escaped_chars))
end

local function span(t,val)
   return ('<span class="%s">%s</span>'):format(t,val)
end

local spans = {keyword=true,number=true,string=true,comment=true,global=true,backtick=true}

local cpp_lang = {C = true, c = true, cpp = true, cxx = true, h = true}

function prettify.lua (lang, fname, code, initial_lineno, pre, linenos)
   local res, lexer = List(), require 'ldoc.lexer'
   local tokenizer
   local ik = 1
   if not cpp_lang[lang] then
      tokenizer = lexer.lua
   else
      tokenizer = lexer.cpp
   end

   if pre then
      res:append '<pre>\n'
   end
   initial_lineno = initial_lineno or 0

   local tok = tokenizer(code,{},{})
   local error_reporter = {
      warning = function (self,msg)
         io.stderr:write(fname..':'..tok:lineno()+initial_lineno..': '..msg,'\n')
      end
   }
   local last_t, last_val
   local last_non_space_idx, last_non_space_t, last_non_space_val
   local t,val = tok()
   if not t then return nil,"empty file" end
   while t do
      val = escape(val)
      if linenos and tok:lineno() == linenos[ik] then
         res:append('<a id="'..linenos[ik]..'"></a>')
         ik = ik + 1
      end

      if globals.functions[val] or globals.tables[val] then
         t = 'global'
      end
      if user_keywords[val] then
         res:append(span('user-keyword keyword-' .. val,val))
      elseif spans[t] then
         if t == 'comment' or t == 'backtick' then -- may contain @{ref} or `..`
            val = prettify.resolve_inline_references(val,error_reporter)
         end
         res:append(span(t,val))
      else
         res:append(val)
      end

      if (t == 'string' or function_arg_delimiters[val]) and last_non_space_t == 'iden' then
         res[last_non_space_idx] = span('function-name',last_non_space_val)
      end
      if t ~= 'space' then
          -- don't replace user-keywords with function-name:
          last_non_space_t = user_keywords[val] and 'keyword' or t
          last_non_space_idx = #res
          last_non_space_val = val
      end

      last_t, last_val = t,val
      t,val = tok()
   end
   if last_t == 'comment' then
      res[#res] = span('comment',last_val:gsub('\r*\n$',''))
   end
   local last = res[#res]
   if last:match '\n$' then
      res[#res] = last:gsub('\n+','')
   end
   if pre then
      res:append '</pre>\n'
   end
   return res:join ()
end

local lxsh

local lxsh_highlighers = {bib=true,c=true,lua=true,sh=true}

function prettify.code (lang,fname,code,initial_lineno,pre)
   if not lxsh then
      return prettify.lua (lang,fname, code, initial_lineno, pre)
   else
      if not lxsh_highlighers[lang] then
         lang = 'lua'
      end
      code = lxsh.highlighters[lang](code, {
         formatter = lxsh.formatters.html,
         external = true
      })
      if not pre then
         code = code:gsub("^<pre.->(.-)%s*</pre>$", '%1')
      end
      return code
   end
end

function prettify.set_prettifier (pretty)
   local ok
   if pretty == 'lxsh' then
      ok,lxsh = pcall(require,'lxsh')
      if not ok then
         print('pretty: '..pretty..' not found, using built-in Lua')
         lxsh = nil
      end
   end
end

function prettify.set_user_keywords(keywords)
  if keywords then
    user_keywords = tablex.makeset(keywords)
  end
end

return prettify