Codebase list lua-ldoc / 7fcf20d
Merge tag '1.4.2' 1.4 release LR Julian Wollrath 10 years ago
27 changed file(s) with 3089 addition(s) and 1809 deletion(s). Raw diff Collapse all Expand all
0 ## Version 1.4.2
1
2 ### Features
3
4 * Can define fields/properties of objects; `readonly` modifier supported (#93)
5 * Can switch off auto-linking to Lua manual with `no_lua_ref`
6 * Module sorting is off by default, use `sort_modules=true`
7 * References to 'classes' now work properly
8 * Option to use first Markdown title instead of file names with `use_markdown_titles`
9 * Automatic `Metamethods` and `Methods` sections generated for `classmod` classes
10 * `unqualified=true` to strip package names on sidebar (#110)
11 * Custom tags (which may be hidden)
12 * Custom Display Name handlers
13
14 ### Fixes
15
16 * stricter about doc comments, now excludes common '----- XXXXX ----' pattern
17 * no longer expects space after `##` in Markdown (#96)
18 * Section lookup was broken
19 * With `export` tag, decide whether method is static or not
20 * `classmod` classes now respect custom sections (#113)
21 * Minor issues with prettification
22 * Command-line flags set explicitly take precendence over configuration file values.
23 * Boilerplate Lua block comment ignored properly (#137)
24 * Inline links with underscores sorted (#22)
25 * Info section ordering is now consistent (#150)
26
27 ## Version 1.4.0
28
29 ### Features
30
31 * `sort=true` to sort items within sections alphabetically
32 * `@set` tag in module comments; e.g, can say `@set sort=true`
33 * `@classmod` tag for defining modules that export one class
34 * can generate Markdown output
35 * Can prettify C as well as Lua code with built-in prettifier
36 * lfs and lpeg references understood
37 * 'pale' template available
38 * multiple return groups
39 * experimental `@error` tag
40 * Moonscript and plain C support
41
42
43 ### Fixes
44
45 * works with non-compatibily Lua 5.2, including `markdown.lua`
46 * module names can not be types
47 * all `builtin` Lua files are requirable without `module`
48 * backticks expand in copyright and other 'info' tabs
49 * `-m` tries harder to resolve methods
50 * auto-scroll in navigation area to avoid breaking identifiers
51 * better error message for non-luadoc-compatible behaviour
52 * custom see references fixed
53
54
55
+0
-7
config.ld less more
0 project='LDoc'
1 title='LDoc documentation'
2 description='A Lua documentation tool'
3 format='discount'
4 file='ldoc.lua'
5 dir='out'
6 readme='doc/doc.md'
55 file='../ldoc.lua'
66 dir='../out'
77 readme='doc.md'
8 examples = {'../tests/styles/colon.lua','../tests/styles/four.lua','../tests/example/mylib.c'}
8 style='!pale'
9 kind_names={topic='Manual',script='Programs'}
10 examples = {
11 '../tests/styles/colon.lua',
12 '../tests/styles/four.lua',
13 '../tests/styles/three.lua',
14 '../tests/styles/multiple.lua',
15 '../tests/example/mylib.c',
16 '../tests/moonscript/List.moon',
17 }
918
33
44 ## Introduction
55
6 LDoc is a second-generation documentation tool that can be used as a replacement for
7 [LuaDoc](http://keplerproject.github.com/luadoc/). It arose out of my need to document my
8 own projects and only depends on the [Penlight](https://github.com/stevedonovan/Penlight)
9 libraries.
10
11 It is mostly compatible with LuaDoc, except that certain workarounds are no longer needed.
6 LDoc is a software documentation tool which automatically generates API documentation
7 out of source code comments (doc comments). It is mainly targeted at Lua and documenting
8 Lua APIs, but it can also parse C with according doc comments for documenting Lua modules
9 implemented in C.
10
11 It is mostly compatible with [LuaDoc](http://keplerproject.github.com/luadoc/),
12 except that certain workarounds are no longer needed.
1213 For instance, it is not so married to the idea that Lua modules should be defined using the
1314 `module` function; this is not only a matter of taste since this has been deprecated in Lua
1415 5.2.
3132
3233 ## Commenting Conventions
3334
34 LDoc follows the conventions established by Javadoc and later by LuaDoc.
35 LDoc follows the conventions established by Javadoc and later by LuaDoc to document the
36 modules, functions, tables and types ("classes") of your API.
37
38 ### Doc comments
3539
3640 Only 'doc comments' are parsed; these can be started with at least 3 hyphens, or by a empty
3741 comment line with at least 3 hypens:
5458 warning issued. The only exception is if the module starts with an explicit `module`
5559 statement.
5660
61 If your coding standards require a boilerplate copyright notice, then the `-B` flag or
62 `boilerplate=true` will make LDoc ignore the first comment of each module.
63
64 Common commenting patterns like '---- (text) -----' are exempted, since they are often used
65 for programmer-facing documentation.
66
67
68 ### Tags
69
5770 All doc comments start with a summary sentence, that ends with a period or a question mark.
5871 An optional description may follow. Normally the summary sentence will appear in the module
5972 contents.
6073
61 After this descriptive text, there will typically be _tags_. These follow the convention
62 established by Javadoc and widely used in tools for other languages.
74 After this descriptive text, there will typically be _tags_ which are introduced with an @.
75 These follow the convention established by Javadoc and widely used in tools for other languages.
76
77 --- Some doc comment
78 -- @tag1 parameters for first tag
79 -- @tag2 parameters for the second tag
80
81 The order of tags is not important, but as always, consistency is useful.
82
83 Here are all the tags known to LDoc:
84
85 * **@module** A Lua module containing functions and tables, which may be inside sections
86 * **@classmod** Like **@module** but describing a class
87 * **@submodule** A file containing definitions that you wish to put into the named _master_ module
88 * **@script** A Lua program
89 * **@author** (multiple), **copyright**, **@license**, **@release** only used for _project-level_ tags like **@module**
90 * **@function**, **@lfunction**. Functions inside a module
91 * **@param** formal arguments of a function (multiple)
92 * **@return** returned values of a function (multiple)
93 * **@raise** unhandled error thrown by this function
94 * **@local** explicitly marks a function as not being exported (unless `--all`)
95 * **@see** reference other documented items
96 * **@usage** give an example of a function's use. (Has a somewhat different meaning when used
97 with **@module**)
98 * **@table** a Lua table
99 * **@field** a named member of a table
100 * **@section** starting a named section for grouping functions or tables together
101 * **@type** a section which describes a class
102 * **@within** puts the function or table into an implicit section
103 * **@fixme**, **@todo** and **@warning** are _annotations_, which are doc comments that
104 occur inside a function body.
105
106 The first important tag to know is the module tag:
107
108 #### Modules: naming and describing your API module
109
110 The first thing in your API module should be a name and a description.
111 This is how a module is commonly done in Lua 5.2 with a **@module** tag at the top
112 which introduces the name:
113
114 --- a test module
115 -- @module test
116
117 local test = {}
118
119 function test.my_module_function_1()
120 ...
121 end
122
123 ...
124
125 return test
126
127 This sets up a module named 'test' with the description 'a test module'.
128
129 #### Functions
130
131 The next thing to describe are the functions your module has.
132 This is a simple example of a documented function:
63133
64134 --- foo explodes text.
65135 -- It is a specialized splitting operation on a string.
69139 ....
70140 end
71141
72 There are also 'tparam' and 'treturn' which let you [specify a type](#Tag_Modifiers):
73
74 -- @tparam string text the string
142 You can also give the function name itself as an explicit tag,
143 which is especially useful when documenting a Lua api exported by C code:
144
145 /// A C function which is exported to Lua with another name,
146 // because the ways of C can be mysterious!
147 // @function our_nice_function
148 int _some_function_for_lua(lua_State* l) {
149 ....
150 }
151
152 The tags basically add all the detail that cannot be derived from the source code
153 automatically.
154
155 #### Function parameters and return values
156
157 Common tags are the 'param' tag which takes a parameter name followed by a parameter
158 description separated by a space, and the 'return' tag which is simply followed by
159 a description for a return value:
160
161 -- @param name_of_parameter the description of this parameter as verbose text
162 -- @return the description of the return value
163
164 If you want to [specify a type](#Tag_Modifiers) for a parameter or a return value,
165 there are also 'tparam' and 'treturn':
166
167 -- @tparam string text this parameter is named 'text' and has the fixed type 'string'
75168 -- @treturn {string,...} a table of substrings
76169
77170 There may be multiple 'param' tags, which should document each formal parameter of the
78171 function. For Lua, there can also be multiple 'return' tags
79
80 --- solvers for common equations.
81 module("solvers", package.seeall)
82172
83173 --- solve a quadratic equation.
84174 -- @param a first coeff
98188 end
99189
100190 ...
101
102 This is the common module style used in Lua 5.1, but it's increasingly common to see less
103 'magic' ways of creating modules in Lua. Since `module` is deprecated in Lua 5.2, any
104 future-proof documentation tool needs to handle these styles gracefully:
105
106 --- a test module
107 -- @module test
108
109 local test = {}
110
111 --- first test.
112 function test.one()
113 ...
114 end
115
116 ...
117
118 return test
119
120 Here the name of the module is explicitly given using the 'module' tag. If you leave this
121 out, then LDoc will infer the name of the module from the name of the file and its relative
122 location in the filesystem; this logic is also used for the `module(...)` idiom. (How this
123 works and when you need to provide extra information is discussed later.)
124
125 It is common to use a local name for a module when declaring its contents. In this case the
126 'alias' tag can tell LDoc that these functions do belong to the module:
127
128 --- another test.
129 -- @module test2
130 -- @alias M
131
132 local M = {}
133
134 -- first test.
135 function M.one()
136 ..
137 end
138
139 return M
140
141 `M` and `_M` are used commonly enough that LDoc will recognize them as aliases
142 automatically, but 'alias' allows you to use any identifier.
143
144 LDoc tries to deduce the function name and the formal parameter names from examining the
145 code after the doc comment. It also recognizes the 'unsugared' way of defining functions as
146 explicit assignment to a variable:
147
148 --- second test.
149 M.two = function(...) ... end
150
151 Apart from exported functions, a module usually contains local functions. By default, LDoc
152 does not include these in the documentation, but they can be enabled using the `--all` flag.
153 They can be documented just like 'public' functions:
154
155 --- it's clear that boo is local from context.
156 local function boo(...) .. end
157
158 local foo
159
160 --- we need to give a hint here for foo
161 -- @local here
162 function foo(...) .. end
191 Of course there is also the 'module' tag which you have already seen.
192
193 #### Tables and constant values (fields)
163194
164195 Modules can of course export tables and other values. The classic way to document a table
165196 looks like this:
193224
194225 That is, a module may contain exported functions, local functions, tables and fields.
195226
227 #### Explicitly specifying a function or fields
228
196229 When the code analysis would lead to the wrong type, you can always be explicit.
197230
198 --- module contents.
231 --- module contents with explicitly documented field _CONTENTS.
199232 -- @field _CONTENTS
200233 M._CONTENTS = {constants=true,one=true,...}
201234
202 The order of tags is not important, but as always, consistency is useful. Tags like 'param'
203 and 'return' can be specified multiple times, whereas a type tag like 'function' can only
204 occur once in a comment. The basic rule is that a single doc comment can only document one
205 entity.
235 --- an explicitly named function.
236 -- @function my_function
237 function my_function()
238 ...
239 end
240
241 As mentioned before, this is often especially useful in C where things
242 may look different in the C code than they will in the final Lua api which
243 you want to document.
244
245 ### Doing modules the Lua 5.1 way
246
247 As an alternative to using the 'module' tag as described before, you
248 can still start your modules the Lua 5.1 way:
249
250 --- solvers for common equations.
251 module("solvers", package.seeall)
252
253 However, the 'module' function is deprecated in Lua 5.2 and it is increasingly
254 common to see less 'magic' ways of creating modules, as seen in the description
255 of the 'module' tag previously with the explicitely returned module table.
256
257 #### Repeating tags
258
259 Tags like 'param' and 'return' can be specified multiple times, whereas a type
260 tag like 'function' can only occur once in a comment.
261
262 The basic rule is that a single doc comment can only document one entity.
263
264 ### Local module name
265
266 It is common to use a local name for a module when declaring its contents. In this case the
267 'alias' tag can tell LDoc that these functions do belong to the module:
268
269 --- another test.
270 -- @module test2
271 -- @alias M
272
273 local M = {}
274
275 -- first test.
276 function M.one()
277 ..
278 end
279
280 return M
281
282 `M` and `_M` are used commonly enough that LDoc will recognize them as aliases
283 automatically, but 'alias' allows you to use any identifier.
284
285 LDoc tries to deduce the function name and the formal parameter names from examining the
286 code after the doc comment. It also recognizes the 'unsugared' way of defining functions as
287 explicit assignment to a variable:
288
289 --- second test.
290 M.two = function(...) ... end
291
292 ### Local functions
293
294 Apart from exported functions, a module usually contains local functions. By default, LDoc
295 does not include these in the documentation, but they can be enabled using the `--all` flag.
296 They can be documented just like 'public' functions:
297
298 --- it's clear that boo is local from context.
299 local function boo(...) .. end
300
301 local foo
302
303 --- we need to give a hint here for foo
304 -- @local here
305 function foo(...) .. end
306
307 ### Alternative way of specifying tags
308
309 Since 1.3, LDoc allows the use of _colons_ instead of @.
310
311 --- a simple function.
312 -- string name person's name
313 -- int: age age of person
314 -- !person: person object
315 -- treturn: ?string
316 -- function check(name,age)
317
318 However, you must either use the `--colon` flag or set `colon=true` in your `config.ld`.
319
320 In this style, types may be used directly if prefixed with '!' or '?' (for type-or-nil)
321
322 (see @{colon.lua}, rendered [here](http://stevedonovan.github.io/ldoc/examples/colon))
323
324 ### Which files are processed
206325
207326 By default, LDoc will process any file ending in '.lua' or '.luadoc' in a specified
208327 directory; you may point it to a single file as well. A 'project' usually consists of many
217336 (containing code) and examples and 'topics' (containing documentation). These then contain
218337 items like functions, tables, sections, and so forth.
219338
220 If you want to document scripts, then use `@script` instead of `@module`. New with 1.4 is
221 `@classmod` which is a module which exports a single class.
339 If you want to document scripts, then use **@script** instead of **@module**. New with 1.4 is
340 **@classmod** which is a module which exports a single class.
222341
223342
224343 ## See References
225344
226 The tag 'see' is used to reference other parts of the documentation, and 'usage' can provide
345 **@see** is used to reference other parts of the documentation, and **@usage** can provide
227346 examples of use; there can be multiple such tags:
228347
229348 ---------
240359 to a function in another module, then the reference has to be qualified.
241360
242361 References to methods use a colon: `myclass:method`; this is for instance how you would
243 refer to members of a `@type` section.
244
245 The example at `tests/complex` shows how @see references are interpreted:
362 refer to members of a **@type** section.
363
364 The example at `tests/complex` shows how **@see** references are interpreted:
246365
247366 complex.util.parse
248367 complex.convert.basic
263382 'table.concat' are handled sensibly.
264383
265384 References may be made inline using the `@{\ref}` syntax. This may appear anywhere in the
266 text, and is more flexible than `@see`. In particular, it provides one way to document the
385 text, and is more flexible than **@see**. In particular, it provides one way to document the
267386 type of a parameter or return value when that type has a particular structure:
268387
269388 ------
287406
288407 You can also put references in backticks, like `\`stdvars\``. This is commonly used in
289408 Markdown to indicate code, so it comes naturally when writing documents. It is controlled by
290 the configuration variable `backtick_references`; the default is `true` if you use Markdown
291 in your project, but can be specified explicitly in your `config.ld`.
292
293 ### Custom @see References
409 the configuration variable `backtick_references` or the `backtick` format;
410 the default is `true` if you use Markdown in your project, but can be specified explicitly
411 in `config.ld`.
412
413 To quote such references so they won't be expanded, say @{\\ref}.
414
415 #### Custom @see References
294416
295417 It's useful to define how to handle references external to a project. For instance, in the
296418 [luaposix](https://github.com/luaposix/luaposix) project we wanted to have `man` references
309431
310432 local upat = "http://www.kernel.org/doc/man-pages/online/pages/man%s/%s.%s.html"
311433
312 custom_see_handler('^(%a+)%((%d)%)$',function(name,section)
434 custom_see_handler('^([%w_]+)%((%d)%)$',function(name,section)
313435 local url = upat:format(section,name,section)
314436 local name = name .. '(' ..section..')'
315437 return name, url
316438 end)
317439
318 '^(%a+)%((%d)%)$' both matches the pattern and extracts the name and its section. Then it's
440 `^([%w_]+)%((%d)%)$` both matches the pattern and extracts the name and its section. Then it's
319441 a simple matter of building up the appropriate URL. The function is expected to
320442 return _link text_ and _link source_ and the patterns are checked before LDoc tries to resolve
321443 project references. So it is best to make them match as exactly as possible.
322444
445 ## Module Tags
446
447 LDoc requires you to have a module doc comment. If your code style requires
448 license blocks that might look like doc comments, then set `boilerplate=true` in your
449 configuration and they will be skipped.
450
451 This comment does not have to have an explicit **@module** tag and LDoc continues to
452 respect the use of `module()`.
453
454 There are three types of 'modules' (i.e. 'project-level'); `module`, a library
455 loadable with `require()`, `script`, a program, and `classmod` which is a class
456 implemented in a single module.
457
458 There are some tags which are only useful in module comments: `author`,`copyright`,
459 `license` and `release`. These are presented in a special **Info** section in the
460 default HTML output.
461
462 The **@usage** tag has a somewhat different presentation when used in modules; the text
463 is presented formatted as-is in a code font. If you look at the script `ldoc` in
464 this documentation, you can see how the command-line usage is shown. Since coding
465 is all about avoiding repetition and the out-of-sync issues that arise,
466 the **@usage** tag can appear later in the module, before a long string. For instance,
467 the main script of LDoc is [ldoc.lua](https://github.com/stevedonovan/LDoc/blob/master/ldoc.lua)
468 and you will see that the usage tag appears on line 36 before the usage string
469 presented as help.
470
471 **@export** is another module tag that is usually 'detached'. It is for supporting
472 modules that wish to explicitly export their functions @{three.lua|at the end}.
473 In that example, both `question` and `answer` are local and therefore private to
474 the module, but `answer` has been explicitly exported. (If you invoke LDoc with
475 the `-a` flag on this file, you will see the documentation for the unexported
476 function as well.)
477
478 **@set** is a powerful tag which assigns a configuration variable to a value _just for this module_.
479 Saying `@set no_summary=true` in a module comment will temporarily disable summary generation when
480 the template is expanded. Generally configuration variables that effect template expansion
481 are modifiable in this way. For instance, if you wish that the contents of a particular module
482 be sorted, then `@set sort=true` will do it _just_ for that module.
483
323484 ## Sections
324485
325486 LDoc supports _explicit_ sections. By default, the implicit sections correspond to the pre-existing
326487 types in a module: 'Functions', 'Tables' and 'Fields' (There is another default section
327488 'Local Functions' which only appears if LDoc is invoked with the `--all` flag.) But new
328 sections can be added; the first mechanism is when you define a new type (say 'macro'). Then a new
329 section ('Macros') is created to contain these types.
330
331 There is also a way to declare ad-hoc sections using the `@section` tag.
489 sections can be added; the first mechanism is when you @{Adding_new_Tags|define a new type}
490 (say 'macro'). Then a new section ('Macros') is created to contain these types.
491
492 There is also a way to declare ad-hoc sections using the **@section** tag.
332493 The need occurs when a module has a lot of functions that need to be put into logical
333494 sections.
334495
350511
351512 A section doc-comment has the same structure as a normal doc-comment; the summary is used as
352513 the new section title, and the description will be output at the start of the function
353 details for that section.
354
355 In any case, sections appear under 'Contents' on the left-hand side. See the
514 details for that section; the name is not used, but must be unique.
515
516 Sections appear under 'Contents' on the left-hand side. See the
356517 [winapi](http://stevedonovan.github.com/winapi/api.html) documentation for an example of how
357518 this looks.
358519
373534 end
374535
375536 (In an ideal world, we would use the word 'class' instead of 'type', but this would conflict
376 with the LuaDoc usage.)
537 with the LuaDoc `class` tag.)
377538
378539 A section continues until the next section is found, `@section end`, or end of file.
379540
380 You can put items into an implicit section using the @within tag. This allows you to put
541 You can put items into an implicit section using **@within**. This allows you to put
381542 adjacent functions in different sections, so that you are not forced to order your code
382543 in a particular way.
383544
384 Sometimes a module may logically span several files. There will be a master module with name
545 With 1.4, there is another option for documenting classes, which is the top-level type
546 `classmod`. It is intended for larger classes which are implemented within one module,
547 and the advantage that methods can be put into sections.
548
549 Sometimes a module may logically span several files, which can easily happen with large
550 There will be a master module with name
385551 'foo' and other files which when required add functions to that module. If these files have
386 a @submodule tag, their contents will be placed in the master module documentation. However,
552 a **@submodule** tag, their contents will be placed in the master module documentation. However,
387553 a current limitation is that the master module must be processed before the submodules.
388554
389555 See the `tests/submodule` example for how this works in practice.
415581 LDoc will also work with C/C++ files, since extension writers clearly have the same
416582 documentation needs as Lua module writers.
417583
418 LDoc allows you to attach a _type_ to a parameter or return value
419
420 --- better mangler.
421 -- @tparam string name
422 -- @int max length
423 -- @treturn string mangled name
424 function strmangler(name,max)
425 ...
426 end
427
428 `int` here is short for `tparam int` (see @{Tag_Modifiers})
429
430 It's common for types to be optional, or have different types, so the type can be like
431 '?int|string' which renders as '(int or string)', or '?int', which renders as
432 '(optional int)'.
433
434 LDoc gives the documenter the option to use Markdown to parse the contents of comments.
435
436 Since 1.3, LDoc allows the use of _colons_ instead of @.
437
438 --- a simple function.
439 -- string name person's name
440 -- int: age age of person
441 -- !person: person object
442 -- treturn: ?string
443 -- function check(name,age)
444
445 However, you must either use the `--colon` flag or set `colon=true` in your `config.ld`.
446
447 In this style, types may be used directly if prefixed with '!' or '?' (for type-or-nil)
448
449 (see @{colon.lua})
584 LDoc allows you to attach a _type_ to a parameter or return value with `tparam` or `treturn`,
585 and gives the documenter the option to use Markdown to parse the contents of comments.
586 You may also include code examples which will be prettified, and readme files which will be
587 rendered with Markdown and contain prettified code blocks.
450588
451589 ## Adding new Tags
452590
541679
542680 LDoc can process C/C++ files:
543681
544 @plain
545 /***
546 Create a table with given array and hash slots.
547 @function createtable
548 @param narr initial array slots, default 0
549 @param nrec initial hash slots, default 0
550 @return the new table
551 */
552 static int l_createtable (lua_State *L) {
553 ....
682 ```c
683 /***
684 Create a table with given array and hash slots.
685 @function createtable
686 @param narr initial array slots, default 0
687 @param nrec initial hash slots, default 0
688 @return the new table
689 */
690 static int l_createtable (lua_State *L) {
691 ....
692 ```
554693
555694 Both `/**` and `///` are recognized as starting a comment block. Otherwise, the tags are
556695 processed in exactly the same way. It is necessary to specify that this is a function with a
566705 the docs from the separate files. For this, use `merge=true`.
567706
568707 See @{mylib.c} for the full example.
708
709 ## Moonscript Support
710
711 1.4 introduces basic support for [Moonscript](http://moonscript.org). Moonscript module
712 conventions are just the same as Lua, except for an explicit class construct.
713 @{list.moon} shows how **@classmod** can declare modules that export one class, with metamethods
714 and methods put implicitly into a separate section.
569715
570716 ## Basic Usage
571717
630776 - [lunamark](http://jgm.github.com/lunamark/), another pure Lua processor, faster than
631777 markdown, and with extra features (`luarocks install lunamark`).
632778
633 You can request the processor you like with `format = 'markdown|discount|lunamark'`, and
779 You can request the processor you like with `format = 'markdown|discount|lunamark|plain|backticks'`, and
634780 LDoc will attempt to use it. If it can't find it, it will look for one of the other
635781 markdown processors; the original `markdown.lua` ships with LDoc, although it's slow
636782 for larger documents.
637783
638784 Even with the default of 'plain' some minimal processing takes place, in particular empty lines
639 are treated as line breaks. If 'process_backticks=true` then backticks will be
785 are treated as line breaks. If the 'backticks' formatter is used, then it's equivalent to
786 using 'process_backticks=true` in `config.ld` and backticks will be
640787 expanded into documentation links like `@{\ref}` and converted into `<code>ref</code>`
641788 otherwise.
642789
754901
755902 The _navigation section_ down the left has several parts:
756903
757 - The project name ('project' in the config)
758 - A project description ('description')
759 - ''Contents'' of the current page
760 - ''Modules'' listing all the modules in this project
904 - The project name (`project` in the config)
905 - A project description (`description`)
906 - **Contents** of the current page
907 - **Modules** listing all the modules in this project
761908
762909 Note that `description` will be passed through Markdown, if it has been specified for the
763910 project. This gives you an opportunity to make lists of links, etc; any '##' headers will be
764911 formatted like the other top-level items on the navigation bar.
765912
766 'Contents' is automatically generated. It will contain any explicit sections, if they have
767 been used. Otherwise you will get the usual categories: 'Functions', 'Tables' and 'Fields'.
768
769 'Modules' will appear for any project providing Lua libraries; there may also be a 'Scripts'
913 **Contents** is automatically generated. It will contain any explicit sections
914 as well as the usual categories: 'Functions', 'Tables' and 'Fields'. For a documentation page,
915 the subtitles become the sections shown here.
916
917 **Modules** will appear for any project providing Lua libraries; there may also be a 'Scripts'
770918 section if the project contains Lua scripts. For example,
771919 [LuaMacro](http://stevedonovan.github.com/LuaMacro/docs/api.html) has a driver script `luam`
772920 in this section. The
773921 [builtin](http://stevedonovan.github.com/LuaMacro/docs/modules/macro.builtin.html) module
774 only defines macros, which are defined as a _custom tag type_.
922 only defines macros, which are defined as a _custom tag type[?]_.
775923
776924 The _content section_ on the right shows:
777925
787935 'see' in that order. (For tables, 'Fields' is used instead of 'Parameters' but internally
788936 fields of a table are stored as the 'param' tag.)
789937
938 By default, the items appear in the order of declaration within their section. If `sort=true`
939 then they will be sorted alphabetically. (This can be set per-module with @{Module_Tags|@set}.)
940
790941 You can of course customize the default template, but there are some parameters that can
791 control what the template will generate. Setting `one` to `true` in your configuration file
942 control what the template will generate. Setting `one=true` in your configuration file
792943 will give a _one-column_ layout, which can be easier to use as a programming reference. You
793944 can suppress the contents summary with `no_summary`.
794945
796947
797948 A basic customization is to override the default UTF-8 encoding using `charset`. For instance,
798949 Brazillian software would find it useful to put `charset='ISO-8859-1'` in `config.ld`, or use
799 the @charset tag for individual files.
950 the **@charset** tag for individual files.
800951
801952 Setting `no_return_or_parms` to `true` will suppress the display of 'param' and 'return'
802953 tags. This may appeal to programmers who dislike the traditional @tag soup xDoc style and
838989
839990 LDoc allows for source examples to be included in the documentation. For example, see the
840991 online documentation for [winapi](http://stevedonovan.github.com/winapi/api.html). The
841 function `utf8_expand` has a `@see` reference to 'testu.lua' and following that link gives
992 function `utf8_expand` has a **@see** reference to 'testu.lua' and following that link gives
842993 you a pretty-printed version of the code.
843994
844995 The line in the `config.ld` that enables this is:
846997 examples = {'examples', exclude = {'examples/slow.lua'}}
847998
848999 That is, all files in the `examples` folder are to be pretty-printed, except for `slow.lua`
849 which is meant to be called from one of the examples. Now a see-reference to `testu.lua`
850 resolves to 'examples/testu.lua.html'.
1000 which is meant to be called from one of the examples.
1001 To link to an example, use a reference like `@{\testu.lua}`
1002 which resolves to 'examples/testu.lua.html'.
8511003
8521004 Examples may link back to the API documentation, for instance the example `input.lua` has a
8531005 `@{\spawn_process}` inline reference.
8541006
855 By default, LDoc uses a built-in Lua code 'prettifier'. See-references are allowed in comments,
856 and also in code if they're enclosed in backticks.
1007 By default, LDoc uses a built-in Lua code 'prettifier'. Reference links are allowed in comments,
1008 and also in code if they're enclosed in backticks. Lua and C are known languages.
8571009
8581010 [lxsh](https://github.com/xolox/lua-lxsh)
859 can be used (available from LuaRocks) if you want support for C as well. `pretty='lxsh'` will
1011 can be used (available from LuaRocks) if you want something more powerful. `pretty='lxsh'` will
8601012 cause `lxsh` to be used, if available.
8611013
8621014 ## Readme files
9021054 references, it is not an error if the reference cannot be found.
9031055
9041056 The _sections_ of a document (the second-level headings) are also references. This
905 particular section can be refered to as `@{\doc.md.Resolving_References_in_Documents}` - the
1057 particular section you are reading can be refered to as `@{\doc.md.Readme_files}` - the
9061058 rule is that any non-alphabetic character is replaced by an underscore.
1059
1060 Any indented blocks are assumed to be Lua, unless their first line is `@plain`. New
1061 with 1.4 is github-markdown-style fenced code blocks, which start with three backticks
1062 optionally followed by a language. The code continues until another three backticks
1063 is found: the language can be `c`, `cpp` or `cxx` for C/C++, anything else is Lua.
9071064
9081065 ## Tag Modifiers
9091066
9231080
9241081 tparam_alias('string','string')
9251082
926 That is, "@string" will now have the same meaning as "@tparam string"; this also applies
1083 That is, **@string** will now have the same meaning as "@tparam string"; this also applies
9271084 to the optional type syntax "?|T1|T2".
9281085
9291086 From 1.3, the following standard type aliases are predefined:
9541111
9551112 alias('tparam',{'param',modifiers={type="$1"}})
9561113
957 As an extension, you're allowed to use '@param' tags in table definitions. This makes it
958 possible to use type alias like '@string' to describe fields, since they will expand to
1114 As an extension, you're allowed to use **@param** tags in table definitions. This makes it
1115 possible to use type aliases like **@string** to describe fields, since they will expand to
9591116 'param'.
9601117
9611118 Another modifier understood by LDoc is `opt`. For instance,
9841141 end
9851142 ----> displayed as: one (name, age [, calender='gregorian' [, offset=0]])
9861143
987 Currently the `type` and `opt` modifiers are the only ones known and used by LDoc when generating HTML
1144
1145 (See @{four.lua}, rendered [here](http://stevedonovan.github.io/ldoc/examples/four))
1146
1147 An experimental feature in 1.4 allows different 'return groups' to be defined. There may be
1148 multiple **@return** tags, and the meaning of this is well-defined, since Lua functions may
1149 return multiple values. However, being a dynamic language it may return a single value if
1150 successful and two values (`nil`,an error message) if there is an error. This is in fact the
1151 convention for returning 'normal' errors (like 'file not found') as opposed to parameter errors
1152 (like 'file must be a string') that are often raised as errors.
1153
1154 Return groups allow a documenter to specify the various possible return values of a function,
1155 by specifying _number_ modifiers. All `return` tags with the same digit modifier belong together
1156 as a group:
1157
1158 -----
1159 -- function with return groups.
1160 -- @return[1] result
1161 -- @return[2] nil
1162 -- @return[2] error message
1163 function mul1() ... end
1164
1165 This is the first function in @{multiple.lua}, and the [output](http://stevedonovan.github.io/ldoc/examples/multiple)
1166 shows how return groups are presented, with an **Or** between the groups.
1167
1168 This is rather clumsy, and so there is a shortcut, the **@error** tag which achieves the same result,
1169 with helpful type information.
1170
1171 Currently the `type`,`opt` and `<digit>` modifiers are the only ones known and used by LDoc when generating HTML
9881172 output. However, any other modifiers are allowed and are available for use with your own
9891173 templates or for extraction by your own tools.
9901174
991 (See @{four.lua})
9921175
9931176 ## Fields allowed in `config.ld`
9941177
10111194 template. In `config.ld` they may also be `true`, meaning use the same directory as the
10121195 configuration file.
10131196 - `merge` allow documentation from different files to be merged into modules without
1014 explicit @submodule tag
1015
1016 _These only appear in config.ld:_
1197 explicit **@submodule** tag
1198
1199 _These only appear in the configuration file:_
10171200
10181201 - `description` a short project description used under the project title
10191202 - `full_description` when you _really_ need a longer project description
10201203 - `examples` a directory or file: can be a table
10211204 - `readme` or `topics` readme files (to be processed with Markdown)
10221205 - `pretty` code prettify 'lua' (default) or 'lxsh'
1023 - `charset` use if you want to override the UTF-8 default (also @charset in files)
1206 - `charset` use if you want to override the UTF-8 default (also **@charset** in files)
10241207 - `sort` set if you want all items in alphabetical order
10251208 - `no_return_or_parms` don't show parameters or return values in output
10261209 - `backtick_references` whether references in backticks will be resolved. Happens by default
10311214 'file:///D:/dev/lua/projects/lua-5.1.4/doc/manual.html'
10321215 - `no_summary` suppress the Contents summary
10331216 - `custom_see_handler` function that filters see-references
1217 - `custom_display_name_handler` function that formats an item's name. The arguments are the item
1218 and the default function used to format the name. For example, to show an icon or label beside any
1219 function tagged with a certain tag:
1220 -- define a @callback tag:
1221 custom_tags = { { 'callback', hidden = true } }
1222
1223 -- show a label beside functions tagged with @callback.
1224 custom_display_name_handler = function(item, default_handler)
1225 if item.type == 'function' and item.tags.callback then
1226 return item.name .. ' [callback]'
1227 end
1228 return default_handler(item)
1229 end
1230
10341231 - `not_luadoc` set to `true` if the docs break LuaDoc compatibility
10351232 - `no_space_before_args` set to `true` if you do not want a space between a function's name and its arguments.
10361233 - `template_escape` overrides the usual '#' used for Lua code in templates. This needs to be changed if the output format is Markdown, for instance.
10951292
10961293 This is then styled with `ldoc.css`. Currently the template and stylesheet is very much
10971294 based on LuaDoc, so the results are mostly equivalent; the main change that the template has
1098 been more generalized. The default location (indicated by '!') is the directory of `ldoc.lua`.
1295 been more generalized. The default location (indicated by '!') is the directory of `ldoc_ltp.lua`.
1296
1297 You will notice that the built-in templates and stylesheets end in `.lua`; this is simply to
1298 make it easier for LDoc to find them. Where you are customizing one or both of the template
1299 and stylesheet, they will have their usual extensions.
10991300
11001301 You may customize how you generate your documentation by specifying an alternative style
11011302 sheet and/or template, which can be deployed with your project. The parameters are `--style`
11071308 An example of fully customized documentation is `tests/example/style`: this is what you
11081309 could call 'minimal Markdown style' where there is no attempt to tag things (except
11091310 emphasizing parameter names). The narrative alone _can_ to be sufficient, if it is written
1110 appropriately.
1311 well.
1312
1313 There are two other stylesheets available in LDoc since 1.4; the first is `ldoc_one.css` which is what
1314 you get from `one=true` and the second is `ldoc_pale.css`. This is a lighter theme which
1315 might give some relief from the heavier colours of the default. You can use this style with
1316 `style="!pale"` or `-s !pale`.
1317 See the [Lake](http://stevedonovan.github.io/lake/modules/lakelibs.html) documentation
1318 as an example of its use.
11111319
11121320 Of course, there's no reason why LDoc must always generate HTML. `--ext` defines what output
11131321 extension to use; this can also be set in the configuration file. So it's possible to write
11151323 and presentation makes this kind of new application possible with LDoc.
11161324
11171325 From 1.4, LDoc has some limited support for generating Markdown output, although only
1118 for single files currently. Use `--ext md` for this. 'ldoc/html/ldoc_mdtp.lua' defines
1119 the template for Markdown.
1326 for single files currently. Use `--ext md` for this. 'ldoc/html/ldoc_md_ltp.lua' defines
1327 the template for Markdown, but this can be overriden with `template` as above. It's another
1328 example of minimal structure, and provides a better place to learn about these templates than the
1329 rather elaborate default HTML template.
11201330
11211331 ## Internal Data Representation
11221332
11501360 entities, including scripts) which each contain an `item` array (functions, tables and so
11511361 forth).
11521362
1153 For instance, to find all functions which don't have a @return tag:
1363 For instance, to find all functions which don't have a **@return** tag:
11541364
11551365 return {
11561366 filter = function (t)
11641374 end
11651375 }
11661376
1167 The internal naming is not always so consistent; `ret` corresponds to @return, and `params`
1168 corresponds to @param. `item.params` is an array of the function parameters, in order; it
1377 The internal naming is not always so consistent; `ret` corresponds to **@return**, and `params`
1378 corresponds to **@param**. `item.params` is an array of the function parameters, in order; it
11691379 is also a map from these names to the individual descriptions of the parameters.
11701380
11711381 `item.modifiers` is a table where the keys are the tags and the values are arrays of
2020 -- - 'N' tags which have no associated value, like 'local` (TAG_FLAG)
2121 -- - 'T' tags which represent a type, like 'function' (TAG_TYPE)
2222 local known_tags = {
23 param = 'M', see = 'M', usage = 'ML', ['return'] = 'M', field = 'M', author='M',set='M';
23 param = 'M', see = 'M', comment = 'M', usage = 'ML', ['return'] = 'M', field = 'M', author='M',set='M';
2424 class = 'id', name = 'id', pragma = 'id', alias = 'id', within = 'id',
2525 copyright = 'S', summary = 'S', description = 'S', release = 'S', license = 'S',
2626 fixme = 'S', todo = 'S', warning = 'S', raise = 'S', charset = 'S',
120120 return List.iter(known_tags._module_info)
121121 end
122122
123
124123 -- annotation tags can appear anywhere in the code and may contain any of these tags:
125124 known_tags._annotation_tags = {
126125 fixme = true, todo = true, warning = true
129128 local acount = 1
130129
131130 function doc.expand_annotation_item (tags, last_item)
132 if tags.summary ~= '' then return false end
131 if tags.summary ~= '' or last_item == nil then return false end
132 local item_name = last_item.tags.name
133133 for tag, value in pairs(tags) do
134134 if known_tags._annotation_tags[tag] then
135135 tags:add('class','annotation')
136136 tags:add('summary',value)
137 local item_name = last_item and last_item.tags.name or '?'
138137 tags:add('name',item_name..'-'..tag..acount)
139138 acount = acount + 1
140139 return true
141 end
142 end
140 elseif tag == 'return' then
141 last_item:set_tag(tag,value)
142 end
143 end
144 return false
143145 end
144146
145147 -- we process each file, resulting in a File object, which has a list of Item objects.
173175 for item in self.items:iter() do
174176 local tags = item.tags
175177 if tags.name == name then
178 tags.export = true
176179 if tags['local'] then
177180 tags['local'] = nil
178181 end
204207 end
205208 end
206209
210 local function init_within_section (mod,name)
211 mod.kinds:add_kind(name, name)
212 mod.enclosing_section = mod.section
213 mod.section = nil
214 return name
215 end
216
207217 function File:finish()
208218 local this_mod
209219 local items = self.items
210220 local tagged_inside
211 local function add_section (item, display_name)
212 display_name = display_name or item.display_name
213 this_mod.section = item
214 this_mod.kinds:add_kind(display_name,display_name..' ',nil,item)
215 this_mod.sections:append(item)
216 this_mod.sections.by_name[display_name:gsub('%A','_')] = item
217 end
221 self.args = self.args or {}
218222 for item in items:iter() do
219223 if mod_section_type(this_mod) == 'factory' and item.tags then
220224 local klass = '@{'..this_mod.section.name..'}'
226230 end
227231 end
228232 item:finish()
229 if doc.project_level(item.type) then
233 -- the default is not to show local functions in the documentation.
234 if not self.args.all and (item.type=='lfunction' or (item.tags and item.tags['local'])) then
235 -- don't add to the module --
236 elseif doc.project_level(item.type) then
230237 this_mod = item
231238 local package,mname,submodule
232239 if item.type == 'module' then
261268 if not submodule then
262269 this_mod.package = package
263270 this_mod.mod_name = mname
264 this_mod.kinds = ModuleMap() -- the iterator over the module contents
271 this_mod.kinds = doc.ModuleMap() -- the iterator over the module contents
265272 self.modules:append(this_mod)
266273 end
267274 elseif doc.section_tag(item.type) then
270277 this_mod.section = nil
271278 else
272279 local summary = item.summary:gsub('%.$','')
280 local lookup_name
273281 if doc.class_tag(item.type) then
274282 display_name = 'Class '..item.name
283 lookup_name = item.name
275284 item.module = this_mod
276285 this_mod.items.by_name[item.name] = item
277286 else
278287 display_name = summary
288 lookup_name = summary
279289 end
280290 item.display_name = display_name
281 add_section(item)
291 this_mod.section = item
292 this_mod.kinds:add_kind(display_name,display_name..' ',nil,item)
293 this_mod.sections:append(item)
294 this_mod.sections.by_name[lookup_name:gsub('%A','_')] = item
282295 end
283296 else
284297 local to_be_removed
285298 -- add the item to the module's item list
286299 if this_mod then
287300 -- new-style modules will have qualified names like 'mod.foo'
301 if item.name == nil then
302 self:error("item's name is nil")
303 end
288304 local mod,fname = split_dotted_name(item.name)
289305 -- warning for inferred unqualified names in new style modules
290306 -- (retired until we handle methods like Set:unset() properly)
301317 item.name = fname
302318 end
303319
304 local enclosing_section
305320 if tagged_inside then
306321 item.tags.within = tagged_inside
307322 end
308323 if item.tags.within then
309 local name = item.tags.within
310 this_mod.kinds:add_kind(name, name)
311 enclosing_section = this_mod.section
312 this_mod.section = nil
324 init_within_section(this_mod,item.tags.within)
313325 end
314326
315327 -- right, this item was within a section or a 'class'
325337 -- if it was a class, then if the name is unqualified then it becomes
326338 -- 'Class:foo' (unless flagged as being a constructor, static or not a function)
327339 if doc.class_tag(stype) or classmod then
328 if not item.name:match '[:%.]' then -- not qualified
340 if not item.name:match '[:%.]' then -- not qualified name!
341 -- a class is either a @type section or a @classmod module. Is this a _method_?
329342 local class = classmod and this_mod.name or this_section.name
330 local lang = this_mod.file.lang
331343 local static = item.tags.constructor or item.tags.static or item.type ~= 'function'
332 item.name = class..(not static and lang.method_call or '.')..item.name
344 -- methods and metamethods go into their own special sections...
345 if classmod and item.type == 'function' then
346 local inferred_section
347 if item.name:match '^__' then
348 inferred_section = 'Metamethods'
349 elseif not static then
350 inferred_section = 'Methods'
351 end
352 if inferred_section then
353 item.tags.within = init_within_section(this_mod,inferred_section)
354 end
355 end
356 -- Whether to use '.' or the language's version of ':' (e.g. \ for Moonscript)
357 item.name = class..(not static and this_mod.file.lang.method_call or '.')..item.name
333358 end
334359 if stype == 'factory' then
335360 if item.tags.private then to_be_removed = true
348373 section_description = item.tags.within
349374 item.section = section_description
350375 else
351 section_description = "Methods"
376 if item.type == 'function' or item.type == 'lfunction' then
377 section_description = "Methods"
378 end
352379 item.section = item.type
353380 end
354 elseif item.tags.within then
381 elseif item.tags.within then -- ad-hoc section...
355382 section_description = item.tags.within
356383 item.section = section_description
357384 else -- otherwise, just goes into the default sections (Functions,Tables,etc)
358 item.section = item.type
385 item.section = item.type;
359386 end
360387
361388 item.module = this_mod
367394 end
368395
369396 -- restore current section after a 'within'
370 if enclosing_section then this_mod.section = enclosing_section end
397 if this_mod.enclosing_section then
398 this_mod.section = this_mod.enclosing_section
399 this_mod.enclosing_section = nil
400 end
371401
372402 else
373403 -- must be a free-standing function (sometimes a problem...)
404434 self.tags = {}
405435 self.formal_args = tags.formal_args
406436 tags.formal_args = nil
407 local iter = tags.iter
408 if not iter then
409 iter = Map.iter
410 end
437 local iter = tags.iter or Map.iter
411438 for tag in iter(tags) do
412439 self:set_tag(tag,tags[tag])
413440 end
421448
422449 function Item:trailing_warning (kind,tag,rest)
423450 if type(rest)=='string' and #rest > 0 then
424 Item.warning(self,kind.." tag: '"..tag..'" has trailing text; use not_luadoc=true if you want description to continue between tags\n'..rest)
425 end
451 Item.warning(self,kind.." tag: '"..tag..'" has trailing text ; use not_luadoc=true if you want description to continue between tags\n"'..rest..'"')
452 end
453 end
454
455 local function is_list (l)
456 return getmetatable(l) == List
426457 end
427458
428459 function Item:set_tag (tag,value)
430461 local args = self.file.args
431462
432463 if ttype == TAG_MULTI or ttype == TAG_MULTI_LINE then -- value is always a List!
433 if getmetatable(value) ~= List then
464 local ovalue = self.tags[tag]
465 if ovalue then -- already defined, must be a list
466 --print(tag,ovalue,value)
467 if is_list(value) then
468 ovalue:extend(value)
469 else
470 ovalue:append(value)
471 end
472 value = ovalue
473 end
474 -- these multiple values are always represented as lists
475 if not is_list(value) then
434476 value = List{value}
435477 end
436478 if ttype ~= TAG_MULTI_LINE and args and args.not_luadoc then
447489 if type(value) == 'table' then
448490 if value.append then -- it was a List!
449491 -- such tags are _not_ multiple, e.g. name
450 self:error("'"..tag.."' cannot have multiple values")
492 if tag == 'class' and value:contains 'example' then
493 self:error("cannot use 'example' tag for functions or tables. Use 'usage'")
494 else
495 self:error("'"..tag.."' cannot have multiple values; "..tostring(value))
496 end
451497 end
452498 value = value[1]
453499 modifiers = value.modifiers
481527 if alias then
482528 if type(alias) == 'string' then
483529 tag = alias
484 else
530 elseif type(alias) == 'table' then --{ tag, value=, modifiers = }
485531 local avalue,amod
486532 tag, avalue, amod = alias[1],alias.value,alias.modifiers
487533 if avalue then value = avalue..' '..value end
495541 modifiers[m] = v
496542 end
497543 end
544 else -- has to be a function that at least returns tag, value
545 return alias(tags,value,modifiers)
498546 end
499547 end
500548 local ttype = known_tags[tag]
546594
547595 local build_arg_list, split_iden -- forward declaration
548596
597 function Item:split_param (line)
598 local name, comment = line:match('%s*([%w_%.:]+)(.*)')
599 if not name then
600 self:error("bad param name format '"..line.."'. Are you missing a parameter name?")
601 end
602 return name, comment
603 end
549604
550605 function Item:finish()
551606 local tags = self.tags
594649 local param_names, comments = List(), List()
595650 if params then
596651 for line in params:iter() do
597 local name, comment = line:match('%s*([%w_%.:]+)(.*)')
598 if not name then
599 self:error("bad param name format '"..line.."'. Are you missing a parameter name?")
600 end
652 local name, comment = self:split_param(line)
601653 param_names:append(name)
602654 comments:append(comment)
603655 end
613665 if fargs then
614666 if #param_names == 0 then
615667 --docs may be embedded in argument comments; in either case, use formal arg names
616 formal = List()
617 if fargs.return_comment then
618 local retc = self:parse_argument_comment(fargs.return_comment,'return')
619 self.ret = List{retc}
620 end
621 for i, name in ipairs(fargs) do
622 formal:append(name)
623 comments:append(self:parse_argument_comment(fargs.comments[name],self.parameter))
624 end
625 elseif #fargs > 0 then
668 local ret
669 formal,comments,ret = self:parse_formal_arguments(fargs)
670 if ret and not self.ret then self.ret = ret end
671 elseif #fargs > 0 then -- consistency check!
626672 local varargs = fargs[#fargs] == '...'
627673 if varargs then table.remove(fargs) end
674 if tags.export then
675 if fargs[1] == 'self' then
676 table.remove(fargs,1)
677 else
678 tags.static = true
679 end
680 end
628681 local k = 0
629682 for _,pname in ipairs(param_names) do
630683 local _,field = split_iden(pname)
640693 end
641694 end
642695 if k < #fargs then
643 for i = k+1,#fargs do
644 if fargs[i] ~= '...' then
645 self:warning("undocumented formal argument: "..quote(fargs[i]))
646 end
696 for i = k+1,#fargs do if fargs[i] ~= '...' then
697 self:warning("undocumented formal argument: "..quote(fargs[i]))
698 end end
699 end
700 end -- #fargs > 0
701 -- formal arguments may come with types, inferred by the
702 -- appropriate code in ldoc.lang
703 if fargs.types then
704 self.modifiers[field] = List()
705 for t in fargs.types:iter() do
706 self:add_type(field,t)
707 end
708 if fargs.return_type then
709 if not self.ret then -- type, but no comment; no worries
710 self.ret = List{''}
647711 end
648 end
649 end
650 end
712 self.modifiers['return'] = List()
713 self:add_type('return',fargs.return_type)
714 end
715 end
716 end -- fargs
651717
652718 -- the comments are associated with each parameter by
653719 -- adding name-value pairs to the params list (this is
683749 self.params = params
684750 self.args = build_arg_list (names,pmods)
685751 end
752 if self.ret then
753 self:build_return_groups()
754 end
755 end
756
757 function Item:add_type(field,type)
758 self.modifiers[field]:append {type = type}
686759 end
687760
688761 -- ldoc allows comments in the formal arg list to be used, if they aren't specified with @param
693766 comment = comment:gsub('^%-+%s*','')
694767 local type,rest = comment:match '([^:]+):(.*)'
695768 if type then
696 self.modifiers[field]:append {type = type}
769 self:add_type(field,type)
697770 comment = rest
698771 end
699772 end
700773 return comment or ''
774 end
775
776 function Item:parse_formal_arguments (fargs)
777 local formal, comments, ret = List(), List()
778 if fargs.return_comment then
779 local retc = self:parse_argument_comment(fargs.return_comment,'return')
780 ret = List{retc}
781 end
782 for i, name in ipairs(fargs) do
783 formal:append(name)
784 comments:append(self:parse_argument_comment(fargs.comments[name],self.parameter))
785 end
786 return formal, comments, ret
701787 end
702788
703789 function split_iden (name)
751837 return '('..table.concat(buffer)..')'
752838 end
753839
840 ------ retrieving information about parameters -----
841 -- The template leans on these guys heavily....
842
754843 function Item:param_modifiers (p)
755844 local mods = self.modifiers[self.parameter]
756845 if not mods then return '' end
770859 return opt
771860 end
772861
773 function Item:type_of_ret(idx)
774 local rparam = self.modifiers['return'][idx]
775 return rparam and rparam.type or ''
862 function Item:readonly(p)
863 local m = self:param_modifiers(p)
864 if not m then return nil end
865 return m.readonly
776866 end
777867
778868 function Item:subparam(p)
793883 end
794884 end
795885
886 -------- return values and types -------
887
888 function Item:type_of_ret(idx)
889 local rparam = self.modifiers['return'][idx]
890 return rparam and rparam.type or ''
891 end
892
893 local function integer_keys(t)
894 if type(t) ~= 'table' then return 0 end
895 for k in pairs(t) do
896 local num = tonumber(k)
897 if num then return num end
898 end
899 return 0
900 end
901
902 function Item:return_type(r)
903 if not r.type then return '' end
904 return r.type, r.ctypes
905 end
906
907 local struct_return_type = '*'
908
909 function Item:build_return_groups()
910 local modifiers = self.modifiers
911 local retmod = modifiers['return']
912 local groups = List()
913 local lastg, group
914 for i,ret in ipairs(self.ret) do
915 local mods = retmod[i]
916 local g = integer_keys(mods)
917 if g ~= lastg then
918 group = List()
919 group.g = g
920 groups:append(group)
921 lastg = g
922 end
923 --require 'pl.pretty'.dump(ret)
924 if not mods then
925 self:error(quote(self.name)..' had no return?')
926 end
927 group:append({text=ret, type = mods and (mods.type or '') or '',mods = mods})
928 end
929 -- order by groups to force error groups to the end
930 table.sort(groups,function(g1,g2) return g1.g < g2.g end)
931 self.retgroups = groups
932 --require 'pl.pretty'.dump(groups)
933 -- cool, now see if there are any treturns that have tfields to associate with
934 local fields = self.tags.field
935 if fields then
936 local fcomments = List()
937 for i,f in ipairs(fields) do
938 local name, comment = self:split_param(f)
939 fields[i] = name
940 fcomments[i] = comment
941 end
942 local fmods = modifiers.field
943 for group in groups:iter() do for r in group:iter() do
944 if r.mods and r.mods.type then
945 local ctypes, T = List(), r.mods.type
946 for i,f in ipairs(fields) do if fmods[i][T] then
947 ctypes:append {name=f,type=fmods[i].type,comment=fcomments[i]}
948 end end
949 r.ctypes = ctypes
950 --require 'pl.pretty'.dump(ctypes)
951 end
952 end end
953 end
954 end
955
956 local ecount = 0
957
958 -- this alias macro implements @error.
959 -- Alias macros need to return the same results as Item:check_tags...
960 function doc.error_macro(tags,value,modifiers)
961 local merge_groups = doc.ldoc.merge_error_groups
962 local g = '2' -- our default group id
963 -- Were we given an explicit group modifier?
964 local key = integer_keys(modifiers)
965 if key > 0 then
966 g = tostring(key)
967 else
968 local l = tags:get 'return'
969 if l then -- there were returns already......
970 -- maximum group of _existing_ error return
971 local grp, lastr = 0
972 for r in l:iter() do if type(r) == 'table' then
973 local rg = r.modifiers._err
974 if rg then
975 lastr = r
976 grp = math.max(grp,rg)
977 end
978 end end
979 if grp > 0 then -- cool, create new group
980 if not merge_groups then
981 g = tostring(grp+1)
982 else
983 local mods, text, T = lastr.modifiers
984 local new = function(text)
985 return mods._collected..' '..text,{type='string',[T]=true}
986 end
987 if not mods._collected then
988 text = lastr[1]
989 lastr[1] = merge_groups
990 T = '@'..ecount
991 mods.type = T
992 mods._collected = 1
993 ecount = ecount + 1
994 tags:add('field',new(text))
995 else
996 T = mods.type
997 end
998 mods._collected = mods._collected + 1
999 return 'field',new(value)
1000 end
1001 end
1002 end
1003 end
1004 tags:add('return','',{[g]=true,type='nil'})
1005 -- note that this 'return' is tagged with _err!
1006 return 'return', value, {[g]=true,_err=tonumber(g),type='string'}
1007 end
1008
1009 ---------- bothering the user --------------------
7961010
7971011 function Item:warning(msg)
7981012 local file = self.file and self.file.filename
8261040 local err = io.stderr
8271041
8281042 local function custom_see_references (s)
829 for pat, action in pairs(see_reference_handlers) do
830 if s:match(pat) then
831 local label, href = action(s:match(pat))
832 if not label then print('custom rule failed',s,pat,href) end
833 return {href = href, label = label}
834 end
835 end
1043 for pat, action in pairs(see_reference_handlers) do
1044 if s:match(pat) then
1045 local label, href = action(s:match(pat))
1046 if not label then print('custom rule failed',s,pat,href) end
1047 return {href = href, label = label}
1048 end
1049 end
8361050 end
8371051
8381052 local function reference (s, mod_ref, item_ref)
8391053 local name = item_ref and item_ref.name or ''
8401054 -- this is deeply hacky; classes have 'Class ' prepended.
841 if item_ref and doc.class_tag(item_ref.type) then
842 name = 'Class_'..name
843 end
1055 --~ if item_ref and doc.class_tag(item_ref.type) then
1056 --~ name = 'Class_'..name
1057 --~ end
8441058 return {mod = mod_ref, name = name, label=s}
8451059 end
8461060
1061 function Module:lookup_class_item (packmod, s)
1062 local klass = packmod --"Class_"..packmod
1063 local qs = klass..':'..s
1064 local klass_section = self.sections.by_name[klass]
1065 if not klass_section then return nil end -- no such class
1066 for item in self.items:iter() do
1067 --print('item',qs,item.name)
1068 if s == item.name or qs == item.name then
1069 return reference(s,self,item)
1070 end
1071 end
1072 return nil
1073 end
1074
8471075 function Module:process_see_reference (s,modules,istype)
1076 if s == nil then return nil end
8481077 local mod_ref,fun_ref,name,packmod
8491078 local ref = custom_see_references(s)
8501079 if ref then return ref end
8511080 if not s:match '^[%w_%.%:%-]+$' or not s:match '[%w_]$' then
8521081 return nil, "malformed see reference: '"..s..'"'
8531082 end
1083
1084 -- `istype` means that we are looking up strictly in a _type_ context, so then only
1085 -- allow `classmod` module references.
8541086 local function ismod(item)
8551087 if item == nil then return false end
8561088 if not istype then return true
8581090 return item.type == 'classmod'
8591091 end
8601092 end
1093
1094 -- it is _entirely_ possible that someone does not want auto references for standard Lua libraries!
1095 local lua_manual_ref
1096 local ldoc = tools.item_ldoc(self)
1097 if ldoc and ldoc.no_lua_ref then
1098 lua_manual_ref = function(s) return false end
1099 else
1100 lua_manual_ref = global.lua_manual_ref
1101 end
1102
8611103 -- is this a fully qualified module name?
8621104 local mod_ref = modules.by_name[s]
8631105 if ismod(mod_ref) then return reference(s, mod_ref,nil) end
8741116 if not mod_ref then
8751117 mod_ref = self:hunt_for_reference(packmod, modules)
8761118 if not mod_ref then
877 local ref = global.lua_manual_ref(s)
1119 local ref = self:lookup_class_item(packmod,s)
1120 if ref then return ref end
1121 local mod, klass = split_dotted_name(packmod)
1122 mod_ref = modules.by_name[mod]
1123 if mod_ref then
1124 ref = mod_ref:lookup_class_item(klass,name)
1125 if ref then return ref end
1126 end
1127 ref = lua_manual_ref(s)
8781128 if ref then return ref end
8791129 return nil,"module not found: "..packmod
8801130 end
8811131 end
882 fun_ref = mod_ref.items.by_name[name]
1132 fun_ref = mod_ref:get_fun_ref(name)
8831133 if fun_ref then
8841134 return reference(s,mod_ref,fun_ref)
8851135 else
8931143 else -- plain jane name; module in this package, function in this module
8941144 mod_ref = modules.by_name[self.package..'.'..s]
8951145 if ismod(mod_ref) then return reference(s, mod_ref,nil) end
896 fun_ref = self.items.by_name[s]
897 if fun_ref then return reference(s, self,fun_ref)
1146 fun_ref = self:get_fun_ref(s)
1147 if fun_ref then return reference(s,self,fun_ref)
8981148 else
899 local ref = global.lua_manual_ref (s)
1149 local ref = lua_manual_ref (s)
9001150 if ref then return ref end
9011151 return nil, "function not found: "..s.." in this module"
9021152 end
9031153 end
9041154 end
1155
1156 function Module:get_fun_ref(s)
1157 local fun_ref = self.items.by_name[s]
1158 -- did not get an exact match, so try to match by the unqualified fun name
1159 if not fun_ref then
1160 local patt = '[.:]'..s..'$'
1161 for qname,ref in pairs(self.items.by_name) do
1162 if qname:match(patt) then
1163 fun_ref = ref
1164 break
1165 end
1166 end
1167 end
1168 return fun_ref
1169 end
1170
9051171
9061172 -- resolving @see references. A word may be either a function in this module,
9071173 -- or a module in this package. A MOD.NAME reference is within this package.
9341200 end
9351201 end
9361202
937 -- suppress the display of local functions and annotations.
938 -- This is just a placeholder hack until we have a more general scheme
939 -- for indicating 'private' content of a module.
940 function Module:mask_locals ()
941 self.kinds['Local Functions'] = nil
942 self.kinds['Annotations'] = nil
943 end
944
9451203 function Item:dump_tags (taglist)
9461204 for tag, value in pairs(self.tags) do
9471205 if not taglist or taglist[tag] then
2828 text-decoration: none;
2929 }
3030 li {
31 list-style: bullet;
31 list-style: disc;
3232 margin-left: 20px;
3333 }
3434 caption,th {
252252 border-style: solid;
253253 border-color: #cccccc;
254254 }
255 table.module_list td.name { background-color: #f0f0f0; ; min-width: 200px; }
255 table.module_list td.name { background-color: #f0f0f0; min-width: 200px; }
256256 table.module_list td.summary { width: 100%; }
257257
258258
268268 border-style: solid;
269269 border-color: #cccccc;
270270 }
271 table.function_list td.name { background-color: #f0f0f0; ; min-width: 200px; }
271 table.function_list td.name { background-color: #f0f0f0; min-width: 200px; }
272272 table.function_list td.summary { width: 100%; }
273
274 ul.nowrap {
275 overflow:auto;
276 white-space:nowrap;
277 }
273278
274279 dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;}
275280 dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;}
2323 # local use_li = ldoc.use_li
2424 # local display_name = ldoc.display_name
2525 # local iter = ldoc.modules.iter
26 # ---local M = ldoc.markup
2726 # local function M(txt,item) return ldoc.markup(txt,item,ldoc.plain) end
2827 # local nowrap = ldoc.wrap and '' or 'nowrap'
2928
5352 # if ldoc.no_summary and module and not ldoc.one then -- bang out the functions on the side
5453 # for kind, items in module.kinds() do
5554 <h2>$(kind)</h2>
56 <ul>
55 <ul class="nowrap">
5756 # for item in items() do
5857 <li><a href="#$(item.name)">$(display_name(item))</a></li>
5958 # end
6160 # end
6261 # end
6362 # -------- contents of project ----------
64 # -- if not ldoc.no_summary then
6563 # local this_mod = module and module.name
6664 # for kind, mods, type in ldoc.kinds() do
6765 # if not ldoc.kinds_allowed or ldoc.kinds_allowed[type] then
6866 <h2>$(kind)</h2>
69 <ul>
70 # for mod in mods() do
71 # if mod.name == this_mod then -- highlight current module, link to others
72 <li><strong>$(mod.name)</strong></li>
67 <ul class="$(kind=='Topics' and '' or 'nowrap'">
68 # for mod in mods() do local name = ldoc.module_name(mod)
69 # if mod.name == this_mod then
70 <li><strong>$(name)</strong></li>
7371 # else
74 <li><a href="$(ldoc.ref_to_module(mod))">$(mod.name)</a></li>
72 <li><a href="$(ldoc.ref_to_module(mod))">$(name)</a></li>
7573 # end
7674 # end
7775 # end
78 # -- end
7976 </ul>
8077 # end
8178
8279 </div>
8380
8481 <div id="content">
85
86 #if module then
87 <h1>$(ldoc.module_typename(module)) <code>$(module.name)</code></h1>
88 # end
8982
9083 # if ldoc.body then -- verbatim HTML as contents; 'non-code' entries
9184 $(ldoc.body)
9285 # elseif module then -- module documentation
86 <h1>$(ldoc.module_typename(module)) <code>$(module.name)</code></h1>
9387 <p>$(M(module.summary,module))</p>
9488 <p>$(M(module.description,module))</p>
9589 # if module.usage then
10498 # if module.info then
10599 <h3>Info:</h3>
106100 <ul>
107 # for tag, value in ldoc.pairs(module.info) do
101 # for tag, value in module.info:iter() do
108102 <li><strong>$(tag)</strong>: $(M(value,module))</li>
109103 # end
110104 </ul>
154148 <dd>
155149 $(M(ldoc.descript(item),item))
156150
151 # if ldoc.custom_tags then
152 # for custom in iter(ldoc.custom_tags) do
153 # local tag = item.tags[custom[1]]
154 # if tag and not custom.hidden then
155 # local li,il = use_li(tag)
156 <h3>$(custom.title or custom[1]):</h3>
157 <ul>
158 # for value in iter(tag) do
159 $(li)$(custom.format and custom.format(value) or M(value))$(il)
160 # end -- for
161 # end -- if tag
162 </ul>
163 # end -- iter tags
164 # end
165
157166 # if show_parms and item.params and #item.params > 0 then
158 <h3>$(module.kinds:type_of(item).subnames):</h3>
167 # local subnames = module.kinds:type_of(item).subnames
168 # if subnames then
169 <h3>$(subnames):</h3>
170 # end
159171 <ul>
160172 # for parm in iter(item.params) do
161173 # local param,sublist = item:subparam(parm)
173185 # if def then
174186 (<em>default</em> $(def))
175187 # end
188 # if item:readonly(p) then
189 <em>readonly</em>
190 # end
176191 </li>
177192 # end
178193 # if sublist then
182197 </ul>
183198 # end -- if params
184199
185 # if show_return and item.ret then
186 # local li,il = use_li(item.ret)
200 # if show_return and item.retgroups then local groups = item.retgroups
187201 <h3>Returns:</h3>
202 # for i,group in ldoc.ipairs(groups) do local li,il = use_li(group)
188203 <ol>
189 # for i,r in ldoc.ipairs(item.ret) do
204 # for r in group:iter() do local type, ctypes = item:return_type(r); local rt = ldoc.typename(type)
190205 $(li)
191 # local tp = ldoc.typename(item:type_of_ret(i))
192 # if tp ~= '' then
193 <span class="types">$(tp)</span>
194 # end
195 $(M(r,item))$(il)
196 # end -- for
206 # if rt ~= '' then
207 <span class="types">$(rt)</span>
208 # end
209 $(M(r.text,item))$(il)
210 # if ctypes then
211 <ul>
212 # for c in ctypes:iter() do
213 <li><span class="parameter">$(c.name)</span>
214 <span class="types">$(ldoc.typename(c.type))</span>
215 $(M(c.comment,item))</li>
216 # end
217 </ul>
218 # end -- if ctypes
219 # end -- for r
197220 </ol>
221 # if i < #groups then
222 <h3>Or</h3>
223 # end
224 # end -- for group
198225 # end -- if returns
199226
200227 # if show_return and item.raise then
253280 </div> <!-- id="content" -->
254281 </div> <!-- id="main" -->
255282 <div id="about">
256 <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.0</a></i>
283 <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.2</a></i>
257284 </div> <!-- id="about" -->
258285 </div> <!-- id="container" -->
259286 </body>
0 return [[
1 > local lev = ldoc.level or 2
2 > local lev1,lev2 = ('#'):rep(lev),('#'):rep(lev+1)
3 > for kind, items in module.kinds() do
4 > local kitem = module.kinds:get_item(kind)
5 > if kitem then
6 $(lev1) $(ldoc.descript(kitem))
7
8 > end
9 > for item in items() do
10 $(lev2) $(ldoc.display_name(item))
11
12 $(ldoc.descript(item))
13
14 > end
15 > end
16 ]]
+0
-17
ldoc/html/ldoc_mdtp.lua less more
0 return [[
1 > local lev = ldoc.level or 2
2 > local lev1,lev2 = ('#'):rep(lev),('#'):rep(lev+1)
3 > for kind, items in module.kinds() do
4 > local kitem = module.kinds:get_item(kind)
5 > if kitem then
6 $(lev1) $(ldoc.descript(kitem))
7
8 > end
9 > for item in items() do
10 $(lev2) $(ldoc.display_name(item))
11
12 $(ldoc.descript(item))
13
14 > end
15 > end
16 ]]
0 return [[/* BEGIN RESET
1
2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 2.8.2r1
6 */
7 html {
8 color: #000;
9 background: #FFF;
10 }
11 body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td {
12 margin: 0;
13 padding: 0;
14 }
15 table {
16 border-collapse: collapse;
17 border-spacing: 0;
18 }
19 fieldset,img {
20 border: 0;
21 }
22 address,caption,cite,code,dfn,em,strong,th,var,optgroup {
23 font-style: inherit;
24 font-weight: inherit;
25 }
26 del,ins {
27 text-decoration: none;
28 }
29 li {
30 list-style: bullet;
31 margin-left: 20px;
32 }
33 caption,th {
34 text-align: left;
35 }
36 h1,h2,h3,h4,h5,h6 {
37 font-size: 100%;
38 font-weight: bold;
39 }
40 q:before,q:after {
41 content: '';
42 }
43 abbr,acronym {
44 border: 0;
45 font-variant: normal;
46 }
47 sup {
48 vertical-align: baseline;
49 }
50 sub {
51 vertical-align: baseline;
52 }
53 legend {
54 color: #000;
55 }
56 input,button,textarea,select,optgroup,option {
57 font-family: inherit;
58 font-size: inherit;
59 font-style: inherit;
60 font-weight: inherit;
61 }
62 input,button,textarea,select {*font-size:100%;
63 }
64 /* END RESET */
65
66 body {
67 margin-left: 1em;
68 margin-right: 1em;
69 font-family: arial, helvetica, geneva, sans-serif;
70 background-color: #ffffff; margin: 0px;
71 }
72
73 code, tt { font-family: monospace; }
74 span.parameter { font-family:monospace; }
75 span.parameter:after { content:":"; }
76 span.types:before { content:"("; }
77 span.types:after { content:")"; }
78 .type { font-weight: bold; font-style:italic }
79
80 body, p, td, th { font-size: .95em; line-height: 1.2em;}
81
82 p, ul { margin: 10px 0 0 0px;}
83
84 strong { font-weight: bold;}
85
86 em { font-style: italic;}
87
88 h1 {
89 font-size: 1.5em;
90 margin: 0 0 20px 0;
91 }
92 h2, h3, h4 { margin: 15px 0 10px 0; }
93 h2 { font-size: 1.25em; }
94 h3 { font-size: 1.15em; }
95 h4 { font-size: 1.06em; }
96
97 a:link { font-weight: bold; color: #004080; text-decoration: none; }
98 a:visited { font-weight: bold; color: #006699; text-decoration: none; }
99 a:link:hover { text-decoration: underline; }
100
101 hr {
102 color:#cccccc;
103 background: #00007f;
104 height: 1px;
105 }
106
107 blockquote { margin-left: 3em; }
108
109 ul { list-style-type: disc; }
110
111 p.name {
112 font-family: "Andale Mono", monospace;
113 padding-top: 1em;
114 }
115
116 pre.example {
117 background-color: rgb(245, 245, 245);
118 border: 1px solid silver;
119 padding: 10px;
120 margin: 10px 0 10px 0;
121 font-family: "Andale Mono", monospace;
122 font-size: .85em;
123 }
124
125 pre {
126 background-color: rgb(245,245,255); // rgb(245, 245, 245);
127 border: 1px solid #cccccc; //silver;
128 padding: 10px;
129 margin: 10px 0 10px 0;
130 overflow: auto;
131 font-family: "Andale Mono", monospace;
132 }
133
134
135 table.index { border: 1px #00007f; }
136 table.index td { text-align: left; vertical-align: top; }
137
138 #container {
139 margin-left: 1em;
140 margin-right: 1em;
141 background-color: #f0f0f0;
142 }
143
144 #product {
145 text-align: center;
146 border-bottom: 1px solid #cccccc;
147 background-color: #ffffff;
148 }
149
150 #product big {
151 font-size: 2em;
152 }
153
154 #main {
155 background-color:#FFFFFF; // #f0f0f0;
156 //border-left: 2px solid #cccccc;
157 }
158
159 #navigation {
160 float: left;
161 width: 14em;
162 vertical-align: top;
163 background-color:#FFFFFF; // #f0f0f0;
164 overflow: visible;
165 }
166
167 #navigation h2 {
168 background-color:#FFFFFF;//:#e7e7e7;
169 font-size:1.1em;
170 color:#000000;
171 text-align: left;
172 padding:0.2em;
173 //border-top:1px solid #dddddd;
174 border-bottom:1px solid #dddddd;
175 }
176
177 #navigation ul
178 {
179 font-size:1em;
180 list-style-type: none;
181 margin: 1px 1px 10px 1px;
182 }
183
184 #navigation li {
185 text-indent: -1em;
186 display: block;
187 margin: 3px 0px 0px 22px;
188 }
189
190 #navigation li li a {
191 margin: 0px 3px 0px -1em;
192 }
193
194 #content {
195 margin-left: 14em;
196 padding: 1em;
197 width: 700px;
198 border-left: 2px solid #cccccc;
199 // border-right: 2px solid #cccccc;
200 background-color: #ffffff;
201 }
202
203 #about {
204 clear: both;
205 padding: 5px;
206 border-top: 2px solid #cccccc;
207 background-color: #ffffff;
208 }
209
210 @media print {
211 body {
212 font: 12pt "Times New Roman", "TimeNR", Times, serif;
213 }
214 a { font-weight: bold; color: #004080; text-decoration: underline; }
215
216 #main {
217 background-color: #ffffff;
218 border-left: 0px;
219 }
220
221 #container {
222 margin-left: 2%;
223 margin-right: 2%;
224 background-color: #ffffff;
225 }
226
227 #content {
228 padding: 1em;
229 background-color: #ffffff;
230 }
231
232 #navigation {
233 display: none;
234 }
235 pre.example {
236 font-family: "Andale Mono", monospace;
237 font-size: 10pt;
238 page-break-inside: avoid;
239 }
240 }
241
242 table.module_list {
243 border-width: 1px;
244 border-style: solid;
245 border-color: #cccccc;
246 border-collapse: collapse;
247 }
248 table.module_list td {
249 border-width: 1px;
250 padding: 3px;
251 border-style: solid;
252 border-color: #cccccc;
253 }
254 table.module_list td.name { background-color: #f0f0f0; ; min-width: 200px; }
255 table.module_list td.summary { width: 100%; }
256
257 table.function_list {
258 border-width: 1px;
259 border-style: solid;
260 border-color: #cccccc;
261 border-collapse: collapse;
262 }
263 table.function_list td {
264 border-width: 1px;
265 padding: 3px;
266 border-style: solid;
267 border-color: #cccccc;
268 }
269 table.function_list td.name { background-color: #f6f6ff; ; min-width: 200px; }
270 table.function_list td.summary { width: 100%; }
271
272 dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;}
273 dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;}
274 dl.table h3, dl.function h3 {font-size: .95em;}
275
276 ul.nowrap {
277 overflow:auto;
278 whitespace:nowrap;
279 }
280
281 /* stop sublists from having initial vertical space */
282 ul ul { margin-top: 0px; }
283 ol ul { margin-top: 0px; }
284 ol ol { margin-top: 0px; }
285 ul ol { margin-top: 0px; }
286
287 /* styles for prettification of source */
288 pre .comment { color: #558817; }
289 pre .constant { color: #a8660d; }
290 pre .escape { color: #844631; }
291 pre .keyword { color: #2239a8; font-weight: bold; }
292 pre .library { color: #0e7c6b; }
293 pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; }
294 pre .string { color: #a8660d; }
295 pre .number { color: #f8660d; }
296 pre .operator { color: #2239a8; font-weight: bold; }
297 pre .preprocessor, pre .prepro { color: #a33243; }
298 pre .global { color: #800080; }
299 pre .prompt { color: #558817; }
300 pre .url { color: #272fc2; text-decoration: underline; }
301 ]]
1818 local stringx = require 'pl.stringx'
1919 local template = require 'pl.template'
2020 local tablex = require 'pl.tablex'
21 local OrderedMap = require 'pl.OrderedMap'
2122 local tools = require 'ldoc.tools'
2223 local markup = require 'ldoc.markup'
2324 local prettify = require 'ldoc.prettify'
2425 local doc = require 'ldoc.doc'
26 local unpack = utils.unpack
2527 local html = {}
2628
2729
3739 end
3840
3941 local function get_module_info(m)
40 local info = {}
42 local info = OrderedMap()
4143 for tag in doc.module_info_tags() do
4244 local val = m.tags[tag]
4345 if type(val)=='table' then
4446 val = table.concat(val,',')
4547 end
4648 tag = stringx.title(tag)
47 info[tag] = val
48 end
49 if next(info) then
49 info:set(tag,val)
50 end
51 if #info:keys() > 0 then
5052 return info
5153 end
5254 end
9193 -- Item descriptions come from combining the summary and description fields
9294 function ldoc.descript(item)
9395 return (item.summary or '?')..' '..(item.description or '')
96 end
97
98 function ldoc.module_name (mod)
99 local name = mod.name
100 if args.unqualified and (mod.type == 'module' or mod.type == 'classmod') then -- leave out package
101 name = name:gsub('^.-%.','')
102 elseif mod.type == 'topic' then
103 if mod.display_name then
104 name = mod.display_name
105 else -- leave out md extension
106 name = name:gsub('%..*$','')
107 end
108 end
109 return name
94110 end
95111
96112 -- this generates the internal module/function references
140156 if #ls > 1 then return '<li>','</li>' else return '','' end
141157 end
142158
143 function ldoc.display_name(item)
159 function ldoc.default_display_name(item)
144160 local name = item.display_name or item.name
145161 if item.type == 'function' or item.type == 'lfunction' then
146162 if not ldoc.no_space_before_args then
152168 end
153169 end
154170
171 function ldoc.display_name(item)
172 if ldoc.custom_display_name_handler then
173 return ldoc.custom_display_name_handler(item, ldoc.default_display_name)
174 else
175 return ldoc.default_display_name(item)
176 end
177 end
178
155179 function ldoc.no_spaces(s)
156180 s = s:gsub('%s*$','')
157181 return (s:gsub('%W','_'))
166190 end
167191
168192 function ldoc.typename (tp)
169 if not tp or tp == '' then return '' end
193 if not tp or tp == '' or tp:match '^@' then return '' end
170194 local optional
171195 -- ?<type> is short for ?nil|<type>
172196 if tp:match("^%?") and not tp:match '|' then
177201 optional = true
178202 tp = tp2
179203 end
204
180205 local types = {}
181206 for name in tp:gmatch("[^|]+") do
182 local ref,err = markup.process_reference(name,true)
207 local sym = name:match '([%w%.%:]+)'
208 local ref,err = markup.process_reference(sym,true)
183209 if ref then
184 types[#types+1] = ('<a class="type" href="%s">%s</a>'):format(ldoc.href(ref),ref.label or name)
210 if ref.label and sym == name then
211 name = ref.label
212 end
213 types[#types+1] = ('<a class="type" href="%s">%s</a>'):format(ldoc.href(ref),name)
185214 else
186215 types[#types+1] = '<span class="type">'..name..'</span>'
187216 end
7373 self.line_comment = '^%-%-+' -- used for stripping
7474 self.start_comment_ = '^%-%-%-+' -- used for doc comment line start
7575 self.block_comment = '^%-%-%[=*%[%-+' -- used for block doc comments
76 self.end_comment_ = '[^%-]%-%-+\n$' ---- exclude --- this kind of comment ---
76 self.end_comment_ = '[^%-]%-%-+[^-]*\n$' ---- exclude --- this kind of comment ---
7777 self.method_call = ':'
7878 self:finalize()
7979 end
8686
8787 function Lua:grab_block_comment(v,tok)
8888 local equals = v:match('^%-%-%[(=*)%[')
89 if not equals then return v end
8990 v = v:gsub(self.block_comment,'')
9091 return tools.grab_block_comment(v,tok,'%]'..equals..'%]')
9192 end
261262 end
262263
263264 function CC:grab_block_comment(v,tok)
264 v = v:gsub(self.block_comment,'')
265 v = v:gsub(self.block_comment,''):gsub('\n%s*%*','\n')
265266 return 'comment',v:sub(1,-3)
267 end
268
269 --- here the argument name is always last, and the type is composed of any tokens before
270 function CC:extract_arg (tl,idx)
271 idx = idx or 1
272 local res = List()
273 for i = idx,#tl-1 do
274 res:append(tl[i][2])
275 end
276 local type = res:join ' '
277 return tl[#tl][2], type
278 end
279
280 function CC:item_follows (t,v,tok)
281 if not self.extra.C then
282 return false
283 end
284 if t == 'iden' or t == 'keyword' then --
285 if v == self.extra.export then -- this is not part of the return type!
286 t,v = tnext(tok)
287 end
288 -- types may have multiple tokens: example, const char *bonzo(...)
289 local return_type, name = v
290 t,v = tnext(tok)
291 name = v
292 t,v = tnext(tok)
293 while t ~= '(' do
294 return_type = return_type .. ' ' .. name
295 name = v
296 t,v = tnext(tok)
297 end
298 --print ('got',name,t,v,return_type)
299 return function(tags,tok)
300 if not tags.name then
301 tags:add('name',name)
302 end
303 tags:add('class','function')
304 if t == '(' then
305 tags.formal_args,t,v = tools.get_parameters(tok,')',',',self)
306 if return_type ~= 'void' then
307 tags.formal_args.return_type = return_type
308 end
309 end
310 end
311 end
312 return false
266313 end
267314
268315 local Moon = class(Lua)
370370 {'^|=',tdump},
371371 {'^%^=',tdump},
372372 {'^::',tdump},
373 {'^%.%.%.',tdump},
373374 {'^.',tdump}
374375 }
375376 end
0 #!/usr/bin/env lua
1
2 --[[
3 # markdown.lua -- version 0.32
4
5 <http://www.frykholm.se/files/markdown.lua>
6
7 **Author:** Niklas Frykholm, <niklas@frykholm.se>
8 **Date:** 31 May 2008
9
10 This is an implementation of the popular text markup language Markdown in pure Lua.
11 Markdown can convert documents written in a simple and easy to read text format
12 to well-formatted HTML. For a more thourough description of Markdown and the Markdown
13 syntax, see <http://daringfireball.net/projects/markdown>.
14
15 The original Markdown source is written in Perl and makes heavy use of advanced
16 regular expression techniques (such as negative look-ahead, etc) which are not available
17 in Lua's simple regex engine. Therefore this Lua port has been rewritten from the ground
18 up. It is probably not completely bug free. If you notice any bugs, please report them to
19 me. A unit test that exposes the error is helpful.
20
21 ## Usage
22
23 require "markdown"
24 markdown(source)
25
26 ``markdown.lua`` exposes a single global function named ``markdown(s)`` which applies the
27 Markdown transformation to the specified string.
28
29 ``markdown.lua`` can also be used directly from the command line:
30
31 lua markdown.lua test.md
32
33 Creates a file ``test.html`` with the converted content of ``test.md``. Run:
34
35 lua markdown.lua -h
36
37 For a description of the command-line options.
38
39 ``markdown.lua`` uses the same license as Lua, the MIT license.
40
41 ## License
42
43 Copyright &copy; 2008 Niklas Frykholm.
44
45 Permission is hereby granted, free of charge, to any person obtaining a copy of this
46 software and associated documentation files (the "Software"), to deal in the Software
47 without restriction, including without limitation the rights to use, copy, modify, merge,
48 publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
49 to whom the Software is furnished to do so, subject to the following conditions:
50
51 The above copyright notice and this permission notice shall be included in all copies
52 or substantial portions of the Software.
53
54 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
56 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
57 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
58 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
59 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
60 THE SOFTWARE.
61
62 ## Version history
63
64 - **0.32** -- 31 May 2008
65 - Fix for links containing brackets
66 - **0.31** -- 1 Mar 2008
67 - Fix for link definitions followed by spaces
68 - **0.30** -- 25 Feb 2008
69 - Consistent behavior with Markdown when the same link reference is reused
70 - **0.29** -- 24 Feb 2008
71 - Fix for <pre> blocks with spaces in them
72 - **0.28** -- 18 Feb 2008
73 - Fix for link encoding
74 - **0.27** -- 14 Feb 2008
75 - Fix for link database links with ()
76 - **0.26** -- 06 Feb 2008
77 - Fix for nested italic and bold markers
78 - **0.25** -- 24 Jan 2008
79 - Fix for encoding of naked <
80 - **0.24** -- 21 Jan 2008
81 - Fix for link behavior.
82 - **0.23** -- 10 Jan 2008
83 - Fix for a regression bug in longer expressions in italic or bold.
84 - **0.22** -- 27 Dec 2007
85 - Fix for crash when processing blocks with a percent sign in them.
86 - **0.21** -- 27 Dec 2007
87 - Fix for combined strong and emphasis tags
88 - **0.20** -- 13 Oct 2007
89 - Fix for < as well in image titles, now matches Dingus behavior
90 - **0.19** -- 28 Sep 2007
91 - Fix for quotation marks " and ampersands & in link and image titles.
92 - **0.18** -- 28 Jul 2007
93 - Does not crash on unmatched tags (behaves like standard markdown)
94 - **0.17** -- 12 Apr 2007
95 - Fix for links with %20 in them.
96 - **0.16** -- 12 Apr 2007
97 - Do not require arg global to exist.
98 - **0.15** -- 28 Aug 2006
99 - Better handling of links with underscores in them.
100 - **0.14** -- 22 Aug 2006
101 - Bug for *`foo()`*
102 - **0.13** -- 12 Aug 2006
103 - Added -l option for including stylesheet inline in document.
104 - Fixed bug in -s flag.
105 - Fixed emphasis bug.
106 - **0.12** -- 15 May 2006
107 - Fixed several bugs to comply with MarkdownTest 1.0 <http://six.pairlist.net/pipermail/markdown-discuss/2004-December/000909.html>
108 - **0.11** -- 12 May 2006
109 - Fixed bug for escaping `*` and `_` inside code spans.
110 - Added license terms.
111 - Changed join() to table.concat().
112 - **0.10** -- 3 May 2006
113 - Initial public release.
114
115 // Niklas
116 ]]
117
118
119 -- Set up a table for holding local functions to avoid polluting the global namespace
120 -- Penlight 1.2 defines compatible 5.1 setfenv in utils table
121 local M = {}
122 local MT = {__index = _G}
123 setmetatable(M, MT)
124
125 ----------------------------------------------------------------------
126 -- Utility functions
127 ----------------------------------------------------------------------
128
129 -- Locks table t from changes, writes an error if someone attempts to change the table.
130 -- This is useful for detecting variables that have "accidently" been made global. Something
131 -- I tend to do all too much.
132 function M.lock(t)
133 local function lock_new_index(t, k, v)
134 error("module has been locked -- " .. k .. " must be declared local", 2)
135 end
136
137 local mt = {__newindex = lock_new_index}
138 if getmetatable(t) then
139 mt.__index = getmetatable(t).__index
140 end
141 setmetatable(t, mt)
142 end
143
144 -- Returns the result of mapping the values in table t through the function f
145 local function map(t, f)
146 local out = {}
147 for k,v in pairs(t) do out[k] = f(v,k) end
148 return out
149 end
150
151 -- The identity function, useful as a placeholder.
152 local function identity(text) return text end
153
154 -- Functional style if statement. (NOTE: no short circuit evaluation)
155 local function iff(t, a, b) if t then return a else return b end end
156
157 -- Splits the text into an array of separate lines.
158 local function split(text, sep)
159 sep = sep or "\n"
160 local lines = {}
161 local pos = 1
162 while true do
163 local b,e = text:find(sep, pos)
164 if not b then table.insert(lines, text:sub(pos)) break end
165 table.insert(lines, text:sub(pos, b-1))
166 pos = e + 1
167 end
168 return lines
169 end
170
171 -- Converts tabs to spaces
172 local function detab(text)
173 local tab_width = 4
174 local function rep(match)
175 local spaces = -match:len()
176 while spaces<1 do spaces = spaces + tab_width end
177 return match .. string.rep(" ", spaces)
178 end
179 text = text:gsub("([^\n]-)\t", rep)
180 return text
181 end
182
183 -- Applies string.find for every pattern in the list and returns the first match
184 local function find_first(s, patterns, index)
185 local res = {}
186 for _,p in ipairs(patterns) do
187 local match = {s:find(p, index)}
188 if #match>0 and (#res==0 or match[1] < res[1]) then res = match end
189 end
190 return unpack(res)
191 end
192
193 -- If a replacement array is specified, the range [start, stop] in the array is replaced
194 -- with the replacement array and the resulting array is returned. Without a replacement
195 -- array the section of the array between start and stop is returned.
196 local function splice(array, start, stop, replacement)
197 if replacement then
198 local n = stop - start + 1
199 while n > 0 do
200 table.remove(array, start)
201 n = n - 1
202 end
203 for i,v in ipairs(replacement) do
204 table.insert(array, start, v)
205 end
206 return array
207 else
208 local res = {}
209 for i = start,stop do
210 table.insert(res, array[i])
211 end
212 return res
213 end
214 end
215
216 -- Outdents the text one step.
217 local function outdent(text)
218 text = "\n" .. text
219 text = text:gsub("\n ? ? ?", "\n")
220 text = text:sub(2)
221 return text
222 end
223
224 -- Indents the text one step.
225 local function indent(text)
226 text = text:gsub("\n", "\n ")
227 return text
228 end
229
230 -- Does a simple tokenization of html data. Returns the data as a list of tokens.
231 -- Each token is a table with a type field (which is either "tag" or "text") and
232 -- a text field (which contains the original token data).
233 local function tokenize_html(html)
234 local tokens = {}
235 local pos = 1
236 while true do
237 local start = find_first(html, {"<!%-%-", "<[a-z/!$]", "<%?"}, pos)
238 if not start then
239 table.insert(tokens, {type="text", text=html:sub(pos)})
240 break
241 end
242 if start ~= pos then table.insert(tokens, {type="text", text = html:sub(pos, start-1)}) end
243
244 local _, stop
245 if html:match("^<!%-%-", start) then
246 _,stop = html:find("%-%->", start)
247 elseif html:match("^<%?", start) then
248 _,stop = html:find("?>", start)
249 else
250 _,stop = html:find("%b<>", start)
251 end
252 if not stop then
253 -- error("Could not match html tag " .. html:sub(start,start+30))
254 table.insert(tokens, {type="text", text=html:sub(start, start)})
255 pos = start + 1
256 else
257 table.insert(tokens, {type="tag", text=html:sub(start, stop)})
258 pos = stop + 1
259 end
260 end
261 return tokens
262 end
263
264 ----------------------------------------------------------------------
265 -- Hash
266 ----------------------------------------------------------------------
267
268 -- This is used to "hash" data into alphanumeric strings that are unique
269 -- in the document. (Note that this is not cryptographic hash, the hash
270 -- function is not one-way.) The hash procedure is used to protect parts
271 -- of the document from further processing.
272
273 local HASH = {
274 -- Has the hash been inited.
275 inited = false,
276
277 -- The unique string prepended to all hash values. This is to ensure
278 -- that hash values do not accidently coincide with an actual existing
279 -- string in the document.
280 identifier = "",
281
282 -- Counter that counts up for each new hash instance.
283 counter = 0,
284
285 -- Hash table.
286 table = {}
287 }
288
289 -- Inits hashing. Creates a hash_identifier that doesn't occur anywhere
290 -- in the text.
291 local function init_hash(text)
292 HASH.inited = true
293 HASH.identifier = ""
294 HASH.counter = 0
295 HASH.table = {}
296
297 local s = "HASH"
298 local counter = 0
299 local id
300 while true do
301 id = s .. counter
302 if not text:find(id, 1, true) then break end
303 counter = counter + 1
304 end
305 HASH.identifier = id
306 end
307
308 -- Returns the hashed value for s.
309 local function hash(s)
310 assert(HASH.inited)
311 if not HASH.table[s] then
312 HASH.counter = HASH.counter + 1
313 local id = HASH.identifier .. HASH.counter .. "X"
314 HASH.table[s] = id
315 end
316 return HASH.table[s]
317 end
318
319 ----------------------------------------------------------------------
320 -- Protection
321 ----------------------------------------------------------------------
322
323 -- The protection module is used to "protect" parts of a document
324 -- so that they are not modified by subsequent processing steps.
325 -- Protected parts are saved in a table for later unprotection
326
327 -- Protection data
328 local PD = {
329 -- Saved blocks that have been converted
330 blocks = {},
331
332 -- Block level tags that will be protected
333 tags = {"p", "div", "h1", "h2", "h3", "h4", "h5", "h6", "blockquote",
334 "pre", "table", "dl", "ol", "ul", "script", "noscript", "form", "fieldset",
335 "iframe", "math", "ins", "del"}
336 }
337
338 -- Pattern for matching a block tag that begins and ends in the leftmost
339 -- column and may contain indented subtags, i.e.
340 -- <div>
341 -- A nested block.
342 -- <div>
343 -- Nested data.
344 -- </div>
345 -- </div>
346 local function block_pattern(tag)
347 return "\n<" .. tag .. ".-\n</" .. tag .. ">[ \t]*\n"
348 end
349
350 -- Pattern for matching a block tag that begins and ends with a newline
351 local function line_pattern(tag)
352 return "\n<" .. tag .. ".-</" .. tag .. ">[ \t]*\n"
353 end
354
355 -- Protects the range of characters from start to stop in the text and
356 -- returns the protected string.
357 local function protect_range(text, start, stop)
358 local s = text:sub(start, stop)
359 local h = hash(s)
360 PD.blocks[h] = s
361 text = text:sub(1,start) .. h .. text:sub(stop)
362 return text
363 end
364
365 -- Protect every part of the text that matches any of the patterns. The first
366 -- matching pattern is protected first, etc.
367 local function protect_matches(text, patterns)
368 while true do
369 local start, stop = find_first(text, patterns)
370 if not start then break end
371 text = protect_range(text, start, stop)
372 end
373 return text
374 end
375
376 -- Protects blocklevel tags in the specified text
377 local function protect(text)
378 -- First protect potentially nested block tags
379 text = protect_matches(text, map(PD.tags, block_pattern))
380 -- Then protect block tags at the line level.
381 text = protect_matches(text, map(PD.tags, line_pattern))
382 -- Protect <hr> and comment tags
383 text = protect_matches(text, {"\n<hr[^>]->[ \t]*\n"})
384 text = protect_matches(text, {"\n<!%-%-.-%-%->[ \t]*\n"})
385 return text
386 end
387
388 -- Returns true if the string s is a hash resulting from protection
389 local function is_protected(s)
390 return PD.blocks[s]
391 end
392
393 -- Unprotects the specified text by expanding all the nonces
394 local function unprotect(text)
395 for k,v in pairs(PD.blocks) do
396 v = v:gsub("%%", "%%%%")
397 text = text:gsub(k, v)
398 end
399 return text
400 end
401
402
403 ----------------------------------------------------------------------
404 -- Block transform
405 ----------------------------------------------------------------------
406
407 -- The block transform functions transform the text on the block level.
408 -- They work with the text as an array of lines rather than as individual
409 -- characters.
410
411 -- Returns true if the line is a ruler of (char) characters.
412 -- The line must contain at least three char characters and contain only spaces and
413 -- char characters.
414 local function is_ruler_of(line, char)
415 if not line:match("^[ %" .. char .. "]*$") then return false end
416 if not line:match("%" .. char .. ".*%" .. char .. ".*%" .. char) then return false end
417 return true
418 end
419
420 -- Identifies the block level formatting present in the line
421 local function classify(line)
422 local info = {line = line, text = line}
423
424 if line:match("^ ") then
425 info.type = "indented"
426 info.outdented = line:sub(5)
427 return info
428 end
429
430 for _,c in ipairs({'*', '-', '_', '='}) do
431 if is_ruler_of(line, c) then
432 info.type = "ruler"
433 info.ruler_char = c
434 return info
435 end
436 end
437
438 if line == "" then
439 info.type = "blank"
440 return info
441 end
442
443 if line:match("^(#+)[ \t]*(.-)[ \t]*#*[ \t]*$") then
444 local m1, m2 = line:match("^(#+)[ \t]*(.-)[ \t]*#*[ \t]*$")
445 info.type = "header"
446 info.level = m1:len()
447 info.text = m2
448 return info
449 end
450
451 if line:match("^ ? ? ?(%d+)%.[ \t]+(.+)") then
452 local number, text = line:match("^ ? ? ?(%d+)%.[ \t]+(.+)")
453 info.type = "list_item"
454 info.list_type = "numeric"
455 info.number = 0 + number
456 info.text = text
457 return info
458 end
459
460 if line:match("^ ? ? ?([%*%+%-])[ \t]+(.+)") then
461 local bullet, text = line:match("^ ? ? ?([%*%+%-])[ \t]+(.+)")
462 info.type = "list_item"
463 info.list_type = "bullet"
464 info.bullet = bullet
465 info.text= text
466 return info
467 end
468
469 if line:match("^>[ \t]?(.*)") then
470 info.type = "blockquote"
471 info.text = line:match("^>[ \t]?(.*)")
472 return info
473 end
474
475 if is_protected(line) then
476 info.type = "raw"
477 info.html = unprotect(line)
478 return info
479 end
480
481 info.type = "normal"
482 return info
483 end
484
485 -- Find headers constisting of a normal line followed by a ruler and converts them to
486 -- header entries.
487 local function headers(array)
488 local i = 1
489 while i <= #array - 1 do
490 if array[i].type == "normal" and array[i+1].type == "ruler" and
491 (array[i+1].ruler_char == "-" or array[i+1].ruler_char == "=") then
492 local info = {line = array[i].line}
493 info.text = info.line
494 info.type = "header"
495 info.level = iff(array[i+1].ruler_char == "=", 1, 2)
496 table.remove(array, i+1)
497 array[i] = info
498 end
499 i = i + 1
500 end
501 return array
502 end
503
504 local block_transform, blocks_to_html, encode_code, span_transform, encode_backslash_escapes
505
506 -- Find list blocks and convert them to protected data blocks
507 local function lists(array, sublist)
508 local function process_list(arr)
509 local function any_blanks(arr)
510 for i = 1, #arr do
511 if arr[i].type == "blank" then return true end
512 end
513 return false
514 end
515
516 local function split_list_items(arr)
517 local acc = {arr[1]}
518 local res = {}
519 for i=2,#arr do
520 if arr[i].type == "list_item" then
521 table.insert(res, acc)
522 acc = {arr[i]}
523 else
524 table.insert(acc, arr[i])
525 end
526 end
527 table.insert(res, acc)
528 return res
529 end
530
531 local function process_list_item(lines, block)
532 while lines[#lines].type == "blank" do
533 table.remove(lines)
534 end
535
536 local itemtext = lines[1].text
537 for i=2,#lines do
538 itemtext = itemtext .. "\n" .. outdent(lines[i].line)
539 end
540 if block then
541 itemtext = block_transform(itemtext, true)
542 if not itemtext:find("<pre>") then itemtext = indent(itemtext) end
543 return " <li>" .. itemtext .. "</li>"
544 else
545 local lines = split(itemtext)
546 lines = map(lines, classify)
547 lines = lists(lines, true)
548 lines = blocks_to_html(lines, true)
549 itemtext = table.concat(lines, "\n")
550 if not itemtext:find("<pre>") then itemtext = indent(itemtext) end
551 return " <li>" .. itemtext .. "</li>"
552 end
553 end
554
555 local block_list = any_blanks(arr)
556 local items = split_list_items(arr)
557 local out = ""
558 for _, item in ipairs(items) do
559 out = out .. process_list_item(item, block_list) .. "\n"
560 end
561 if arr[1].list_type == "numeric" then
562 return "<ol>\n" .. out .. "</ol>"
563 else
564 return "<ul>\n" .. out .. "</ul>"
565 end
566 end
567
568 -- Finds the range of lines composing the first list in the array. A list
569 -- starts with (^ list_item) or (blank list_item) and ends with
570 -- (blank* $) or (blank normal).
571 --
572 -- A sublist can start with just (list_item) does not need a blank...
573 local function find_list(array, sublist)
574 local function find_list_start(array, sublist)
575 if array[1].type == "list_item" then return 1 end
576 if sublist then
577 for i = 1,#array do
578 if array[i].type == "list_item" then return i end
579 end
580 else
581 for i = 1, #array-1 do
582 if array[i].type == "blank" and array[i+1].type == "list_item" then
583 return i+1
584 end
585 end
586 end
587 return nil
588 end
589 local function find_list_end(array, start)
590 local pos = #array
591 for i = start, #array-1 do
592 if array[i].type == "blank" and array[i+1].type ~= "list_item"
593 and array[i+1].type ~= "indented" and array[i+1].type ~= "blank" then
594 pos = i-1
595 break
596 end
597 end
598 while pos > start and array[pos].type == "blank" do
599 pos = pos - 1
600 end
601 return pos
602 end
603
604 local start = find_list_start(array, sublist)
605 if not start then return nil end
606 return start, find_list_end(array, start)
607 end
608
609 while true do
610 local start, stop = find_list(array, sublist)
611 if not start then break end
612 local text = process_list(splice(array, start, stop))
613 local info = {
614 line = text,
615 type = "raw",
616 html = text
617 }
618 array = splice(array, start, stop, {info})
619 end
620
621 -- Convert any remaining list items to normal
622 for _,line in ipairs(array) do
623 if line.type == "list_item" then line.type = "normal" end
624 end
625
626 return array
627 end
628
629 -- Find and convert blockquote markers.
630 local function blockquotes(lines)
631 local function find_blockquote(lines)
632 local start
633 for i,line in ipairs(lines) do
634 if line.type == "blockquote" then
635 start = i
636 break
637 end
638 end
639 if not start then return nil end
640
641 local stop = #lines
642 for i = start+1, #lines do
643 if lines[i].type == "blank" or lines[i].type == "blockquote" then
644 elseif lines[i].type == "normal" then
645 if lines[i-1].type == "blank" then stop = i-1 break end
646 else
647 stop = i-1 break
648 end
649 end
650 while lines[stop].type == "blank" do stop = stop - 1 end
651 return start, stop
652 end
653
654 local function process_blockquote(lines)
655 local raw = lines[1].text
656 for i = 2,#lines do
657 raw = raw .. "\n" .. lines[i].text
658 end
659 local bt = block_transform(raw)
660 if not bt:find("<pre>") then bt = indent(bt) end
661 return "<blockquote>\n " .. bt ..
662 "\n</blockquote>"
663 end
664
665 while true do
666 local start, stop = find_blockquote(lines)
667 if not start then break end
668 local text = process_blockquote(splice(lines, start, stop))
669 local info = {
670 line = text,
671 type = "raw",
672 html = text
673 }
674 lines = splice(lines, start, stop, {info})
675 end
676 return lines
677 end
678
679 -- Find and convert codeblocks.
680 local function codeblocks(lines)
681 local function find_codeblock(lines)
682 local start
683 for i,line in ipairs(lines) do
684 if line.type == "indented" then start = i break end
685 end
686 if not start then return nil end
687
688 local stop = #lines
689 for i = start+1, #lines do
690 if lines[i].type ~= "indented" and lines[i].type ~= "blank" then
691 stop = i-1
692 break
693 end
694 end
695 while lines[stop].type == "blank" do stop = stop - 1 end
696 return start, stop
697 end
698
699 local function process_codeblock(lines)
700 local raw = detab(encode_code(outdent(lines[1].line)))
701 for i = 2,#lines do
702 raw = raw .. "\n" .. detab(encode_code(outdent(lines[i].line)))
703 end
704 return "<pre><code>" .. raw .. "\n</code></pre>"
705 end
706
707 while true do
708 local start, stop = find_codeblock(lines)
709 if not start then break end
710 local text = process_codeblock(splice(lines, start, stop))
711 local info = {
712 line = text,
713 type = "raw",
714 html = text
715 }
716 lines = splice(lines, start, stop, {info})
717 end
718 return lines
719 end
720
721 -- Convert lines to html code
722 function blocks_to_html(lines, no_paragraphs)
723 local out = {}
724 local i = 1
725 while i <= #lines do
726 local line = lines[i]
727 if line.type == "ruler" then
728 table.insert(out, "<hr/>")
729 elseif line.type == "raw" then
730 table.insert(out, line.html)
731 elseif line.type == "normal" then
732 local s = line.line
733
734 while i+1 <= #lines and lines[i+1].type == "normal" do
735 i = i + 1
736 s = s .. "\n" .. lines[i].line
737 end
738
739 if no_paragraphs then
740 table.insert(out, span_transform(s))
741 else
742 table.insert(out, "<p>" .. span_transform(s) .. "</p>")
743 end
744 elseif line.type == "header" then
745 local s = "<h" .. line.level .. ">" .. span_transform(line.text) .. "</h" .. line.level .. ">"
746 table.insert(out, s)
747 else
748 table.insert(out, line.line)
749 end
750 i = i + 1
751 end
752 return out
753 end
754
755 -- Perform all the block level transforms
756 function block_transform(text, sublist)
757 local lines = split(text)
758 lines = map(lines, classify)
759 lines = headers(lines)
760 lines = lists(lines, sublist)
761 lines = codeblocks(lines)
762 lines = blockquotes(lines)
763 lines = blocks_to_html(lines)
764 local text = table.concat(lines, "\n")
765 return text
766 end
767
768 -- Debug function for printing a line array to see the result
769 -- of partial transforms.
770 local function print_lines(lines)
771 for i, line in ipairs(lines) do
772 print(i, line.type, line.text or line.line)
773 end
774 end
775
776 ----------------------------------------------------------------------
777 -- Span transform
778 ----------------------------------------------------------------------
779
780 -- Functions for transforming the text at the span level.
781
782 -- These characters may need to be escaped because they have a special
783 -- meaning in markdown.
784 local escape_chars = "'\\`*_{}[]()>#+-.!'"
785 local escape_table = {}
786
787 local function init_escape_table()
788 escape_table = {}
789 for i = 1,#escape_chars do
790 local c = escape_chars:sub(i,i)
791 escape_table[c] = hash(c)
792 end
793 end
794
795 -- Adds a new escape to the escape table.
796 local function add_escape(text)
797 if not escape_table[text] then
798 escape_table[text] = hash(text)
799 end
800 return escape_table[text]
801 end
802
803 -- Escape characters that should not be disturbed by markdown.
804 local function escape_special_chars(text)
805 local tokens = tokenize_html(text)
806
807 local out = ""
808 for _, token in ipairs(tokens) do
809 local t = token.text
810 if token.type == "tag" then
811 -- In tags, encode * and _ so they don't conflict with their use in markdown.
812 t = t:gsub("%*", escape_table["*"])
813 t = t:gsub("%_", escape_table["_"])
814 else
815 t = encode_backslash_escapes(t)
816 end
817 out = out .. t
818 end
819 return out
820 end
821
822 -- Encode backspace-escaped characters in the markdown source.
823 function encode_backslash_escapes(t)
824 for i=1,escape_chars:len() do
825 local c = escape_chars:sub(i,i)
826 t = t:gsub("\\%" .. c, escape_table[c])
827 end
828 return t
829 end
830
831 -- Unescape characters that have been encoded.
832 local function unescape_special_chars(t)
833 local tin = t
834 for k,v in pairs(escape_table) do
835 k = k:gsub("%%", "%%%%")
836 t = t:gsub(v,k)
837 end
838 if t ~= tin then t = unescape_special_chars(t) end
839 return t
840 end
841
842 -- Encode/escape certain characters inside Markdown code runs.
843 -- The point is that in code, these characters are literals,
844 -- and lose their special Markdown meanings.
845 function encode_code(s)
846 s = s:gsub("%&", "&amp;")
847 s = s:gsub("<", "&lt;")
848 s = s:gsub(">", "&gt;")
849 for k,v in pairs(escape_table) do
850 s = s:gsub("%"..k, v)
851 end
852 return s
853 end
854
855 -- Handle backtick blocks.
856 local function code_spans(s)
857 s = s:gsub("\\\\", escape_table["\\"])
858 s = s:gsub("\\`", escape_table["`"])
859
860 local pos = 1
861 while true do
862 local start, stop = s:find("`+", pos)
863 if not start then return s end
864 local count = stop - start + 1
865 -- Find a matching numbert of backticks
866 local estart, estop = s:find(string.rep("`", count), stop+1)
867 local brstart = s:find("\n", stop+1)
868 if estart and (not brstart or estart < brstart) then
869 local code = s:sub(stop+1, estart-1)
870 code = code:gsub("^[ \t]+", "")
871 code = code:gsub("[ \t]+$", "")
872 code = code:gsub(escape_table["\\"], escape_table["\\"] .. escape_table["\\"])
873 code = code:gsub(escape_table["`"], escape_table["\\"] .. escape_table["`"])
874 code = "<code>" .. encode_code(code) .. "</code>"
875 code = add_escape(code)
876 s = s:sub(1, start-1) .. code .. s:sub(estop+1)
877 pos = start + code:len()
878 else
879 pos = stop + 1
880 end
881 end
882 return s
883 end
884
885 -- Encode alt text... enodes &, and ".
886 local function encode_alt(s)
887 if not s then return s end
888 s = s:gsub('&', '&amp;')
889 s = s:gsub('"', '&quot;')
890 s = s:gsub('<', '&lt;')
891 return s
892 end
893
894 local link_database
895
896 -- Handle image references
897 local function images(text)
898 local function reference_link(alt, id)
899 alt = encode_alt(alt:match("%b[]"):sub(2,-2))
900 id = id:match("%[(.*)%]"):lower()
901 if id == "" then id = text:lower() end
902 link_database[id] = link_database[id] or {}
903 if not link_database[id].url then return nil end
904 local url = link_database[id].url or id
905 url = encode_alt(url)
906 local title = encode_alt(link_database[id].title)
907 if title then title = " title=\"" .. title .. "\"" else title = "" end
908 return add_escape ('<img src="' .. url .. '" alt="' .. alt .. '"' .. title .. "/>")
909 end
910
911 local function inline_link(alt, link)
912 alt = encode_alt(alt:match("%b[]"):sub(2,-2))
913 local url, title = link:match("%(<?(.-)>?[ \t]*['\"](.+)['\"]")
914 url = url or link:match("%(<?(.-)>?%)")
915 url = encode_alt(url)
916 title = encode_alt(title)
917 if title then
918 return add_escape('<img src="' .. url .. '" alt="' .. alt .. '" title="' .. title .. '"/>')
919 else
920 return add_escape('<img src="' .. url .. '" alt="' .. alt .. '"/>')
921 end
922 end
923
924 text = text:gsub("!(%b[])[ \t]*\n?[ \t]*(%b[])", reference_link)
925 text = text:gsub("!(%b[])(%b())", inline_link)
926 return text
927 end
928
929 -- Handle anchor references
930 local function anchors(text)
931 local function reference_link(text, id)
932 text = text:match("%b[]"):sub(2,-2)
933 id = id:match("%b[]"):sub(2,-2):lower()
934 if id == "" then id = text:lower() end
935 link_database[id] = link_database[id] or {}
936 if not link_database[id].url then return nil end
937 local url = link_database[id].url or id
938 url = encode_alt(url)
939 local title = encode_alt(link_database[id].title)
940 if title then title = " title=\"" .. title .. "\"" else title = "" end
941 return add_escape("<a href=\"" .. url .. "\"" .. title .. ">") .. text .. add_escape("</a>")
942 end
943
944 local function inline_link(text, link)
945 text = text:match("%b[]"):sub(2,-2)
946 local url, title = link:match("%(<?(.-)>?[ \t]*['\"](.+)['\"]")
947 title = encode_alt(title)
948 url = url or link:match("%(<?(.-)>?%)") or ""
949 url = encode_alt(url)
950 if title then
951 return add_escape("<a href=\"" .. url .. "\" title=\"" .. title .. "\">") .. text .. "</a>"
952 else
953 return add_escape("<a href=\"" .. url .. "\">") .. text .. add_escape("</a>")
954 end
955 end
956
957 text = text:gsub("(%b[])[ \t]*\n?[ \t]*(%b[])", reference_link)
958 text = text:gsub("(%b[])(%b())", inline_link)
959 return text
960 end
961
962 -- Handle auto links, i.e. <http://www.google.com/>.
963 local function auto_links(text)
964 local function link(s)
965 return add_escape("<a href=\"" .. s .. "\">") .. s .. "</a>"
966 end
967 -- Encode chars as a mix of dec and hex entitites to (perhaps) fool
968 -- spambots.
969 local function encode_email_address(s)
970 -- Use a deterministic encoding to make unit testing possible.
971 -- Code 45% hex, 45% dec, 10% plain.
972 local hex = {code = function(c) return "&#x" .. string.format("%x", c:byte()) .. ";" end, count = 1, rate = 0.45}
973 local dec = {code = function(c) return "&#" .. c:byte() .. ";" end, count = 0, rate = 0.45}
974 local plain = {code = function(c) return c end, count = 0, rate = 0.1}
975 local codes = {hex, dec, plain}
976 local function swap(t,k1,k2) local temp = t[k2] t[k2] = t[k1] t[k1] = temp end
977
978 local out = ""
979 for i = 1,s:len() do
980 for _,code in ipairs(codes) do code.count = code.count + code.rate end
981 if codes[1].count < codes[2].count then swap(codes,1,2) end
982 if codes[2].count < codes[3].count then swap(codes,2,3) end
983 if codes[1].count < codes[2].count then swap(codes,1,2) end
984
985 local code = codes[1]
986 local c = s:sub(i,i)
987 -- Force encoding of "@" to make email address more invisible.
988 if c == "@" and code == plain then code = codes[2] end
989 out = out .. code.code(c)
990 code.count = code.count - 1
991 end
992 return out
993 end
994 local function mail(s)
995 s = unescape_special_chars(s)
996 local address = encode_email_address("mailto:" .. s)
997 local text = encode_email_address(s)
998 return add_escape("<a href=\"" .. address .. "\">") .. text .. "</a>"
999 end
1000 -- links
1001 text = text:gsub("<(https?:[^'\">%s]+)>", link)
1002 text = text:gsub("<(ftp:[^'\">%s]+)>", link)
1003
1004 -- mail
1005 text = text:gsub("<mailto:([^'\">%s]+)>", mail)
1006 text = text:gsub("<([-.%w]+%@[-.%w]+)>", mail)
1007 return text
1008 end
1009
1010 -- Encode free standing amps (&) and angles (<)... note that this does not
1011 -- encode free >.
1012 local function amps_and_angles(s)
1013 -- encode amps not part of &..; expression
1014 local pos = 1
1015 while true do
1016 local amp = s:find("&", pos)
1017 if not amp then break end
1018 local semi = s:find(";", amp+1)
1019 local stop = s:find("[ \t\n&]", amp+1)
1020 if not semi or (stop and stop < semi) or (semi - amp) > 15 then
1021 s = s:sub(1,amp-1) .. "&amp;" .. s:sub(amp+1)
1022 pos = amp+1
1023 else
1024 pos = amp+1
1025 end
1026 end
1027
1028 -- encode naked <'s
1029 s = s:gsub("<([^a-zA-Z/?$!])", "&lt;%1")
1030 s = s:gsub("<$", "&lt;")
1031
1032 -- what about >, nothing done in the original markdown source to handle them
1033 return s
1034 end
1035
1036 -- Handles emphasis markers (* and _) in the text.
1037 local function emphasis(text)
1038 for _, s in ipairs {"%*%*", "%_%_"} do
1039 text = text:gsub(s .. "([^%s][%*%_]?)" .. s, "<strong>%1</strong>")
1040 text = text:gsub(s .. "([^%s][^<>]-[^%s][%*%_]?)" .. s, "<strong>%1</strong>")
1041 end
1042 for _, s in ipairs {"%*", "%_"} do
1043 text = text:gsub(s .. "([^%s_])" .. s, "<em>%1</em>")
1044 text = text:gsub(s .. "(<strong>[^%s_]</strong>)" .. s, "<em>%1</em>")
1045 text = text:gsub(s .. "([^%s_][^<>_]-[^%s_])" .. s, "<em>%1</em>")
1046 text = text:gsub(s .. "([^<>_]-<strong>[^<>_]-</strong>[^<>_]-)" .. s, "<em>%1</em>")
1047 end
1048 return text
1049 end
1050
1051 -- Handles line break markers in the text.
1052 local function line_breaks(text)
1053 return text:gsub(" +\n", " <br/>\n")
1054 end
1055
1056 -- Perform all span level transforms.
1057 function span_transform(text)
1058 text = code_spans(text)
1059 text = escape_special_chars(text)
1060 text = images(text)
1061 text = anchors(text)
1062 text = auto_links(text)
1063 text = amps_and_angles(text)
1064 text = emphasis(text)
1065 text = line_breaks(text)
1066 return text
1067 end
1068
1069 ----------------------------------------------------------------------
1070 -- Markdown
1071 ----------------------------------------------------------------------
1072
1073 -- Cleanup the text by normalizing some possible variations to make further
1074 -- processing easier.
1075 local function cleanup(text)
1076 -- Standardize line endings
1077 text = text:gsub("\r\n", "\n") -- DOS to UNIX
1078 text = text:gsub("\r", "\n") -- Mac to UNIX
1079
1080 -- Convert all tabs to spaces
1081 text = detab(text)
1082
1083 -- Strip lines with only spaces and tabs
1084 while true do
1085 local subs
1086 text, subs = text:gsub("\n[ \t]+\n", "\n\n")
1087 if subs == 0 then break end
1088 end
1089
1090 return "\n" .. text .. "\n"
1091 end
1092
1093 -- Strips link definitions from the text and stores the data in a lookup table.
1094 local function strip_link_definitions(text)
1095 local linkdb = {}
1096
1097 local function link_def(id, url, title)
1098 id = id:match("%[(.+)%]"):lower()
1099 linkdb[id] = linkdb[id] or {}
1100 linkdb[id].url = url or linkdb[id].url
1101 linkdb[id].title = title or linkdb[id].title
1102 return ""
1103 end
1104
1105 local def_no_title = "\n ? ? ?(%b[]):[ \t]*\n?[ \t]*<?([^%s>]+)>?[ \t]*"
1106 local def_title1 = def_no_title .. "[ \t]+\n?[ \t]*[\"'(]([^\n]+)[\"')][ \t]*"
1107 local def_title2 = def_no_title .. "[ \t]*\n[ \t]*[\"'(]([^\n]+)[\"')][ \t]*"
1108 local def_title3 = def_no_title .. "[ \t]*\n?[ \t]+[\"'(]([^\n]+)[\"')][ \t]*"
1109
1110 text = text:gsub(def_title1, link_def)
1111 text = text:gsub(def_title2, link_def)
1112 text = text:gsub(def_title3, link_def)
1113 text = text:gsub(def_no_title, link_def)
1114 return text, linkdb
1115 end
1116
1117 link_database = {}
1118
1119 -- Main markdown processing function
1120 local function markdown(text)
1121 init_hash(text)
1122 init_escape_table()
1123
1124 text = cleanup(text)
1125 text = protect(text)
1126 text, link_database = strip_link_definitions(text)
1127 text = block_transform(text)
1128 text = unescape_special_chars(text)
1129 return text
1130 end
1131
1132 ----------------------------------------------------------------------
1133 -- End of module
1134 ----------------------------------------------------------------------
1135
1136 M.lock(M)
1137
1138 -- Expose markdown function to the world
1139 _G.markdown = M.markdown
1140
1141 -- Class for parsing command-line options
1142 local OptionParser = {}
1143 OptionParser.__index = OptionParser
1144
1145 -- Creates a new option parser
1146 function OptionParser:new()
1147 local o = {short = {}, long = {}}
1148 setmetatable(o, self)
1149 return o
1150 end
1151
1152 -- Calls f() whenever a flag with specified short and long name is encountered
1153 function OptionParser:flag(short, long, f)
1154 local info = {type = "flag", f = f}
1155 if short then self.short[short] = info end
1156 if long then self.long[long] = info end
1157 end
1158
1159 -- Calls f(param) whenever a parameter flag with specified short and long name is encountered
1160 function OptionParser:param(short, long, f)
1161 local info = {type = "param", f = f}
1162 if short then self.short[short] = info end
1163 if long then self.long[long] = info end
1164 end
1165
1166 -- Calls f(v) for each non-flag argument
1167 function OptionParser:arg(f)
1168 self.arg = f
1169 end
1170
1171 -- Runs the option parser for the specified set of arguments. Returns true if all arguments
1172 -- where successfully parsed and false otherwise.
1173 function OptionParser:run(args)
1174 local pos = 1
1175 local param
1176 while pos <= #args do
1177 local arg = args[pos]
1178 if arg == "--" then
1179 for i=pos+1,#args do
1180 if self.arg then self.arg(args[i]) end
1181 return true
1182 end
1183 end
1184 if arg:match("^%-%-") then
1185 local info = self.long[arg:sub(3)]
1186 if not info then print("Unknown flag: " .. arg) return false end
1187 if info.type == "flag" then
1188 info.f()
1189 pos = pos + 1
1190 else
1191 param = args[pos+1]
1192 if not param then print("No parameter for flag: " .. arg) return false end
1193 info.f(param)
1194 pos = pos+2
1195 end
1196 elseif arg:match("^%-") then
1197 for i=2,arg:len() do
1198 local c = arg:sub(i,i)
1199 local info = self.short[c]
1200 if not info then print("Unknown flag: -" .. c) return false end
1201 if info.type == "flag" then
1202 info.f()
1203 else
1204 if i == arg:len() then
1205 param = args[pos+1]
1206 if not param then print("No parameter for flag: -" .. c) return false end
1207 info.f(param)
1208 pos = pos + 1
1209 else
1210 param = arg:sub(i+1)
1211 info.f(param)
1212 end
1213 break
1214 end
1215 end
1216 pos = pos + 1
1217 else
1218 if self.arg then self.arg(arg) end
1219 pos = pos + 1
1220 end
1221 end
1222 return true
1223 end
1224
1225 -- Handles the case when markdown is run from the command line
1226 local function run_command_line(arg)
1227 -- Generate output for input s given options
1228 local function run(s, options)
1229 s = markdown(s)
1230 if not options.wrap_header then return s end
1231 local header = ""
1232 if options.header then
1233 local f = io.open(options.header) or error("Could not open file: " .. options.header)
1234 header = f:read("*a")
1235 f:close()
1236 else
1237 header = [[
1238 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1239 <html>
1240 <head>
1241 <meta http-equiv="content-type" content="text/html; charset=CHARSET" />
1242 <title>TITLE</title>
1243 <link rel="stylesheet" type="text/css" href="STYLESHEET" />
1244 </head>
1245 <body>
1246 ]]
1247 local title = options.title or s:match("<h1>(.-)</h1>") or s:match("<h2>(.-)</h2>") or
1248 s:match("<h3>(.-)</h3>") or "Untitled"
1249 header = header:gsub("TITLE", title)
1250 if options.inline_style then
1251 local style = ""
1252 local f = io.open(options.stylesheet)
1253 if f then
1254 style = f:read("*a") f:close()
1255 else
1256 error("Could not include style sheet " .. options.stylesheet .. ": File not found")
1257 end
1258 header = header:gsub('<link rel="stylesheet" type="text/css" href="STYLESHEET" />',
1259 "<style type=\"text/css\"><!--\n" .. style .. "\n--></style>")
1260 else
1261 header = header:gsub("STYLESHEET", options.stylesheet)
1262 end
1263 header = header:gsub("CHARSET", options.charset)
1264 end
1265 local footer = "</body></html>"
1266 if options.footer then
1267 local f = io.open(options.footer) or error("Could not open file: " .. options.footer)
1268 footer = f:read("*a")
1269 f:close()
1270 end
1271 return header .. s .. footer
1272 end
1273
1274 -- Generate output path name from input path name given options.
1275 local function outpath(path, options)
1276 if options.append then return path .. ".html" end
1277 local m = path:match("^(.+%.html)[^/\\]+$") if m then return m end
1278 m = path:match("^(.+%.)[^/\\]*$") if m and path ~= m .. "html" then return m .. "html" end
1279 return path .. ".html"
1280 end
1281
1282 -- Default commandline options
1283 local options = {
1284 wrap_header = true,
1285 header = nil,
1286 footer = nil,
1287 charset = "utf-8",
1288 title = nil,
1289 stylesheet = "default.css",
1290 inline_style = false
1291 }
1292 local help = [[
1293 Usage: markdown.lua [OPTION] [FILE]
1294 Runs the markdown text markup to HTML converter on each file specified on the
1295 command line. If no files are specified, runs on standard input.
1296
1297 No header:
1298 -n, --no-wrap Don't wrap the output in <html>... tags.
1299 Custom header:
1300 -e, --header FILE Use content of FILE for header.
1301 -f, --footer FILE Use content of FILE for footer.
1302 Generated header:
1303 -c, --charset SET Specifies charset (default utf-8).
1304 -i, --title TITLE Specifies title (default from first <h1> tag).
1305 -s, --style STYLE Specifies style sheet file (default default.css).
1306 -l, --inline-style Include the style sheet file inline in the header.
1307 Generated files:
1308 -a, --append Append .html extension (instead of replacing).
1309 Other options:
1310 -h, --help Print this help text.
1311 -t, --test Run the unit tests.
1312 ]]
1313
1314 local run_stdin = true
1315 local op = OptionParser:new()
1316 op:flag("n", "no-wrap", function () options.wrap_header = false end)
1317 op:param("e", "header", function (x) options.header = x end)
1318 op:param("f", "footer", function (x) options.footer = x end)
1319 op:param("c", "charset", function (x) options.charset = x end)
1320 op:param("i", "title", function(x) options.title = x end)
1321 op:param("s", "style", function(x) options.stylesheet = x end)
1322 op:flag("l", "inline-style", function(x) options.inline_style = true end)
1323 op:flag("a", "append", function() options.append = true end)
1324 op:flag("t", "test", function()
1325 local n = arg[0]:gsub("markdown.lua", "markdown-tests.lua")
1326 local f = io.open(n)
1327 if f then
1328 f:close() dofile(n)
1329 else
1330 error("Cannot find markdown-tests.lua")
1331 end
1332 run_stdin = false
1333 end)
1334 op:flag("h", "help", function() print(help) run_stdin = false end)
1335 op:arg(function(path)
1336 local file = io.open(path) or error("Could not open file: " .. path)
1337 local s = file:read("*a")
1338 file:close()
1339 s = run(s, options)
1340 file = io.open(outpath(path, options), "w") or error("Could not open output file: " .. outpath(path, options))
1341 file:write(s)
1342 file:close()
1343 run_stdin = false
1344 end
1345 )
1346
1347 if not op:run(arg) then
1348 print(help)
1349 run_stdin = false
1350 end
1351
1352 if run_stdin then
1353 local s = io.read("*a")
1354 s = run(s, options)
1355 io.write(s)
1356 end
1357 end
1358
1359 -- If we are being run from the command-line, act accordingly
1360 if arg and arg[0]:find("markdown%.lua$") then
1361 run_command_line(arg)
1362 else
1363 return markdown
1364 end
0 #!/usr/bin/env lua
1
2 --[[
3 # markdown.lua -- version 0.32
4
5 <http://www.frykholm.se/files/markdown.lua>
6
7 **Author:** Niklas Frykholm, <niklas@frykholm.se>
8 **Date:** 31 May 2008
9
10 This is an implementation of the popular text markup language Markdown in pure Lua.
11 Markdown can convert documents written in a simple and easy to read text format
12 to well-formatted HTML. For a more thourough description of Markdown and the Markdown
13 syntax, see <http://daringfireball.net/projects/markdown>.
14
15 The original Markdown source is written in Perl and makes heavy use of advanced
16 regular expression techniques (such as negative look-ahead, etc) which are not available
17 in Lua's simple regex engine. Therefore this Lua port has been rewritten from the ground
18 up. It is probably not completely bug free. If you notice any bugs, please report them to
19 me. A unit test that exposes the error is helpful.
20
21 ## Usage
22
23 require "markdown"
24 markdown(source)
25
26 ``markdown.lua`` exposes a single global function named ``markdown(s)`` which applies the
27 Markdown transformation to the specified string.
28
29 ``markdown.lua`` can also be used directly from the command line:
30
31 lua markdown.lua test.md
32
33 Creates a file ``test.html`` with the converted content of ``test.md``. Run:
34
35 lua markdown.lua -h
36
37 For a description of the command-line options.
38
39 ``markdown.lua`` uses the same license as Lua, the MIT license.
40
41 ## License
42
43 Copyright &copy; 2008 Niklas Frykholm.
44
45 Permission is hereby granted, free of charge, to any person obtaining a copy of this
46 software and associated documentation files (the "Software"), to deal in the Software
47 without restriction, including without limitation the rights to use, copy, modify, merge,
48 publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
49 to whom the Software is furnished to do so, subject to the following conditions:
50
51 The above copyright notice and this permission notice shall be included in all copies
52 or substantial portions of the Software.
53
54 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
56 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
57 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
58 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
59 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
60 THE SOFTWARE.
61
62 ## Version history
63
64 - **0.32** -- 31 May 2008
65 - Fix for links containing brackets
66 - **0.31** -- 1 Mar 2008
67 - Fix for link definitions followed by spaces
68 - **0.30** -- 25 Feb 2008
69 - Consistent behavior with Markdown when the same link reference is reused
70 - **0.29** -- 24 Feb 2008
71 - Fix for <pre> blocks with spaces in them
72 - **0.28** -- 18 Feb 2008
73 - Fix for link encoding
74 - **0.27** -- 14 Feb 2008
75 - Fix for link database links with ()
76 - **0.26** -- 06 Feb 2008
77 - Fix for nested italic and bold markers
78 - **0.25** -- 24 Jan 2008
79 - Fix for encoding of naked <
80 - **0.24** -- 21 Jan 2008
81 - Fix for link behavior.
82 - **0.23** -- 10 Jan 2008
83 - Fix for a regression bug in longer expressions in italic or bold.
84 - **0.22** -- 27 Dec 2007
85 - Fix for crash when processing blocks with a percent sign in them.
86 - **0.21** -- 27 Dec 2007
87 - Fix for combined strong and emphasis tags
88 - **0.20** -- 13 Oct 2007
89 - Fix for < as well in image titles, now matches Dingus behavior
90 - **0.19** -- 28 Sep 2007
91 - Fix for quotation marks " and ampersands & in link and image titles.
92 - **0.18** -- 28 Jul 2007
93 - Does not crash on unmatched tags (behaves like standard markdown)
94 - **0.17** -- 12 Apr 2007
95 - Fix for links with %20 in them.
96 - **0.16** -- 12 Apr 2007
97 - Do not require arg global to exist.
98 - **0.15** -- 28 Aug 2006
99 - Better handling of links with underscores in them.
100 - **0.14** -- 22 Aug 2006
101 - Bug for *`foo()`*
102 - **0.13** -- 12 Aug 2006
103 - Added -l option for including stylesheet inline in document.
104 - Fixed bug in -s flag.
105 - Fixed emphasis bug.
106 - **0.12** -- 15 May 2006
107 - Fixed several bugs to comply with MarkdownTest 1.0 <http://six.pairlist.net/pipermail/markdown-discuss/2004-December/000909.html>
108 - **0.11** -- 12 May 2006
109 - Fixed bug for escaping `*` and `_` inside code spans.
110 - Added license terms.
111 - Changed join() to table.concat().
112 - **0.10** -- 3 May 2006
113 - Initial public release.
114
115 // Niklas
116 ]]
117
118
119 -- Set up a table for holding local functions to avoid polluting the global namespace
120 local M = {}
121 local unpack = unpack or table.unpack
122 local MT = {__index = _G}
123 setmetatable(M, MT)
124
125 ----------------------------------------------------------------------
126 -- Utility functions
127 ----------------------------------------------------------------------
128
129 -- Locks table t from changes, writes an error if someone attempts to change the table.
130 -- This is useful for detecting variables that have "accidently" been made global. Something
131 -- I tend to do all too much.
132 function M.lock(t)
133 local function lock_new_index(t, k, v)
134 error("module has been locked -- " .. k .. " must be declared local", 2)
135 end
136
137 local mt = {__newindex = lock_new_index}
138 if getmetatable(t) then
139 mt.__index = getmetatable(t).__index
140 end
141 setmetatable(t, mt)
142 end
143
144 -- Returns the result of mapping the values in table t through the function f
145 local function map(t, f)
146 local out = {}
147 for k,v in pairs(t) do out[k] = f(v,k) end
148 return out
149 end
150
151 -- The identity function, useful as a placeholder.
152 local function identity(text) return text end
153
154 -- Functional style if statement. (NOTE: no short circuit evaluation)
155 local function iff(t, a, b) if t then return a else return b end end
156
157 -- Splits the text into an array of separate lines.
158 local function split(text, sep)
159 sep = sep or "\n"
160 local lines = {}
161 local pos = 1
162 while true do
163 local b,e = text:find(sep, pos)
164 if not b then table.insert(lines, text:sub(pos)) break end
165 table.insert(lines, text:sub(pos, b-1))
166 pos = e + 1
167 end
168 return lines
169 end
170
171 -- Converts tabs to spaces
172 local function detab(text)
173 local tab_width = 4
174 local function rep(match)
175 local spaces = -match:len()
176 while spaces<1 do spaces = spaces + tab_width end
177 return match .. string.rep(" ", spaces)
178 end
179 text = text:gsub("([^\n]-)\t", rep)
180 return text
181 end
182
183 -- Applies string.find for every pattern in the list and returns the first match
184 local function find_first(s, patterns, index)
185 local res = {}
186 for _,p in ipairs(patterns) do
187 local match = {s:find(p, index)}
188 if #match>0 and (#res==0 or match[1] < res[1]) then res = match end
189 end
190 return unpack(res)
191 end
192
193 -- If a replacement array is specified, the range [start, stop] in the array is replaced
194 -- with the replacement array and the resulting array is returned. Without a replacement
195 -- array the section of the array between start and stop is returned.
196 local function splice(array, start, stop, replacement)
197 if replacement then
198 local n = stop - start + 1
199 while n > 0 do
200 table.remove(array, start)
201 n = n - 1
202 end
203 for i,v in ipairs(replacement) do
204 table.insert(array, start, v)
205 end
206 return array
207 else
208 local res = {}
209 for i = start,stop do
210 table.insert(res, array[i])
211 end
212 return res
213 end
214 end
215
216 -- Outdents the text one step.
217 local function outdent(text)
218 text = "\n" .. text
219 text = text:gsub("\n ? ? ?", "\n")
220 text = text:sub(2)
221 return text
222 end
223
224 -- Indents the text one step.
225 local function indent(text)
226 text = text:gsub("\n", "\n ")
227 return text
228 end
229
230 -- Does a simple tokenization of html data. Returns the data as a list of tokens.
231 -- Each token is a table with a type field (which is either "tag" or "text") and
232 -- a text field (which contains the original token data).
233 local function tokenize_html(html)
234 local tokens = {}
235 local pos = 1
236 while true do
237 local start = find_first(html, {"<!%-%-", "<[a-z/!$]", "<%?"}, pos)
238 if not start then
239 table.insert(tokens, {type="text", text=html:sub(pos)})
240 break
241 end
242 if start ~= pos then table.insert(tokens, {type="text", text = html:sub(pos, start-1)}) end
243
244 local _, stop
245 if html:match("^<!%-%-", start) then
246 _,stop = html:find("%-%->", start)
247 elseif html:match("^<%?", start) then
248 _,stop = html:find("?>", start)
249 else
250 _,stop = html:find("%b<>", start)
251 end
252 if not stop then
253 -- error("Could not match html tag " .. html:sub(start,start+30))
254 table.insert(tokens, {type="text", text=html:sub(start, start)})
255 pos = start + 1
256 else
257 table.insert(tokens, {type="tag", text=html:sub(start, stop)})
258 pos = stop + 1
259 end
260 end
261 return tokens
262 end
263
264 ----------------------------------------------------------------------
265 -- Hash
266 ----------------------------------------------------------------------
267
268 -- This is used to "hash" data into alphanumeric strings that are unique
269 -- in the document. (Note that this is not cryptographic hash, the hash
270 -- function is not one-way.) The hash procedure is used to protect parts
271 -- of the document from further processing.
272
273 local HASH = {
274 -- Has the hash been inited.
275 inited = false,
276
277 -- The unique string prepended to all hash values. This is to ensure
278 -- that hash values do not accidently coincide with an actual existing
279 -- string in the document.
280 identifier = "",
281
282 -- Counter that counts up for each new hash instance.
283 counter = 0,
284
285 -- Hash table.
286 table = {}
287 }
288
289 -- Inits hashing. Creates a hash_identifier that doesn't occur anywhere
290 -- in the text.
291 local function init_hash(text)
292 HASH.inited = true
293 HASH.identifier = ""
294 HASH.counter = 0
295 HASH.table = {}
296
297 local s = "HASH"
298 local counter = 0
299 local id
300 while true do
301 id = s .. counter
302 if not text:find(id, 1, true) then break end
303 counter = counter + 1
304 end
305 HASH.identifier = id
306 end
307
308 -- Returns the hashed value for s.
309 local function hash(s)
310 assert(HASH.inited)
311 if not HASH.table[s] then
312 HASH.counter = HASH.counter + 1
313 local id = HASH.identifier .. HASH.counter .. "X"
314 HASH.table[s] = id
315 end
316 return HASH.table[s]
317 end
318
319 ----------------------------------------------------------------------
320 -- Protection
321 ----------------------------------------------------------------------
322
323 -- The protection module is used to "protect" parts of a document
324 -- so that they are not modified by subsequent processing steps.
325 -- Protected parts are saved in a table for later unprotection
326
327 -- Protection data
328 local PD = {
329 -- Saved blocks that have been converted
330 blocks = {},
331
332 -- Block level tags that will be protected
333 tags = {"p", "div", "h1", "h2", "h3", "h4", "h5", "h6", "blockquote",
334 "pre", "table", "dl", "ol", "ul", "script", "noscript", "form", "fieldset",
335 "iframe", "math", "ins", "del"}
336 }
337
338 -- Pattern for matching a block tag that begins and ends in the leftmost
339 -- column and may contain indented subtags, i.e.
340 -- <div>
341 -- A nested block.
342 -- <div>
343 -- Nested data.
344 -- </div>
345 -- </div>
346 local function block_pattern(tag)
347 return "\n<" .. tag .. ".-\n</" .. tag .. ">[ \t]*\n"
348 end
349
350 -- Pattern for matching a block tag that begins and ends with a newline
351 local function line_pattern(tag)
352 return "\n<" .. tag .. ".-</" .. tag .. ">[ \t]*\n"
353 end
354
355 -- Protects the range of characters from start to stop in the text and
356 -- returns the protected string.
357 local function protect_range(text, start, stop)
358 local s = text:sub(start, stop)
359 local h = hash(s)
360 PD.blocks[h] = s
361 text = text:sub(1,start) .. h .. text:sub(stop)
362 return text
363 end
364
365 -- Protect every part of the text that matches any of the patterns. The first
366 -- matching pattern is protected first, etc.
367 local function protect_matches(text, patterns)
368 while true do
369 local start, stop = find_first(text, patterns)
370 if not start then break end
371 text = protect_range(text, start, stop)
372 end
373 return text
374 end
375
376 -- Protects blocklevel tags in the specified text
377 local function protect(text)
378 -- First protect potentially nested block tags
379 text = protect_matches(text, map(PD.tags, block_pattern))
380 -- Then protect block tags at the line level.
381 text = protect_matches(text, map(PD.tags, line_pattern))
382 -- Protect <hr> and comment tags
383 text = protect_matches(text, {"\n<hr[^>]->[ \t]*\n"})
384 text = protect_matches(text, {"\n<!%-%-.-%-%->[ \t]*\n"})
385 return text
386 end
387
388 -- Returns true if the string s is a hash resulting from protection
389 local function is_protected(s)
390 return PD.blocks[s]
391 end
392
393 -- Unprotects the specified text by expanding all the nonces
394 local function unprotect(text)
395 for k,v in pairs(PD.blocks) do
396 v = v:gsub("%%", "%%%%")
397 text = text:gsub(k, v)
398 end
399 return text
400 end
401
402
403 ----------------------------------------------------------------------
404 -- Block transform
405 ----------------------------------------------------------------------
406
407 -- The block transform functions transform the text on the block level.
408 -- They work with the text as an array of lines rather than as individual
409 -- characters.
410
411 -- Returns true if the line is a ruler of (char) characters.
412 -- The line must contain at least three char characters and contain only spaces and
413 -- char characters.
414 local function is_ruler_of(line, char)
415 if not line:match("^[ %" .. char .. "]*$") then return false end
416 if not line:match("%" .. char .. ".*%" .. char .. ".*%" .. char) then return false end
417 return true
418 end
419
420 -- Identifies the block level formatting present in the line
421 local function classify(line)
422 local info = {line = line, text = line}
423
424 if line:match("^ ") then
425 info.type = "indented"
426 info.outdented = line:sub(5)
427 return info
428 end
429
430 for _,c in ipairs({'*', '-', '_', '='}) do
431 if is_ruler_of(line, c) then
432 info.type = "ruler"
433 info.ruler_char = c
434 return info
435 end
436 end
437
438 if line == "" then
439 info.type = "blank"
440 return info
441 end
442
443 if line:match("^(#+)[ \t]*(.-)[ \t]*#*[ \t]*$") then
444 local m1, m2 = line:match("^(#+)[ \t]*(.-)[ \t]*#*[ \t]*$")
445 info.type = "header"
446 info.level = m1:len()
447 info.text = m2
448 return info
449 end
450
451 if line:match("^ ? ? ?(%d+)%.[ \t]+(.+)") then
452 local number, text = line:match("^ ? ? ?(%d+)%.[ \t]+(.+)")
453 info.type = "list_item"
454 info.list_type = "numeric"
455 info.number = 0 + number
456 info.text = text
457 return info
458 end
459
460 if line:match("^ ? ? ?([%*%+%-])[ \t]+(.+)") then
461 local bullet, text = line:match("^ ? ? ?([%*%+%-])[ \t]+(.+)")
462 info.type = "list_item"
463 info.list_type = "bullet"
464 info.bullet = bullet
465 info.text= text
466 return info
467 end
468
469 if line:match("^>[ \t]?(.*)") then
470 info.type = "blockquote"
471 info.text = line:match("^>[ \t]?(.*)")
472 return info
473 end
474
475 if is_protected(line) then
476 info.type = "raw"
477 info.html = unprotect(line)
478 return info
479 end
480
481 info.type = "normal"
482 return info
483 end
484
485 -- Find headers constisting of a normal line followed by a ruler and converts them to
486 -- header entries.
487 local function headers(array)
488 local i = 1
489 while i <= #array - 1 do
490 if array[i].type == "normal" and array[i+1].type == "ruler" and
491 (array[i+1].ruler_char == "-" or array[i+1].ruler_char == "=") then
492 local info = {line = array[i].line}
493 info.text = info.line
494 info.type = "header"
495 info.level = iff(array[i+1].ruler_char == "=", 1, 2)
496 table.remove(array, i+1)
497 array[i] = info
498 end
499 i = i + 1
500 end
501 return array
502 end
503
504 local block_transform, blocks_to_html, encode_code, span_transform, encode_backslash_escapes
505
506 -- Find list blocks and convert them to protected data blocks
507 local function lists(array, sublist)
508 local function process_list(arr)
509 local function any_blanks(arr)
510 for i = 1, #arr do
511 if arr[i].type == "blank" then return true end
512 end
513 return false
514 end
515
516 local function split_list_items(arr)
517 local acc = {arr[1]}
518 local res = {}
519 for i=2,#arr do
520 if arr[i].type == "list_item" then
521 table.insert(res, acc)
522 acc = {arr[i]}
523 else
524 table.insert(acc, arr[i])
525 end
526 end
527 table.insert(res, acc)
528 return res
529 end
530
531 local function process_list_item(lines, block)
532 while lines[#lines].type == "blank" do
533 table.remove(lines)
534 end
535
536 local itemtext = lines[1].text
537 for i=2,#lines do
538 itemtext = itemtext .. "\n" .. outdent(lines[i].line)
539 end
540 if block then
541 itemtext = block_transform(itemtext, true)
542 if not itemtext:find("<pre>") then itemtext = indent(itemtext) end
543 return " <li>" .. itemtext .. "</li>"
544 else
545 local lines = split(itemtext)
546 lines = map(lines, classify)
547 lines = lists(lines, true)
548 lines = blocks_to_html(lines, true)
549 itemtext = table.concat(lines, "\n")
550 if not itemtext:find("<pre>") then itemtext = indent(itemtext) end
551 return " <li>" .. itemtext .. "</li>"
552 end
553 end
554
555 local block_list = any_blanks(arr)
556 local items = split_list_items(arr)
557 local out = ""
558 for _, item in ipairs(items) do
559 out = out .. process_list_item(item, block_list) .. "\n"
560 end
561 if arr[1].list_type == "numeric" then
562 return "<ol>\n" .. out .. "</ol>"
563 else
564 return "<ul>\n" .. out .. "</ul>"
565 end
566 end
567
568 -- Finds the range of lines composing the first list in the array. A list
569 -- starts with (^ list_item) or (blank list_item) and ends with
570 -- (blank* $) or (blank normal).
571 --
572 -- A sublist can start with just (list_item) does not need a blank...
573 local function find_list(array, sublist)
574 local function find_list_start(array, sublist)
575 if array[1].type == "list_item" then return 1 end
576 if sublist then
577 for i = 1,#array do
578 if array[i].type == "list_item" then return i end
579 end
580 else
581 for i = 1, #array-1 do
582 if array[i].type == "blank" and array[i+1].type == "list_item" then
583 return i+1
584 end
585 end
586 end
587 return nil
588 end
589 local function find_list_end(array, start)
590 local pos = #array
591 for i = start, #array-1 do
592 if array[i].type == "blank" and array[i+1].type ~= "list_item"
593 and array[i+1].type ~= "indented" and array[i+1].type ~= "blank" then
594 pos = i-1
595 break
596 end
597 end
598 while pos > start and array[pos].type == "blank" do
599 pos = pos - 1
600 end
601 return pos
602 end
603
604 local start = find_list_start(array, sublist)
605 if not start then return nil end
606 return start, find_list_end(array, start)
607 end
608
609 while true do
610 local start, stop = find_list(array, sublist)
611 if not start then break end
612 local text = process_list(splice(array, start, stop))
613 local info = {
614 line = text,
615 type = "raw",
616 html = text
617 }
618 array = splice(array, start, stop, {info})
619 end
620
621 -- Convert any remaining list items to normal
622 for _,line in ipairs(array) do
623 if line.type == "list_item" then line.type = "normal" end
624 end
625
626 return array
627 end
628
629 -- Find and convert blockquote markers.
630 local function blockquotes(lines)
631 local function find_blockquote(lines)
632 local start
633 for i,line in ipairs(lines) do
634 if line.type == "blockquote" then
635 start = i
636 break
637 end
638 end
639 if not start then return nil end
640
641 local stop = #lines
642 for i = start+1, #lines do
643 if lines[i].type == "blank" or lines[i].type == "blockquote" then
644 elseif lines[i].type == "normal" then
645 if lines[i-1].type == "blank" then stop = i-1 break end
646 else
647 stop = i-1 break
648 end
649 end
650 while lines[stop].type == "blank" do stop = stop - 1 end
651 return start, stop
652 end
653
654 local function process_blockquote(lines)
655 local raw = lines[1].text
656 for i = 2,#lines do
657 raw = raw .. "\n" .. lines[i].text
658 end
659 local bt = block_transform(raw)
660 if not bt:find("<pre>") then bt = indent(bt) end
661 return "<blockquote>\n " .. bt ..
662 "\n</blockquote>"
663 end
664
665 while true do
666 local start, stop = find_blockquote(lines)
667 if not start then break end
668 local text = process_blockquote(splice(lines, start, stop))
669 local info = {
670 line = text,
671 type = "raw",
672 html = text
673 }
674 lines = splice(lines, start, stop, {info})
675 end
676 return lines
677 end
678
679 -- Find and convert codeblocks.
680 local function codeblocks(lines)
681 local function find_codeblock(lines)
682 local start
683 for i,line in ipairs(lines) do
684 if line.type == "indented" then start = i break end
685 end
686 if not start then return nil end
687
688 local stop = #lines
689 for i = start+1, #lines do
690 if lines[i].type ~= "indented" and lines[i].type ~= "blank" then
691 stop = i-1
692 break
693 end
694 end
695 while lines[stop].type == "blank" do stop = stop - 1 end
696 return start, stop
697 end
698
699 local function process_codeblock(lines)
700 local raw = detab(encode_code(outdent(lines[1].line)))
701 for i = 2,#lines do
702 raw = raw .. "\n" .. detab(encode_code(outdent(lines[i].line)))
703 end
704 return "<pre><code>" .. raw .. "\n</code></pre>"
705 end
706
707 while true do
708 local start, stop = find_codeblock(lines)
709 if not start then break end
710 local text = process_codeblock(splice(lines, start, stop))
711 local info = {
712 line = text,
713 type = "raw",
714 html = text
715 }
716 lines = splice(lines, start, stop, {info})
717 end
718 return lines
719 end
720
721 -- Convert lines to html code
722 function blocks_to_html(lines, no_paragraphs)
723 local out = {}
724 local i = 1
725 while i <= #lines do
726 local line = lines[i]
727 if line.type == "ruler" then
728 table.insert(out, "<hr/>")
729 elseif line.type == "raw" then
730 table.insert(out, line.html)
731 elseif line.type == "normal" then
732 local s = line.line
733
734 while i+1 <= #lines and lines[i+1].type == "normal" do
735 i = i + 1
736 s = s .. "\n" .. lines[i].line
737 end
738
739 if no_paragraphs then
740 table.insert(out, span_transform(s))
741 else
742 table.insert(out, "<p>" .. span_transform(s) .. "</p>")
743 end
744 elseif line.type == "header" then
745 local s = "<h" .. line.level .. ">" .. span_transform(line.text) .. "</h" .. line.level .. ">"
746 table.insert(out, s)
747 else
748 table.insert(out, line.line)
749 end
750 i = i + 1
751 end
752 return out
753 end
754
755 -- Perform all the block level transforms
756 function block_transform(text, sublist)
757 local lines = split(text)
758 lines = map(lines, classify)
759 lines = headers(lines)
760 lines = lists(lines, sublist)
761 lines = codeblocks(lines)
762 lines = blockquotes(lines)
763 lines = blocks_to_html(lines)
764 local text = table.concat(lines, "\n")
765 return text
766 end
767
768 -- Debug function for printing a line array to see the result
769 -- of partial transforms.
770 local function print_lines(lines)
771 for i, line in ipairs(lines) do
772 print(i, line.type, line.text or line.line)
773 end
774 end
775
776 ----------------------------------------------------------------------
777 -- Span transform
778 ----------------------------------------------------------------------
779
780 -- Functions for transforming the text at the span level.
781
782 -- These characters may need to be escaped because they have a special
783 -- meaning in markdown.
784 local escape_chars = "'\\`*_{}[]()>#+-.!'"
785 local escape_table = {}
786
787 local function init_escape_table()
788 escape_table = {}
789 for i = 1,#escape_chars do
790 local c = escape_chars:sub(i,i)
791 escape_table[c] = hash(c)
792 end
793 end
794
795 -- Adds a new escape to the escape table.
796 local function add_escape(text)
797 if not escape_table[text] then
798 escape_table[text] = hash(text)
799 end
800 return escape_table[text]
801 end
802
803 -- Escape characters that should not be disturbed by markdown.
804 local function escape_special_chars(text)
805 local tokens = tokenize_html(text)
806
807 local out = ""
808 for _, token in ipairs(tokens) do
809 local t = token.text
810 if token.type == "tag" then
811 -- In tags, encode * and _ so they don't conflict with their use in markdown.
812 t = t:gsub("%*", escape_table["*"])
813 t = t:gsub("%_", escape_table["_"])
814 else
815 t = encode_backslash_escapes(t)
816 end
817 out = out .. t
818 end
819 return out
820 end
821
822 -- Encode backspace-escaped characters in the markdown source.
823 function encode_backslash_escapes(t)
824 for i=1,escape_chars:len() do
825 local c = escape_chars:sub(i,i)
826 t = t:gsub("\\%" .. c, escape_table[c])
827 end
828 return t
829 end
830
831 -- Unescape characters that have been encoded.
832 local function unescape_special_chars(t)
833 local tin = t
834 for k,v in pairs(escape_table) do
835 k = k:gsub("%%", "%%%%")
836 t = t:gsub(v,k)
837 end
838 if t ~= tin then t = unescape_special_chars(t) end
839 return t
840 end
841
842 -- Encode/escape certain characters inside Markdown code runs.
843 -- The point is that in code, these characters are literals,
844 -- and lose their special Markdown meanings.
845 function encode_code(s)
846 s = s:gsub("%&", "&amp;")
847 s = s:gsub("<", "&lt;")
848 s = s:gsub(">", "&gt;")
849 for k,v in pairs(escape_table) do
850 s = s:gsub("%"..k, v)
851 end
852 return s
853 end
854
855 -- Handle backtick blocks.
856 local function code_spans(s)
857 s = s:gsub("\\\\", escape_table["\\"])
858 s = s:gsub("\\`", escape_table["`"])
859
860 local pos = 1
861 while true do
862 local start, stop = s:find("`+", pos)
863 if not start then return s end
864 local count = stop - start + 1
865 -- Find a matching numbert of backticks
866 local estart, estop = s:find(string.rep("`", count), stop+1)
867 local brstart = s:find("\n", stop+1)
868 if estart and (not brstart or estart < brstart) then
869 local code = s:sub(stop+1, estart-1)
870 code = code:gsub("^[ \t]+", "")
871 code = code:gsub("[ \t]+$", "")
872 code = code:gsub(escape_table["\\"], escape_table["\\"] .. escape_table["\\"])
873 code = code:gsub(escape_table["`"], escape_table["\\"] .. escape_table["`"])
874 code = "<code>" .. encode_code(code) .. "</code>"
875 code = add_escape(code)
876 s = s:sub(1, start-1) .. code .. s:sub(estop+1)
877 pos = start + code:len()
878 else
879 pos = stop + 1
880 end
881 end
882 return s
883 end
884
885 -- Encode alt text... enodes &, and ".
886 local function encode_alt(s)
887 if not s then return s end
888 s = s:gsub('&', '&amp;')
889 s = s:gsub('"', '&quot;')
890 s = s:gsub('<', '&lt;')
891 return s
892 end
893
894 local link_database
895
896 -- Handle image references
897 local function images(text)
898 local function reference_link(alt, id)
899 alt = encode_alt(alt:match("%b[]"):sub(2,-2))
900 id = id:match("%[(.*)%]"):lower()
901 if id == "" then id = text:lower() end
902 link_database[id] = link_database[id] or {}
903 if not link_database[id].url then return nil end
904 local url = link_database[id].url or id
905 url = encode_alt(url)
906 local title = encode_alt(link_database[id].title)
907 if title then title = " title=\"" .. title .. "\"" else title = "" end
908 return add_escape ('<img src="' .. url .. '" alt="' .. alt .. '"' .. title .. "/>")
909 end
910
911 local function inline_link(alt, link)
912 alt = encode_alt(alt:match("%b[]"):sub(2,-2))
913 local url, title = link:match("%(<?(.-)>?[ \t]*['\"](.+)['\"]")
914 url = url or link:match("%(<?(.-)>?%)")
915 url = encode_alt(url)
916 title = encode_alt(title)
917 if title then
918 return add_escape('<img src="' .. url .. '" alt="' .. alt .. '" title="' .. title .. '"/>')
919 else
920 return add_escape('<img src="' .. url .. '" alt="' .. alt .. '"/>')
921 end
922 end
923
924 text = text:gsub("!(%b[])[ \t]*\n?[ \t]*(%b[])", reference_link)
925 text = text:gsub("!(%b[])(%b())", inline_link)
926 return text
927 end
928
929 -- Handle anchor references
930 local function anchors(text)
931 local function reference_link(text, id)
932 text = text:match("%b[]"):sub(2,-2)
933 id = id:match("%b[]"):sub(2,-2):lower()
934 if id == "" then id = text:lower() end
935 link_database[id] = link_database[id] or {}
936 if not link_database[id].url then return nil end
937 local url = link_database[id].url or id
938 url = encode_alt(url)
939 local title = encode_alt(link_database[id].title)
940 if title then title = " title=\"" .. title .. "\"" else title = "" end
941 return add_escape("<a href=\"" .. url .. "\"" .. title .. ">") .. text .. add_escape("</a>")
942 end
943
944 local function inline_link(text, link)
945 text = text:match("%b[]"):sub(2,-2)
946 local url, title = link:match("%(<?(.-)>?[ \t]*['\"](.+)['\"]")
947 title = encode_alt(title)
948 url = url or link:match("%(<?(.-)>?%)") or ""
949 url = encode_alt(url)
950 if title then
951 return add_escape("<a href=\"" .. url .. "\" title=\"" .. title .. "\">") .. text .. "</a>"
952 else
953 return add_escape("<a href=\"" .. url .. "\">") .. text .. add_escape("</a>")
954 end
955 end
956
957 text = text:gsub("(%b[])[ \t]*\n?[ \t]*(%b[])", reference_link)
958 text = text:gsub("(%b[])(%b())", inline_link)
959 return text
960 end
961
962 -- Handle auto links, i.e. <http://www.google.com/>.
963 local function auto_links(text)
964 local function link(s)
965 return add_escape("<a href=\"" .. s .. "\">") .. s .. "</a>"
966 end
967 -- Encode chars as a mix of dec and hex entitites to (perhaps) fool
968 -- spambots.
969 local function encode_email_address(s)
970 -- Use a deterministic encoding to make unit testing possible.
971 -- Code 45% hex, 45% dec, 10% plain.
972 local hex = {code = function(c) return "&#x" .. string.format("%x", c:byte()) .. ";" end, count = 1, rate = 0.45}
973 local dec = {code = function(c) return "&#" .. c:byte() .. ";" end, count = 0, rate = 0.45}
974 local plain = {code = function(c) return c end, count = 0, rate = 0.1}
975 local codes = {hex, dec, plain}
976 local function swap(t,k1,k2) local temp = t[k2] t[k2] = t[k1] t[k1] = temp end
977
978 local out = ""
979 for i = 1,s:len() do
980 for _,code in ipairs(codes) do code.count = code.count + code.rate end
981 if codes[1].count < codes[2].count then swap(codes,1,2) end
982 if codes[2].count < codes[3].count then swap(codes,2,3) end
983 if codes[1].count < codes[2].count then swap(codes,1,2) end
984
985 local code = codes[1]
986 local c = s:sub(i,i)
987 -- Force encoding of "@" to make email address more invisible.
988 if c == "@" and code == plain then code = codes[2] end
989 out = out .. code.code(c)
990 code.count = code.count - 1
991 end
992 return out
993 end
994 local function mail(s)
995 s = unescape_special_chars(s)
996 local address = encode_email_address("mailto:" .. s)
997 local text = encode_email_address(s)
998 return add_escape("<a href=\"" .. address .. "\">") .. text .. "</a>"
999 end
1000 -- links
1001 text = text:gsub("<(https?:[^'\">%s]+)>", link)
1002 text = text:gsub("<(ftp:[^'\">%s]+)>", link)
1003
1004 -- mail
1005 text = text:gsub("<mailto:([^'\">%s]+)>", mail)
1006 text = text:gsub("<([-.%w]+%@[-.%w]+)>", mail)
1007 return text
1008 end
1009
1010 -- Encode free standing amps (&) and angles (<)... note that this does not
1011 -- encode free >.
1012 local function amps_and_angles(s)
1013 -- encode amps not part of &..; expression
1014 local pos = 1
1015 while true do
1016 local amp = s:find("&", pos)
1017 if not amp then break end
1018 local semi = s:find(";", amp+1)
1019 local stop = s:find("[ \t\n&]", amp+1)
1020 if not semi or (stop and stop < semi) or (semi - amp) > 15 then
1021 s = s:sub(1,amp-1) .. "&amp;" .. s:sub(amp+1)
1022 pos = amp+1
1023 else
1024 pos = amp+1
1025 end
1026 end
1027
1028 -- encode naked <'s
1029 s = s:gsub("<([^a-zA-Z/?$!])", "&lt;%1")
1030 s = s:gsub("<$", "&lt;")
1031
1032 -- what about >, nothing done in the original markdown source to handle them
1033 return s
1034 end
1035
1036 -- Handles emphasis markers (* and _) in the text.
1037 local function emphasis(text)
1038 for _, s in ipairs {"%*%*", "%_%_"} do
1039 text = text:gsub(s .. "([^%s][%*%_]?)" .. s, "<strong>%1</strong>")
1040 text = text:gsub(s .. "([^%s][^<>]-[^%s][%*%_]?)" .. s, "<strong>%1</strong>")
1041 end
1042 for _, s in ipairs {"%*", "%_"} do
1043 text = text:gsub(s .. "([^%s_])" .. s, "<em>%1</em>")
1044 text = text:gsub(s .. "(<strong>[^%s_]</strong>)" .. s, "<em>%1</em>")
1045 text = text:gsub(s .. "([^%s_][^<>_]-[^%s_])" .. s, "<em>%1</em>")
1046 text = text:gsub(s .. "([^<>_]-<strong>[^<>_]-</strong>[^<>_]-)" .. s, "<em>%1</em>")
1047 end
1048 return text
1049 end
1050
1051 -- Handles line break markers in the text.
1052 local function line_breaks(text)
1053 return text:gsub(" +\n", " <br/>\n")
1054 end
1055
1056 -- Perform all span level transforms.
1057 function span_transform(text)
1058 text = code_spans(text)
1059 text = escape_special_chars(text)
1060 text = images(text)
1061 text = anchors(text)
1062 text = auto_links(text)
1063 text = amps_and_angles(text)
1064 text = emphasis(text)
1065 text = line_breaks(text)
1066 return text
1067 end
1068
1069 ----------------------------------------------------------------------
1070 -- Markdown
1071 ----------------------------------------------------------------------
1072
1073 -- Cleanup the text by normalizing some possible variations to make further
1074 -- processing easier.
1075 local function cleanup(text)
1076 -- Standardize line endings
1077 text = text:gsub("\r\n", "\n") -- DOS to UNIX
1078 text = text:gsub("\r", "\n") -- Mac to UNIX
1079
1080 -- Convert all tabs to spaces
1081 text = detab(text)
1082
1083 -- Strip lines with only spaces and tabs
1084 while true do
1085 local subs
1086 text, subs = text:gsub("\n[ \t]+\n", "\n\n")
1087 if subs == 0 then break end
1088 end
1089
1090 return "\n" .. text .. "\n"
1091 end
1092
1093 -- Strips link definitions from the text and stores the data in a lookup table.
1094 local function strip_link_definitions(text)
1095 local linkdb = {}
1096
1097 local function link_def(id, url, title)
1098 id = id:match("%[(.+)%]"):lower()
1099 linkdb[id] = linkdb[id] or {}
1100 linkdb[id].url = url or linkdb[id].url
1101 linkdb[id].title = title or linkdb[id].title
1102 return ""
1103 end
1104
1105 local def_no_title = "\n ? ? ?(%b[]):[ \t]*\n?[ \t]*<?([^%s>]+)>?[ \t]*"
1106 local def_title1 = def_no_title .. "[ \t]+\n?[ \t]*[\"'(]([^\n]+)[\"')][ \t]*"
1107 local def_title2 = def_no_title .. "[ \t]*\n[ \t]*[\"'(]([^\n]+)[\"')][ \t]*"
1108 local def_title3 = def_no_title .. "[ \t]*\n?[ \t]+[\"'(]([^\n]+)[\"')][ \t]*"
1109
1110 text = text:gsub(def_title1, link_def)
1111 text = text:gsub(def_title2, link_def)
1112 text = text:gsub(def_title3, link_def)
1113 text = text:gsub(def_no_title, link_def)
1114 return text, linkdb
1115 end
1116
1117 link_database = {}
1118
1119 -- Main markdown processing function
1120 local function markdown(text)
1121 init_hash(text)
1122 init_escape_table()
1123
1124 text = cleanup(text)
1125 text = protect(text)
1126 text, link_database = strip_link_definitions(text)
1127 text = block_transform(text)
1128 text = unescape_special_chars(text)
1129 return text
1130 end
1131
1132 ----------------------------------------------------------------------
1133 -- End of module
1134 ----------------------------------------------------------------------
1135
1136 M.lock(M)
1137
1138 -- Expose markdown function to the world
1139 _G.markdown = M.markdown
1140
1141 -- Class for parsing command-line options
1142 local OptionParser = {}
1143 OptionParser.__index = OptionParser
1144
1145 -- Creates a new option parser
1146 function OptionParser:new()
1147 local o = {short = {}, long = {}}
1148 setmetatable(o, self)
1149 return o
1150 end
1151
1152 -- Calls f() whenever a flag with specified short and long name is encountered
1153 function OptionParser:flag(short, long, f)
1154 local info = {type = "flag", f = f}
1155 if short then self.short[short] = info end
1156 if long then self.long[long] = info end
1157 end
1158
1159 -- Calls f(param) whenever a parameter flag with specified short and long name is encountered
1160 function OptionParser:param(short, long, f)
1161 local info = {type = "param", f = f}
1162 if short then self.short[short] = info end
1163 if long then self.long[long] = info end
1164 end
1165
1166 -- Calls f(v) for each non-flag argument
1167 function OptionParser:arg(f)
1168 self.arg = f
1169 end
1170
1171 -- Runs the option parser for the specified set of arguments. Returns true if all arguments
1172 -- where successfully parsed and false otherwise.
1173 function OptionParser:run(args)
1174 local pos = 1
1175 local param
1176 while pos <= #args do
1177 local arg = args[pos]
1178 if arg == "--" then
1179 for i=pos+1,#args do
1180 if self.arg then self.arg(args[i]) end
1181 return true
1182 end
1183 end
1184 if arg:match("^%-%-") then
1185 local info = self.long[arg:sub(3)]
1186 if not info then print("Unknown flag: " .. arg) return false end
1187 if info.type == "flag" then
1188 info.f()
1189 pos = pos + 1
1190 else
1191 param = args[pos+1]
1192 if not param then print("No parameter for flag: " .. arg) return false end
1193 info.f(param)
1194 pos = pos+2
1195 end
1196 elseif arg:match("^%-") then
1197 for i=2,arg:len() do
1198 local c = arg:sub(i,i)
1199 local info = self.short[c]
1200 if not info then print("Unknown flag: -" .. c) return false end
1201 if info.type == "flag" then
1202 info.f()
1203 else
1204 if i == arg:len() then
1205 param = args[pos+1]
1206 if not param then print("No parameter for flag: -" .. c) return false end
1207 info.f(param)
1208 pos = pos + 1
1209 else
1210 param = arg:sub(i+1)
1211 info.f(param)
1212 end
1213 break
1214 end
1215 end
1216 pos = pos + 1
1217 else
1218 if self.arg then self.arg(arg) end
1219 pos = pos + 1
1220 end
1221 end
1222 return true
1223 end
1224
1225 -- Handles the case when markdown is run from the command line
1226 local function run_command_line(arg)
1227 -- Generate output for input s given options
1228 local function run(s, options)
1229 s = markdown(s)
1230 if not options.wrap_header then return s end
1231 local header = ""
1232 if options.header then
1233 local f = io.open(options.header) or error("Could not open file: " .. options.header)
1234 header = f:read("*a")
1235 f:close()
1236 else
1237 header = [[
1238 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1239 <html>
1240 <head>
1241 <meta http-equiv="content-type" content="text/html; charset=CHARSET" />
1242 <title>TITLE</title>
1243 <link rel="stylesheet" type="text/css" href="STYLESHEET" />
1244 </head>
1245 <body>
1246 ]]
1247 local title = options.title or s:match("<h1>(.-)</h1>") or s:match("<h2>(.-)</h2>") or
1248 s:match("<h3>(.-)</h3>") or "Untitled"
1249 header = header:gsub("TITLE", title)
1250 if options.inline_style then
1251 local style = ""
1252 local f = io.open(options.stylesheet)
1253 if f then
1254 style = f:read("*a") f:close()
1255 else
1256 error("Could not include style sheet " .. options.stylesheet .. ": File not found")
1257 end
1258 header = header:gsub('<link rel="stylesheet" type="text/css" href="STYLESHEET" />',
1259 "<style type=\"text/css\"><!--\n" .. style .. "\n--></style>")
1260 else
1261 header = header:gsub("STYLESHEET", options.stylesheet)
1262 end
1263 header = header:gsub("CHARSET", options.charset)
1264 end
1265 local footer = "</body></html>"
1266 if options.footer then
1267 local f = io.open(options.footer) or error("Could not open file: " .. options.footer)
1268 footer = f:read("*a")
1269 f:close()
1270 end
1271 return header .. s .. footer
1272 end
1273
1274 -- Generate output path name from input path name given options.
1275 local function outpath(path, options)
1276 if options.append then return path .. ".html" end
1277 local m = path:match("^(.+%.html)[^/\\]+$") if m then return m end
1278 m = path:match("^(.+%.)[^/\\]*$") if m and path ~= m .. "html" then return m .. "html" end
1279 return path .. ".html"
1280 end
1281
1282 -- Default commandline options
1283 local options = {
1284 wrap_header = true,
1285 header = nil,
1286 footer = nil,
1287 charset = "utf-8",
1288 title = nil,
1289 stylesheet = "default.css",
1290 inline_style = false
1291 }
1292 local help = [[
1293 Usage: markdown.lua [OPTION] [FILE]
1294 Runs the markdown text markup to HTML converter on each file specified on the
1295 command line. If no files are specified, runs on standard input.
1296
1297 No header:
1298 -n, --no-wrap Don't wrap the output in <html>... tags.
1299 Custom header:
1300 -e, --header FILE Use content of FILE for header.
1301 -f, --footer FILE Use content of FILE for footer.
1302 Generated header:
1303 -c, --charset SET Specifies charset (default utf-8).
1304 -i, --title TITLE Specifies title (default from first <h1> tag).
1305 -s, --style STYLE Specifies style sheet file (default default.css).
1306 -l, --inline-style Include the style sheet file inline in the header.
1307 Generated files:
1308 -a, --append Append .html extension (instead of replacing).
1309 Other options:
1310 -h, --help Print this help text.
1311 -t, --test Run the unit tests.
1312 ]]
1313
1314 local run_stdin = true
1315 local op = OptionParser:new()
1316 op:flag("n", "no-wrap", function () options.wrap_header = false end)
1317 op:param("e", "header", function (x) options.header = x end)
1318 op:param("f", "footer", function (x) options.footer = x end)
1319 op:param("c", "charset", function (x) options.charset = x end)
1320 op:param("i", "title", function(x) options.title = x end)
1321 op:param("s", "style", function(x) options.stylesheet = x end)
1322 op:flag("l", "inline-style", function(x) options.inline_style = true end)
1323 op:flag("a", "append", function() options.append = true end)
1324 op:flag("t", "test", function()
1325 local n = arg[0]:gsub("markdown.lua", "markdown-tests.lua")
1326 local f = io.open(n)
1327 if f then
1328 f:close() dofile(n)
1329 else
1330 error("Cannot find markdown-tests.lua")
1331 end
1332 run_stdin = false
1333 end)
1334 op:flag("h", "help", function() print(help) run_stdin = false end)
1335 op:arg(function(path)
1336 local file = io.open(path) or error("Could not open file: " .. path)
1337 local s = file:read("*a")
1338 file:close()
1339 s = run(s, options)
1340 file = io.open(outpath(path, options), "w") or error("Could not open output file: " .. outpath(path, options))
1341 file:write(s)
1342 file:close()
1343 run_stdin = false
1344 end
1345 )
1346
1347 if not op:run(arg) then
1348 print(help)
1349 run_stdin = false
1350 end
1351
1352 if run_stdin then
1353 local s = io.read("*a")
1354 s = run(s, options)
1355 io.write(s)
1356 end
1357 end
1358
1359 -- If we are being run from the command-line, act accordingly
1360 if arg and arg[0]:find("markdown%.lua$") then
1361 run_command_line(arg)
1362 else
1363 return markdown
1364 end
1919 if not qname then
2020 qname = name
2121 end
22 local ref,err = markup.process_reference(qname)
22 local ref, err
23 local custom_ref, refname = utils.splitv(qname,':')
24 if custom_ref and ldoc.custom_references then
25 custom_ref = ldoc.custom_references[custom_ref]
26 if custom_ref then
27 ref,err = custom_ref(refname)
28 end
29 end
30 if not ref then
31 ref,err = markup.process_reference(qname)
32 end
2333 if not ref then
2434 err = err .. ' ' .. qname
25 if item then item:warning(err)
35 if item and item.warning then item:warning(err)
2636 else
2737 io.stderr:write('nofile error: ',err,'\n')
2838 end
4353 res = res:gsub('`([^`]+)`',function(name)
4454 local ref,err = markup.process_reference(name)
4555 if ref then
56 if not plain and name then
57 name = name:gsub('_', '\\_')
58 end
4659 return ('<a href="%s">%s</a> '):format(ldoc.href(ref),name)
4760 else
4861 return '<code>'..name..'</code>'
5669 -- they can appear in the contents list as a ToC.
5770 function markup.add_sections(F, txt)
5871 local sections, L, first = {}, 1, true
59 local title_pat_end, title_pat = '[^#]%s*(.+)'
72 local title_pat
73 local lstrip = stringx.lstrip
6074 for line in stringx.lines(txt) do
6175 if first then
6276 local level,header = line:match '^(#+)%s*(.+)'
6579 else
6680 level = '##'
6781 end
68 title_pat = '^'..level..title_pat_end
82 title_pat = '^'..level..'([^#]%s*.+)'
83 title_pat = lstrip(title_pat)
6984 first = false
85 F.display_name = header
7086 end
7187 local title = line:match (title_pat)
7288 if title then
73 -- Markdown does allow this pattern
89 -- Markdown allows trailing '#'...
7490 title = title:gsub('%s*#+$','')
75 sections[L] = F:add_document_section(title)
91 sections[L] = F:add_document_section(lstrip(title))
7692 end
7793 L = L + 1
7894 end
86102 return indent,line
87103 end
88104
89 local function non_blank (line)
90 return line:find '%S'
105 local function blank (line)
106 return not line:find '%S'
91107 end
92108
93109 local global_context, local_context
115131 code = concat(code,'\n')
116132 if code ~= '' then
117133 local err
134 -- If we omit the following '\n', a '--' (or '//') comment on the
135 -- last line won't be recognized.
118136 code, err = prettify.code(lang,filename,code..'\n',L,false)
119137 append(res,'<pre>')
120138 append(res, code)
152170 if indent >= 4 then -- indented code block
153171 local code = {}
154172 local plain
155 while indent >= 4 or not non_blank(line) do
173 while indent >= 4 or blank(line) do
156174 if not start_indent then
157175 start_indent = indent
158176 if line:match '^%s*@plain%s*$' then
161179 end
162180 end
163181 if not plain then
164 append(code,line:sub(start_indent))
182 append(code,line:sub(start_indent + 1))
165183 else
166184 append(res,line)
167185 end
170188 indent, line = indent_line(line)
171189 end
172190 start_indent = nil
173 if #code > 1 then table.remove(code) end
191 while #code > 1 and blank(code[#code]) do -- trim blank lines.
192 table.remove(code)
193 end
174194 pretty_code (code,'lua')
175195 else
176196 local section = F.sections[L]
00 -- parsing code for doc comments
11
2 local utils = require 'pl.utils'
23 local List = require 'pl.List'
34 local Map = require 'pl.Map'
45 local stringio = require 'pl.stringio'
67 local tools = require 'ldoc.tools'
78 local doc = require 'ldoc.doc'
89 local Item,File = doc.Item,doc.File
10 local unpack = utils.unpack
911
1012 ------ Parsing the Source --------------
1113 -- This uses the lexer from PL, but it should be possible to use Peter Odding's
6971 return preamble,tag_items
7072 end
7173
72 -- Tags are stored as an ordered map
74 -- Tags are stored as an ordered multi map from strings to strings
75 -- If the same key is used, then the value becomes a list
7376 local Tags = {}
7477 Tags.__index = Tags
7578
8891 return tags
8992 end
9093
91 function Tags:add (tag,value)
94 function Tags:add (tag,value,modifiers)
95 if modifiers then -- how modifiers are encoded
96 value = {value,modifiers=modifiers}
97 end
98 local ovalue = self:get(tag)
99 if ovalue then
100 ovalue:append(value)
101 value = ovalue
102 end
92103 rawset(self,tag,value)
93 self._order:append(tag)
104 if not ovalue then
105 self._order:append(tag)
106 end
107 end
108
109 function Tags:get (tag)
110 local ovalue = rawget(self,tag)
111 if ovalue then -- previous value?
112 if getmetatable(ovalue) ~= List then
113 ovalue = List{ovalue}
114 end
115 return ovalue
116 end
94117 end
95118
96119 function Tags:iter ()
128151 value = strip(value)
129152 end
130153
131 if modifiers then value = { value, modifiers=modifiers } end
132 local old_value = tags[tag]
133
134 if not old_value then -- first element
135 tags:add(tag,value)
136 elseif type(old_value)=='table' and old_value.append then -- append to existing list
137 old_value :append (value)
138 else -- upgrade string->list
139 tags:add(tag,List{old_value, value})
140 end
154 tags:add(tag,value,modifiers)
141155 end
142156 return tags --Map(tags)
143157 end
199213 local t,v = tnext(tok)
200214 -- with some coding styles first comment is standard boilerplate; option to ignore this.
201215 if args.boilerplate and t == 'comment' then
216 -- hack to deal with boilerplate inside Lua block comments
217 if v:match '%s*%-%-%[%[' then lang:grab_block_comment(v,tok) end
202218 t,v = tnext(tok)
203219 end
204220 if t == '#' then -- skip Lua shebang line, if present
349365 if is_local or tags['local'] then
350366 tags:add('local',true)
351367 end
368 -- support for standalone fields/properties of classes/modules
369 if (tags.field or tags.param) and not tags.class then
370 -- the hack is to take a subfield and pull out its name,
371 -- (see Tag:add above) but let the subfield itself go through
372 -- with any modifiers.
373 local fp = tags.field or tags.param
374 if type(fp) == 'table' then fp = fp[1] end
375 fp = tools.extract_identifier(fp)
376 tags:add('name',fp)
377 tags:add('class','field')
378 end
352379 if tags.name then
353380 current_item = F:new_item(tags,line)
354381 current_item.inferred = item_follows ~= nil
356383 if module_item then
357384 F:error("Module already declared!")
358385 end
359 if tags.class == 'classmod' then
360 tags = tags.new('section','methods')
361 tags:add('summary','Methods')
362 F:new_item(tags,line)
363 end
364386 module_item = current_item
365387 end
366388 end
33 -- A module reference to an example `test-fun.lua` would look like
44 -- `@{example:test-fun}`.
55 local List = require 'pl.List'
6 local lexer = require 'ldoc.lexer'
76 local globals = require 'ldoc.builtin.globals'
8 local tnext = lexer.skipws
97 local prettify = {}
108
119 local escaped_chars = {
2523
2624 local spans = {keyword=true,number=true,string=true,comment=true,global=true,backtick=true}
2725
28 function prettify.lua (fname, code, initial_lineno, pre)
29 local res = List()
26 local cpp_lang = {c = true, cpp = true, cxx = true, h = true}
27
28 function prettify.lua (lang, fname, code, initial_lineno, pre)
29 local res, lexer, tokenizer = List(), require 'ldoc.lexer'
30 local tnext = lexer.skipws
31 if not cpp_lang[lang] then
32 tokenizer = lexer.lua
33 else
34 tokenizer = lexer.cpp
35 end
36
3037 if pre then
3138 res:append '<pre>\n'
3239 end
3340 initial_lineno = initial_lineno or 0
3441
35 local tok = lexer.lua(code,{},{})
42 local tok = tokenizer(code,{},{})
3643 local error_reporter = {
3744 warning = function (self,msg)
3845 io.stderr:write(fname..':'..tok:lineno()+initial_lineno..': '..msg,'\n')
7178
7279 function prettify.code (lang,fname,code,initial_lineno,pre)
7380 if not lxsh then
74 return prettify.lua (fname, code, initial_lineno, pre)
81 return prettify.lua (lang,fname, code, initial_lineno, pre)
7582 else
7683 if not lxsh_highlighers[lang] then
7784 lang = 'lua'
8188 external = true
8289 })
8390 if not pre then
84 code = code:gsub("^<pre*.->(.*)</pre>$", '%1')
91 code = code:gsub("^<pre.->(.-)%s*</pre>$", '%1')
8592 end
8693 return code
8794 end
0 mode=lua
1 tabs=use=false,size=3
1515 local quit = utils.quit
1616 local lfs = require 'lfs'
1717
18 -- at rendering time, can access the ldoc table from any module item,
19 -- or the item itself if it's a module
20 function M.item_ldoc (item)
21 local mod = item and (item.module or item)
22 return mod and mod.ldoc
23 end
24
1825 -- this constructs an iterator over a list of objects which returns only
1926 -- those objects where a field has a certain value. It's used to iterate
2027 -- only over functions or tables, etc. If the list of item has a module
2532 local fls = list:filter(function(item)
2633 return item[field] == value
2734 end)
28 local mod = fls[1] and fls[1].module
29 local ldoc = mod and mod.ldoc
35 local ldoc = M.item_ldoc(fls[1])
3036 if ldoc and ldoc.sort then
3137 fls:sort(function(ia,ib)
3238 return ia.name < ib.name
130136 end
131137 end
132138
133
134139 ----- some useful utility functions ------
135140
136141 function M.module_basepath()
144149 end
145150
146151 -- split a qualified name into the module part and the name part,
147 -- e.g 'pl.utils.split' becomes 'pl.utils' and 'split'
152 -- e.g 'pl.utils.split' becomes 'pl.utils' and 'split'. Also
153 -- must understand colon notation!
148154 function M.split_dotted_name (s)
149 local s1,s2 = path.splitext(s)
150 if s2=='' then return nil
151 else return s1,s2:sub(2)
152 end
155 local s1,s2 = s:match '^(.+)[%.:](.+)$'
156 if s1 then -- we can split
157 return s1,s2
158 else
159 return nil
160 end
161 --~ local s1,s2 = path.splitext(s)
162 --~ if s2=='' then return nil
163 --~ else return s1,s2:sub(2)
164 --~ end
153165 end
154166
155167 -- grab lines from a line iterator `iter` until the line matches the pattern.
283295 -- following the arguments. ldoc will use these in addition to explicit
284296 -- param tags.
285297
286 function M.get_parameters (tok,endtoken,delim)
298 function M.get_parameters (tok,endtoken,delim,lang)
287299 tok = M.space_skip_getter(tok)
288300 local args = List()
289301 args.comments = {}
291303
292304 if not ltl or not ltl[1] or #ltl[1] == 0 then return args end -- no arguments
293305
294 local function strip_comment (text)
295 return text:match("%s*%-%-+%s*(.*)")
306 local strip_comment, extract_arg
307
308 if lang then
309 strip_comment = utils.bind1(lang.trim_comment,lang)
310 extract_arg = utils.bind1(lang.extract_arg,lang)
311 else
312 strip_comment = function(text)
313 return text:match("%s*%-%-+%s*(.*)")
314 end
315 extract_arg = function(tl,idx)
316 return value_of(tl[idx or 1])
317 end
296318 end
297319
298320 local function set_comment (idx,tok)
304326 text = current_comment .. " " .. text
305327 end
306328 args.comments[arg] = text
329 end
330
331 local function add_arg (tl,idx)
332 local name, type = extract_arg(tl,idx)
333 args:append(name)
334 if type then
335 if not args.types then args.types = List() end
336 args.types:append(type)
337 end
307338 end
308339
309340 for i = 1,#ltl do
322353 j = j + 1
323354 end
324355 if #tl > 1 then
325 args:append(value_of(tl[j]))
356 add_arg(tl,j)
326357 end
327358 else
328 args:append(value_of(tl[1]))
359 add_arg(tl,1)
329360 end
330361 if i == #ltl and #tl > 1 then
331362 while j <= #tl and type_of(tl[j]) ~= 'comment' do
0 package = "ldoc"
1 version = "scm-2"
2
3 source = {
4 dir="LDoc",
5 url = "git://github.com/stevedonovan/LDoc.git"
6 }
7
8 description = {
9 summary = "A Lua Documentation Tool",
10 detailed = [[
11 LDoc is a LuaDoc-compatible documentation generator which can also
12 process C extension source. Markdown may be optionally used to
13 render comments, as well as integrated readme documentation and
14 pretty-printed example files
15 ]],
16 homepage='http://stevedonovan.github.com/ldoc',
17 maintainer='steve.j.donovan@gmail.com',
18 license = "MIT/X11",
19 }
20
21 dependencies = {
22 "penlight","markdown"
23 }
24
25 build = {
26 type = "builtin",
27 modules = {
28 ["ldoc.tools"] = "ldoc/tools.lua",
29 ["ldoc.lang"] = "ldoc/lang.lua",
30 ["ldoc.parse"] = "ldoc/parse.lua",
31 ["ldoc.html"] = "ldoc/html.lua",
32 ["ldoc.lexer"] = "ldoc/lexer.lua",
33 ["ldoc.markup"] = "ldoc/markup.lua",
34 ["ldoc.prettify"] = "ldoc/prettify.lua",
35 ["ldoc.markdown"] = "ldoc/markdown.lua",
36 ["ldoc.doc"] = "ldoc/doc.lua",
37 ["ldoc.html.ldoc_css"] = "ldoc/html/ldoc_css.lua",
38 ["ldoc.html.ldoc_ltp"] = "ldoc/html/ldoc_ltp.lua",
39 ["ldoc.html.ldoc_one_css"] = "ldoc/html/ldoc_one_css.lua",
40 ["ldoc.html.ldoc_pale_css"] = "ldoc/html/ldoc_pale_css.lua",
41 ["ldoc.builtin.globals"] = "ldoc/builtin/globals.lua",
42 ["ldoc.builtin.coroutine"] = "ldoc/builtin/coroutine.lua",
43 ["ldoc.builtin.global"] = "ldoc/builtin/global.lua",
44 ["ldoc.builtin.debug"] = "ldoc/builtin/debug.lua",
45 ["ldoc.builtin.io"] = "ldoc/builtin/io.lua",
46 ["ldoc.builtin.lfs"] = "ldoc/builtin/lfs.lua",
47 ["ldoc.builtin.lpeg"] = "ldoc/builtin/lpeg.lua",
48 ["ldoc.builtin.math"] = "ldoc/builtin/math.lua",
49 ["ldoc.builtin.os"] = "ldoc/builtin/os.lua",
50 ["ldoc.builtin.package"] = "ldoc/builtin/package.lua",
51 ["ldoc.builtin.string"] = "ldoc/builtin/string.lua",
52 ["ldoc.builtin.table"] = "ldoc/builtin/table.lua",
53 },
54 copy_directories = {'doc','tests'},
55 install = {
56 bin = {
57 ldoc = "ldoc.lua"
58 }
59 }
60 }
61
66 --
77 -- C/C++ support for Lua extensions is provided.
88 --
9 -- Available from LuaRocks as 'ldoc' and as a [Zip file](http://stevedonovan.github.com/files/ldoc-1.3.9.zip)
9 -- Available from LuaRocks as 'ldoc' and as a [Zip file](http://stevedonovan.github.com/files/ldoc-1.4.2.zip)
1010 --
1111 -- [Github Page](https://github.com/stevedonovan/ldoc)
1212 --
2424 local stringx = require 'pl.stringx'
2525 local tablex = require 'pl.tablex'
2626
27 -- Penlight compatibility
28 utils.unpack = utils.unpack or unpack or table.unpack
2729
2830 local append = table.insert
2931
3436
3537 --- @usage
3638 local usage = [[
37 ldoc, a documentation generator for Lua, vs 1.4.0
39 ldoc, a documentation generator for Lua, vs 1.4.2
3840 -d,--dir (default doc) output directory
3941 -o,--output (default 'index') output name
4042 -v,--verbose verbose
4951 -b,--package (default .) top-level package basename (needed for module(...))
5052 -x,--ext (default html) output file extension
5153 -c,--config (default config.ld) configuration name
54 -u,--unqualified don't show package name in sidebar links
5255 -i,--ignore ignore any 'no doc comment or no module' warnings
5356 -X,--not_luadoc break LuaDoc compatibility. Descriptions may continue after tags.
5457 -D,--define (default none) set a flag to be used in config.ld
7982 local quit = utils.quit
8083
8184
82 class.ModuleMap(KindMap)
83 local ModuleMap = ModuleMap
85 local ModuleMap = class(KindMap)
86 doc.ModuleMap = ModuleMap
8487
8588 function ModuleMap:_init ()
8689 self.klass = ModuleMap
8790 self.fieldname = 'section'
8891 end
8992
90 ModuleMap:add_kind('function','Functions','Parameters')
91 ModuleMap:add_kind('table','Tables','Fields')
92 ModuleMap:add_kind('field','Fields')
93 ModuleMap:add_kind('lfunction','Local Functions','Parameters')
94 ModuleMap:add_kind('annotation','Issues')
95
96
97 class.ProjectMap(KindMap)
93 local ProjectMap = class(KindMap)
9894 ProjectMap.project_level = true
9995
10096 function ProjectMap:_init ()
10298 self.fieldname = 'type'
10399 end
104100
105 ProjectMap:add_kind('module','Modules')
106 ProjectMap:add_kind('script','Scripts')
107 ProjectMap:add_kind('classmod','Classes')
108 ProjectMap:add_kind('topic','Topics')
109 ProjectMap:add_kind('example','Examples')
101
110102
111103 local lua, cc = lang.lua, lang.cc
112104
121113 ['.mm'] = cc,
122114 ['.moon'] = lang.moon,
123115 }
124
125116 ------- ldoc external API ------------
126117
127118 -- the ldoc table represents the API available in `config.ld`.
128119 local ldoc = { charset = 'UTF-8' }
120
121 local known_types, kind_names = {}
122
123 local function lookup (itype,igroup,isubgroup)
124 local kn = kind_names[itype]
125 known_types[itype] = true
126 if kn then
127 if type(kn) == 'string' then
128 igroup = kn
129 else
130 igroup = kn[1]
131 isubgroup = kn[2]
132 end
133 end
134 return itype, igroup, isubgroup
135 end
136
137 local function setup_kinds ()
138 kind_names = ldoc.kind_names or {}
139
140 ModuleMap:add_kind(lookup('function','Functions','Parameters'))
141 ModuleMap:add_kind(lookup('table','Tables','Fields'))
142 ModuleMap:add_kind(lookup('field','Fields'))
143 ModuleMap:add_kind(lookup('lfunction','Local Functions','Parameters'))
144 ModuleMap:add_kind(lookup('annotation','Issues'))
145
146 ProjectMap:add_kind(lookup('module','Modules'))
147 ProjectMap:add_kind(lookup('script','Scripts'))
148 ProjectMap:add_kind(lookup('classmod','Classes'))
149 ProjectMap:add_kind(lookup('topic','Topics'))
150 ProjectMap:add_kind(lookup('example','Examples'))
151
152 for k in pairs(kind_names) do
153 if not known_types[k] then
154 quit("unknown item type "..tools.quote(k).." in kind_names")
155 end
156 end
157 end
158
159
129160 local add_language_extension
130
131 local function override (field)
132 if ldoc[field] ~= nil then args[field] = ldoc[field] end
161 -- hacky way for doc module to be passed options...
162 doc.ldoc = ldoc
163
164 -- if the corresponding argument was the default, then any ldoc field overrides
165 local function override (field,defval)
166 defval = defval or false
167 if args[field] == defval and ldoc[field] ~= nil then args[field] = ldoc[field] end
133168 end
134169
135170 -- aliases to existing tags can be defined. E.g. just 'p' for 'param'
147182 type = type or name
148183 ldoc.alias(name,{'param',modifiers={type=type}})
149184 end
185
186 ldoc.alias ('error',doc.error_macro)
150187
151188 ldoc.tparam_alias 'string'
152189 ldoc.tparam_alias 'number'
185222 end
186223
187224 local ldoc_contents = {
188 'alias','add_language_extension','new_type','add_section', 'tparam_alias',
225 'alias','add_language_extension','custom_tags','new_type','add_section', 'tparam_alias',
189226 'file','project','title','package','format','output','dir','ext', 'topics',
190227 'one','style','template','description','examples', 'pretty', 'charset', 'plain',
191 'readme','all','manual_url', 'ignore', 'colon', 'sort', 'module_file',
192 'boilerplate','merge', 'wrap', 'not_luadoc', 'template_escape',
228 'readme','all','manual_url', 'ignore', 'colon', 'sort', 'module_file','vars',
229 'boilerplate','merge', 'wrap', 'not_luadoc', 'template_escape','merge_error_groups',
193230 'no_return_or_parms','no_summary','full_description','backtick_references', 'custom_see_handler',
194 'no_space_before_args',
231 'no_space_before_args','parse_extra','no_lua_ref','sort_modules','use_markdown_titles',
232 'unqualified', 'custom_display_name_handler', 'kind_names', 'custom_references',
195233 }
196234 ldoc_contents = tablex.makeset(ldoc_contents)
197235
298336 args.file = abspath(args.file)
299337 end
300338
339 if type(ldoc.custom_tags) == 'table' then -- custom tags
340 for i, custom in ipairs(ldoc.custom_tags) do
341 if type(custom) == 'string' then
342 custom = {custom}
343 ldoc.custom_tags[i] = custom
344 end
345 doc.add_tag(custom[1], 'ML')
346 end
347 end -- custom tags
348
301349 local source_dir = args.file
302350 if type(source_dir) == 'table' then
303351 source_dir = source_dir[1]
316364 -- * '..' the path given points to the source directory
317365 -- * 'NAME' explicitly give the base module package name
318366 --
367
368 override ('package','.')
319369
320370 local function setup_package_base()
321371 if ldoc.package then args.package = ldoc.package end
348398 local ftype = file_types[ext]
349399 if ftype then
350400 if args.verbose then print(f) end
401 ftype.extra = ldoc.parse_extra or {}
351402 local F,err = parse.file(f,ftype,args)
352403 if err then
353404 if F then
367418 override 'merge'
368419 override 'not_luadoc'
369420 override 'module_file'
421 override 'boilerplate'
422
423 setup_kinds()
424
425 -- LDoc is doing plain ole C, don't want random Lua references!
426 if ldoc.parse_extra and ldoc.parse_extra.C then
427 ldoc.no_lua_ref = true
428 end
429
430 if ldoc.merge_error_groups == nil then
431 ldoc.merge_error_groups = 'Error Message'
432 end
370433
371434 -- ldoc.module_file establishes a partial ordering where the
372435 -- master module files are processed first.
428491 quit ("file or directory does not exist: "..quote(args.file))
429492 end
430493
494
431495 -- create the function that renders text (descriptions and summaries)
432496 -- (this also will initialize the code prettifier used)
433 override 'format'
497 override ('format','plain')
434498 override 'pretty'
435499 ldoc.markup = markup.create(ldoc, args.format,args.pretty)
436500
468532 })
469533 -- wrap prettify for this example so it knows which file to blame
470534 -- if there's a problem
471 item.postprocess = function(code) return prettify.lua(f,code,0,true) end
535 local ext = path.extension(f):sub(2)
536 item.postprocess = function(code) return prettify.lua(ext,f,code,0,true) end
472537 end)
473538 end
474539
490555 -- headers in the readme, which are attached to the File. So
491556 -- we pass the File to the postprocesser, which will insert the section markers
492557 -- and resolve inline @ references.
558 if ldoc.use_markdown_titles then
559 item.display_name = F.display_name
560 end
493561 item.postprocess = function(txt) return ldoc.markup(txt,F) end
494562 end)
495563 end
519587 project:add(mod,module_list)
520588 end
521589
522 -- the default is not to show local functions in the documentation.
523 if not args.all and not ldoc.all then
524 for mod in module_list:iter() do
525 mod:mask_locals()
526 end
527 end
528
529 table.sort(module_list,function(m1,m2)
530 return m1.name < m2.name
531 end)
590 override 'all'
591
592 if ldoc.sort_modules then
593 table.sort(module_list,function(m1,m2)
594 return m1.name < m2.name
595 end)
596 end
532597
533598 ldoc.single = modcount == 1 and first_module or nil
534599
600 --do return end
535601
536602 -------- three ways to dump the object graph after processing -----
537603
542608 if args.module == true then
543609 file_list[1]:dump(args.verbose)
544610 else
545 local fun = module_list[1].items.by_name[args.module]
546 if not fun then quit(quote(args.module).." is not part of "..quote(args.file)) end
611 local M,name = module_list[1], args.module
612 local fun = M.items.by_name[name]
613 if not fun then
614 fun = M.items.by_name[M.mod_name..':'..name]
615 end
616 if not fun then quit(quote(name).." is not part of "..quote(args.file)) end
547617 fun:dump(true)
548618 end
549619 return
574644 os.exit()
575645 end
576646
647 -- can specify format, output, dir and ext in config.ld
648 override ('output','index')
649 override ('dir','doc')
650 override ('ext','html')
651 override 'one'
652
653 -- handling styling and templates --
577654 ldoc.css, ldoc.templ = 'ldoc.css','ldoc.ltp'
578655
656 -- special case: user wants to generate a .md file from a .lua file
579657 if args.ext == 'md' then
580 ldoc.templ = 'ldoc.mdtp'
658 if #module_list ~= 1 then
659 quit("can currently only generate Markdown output from one module only")
660 end
661 if ldoc.template == '!' then
662 ldoc.template = '!md'
663 end
664 args.output = module_list[1].name
665 args.dir = '.'
581666 ldoc.template_escape = '>'
582667 ldoc.style = false
583668 args.ext = '.md'
669 end
670
671 local function match_bang (s)
672 if type(s) ~= 'string' then return end
673 return s:match '^!(.*)'
584674 end
585675
586676 local function style_dir (sname)
593683 if style then
594684 if style == true then
595685 dir = config_dir
596 elseif type(style) == 'string' and path.isdir(style) then
686 elseif type(style) == 'string' and (path.isdir(style) or match_bang(style)) then
597687 dir = style
598688 else
599689 quit(quote(tostring(style)).." is not a directory")
601691 args[sname] = dir
602692 end
603693 end
604
605694
606695 -- the directories for template and stylesheet can be specified
607696 -- either by command-line '--template','--style' arguments or by 'template and
613702 style_dir 'style'
614703 style_dir 'template'
615704
616 -- can specify format, output, dir and ext in config.ld
617 override 'output'
618 override 'dir'
619 override 'ext'
620 override 'one'
621 override 'boilerplate'
622
623705 if not args.ext:find '^%.' then
624706 args.ext = '.'..args.ext
625707 end
626708
627709 if args.one then
628 ldoc.css = 'ldoc_one.css'
629 end
630
631 if args.style == '!' or args.template == '!' then
710 ldoc.style = '!one'
711 end
712
713 local builtin_style, builtin_template = match_bang(args.style),match_bang(args.template)
714 if builtin_style or builtin_template then
632715 -- '!' here means 'use built-in templates'
633716 local tmpdir = path.join(path.is_windows and os.getenv('TMP') or '/tmp','ldoc')
634717 if not path.isdir(tmpdir) then
635718 lfs.mkdir(tmpdir)
636719 end
637720 local function tmpwrite (name)
638 utils.writefile(path.join(tmpdir,name),require('ldoc.html.'..name:gsub('%.','_')))
639 end
640 if args.style == '!' then
721 local ok,text = pcall(require,'ldoc.html.'..name:gsub('%.','_'))
722 if not ok then
723 quit("cannot find builtin template "..name..": "..text)
724 end
725 if not utils.writefile(path.join(tmpdir,name),text) then
726 quit("cannot write to temp directory "..tmpdir)
727 end
728 end
729 if builtin_style then
730 if builtin_style ~= '' then
731 ldoc.css = 'ldoc_'..builtin_style..'.css'
732 end
641733 tmpwrite(ldoc.css)
642734 args.style = tmpdir
643735 end
644 if args.template == '!' then
736 if builtin_template then
737 if builtin_template ~= '' then
738 ldoc.templ = 'ldoc_'..builtin_template..'.ltp'
739 end
645740 tmpwrite(ldoc.templ)
646741 args.template = tmpdir
647742 end
1010 The [API documentation](http://stevedonovan.github.com/Penlight/api/index.html) of Penlight
1111 is an example of a project using plain LuaDoc markup processed using LDoc.
1212
13 LDoc is intended to be compatible with [LuaDoc](http://luadoc.luaforge.net/manual.htm) and
13 LDoc is intended to be compatible with [LuaDoc](http://keplerproject.github.io/luadoc/) and
1414 thus follows the pattern set by the various *Doc tools:
1515
1616 --- Summary ends with a period.
2222 len: => #@ls
2323
2424 --- string representation
25 -- @within Metamethods
2625 __tostring: => '['..(concat @ls,',')..']'
2726
2827 --- return idx of first occurence of `item`
5352 self
5453
5554 --- concatenate two lists, giving a new list
56 -- @within Metamethods
5755 __concat: (l1,l2) -> l1\copy!\extend l2
5856
5957 --- an iterator over all items
0 ------
1 -- Various ways of indicating errors
2 -- @module multiple
3
4 -----
5 -- function with return groups.
6 -- @treturn[1] string result
7 -- @return[2] nil
8 -- @return[2] error message
9 function mul1 () end
10
11 -----
12 -- function with return and error tag
13 -- @return result
14 -- @error message
15 function mul2 () end
16
17 -----
18 -- function with multiple error tags
19 -- @return result
20 -- @error not found
21 -- @error bad format
22 function mul3 () end
23
24 ----
25 -- function with inline return and errors
26 -- @string name
27 function mul4 (name)
28 if type(name) ~= 'string' then
29 --- @error[1] not a string
30 return nil, 'not a string'
31 end
32 if #name == 0 then
33 --- @error[2] zero-length string
34 return nil, 'zero-length string'
35 end
36 --- @treturn string converted to uppercase
37 return name:upper()
38 end
39 -----
40 -- function that raises an error.
41 -- @string filename
42 -- @treturn string result
43 -- @raise 'file not found'
44 function mul5(filename) end
00 --------------------------------------------------------------------------------
1 --- Queue of objects sorted by priority
1 --- Queue of objects sorted by priority.
22 -- @module lua-nucleo.priority_queue
3 -- This file is a part of lua-nucleo library
3 -- This file is a part of lua-nucleo library. Note that if you wish to spread
4 -- the description after tags, then invoke with `not_luadoc=true`.
5 -- The flags here are `ldoc -X -f backtick priority_queue.lua`, which
6 -- also expands backticks.
47 -- @copyright lua-nucleo authors (see file `COPYRIGHT` for the license)
58 --------------------------------------------------------------------------------
69
3336
3437 local insert = function(self, priority, value)
3538 method_arguments(
36 self,
39 s
3740 "number", priority
3841 )
3942 assert(value ~= nil, "value can't be nil") -- value may be of any type, except nil
0 ------
1 -- functions returning compound types
2 -- @module struct
3
4 -----
5 -- returns a 'struct'.
6 -- @string name your name dammit
7 -- @tfield string arb stuff
8 -- @treturn st details of person
9 -- @tfield[st] string name of person
10 -- @tfield[st] int age of person
11 function struct(name) end
12
0 -----
1 -- module containing a class
2 -- @module type
3
4 ----
5 -- Our class.
6 -- @type Bonzo
7
8 ----
9 -- make a new Bonzo.
10 -- @see Bonzo:dog
11 -- @string s name of Bonzo
12 function Bonzo.new(s)
13 end
14
15 -----
16 -- get a string representation.
17 -- works with `tostring`
18 function Bonzo:__tostring()
19 end
20
21 ----
22 -- Another method.
23 function Bonzo:dog ()
24
25 end
26
27 ----
28 -- Private method.
29 -- You need -a flag or 'all=true' to see these
30 -- @local
31 function Bonzo:cat ()
32
33 end
34
35
36 ----
37 -- A subtable with fields.
38 -- @table Details
39 -- @string[readonly] name
40 -- @int[readonly] age
41
42 ---
43 -- This is a simple field/property of the class.
44 -- @string[opt="Bilbo",readonly] frodo direct access to text