diff options
author | chai <chaifix@163.com> | 2021-10-30 11:42:13 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2021-10-30 11:42:13 +0800 |
commit | 53364ddc2e09362cb17432abf4fb598557554a9f (patch) | |
tree | 8d2deafc82aceb13db31938a2aecc70927fc1457 | |
parent | 42ec7286b2d36a9ba22925f816a17cb1cc2aa5ce (diff) |
+ LDoc
109 files changed, 13985 insertions, 0 deletions
diff --git a/Data/Libraries/LDoc/.github/workflows/luacheck.yml b/Data/Libraries/LDoc/.github/workflows/luacheck.yml new file mode 100644 index 0000000..20b706c --- /dev/null +++ b/Data/Libraries/LDoc/.github/workflows/luacheck.yml @@ -0,0 +1,23 @@ +name: Luacheck + +on: [push, pull_request] + +jobs: + luacheck: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup Lua + uses: leafo/gh-actions-lua@v8 + with: + luaVersion: 5.4 + - name: Setup Lua Rocks + uses: leafo/gh-actions-luarocks@v4 + - name: Setup dependencies + run: luarocks install luacheck + - name: Run Code Linter + run: | + luacheck . + luarocks lint *.rockspec diff --git a/Data/Libraries/LDoc/.luacheckrc b/Data/Libraries/LDoc/.luacheckrc new file mode 100644 index 0000000..681b66a --- /dev/null +++ b/Data/Libraries/LDoc/.luacheckrc @@ -0,0 +1,21 @@ +unused_args = false +redefined = false +max_line_length = false + +include_files = { + "**/*.lua", + "*.rockspec", + ".luacheckrc", +} + +exclude_files = { + -- Tests are too messy to lint + "tests", + -- Travis Lua environment + "here/*.lua", + "here/**/*.lua", + -- GH Actions Lua Environment + ".lua", + ".luarocks", + ".install", +} diff --git a/Data/Libraries/LDoc/CHANGELOG.md b/Data/Libraries/LDoc/CHANGELOG.md new file mode 100644 index 0000000..a96b72c --- /dev/null +++ b/Data/Libraries/LDoc/CHANGELOG.md @@ -0,0 +1,105 @@ +## Version 1.4.4 + +### Features + * better Lua 5.3 support + * handles tables with integer_keys as well as string keys + * `--testing` - version and date does not change + * `--no_args_infer` to completely switch off argument inference and parsing + * `custom_csv` option to specify extra CSS file + * explicit warnings if we cannot deduce item from following code + * modules may return a single _function_ (see tests/funmod.lua) + * honours the `SOURCE_DATE_EPOCH` environment variable + * Moonscript fat arrow and auto-assign ctor support + * Better Discount support. All varieties including Debian lua-discount package (binding to libmarkdown2) + * prettier output for `ldoc -m` on Unix + * updated global builtin documentation + + +### Fixes + * consistently using Unix line-endings + * `--fatalwarnings` now also works with parser errors (#255) + * user-specific temporary directory for expanding templates + * blank line after comment of code block suppressed (#240) + * comments at end of code blocks were not highlighting + * strip left spaces from usage code (#191) + * don't parse `module` if it's a field name (e.g `foo.module()`) + * temporary files on Windows fix + +## Version 1.4.3 + +### Features + + * @include tag for including Markdown documentation file directly into module docstring + * `prettify_files` makes per-item links to prettified source. + * link targets rendered in bright yellow to make referenced functions more obvious + * add update time to footer of page + * better C support: `global_lookup=true` - invoked when `parse_extra={C=true}` + * `kind_names` can override names used in sidebar + +### Fixes + + * `all=true` in `config.ld` did not work. + * `dont_escape_underscore` logic fixed: do not use in prettified code blocks + * check that `ldoc` config exists before checking field values + * annotation rendering fixed + * summary not dropped when using `type` sections + * directory as argument case was broken + * parameter names which were List methods causing mayhem + * files are processed in fixed order across platforms + +## Version 1.4.2 + +### Features + + * Can define fields/properties of objects; `readonly` modifier supported (#93) + * Can switch off auto-linking to Lua manual with `no_lua_ref` + * Module sorting is off by default, use `sort_modules=true` + * References to 'classes' now work properly + * Option to use first Markdown title instead of file names with `use_markdown_titles` + * Automatic `Metamethods` and `Methods` sections generated for `classmod` classes + * `unqualified=true` to strip package names on sidebar (#110) + * Custom tags (which may be hidden) + * Custom Display Name handlers + +### Fixes + + * stricter about doc comments, now excludes common '----- XXXXX ----' pattern + * no longer expects space after `##` in Markdown (#96) + * Section lookup was broken + * With `export` tag, decide whether method is static or not + * `classmod` classes now respect custom sections (#113) + * Minor issues with prettification + * Command-line flags set explicitly take precendence over configuration file values. + * Boilerplate Lua block comment ignored properly (#137) + * Inline links with underscores sorted (#22) + * Info section ordering is now consistent (#150) + +## Version 1.4.0 + +### Features + + * `sort=true` to sort items within sections alphabetically + * `@set` tag in module comments; e.g, can say `@set sort=true` + * `@classmod` tag for defining modules that export one class + * can generate Markdown output + * Can prettify C as well as Lua code with built-in prettifier + * lfs and lpeg references understood + * 'pale' template available + * multiple return groups + * experimental `@error` tag + * Moonscript and plain C support + + +### Fixes + + * works with non-compatibily Lua 5.2, including `markdown.lua` + * module names can not be types + * all `builtin` Lua files are requirable without `module` + * backticks expand in copyright and other 'info' tabs + * `-m` tries harder to resolve methods + * auto-scroll in navigation area to avoid breaking identifiers + * better error message for non-luadoc-compatible behaviour + * custom see references fixed + + + diff --git a/Data/Libraries/LDoc/COPYRIGHT b/Data/Libraries/LDoc/COPYRIGHT new file mode 100644 index 0000000..841f141 --- /dev/null +++ b/Data/Libraries/LDoc/COPYRIGHT @@ -0,0 +1,22 @@ +LDoc License +----------- +Copyright (C) 2011 Steve Donovan. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/Data/Libraries/LDoc/Makefile b/Data/Libraries/LDoc/Makefile new file mode 100644 index 0000000..dade791 --- /dev/null +++ b/Data/Libraries/LDoc/Makefile @@ -0,0 +1,64 @@ +LUA= $(shell echo `which lua`) +LUA_BINDIR= $(shell echo `dirname $(LUA)`) +LUA_PREFIX= $(shell echo `dirname $(LUA_BINDIR)`) +LUA_SHAREDIR=$(LUA_PREFIX)/share/lua/5.1 + +_REPODIR != cd "$(shell dirname $(firstword $(MAKEFILE_LIST)))/" && pwd + +ldoc: + +install: install_parts + @echo "lua $(LUA_SHAREDIR)/ldoc.lua \$$*" > "$(DESTDIR)$(LUA_BINDIR)/ldoc" + @chmod -v +x "$(DESTDIR)$(LUA_BINDIR)/ldoc" + +install_luajit: install_parts + @echo "luajit $(LUA_SHAREDIR)/ldoc.lua \$$*" > "$(DESTDIR)$(LUA_BINDIR)/ldoc" + @chmod -v +x "$(DESTDIR)$(LUA_BINDIR)/ldoc" + +install_parts: + @if [ ! -d "$(DESTDIR)$(LUA_BINDIR)" ]; then \ + mkdir -vp "$(DESTDIR)$(LUA_BINDIR)"; \ + fi + @mkdir -vp "$(DESTDIR)$(LUA_SHAREDIR)" + @cp -v ldoc.lua "$(DESTDIR)$(LUA_SHAREDIR)" + @cp -vr ldoc "$(DESTDIR)$(LUA_SHAREDIR)" + +uninstall: + @-rm -v "$(DESTDIR)$(LUA_SHAREDIR)/ldoc.lua" + @-rm -vr "$(DESTDIR)$(LUA_SHAREDIR)/ldoc" + @-rm -v "$(DESTDIR)$(LUA_BINDIR)/ldoc" + +test: test-basic test-example test-md test-tables + +RUN=&& lua $(_REPODIR)/ldoc.lua . && diff -r doc cdocs && echo ok + +test-prep: + find -type d -name doc -execdir rsync -av --del {}/ cdocs/ \; + +test-basic: + cd tests $(RUN) + +test-example: + cd tests/example $(RUN) + +test-md: + cd tests/md-test $(RUN) + +test-tables: + cd tests/simple $(RUN) + +test-clean: clean-basic clean-example clean-md clean-tables + +CLEAN=&& lua $(_REPODIR)/ldoc.lua . && rd /S /Q cdocs && cp -rf doc cdocs + +clean-basic: + cd tests $(CLEAN) + +clean-example: + cd tests && cd example $(CLEAN) + +clean-md: + cd tests && cd md-test $(CLEAN) + +clean-tables: + cd tests && cd simple $(CLEAN) diff --git a/Data/Libraries/LDoc/README.md b/Data/Libraries/LDoc/README.md new file mode 100644 index 0000000..bb660a1 --- /dev/null +++ b/Data/Libraries/LDoc/README.md @@ -0,0 +1,59 @@ +# LDoc - A Lua Documentation Tool + +[](https://github.com/lunarmodules/LDoc/actions) + +Copyright (C) 2011-2012 Steve Donovan. + +## Rationale + +This project grew out of the documentation needs of +[Penlight](https://github.com/lunarmodules/Penlight) (and not always getting satisfaction +with LuaDoc) and depends on Penlight itself. (This allowed me to _not_ write a lot of code.) + +The [API documentation](https://lunarmodules.github.io/Penlight/) of Penlight +is an example of a project using plain LuaDoc markup processed using LDoc. + +LDoc is intended to be compatible with [LuaDoc](https://keplerproject.github.io/luadoc/) and +thus follows the pattern set by the various *Doc tools: + + --- Summary ends with a period. + -- Some description, can be over several lines. + -- @param p1 first parameter + -- @param p2 second parameter + -- @return a string value + -- @see second_fun + function mod1.first_fun(p1,p2) + end + +Tags such as `see` and `usage` are supported, and generally the names of functions and +modules can be inferred from the code. + +LDoc is designed to give better diagnostics: if a `@see` reference cannot be found, then the +line number of the reference is given. LDoc knows about modules which do not use `module()` +- this is important since this function has become deprecated in Lua 5.2. And you can avoid +having to embed HTML in commments by using Markdown. + +LDoc will also work with Lua C extension code, and provides some convenient shortcuts. + +An example showing the support for named sections and 'classes' is the [Winapi +documentation](https://stevedonovan.github.io/winapi/api.html); this is generated from +[winapi.l.c](https://github.com/stevedonovan/winapi/blob/master/winapi.l.c). + +## Installation + +This is straightforward; the only external dependency is +[Penlight](https://github.com/lunarmodules/Penlight), which in turn needs +[LuaFileSystem](https://keplerproject.github.io/luafilesystem/). These are already present +in [Lua for Windows](https://github.com/rjpcomputing/luaforwindows), and Penlight is also available through [LuaRocks](https://luarocks.org/) as `luarocks install +penlight`. + +Unpack the sources somewhere and make an alias to `ldoc.lua` on your path. That is, either +an executable script called 'ldoc' like so: + + lua /path/to/ldoc/ldoc.lua $* + +Or a batch file called 'ldoc.bat': + + @echo off + lua \path\to\ldoc\ldoc.lua %* + diff --git a/Data/Libraries/LDoc/doc/config.ld b/Data/Libraries/LDoc/doc/config.ld new file mode 100644 index 0000000..b775eed --- /dev/null +++ b/Data/Libraries/LDoc/doc/config.ld @@ -0,0 +1,19 @@ +project='LDoc' +title='LDoc documentation' +description='A Lua documentation tool' +format='discount' +backtick_references=false +file='../ldoc.lua' +dir='../out' +readme='doc.md' +style='!new' +kind_names={topic='Manual',script='Programs'} +examples = { + '../tests/styles/colon.lua', + '../tests/styles/four.lua', + '../tests/styles/three.lua', + '../tests/styles/multiple.lua', + '../tests/example/mylib.c', + '../tests/moonscript/List.moon', +} + diff --git a/Data/Libraries/LDoc/doc/doc.md b/Data/Libraries/LDoc/doc/doc.md new file mode 100644 index 0000000..cdb4f61 --- /dev/null +++ b/Data/Libraries/LDoc/doc/doc.md @@ -0,0 +1,1406 @@ +# LDoc, a Lua Documentation Tool + +@lookup doc.md + +## Introduction + +LDoc is a software documentation tool which automatically generates API documentation +out of source code comments (doc comments). It is mainly targeted at Lua and documenting +Lua APIs, but it can also parse C with according doc comments for documenting Lua modules +implemented in C. + +It is mostly compatible with [LuaDoc](http://keplerproject.github.io/luadoc/), +except that certain workarounds are no longer needed. +For instance, it is not so married to the idea that Lua modules should be defined using the +`module` function; this is not only a matter of taste since this has been deprecated in Lua +5.2. + +Otherwise, the output is very similar, which is no accident since the HTML templates are +based directly on LuaDoc. You can ship your own customized templates and style sheets with +your [own project](https://nilnor.github.io/textui/docs/) (also see Graham Hannington's +documentation for [Lua for z/OS](http://lua4z.com/doc/)). LDoc comes with three extra themes; 'pale' +for those who like whitespace, 'one' for one-column output, and 'fixed' for a fixed navigation +bar down the left side. + +You have an option to use Markdown to process the documentation, which means no ugly HTML +is needed in doc comments. +C/C++ extension modules may be documented in a similar way, although function +names cannot be inferred from the code itself. + +LDoc can provide integrated documentation, with traditional function comments, any documents +in Markdown format, and specified source examples. Lua source in examples and the documents +will be prettified. + +Although there are a fair number of command-line options, the preferred route is to write a +`config.ld` configuration file in Lua format. By convention, if LDoc is simply invoked as +`ldoc .` it will read this file first. In this way, the aim is to make it very easy for +end-users to build your documentation using this simple command. + +## Commenting Conventions + +LDoc follows the conventions established by Javadoc and later by LuaDoc to document the +modules, functions, tables and types ("classes") of your API. + +### Doc comments + +Only 'doc comments' are parsed; these can be started with at least 3 hyphens, or by a empty +comment line with at least 3 hypens: + + --- summary. + -- Description; this can extend over + -- several lines + + ----------------- + -- This will also do. + +You can also use Lua block comments: + + --[[-- + Summary. A description + ...; + ]] + +Any module or script must start with a doc comment; any other files are ignored and a +warning issued. The only exception is if the module starts with an explicit `module` +statement. + +If your coding standards require a boilerplate copyright notice, then the `-B` flag or +`boilerplate=true` will make LDoc ignore the first comment of each module. + +Common commenting patterns like '---- (text) -----' are exempted, since they are often used +for programmer-facing documentation. + + +### Tags + +All doc comments start with a summary sentence, that ends with a period or a question mark. +An optional description may follow. Normally the summary sentence will appear in the module +contents. + +After this descriptive text, there will typically be _tags_ which are introduced with an @. +These follow the convention established by Javadoc and widely used in tools for other languages. + + --- Some doc comment + -- @tag1 parameters for first tag + -- @tag2 parameters for the second tag + +The order of tags is not important, but as always, consistency is useful. + +Here are all the tags known to LDoc: + + * **@module** A Lua module containing functions and tables, which may be inside sections + * **@classmod** Like **@module** but describing a class + * **@submodule** A file containing definitions that you wish to put into the named _master_ module + * **@script** A Lua program + * **@author** (multiple), **@copyright**, **@license**, **@release** only used for _project-level_ tags like **@module** + * **@function**, **@lfunction**. Functions inside a module + * **@param** formal arguments of a function (multiple) + * **@return** returned values of a function (multiple) + * **@raise** unhandled error thrown by this function + * **@local** explicitly marks a function as not being exported (unless `--all`) + * **@see** reference other documented items + * **@usage** give an example of a function's use. (Has a somewhat different meaning when used + with **@module**) + * **@table** a Lua table + * **@field** a named member of a table + * **@section** starting a named section for grouping functions or tables together + * **@type** a section which describes a class + * **@within** puts the function or table into an implicit section + * **@fixme**, **@todo** and **@warning** are _annotations_, which are doc comments that + occur inside a function body. + +The first important tag to know is the module tag: + +#### Modules: naming and describing your API module + +The first thing in your API module should be a name and a description. +This is how a module is commonly done in Lua 5.2 with a **@module** tag at the top +which introduces the name: + + --- a test module + -- @module test + + local test = {} + + function test.my_module_function_1() + ... + end + + ... + + return test + +This sets up a module named 'test' with the description 'a test module'. + +#### Functions + +The next thing to describe are the functions your module has. +This is a simple example of a documented function: + + --- foo explodes text. + -- It is a specialized splitting operation on a string. + -- @param text the string + -- @return a table of substrings + function foo (text) + .... + end + +You can also give the function name itself as an explicit tag, +which is especially useful when documenting a Lua api exported by C code: + +```C +/// A C function which is exported to Lua with another name, +// because the ways of C can be mysterious! +// @function our_nice_function +int _some_function_for_lua(lua_State* l) { + .... +} +``` + +The tags basically add all the detail that cannot be derived from the source code +automatically. + +#### Function parameters and return values + +Common tags are the 'param' tag which takes a parameter name followed by a parameter +description separated by a space, and the 'return' tag which is simply followed by +a description for a return value: + + -- @param name_of_parameter the description of this parameter as verbose text + -- @return the description of the return value + +If you want to [specify a type](#Tag_Modifiers) for a parameter or a return value, +there are also 'tparam' and 'treturn': + + -- @tparam string text this parameter is named 'text' and has the fixed type 'string' + -- @treturn {string,...} a table of substrings + +There may be multiple 'param' tags, which should document each formal parameter of the +function. For Lua, there can also be multiple 'return' tags + + --- solve a quadratic equation. + -- @param a first coeff + -- @param b second coeff + -- @param c third coeff + -- @return first root, or nil + -- @return second root, or imaginary root error + function solve (a,b,c) + local disc = b^2 - 4*a*c + if disc < 0 then + return nil,"imaginary roots" + else + disc = math.sqrt(disc) + return (-b + disc)/2*a, + (-b - disc)/2*a + end + end + + ... + +#### Tables and constant values (fields) + +Modules can of course export tables and other values. The classic way to document a table +looks like this: + + --- a useful table of constants + -- @field alpha first correction + -- @field beta second correction + -- @field gamma fudge factor + -- @table constants + +Here the kind of item is made explicit by the 'table' tag; tables have 'fields' in the same +way as functions have parameters. + +This can get tedious, so LDoc will attempt to extract table documentation from code: + + --- a useful table of constants + M.constants = { + alpha = 0.23, -- first correction + beta = 0.443, -- second correction + gamma = 0.01 -- fudge factor + } + +The rule followed here is `NAME = <table-constructor>`. If LDoc can't work out the name and +type from the following code, then a warning will be issued, pointing to the file and +location. Only single-level tables are currently supported, and the fields must be valid +identifiers. + +Another kind of module-level type is 'field', such as follows: + + --- module version. + M._VERSION = '0.5' + +That is, a module may contain exported functions, local functions, tables and fields. + +#### Explicitly specifying a function or fields + +When the code analysis would lead to the wrong type, you can always be explicit. + + --- module contents with explicitly documented field _CONTENTS. + -- @field _CONTENTS + M._CONTENTS = {constants=true,one=true,...} + + --- an explicitly named function. + -- @function my_function + function my_function() + ... + end + +This is especially useful in C where the function declarations +are different from final Lua api which you are documenting. + +### Doing modules the Lua 5.1 way + +As an alternative to using the 'module' tag as described previously, you +can still start your modules the Lua 5.1 way: + + --- solvers for common equations. + module("solvers", package.seeall) + +However, the 'module' function is deprecated in Lua 5.2 and it is increasingly +common to see less 'magic' ways of creating modules, as seen in the description +of the 'module' tag previously with the explicitely returned module table. + +### Repeating tags + +Tags like 'param' and 'return' can be specified multiple times, whereas a type +tag like 'function' can only occur once in a comment. + +The basic rule is that a single doc comment can only document one entity. + +### Local module name + +It is common to use a local name for a module when declaring its contents. In this case the +'alias' tag can tell LDoc that these functions do belong to the module: + + --- another test. + -- @module test2 + -- @alias M + + local M = {} + + -- first test. + function M.one() + .. + end + + return M + +`M` and `_M` are used commonly enough that LDoc will recognize them as aliases +automatically, but 'alias' allows you to use any identifier. + +LDoc tries to deduce the function name and the formal parameter names from examining the +code after the doc comment. It also recognizes the 'unsugared' way of defining functions as +explicit assignment to a variable: + + --- second test. + M.two = function(...) ... end + +### Local functions + +Apart from exported functions, a module usually contains local functions. By default, LDoc +does not include these in the documentation, but they can be enabled using the `--all` flag, +or `all=true` in `config.ld`. +They can be documented just like 'public' functions: + + --- it's clear that boo is local from context. + local function boo(...) .. end + + local foo + + --- we need to give a hint here for foo + -- @local here + function foo(...) .. end + +### Alternative way of specifying tags + +Since 1.3, LDoc allows the use of _colons_ instead of @. + + --- a simple function. + -- string: name person's name + -- int: age age of person + -- !person: person object + -- treturn: ?string + -- function check(name,age) + +However, you must either use the `--colon` flag or set `colon=true` in your `config.ld`. + +In this style, types may be used directly if prefixed with '!' or '?' (for type-or-nil) + +(see @{colon.lua}) + +## Sections + +LDoc supports _explicit_ sections. By default, the implicit sections correspond to the pre-existing +types in a module: 'Functions', 'Tables' and 'Fields' (There is another default section +'Local Functions' which only appears if LDoc is invoked with the `--all` flag.) But new +sections can be added; the first mechanism is when you @{Adding_new_Tags|define a new type} +(say 'macro'). Then a new section ('Macros') is created to contain these types. + +There is also a way to declare ad-hoc sections using the **@section** tag. +The need occurs when a module has a lot of functions that need to be put into logical +sections. + + --- File functions. + -- Useful utilities for opening foobar format files. + -- @section file + + --- open a file + ... + + --- read a file + ... + + --- Encoding operations. + -- Encoding foobar output in different ways. + -- @section encoding + + ... + +A section doc-comment has the same structure as a normal doc-comment; the summary is used as +the new section title, and the description will be output at the start of the function +details for that section; the name is not used, but must be unique. + +Sections appear under 'Contents' on the left-hand side. See the +[winapi](https://stevedonovan.github.io/winapi/api.html) documentation for an example of how +this looks. + +Arguably a module writer should not write such very long modules, but it is not the job of +the documentation tool to limit the programmer! + +A specialized kind of section is `type`: it is used for documenting classes. The functions +(or fields) within a type section are considered to be the methods of that class. + + --- A File class. + -- @type File + + .... + --- get the modification time. + -- @return standard time since epoch + function File:mtime() + ... + end + +(In an ideal world, we would use the word 'class' instead of 'type', but this would conflict +with the LuaDoc `class` tag.) + +A section continues until the next section is found, `@section end`, or end of file. + +You can put items into _implicit sections_ using **@within**. This allows you to put +adjacent functions in different sections, so that you are not forced to order your code +in a particular way. + +With 1.4, there is another option for documenting classes, which is the top-level type +`classmod`. It is intended for larger classes which are implemented within one module, +and the advantage that methods can be put into sections. + +Sometimes a module may logically span several files, which can easily happen with large +There will be a master module with name +'foo' and other files which when required add functions to that module. If these files have +a **@submodule** tag, their contents will be placed in the master module documentation. However, +a current limitation is that the master module must be processed before the submodules. + +See the `tests/submodule` example for how this works in practice. + +## Which files are processed? + +By default, LDoc will process any file ending in '.lua' or '.luadoc' in a specified +directory; you may point it to a single file as well. A 'project' usually consists of many +modules in one or more _packages_. The generated `index.html` will point to the generated +documentation for each of these modules. + +If only one module or script is documented for a project, then the `index.html` generated +contains the documentation for that module, since an index pointing to one module would be +redundant. + +LDoc has a two-layer hierarchy; underneath the project, there are modules, scripts, classes +(containing code) and examples and 'topics' (containing documentation). These then contain +items like functions, tables, sections, and so forth. + +If you want to document scripts, then use **@script** instead of **@module**. New with 1.4 is +**@classmod** which is a module which exports a single class. + +## See References + +**@see** is used to reference other parts of the documentation, and **@usage** can provide +examples of use; there can be multiple such tags: + + --------- + -- split a string in two. + -- @param s the string + -- @param delim the delimiter (default space) + -- @return first part + -- @return second part + -- @usage local hello,world = split2("hello world") + -- @see split + function split2(s,delim) .. end + +Here it's assumed that 'split' is a function defined in the same module. If you wish to link +to a function in another module, then the reference has to be qualified. + +References to methods use a colon: `myclass:method`; this is for instance how you would +refer to members of a **@type** section. + +The example at `tests/complex` shows how **@see** references are interpreted: + + complex.util.parse + complex.convert.basic + complex.util + complex.display + complex + +You may of course use the full name of a module or function, but can omit the top-level +namespace - e.g. can refer to the module `util` and the function `display.display_that` +directly. Within a module, you can directly use a function name, e.g. in `display` you can +say `display_this`. + +What applies to functions also applies to any module-level item like tables. New +module-level items can be defined and they will work according to these rules. + +If a reference is not found within the project, LDoc checks to see if it is a reference to a +Lua standard function or table, and links to the online Lua manual. So references like +'table.concat' are handled sensibly. + +References may be made inline using the `@{\ref}` syntax. This may appear anywhere in the +text, and is more flexible than **@see**. In particular, it provides one way to document the +type of a parameter or return value when that type has a particular structure: + + ------ + -- extract standard variables. + -- @param s the string + -- @return @{\\stdvars} + function extract_std(s) ... end + + ------ + -- standard variables. + -- Use @{\\extract_std} to parse a string containing variables, + -- and @{\\pack_std} to make such a string. + -- @field length + -- @field duration + -- @field viscosity + -- @table stdvars + +`@{\ref}` is very useful for referencing your API from code samples and readme text. + +The link text can be changed from the default by the extended syntax `@{\ref|text}. + +You can also put references in backticks, like `\`stdvars\``. This is commonly used in +Markdown to indicate code, so it comes naturally when writing documents. The difference +is that the backticked expression does not have to be a reference and then will appear +in code style; with @ references you will get a warning for unrecognized symbols +and the result will be rendered as '???'. + +It is controlled by the configuration variable `backtick_references` or the `backtick` format; +the default is `true` if you use Markdown in your project, but can be specified explicitly +in `config.ld`. + +To quote such references so they won't be expanded, say @{\\ref}. + +#### Custom @see References + +It's useful to define how to handle references external to a project. For instance, in the +[luaposix](https://github.com/luaposix/luaposix) project we wanted to have `man` references +to the corresponding C function: + + ------------ + -- raise a signal on this process. + -- @see raise(3) + -- @int nsig + -- @return integer error cod + function raise (nsig) + end + +These see references always have this particular form, and the task is to turn them into +online references to the Linux manpages. So in `config.ld` we have: + + local upat = "http://www.kernel.org/doc/man-pages/online/pages/man%s/%s.%s.html" + + custom_see_handler('^([%w_]+)%((%d)%)$',function(name,section) + local url = upat:format(section,name,section) + local name = name .. '(' ..section..')' + return name, url + end) + +`^([%w_]+)%((%d)%)$` both matches the pattern and extracts the name and its section. Then it's +a simple matter of building up the appropriate URL. The function is expected to +return _link text_ and _link source_ and the patterns are checked before LDoc tries to resolve +project references. So it is best to make them match as exactly as possible. + +## Module Tags + +LDoc requires you to have a module doc comment. If your code style requires +license blocks that might look like doc comments, then set `boilerplate=true` in your +configuration and they will be skipped. + +This comment does not have to have an explicit **@module** tag and LDoc continues to +respect the use of `module()`. + +There are three types of 'modules' (i.e. 'project-level'); `module`, a library +loadable with `require()`, `script`, a program, and `classmod` which is a class +implemented in a single module. + +There are some tags which are only useful in module comments: `author`,`copyright`, +`license` and `release`. These are presented in a special **Info** section in the +default HTML output. + +The **@usage** tag has a somewhat different presentation when used in modules; the text +is presented formatted as-is in a code font. If you look at the script `ldoc` in +this documentation, you can see how the command-line usage is shown. Since coding +is all about avoiding repetition and the out-of-sync issues that arise, +the **@usage** tag can appear later in the module, before a long string. For instance, +the main script of LDoc is [ldoc.lua](https://github.com/stevedonovan/LDoc/blob/master/ldoc.lua) +and you will see that the usage tag appears on line 36 before the usage string +presented as help. + +**@export** is another module tag that is usually 'detached'. It is for supporting +modules that wish to explicitly export their functions @{three.lua|at the end}. +In that example, both `question` and `answer` are local and therefore private to +the module, but `answer` has been explicitly exported. (If you invoke LDoc with +the `-a` flag on this file, you will see the documentation for the unexported +function as well.) + +**@set** is a powerful tag which assigns a configuration variable to a value _just for this module_. +Saying `@set no_summary=true` in a module comment will temporarily disable summary generation when +the template is expanded. Generally configuration variables that effect template expansion +are modifiable in this way. For instance, if you wish that the contents of a particular module +be sorted, then `@set sort=true` will do it _just_ for that module. + +## Adding new Tags + +LDoc tries to be faithful to LuaDoc, but provides some extensions. Aliases for tags can be +defined, and new types declared. + + --- zero function. Two new ldoc features here; item types + -- can be used directly as tags, and aliases for tags + -- can be defined in config.ld. + -- @function zero_fun + -- @p k1 first + -- @p k2 second + +Here an alias for 'param' has been defined. If a file `config.ld` is found in the source, +then it will be loaded as Lua data. For example, the configuration for the above module +provides a title and defines an alias for 'param': + + title = "testmod docs" + project = "testmod" + alias("p","param") + +Extra tag _types_ can be defined: + + new_type("macro","Macros") + +And then used as any other type: + + ----- + -- A useful macro. This is an example of a custom type. + -- @macro first_macro + -- @see second_function + +This will also create a new module section called 'Macros'. + +If your new type has arguments or fields, then specify the name: + + new_type("macro","Macros",false,"param") + +(The third argument means that this is not a _project level_ tag) + +Then you may say: + + ----- + -- A macro with arguments. + -- @macro second_macro + -- @param x the argument + +And the arguments will be displayed under the subsection 'param' + + +## Inferring more from Code + +The qualified name of a function will be inferred from any `function` keyword following the +doc comment. LDoc goes further with this kind of code analysis, however. + +Instead of: + + --- first table. + -- @table one + -- @field A alpha + -- @field B beta + M.one = { + A = 1, + B = 2; + } + +you can write: + + --- first table + -- @table one + M.one = { + A = 1, -- alpha + B = 2; -- beta + } + +Similarly, function parameter comments can be directly used: + + ------------ + -- third function. Can also provide parameter comments inline, + -- provided they follow this pattern. + function mod1.third_function( + alpha, -- correction A + beta, -- correction B + gamma -- factor C + ) + ... + end + +As always, explicit tags can override this behaviour if it is inappropriate. + +## Extension modules written in C + +LDoc can process C/C++ files: + +```c +/*** +Create a table with given array and hash slots. +@function createtable +@param narr initial array slots, default 0 +@param nrec initial hash slots, default 0 +@return the new table +*/ +static int l_createtable (lua_State *L) { +.... +``` + +Both `/**` and `///` are recognized as starting a comment block. Otherwise, the tags are +processed in exactly the same way. It is necessary to specify that this is a function with a +given name, since this cannot be reliably be inferred from code. Such a file will need a +module comment, which is treated exactly as in Lua. + +An unknown extension can be associated with a language using a call like +`add_language_extension('lc','c')` in `config.ld`. (Currently the language can only be 'c' +or 'lua'.) + +An LDoc feature which is particularly useful for C extensions is _module merging_. If several +files are all marked as `@module lib` then a single module `lib` is generated, containing all +the docs from the separate files. For this, use `merge=true`. + +See @{mylib.c} for the full example. + +## Moonscript Support + +1.4 introduces basic support for [Moonscript](https://moonscript.org). Moonscript module +conventions are just the same as Lua, except for an explicit class construct. +@{List.moon} shows how **@classmod** can declare modules that export one class, with metamethods +and methods put implicitly into a separate section. + +## Basic Usage + +For example, to process all files in the 'lua' directory: + + $ ldoc lua + output written to doc/ + +Thereafter the `doc` directory will contain `index.html` which points to individual modules +in the `modules` subdirectory. The `--dir` flag can specify where the output is generated, +and will ensure that the directory exists. The output structure is like LuaDoc: there is an +`index.html` and the individual modules are in the `modules` subdirectory. This applies to +all project-level types, so that you can also get `scripts`, `examples` and `topics` +directories. + +If your modules use `module(...)` then the module name has to be deduced. If `ldoc` is run +from the root of the package, then this deduction does not need any help - e.g. if your +package was `foo` then `ldoc foo` will work as expected. If we were actually in the `foo` +directory then `ldoc -b .. .` will correctly deduce the module names. An example would be +generating documentation for LuaDoc itself: + + $ ldoc -b .. /path/to/luadoc + +Without the `-b` setting the base of the package to the _parent_ of the directory, implicit +modules like `luadoc.config` will be incorrectly placed in the global namespace. + +For new-style modules, that don't use `module()`, it is recommended that the module comment +has an explicit `@module PACKAGE.NAME`. If it does not, then `ldoc` will still attempt to +deduce the module name, but may need help with `--package/-b` as above. + +A special case is if you simply say 'ldoc .'. Then there _must_ be a `config.ld` file +available in the directory, and it can specify the file: + + file = "mymod.lua" + title = "mymod documentation" + description = "mymod does some simple but useful things" + +`file` can of course point to a directory, just as with the `--file` option. This mode makes +it particularly easy for the user to build the documentation, by allowing you to specify +everything explicitly in the configuration. + +In `config.ld`, `file` may be a Lua table, containing file names or directories; if it has +an `exclude` field then that will be used to exclude files from the list, for example +`{'examples', exclude = {'examples/slow.lua'}}`. + +A particular configuration file can be specified with the `-c` flag. Configuration files don't +_have_ to contain a `file` field, but in that case LDoc does need an explicit file on the command +line. This is useful if you have some defaults you wish to apply to all of your docs. + +## Markdown Support + +`format = 'markdown'` can be used in your `config.ld` and will be used to process summaries +and descriptions; you can also use the `-f` flag. This requires a markdown processor. +LDoc knows how to use: + + - [markdown.lua](https://www.frykholm.se/files/markdown.lua) a pure Lua processor by +Niklas Frykholm. For convenience, LDoc comes with a copy of markdown.lua. + - [lua-discount](http://asbradbury.org/projects/lua-discount/), a faster alternative +(installed with `luarocks install lua-discount`). lua-discount uses the C +[discount](https://www.pell.portland.or.us/~orc/Code/discount/) Markdown processor which has +more features than the pure Lua version, such as PHP-Extra style tables. + - [lunamark](https://jgm.github.io/lunamark/), another pure Lua processor, faster than +markdown, and with extra features (`luarocks install lunamark`). + - commonmark via [cmark-lua](https://github.com/jgm/cmark-lua), a Lua wrapper +around the fast [libcmark](https://github.com/jgm/cmark) C library (`luarocks +install cmark`) + +You can request the processor you like with `format = 'markdown|discount|lunamark|commonmark|plain|backticks'`, and +LDoc will attempt to use it. If it can't find it, it will look for one of the other +markdown processors; the original `markdown.lua` ships with LDoc, although it's slow +for larger documents. + +Even with the default of 'plain' some minimal processing takes place, in particular empty lines +are treated as line breaks. If the 'backticks' formatter is used, then it's equivalent to +using `process_backticks=true` in `config.ld` and backticks will be +expanded into documentation links like `@{\ref}` and converted into `<code>ref</code>` +otherwise. + +This formatting applies to all of a project, including any readmes and so forth. You may want +Markdown for this 'narrative' documentation, but not for your code comments. `plain=true` will +switch off formatting for code. + +## Processing Single Modules + +`--output` can be used to give the output file a different name. This is useful for the +special case when a single module file is specified. Here an index would be redundant, so +the single HTML file generated contains the module documentation. + + $ ldoc mylib.lua --> results in doc/index.html + $ ldoc --output mylib mylib.lua --> results in doc/mylib.html + $ ldoc --output mylib --dir html mylib.lua --> results in html/mylib.html + +The default sections used by LDoc are 'Functions', 'Tables' and 'Fields', corresponding to +the built-in types 'function', 'table' and 'field'. If `config.ld` contains something like +`new_type("macro","Macros")` then this adds a new section 'Macros' which contains items of +'macro' type - 'macro' is registered as a new valid tag name. The default template then +presents items under their corresponding section titles, in order of definition. + +## Getting Help about a Module + +There is an option to simply dump the results of parsing modules. Consider the C example +`tests/example/mylib.c': + + @plain + $ ldoc --dump mylib.c + ---- + module: mylib A sample C extension. + Demonstrates using ldoc's C/C++ support. Can either use /// or /*** */ etc. + + function createtable(narr, nrec) + Create a table with given array and hash slots. + narr initial array slots, default 0 + nrec initial hash slots, default 0 + + function solve(a, b, c) + Solve a quadratic equation. + a coefficient of x^2 + b coefficient of x + c constant + return {"first root","second root"} + +This is useful to quickly check for problems; here we see that `createable` did not have a +return tag. + +LDoc takes this idea of data dumping one step further. If used with the `-m` flag it will +look up an installed Lua module and parse it. If it has been marked up in LuaDoc-style then +you will get a handy summary of the contents: + + @plain + $ ldoc -m pl.pretty + ---- + module: pl.pretty Pretty-printing Lua tables. + * read(s) - read a string representation of a Lua table. + * write(tbl, space, not_clever) - Create a string representation of a Lua table. + + * dump(t, ...) - Dump a Lua table out to a file or stdout. + +You can specify a fully qualified function to get more information: + + @plain + $ ldoc -m pl.pretty.write + + function write(tbl, space, not_clever) + create a string representation of a Lua table. + tbl {table} Table to serialize to a string. + space {string} (optional) The indent to use. + Defaults to two spaces. + not_clever {bool} (optional) Use for plain output, e.g {['key']=1}. + Defaults to false. + +LDoc knows about the basic Lua libraries, so that it can be used as a handy console reference: + + @plain + $> ldoc -m assert + + function assert(v, message) + Issues an error when the value of its argument `v` is false (i.e., + nil or false); otherwise, returns all its arguments. + `message` is an error + message; when absent, it defaults to "assertion failed!" + v + message + +Thanks to Mitchell's [Textadept](https://orbitalquark.github.io/textadept/) project, LDoc has a +set of `.luadoc` files for all the standard tables, plus +[LuaFileSystem](https://keplerproject.github.io/luafilesystem/) and +[LPeg](http://www.inf.puc-rio.br/~roberto/lpeg/lpeg.html). + + @plain + $> ldoc -m lfs.lock + + function lock(filehandle, mode, start, length) + Locks a file or a part of it. + This function works on open files; the file + handle should be specified as the first argument. The string mode could be + either r (for a read/shared lock) or w (for a write/exclusive lock). The + optional arguments start and length can be used to specify a starting point + and its length; both should be numbers. + Returns true if the operation was successful; in case of error, it returns + nil plus an error string. + filehandle + mode + start + length + +## Anatomy of a LDoc-generated Page + +[winapi](https://stevedonovan.github.io/winapi/api.html) can be used as a good example of a +module that uses extended LDoc features. + +The _navigation section_ down the left has several parts: + + - The project name (`project` in the config) + - A project description (`description`) + - **Contents** of the current page + - **Modules** listing all the modules in this project + +Note that `description` will be passed through Markdown, if it has been specified for the +project. This gives you an opportunity to make lists of links, etc; any '##' headers will be +formatted like the other top-level items on the navigation bar. + +**Contents** is automatically generated. It will contain any explicit sections +as well as the usual categories: 'Functions', 'Tables' and 'Fields'. For a documentation page, +the subtitles become the sections shown here. + +**Modules** will appear for any project providing Lua libraries; there may also be a 'Scripts' +section if the project contains Lua scripts. For example, +[LuaMacro](https://stevedonovan.github.io/LuaMacro/docs/api.html) has a driver script `luam` +in this section. The +[builtin](https://stevedonovan.github.io/LuaMacro/docs/modules/macro.builtin.html) module +only defines macros, which are defined as a _custom tag type[?]_. + +The _content section_ on the right shows: + + - The module summary and description + - The contents summary, per section as above + - The detailed documentation for each item + +As before, the description can use Markdown. The summary contains the contents of each +section as a table, with links to the details. This is where the difference between an +item's summary and an item's description is important; the first will appear in the contents +summary. The item details show the item name and its summary again, followed by the +description. There are then sections for the following tags: 'param', 'usage', 'return' and +'see' in that order. (For tables, 'Fields' is used instead of 'Parameters' but internally +fields of a table are stored as the 'param' tag.) + +By default, the items appear in the order of declaration within their section. If `sort=true` +then they will be sorted alphabetically. (This can be set per-module with @{Module_Tags|@set}.) + +You can of course customize the default template, but there are some parameters that can +control what the template will generate. Setting `one=true` in your configuration file +will give a _one-column_ layout, which can be easier to use as a programming reference. You +can suppress the contents summary with `no_summary`. + +If you don't like the usual top-level names, like 'Module' and 'Topics', you can override these +with `kind_names` in `config.ld`. For instance, in Penlight I use `kind_names={topic='Manual',module='Libraries'}` + +## Customizing the Page + +A basic customization is to override the default UTF-8 encoding using `charset`. For instance, +Brazillian software would find it useful to put `charset='ISO-8859-1'` in `config.ld`, or use +the **@charset** tag for individual files. + +Setting `no_return_or_parms` to `true` will suppress the display of 'param' and 'return' +tags. This may appeal to programmers who dislike the traditional @tag soup xDoc style and +prefer to comment functions just with a description. This is particularly useful when using +Markdown in a stylized way to specify arguments: + + --------- + -- This extracts the shortest common substring from the strings _s1_ and _s2_ + function M.common_substring(s1,s2) + +Here I've chosen to italicise parameter names; the main thing is to be consistent. + +This style is close to the Python [documentation +standard](https://docs.python.org/library/array.html#module-array), especially when used with +`no_summary`. + +It is also very much how the Lua documentation is ordered. For instance, this configuration +file formats the built-in documentation for the Lua global functions in a way which is close +to the original: + + project = 'Lua' + description = 'Lua Standard Libraries' + file = {'ldoc/builtin',exclude = {'ldoc/builtin/globals.lua'}} + no_summary = true + no_return_or_parms = true + format = 'discount' + +Generally, using Markdown gives you the opportunity to structure your documentation in any +way you want; particularly if using lua-discount and its [table +syntax](https://michelf.com/projects/php-markdown/extra/#table); the desired result can often +be achieved then by using a custom style sheet. + +## Examples + +It has been long known that documentation generated just from the source is not really +adequate to explain _how_ to use a library. People like reading narrative documentation, +and they like looking at examples. Previously I found myself dealing with source-generated +and writer-generated documentation using different tools, and having to match these up. + +LDoc allows for source examples to be included in the documentation. For example, see the +online documentation for [winapi](https://stevedonovan.github.io/winapi/api.html). The +function `utf8_expand` has a **@see** reference to 'testu.lua' and following that link gives +you a pretty-printed version of the code. + +The line in the `config.ld` that enables this is: + + examples = {'examples', exclude = {'examples/slow.lua'}} + +That is, all files in the `examples` folder are to be pretty-printed, except for `slow.lua` +which is meant to be called from one of the examples. +To link to an example, use a reference like `@{\testu.lua}` +which resolves to 'examples/testu.lua.html'. + +Examples may link back to the API documentation, for instance the example `input.lua` has a +`@{\spawn_process}` inline reference. + +By default, LDoc uses a built-in Lua code 'prettifier'. Reference links are allowed in comments, +and also in code if they're enclosed in backticks. Lua and C are known languages. + +[lxsh](https://github.com/xolox/lua-lxsh) +can be used (available from LuaRocks) if you want something more powerful. `pretty='lxsh'` will +cause `lxsh` to be used, if available. + +Sometimes the best examples you have are your source files. `prettify_files=true` will prettify +all sources, and generate per-function links to the source. + +## Readme files + +Like all good Github projects, Winapi has a `readme.md`: + + readme = "readme.md" + +This goes under the 'Topics' global section; the 'Contents' of this document is generated +from the second-level (##) headings of the readme. + +Readme files are always processed with the current Markdown processor, but may also contain `@{\ref}` references back +to the documentation and to example files. Any symbols within backticks will be expanded as +references, if possible. As with doc comments, a link to a standard Lua function like +`@{\os.execute}` will work as well. Any code sections will be pretty-printed as Lua, unless +the first indented line is '@plain'. (See the source for this readme to see how it's used.) + +Another name for `readme` is `topics`, which is more descriptive. From LDoc 1.2, +`readme/topics` can be a list of documents. These act as a top-level table-of-contents for +your documentation. Currently, if you want them in a particular order, then use names like +`01-introduction.md` etc, which sort appropriately. + +The first line of a document may be a Markdown `#` title. If so, then LDoc will regard the +next level as the subheadings, normally second-level `##`. But if the title is already +second-level, then third-level headings will be used `###`, and so forth. The implication is +that the first heading must be top-level relative to the headings that follow, and must +start at the first line. + +A reference like `@{\string.upper}` is unambiguous, and will refer to the online Lua manual. +In a project like Penlight, it can get tedious to have to write out fully qualified names +like `@{\pl.utils.printf}`. The first simplification is to use the `package` field to resolve +unknown references, which in this case is 'pl'. (Previously we discussed how `package` is +used to tell LDoc where the base package is in cases where the module author wishes to +remain vague, but it does double-duty here.) A further level of simplification comes from +the `@lookup` directive in documents, which must start at the first column on its own line. +For instance, if I am talking about `pl.utils`, then I can say `@lookup utils` and +thereafter references like `@{\printf}` will resolve correctly. + +If you look at the source for this document, you will see a `@lookup doc.md` which allows +direct references to sections like @{Readme_files|this} with `@{\Readme_files|this}`. + +Remember that the default is for references in backticks to be resolved; unlike @ +references, it is not an error if the reference cannot be found. + +The _sections_ of a document (the second-level headings) are also references. This +particular section you are reading can be refered to as `@{\doc.md.Readme_files}` - the +rule is that any non-alphabetic character is replaced by an underscore. + +Any indented blocks are assumed to be Lua, unless their first line is `@plain`. New +with 1.4 is github-markdown-style fenced code blocks, which start with three backticks +optionally followed by a language. The code continues until another three backticks +is found: the language can be `c`, `cpp` or `cxx` for C/C++, anything else is Lua. + +## Tag Modifiers + +Ay tag may have _tag modifiers_. For instance, you may say +`@param[type=number]` and this associates the modifier `type` with value `number` with this +particular param tag. A shorthand has been introduced for this common case, which is `@tparam +<type> <parmname> <comment>`; in the same way `@treturn` is defined. + +This is useful for larger projects where you want to provide the argument and return value +types for your API, in a structured way that can be easily extracted later. + +These types can be combined, so that "?string|number" means "ether a string or a number"; +"?string" is short for "?|nil|string". However, for this last case you should usually use the +`opt` modifier discussed below. + +There is a useful function for creating new tags that can be used in `config.ld`: + + tparam_alias('string','string') + +That is, **@string** will now have the same meaning as "@tparam string"; this also applies +to the optional type syntax "?|T1|T2". + +From 1.3, the following standard type aliases are predefined: + + * `string` + * `number` + * `int` + * `bool` Lua 'boolean' type + * `func` 'function' (using 'function' would conflict with the type) + * `tab` 'table' + * `thread` + +When using 'colon-style' (@{colon.lua}) it's possible to directly use types by prepending +them with '!'; '?' is also naturally understood. + +The exact form of `<type>` is not defined, but here is one suggested scheme: + + * `number` -- a plain type + * `Bonzo` -- a known type; a reference link will be generated + * `{string,number}` -- a 'list' tuple of two values, built from type expressions + * `{A=string,N=number}` -- a 'struct', ditto (But it's often better to create a named table and refer to it) + * `{Bonzo,...}` -- an array of Bonzo objects + * `{[string]=Bonzo,...}` -- a map of Bonzo objects with string keys + * `Array(Bonzo)` -- (assuming that Array is a container type) + +The `alias` function within configuration files has been extended so that alias tags can be +defined as a tag plus a set of modifiers. So `tparam` is defined as: + + alias('tparam',{'param',modifiers={type="$1"}}) + +As an extension, you're allowed to use **@param** tags in table definitions. This makes it +possible to use type aliases like **@string** to describe fields, since they will expand to +'param'. + + +Another modifier understood by LDoc is `opt`. For instance, + + ---- testing [opt] + -- @param one + -- @param[opt] two + -- @param three + -- @param[opt] four + function fun (one,two,three,four) + end + ----> displayed as: fun (one [, two], three [, four]) + +A more typical Lua API would have a chain of optional arguments, like so: + + ---- a chain of options + -- @param one + -- @param[opt] two + -- @param[optchain] three + -- @param[optchain] four + function fun (one,two,three,four) + end + ----> displayed as: fun (one [, two [, three [, four]]]) + +This is a bit tedious to type, so the rule is that a series of 'opt' modifiers will be interpreted +as 'opt','optchain'.... . If you want to be explicit, then do `convert_opt=true` in your +`config.ld`. + +If a value is given for `opt`then LDoc can present this as the default value for this optional argument. + +This modifier can also be used with typed param aliases. + + --- a function with typed args. + -- If the Lua function has varargs, then + -- you may document an indefinite number of extra arguments! + -- @string name person's name + -- @int age + -- @string[opt='gregorian'] calender optional calendar + -- @int[opt=0] offset optional offset + -- @treturn string + function one (name,age,...) + end + ----> displayed as: one (name, age [, calender='gregorian' [, offset=0]]) + +(See @{four.lua}) + +An experimental feature in 1.4 allows different 'return groups' to be defined. There may be +multiple **@return** tags, and the meaning of this is well-defined, since Lua functions may +return multiple values. However, being a dynamic language it may return a single value if +successful and two values (`nil`,an error message) if there is an error. This is in fact the +convention for returning 'normal' errors (like 'file not found') as opposed to parameter errors +(like 'file must be a string') that are often raised as errors. + +Return groups allow a documenter to specify the various possible return values of a function, +by specifying _number_ modifiers. All `return` tags with the same digit modifier belong together +as a group: + + ----- + -- function with return groups. + -- @return[1] result + -- @return[2] nil + -- @return[2] error message + function mul1() ... end + +This is the first function in @{multiple.lua}, and the output shows how return groups are presented, with an **Or** between the groups. + +This is rather clumsy, and so there is a shortcut, the **@error** tag which achieves the same result, +with helpful type information. + +Currently the `type`,`opt` and `<digit>` modifiers are the only ones known and used by LDoc when generating HTML +output. However, any other modifiers are allowed and are available for use with your own +templates or for extraction by your own tools. + + +## Fields allowed in `config.ld` + +_Same meaning as the corresponding parameters:_ + + - `file` a file or directory containing sources. In `config.ld` this can also be a table +of files and directories. + - `project` name of project, used as title in top left + - `title` page title, default 'Reference' + - `package ` explicit base package name; also used for resolving references in documents + - `all` show local functions, etc as well in the docs + - `format` markup processor, can be 'plain' (default), 'markdown' or 'discount' + - `output` output name (default 'index') + - `dir` directory for output files (default 'doc') + - `colon` use colon style, instead of @ tag style + - `boilerplate` ignore first comment in all source files (e.g. license comments) + - `ext` extension for output (default 'html') + - `one` use a one-column layout + - `style`, `template`: together these specify the directories for the style and and the +template. In `config.ld` they may also be `true`, meaning use the same directory as the +configuration file. + - `merge` allow documentation from different files to be merged into modules without +explicit **@submodule** tag + - `icon` an image that will be displayed under the project name on all pages + +_These only appear in the configuration file:_ + + - `description` a short project description used under the project title + - `full_description` when you _really_ need a longer project description + - `examples` a directory or file: can be a table + - `readme` or `topics` readme files (to be processed with Markdown) + - `pretty` code prettify 'lua' (default) or 'lxsh' + - `prettify_files` prettify the source as well and make links to it; if its value is "show" +then also index the source files. + - `charset` use if you want to override the UTF-8 default (also **@charset** in files) + - `sort` set if you want all items in alphabetical order + - `no_return_or_parms` don't show parameters or return values in output + - `no_lua_ref` stop obsessively trying to create references to standard Lua libraries + - `backtick_references` whether references in backticks will be resolved. Happens by default +when using Markdown. When explicit will expand non-references in backticks into `<code>` elements + - `plain` set to true if `format` is set but you don't want code comments processed + - `wrap` set to true if you want to allow long names to wrap in the summaries + - `manual_url(url)` point to an alternative or local location for the Lua manual, e.g. +'manual_url file:///D:/dev/lua/projects/lua-5.1.4/doc/manual.html'. Remember it is a function! + - `no_summary` suppress the Contents summary + - `custom_tags` define some new tags, which will be presented after the function description. +The format is `{<name>,[title=<name>,}{hidden=false,}{format=nil}}`. For instance +`custom_tags={'remark',title='Remarks'}` will add a little `Remarks` section to the docs for any function +containing this tag. `format` can be a function - if not present the default formatter will be used, +e.g. Markdown + - `custom_see_handler(pat,handler)` function that filters see-references + - `custom_display_name_handler(item, default_handler)` function that formats an item's name. The arguments are the item +and the default function used to format the name. For example, to show an icon or label beside any +function tagged with a certain tag: + + -- define a @callback tag: + custom_tags = { { 'callback', hidden = true } } + + -- show a label beside functions tagged with @callback. + custom_display_name_handler = function(item, default_handler) + if item.type == 'function' and item.tags.callback then + return item.name .. ' [callback]' + end + return default_handler(item) + end + + - `not_luadoc` set to `true` if the docs break LuaDoc compatibility + - `no_space_before_args` set to `true` if you do not want a space between a function's name and its arguments. + - `template_escape` overrides the usual '#' used for Lua code in templates. +This needs to be changed if the output format is Markdown, for instance. + - `user_keywords` A list of keywords that will be marked in "prettified" code. Useful if +you want to display your own functions in a special way. Each keyword may be styled differently +(using CSS). Only works when `pretty` is set to 'lua' (the default). + - `postprocess_html` function that allows a last-minute modification to the produced HTML page. +The arguments are the raw HTML that's intended to be written out (a string), and the module object. +The string this function returns will be what's actually gets written out. + +_Available functions are:_ + + - `alias(a,tag)` provide an alias `a` for the tag `tag`, for instance `p` as short for +`param` + - `add_language_extension(ext,lang)` here `lang` may be either 'c' or 'lua', and `ext` is +an extension to be recognized as this language + - `add_section` + - `new_type(tag,header,project_level)` used to add new tags, which are put in their own +section `header`. They may be 'project level'. + - `tparam_alias(name,type)` for instance, you may wish that `Object` becomes a new tag alias +that means `@tparam Object`. + - `custom_see_handler(pattern,handler)`. If a reference matches `pattern`, then the +extracted values will be passed to `handler`. It is expected to return link text +and a suitable URI. (This match will happen before default processing.) + +## Annotations and Searching for Tags + +Annotations are special tags that can be used to keep track of internal development status. +The known annotations are 'todo', 'fixme' and 'warning'. They may occur in regular +function/table doc comments, or on their own anywhere in the code. + + --- Testing annotations + -- @module annot1 + ... + --- first function. + -- @todo check if this works! + function annot1.first () + if boo then + + end + --- @fixme what about else? + end + +Although not currently rendered by the template as HTML, they can be extracted by the +`--tags` command, which is given a comma-separated list of tags to list. + + @plain + D:\dev\lua\LDoc\tests> ldoc --tags todo,fixme annot1.lua + d:\dev\lua\ldoc\tests\annot1.lua:14: first: todo check if this works! + d:\dev\lua\ldoc\tests\annot1.lua:19: first-fixme1: fixme what about else? + + +## Generating HTML + +LDoc, like LuaDoc, generates output HTML using a template, in this case `ldoc/html/ldoc_ltp.lua`. This +is expanded by the powerful but simple preprocessor devised originally by [Rici +Lake](http://lua-users.org/wiki/SlightlyLessSimpleLuaPreprocessor) which is now part of +Penlight. There are two rules - any line starting with '#' is Lua code, which can also be +embedded with '$(...)'. + + <h2>Contents</h2> + <ul> + # for kind,items in module.kinds() do + <li><a href="#$(no_spaces(kind))">$(kind)</a></li> + # end + </ul> + +This is then styled with `ldoc.css`. Currently the template and stylesheet is very much +based on LuaDoc, so the results are mostly equivalent; the main change that the template has +been more generalized. The default location (indicated by '!') is the directory of `ldoc_ltp.lua`. + +You will notice that the built-in templates and stylesheets end in `.lua`; this is simply to +make it easier for LDoc to find them. Where you are customizing one or both of the template +and stylesheet, they will have their usual extensions. + +You may customize how you generate your documentation by specifying an alternative style +sheet and/or template, which can be deployed with your project. The parameters are `--style` +and `--template`, which give the directories where `ldoc.css` and `ldoc.ltp` are to be +found. If `config.ld` contains these variables, they are interpreted slightly differently; +if they are true, then it means 'use the same directory as config.ld'; otherwise they must +be a valid directory relative to the ldoc invocation. + +An example of fully customized documentation is `tests/example/style`: this is what you +could call 'minimal Markdown style' where there is no attempt to tag things (except +emphasizing parameter names). The narrative alone _can_ to be sufficient, if it is written +well. + +There are three other stylesheets available in LDoc since 1.4; the first is `ldoc_one.css` which is what +you get from `one=true` and the second is `ldoc_pale.css`. This is a lighter theme which +might give some relief from the heavier colours of the default. You can use this style with +`style="!pale"` or `-s !pale`. +See the [Lake](http://stevedonovan.github.io/lake/modules/lakelibs.html) documentation +as an example of its use. With 1.4.3 there is also the `style='!fixed'` where the +left navigation panel is fixed and does not scroll with the rest of the document; +you may find this assists navigation in complex modules and documents. + +Of course, there's no reason why LDoc must always generate HTML. `--ext` defines what output +extension to use; this can also be set in the configuration file. So it's possible to write +a template that converts LDoc output to LaTex, for instance. The separation of processing +and presentation makes this kind of new application possible with LDoc. + +From 1.4, LDoc has some limited support for generating Markdown output, although only +for single files currently. Use `--ext md` for this. 'ldoc/html/ldoc_md_ltp.lua' defines +the template for Markdown, but this can be overriden with `template` as above. It's another +example of minimal structure, and provides a better place to learn about these templates than the +rather elaborate default HTML template. + +## Internal Data Representation + +The `--dump` flag gives a rough text output on the console. But there is a more +customizeable way to process the output data generated by LDoc, using the `--filter` +parameter. This is understood to be a fully qualified function (module + name). For example, +try + + $ ldoc --filter pl.pretty.dump mylib.c + +to see a raw dump of the data. (Simply using `dump` as the value here would be a shorthand +for `pl.pretty.dump`.) This is potentially very powerful, since you may write arbitrary Lua +code to extract the information you need from your project. + +For instance, a file `custom.lua` like this: + + return { + filter = function (t) + for _, mod in ipairs(t) do + print(mod.type,mod.name,mod.summary) + end + end + } + +Can be used like so: + + ~/LDoc/tests/example$ ldoc --filter custom.filter mylib.c + module mylib A sample C extension. + +The basic data structure is straightforward: it is an array of 'modules' (project-level +entities, including scripts) which each contain an `item` array (functions, tables and so +forth). + +For instance, to find all functions which don't have a **@return** tag: + + return { + filter = function (t) + for _, mod in ipairs(t) do + for _, item in ipairs(mod.items) do + if item.type == 'function' and not item.ret then + print(mod.name,item.name,mod.file,item.lineno) + end + end + end + end + } + +The internal naming is not always so consistent; `ret` corresponds to **@return**, and `params` +corresponds to **@param**. `item.params` is an array of the function parameters, in order; it +is also a map from these names to the individual descriptions of the parameters. + +`item.modifiers` is a table where the keys are the tags and the values are arrays of +modifier tables. The standard tag aliases `tparam` and `treturn` attach a `type` modifier +to their tags. + + diff --git a/Data/Libraries/LDoc/ldoc-scm-3.rockspec b/Data/Libraries/LDoc/ldoc-scm-3.rockspec new file mode 100644 index 0000000..a3e578b --- /dev/null +++ b/Data/Libraries/LDoc/ldoc-scm-3.rockspec @@ -0,0 +1,66 @@ +package = "ldoc" +version = "scm-3" + +source = { + dir="LDoc", + url = "git+https://github.com/stevedonovan/LDoc.git" +} + +description = { + summary = "A Lua Documentation Tool", + detailed = [[ + LDoc is a LuaDoc-compatible documentation generator which can also + process C extension source. Markdown may be optionally used to + render comments, as well as integrated readme documentation and + pretty-printed example files + ]], + homepage='http://stevedonovan.github.com/ldoc', + maintainer='steve.j.donovan@gmail.com', + license = "MIT/X11", +} + +dependencies = { + "penlight","markdown" +} + +build = { + type = "builtin", + modules = { + ["ldoc.tools"] = "ldoc/tools.lua", + ["ldoc.lang"] = "ldoc/lang.lua", + ["ldoc.parse"] = "ldoc/parse.lua", + ["ldoc.html"] = "ldoc/html.lua", + ["ldoc.lexer"] = "ldoc/lexer.lua", + ["ldoc.markup"] = "ldoc/markup.lua", + ["ldoc.prettify"] = "ldoc/prettify.lua", + ["ldoc.markdown"] = "ldoc/markdown.lua", + ["ldoc.doc"] = "ldoc/doc.lua", + ["ldoc.html.ldoc_ltp"] = "ldoc/html/ldoc_ltp.lua", + ["ldoc.html.ldoc_md_ltp"] = "ldoc/html/ldoc_md_ltp.lua", + ["ldoc.html.ldoc_css"] = "ldoc/html/ldoc_css.lua", + ["ldoc.html._code_css"] = "ldoc/html/_code_css.lua", + ["ldoc.html._reset_css"] = "ldoc/html/_reset_css.lua", + ["ldoc.html.ldoc_one_css"] = "ldoc/html/ldoc_one_css.lua", + ["ldoc.html.ldoc_pale_css"] = "ldoc/html/ldoc_pale_css.lua", + ["ldoc.html.ldoc_new_css"] = "ldoc/html/ldoc_new_css.lua", + ["ldoc.html.ldoc_fixed_css"] = "ldoc/html/ldoc_fixed_css.lua", + ["ldoc.builtin.globals"] = "ldoc/builtin/globals.lua", + ["ldoc.builtin.coroutine"] = "ldoc/builtin/coroutine.lua", + ["ldoc.builtin.global"] = "ldoc/builtin/global.lua", + ["ldoc.builtin.debug"] = "ldoc/builtin/debug.lua", + ["ldoc.builtin.io"] = "ldoc/builtin/io.lua", + ["ldoc.builtin.lfs"] = "ldoc/builtin/lfs.lua", + ["ldoc.builtin.lpeg"] = "ldoc/builtin/lpeg.lua", + ["ldoc.builtin.math"] = "ldoc/builtin/math.lua", + ["ldoc.builtin.os"] = "ldoc/builtin/os.lua", + ["ldoc.builtin.package"] = "ldoc/builtin/package.lua", + ["ldoc.builtin.string"] = "ldoc/builtin/string.lua", + ["ldoc.builtin.table"] = "ldoc/builtin/table.lua", + }, + copy_directories = {'doc','tests'}, + install = { + bin = { + ldoc = "ldoc.lua" + } + } +} diff --git a/Data/Libraries/LDoc/ldoc.lua b/Data/Libraries/LDoc/ldoc.lua new file mode 100644 index 0000000..ad49f86 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc.lua @@ -0,0 +1,858 @@ +#!/usr/bin/env lua +--------------- +-- ## ldoc, a Lua documentation generator. +-- +-- Compatible with luadoc-style annotations, but providing +-- easier customization options. +-- +-- C/C++ support for Lua extensions is provided. +-- +-- Available from LuaRocks as 'ldoc' and as a [Zip file](http://stevedonovan.github.com/files/ldoc-1.4.3.zip) +-- +-- [Github Page](https://github.com/stevedonovan/ldoc) +-- +-- @author Steve Donovan +-- @copyright 2011 +-- @license MIT/X11 +-- @script ldoc + +local class = require 'pl.class' +local app = require 'pl.app' +local path = require 'pl.path' +local dir = require 'pl.dir' +local utils = require 'pl.utils' +local List = require 'pl.List' +local stringx = require 'pl.stringx' +local tablex = require 'pl.tablex' + +-- Penlight compatibility +utils.unpack = utils.unpack or unpack or table.unpack +local lapp = require 'pl.lapp' + +local version = '1.4.6' + +-- so we can find our private modules +app.require_here() + +--- @usage +local usage = [[ +ldoc, a documentation generator for Lua, v]]..version..[[ + + Invocation: + ldoc [options] <file> + ldoc --version + + Options: + -d,--dir (default doc) output directory + -o,--output (default 'index') output name + -v,--verbose verbose + -a,--all show local functions, etc, in docs + -q,--quiet suppress output + -m,--module module docs as text + -s,--style (default !) directory for style sheet (ldoc.css) + -l,--template (default !) directory for template (ldoc.ltp) + -p,--project (default ldoc) project name + -t,--title (default Reference) page title + -f,--format (default plain) formatting - can be markdown, discount or plain + -b,--package (default .) top-level package basename (needed for module(...)) + -x,--ext (default html) output file extension + -c,--config (default config.ld) configuration name + -u,--unqualified don't show package name in sidebar links + -i,--ignore ignore any 'no doc comment or no module' warnings + -X,--not_luadoc break LuaDoc compatibility. Descriptions may continue after tags. + -D,--define (default none) set a flag to be used in config.ld + -C,--colon use colon style + -N,--no_args_infer don't infer arguments from source + -B,--boilerplate ignore first comment in source files + -M,--merge allow module merging + -S,--simple no return or params, no summary + -O,--one one-column output layout + -V,--version show version information + --date (default system) use this date in generated doc + --dump debug output dump + --filter (default none) filter output as Lua data (e.g pl.pretty.dump) + --tags (default none) show all references to given tags, comma-separated + --fatalwarnings non-zero exit status on any warning + --testing reproducible build; no date or version on output + --icon (default none) an image that will be displayed under the project name on all pages + + <file> (string) source file or directory containing source + + `ldoc .` reads options from an `config.ld` file in same directory; + `ldoc -c path/to/myconfig.ld <file>` reads options from `path/to/myconfig.ld` + and processes <file> if 'file' was not defined in the ld file. +]] +local args = lapp(usage) +local lfs = require 'lfs' +local doc = require 'ldoc.doc' +local lang = require 'ldoc.lang' +local tools = require 'ldoc.tools' +local global = require 'ldoc.builtin.globals' +local markup = require 'ldoc.markup' +local parse = require 'ldoc.parse' +local KindMap = tools.KindMap +local Item,File = doc.Item,doc.File +local quit = utils.quit + +if args.version then + print('LDoc v' .. version) + os.exit(0) +end + + +local ModuleMap = class(KindMap) +doc.ModuleMap = ModuleMap + +function ModuleMap:_init () + self.klass = ModuleMap + self.fieldname = 'section' +end + +local ProjectMap = class(KindMap) +ProjectMap.project_level = true + +function ProjectMap:_init () + self.klass = ProjectMap + self.fieldname = 'type' +end + +local lua, cc = lang.lua, lang.cc + +local file_types = { + ['.lua'] = lua, + ['.ldoc'] = lua, + ['.luadoc'] = lua, + ['.c'] = cc, + ['.h'] = cc, + ['.cpp'] = cc, + ['.cxx'] = cc, + ['.C'] = cc, + ['.mm'] = cc, + ['.cs'] = cc, + ['.moon'] = lang.moon, +} +------- ldoc external API ------------ + +-- the ldoc table represents the API available in `config.ld`. +local ldoc = { charset = 'UTF-8', version = version } + +local known_types, kind_names = {} + +local function lookup (itype,igroup,isubgroup) + local kn = kind_names[itype] + known_types[itype] = true + if kn then + if type(kn) == 'string' then + igroup = kn + else + igroup = kn[1] + isubgroup = kn[2] + end + end + return itype, igroup, isubgroup +end + +local function setup_kinds () + kind_names = ldoc.kind_names or {} + + ModuleMap:add_kind(lookup('function','Functions','Parameters')) + ModuleMap:add_kind(lookup('table','Tables','Fields')) + ModuleMap:add_kind(lookup('field','Fields')) + ModuleMap:add_kind(lookup('type','Types')) + ModuleMap:add_kind(lookup('lfunction','Local Functions','Parameters')) + ModuleMap:add_kind(lookup('annotation','Issues')) + + ProjectMap:add_kind(lookup('module','Modules')) + ProjectMap:add_kind(lookup('script','Scripts')) + ProjectMap:add_kind(lookup('classmod','Classes')) + ProjectMap:add_kind(lookup('topic','Topics')) + ProjectMap:add_kind(lookup('example','Examples')) + ProjectMap:add_kind(lookup('file','Source')) + + for k in pairs(kind_names) do + if not known_types[k] then + quit("unknown item type "..tools.quote(k).." in kind_names") + end + end +end + + +-- hacky way for doc module to be passed options... +doc.ldoc = ldoc + +-- if the corresponding argument was the default, then any ldoc field overrides +local function override (field,defval) + defval = defval or false + if args[field] == defval and ldoc[field] ~= nil then args[field] = ldoc[field] end +end + +-- aliases to existing tags can be defined. E.g. just 'p' for 'param' +function ldoc.alias (a,tag) + doc.add_alias(a,tag) +end + +-- standard aliases -- + +ldoc.alias('tparam',{'param',modifiers={type="$1"}}) +ldoc.alias('treturn',{'return',modifiers={type="$1"}}) +ldoc.alias('tfield',{'field',modifiers={type="$1"}}) + +function ldoc.tparam_alias (name,type) + type = type or name + ldoc.alias(name,{'param',modifiers={type=type}}) +end + +ldoc.alias ('error',doc.error_macro) + +ldoc.tparam_alias 'string' +ldoc.tparam_alias 'number' +ldoc.tparam_alias 'int' +ldoc.tparam_alias 'bool' +ldoc.tparam_alias 'func' +ldoc.tparam_alias 'tab' +ldoc.tparam_alias 'thread' + +function ldoc.add_language_extension(ext, lang) + lang = (lang=='c' and cc) or (lang=='lua' and lua) or quit('unknown language') + if ext:sub(1,1) ~= '.' then ext = '.'..ext end + file_types[ext] = lang +end + +function ldoc.add_section (name, title, subname) + ModuleMap:add_kind(name,title,subname) +end + +-- new tags can be added, which can be on a project level. +function ldoc.new_type (tag, header, project_level,subfield) + doc.add_tag(tag,doc.TAG_TYPE,project_level) + if project_level then + ProjectMap:add_kind(tag,header,subfield) + else + ModuleMap:add_kind(tag,header,subfield) + end +end + +function ldoc.manual_url (url) + global.set_manual_url(url) +end + +function ldoc.custom_see_handler(pat, handler) + doc.add_custom_see_handler(pat, handler) +end + +local ldoc_contents = { + 'alias','add_language_extension','custom_tags','new_type','add_section', 'tparam_alias', + 'file','project','title','package', 'icon','format','output','dir','ext', 'topics', + 'one','style','template','description','examples', 'pretty', 'charset', 'plain', + 'readme','all','manual_url', 'ignore', 'colon', 'sort', 'module_file','vars', + 'boilerplate','merge', 'wrap', 'not_luadoc', 'template_escape','merge_error_groups', + 'no_return_or_parms','no_summary','full_description','backtick_references', 'custom_see_handler', + 'no_space_before_args','parse_extra','no_lua_ref','sort_modules','use_markdown_titles', + 'unqualified', 'custom_display_name_handler', 'kind_names', 'custom_references', + 'dont_escape_underscore','global_lookup','prettify_files','convert_opt', 'user_keywords', + 'postprocess_html', + 'custom_css','version', + 'no_args_infer' +} +ldoc_contents = tablex.makeset(ldoc_contents) + +local function loadstr (ldoc,txt) + local chunk, err + -- Penlight's Lua 5.2 compatibility has wobbled over the years... + if not rawget(_G,'loadin') then -- Penlight 0.9.5 + -- Penlight 0.9.7; no more global load() override + local load = load or utils.load + chunk,err = load(txt,'config',nil,ldoc) + else + -- luacheck: push ignore 113 + chunk,err = loadin(ldoc,txt) + -- luacheck: pop + end + return chunk, err +end + +-- any file called 'config.ld' found in the source tree will be +-- handled specially. It will be loaded using 'ldoc' as the environment. +local function read_ldoc_config (fname) + local directory = path.dirname(fname) + if directory == '' then + directory = '.' + end + local chunk, err, _ + if args.filter == 'none' then + print('reading configuration from '..fname) + end + local txt,not_found = utils.readfile(fname) + if txt then + chunk, err = loadstr(ldoc,txt) + if chunk then + if args.define ~= 'none' then ldoc[args.define] = true end + _,err = pcall(chunk) + end + end + if err then quit('error loading config file '..fname..': '..err) end + for k in pairs(ldoc) do + if not ldoc_contents[k] then + quit("this config file field/function is unrecognized: "..k) + end + end + return directory, not_found +end + +local quote = tools.quote +--- processing command line and preparing for output --- + +local file_list = List() +File.list = file_list +local config_dir + + +local ldoc_dir = arg[0]:gsub('[^/\\]+$','') +local doc_path = ldoc_dir..'/ldoc/builtin/?.lua' + +-- ldoc -m is expecting a Lua package; this converts this to a file path +if args.module then + -- first check if we've been given a global Lua lib function + if args.file:match '^%a+$' and global.functions[args.file] then + args.file = 'global.'..args.file + end + local fullpath,mod,_ = tools.lookup_existing_module_or_function (args.file, doc_path) + if not fullpath then + quit(mod) + else + args.file = fullpath + args.module = mod + end +end + +local abspath = tools.abspath + +-- a special case: 'ldoc .' can get all its parameters from config.ld +if args.file == '.' then + local err + config_dir,err = read_ldoc_config(args.config) + if err then quit("no "..quote(args.config).." found") end + local config_path = path.dirname(args.config) + if config_path ~= '' then + print('changing to directory',config_path) + lfs.chdir(config_path) + end + args.file = ldoc.file or '.' + if args.file == '.' then + args.file = lfs.currentdir() + elseif type(args.file) == 'table' then + for i,f in ipairs(args.file) do + args.file[i] = abspath(f) + end + else + args.file = abspath(args.file) + end +else + -- user-provided config file + if args.config ~= 'config.ld' then + local err + config_dir,err = read_ldoc_config(args.config) + if err then quit("no "..quote(args.config).." found") end + end + -- with user-provided file + if args.file == nil then + lapp.error('missing required parameter: file') + end + args.file = abspath(args.file) +end + +if type(ldoc.custom_tags) == 'table' then -- custom tags + for i, custom in ipairs(ldoc.custom_tags) do + if type(custom) == 'string' then + custom = {custom} + ldoc.custom_tags[i] = custom + end + doc.add_tag(custom[1], 'ML') + end +end -- custom tags + +local source_dir = args.file +if type(source_dir) == 'table' then + source_dir = source_dir[1] +end +if type(source_dir) == 'string' and path.isfile(source_dir) then + source_dir = path.splitpath(source_dir) +end +source_dir = source_dir:gsub('[/\\]%.$','') + +---------- specifying the package for inferring module names -------- +-- If you use module(...), or forget to explicitly use @module, then +-- ldoc has to infer the module name. There are three sensible values for +-- `args.package`: +-- +-- * '.' the actual source is in an immediate subdir of the path given +-- * '..' the path given points to the source directory +-- * 'NAME' explicitly give the base module package name +-- + +override ('package','.') + +local function setup_package_base() + if ldoc.package then args.package = ldoc.package end + if args.package == '.' then + args.package = source_dir + elseif args.package == '..' then + args.package = path.splitpath(source_dir) + elseif not args.package:find '[\\/]' then + local subdir,dir = path.splitpath(source_dir) + if dir == args.package then + args.package = subdir + elseif path.isdir(path.join(source_dir,args.package)) then + args.package = source_dir + else + quit("args.package is not the name of the source directory") + end + end +end + + +--------- processing files --------------------- +-- ldoc may be given a file, or a directory. `args.file` may also be specified in config.ld +-- where it is a list of files or directories. If specified on the command-line, we have +-- to find an optional associated config.ld, if not already loaded. + +if ldoc.ignore then args.ignore = true end + +local function process_file (f, flist) + local ext = path.extension(f) + local ftype = file_types[ext] + if ftype then + if args.verbose then print(f) end + ftype.extra = ldoc.parse_extra or {} + local F,err = parse.file(f,ftype,args) + if err then + if F then + F:warning("internal LDoc error") + end + quit(err) + end + flist:append(F) + end +end + +local process_file_list = tools.process_file_list + +setup_package_base() + +override 'no_args_infer' +override 'colon' +override 'merge' +override 'not_luadoc' +override 'module_file' +override 'boilerplate' +override 'all' + +setup_kinds() + +-- LDoc is doing plain ole C, don't want random Lua references! +if ldoc.parse_extra and ldoc.parse_extra.C then + ldoc.no_lua_ref = true +end + +if ldoc.merge_error_groups == nil then + ldoc.merge_error_groups = 'Error Message' +end + +-- ldoc.module_file establishes a partial ordering where the +-- master module files are processed first. +local function reorder_module_file () + if args.module_file then + local mf = {} + for mname, f in pairs(args.module_file) do + local fullpath = abspath(f) + mf[fullpath] = true + end + return function(x,y) + return mf[x] and not mf[y] + end + end +end + +-- process files, optionally in order that respects master module files +local function process_all_files(files) + local sortfn = reorder_module_file() + local files = tools.expand_file_list(files,'*.*') + if sortfn then files:sort(sortfn) end + for f in files:iter() do + process_file(f, file_list) + end + if #file_list == 0 then quit "no source files found" end +end + +if type(args.file) == 'table' then + -- this can only be set from config file so we can assume config is already read + process_all_files(args.file) + +elseif path.isdir(args.file) then + -- use any configuration file we find, if not already specified + if not config_dir then + local files = List(dir.getallfiles(args.file,'*.*')) + local config_files = files:filter(function(f) + return path.basename(f) == args.config + end) + if #config_files > 0 then + config_dir = read_ldoc_config(config_files[1]) + if #config_files > 1 then + print('warning: other config files found: '..config_files[2]) + end + end + end + + process_all_files({args.file}) + +elseif path.isfile(args.file) then + -- a single file may be accompanied by a config.ld in the same dir + if not config_dir then + config_dir = path.dirname(args.file) + if config_dir == '' then config_dir = '.' end + local config = path.join(config_dir,args.config) + if path.isfile(config) then + read_ldoc_config(config) + end + end + process_file(args.file, file_list) + if #file_list == 0 then quit "unsupported file extension" end +else + quit ("file or directory does not exist: "..quote(args.file)) +end + + +-- create the function that renders text (descriptions and summaries) +-- (this also will initialize the code prettifier used) +override ('format','plain') +override 'pretty' +ldoc.markup = markup.create(ldoc, args.format, args.pretty, ldoc.user_keywords) + +------ 'Special' Project-level entities --------------------------------------- +-- Examples and Topics do not contain code to be processed for doc comments. +-- Instead, they are intended to be rendered nicely as-is, whether as pretty-lua +-- or as Markdown text. Treating them as 'modules' does stretch the meaning of +-- of the term, but allows them to be treated much as modules or scripts. +-- They define an item 'body' field (containing the file's text) and a 'postprocess' +-- field which is used later to convert them into HTML. They may contain @{ref}s. + +local function add_special_project_entity (f,tags,process) + local F = File(f) + tags.name = path.basename(f) + local text = utils.readfile(f) + local item = F:new_item(tags,1) + if process then + text = process(F, text) + end + F:finish() + file_list:append(F) + item.body = text + return item, F +end + +local function prettify_source_files(files,class,linemap) + local prettify = require 'ldoc.prettify' + + process_file_list (files, '*.*', function(f) + local ext = path.extension(f) + local ftype = file_types[ext] + if ftype then + local item = add_special_project_entity(f,{ + class = class, + }) + -- wrap prettify for this example so it knows which file to blame + -- if there's a problem + local lang = ext:sub(2) + item.postprocess = function(code) + return '<h2>'..path.basename(f)..'</h2>\n' .. + prettify.lua(lang,f,code,0,true,linemap and linemap[f]) + end + end + end) +end + +if type(ldoc.examples) == 'string' then + ldoc.examples = {ldoc.examples} +end +if type(ldoc.examples) == 'table' then + prettify_source_files(ldoc.examples,"example") +end + +ldoc.is_file_prettified = {} + +if ldoc.prettify_files then + local files = List() + local linemap = {} + for F in file_list:iter() do + files:append(F.filename) + local mod = F.modules[1] + if mod then + local ls = List() + for item in mod.items:iter() do + ls:append(item.lineno) + end + linemap[F.filename] = ls + end + end + + if type(ldoc.prettify_files) == 'table' then + files = tools.expand_file_list(ldoc.prettify_files, '*.*') + elseif type(ldoc.prettify_files) == 'string' then + -- the gotcha is that if the person has a folder called 'show', only the contents + -- of that directory will be converted. So, we warn of this amibiguity + if ldoc.prettify_files == 'show' then + -- just fall through with all module files collected above + if path.exists 'show' then + print("Notice: if you only want to prettify files in `show`, then set prettify_files to `show/`") + end + else + files = tools.expand_file_list({ldoc.prettify_files}, '*.*') + end + end + + ldoc.is_file_prettified = tablex.makeset(files) + prettify_source_files(files,"file",linemap) +end + +if args.simple then + ldoc.no_return_or_parms=true + ldoc.no_summary=true +end + +ldoc.readme = ldoc.readme or ldoc.topics +if type(ldoc.readme) == 'string' then + ldoc.readme = {ldoc.readme} +end +if type(ldoc.readme) == 'table' then + process_file_list(ldoc.readme, '*.md', function(f) + local item, F = add_special_project_entity(f,{ + class = 'topic' + }, markup.add_sections) + -- add_sections above has created sections corresponding to the 2nd level + -- headers in the readme, which are attached to the File. So + -- we pass the File to the postprocesser, which will insert the section markers + -- and resolve inline @ references. + if ldoc.use_markdown_titles then + item.display_name = F.display_name + end + item.postprocess = function(txt) return ldoc.markup(txt,F) end + end) +end + +-- extract modules from the file objects, resolve references and sort appropriately --- + +local first_module +local project = ProjectMap() +local module_list = List() +module_list.by_name = {} + +local modcount = 0 + +for F in file_list:iter() do + for mod in F.modules:iter() do + if not first_module then first_module = mod end + if doc.code_tag(mod.type) then modcount = modcount + 1 end + module_list:append(mod) + module_list.by_name[mod.name] = mod + end +end + +for mod in module_list:iter() do + if not args.module then -- no point if we're just showing docs on the console + mod:resolve_references(module_list) + end + project:add(mod,module_list) +end + + +if ldoc.sort_modules then + table.sort(module_list,function(m1,m2) + return m1.name < m2.name + end) +end + +ldoc.single = modcount == 1 and first_module or nil + +--do return end + +-------- three ways to dump the object graph after processing ----- + +-- ldoc -m will give a quick & dirty dump of the module's documentation; +-- using -v will make it more verbose +if args.module then + if #module_list == 0 then quit("no modules found") end + if args.module == true then + file_list[1]:dump(args.verbose) + else + local M,name = module_list[1], args.module + local fun = M.items.by_name[name] + if not fun then + fun = M.items.by_name[M.mod_name..':'..name] + end + if not fun then quit(quote(name).." is not part of "..quote(args.file)) end + fun:dump(true) + end + return +end + +-- ldoc --dump will do the same as -m, except for the currently specified files +if args.dump then + for mod in module_list:iter() do + mod:dump(true) + end + os.exit() +end +if args.tags ~= 'none' then + local tagset = {} + for t in stringx.split(args.tags,','):iter() do + tagset[t] = true + end + for mod in module_list:iter() do + mod:dump_tags(tagset) + end + os.exit() +end + +-- ldoc --filter mod.name will load the module `mod` and pass the object graph +-- to the function `name`. As a special case --filter dump will use pl.pretty.dump. +if args.filter ~= 'none' then + doc.filter_objects_through_function(args.filter, module_list) + os.exit() +end + +-- can specify format, output, dir and ext in config.ld +override ('output','index') +override ('dir','doc') +override ('ext','html') +override 'one' + +-- handling styling and templates -- +ldoc.css, ldoc.templ = 'ldoc.css','ldoc.ltp' + +-- special case: user wants to generate a .md file from a .lua file +if args.ext == 'md' then + if #module_list ~= 1 then + quit("can currently only generate Markdown output from one module only") + end + if not ldoc.template or ldoc.template == '!' then + ldoc.template = '!md' + end + args.output = module_list[1].name + args.dir = '.' + ldoc.template_escape = '>' + ldoc.style = false + args.ext = '.md' +end + +local function match_bang (s) + if type(s) ~= 'string' then return end + return s:match '^!(.*)' +end + +local function style_dir (sname) + local style = ldoc[sname] + local dir + if style==false and sname == 'style' then + args.style = false + ldoc.css = false + end + if style then + if style == true then + dir = config_dir + elseif type(style) == 'string' and (path.isdir(style) or match_bang(style)) then + dir = style + else + quit(quote(tostring(style)).." is not a directory") + end + args[sname] = dir + end +end + +-- the directories for template and stylesheet can be specified +-- either by command-line '--template','--style' arguments or by 'template and +-- 'style' fields in config.ld. +-- The assumption here is that if these variables are simply true then the directory +-- containing config.ld contains a ldoc.css and a ldoc.ltp respectively. Otherwise +-- they must be a valid subdirectory. + +style_dir 'style' +style_dir 'template' + +if not args.ext:find '^%.' then + args.ext = '.'..args.ext +end + +if args.one then + ldoc.style = '!one' +end + +local builtin_style, builtin_template = match_bang(args.style),match_bang(args.template) +if builtin_style or builtin_template then + -- '!' here means 'use built-in templates' + local user = path.expanduser('~'):gsub('[/\\: ]','_') + local tmpdir = path.join(path.is_windows and os.getenv('TMP') or (os.getenv('TMPDIR') or '/tmp'),'ldoc'..user) + if not path.isdir(tmpdir) then + lfs.mkdir(tmpdir) + end + local function tmpwrite (name) + local ok,text = pcall(require,'ldoc.html.'..name:gsub('%.','_')) + if not ok then + quit("cannot find builtin template "..name.." ("..text..")") + end + if not utils.writefile(path.join(tmpdir,name),text) then + quit("cannot write to temp directory "..tmpdir) + end + end + if builtin_style then + if builtin_style ~= '' then + ldoc.css = 'ldoc_'..builtin_style..'.css' + end + tmpwrite(ldoc.css) + args.style = tmpdir + end + if builtin_template then + if builtin_template ~= '' then + ldoc.templ = 'ldoc_'..builtin_template..'.ltp' + end + tmpwrite(ldoc.templ) + args.template = tmpdir + end +end + +-- default icon to nil +if args.icon == 'none' then args.icon = nil end + +ldoc.log = print +ldoc.kinds = project +ldoc.modules = module_list +ldoc.title = ldoc.title or args.title +ldoc.project = ldoc.project or args.project +ldoc.package = args.package:match '%a+' and args.package or nil +ldoc.icon = ldoc.icon or args.icon + +local source_date_epoch = os.getenv("SOURCE_DATE_EPOCH") +if args.testing then + ldoc.updatetime = "2015-01-01 12:00:00" + ldoc.version = 'TESTING' +elseif source_date_epoch == nil then + if args.date == 'system' then + ldoc.updatetime = os.date("%Y-%m-%d %H:%M:%S") + else + ldoc.updatetime = args.date + end +else + ldoc.updatetime = os.date("!%Y-%m-%d %H:%M:%S",source_date_epoch) +end + +local html = require 'ldoc.html' + +html.generate_output(ldoc, args, project) + +if args.verbose then + print 'modules' + for k in pairs(module_list.by_name) do print(k) end +end + +if args.fatalwarnings and Item.had_warning then + os.exit(1) +end diff --git a/Data/Libraries/LDoc/ldoc/SciTE.properties b/Data/Libraries/LDoc/ldoc/SciTE.properties new file mode 100644 index 0000000..788e228 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/SciTE.properties @@ -0,0 +1,3 @@ +tabsize=3 +indent.size=3 +use.tabs=0 diff --git a/Data/Libraries/LDoc/ldoc/builtin/coroutine.lua b/Data/Libraries/LDoc/ldoc/builtin/coroutine.lua new file mode 100644 index 0000000..25e2f82 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/builtin/coroutine.lua @@ -0,0 +1,50 @@ +--- creating and controlling coroutines. +-- @module coroutine + +local coroutine = {} + +--- +-- Creates a new coroutine, with body `f`. `f` must be a Lua +-- function. Returns this new coroutine, an object with type `"thread"`. +function coroutine.create(f) end + +--- +-- Starts or continues the execution of coroutine `co`. The first time +-- you resume a coroutine, it starts running its body. The values +-- ... are passed as the arguments to the body function. If the coroutine +-- has yielded, `resume` restarts it; the values ... are passed +-- as the results from the yield. +-- If the coroutine runs without any errors, `resume` returns true plus any +-- values passed to `yield` (if the coroutine yields) or any values returned +-- by the body function (if the coroutine terminates). If there is any error, +-- `resume` returns false plus the error message. +function coroutine.resume(co , ...) end + +--- +-- Returns the running coroutine. Or nil when called by the main thread. +function coroutine.running() end + +--- +-- Returns the status of coroutine `co`. Result is a string: `"running"`, if +-- the coroutine is running (that is, it called `status`); `"suspended"`, if +-- the coroutine is suspended in a call to `yield`, or if it has not started +-- running yet; `"normal"` if the coroutine is active but not running (that +-- is, it has resumed another coroutine); and `"dead"` if the coroutine has +-- finished its body function, or if it has stopped with an error. +function coroutine.status(co) end + +--- +-- Creates a new coroutine, with body `f`. `f` must be a Lua +-- function. Returns a function that resumes the coroutine each time it is +-- called. Any arguments passed to the function behave as the extra arguments to +-- `resume`. Returns the same values returned by `resume`, except the first +-- boolean. In case of error, propagates the error. +function coroutine.wrap(f) end + +--- +-- Suspends the execution of the calling coroutine. The coroutine cannot +-- be running a C function, a metamethod, or an iterator. Any arguments to +-- `yield` are passed as extra results to `resume`. +function coroutine.yield(...) end + +return coroutine diff --git a/Data/Libraries/LDoc/ldoc/builtin/debug.lua b/Data/Libraries/LDoc/ldoc/builtin/debug.lua new file mode 100644 index 0000000..6121a8f --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/builtin/debug.lua @@ -0,0 +1,124 @@ +--- getting runtime debug information. +-- @module debug + +local debug = {} +--- +-- Enters an interactive mode with the user, running each string that +-- the user enters. Using simple commands and other debug facilities, +-- the user can inspect global and local variables, change their values, +-- evaluate expressions, and so on. A line containing only the word `cont` +-- finishes this function, so that the caller continues its execution. +-- Note that commands for `debug.debug` are not lexically nested within any +-- function, and so have no direct access to local variables. +function debug.debug() end + +--- +-- Returns the environment of object `o`. +function debug.getfenv(o) end + +--- +-- Returns the current hook settings of the thread, as three values: the +-- current hook function, the current hook mask, and the current hook count +-- (as set by the `debug.sethook` function). +function debug.gethook(thread) end + +--- +-- Returns a table with information about a function. You can give the +-- function directly, or you can give a number as the value of `function`, +-- which means the function running at level `function` of the call stack +-- of the given thread: level 0 is the current function (`getinfo` itself); +-- level 1 is the function that called `getinfo`; and so on. If `function` +-- is a number larger than the number of active functions, then `getinfo` +-- returns nil. +-- +-- `thread` and `what` are optional. +-- +-- The returned table can contain all the fields returned by `lua_getinfo`, +-- with the string `what` describing which fields to fill in. The default for +-- `what` is to get all information available, except the table of valid +-- lines. If present, the option '`f`' adds a field named `func` with +-- the function itself. If present, the option '`L`' adds a field named +-- `activelines` with the table of valid lines. +-- For instance, the expression `debug.getinfo(1,"n").name` returns a table +-- with a name for the current function, if a reasonable name can be found, +-- and the expression `debug.getinfo(print)` returns a table with all available +-- information about the `print` function. +function debug.getinfo(thread, func , what) end + +--- +-- This function returns the name and the value of the local variable with +-- index `loc` of the function at level `level` of the stack. (The first +-- parameter or local variable has index 1, and so on, until the last active +-- local variable.) The function returns nil if there is no local variable +-- with the given index, and raises an error when called with a `level` out +-- of range. (You can call `debug.getinfo` to check whether the level is valid.) +-- Variable names starting with '`(`' (open parentheses) represent internal +-- variables (loop control variables, temporaries, and C function locals). +function debug.getlocal(thread, level, loc) end + +--- +-- Returns the metatable of the given `object` or nil if it does not have +-- a metatable. +function debug.getmetatable(object) end + +--- +-- Returns the registry table (see §3.5). +function debug.getregistry() end + +--- +-- This function returns the name and the value of the upvalue with index +-- `up` of the function `func`. The function returns nil if there is no +-- upvalue with the given index. +function debug.getupvalue(func, up) end + +--- +-- Sets the environment of the given `object` to the given `table`. Returns +-- `object`. +function debug.setfenv(object, table) end + +--- +-- Sets the given function as a hook. The string `mask` and the number +-- `count` describe when the hook will be called. The string mask may have +-- the following characters, with the given meaning: +-- +-- * `"c"`: the hook is called every time Lua calls a function; +-- * `"r"`: the hook is called every time Lua returns from a function; +-- * `"l"`: the hook is called every time Lua enters a new line of code. +-- +-- With a `count` different from zero, the hook is called after every `count` +-- instructions. +-- +-- When called without arguments, `debug.sethook` turns off the hook. +-- +-- When the hook is called, its first parameter is a string describing +-- the event that has triggered its call: `"call"`, `"return"` (or `"tail +-- return"`, when simulating a return from a tail call), `"line"`, and +-- `"count"`. For line events, the hook also gets the new line number as its +-- second parameter. Inside a hook, you can call `getinfo` with level 2 to +-- get more information about the running function (level 0 is the `getinfo` +-- function, and level 1 is the hook function), unless the event is `"tail +-- return"`. In this case, Lua is only simulating the return, and a call to +-- `getinfo` will return invalid data. +function debug.sethook(thread, hook, mask , count) end + +--- +-- This function assigns the value `value` to the local variable with +-- index `loc` of the function at level `level` of the stack. The function +-- returns nil if there is no local variable with the given index, and raises +-- an error when called with a `level` out of range. (You can call `getinfo` +-- to check whether the level is valid.) Otherwise, it returns the name of +-- the local variable. +function debug.setlocal(thread, level, loc, value) end + +--- +-- Sets the metatable for the given `object` to the given `table` (which +-- can be nil). +function debug.setmetatable(object, table) end + +--- +-- This function assigns the value `value` to the upvalue with index `up` +-- of the function `func`. The function returns nil if there is no upvalue +-- with the given index. Otherwise, it returns the name of the upvalue. +function debug.setupvalue(func, up, value) end + +return debug diff --git a/Data/Libraries/LDoc/ldoc/builtin/global.lua b/Data/Libraries/LDoc/ldoc/builtin/global.lua new file mode 100644 index 0000000..b1799c3 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/builtin/global.lua @@ -0,0 +1,243 @@ +--- Lua global functions. + +module 'global' + +-- luacheck: ignore 121 + +--- +-- Issues an error when its argument `v` is false. +-- That is, nil or false. otherwise, returns all its arguments. +-- `message` is an error when absent, it defaults to "assertion failed!" +function assert(v , message) end + +--- +-- This function is a generic interface to the garbage collector. It +-- performs different functions according to its first argument, `opt`: +-- +-- * "stop": stops the garbage collector. +-- * "restart": restarts the garbage collector. +-- * "collect": performs a full garbage-collection cycle. +-- * "count": returns the total memory in use by Lua (in Kbytes). +-- * "step": performs a garbage-collection step. The step "size" is controlled +-- by `arg` (larger values mean more steps) in a non-specified way. If you +-- want to control the step size you must experimentally tune the value of +-- * "arg". Returns true if the step finished a collection cycle. +-- * "setpause": sets `arg` as the new value for the *pause* of the collector +-- (see 2.10). Returns the previous value for *pause*. +-- * "setstepmul": sets `arg` as the new value for the *step multiplier* +-- of the collector (see 2.10). Returns the previous value for *step*. +-- +function collectgarbage(opt , arg) end + +--- +-- Opens the named file and executes its contents as a Lua chunk. When +-- called without arguments, +-- `dofile` executes the contents of the standard input (`stdin`). Returns +-- all values returned by the chunk. In case of errors, `dofile` propagates +-- the error to its caller (that is, `dofile` does not run in protected mode). +function dofile(filename) end + +--- +-- Terminates the last protected function called. +-- Returns `message` as the error message. +-- Function `error` never returns. +-- Usually, `error` adds some information about the error position at the +-- beginning of the message. The `level` argument specifies how to get the +-- error position. With level 1 (the default), the error position is where the +-- `error` function was called. Level 2 points the error to where the function +-- that called `error` was called; and so on. Passing a level 0 avoids the +-- addition of error position information to the message. +function error(message , level) end + +--- +-- A global variable (not a function) that holds the global environment +-- (that is, `_G._G = _G`). Lua itself does not use this variable; changing +-- its value does not affect any environment, nor vice-versa. (Set `__ENV` +-- to change environments in functions) +-- @table _G + +--- +-- If `object` does not have a metatable, returns nil. Otherwise, if the +-- object's metatable has a `"__metatable"` field, returns the associated +-- value. Otherwise, returns the metatable of the given object. +function getmetatable(object) end + +--- +-- For iterating over sequences. Returns three values: an iterator function, the table `t`, and 0, +-- so that the construction +-- for i,v in ipairs(t) do *body* end +-- will iterate over the pairs (`1,t[1]`), (`2,t[2]`), ..., up to the +-- first integer key absent from the table. +function ipairs(t) end + +--- +-- Loads a chunk. +-- If `ld` is a string, the chunk is this string. +-- If `ld` is a function, load calls it repeatedly to get the chunk pieces. Each call to `ld` must return a +-- string that concatenates with previous results. A return of an empty string, nil, or no value +-- signals the end of the chunk. +-- If there are no syntactic errors, returns the compiled chunk as a function; +-- otherwise, returns nil plus the error message. +-- If the resulting function has upvalues, the first upvalue is set to the value of the global environment or to `env`, +-- if that parameter is given. When loading main chunks, the first upvalue will be the`_ENV` variable (see 2.2). +-- `source` is used as the source of the chunk for error messages and debug information (see 4.9). +-- When absent, it defaults to `ld`, if `ld` is a string, or to "=(load)" otherwise. +-- The string `mode` controls whether the chunk can be text or binary (that is, a precompiled chunk). +-- It may be the string "b" (only binary chunks), "t" (only text chunks), or "bt" (both binary and text). +-- The default is "bt" +function load (ld , source , mode , env) end + +--- +-- Similar to `load`, but gets the chunk from file `filename`. Or from the +-- standard input, if no file name is given. +function loadfile (filename , mode , env) end + +--- +-- Allows a program to traverse all fields of a table. Its first argument is +-- a table and its second argument is an index in this table. `next` returns +-- the next index of the table and its associated value. +-- +-- When called with nil +-- as its second argument, `next` returns an initial index and its associated +-- value. When called with the last index, or with nil in an empty table, `next` +-- returns nil. +-- +-- If the second argument is absent, then it is interpreted as +-- nil. In particular, you can use `next(t)` to check whether a table is empty. +-- The order in which the indices are enumerated is not specified, *even for +-- numeric indices*. (To traverse a table in numeric order, use a numerical +-- for or the `ipairs` function.) +-- +-- The behavior of `next` is *undefined* if, during the traversal, you assign +-- any value to a non-existent field in the table. You may however modify +-- existing fields. In particular, you may clear existing fields. +function next(table , index) end + +--- +-- For iterating over all key-value pairs of a table. +-- Returns three values: the `next` function, the table `t`, and nil, +-- so that the construction +-- for k,v in pairs(t) do *body* end +-- will iterate over all key-value pairs of table `t`. +-- See function `next` for the caveats of modifying the table during its +-- traversal. +function pairs(t) end + +--- +-- Calls function `f` with the given arguments in *protected mode*. This +-- means that any error inside `f` is not propagated; instead, `pcall` catches +-- the error and returns a status code. Its first result is the status code (a +-- boolean), which is true if the call succeeds without errors. In such case, +-- `pcall` also returns all results from the call, after this first result. In +-- case of any error, `pcall` returns false plus the error message. +function pcall(f, arg1, ...) end + +--- +--Prints any number of values to `stdout`. +-- Uses the `tostring` function to convert them to strings. `print` is not +-- intended for formatted output, but only as a quick way to show a value, +-- typically for debugging. For formatted output, use `string.format`. +function print(...) end + +--- +-- Checks whether `v1` is equal to `v2`. Does not invoke any +-- metamethod. Returns a boolean. +function rawequal(v1, v2) end + +--- +-- Gets the real value of `table[index]`. Does not invoke any +-- metamethod. `table` must be a table; `index` may be any value. +function rawget(table, index) end + +--- +-- Sets the real value of `table[index]` to `value`. Does not invoke any +-- metamethod. `table` must be a table, `index` any value different from nil, +-- and `value` any Lua value. +-- This function returns `table`. +function rawset(table, index, value) end + +--- +-- Returns all arguments after argument number +-- `index`. Otherwise, `index` must be the string `"#"`, and `select` returns +-- the total number of extra arguments it received. +function select(index, ...) end + +--- +-- Sets the metatable for the given table. (You cannot change the metatable +-- of other types from Lua, only from C.) If `metatable` is nil, removes the +-- metatable of the given table. If the original metatable has a `"__metatable"` +-- field, raises an error. +-- This function returns `table`. +function setmetatable(table, metatable) end + +--- +-- Tries to convert its argument to a number. If the argument is already +-- a number or a string convertible to a number, then `tonumber` returns this +-- number; otherwise, it returns nil. +-- An optional argument specifies the base to interpret the numeral. The base +-- may be any integer between 2 and 36, inclusive. In bases above 10, the +-- letter '`A`' (in either upper or lower case) represents 10, '`B`' represents +-- 11, and so forth, with '`Z`' representing 35. In base 10 (the default), +-- the number can have a decimal part, as well as an optional exponent part +-- (see 2.1). In other bases, only unsigned integers are accepted. +function tonumber(e , base) end + +--- +-- Converts any value to a string in a reasonable format. +-- For complete control of how numbers are converted, use `string.format`. +-- If the metatable of `e` has a `"__tostring"` field, then `tostring` calls +-- the corresponding value with `e` as argument, and uses the result of the +-- call as its result. +function tostring(e) end + +--- +-- Returns the type of its only argument, coded as a string. The possible +-- results of this function are " +-- `nil`" (a string, not the value nil), "`number`", "`string`", "`boolean`", +-- "`table`", "`function`", "`thread`", and "`userdata`". +function type(v) end + +--- +-- A global variable (not a function) that holds a string containing the +-- current interpreter version. The current contents of this variable is +-- "`Lua 5.1`". +-- @table _VERSION + +--- +-- This function is similar to `pcall`, except that you can set a new +-- error handler. +-- `xpcall` calls function `f` in protected mode, using `err` as the error +-- handler. Any error inside `f` is not propagated; instead, `xpcall` catches +-- the error, calls the `err` function with the original error object, and +-- returns a status code. Its first result is the status code (a boolean), +-- which is true if the call succeeds without errors. In this case, `xpcall` +-- also returns all results from the call, after this first result. In case +-- of any error, `xpcall` returns false plus the result from `err`. +function xpcall(f, err) end + +--- +-- Loads the given module. The function starts by looking into the +-- `package.loaded` table to determine whether `modname` is already +-- loaded. If it is, then `require` returns the value stored at +-- `package.loaded[modname]`. Otherwise, it tries to find a *loader* for +-- the module. +-- To find a loader, `require` is guided by the `package.loaders` array. By +-- changing this array, we can change how `require` looks for a module. The +-- following explanation is based on the default configuration for +-- `package.loaders`. +-- First `require` queries `package.preload[modname]`. If it has a value, +-- this value (which should be a function) is the loader. Otherwise `require` +-- searches for a Lua loader using the path stored in `package.path`. If +-- that also fails, it searches for a C loader using the path stored in +-- `package.cpath`. If that also fails, it tries an *all-in-one* loader (see +-- `package.loaders`). +-- Once a loader is found, `require` calls the loader with a single argument, +-- `modname`. If the loader returns any value, `require` assigns the returned +-- value to `package.loaded[modname]`. If the loader returns no value and +-- has not assigned any value to `package.loaded[modname]`, then `require` +-- assigns true to this entry. In any case, `require` returns the final value +-- of `package.loaded[modname]`. +-- If there is any error loading or running the module, or if it cannot find +-- any loader for the module, then `require` signals an error. +function require(modname) end + diff --git a/Data/Libraries/LDoc/ldoc/builtin/globals.lua b/Data/Libraries/LDoc/ldoc/builtin/globals.lua new file mode 100644 index 0000000..a26f605 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/builtin/globals.lua @@ -0,0 +1,170 @@ +------- +-- global functions and tables +local tools = require 'ldoc.tools' +local globals = {} +local lua52 = _VERSION:match '5.2' +local lua53 = _VERSION:match '5.3' + + +globals.functions = { + assert = true, + collectgarbage = true, + dofile = true, + error = true, + getmetatable = true, + setmetatable = true, + pairs = true, + ipairs = true, + load = true, + loadfile = true, + loadstring = true, + next = true, + pcall = true, + print = true, + rawequal = true, + rawget = true, + rawset = true, + select = true, + tonumber = true, + tostring = true, + type = true, + xpcall = true, + module = true, + require = true, +} +local functions = globals.functions + +if lua52 or lua53 then + functions.rawlen = true +else + functions.setfenv = true + functions.getfenv = true + functions.unpack = true +end + +local manual, fun_ref + +function globals.set_manual_url(url) + manual = url .. '#' + fun_ref = manual..'pdf-' +end + +if lua53 then + globals.tables = { + io = '6.8', + package = '6.3', + math = '6.7', + os = '6.9', + string = '6.4', + table = '6.6', + coroutine = '6.2', + debug = '6.10' + } + globals.set_manual_url 'https://www.lua.org/manual/5.3/manual.html' +elseif lua52 then + globals.tables = { + io = '6.8', + package = '6.3', + math = '6.6', + os = '6.9', + string = '6.4', + table = '6.5', + coroutine = '6.2', + debug = '6.10' + } + globals.set_manual_url 'https://www.lua.org/manual/5.2/manual.html' +else + globals.tables = { + io = '5.7', + package = '5.3', + math = '5.6', + os = '5.8', + string = '5.4', + table = '5.5', + coroutine = '5.2', + debug = '5.9' + } + globals.set_manual_url 'https://www.lua.org/manual/5.1/manual.html' +end + +local file_methods = { + close = true, + flush = true, + lines = true, + read = true, + seek = true, + setvbuf = true, + write = true, +} + +-- external libs tracked by LDoc using LDoc style +local xlibs = { + lfs='lfs.html', lpeg='lpeg.html', +} +local xlib_url = 'http://stevedonovan.github.io/lua-stdlibs/modules/' + +local tables = globals.tables + +local function function_ref (name,tbl) + local href + if not tbl then -- can only be a standard Lua global function + if globals.functions[name] then + return {href = fun_ref..name, label = name} + else + return nil + end + end + if tbl == 'file' then -- special case: file objects! + if not file_methods[name] then + return nil + end + name = 'file:'..name + href = fun_ref..name + elseif tables[tbl] then -- function inside standard Lua table + local t = rawget(_G,tbl) -- do a quick sanity check + if not rawget(t,name) then + return nil + end + name = tbl..'.'..name + href = fun_ref..name + elseif xlibs[tbl] then -- in external libs, use LDoc style + local t = require('ldoc.builtin.'..tbl) + if not rawget(t,name) then + return nil + end + href = xlib_url..xlibs[tbl]..'#'..name + name = tbl..'.'..name + else + return nil + end + return {href = href, label = name} +end + +local function module_ref (tbl) + local href + if tables[tbl] ~= nil then -- standard Lua table + href = manual..tables[tbl] + elseif xlibs[tbl] then -- external lib + href = xlib_url..xlibs[tbl] + else + return nil + end + return {href = href, label = tbl} +end + +function globals.lua_manual_ref (name) + local tbl,fname = tools.split_dotted_name(name) + local ref + if not tbl then -- plain symbol + ref = function_ref(name) + if ref then return ref end + ref = module_ref(name) + if ref then return ref end + else + ref = function_ref(fname,tbl) + if ref then return ref end + end + return nil +end + +return globals diff --git a/Data/Libraries/LDoc/ldoc/builtin/io.lua b/Data/Libraries/LDoc/ldoc/builtin/io.lua new file mode 100644 index 0000000..c97cb4e --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/builtin/io.lua @@ -0,0 +1,162 @@ +--- Reading and Writing Files. +-- @module io + +local io = {} + +-- luacheck: ignore 241 +local file = {} + +--- +-- Equivalent to `file:close()`. Without a `file`, closes the default +-- output file. +function io.close(file) end + +--- +-- Equivalent to `file:flush` over the default output file. +function io.flush() end + +--- +-- When called with a file name, it opens the named file (in text mode), +-- and sets its handle as the default input file. When called with a file +-- handle, it simply sets this file handle as the default input file. When +-- called without parameters, it returns the current default input file. +-- In case of errors this function raises the error, instead of returning an +-- error code. +function io.input(file) end + +--- +-- Opens the given file name in read mode and returns an iterator function +-- that, each time it is called, returns a new line from the file. Therefore, +-- the construction +-- for line in io.lines(filename) do *body* end +-- will iterate over all lines of the file. When the iterator function detects +-- the end of file, it returns nil (to finish the loop) and automatically +-- closes the file. +-- The call `io.lines()` (with no file name) is equivalent to +-- `io.input():lines()`; that is, it iterates over the lines of the default +-- input file. In this case it does not close the file when the loop ends. +function io.lines(filename) end + +--- +-- This function opens a file, in the mode specified in the string `mode`. It +-- returns a new file handle, or, in case of errors, nil plus an error message. +-- The `mode` string can be any of the following: +-- "r": read mode (the default); +-- "w": write mode; +-- "a": append mode; +-- "r+": update mode, all previous data is preserved; +-- "w+": update mode, all previous data is erased; +-- "a+": append update mode, previous data is preserved, writing is only +-- allowed at the end of file. +-- The `mode` string can also have a '`b`' at the end, which is needed in +-- some systems to open the file in binary mode. This string is exactly what +-- is used in the standard C function `fopen`. +function io.open(filename , mode) end + +--- +-- Similar to `io.input`, but operates over the default output file. +function io.output(file) end + +--- +-- Starts program `prog` in a separated process and returns a file handle +-- that you can use to read data from this program (if `mode` is `"r"`, +-- the default) or to write data to this program (if `mode` is `"w"`). +-- This function is system dependent and is not available on all platforms. +function io.popen(prog , mode) end + +--- +-- Equivalent to `io.input():read`. +function io.read(...) end + +-- * `io.stderr`: Standard error. +-- * `io.stdin`: Standard in. +-- * `io.stdout`: Standard out. + +--- +-- Returns a handle for a temporary file. This file is opened in update +-- mode and it is automatically removed when the program ends. +function io.tmpfile() end + +--- +-- Checks whether `obj` is a valid file handle. Returns the string `"file"` +-- if `obj` is an open file handle, `"closed file"` if `obj` is a closed file +-- handle, or nil if `obj` is not a file handle. +function io.type(obj) end + +--- +-- Equivalent to `io.output():write`. +function io.write(...) end + +--- +-- Closes `file`. Note that files are automatically closed when their +-- handles are garbage collected, but that takes an unpredictable amount of +-- time to happen. +function file:close() end + +--- +-- Saves any written data to `file`. +function file:flush() end + +--- +-- Returns an iterator function that, each time it is called, returns a +-- new line from the file. Therefore, the construction +-- for line in file:lines() do *body* end +-- will iterate over all lines of the file. (Unlike `io.lines`, this function +-- does not close the file when the loop ends.) +function file:lines() end + +--- +-- Reads the file `file`, according to the given formats, which specify +-- what to read. For each format, the function returns a string (or a number) +-- with the characters read, or nil if it cannot read data with the specified +-- format. When called without formats, it uses a default format that reads +-- the entire next line (see below). +-- The available formats are +-- "*n": reads a number; this is the only format that returns a number +-- instead of a string. +-- "*a": reads the whole file, starting at the current position. On end of +-- file, it returns the empty string. +-- "*l": reads the next line (skipping the end of line), returning nil on +-- end of file. This is the default format. +-- *number*: reads a string with up to this number of characters, returning +-- nil on end of file. If number is zero, it reads nothing and returns an +-- empty string, or nil on end of file. +function file:read(...) end + +--- +-- Sets and gets the file position, measured from the beginning of the +-- file, to the position given by `offset` plus a base specified by the string +-- `whence`, as follows: +-- "set": base is position 0 (beginning of the file); +-- "cur": base is current position; +-- "end": base is end of file; +-- In case of success, function `seek` returns the final file position, +-- measured in bytes from the beginning of the file. If this function fails, +-- it returns nil, plus a string describing the error. +-- The default value for `whence` is `"cur"`, and for `offset` is 0. Therefore, +-- the call `file:seek()` returns the current file position, without changing +-- it; the call `file:seek("set")` sets the position to the beginning of the +-- file (and returns 0); and the call `file:seek("end")` sets the position +-- to the end of the file, and returns its size. +function file:seek(whence , offset) end + +--- +-- Sets the buffering mode for an output file. There are three available +-- modes: +-- +-- * "no": no buffering; the result of any output operation appears immediately. +-- * "full": full buffering; output operation is performed only when the +-- buffer is full (or when you explicitly `flush` the file (see `io.flush`)). +-- * "line": line buffering; output is buffered until a newline is output or +-- there is any input from some special files (such as a terminal device). +-- For the last two cases, `size` specifies the size of the buffer, in +-- bytes. The default is an appropriate size. +function file:setvbuf(mode , size) end + +--- +-- Writes the value of each of its arguments to the `file`. The arguments +-- must be strings or numbers. To write other values, use `tostring` or +-- `string.format` before `write`. +function file:write(...) end + +return io diff --git a/Data/Libraries/LDoc/ldoc/builtin/lfs.lua b/Data/Libraries/LDoc/ldoc/builtin/lfs.lua new file mode 100644 index 0000000..4f692fa --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/builtin/lfs.lua @@ -0,0 +1,125 @@ +--- File and Directory manipulation +-- @module lfs + +local lfs = {} + +--- +-- Returns a table with the file attributes corresponding to filepath (or nil +-- followed by an error message in case of error). If the second optional +-- argument is given, then only the value of the named attribute is returned +-- (this use is equivalent to lfs.attributes(filepath).aname, but the table is +-- not created and only one attribute is retrieved from the O.S.). The +-- attributes are described as follows; attribute mode is a string, all the +-- others are numbers, and the time related attributes use the same time +-- reference of os.time: +-- +-- - dev: on Unix systems, this represents the device that the inode resides on. +-- On Windows systems, represents the drive number of the disk containing +-- the file +-- - ino: on Unix systems, this represents the inode number. On Windows systems +-- this has no meaning +-- - mode: string representing the associated protection mode (the values could +-- be file, directory, link, socket, named pipe, char device, block +-- device or other) +-- - nlink: number of hard links to the file +-- - uid: user-id of owner (Unix only, always 0 on Windows) +-- - gid: group-id of owner (Unix only, always 0 on Windows) +-- - rdev: on Unix systems, represents the device type, for special file inodes. +-- On Windows systems represents the same as dev +-- - access: time of last access +-- - modification: time of last data modification +-- - change: time of last file status change +-- - size: file size, in bytes +-- - blocks: block allocated for file; (Unix only) +-- - blksize: optimal file system I/O blocksize; (Unix only) +-- This function uses stat internally thus if the given filepath is a symbolic +-- link, it is followed (if it points to another link the chain is followed +-- recursively) and the information is about the file it refers to. To obtain +-- information about the link itself, see function lfs.symlinkattributes. +function lfs.attributes(filepath , aname) end + +--- +-- Changes the current working directory to the given path. +-- Returns true in case of success or nil plus an error string. +function lfs.chdir(path) end + +--- +-- Creates a lockfile (called lockfile.lfs) in path if it does not exist and +-- returns the lock. If the lock already exists checks it it's stale, using the +-- second parameter (default for the second parameter is INT_MAX, which in +-- practice means the lock will never be stale. To free the the lock call +-- lock:free(). +-- In case of any errors it returns nil and the error message. In particular, +-- if the lock exists and is not stale it returns the "File exists" message. +function lfs.lock_dir(path, seconds_stale) end + +--- +-- Returns a string with the current working directory or nil plus an error +-- string. +function lfs.currentdir() end + +--- +-- Lua iterator over the entries of a given directory. Each time the iterator is +-- called with dir_obj it returns a directory entry's name as a string, or nil +-- if there are no more entries. You can also iterate by calling `dir_obj:next()`, +-- and explicitly close the directory before the iteration finished with +-- `dir_obj:close()`. Raises an error if path is not a directory. +function lfs.dir(path) end + +--- +-- Locks a file or a part of it. This function works on open files; the file +-- handle should be specified as the first argument. The string mode could be +-- either r (for a read/shared lock) or w (for a write/exclusive lock). The +-- optional arguments start and length can be used to specify a starting point +-- and its length; both should be numbers. +-- Returns true if the operation was successful; in case of error, it returns +-- nil plus an error string. +function lfs.lock(filehandle, mode, start, length) end + +--- +-- Creates a new directory. The argument is the name of the new directory. +-- Returns true if the operation was successful; in case of error, it returns +-- nil plus an error string. +function lfs.mkdir(dirname) end + +--- +-- Removes an existing directory. The argument is the name of the directory. +-- Returns true if the operation was successful; in case of error, it returns +-- nil plus an error string. +function lfs.rmdir(dirname) end + +--- +-- Sets the writing mode for a file. The mode string can be either binary or +-- text. Returns the previous mode string for the file. This function is only +-- available in Windows, so you may want to make sure that lfs.setmode exists +-- before using it. +function lfs.setmode(file, mode) end + +--- +-- Identical to lfs.attributes except that it obtains information about the link +-- itself (not the file it refers to). This function is not available in Windows +-- so you may want to make sure that lfs.symlinkattributes exists before using +-- it. +function lfs.symlinkattributes(filepath , aname) end + +--- +-- Set access and modification times of a file. This function is a bind to utime +-- function. The first argument is the filename, the second argument (atime) is +-- the access time, and the third argument (mtime) is the modification time. +-- Both times are provided in seconds (which should be generated with Lua +-- standard function os.time). If the modification time is omitted, the access +-- time provided is used; if both times are omitted, the current time is used. +-- Returns true if the operation was successful; in case of error, it returns +-- nil plus an error string. +function lfs.touch(filepath , atime , mtime) end + +--- +-- Unlocks a file or a part of it. This function works on open files; the file +-- handle should be specified as the first argument. The optional arguments +-- start and length can be used to specify a starting point and its length; both +-- should be numbers. +-- Returns true if the operation was successful; in case of error, it returns +-- nil plus an error string. +function lfs.unlock(filehandle, start, length) end + +return lfs diff --git a/Data/Libraries/LDoc/ldoc/builtin/lpeg.lua b/Data/Libraries/LDoc/ldoc/builtin/lpeg.lua new file mode 100644 index 0000000..f9ce14f --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/builtin/lpeg.lua @@ -0,0 +1,214 @@ +--- LPeg PEG pattern matching. +-- @module lpeg + +local lpeg = {} + +--- +-- The matching function. It attempts to match the given pattern against the +-- subject string. If the match succeeds, returns the index in the subject of +-- the first character after the match, or the captured values (if the pattern +-- captured any value). +-- +-- An optional numeric argument init makes the match starts at that position in +-- the subject string. As usual in Lua libraries, a negative value counts from +-- the end. +-- +-- Unlike typical pattern-matching functions, match works only in anchored mode; +-- that is, it tries to match the pattern with a prefix of the given subject +-- string (at position init), not with an arbitrary substring of the subject. +-- So, if we want to find a pattern anywhere in a string, we must either write a +-- loop in Lua or write a pattern that matches anywhere. This second approach is +-- easy and quite efficient; see examples. +function lpeg.match(pattern, subject , init) end + +--- +-- If the given value is a pattern, returns the string "pattern". Otherwise +-- returns nil. +function lpeg.type(value) end + +--- +-- Returns a string with the running version of LPeg. +function lpeg.version() end + +--- +-- Sets the maximum size for the backtrack stack used by LPeg to track calls and +-- choices. Most well-written patterns need little backtrack levels and +-- therefore you seldom need to change this maximum; but a few useful patterns +-- may need more space. Before changing this maximum you should try to rewrite +-- your pattern to avoid the need for extra space. +function lpeg.setmaxstack(max) end + +--- +-- Converts the given value into a proper pattern, according to the following +-- rules: +-- * If the argument is a pattern, it is returned unmodified. +-- * If the argument is a string, it is translated to a pattern that matches +-- literally the string. +-- * If the argument is a non-negative number n, the result is a pattern that +-- matches exactly n characters. +-- * If the argument is a negative number -n, the result is a pattern that +-- succeeds only if the input string does not have n characters: lpeg.P(-n) +-- is equivalent to -lpeg.P(n) (see the unary minus operation). +-- * If the argument is a boolean, the result is a pattern that always +-- succeeds or always fails (according to the boolean value), without +-- consuming any input. +-- * If the argument is a table, it is interpreted as a grammar (see +-- Grammars). +-- * If the argument is a function, returns a pattern equivalent to a +-- match-time capture over the empty string. +function lpeg.P(value) end + +--- +-- Returns a pattern that matches any single character belonging to one of the +-- given ranges. Each range is a string xy of length 2, representing all +-- characters with code between the codes of x and y (both inclusive). +-- As an example, the pattern `lpeg.R("09")` matches any digit, and `lpeg.R("az", +-- "AZ")` matches any ASCII letter. +function lpeg.R(range) end + +--- +-- Returns a pattern that matches any single character that appears in the given +-- string. (The S stands for Set.) +-- As an example, the pattern lpeg.S("+-*/") matches any arithmetic operator. +-- Note that, if s is a character (that is, a string of length 1), then +-- lpeg.P(s) is equivalent to lpeg.S(s) which is equivalent to lpeg.R(s..s). +-- Note also that both lpeg.S("") and lpeg.R() are patterns that always fail. +function lpeg.S(string) end + +--- +-- This operation creates a non-terminal (a variable) for a grammar. The created +-- non-terminal refers to the rule indexed by v in the enclosing grammar. (See +-- Grammars for details.) +function lpeg.V(v) end + +--- +-- Returns a table with patterns for matching some character classes according +-- to the current locale. The table has fields: +-- +-- * alnum +-- * alpha +-- * cntrl +-- * digit +-- * graph +-- * lower +-- * print +-- * punct +-- * space +-- * upper +-- * xdigit +-- +-- each one containing a +-- correspondent pattern. Each pattern matches any single character that belongs +-- to its class. +-- +-- If called with an argument table, then it creates those fields inside the +-- given table and returns that table. +function lpeg.locale(table) end + +--- +-- Creates a simple capture, which captures the substring of the subject that +-- matches patt. The captured value is a string. If patt has other captures, +-- their values are returned after this one. +function lpeg.C(patt) end + +--- +-- Creates an argument capture. This pattern matches the empty string and +-- produces the value given as the nth extra argument given in the call to +-- lpeg.match. +function lpeg.Carg(n) end + +--- +-- Creates a back capture. This pattern matches the empty string and produces +-- the values produced by the most recent group capture named name. +-- Most recent means the last complete outermost group capture with the given +-- name. A Complete capture means that the entire pattern corresponding to the +-- capture has matched. An Outermost capture means that the capture is not +-- inside another complete capture. +function lpeg.Cb(name) end + +--- +-- Creates a constant capture. This pattern matches the empty string and +-- produces all given values as its captured values. +function lpeg.Cc(...) end + +--- +-- Creates a fold capture. If patt produces a list of captures C1 C2 ... Cn, +-- this capture will produce the value func(...func(func(C1, C2), C3)..., Cn), +-- that is, it will fold (or accumulate, or reduce) the captures from patt using +-- function func. +-- +-- This capture assumes that patt should produce at least one capture with at +-- least one value (of any type), which becomes the initial value of an +-- accumulator. (If you need a specific initial value, you may prefix a constant +-- capture to patt.) For each subsequent capture LPeg calls func with this +-- accumulator as the first argument and all values produced by the capture as +-- extra arguments; the value returned by this call becomes the new value for +-- the accumulator. The final value of the accumulator becomes the captured +-- value. +-- +-- As an example, the following pattern matches a list of numbers separated by +-- commas and returns their addition: +-- +-- -- matches a numeral and captures its value +-- number = lpeg.R"09"^1 / tonumber +-- -- matches a list of numbers, captures their values +-- list = number * ("," * number)^0 +-- -- auxiliary function to add two numbers +-- function add (acc, newvalue) return acc + newvalue end +-- -- folds the list of numbers adding them +-- sum = lpeg.Cf(list, add) +-- -- example of use +-- print(sum:match("10,30,43")) --> 83 +-- +function lpeg.Cf(patt, func) end + +--- +-- Creates a group capture. It groups all values returned by patt into a single +-- capture. The group may be anonymous (if no name is given) or named with the +-- given name. +-- An anonymous group serves to join values from several captures into a single +-- capture. A named group has a different behavior. In most situations, a named +-- group returns no values at all. Its values are only relevant for a following +-- back capture or when used inside a table capture. +function lpeg.Cg(patt , name) end + +--- +-- Creates a position capture. It matches the empty string and captures the +-- position in the subject where the match occurs. The captured value is a +-- number. +function lpeg.Cp() end + +--- +-- Creates a substitution capture, which captures the substring of the subject +-- that matches patt, with substitutions. For any capture inside patt with a +-- value, the substring that matched the capture is replaced by the capture +-- value (which should be a string). The final captured value is the string +-- resulting from all replacements. +function lpeg.Cs(patt) end + +--- +-- Creates a table capture. This capture creates a table and puts all values +-- from all anonymous captures made by patt inside this table in successive +-- integer keys, starting at 1. Moreover, for each named capture group created +-- by patt, the first value of the group is put into the table with the group +-- name as its key. The captured value is only the table. +function lpeg.Ct(patt) end + +--- +-- Creates a match-time capture. Unlike all other captures, this one is +-- evaluated immediately when a match occurs. It forces the immediate evaluation +-- of all its nested captures and then calls func. +-- The given function gets as arguments the entire subject, the current position +-- (after the match of patt), plus any capture values produced by patt. +-- The first value returned by function defines how the match happens. If the +-- call returns a number, the match succeeds and the returned number becomes the +-- new current position. (Assuming a subject s and current position i, the +-- returned number must be in the range [i, len(s) + 1].) If the call returns +-- true, the match succeeds without consuming any input. (So, to return true is +-- equivalent to return i.) If the call returns false, nil, or no value, the +-- match fails. +-- Any extra values returned by the function become the values produced by the +-- capture. +function lpeg.Cmt(patt, func) end + +return lpeg diff --git a/Data/Libraries/LDoc/ldoc/builtin/math.lua b/Data/Libraries/LDoc/ldoc/builtin/math.lua new file mode 100644 index 0000000..3f83624 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/builtin/math.lua @@ -0,0 +1,144 @@ +--- standard mathematical functions. +-- @module math + +local math = {} + +--- +-- Returns the absolute value of `x`. +function math.abs(x) end + +--- +-- Returns the arc cosine of `x` (in radians). +function math.acos(x) end + +--- +-- Returns the arc sine of `x` (in radians). +function math.asin(x) end + +--- +-- Returns the arc tangent of `x` (in radians). +function math.atan(x) end + +--- +-- Returns the arc tangent of `y/x` (in radians), but uses the signs +-- of both parameters to find the quadrant of the result. (It also handles +-- correctly the case of `x` being zero.) +function math.atan2(y, x) end + +--- +-- Returns the smallest integer larger than or equal to `x`. +function math.ceil(x) end + +--- +-- Returns the cosine of `x` (assumed to be in radians). +function math.cos(x) end + +--- +-- Returns the hyperbolic cosine of `x`. +function math.cosh(x) end + +--- +-- Returns the angle `x` (given in radians) in degrees. +function math.deg(x) end + +--- +-- Returns the value *e^x*. +function math.exp(x) end + +--- +-- Returns the largest integer smaller than or equal to `x`. +function math.floor(x) end + +--- +-- Returns the remainder of the division of `x` by `y` that rounds the +-- quotient towards zero. +function math.fmod(x, y) end + +--- +-- Returns `m` and `e` such that *x = m2^e*, `e` is an integer and the +-- absolute value of `m` is in the range *[0.5, 1)* (or zero when `x` is zero). +function math.frexp(x) end + +--- +-- The value `HUGE_VAL`, a value larger than or equal to any other +-- numerical value. +-- function math.huge end +-- * `math.HUGE_VAL`: math.HUGE_VAL + +--- +-- Returns *m2^e* (`e` should be an integer). +function math.ldexp(m, e) end + +--- +-- Returns the natural logarithm of `x`. +function math.log(x) end + +--- +-- Returns the base-10 logarithm of `x`. +function math.log10(x) end + +--- +-- Returns the maximum value among its arguments. +function math.max(x, ...) end + +--- +-- Returns the minimum value among its arguments. +function math.min(x, ...) end + +--- +-- Returns two numbers, the integral part of `x` and the fractional part of +-- `x`. +function math.modf(x) end + +--- +-- The value of *pi*. +-- function math.pi end +-- * `math.pi`: math.pi + +--- +-- Returns *x^y*. (You can also use the expression `x^y` to compute this +-- value.) +function math.pow(x, y) end + +--- +-- Returns the angle `x` (given in degrees) in radians. +function math.rad(x) end + +--- +-- This function is an interface to the simple pseudo-random generator +-- function `rand` provided by ANSI C. (No guarantees can be given for its +-- statistical properties.) +-- When called without arguments, returns a uniform pseudo-random real +-- number in the range *[0,1)*. When called with an integer number `m`, +-- `math.random` returns a uniform pseudo-random integer in the range *[1, +-- m]*. When called with two integer numbers `m` and `n`, `math.random` +-- returns a uniform pseudo-random integer in the range *[m, n]*. +function math.random(m , n) end + +--- +-- Sets `x` as the "seed" for the pseudo-random generator: equal seeds +-- produce equal sequences of numbers. +function math.randomseed(x) end + +--- +-- Returns the sine of `x` (assumed to be in radians). +function math.sin(x) end + +--- +-- Returns the hyperbolic sine of `x`. +function math.sinh(x) end + +--- +-- Returns the square root of `x`. (You can also use the expression `x^0.5` +-- to compute this value.) +function math.sqrt(x) end + +--- +-- Returns the tangent of `x` (assumed to be in radians). +function math.tan(x) end + +--- +-- Returns the hyperbolic tangent of `x`. +function math.tanh(x) end + +return math diff --git a/Data/Libraries/LDoc/ldoc/builtin/os.lua b/Data/Libraries/LDoc/ldoc/builtin/os.lua new file mode 100644 index 0000000..3243b4e --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/builtin/os.lua @@ -0,0 +1,112 @@ +--- Operating System facilities like date, time and program execution. +-- @module os + +local os = {} + +--- +-- Returns an approximation of the amount in seconds of CPU time used by +-- the program. +function os.clock() end + +--- +-- Returns a string or a table containing date and time, formatted according +-- to the given string `format`. +-- +-- If the `time` argument is present, this is the time to be formatted +-- (see the `os.time` function for a description of this value). Otherwise, +-- `date` formats the current time. +-- +-- If `format` starts with '`!`', then the date is formatted in Coordinated +-- Universal Time. After this optional character, if `format` is the string +-- "`*t`", then `date` returns a table with the following fields: +-- +-- * `year` (four digits) +-- * `month` (1--12) +-- * `day` (1--31) +-- * `hour` (0--23) +-- * `min` (0--59) +-- * `sec` (0--61) +-- * `wday` (weekday, Sunday is 1) +-- * `yday` (day of the year) +-- * `isdst` (daylight saving flag, a boolean). +-- +-- If `format` is not "`*t`", then `date` returns the date as a string, +-- formatted according to the same rules as the C function `strftime`. +-- When called without arguments, `date` returns a reasonable date and time +-- representation that depends on the host system and on the current locale +-- (that is, `os.date()` is equivalent to `os.date("%c")`). +function os.date(format , time) end + +--- +-- Returns the number of seconds from time `t1` to time `t2`. In POSIX, +-- Windows, and some other systems, this value is exactly `t2`*-*`t1`. +function os.difftime(t2, t1) end + +--- +-- This function is equivalent to the C function `system`. It passes +-- `command` to be executed by an operating system shell. It returns a status +-- code, which is system-dependent. If `command` is absent, then it returns +-- nonzero if a shell is available and zero otherwise. +function os.execute(command) end + +--- +-- Calls the C function `exit`, with an optional `code`, to terminate the +-- host program. The default value for `code` is the success code. +function os.exit(code) end + +--- +-- Returns the value of the process environment variable `varname`, or +-- nil if the variable is not defined. +function os.getenv(varname) end + +--- +-- Deletes the file or directory with the given name. Directories must be +-- empty to be removed. If this function fails, it returns nil, plus a string +-- describing the error. +function os.remove(filename) end + +--- +-- Renames file or directory named `oldname` to `newname`. If this function +-- fails, it returns nil, plus a string describing the error. +function os.rename(oldname, newname) end + +--- +-- Sets the current locale of the program. `locale` is a string specifying +-- a locale; `category` is an optional string describing which category to +-- change: `"all"`, `"collate"`, `"ctype"`, `"monetary"`, `"numeric"`, or +-- `"time"`; the default category is `"all"`. The function returns the name +-- of the new locale, or nil if the request cannot be honored. +-- If `locale` is the empty string, the current locale is set to an +-- implementation-defined native locale. If `locale` is the string "`C`", +-- the current locale is set to the standard C locale. +-- When called with nil as the first argument, this function only returns +-- the name of the current locale for the given category. +function os.setlocale(locale , category) end + +--- +-- Returns the current time when called without arguments, or a time +-- representing the date and time specified by the given table. This table +-- must have fields `year`, `month`, and `day`, and may have fields `hour`, +-- `min`, `sec`, and `isdst` (for a description of these fields, see the +-- `os.date` function). +-- The returned value is a number, whose meaning depends on your system. In +-- POSIX, Windows, and some other systems, this number counts the number +-- of seconds since some given start time (the "epoch"). In other systems, +-- the meaning is not specified, and the number returned by `time` can be +-- used only as an argument to `date` and `difftime`. +function os.time(table) end + +--- +-- Returns a string with a file name that can be used for a temporary +-- file. The file must be explicitly opened before its use and explicitly +-- removed when no longer needed. +-- On some systems (POSIX), this function also creates a file with that +-- name, to avoid security risks. (Someone else might create the file with +-- wrong permissions in the time between getting the name and creating the +-- file.) You still have to open the file to use it and to remove it (even +-- if you do not use it). +-- When possible, you may prefer to use `io.tmpfile`, which automatically +-- removes the file when the program ends. +function os.tmpname() end + +return os diff --git a/Data/Libraries/LDoc/ldoc/builtin/package.lua b/Data/Libraries/LDoc/ldoc/builtin/package.lua new file mode 100644 index 0000000..a7ff408 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/builtin/package.lua @@ -0,0 +1,97 @@ +--- controlling how `require` finds packages. +-- @module package + +local package = {} + +--- +-- The path used by `require` to search for a C loader. +-- Lua initializes the C path `package.cpath` in the same way it initializes +-- the Lua path `package.path`, using the environment variable `LUA_CPATH` +-- or a default path defined in `luaconf.h`. +-- function package.cpath end +-- * `package.cpath`: package.cpath + +--- +-- A table used by `require` to control which modules are already +-- loaded. When you require a module `modname` and `package.loaded[modname]` +-- is not false, `require` simply returns the value stored there. +-- function package.loaded end +-- * `package.loaded`: package.loaded + +--- +-- A table used by `require` to control how to load modules. +-- Each entry in this table is a *searcher function*. When looking for a module, +-- `require` calls each of these searchers in ascending order, with the module +-- name (the argument given to `require`) as its sole parameter. The function +-- can return another function (the module *loader*) or a string explaining +-- why it did not find that module (or nil if it has nothing to say). Lua +-- initializes this table with four functions. +-- The first searcher simply looks for a loader in the `package.preload` table. +-- The second searcher looks for a loader as a Lua library, using the path +-- stored at `package.path`. A path is a sequence of *templates* separated by +-- semicolons. For each template, the searcher will change each interrogation +-- mark in the template by `filename`, which is the module name with each dot +-- replaced by a "directory separator" (such as "`/`" in Unix); then it will +-- try to open the resulting file name. So, for instance, if the Lua path is +-- the string +-- "./?.lua;./?.lc;/usr/local/?/init.lua" +-- the search for a Lua file for module `foo` will try to open the files +-- `./foo.lua`, `./foo.lc`, and `/usr/local/foo/init.lua`, in that order. +-- The third searcher looks for a loader as a C library, using the path given +-- by the variable `package.cpath`. For instance, if the C path is the string +-- "./?.so;./?.dll;/usr/local/?/init.so" +-- the searcher for module `foo` will try to open the files `./foo.so`, +-- `./foo.dll`, and `/usr/local/foo/init.so`, in that order. Once it finds +-- a C library, this searcher first uses a dynamic link facility to link the +-- application with the library. Then it tries to find a C function inside the +-- library to be used as the loader. The name of this C function is the string +-- "`luaopen_`" concatenated with a copy of the module name where each dot +-- is replaced by an underscore. Moreover, if the module name has a hyphen, +-- its prefix up to (and including) the first hyphen is removed. For instance, +-- if the module name is `a.v1-b.c`, the function name will be `luaopen_b_c`. +-- The fourth searcher tries an *all-in-one loader*. It searches the C +-- path for a library for the root name of the given module. For instance, +-- when requiring `a.b.c`, it will search for a C library for `a`. If found, +-- it looks into it for an open function for the submodule; in our example, +-- that would be `luaopen_a_b_c`. With this facility, a package can pack +-- several C submodules into one single library, with each submodule keeping +-- its original open function. +-- function package.loaders end +-- * `package.loaders`: package.loaders + +--- +-- Dynamically links the host program with the C library `libname`. Inside +-- this library, looks for a function `funcname` and returns this function as a +-- C function. (So, `funcname` must follow the protocol (see `lua_CFunction`)). +-- This is a low-level function. It completely bypasses the package and module +-- system. Unlike `require`, it does not perform any path searching and does +-- not automatically adds extensions. `libname` must be the complete file name +-- of the C library, including if necessary a path and extension. `funcname` +-- must be the exact name exported by the C library (which may depend on the +-- C compiler and linker used). +-- This function is not supported by ANSI C. As such, it is only available +-- on some platforms (Windows, Linux, Mac OS X, Solaris, BSD, plus other Unix +-- systems that support the `dlfcn` standard). +function package.loadlib(libname, funcname) end + +--- +-- The path used by `require` to search for a Lua loader. +-- At start-up, Lua initializes this variable with the value of the environment +-- variable `LUA_PATH` or with a default path defined in `luaconf.h`, if +-- the environment variable is not defined. Any "`;;`" in the value of the +-- environment variable is replaced by the default path. +-- function package.path end +-- * `package.path`: package.path + +--- +-- A table to store loaders for specific modules (see `require`). +-- function package.preload end +-- * `package.preload`: package.preload + +--- +-- Sets a metatable for `module` with its `__index` field referring to the +-- global environment, so that this module inherits values from the global +-- environment. To be used as an option to function `module`. +function package.seeall(module) end + +return package diff --git a/Data/Libraries/LDoc/ldoc/builtin/string.lua b/Data/Libraries/LDoc/ldoc/builtin/string.lua new file mode 100644 index 0000000..cb4d2eb --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/builtin/string.lua @@ -0,0 +1,191 @@ +--- string operations like searching and matching. +-- @module string + +local string = {} + +--- +-- Returns the internal numerical codes of the characters `s[i]`, `s[i+1]`, +-- ..., `s[j]`. The default value for `i` is 1; the default value for `j` +-- is `i`. +-- Note that numerical codes are not necessarily portable across platforms. +function string.byte(s , i , j) end + +--- +-- Receives zero or more integers. Returns a string with length equal to +-- the number of arguments, in which each character has the internal numerical +-- code equal to its corresponding argument. +-- Note that numerical codes are not necessarily portable across platforms. +function string.char(...) end + +--- +-- Returns a string containing a binary representation of the given +-- function, so that a later `loadstring` on this string returns a copy of +-- the function. `function` must be a Lua function without upvalues. +function string.dump(func) end + +--- +-- Looks for the first match of `pattern` in the string `s`. If it finds a +-- match, then `find` returns the indices of `s` where this occurrence starts +-- and ends; otherwise, it returns nil. A third, optional numerical argument +-- `init` specifies where to start the search; its default value is 1 and +-- can be negative. A value of true as a fourth, optional argument `plain` +-- turns off the pattern matching facilities, so the function does a plain +-- "find substring" operation, with no characters in `pattern` being considered +-- "magic". Note that if `plain` is given, then `init` must be given as well. +-- If the pattern has captures, then in a successful match the captured values +-- are also returned, after the two indices. +function string.find(s, pattern , init , plain) end + +--- +-- Returns a formatted version of its variable number of arguments following +-- the description given in its first argument (which must be a string). The +-- format string follows the same rules as the `printf` family of standard C +-- functions. The only differences are that the options/modifiers `*`, `l`, +-- `L`, `n`, `p`, and `h` are not supported and that there is an extra option, +-- `q`. The `q` option formats a string in a form suitable to be safely read +-- back by the Lua interpreter: the string is written between double quotes, +-- and all double quotes, newlines, embedded zeros, and backslashes in the +-- string are correctly escaped when written. For instance, the call +-- +-- string.format('%q', 'a string with "quotes" and \n new line') +-- +-- will produce the string: +-- +-- "a string with \"quotes\" and \ +-- new line" +-- +-- The options `c`, `d`, `E`, `e`, `f`, `g`, `G`, `i`, `o`, `u`, `X`, and +-- `x` all expect a number as argument, whereas `q` and `s` expect a string. +-- This function does not accept string values containing embedded zeros, +-- except as arguments to the `q` option. +function string.format(formatstring, ...) end + +--- +-- Returns an iterator function that, each time it is called, returns the +-- next captures from `pattern` over string `s`. If `pattern` specifies no +-- captures, then the whole match is produced in each call. +-- As an example, the following loop +-- +-- s = "hello world from Lua" +-- for w in string.gmatch(s, "%a+") do +-- print(w) +-- end +-- +-- will iterate over all the words from string `s`, printing one per line. The +-- next example collects all pairs `key=value` from the given string into +-- a table: +-- +-- t = {} +-- s = "from=world, to=Lua" +-- for k, v in string.gmatch(s, "(%w+)=(%w+)") do +-- t[k] = v +-- end +-- +-- For this function, a '`^`' at the start of a pattern does not work as an +-- anchor, as this would prevent the iteration. +function string.gmatch(s, pattern) end + +--- +-- Returns a copy of `s` in which all (or the first `n`, if given) +-- occurrences of the `pattern` have been replaced by a replacement string +-- specified by `repl`, which can be a string, a table, or a function. `gsub` +-- also returns, as its second value, the total number of matches that occurred. +-- +-- If `repl` is a string, then its value is used for replacement. The character +-- `%` works as an escape character: any sequence in `repl` of the form `%n`, +-- with *n* between 1 and 9, stands for the value of the *n*-th captured +-- substring (see below). The sequence `%0` stands for the whole match. The +-- sequence `%%` stands for a single `%`. +-- +-- If `repl` is a table, then the table is queried for every match, using +-- the first capture as the key; if the pattern specifies no captures, then +-- the whole match is used as the key. +-- +-- If `repl` is a function, then this function is called every time a match +-- occurs, with all captured substrings passed as arguments, in order; if +-- the pattern specifies no captures, then the whole match is passed as a +-- sole argument. +-- +-- If the value returned by the table query or by the function call is a +-- string or a number, then it is used as the replacement string; otherwise, +-- if it is false or nil, then there is no replacement (that is, the original +-- match is kept in the string). +-- +-- Here are some examples: +-- x = string.gsub("hello world", "(%w+)", "%1 %1") +-- --> x="hello hello world world" +-- x = string.gsub("hello world", "%w+", "%0 %0", 1) +-- --> x="hello hello world" +-- x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1") +-- --> x="world hello Lua from" +-- x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv) +-- --> x="home = /home/roberto, user = roberto" +-- x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s) +-- return loadstring(s)() +-- end) +-- --> x="4+5 = 9" +-- local t = {name="lua", version="5.1"} +-- x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t) +-- --> x="lua-5.1.tar.gz" +function string.gsub(s, pattern, repl , n) end + +--- +-- Receives a string and returns its length. The empty string `""` has +-- length 0. Embedded zeros are counted, so `"a\000bc\000"` has length 5. +function string.len(s) end + +--- +-- Receives a string and returns a copy of this string with all uppercase +-- letters changed to lowercase. All other characters are left unchanged. The +-- definition of what an uppercase letter is depends on the current locale. +function string.lower(s) end + +--- +-- Looks for the first *match* of `pattern` in the string `s`. If it +-- finds one, then `match` returns the captures from the pattern; otherwise +-- it returns nil. If `pattern` specifies no captures, then the whole match +-- is returned. A third, optional numerical argument `init` specifies where +-- to start the search; its default value is 1 and can be negative. +function string.match(s, pattern , init) end + +--- +-- Returns a string that is the concatenation of `n` copies of the string +-- `s`. +function string.rep(s, n) end + +--- +-- Returns a string that is the string `s` reversed. +function string.reverse(s) end + +--- +-- Returns the substring of `s` that starts at `i` and continues until +-- `j`; `i` and `j` can be negative. If `j` is absent, then it is assumed to +-- be equal to -1 (which is the same as the string length). In particular, +-- the call `string.sub(s,1,j)` returns a prefix of `s` with length `j`, and +-- `string.sub(s, -i)` returns a suffix of `s` with length `i`. +function string.sub(s, i , j) end + +--- +-- Receives a string and returns a copy of this string with all lowercase +-- letters changed to uppercase. All other characters are left unchanged. The +-- definition of what a lowercase letter is depends on the current locale. +function string.upper(s) end + +--- +-- (5.3) Returns a binary string containing the values v1, v2, etc. packed (that is, serialized in binary form) +--- according to the format string fmt (see 6.4.2). +function string.pack (fmt, v1, v2, ...) end + +--- +-- (5.3) Returns the size of a string resulting from string.pack with the given format. +-- The format string cannot have the variable-length options 's' or 'z' (see 6.4.2). +function string.packsize (fmt) end + +--- +-- (5.3) Returns the values packed in string s (see string.pack) according to the format string fmt (see 6.4.2). +-- An optional pos marks where to start reading in s (default is 1) +-- After the read values, this function also returns the index of the first unread byte in s. +function string.unpack (fmt, s , pos) end + +return string + diff --git a/Data/Libraries/LDoc/ldoc/builtin/table.lua b/Data/Libraries/LDoc/ldoc/builtin/table.lua new file mode 100644 index 0000000..92704e7 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/builtin/table.lua @@ -0,0 +1,52 @@ +--- manipulating Lua tables. +-- @module table + +local table = {} + +--- +-- Given an array where all elements are strings or numbers, returns +-- `table[i]..sep..table[i+1] ... sep..table[j]`. The default value for +-- `sep` is the empty string, the default for `i` is 1, and the default for +-- `j` is the length of the table. If `i` is greater than `j`, returns the +-- empty string. +function table.concat(table , sep , i , j) end + +--- +-- Inserts element `value` at position `pos` in `table`, shifting up +-- other elements to open space, if necessary. The default value for `pos` is +-- `n+1`, where `n` is the length of the table (see §2.5.5), so that a call +-- `table.insert(t,x)` inserts `x` at the end of table `t`. +function table.insert(table, pos, value) end + +--- +-- Removes from `table` the element at position `pos`, shifting down other +-- elements to close the space, if necessary. Returns the value of the removed +-- element. The default value for `pos` is `n`, where `n` is the length of the +-- table, so that a call `table.remove(t)` removes the last element of table +-- `t`. +function table.remove(table , pos) end + +--- +-- Returns a new table with all parameters stored into keys 1, 2, etc. and with a field "n" with +-- the total number of parameters. Note that the resulting table may not be a sequence. +function table.pack (...) end +--- +-- Sorts table elements in a given order, +-- *in-place*, from `table[1]` to `table[n]`, where `n` is the length of the +-- table. If `comp` is given, then it must be a function that receives two +-- table elements, and returns true when the first is less than the second +-- (so that `not comp(a[i+1],a[i])` will be true after the sort). If `comp` +-- is not given, then the '<' operator will be used. +function table.sort(table , comp) end + +-- luacheck: ignore 121 + +--- +-- Returns the elements from the given table. This function is equivalent to +-- return list[i], list[i+1], ..., list[j] +-- except that the above code can be written only for a fixed number of +-- elements. By default, `i` is 1 and `j` is the length of the list, as +-- defined by the length operator (see §2.5.5). +function unpack(list , i , j) end + +return table diff --git a/Data/Libraries/LDoc/ldoc/builtin/utf8.lua b/Data/Libraries/LDoc/ldoc/builtin/utf8.lua new file mode 100644 index 0000000..ec91c4f --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/builtin/utf8.lua @@ -0,0 +1,48 @@ +--- This library provides basic support for UTF-8 encoding. +-- @module utf8 + +local utf8 = {} + +--- +-- Receives zero or more integers, converts each one to its corresponding UTF-8 byte sequence and returns +-- a string with the concatenation of all these sequences. +function utf8.char (...) end + +--- +-- The pattern "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" , which matches exactly one +-- UTF-8 byte sequence, assuming that the subject is a valid UTF-8 string. +-- @field charpattern + +--- +-- Iterate over all characters in string. +-- +-- for p, c in utf8.codes(s) do body end +-- +-- will iterate over all characters in string s, with p being the position (in bytes) and c the code point +-- of each character. It raises an error if it meets any invalid byte sequence. +function utf8.codes (s) end + +--- +-- Returns the codepoints (as integers) from all characters in s that start between byte position i and j (both included). +-- The default for i is 1 and for j is i. It raises an error if it meets any invalid byte sequence. +function utf8.codepoint (s , i , j) end + +--- +-- Returns the number of UTF-8 characters in string s that start between positions i and j (both inclusive). +-- The default for i is 1 and for j is -1. If it finds any invalid byte sequence, returns a false value plus +-- the position of the first invalid byte. +function utf8.len (s , i , j) end + +--- +-- Returns the position (in bytes) where the encoding of the n-th character of s (counting from position i) starts. +-- A negative n gets characters before position i. The default for i is 1 when n is non-negative +-- and #s + 1 otherwise, so that utf8.offset(s, -n) gets the offset of the n-th character from the end +-- of the string. +-- If the specified character is neither in the subject nor right after its end, the function returns nil. +-- +-- As a special case, when n is 0 the function returns the start of the encoding of the character that contains the i-th byte of s. +-- +-- This function assumes that s is a valid UTF-8 string. +function utf8.offset (s, n , i) end + +return utf8 diff --git a/Data/Libraries/LDoc/ldoc/config.ld b/Data/Libraries/LDoc/ldoc/config.ld new file mode 100644 index 0000000..9c220ba --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/config.ld @@ -0,0 +1,11 @@ +project = 'Lua' +description = 'Lua Standard Libraries' +full_description = [[ +These are the built-in libraries of Lua 5.1 + +Plus documentation for lpeg and luafilesystem. +]] +file = {'builtin',exclude = {'builtin/globals.lua'}} +no_summary = true +no_return_or_parms = true +format = 'discount' diff --git a/Data/Libraries/LDoc/ldoc/doc.lua b/Data/Libraries/LDoc/ldoc/doc.lua new file mode 100644 index 0000000..c4908c9 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/doc.lua @@ -0,0 +1,1350 @@ +------ +-- Defining the ldoc document model. + + +local class = require 'pl.class' +local utils = require 'pl.utils' +local List = require 'pl.List' +local Map = require 'pl.Map' +local text = require 'pl.text' + +local doc = {} +local global = require 'ldoc.builtin.globals' +local tools = require 'ldoc.tools' +local split_dotted_name = tools.split_dotted_name + +local TAG_MULTI,TAG_ID,TAG_SINGLE,TAG_TYPE,TAG_FLAG,TAG_MULTI_LINE = 'M','id','S','T','N','ML' + +-- these are the basic tags known to ldoc. They come in several varieties: +-- - 'M' tags with multiple values like 'param' (TAG_MULTI) +-- - 'ML' tags which have a single multi-lined value like 'usage' (TAG_MULTI_LINE) +-- - 'id' tags which are identifiers, like 'name' (TAG_ID) +-- - 'S' tags with a single value, like 'release' (TAG_SINGLE) +-- - 'N' tags which have no associated value, like 'local` (TAG_FLAG) +-- - 'T' tags which represent a type, like 'function' (TAG_TYPE) +local known_tags = { + param = 'M', see = 'M', comment = 'M', usage = 'ML', ['return'] = 'M', field = 'M', author='M',set='M'; + class = 'id', name = 'id', pragma = 'id', alias = 'id', + copyright = 'S', summary = 'S', description = 'S', release = 'S', license = 'S', + fixme = 'S', todo = 'S', warning = 'S', raise = 'S', charset = 'S', within = 'S', + ['local'] = 'N', export = 'N', private = 'N', constructor = 'N', static = 'N',include = 'S', + -- project-level + module = 'T', script = 'T', example = 'T', topic = 'T', submodule='T', classmod='T', file='T', + -- module-level + ['function'] = 'T', lfunction = 'T', table = 'T', section = 'T', type = 'T', + annotation = 'T', factory = 'T'; + +} +known_tags._alias = {} +known_tags._project_level = { + module = true, + script = true, + example = true, + topic = true, + submodule = true, + classmod = true, + file = true, +} + +known_tags._code_types = { + module = true, + script = true, + classmod = true, +} + +known_tags._presentation_names = { + classmod = 'Class', +} + +known_tags._module_info = { + 'copyright','release','license','author' +} + +local see_reference_handlers = {} + + +doc.TAG_MULTI,doc.TAG_ID,doc.TAG_SINGLE,doc.TAG_TYPE,doc.TAG_FLAG = + TAG_MULTI,TAG_ID,TAG_SINGLE,TAG_TYPE,TAG_FLAG + +-- add a new tag. +function doc.add_tag(tag,type,project_level) + if not known_tags[tag] then + known_tags[tag] = type + known_tags._project_level[tag] = project_level + end +end + +function doc.add_custom_see_handler(pat,action) + see_reference_handlers[pat] = action +end + +-- add an alias to an existing tag (exposed through ldoc API) +function doc.add_alias (a,tag) + known_tags._alias[a] = tag +end + +-- get the tag alias value, if it exists. +function doc.get_alias(tag) + return known_tags._alias[tag] +end + +-- is it a'project level' tag, such as 'module' or 'script'? +function doc.project_level(tag) + return known_tags._project_level[tag] +end + +-- is it a project level tag containing code? +function doc.code_tag (tag) + return known_tags._code_types[tag] +end + +-- is it a section tag? +function doc.section_tag (tag) + return tag == 'section' or doc.class_tag(tag) +end + +-- is it a class tag, like 'type' or 'factory'? +function doc.class_tag (tag) + return tag == 'type' or tag == 'factory' +end + +-- how the type wants to be formally presented; e.g. 'module' becomes 'Module' +-- but 'classmod' will become 'Class' +function doc.presentation_name (tag) + local name = known_tags._presentation_names[tag] + if not name then + name = tag:gsub('(%a)(%a*)',function(f,r) + return f:upper()..r + end) + end + return name +end + +function doc.module_info_tags () + return List.iter(known_tags._module_info) +end + +-- annotation tags can appear anywhere in the code and may contain any of these tags: +known_tags._annotation_tags = { + fixme = true, todo = true, warning = true +} + +local acount = 1 + +function doc.expand_annotation_item (tags, last_item) + if tags.summary ~= '' or last_item == nil then return false end + local item_name = last_item.tags.name + for tag, value in pairs(tags) do + if known_tags._annotation_tags[tag] then + tags.summary = nil + tags:add('class','annotation') + tags:add('summary',value) + tags:add('name',item_name..'-'..tag..acount) + acount = acount + 1 + return true + elseif tags.error and tag == 'return' then + last_item:set_tag(tag,value) + end + end + return false +end + +-- we process each file, resulting in a File object, which has a list of Item objects. +-- Items can be modules, scripts ('project level') or functions, tables, etc. +-- (In the code 'module' refers to any project level tag.) +-- When the File object is finalized, we specialize some items as modules which +-- are 'container' types containing functions and tables, etc. + +local File = class() +local Item = class() +local Module = class(Item) -- a specialized kind of Item + +doc.File = File +doc.Item = Item +doc.Module = Module + +function File:_init(filename) + self.filename = filename + self.items = List() + self.modules = List() + self.sections = List() +end + +function File:new_item(tags,line) + local item = Item(tags,self,line or 1) + self.items:append(item) + return item +end + +function File:export_item (name) + for item in self.items:iter() do + local tags = item.tags + if tags.name == name then + tags.export = true + if tags['local'] then + tags['local'] = nil + end + return + end + end + -- warn if any of these guys are not found, indicating no + -- documentation was given. + self:warning('no docs '..tools.quote(name)) +end + +local function mod_section_type (this_mod) + return this_mod and this_mod.section and this_mod.section.type +end + +function File:find_module_in_files (name) + for f in File.list:iter() do + for m in f.modules:iter() do + if m.name == name then + return m,f.filename + end + end + end +end + +local function init_within_section (mod,name) + mod.kinds:add_kind(name, name) + mod.enclosing_section = mod.section + mod.section = nil + return name +end + +function File:finish() + local this_mod + local items = self.items + local tagged_inside + self.args = self.args or {} + for item in items:iter() do + if mod_section_type(this_mod) == 'factory' and item.tags then + local klass = '@{'..this_mod.section.name..'}' + -- Factory constructors return the object type, and methods all have implicit self argument + if item.tags.constructor and not item.tags['return'] then + item.tags['return'] = List{klass} + elseif item.tags.param then + item.tags.param:put('self '..klass) + end + end + item:finish() + -- the default is not to show local functions in the documentation. + -- luacheck: push ignore 542 + if not self.args.all and (item.type=='lfunction' or (item.tags and item.tags['local'])) then + -- don't add to the module -- + elseif doc.project_level(item.type) then + this_mod = item + local package,mname,submodule + if item.type == 'module' or item.type == 'classmod' then + -- if name is 'package.mod', then mod_name is 'mod' + package,mname = split_dotted_name(this_mod.name) + if self.args.merge then + local mod,mf = self:find_module_in_files(item.name) + if mod then + print('found master module',mf) + this_mod = mod + if this_mod.section then + print '***closing section from master module***' + this_mod.section = nil + end + submodule = true + end + end + elseif item.type == 'submodule' then + local _ + submodule = true + this_mod,_ = self:find_module_in_files(item.name) + if this_mod == nil then + self:error("'"..item.name.."' not found for submodule") + end + tagged_inside = tools.this_module_name(self.base,self.filename)..' Functions' + this_mod.kinds:add_kind(tagged_inside, tagged_inside) + end + if not package then + mname = this_mod.name + package = '' + end + if not submodule then + this_mod.package = package + this_mod.mod_name = mname + this_mod.kinds = doc.ModuleMap() -- the iterator over the module contents + self.modules:append(this_mod) + end + elseif doc.section_tag(item.type) then + local display_name = item.name + if display_name == 'end' then + this_mod.section = nil + else + local summary = item.summary:gsub('%.$','') + local lookup_name + if doc.class_tag(item.type) then + display_name = 'Class '..item.name + lookup_name = item.name + item.module = this_mod + this_mod.items.by_name[item.name] = item + else + display_name = summary + lookup_name = summary + item.summary = '' + end + item.display_name = display_name + this_mod.section = item + -- the purpose of this little hack is to properly distinguish + -- between built-in kinds and any user-defined kinds. + this_mod.kinds:add_kind(display_name,display_name..' ',nil,item) + this_mod.sections:append(item) + this_mod.sections.by_name[lookup_name:gsub('%A','_')] = item + end + else + local to_be_removed + -- add the item to the module's item list + if this_mod then + -- new-style modules will have qualified names like 'mod.foo' + if item.name == nil then + self:error("item's name is nil") + end + local mod,fname = split_dotted_name(item.name) + -- warning for inferred unqualified names in new style modules + -- (retired until we handle methods like Set:unset() properly) + if not mod and not this_mod.old_style and item.inferred then + --item:warning(item.name .. ' is declared in global scope') + end + -- the function may be qualified with a module alias... + local alias = this_mod.tags.alias + if (alias and mod == alias) or mod == 'M' or mod == '_M' then + mod = this_mod.mod_name + end + -- if that's the mod_name, then we want to only use 'foo' + if mod == this_mod.mod_name and this_mod.tags.pragma ~= 'nostrip' then + item.name = fname + end + + if tagged_inside then + item.tags.within = tagged_inside + end + if item.tags.within then + init_within_section(this_mod,item.tags.within) + end + + -- right, this item was within a section or a 'class' + local section_description + local classmod = this_mod.type == 'classmod' + if this_mod.section or classmod then + local stype + local this_section = this_mod.section + if this_section then + item.section = this_section.display_name + stype = this_section.type + end + -- if it was a class, then if the name is unqualified then it becomes + -- 'Class:foo' (unless flagged as being a constructor, static or not a function) + if doc.class_tag(stype) or classmod then + if not item.name:match '[:%.]' then -- not qualified name! + -- a class is either a @type section or a @classmod module. Is this a _method_? + local class = classmod and this_mod.name or this_section.name + local static = item.tags.constructor or item.tags.static or item.type ~= 'function' + -- methods and metamethods go into their own special sections... + if classmod and item.type == 'function' then + local inferred_section + if item.name:match '^__' then + inferred_section = 'Metamethods' + elseif not static then + inferred_section = 'Methods' + end + if inferred_section then + item.tags.within = init_within_section(this_mod,inferred_section) + end + end + -- Whether to use '.' or the language's version of ':' (e.g. \ for Moonscript) + item.name = class..(not static and this_mod.file.lang.method_call or '.')..item.name + end + if stype == 'factory' then + if item.tags.private then to_be_removed = true + elseif item.type == 'lfunction' then + item.type = 'function' + end + if item.tags.constructor then + item.section = item.type + end + end + end + if this_section then + --section_description = this_section.summary..' '..(this_section.description or '') + --this_section.summary = '' + elseif item.tags.within then + item.section = item.tags.within + else + if item.type == 'function' or item.type == 'lfunction' then + section_description = "Methods" + end + item.section = item.type + end + elseif item.tags.within then -- ad-hoc section... + item.section = item.tags.within + else -- otherwise, just goes into the default sections (Functions,Tables,etc) + item.section = item.type; + end + + item.module = this_mod + if not to_be_removed then + local these_items = this_mod.items + these_items.by_name[item.name] = item + these_items:append(item) + this_mod.kinds:add(item,these_items,section_description) + end + + -- restore current section after a 'within' + if this_mod.enclosing_section then + this_mod.section = this_mod.enclosing_section + this_mod.enclosing_section = nil + end + + else + -- must be a free-standing function (sometimes a problem...) + end + end + -- luacheck: pop + item.names_hierarchy = require('pl.utils').split( + item.name, + '[.:]' + ) + end +end + +-- some serious hackery. We force sections into this 'module', +-- and ensure that there is a dummy item so that the section +-- is not empty. + +function File:add_document_section(title) + local section = title:gsub('%W','_') + self:new_item { + name = section, + class = 'section', + summary = title + } + self:new_item { + name = 'dumbo', + class = 'function', + } + return section +end + +function Item:_init(tags,file,line) + self.file = file + self.lineno = line + self.summary = tags.summary + self.description = tags.description + tags.summary = nil + tags.description = nil + self.tags = {} + self.formal_args = tags.formal_args + tags.formal_args = nil + local iter = tags.iter or Map.iter + for tag in iter(tags) do + self:set_tag(tag,tags[tag]) + end +end + +function Item:add_to_description (rest) + if type(rest) == 'string' then + self.description = (self.description or '') .. rest + end +end + +function Item:trailing_warning (kind,tag,rest) + if type(rest)=='string' and #rest > 0 then + Item.warning(self,kind.." tag: '"..tag..'" has trailing text ; use not_luadoc=true if you want description to continue between tags\n"'..rest..'"') + end +end + +local function is_list (l) + return getmetatable(l) == List +end + +function Item:set_tag (tag,value) + local ttype = known_tags[tag] + local args = self.file.args + + if ttype == TAG_MULTI or ttype == TAG_MULTI_LINE then -- value is always a List! + local ovalue = self.tags[tag] + if ovalue then -- already defined, must be a list + --print(tag,ovalue,value) + if is_list(value) then + ovalue:extend(value) + else + ovalue:append(value) + end + value = ovalue + end + -- these multiple values are always represented as lists + if not is_list(value) then + value = List{value} + end + if ttype ~= TAG_MULTI_LINE and args and args.not_luadoc then + local last = value[#value] + if type(last) == 'string' and last:match '\n' then + local line,rest = last:match('([^\n]+)(.*)') + value[#value] = line + self:add_to_description(rest) + end + end + self.tags[tag] = value + elseif ttype == TAG_ID then + if type(value) == 'table' then + if value.append then -- it was a List! + -- such tags are _not_ multiple, e.g. name + if tag == 'class' and value:contains 'example' then + self:error("cannot use 'example' tag for functions or tables. Use 'usage'") + else + self:error("'"..tag.."' cannot have multiple values; "..tostring(value)) + end + end + value = value[1] + end + if value == nil then self:error("Tag without value: "..tag) end + local id, rest = tools.extract_identifier(value) + self.tags[tag] = id + if args and args.not_luadoc then + self:add_to_description(rest) + else + self:trailing_warning('id',tag,rest) + end + elseif ttype == TAG_SINGLE then + self.tags[tag] = value + elseif ttype == TAG_FLAG then + self.tags[tag] = true + if args.not_luadoc then + self:add_to_description(value) + else + self:trailing_warning('flag',tag,value) + end + else + Item.warning(self,"unknown tag: '"..tag.."' "..tostring(ttype)) + end +end + +-- preliminary processing of tags. We check for any aliases, and for tags +-- which represent types. This implements the shortcut notation. +function Item.check_tag(tags,tag, value, modifiers) + local alias = doc.get_alias(tag) + if alias then + if type(alias) == 'string' then + tag = alias + elseif type(alias) == 'table' then --{ tag, value=, modifiers = } + local avalue,amod + tag, avalue, amod = alias[1],alias.value,alias.modifiers + if avalue then value = avalue..' '..value end + if amod then + modifiers = modifiers or {} + for m,v in pairs(amod) do + local idx = tonumber(v:match('^%$(%d+)')) + if idx then + v, value = value:match('(%S+)(.*)') + end + modifiers[m] = v + end + end + else -- has to be a function that at least returns tag, value + return alias(tags,value,modifiers) + end + end + local ttype = known_tags[tag] + if ttype == TAG_TYPE then + tags:add('class',tag) + tag = 'name' + end + return tag, value, modifiers +end + +-- any tag (except name and classs) may have associated modifiers, +-- in the form @tag[m1,...] where m1 is either name1=value1 or name1. +-- At this stage, these are encoded +-- in the tag value table and need to be extracted. + +local function extract_value_modifier (p) + if type(p)~='table' then + return p, { } + else + return p[1], p.modifiers or { } + end +end + +local function extract_tag_modifiers (tags) + local modifiers, mods = {} + for tag, value in pairs(tags) do + if type(value)=='table' and value.append then -- i.e. it is a List! + local tmods = {} + for i, v in ipairs(value) do + v, mods = extract_value_modifier(v) + tmods[i] = mods + value[i] = v + end + modifiers[tag] = tmods + else + value, mods = extract_value_modifier(value) + modifiers[tag] = mods + tags[tag] = value + end + end + return modifiers +end + +local function read_del (tags,name) + local ret = tags[name] + tags[name] = nil + return ret +end + +local build_arg_list, split_iden -- forward declaration + +function Item:split_param (line) + local name, comment = line:match('%s*([%w_%.:]+)(.*)') + if not name then + self:error("bad param name format '"..line.."'. Are you missing a parameter name?") + end + return name, comment +end + +function Item:finish() + local tags = self.tags + local quote = tools.quote + self.name = read_del(tags,'name') + self.type = read_del(tags,'class') + self.modifiers = extract_tag_modifiers(tags) + self.usage = read_del(tags,'usage') + tags.see = read_del(tags,'see') + if tags.see then + tags.see = tools.identifier_list(tags.see) + end + if self.usage then + for i = 1,#self.usage do + local usage = self.usage[i]:gsub('^%s*\n','') + self.usage[i] = text.dedent(usage) + end + end + if doc.project_level(self.type) then + -- we are a module, so become one! + self.items = List() + self.sections = List() + self.items.by_name = {} + self.sections.by_name = {} + setmetatable(self,Module) + elseif not doc.section_tag(self.type) then + -- params are either a function's arguments, or a table's fields, etc. + if self.type == 'function' then + self.parameter = 'param' + self.ret = read_del(tags,'return') + self.raise = read_del(tags,'raise') + if tags['local'] then + self.type = 'lfunction' + end + else + self.parameter = 'field' + end + local field = self.parameter + local params = read_del(tags,field) + -- use of macros like @string (which is short for '@tparam string') + -- can lead to param tags associated with a table. + if self.parameter == 'field' and tags.param then + local tparams = read_del(tags,'param') + if params then + params:extend(tparams) + List(self.modifiers.field):extend(self.modifiers.param) + else + params = tparams + self.modifiers.field = self.modifiers.param + end + end + local param_names, comments = List(), List() + if params then + for line in params:iter() do + local name, comment = self:split_param(line) + param_names:append(name) + comments:append(comment) + end + end + self.modifiers['return'] = self.modifiers['return'] or List() + self.modifiers[field] = self.modifiers[field] or List() + -- we use the formal arguments (if available) as the authoritative list. + -- If there are both params and formal args, then they must match; + -- (A formal argument of ... may match any number of params at the end, however.) + -- If there are formal args and no params, we see if the args have any suitable comments. + -- Params may have subfields. + local fargs, formal = self.formal_args + if fargs then + if #param_names == 0 then + --docs may be embedded in argument comments; in either case, use formal arg names + local ret + formal,comments,ret = self:parse_formal_arguments(fargs) + if ret and not self.ret then self.ret = ret end + elseif #fargs > 0 then -- consistency check! + local varargs = fargs[#fargs] == '...' + if varargs then table.remove(fargs) end + if tags.export then + if fargs[1] == 'self' then + table.remove(fargs,1) + else + tags.static = true + end + end + local k = 0 + for _,pname in ipairs(param_names) do + local _,field = split_iden(pname) + if not field then + k = k + 1 + if k > #fargs then + if not varargs then + self:warning("extra param with no formal argument: "..quote(pname)) + end + elseif pname ~= fargs[k] then + self:warning("param and formal argument name mismatch: "..quote(pname).." "..quote(fargs[k])) + end + end + end + if k < #fargs then + for i = k+1,#fargs do if fargs[i] ~= '...' then + self:warning("undocumented formal argument: "..quote(fargs[i])) + end end + end + end -- #fargs > 0 + -- formal arguments may come with types, inferred by the + -- appropriate code in ldoc.lang + if fargs.types then + self.modifiers[field] = List() + for t in fargs.types:iter() do + self:add_type(field,t) + end + if fargs.return_type then + if not self.ret then -- type, but no comment; no worries + self.ret = List{''} + end + self.modifiers['return'] = List() + self:add_type('return',fargs.return_type) + end + end + end -- fargs + + -- the comments are associated with each parameter by + -- adding name-value pairs to the params list (this is + -- also done for any associated modifiers) + -- (At this point we patch up any subparameter references) + local pmods = self.modifiers[field] + local params, fields = List() + local original_names = formal and formal or param_names + local names = List() + self.subparams = {} + params.map = {} + + for i,name in ipairs(original_names) do + if type(name) ~= 'string' then + self:error("declared table cannot have array entries") + end + local pname,field = split_iden(name) + if field then + if not fields then + fields = List() + self.subparams[pname] = fields + end + fields:append(name) + else + names:append(name) + params:append(name) + fields = nil + end + + params.map[name] = comments[i] + if pmods then + pmods[name] = pmods[i] + end + end + self.params = params + self.args = build_arg_list (names,pmods) + end + if self.ret then + self:build_return_groups() + end +end + +function Item:add_type(field,type) + self.modifiers[field]:append {type = type} +end + +-- ldoc allows comments in the formal arg list to be used, if they aren't specified with @param +-- Further, these comments may start with a type followed by a colon, and are then equivalent +-- to a @tparam +function Item:parse_argument_comment (comment,field) + if comment then + comment = comment:gsub('^%-+%s*','') + local type,rest = comment:match '([^:]+):(.*)' + if type then + self:add_type(field,type) + comment = rest + end + end + return comment or '' +end + +function Item:parse_formal_arguments (fargs) + local formal, comments, ret = List(), List() + if fargs.return_comment then + local retc = self:parse_argument_comment(fargs.return_comment,'return') + ret = List{retc} + end + for i, name in ipairs(fargs) do + formal:append(name) + comments:append(self:parse_argument_comment(fargs.comments[name],self.parameter)) + end + return formal, comments, ret +end + +function split_iden (name) + if name == '...' then return name end + local pname,field = name:match('(.-)%.(.+)') + if not pname then + return name + else + return pname,field + end +end + +function build_arg_list (names,pmods) + -- build up the string representation of the argument list, + -- using any opt and optchain modifiers if present. + -- For instance, '(a [, b])' if b is marked as optional + -- with @param[opt] b + local buffer, npending = { }, 0 + local function acc(x) table.insert(buffer, x) end + -- a number of trailing [opt]s will be usually converted to [opt],[optchain],... + -- *unless* a person uses convert_opt. + if pmods and not doc.ldoc.convert_opt then + local m = pmods[#names] + if m and m.opt then + m.optchain = m.opt + for i = #names-1,1,-1 do + m = pmods[i] + if not m or not m.opt then break end + m.optchain = m.opt + end + end + end + for i = 1, #names do + local m = pmods and pmods[i] + local opt + if m then + if not m.optchain then + acc ((']'):rep(npending)) + npending=0 + end + opt = m.optchain or m.opt + if opt then + acc('[') + npending=npending+1 + end + end + if i>1 then acc (', ') end + acc(names[i]) + if opt and opt ~= true then acc('='..opt) end + end + acc ((']'):rep(npending)) + return '('..table.concat(buffer)..')' +end + +------ retrieving information about parameters ----- +-- The template leans on these guys heavily.... + +function Item:param_modifiers (p) + local mods = self.modifiers[self.parameter] + if not mods then return '' end + return rawget(mods,p) +end + +function Item:type_of_param(p) + local mparam = self:param_modifiers(p) + return mparam and mparam.type or '' +end + +-- default value for param; if optional but no default, it's just `true`. +function Item:default_of_param(p) + local m = self:param_modifiers(p) + if not m then return nil end + local opt = m.optchain or m.opt + return opt +end + +function Item:readonly(p) + local m = self:param_modifiers(p) + if not m then return nil end + return m.readonly +end + +function Item:subparam(p) + local subp = rawget(self.subparams,p) + if subp then + return subp,p + else + return {p},nil + end +end + +function Item:display_name_of(p) + local pname,field = split_iden(p) + if field then + return field + else + return pname + end +end + +-------- return values and types ------- + +function Item:type_of_ret(idx) + local rparam = self.modifiers['return'][idx] + return rparam and rparam.type or '' +end + +local function integer_keys(t) + if type(t) ~= 'table' then return 0 end + for k in pairs(t) do + local num = tonumber(k) + if num then return num end + end + return 0 +end + +function Item:return_type(r) + if not r.type then return '' end + return r.type, r.ctypes +end + +function Item:build_return_groups() + local quote = tools.quote + local modifiers = self.modifiers + local retmod = modifiers['return'] + local groups = List() + local lastg, group + for i,ret in ipairs(self.ret) do + local mods = retmod[i] + local g = integer_keys(mods) + if g ~= lastg then + group = List() + group.g = g + groups:append(group) + lastg = g + end + --require 'pl.pretty'.dump(ret) + if not mods then + self:error(quote(self.name)..' had no return?') + end + group:append({text=ret, type = mods and (mods.type or '') or '',mods = mods}) + end + -- order by groups to force error groups to the end + table.sort(groups,function(g1,g2) return g1.g < g2.g end) + self.retgroups = groups + --require 'pl.pretty'.dump(groups) + -- cool, now see if there are any treturns that have tfields to associate with + local fields = self.tags.field + if fields then + local fcomments = List() + for i,f in ipairs(fields) do + local name, comment = self:split_param(f) + fields[i] = name + fcomments[i] = comment + end + local fmods = modifiers.field + for group in groups:iter() do for r in group:iter() do + if r.mods and r.mods.type then + local ctypes, T = List(), r.mods.type + for i,f in ipairs(fields) do if fmods[i][T] then + ctypes:append {name=f,type=fmods[i].type,comment=fcomments[i]} + end end + r.ctypes = ctypes + --require 'pl.pretty'.dump(ctypes) + end + end end + end +end + +local ecount = 0 + +-- this alias macro implements @error. +-- Alias macros need to return the same results as Item:check_tags... +function doc.error_macro(tags,value,modifiers) + local merge_groups = doc.ldoc.merge_error_groups + local g = '2' -- our default group id + -- Were we given an explicit group modifier? + local key = integer_keys(modifiers) + if key > 0 then + g = tostring(key) + else + local l = tags:get 'return' + if l then -- there were returns already...... + -- maximum group of _existing_ error return + local grp, lastr = 0 + for r in l:iter() do if type(r) == 'table' then + local rg = r.modifiers._err + if rg then + lastr = r + grp = math.max(grp,rg) + end + end end + if grp > 0 then -- cool, create new group + if not merge_groups then + g = tostring(grp+1) + else + local mods, text, T = lastr.modifiers + local new = function(text) + return mods._collected..' '..text,{type='string',[T]=true} + end + if not mods._collected then + text = lastr[1] + lastr[1] = merge_groups + T = '@'..ecount + mods.type = T + mods._collected = 1 + ecount = ecount + 1 + tags:add('field',new(text)) + else + T = mods.type + end + mods._collected = mods._collected + 1 + return 'field',new(value) + end + end + end + end + tags:add('return','',{[g]=true,type='nil'}) + -- note that this 'return' is tagged with _err! + return 'return', value, {[g]=true,_err=tonumber(g),type='string'} +end + +---------- bothering the user -------------------- + +function Item:warning(msg) + local file = self.file and self.file.filename + if type(file) == 'table' then require 'pl.pretty'.dump(file); file = '?' end + file = file or '?' + io.stderr:write(file,':',self.lineno or '1',': ',self.name or '?',': ',msg,'\n') + Item.had_warning = true + return nil +end + +function Item:error(msg) + self:warning(msg) + os.exit(1) +end + +Module.warning, Module.error = Item.warning, Item.error + +-------- Resolving References ----------------- + +function Module:hunt_for_reference (packmod, modules) + local mod_ref + local package = self.package or '' + repeat -- same package? + local nmod = package..'.'..packmod + mod_ref = modules.by_name[nmod] + if mod_ref then break end -- cool + package = split_dotted_name(package) + until not package + return mod_ref +end + +local function custom_see_references (s) + for pat, action in pairs(see_reference_handlers) do + if s:match(pat) then + local label, href = action(s:match(pat)) + if not label then print('custom rule failed',s,pat,href) end + return {href = href, label = label} + end + end +end + +local function reference (s, mod_ref, item_ref) + local name = item_ref and item_ref.name or '' + -- this is deeply hacky; classes have 'Class ' prepended. +--~ if item_ref and doc.class_tag(item_ref.type) then +--~ name = 'Class_'..name +--~ end + return {mod = mod_ref, name = name, label=s} +end + +function Module:lookup_class_item (packmod, s) + local klass = packmod --"Class_"..packmod + local qs = klass..':'..s + local klass_section = self.sections.by_name[klass] + if not klass_section then return nil end -- no such class + for item in self.items:iter() do + --print('item',qs,item.name) + if s == item.name or qs == item.name then + return reference(s,self,item) + end + end + return nil +end + +function Module:process_see_reference (s,modules,istype) + if s == nil then return nil end + local fun_ref + local ref = custom_see_references(s) + if ref then return ref end + if not s:match '^[%w_%.\\%:%-]+$' or not s:match '[%w_]$' then + return nil, "malformed see reference: '"..s..'"' + end + + -- `istype` means that we are looking up strictly in a _type_ context, so then only + -- allow `classmod` module references. + local function ismod(item) + if item == nil then return false end + if not istype then return true + else + return item.type == 'classmod' + end + end + + -- it is _entirely_ possible that someone does not want auto references for standard Lua libraries! + local lua_manual_ref + local ldoc = tools.item_ldoc(self) + if ldoc and ldoc.no_lua_ref then + lua_manual_ref = function(s) return false end + else + lua_manual_ref = global.lua_manual_ref + end + -- pure C projects use global lookup (no namespaces) + if ldoc and ldoc.global_lookup == nil then + local using_c = ldoc.parse_extra and ldoc.parse_extra.C + ldoc.global_lookup = using_c or false + end + + -- is this a fully qualified module name? + local mod_ref = modules.by_name[s] + if ismod(mod_ref) then return reference(s, mod_ref,nil) end + -- module reference? + mod_ref = self:hunt_for_reference(s, modules) + if ismod(mod_ref) then return mod_ref end + -- method reference? (These are of form CLASS.NAME) + fun_ref = self.items.by_name[s] + if fun_ref then return reference(s,self,fun_ref) end + -- otherwise, start splitting! + local packmod,name = split_dotted_name(s) -- e.g. 'pl.utils','split' + if packmod then -- qualified name + mod_ref = modules.by_name[packmod] -- fully qualified mod name? + if not mod_ref then + mod_ref = self:hunt_for_reference(packmod, modules) + if not mod_ref then + local ref = self:lookup_class_item(packmod,s) + if ref then return ref end + local mod, klass = split_dotted_name(packmod) + mod_ref = modules.by_name[mod] + if mod_ref then + ref = mod_ref:lookup_class_item(klass,name) + if ref then return ref end + end + ref = lua_manual_ref(s) + if ref then return ref end + return nil,"module not found: "..packmod + end + end + fun_ref = mod_ref:get_fun_ref(name) + if fun_ref then + return reference(s,mod_ref,fun_ref) + else + fun_ref = mod_ref.sections.by_name[name] + if not fun_ref then + return nil,"function or section not found: "..s.." in "..mod_ref.name + else + return reference(fun_ref.name:gsub('_',' '),mod_ref,fun_ref) + end + end + else -- plain jane name; module in this package, function in this module + if ldoc and ldoc.global_lookup then + for m in modules:iter() do + fun_ref = m:get_fun_ref(s) + if fun_ref then return reference(s,m,fun_ref) end + end + return nil,"function: "..s.." not found globally" + end + mod_ref = modules.by_name[self.package..'.'..s] + if ismod(mod_ref) then return reference(s, mod_ref,nil) end + + fun_ref = self.items.by_name[self.name..'.'..s] + if fun_ref then return reference(self.name..'.'..s,self,fun_ref) end + + fun_ref = self:get_fun_ref(s) + if fun_ref then return reference(s,self,fun_ref) + else + local ref = lua_manual_ref (s) + if ref then return ref end + return nil, "function not found: "..s.." in this module" + end + end +end + +function Module:get_fun_ref(s) + local fun_ref = self.items.by_name[s] + -- did not get an exact match, so try to match by the unqualified fun name + if not fun_ref then + local patt = '[.:]'..s..'$' + for qname,ref in pairs(self.items.by_name) do + if qname:match(patt) then + fun_ref = ref + break + end + end + end + return fun_ref +end + + +-- resolving @see references. A word may be either a function in this module, +-- or a module in this package. A MOD.NAME reference is within this package. +-- Otherwise, the full qualified name must be used. +-- First, check whether it is already a fully qualified module name. +-- Then split it and see if the module part is a qualified module +-- and try look up the name part in that module. +-- If this isn't successful then try prepending the current package to the reference, +-- and try to to resolve this. +function Module:resolve_references(modules) + local found = List() + -- Resolve see references in item. Can be Module or Item type. + local function resolve_item_references(item) + local see = item.tags.see + if see then -- this guy has @see references + item.see = List() + for s in see:iter() do + local href, err = self:process_see_reference(s,modules) + if href then + item.see:append (href) + found:append{item,s} + elseif err then + item:warning(err) + end + end + end + end + + resolve_item_references(self); -- Resolve module-level see references. + for item in self.items:iter() do + resolve_item_references(item); -- Resolve item-level see references. + end + -- mark as found, so we don't waste time re-searching + for f in found:iter() do + f[1].tags.see:remove_value(f[2]) + end +end + +function Item:dump_tags (taglist) + for tag, value in pairs(self.tags) do + if not taglist or taglist[tag] then + Item.warning(self,tag..' '..tostring(value)) + end + end +end + +function Module:dump_tags (taglist) + Item.dump_tags(self,taglist) + for item in self.items:iter() do + item:dump_tags(taglist) + end +end + +--------- dumping out modules and items ------------- + +local function dump_tags (tags) + if next(tags) then + print 'tags:' + for tag, value in pairs(tags) do + print('\t',tag,value) + end + end +end + +-- ANSI colour codes for making important stuff BOLD +-- (but not on Windows) +local bold,default = '\x1B[1m','\x1B[0m' +if utils.dir_separator == '\\' then + bold,default = '','' +end + +function Module:dump(verbose) + if not doc.project_level(self.type) then return end + print '----' + print(self.type..':',bold..self.name,self.summary..default) + if self.description then print(self.description) end + dump_tags (self.tags) + for item in self.items:iter() do + item:dump(verbose) + end +end + +-- make a text dump of the contents of this File object. +-- The level of detail is controlled by the 'verbose' parameter. +-- Primarily intended as a debugging tool. +function File:dump(verbose) + for mod in self.modules:iter() do + mod:dump(verbose) + end +end + +function Item:dump(verbose) + local name = self.name + if self.type == 'function' then + name = name .. self.args + end + if verbose then + print() + io.write(bold) + print(self.type,name) + io.write(default) + print(self.summary) + if self.description and self.description:match '%S' then + print 'description:' + print(self.description) + end + if self.params and #self.params > 0 then + print 'parameters:' + for _,p in ipairs(self.params) do + print('',p,self.params.map[p]) + end + end + if self.ret and #self.ret > 0 then + print 'returns:' + for _,r in ipairs(self.ret) do + print('',r) + end + end + dump_tags(self.tags) + else + print('* '..bold..name..default..' - '..self.summary) + end +end + +function doc.filter_objects_through_function(filter, module_list) + local quit, quote = utils.quit, tools.quote + if filter == 'dump' then filter = 'pl.pretty.dump' end + local mod,name = tools.split_dotted_name(filter) + local ok,P = pcall(require,mod) + if not ok then quit("cannot find module "..quote(mod)) end + local ok,f = pcall(function() return P[name] end) + if not ok or type(f) ~= 'function' then quit("dump module: no function "..quote(name)) end + + -- clean up some redundant and cyclical references-- + module_list.by_name = nil + for mod in module_list:iter() do + mod.kinds = nil + mod.file = mod.file.filename + for item in mod.items:iter() do + item.module = nil + item.file = nil + item.formal_args = nil + item.tags['return'] = nil + item.see = nil + end + mod.items.by_name = nil + end + + local ok,err = pcall(f,module_list) + if not ok then quit("dump failed: "..err) end +end + +return doc diff --git a/Data/Libraries/LDoc/ldoc/html.lua b/Data/Libraries/LDoc/ldoc/html.lua new file mode 100644 index 0000000..3941802 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/html.lua @@ -0,0 +1,396 @@ +------ generating HTML output --------- +-- Although this can be generalized for outputting any format, since the template +-- is language-agnostic, this implementation concentrates on HTML. +-- This does the actual generation of HTML, and provides support functions in the ldoc +-- table for the template +-- +-- A fair amount of the complexity comes from operating in two basic modes; first, where +-- there is a number of modules (classic LuaDoc) or otherwise, where there is only one +-- module and the index contains the documentation for that module. +-- +-- Like LuaDoc, LDoc puts similar kinds of documentation files in their own directories. +-- So module docs go into 'modules/', scripts go into 'scripts/', and so forth. LDoc +-- generalizes the idea of these project-level categories and in fact custom categories +-- can be created (refered to as 'kinds' in the code) + +local List = require 'pl.List' +local utils = require 'pl.utils' +local path = require 'pl.path' +local stringx = require 'pl.stringx' +local template = require 'pl.template' +local tablex = require 'pl.tablex' +local OrderedMap = require 'pl.OrderedMap' +local tools = require 'ldoc.tools' +local markup = require 'ldoc.markup' +local prettify = require 'ldoc.prettify' +local doc = require 'ldoc.doc' +local unpack = utils.unpack +local html = {} + + +local quit = utils.quit + +local function cleanup_whitespaces(text) + local lines = stringx.splitlines(text) + for i = 1, #lines do + lines[i] = stringx.rstrip(lines[i]) + end + lines[#lines + 1] = "" -- Little trick: file should end with newline + return table.concat(lines, "\n") +end + +local function get_module_info(m) + local info = OrderedMap() + for tag in doc.module_info_tags() do + local val = m.tags[tag] + if type(val)=='table' then + val = table.concat(val,',') + end + tag = stringx.title(tag) + info:set(tag,val) + end + if #info:keys() > 0 then + return info + end +end + +local escape_table = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" } + +function html.generate_output(ldoc, args, project) + local check_directory, check_file, writefile = tools.check_directory, tools.check_file, tools.writefile + local original_ldoc + + local function save_and_set_ldoc (set) + if not set then return end + if not original_ldoc then + original_ldoc = tablex.copy(ldoc) + end + for s in set:iter() do + local var,val = s:match('([^=]+)=(.+)') + local num = tonumber(val) + if num then val = num + elseif val == 'true' then val = true + elseif val == 'false' then val = false + end + print('setting',var,val) + ldoc[var] = val + end + end + + local function restore_ldoc () + if original_ldoc then + ldoc = original_ldoc + end + end + + function ldoc.escape(str) + return (str:gsub("['&<>\"]", escape_table)) + end + + function ldoc.prettify(str) + return prettify.code('lua','usage',str,0,false) + end + + -- Item descriptions come from combining the summary and description fields + function ldoc.descript(item) + return tools.join(' ', item.summary, item.description) + end + + function ldoc.module_name (mod) + local name = mod.name + if args.unqualified and (mod.type == 'module' or mod.type == 'classmod') then -- leave out package + name = name:gsub('^.-%.','') + elseif mod.type == 'topic' then + if mod.display_name then + name = mod.display_name + else -- leave out md extension + name = name:gsub('%..*$','') + end + end + return name + end + + -- this generates the internal module/function references + function ldoc.href(see) + if see.href then -- explict reference, e.g. to Lua manual + return see.href + elseif doc.Module:class_of(see) then + return ldoc.ref_to_module(see) + else + return ldoc.ref_to_module(see.mod)..'#'..see.name + end + end + + -- this is either called from the 'root' (index or single module) or + -- from the 'modules' etc directories. If we are in one of those directories, + -- then linking to another kind is `../kind/name`; to the same kind is just `name`. + -- If we are in the root, then it is `kind/name`. + function ldoc.ref_to_module (mod) + local base = "" -- default: same directory + mod = mod or ldoc.module + local kind, module = mod.kind, ldoc.module + local name = mod.name -- default: name of module + if not ldoc.single then + if module then -- we are in kind/ + if module.type ~= type then -- cross ref to ../kind/ + base = "../"..kind.."/" + end + else -- we are in root: index + base = kind..'/' + end + else -- single module + if mod == ldoc.single then + name = ldoc.output + if not ldoc.root then base = '../' end + elseif ldoc.root then -- ref to other kinds (like examples) + base = kind..'/' + else + if module.type ~= type then -- cross ref to ../kind/ + base = "../"..kind.."/" + end + end + end + return base..name..'.html' + end + + function ldoc.include_file (file) + local text,_ = utils.readfile(file) + if not text then quit("unable to include "..file) + else + return text + end + end + +-- these references are never from the index...? +function ldoc.source_ref (fun) + local modname = fun.module.name + local pack,name = tools.split_dotted_name(modname) + if not pack then + name = modname + end + return (ldoc.single and "" or "../").."source/"..name..'.lua.html#'..fun.lineno + end + + function ldoc.use_li(ls) + if #ls > 1 then return '<li>','</li>' else return '','' end + end + + function ldoc.default_display_name(item) + -- Project-level items: + if doc.project_level(item.type) then + return ldoc.module_name(item) + end + -- Module-level items: + local name = item.display_name or item.name + if item.type == 'function' or item.type == 'lfunction' then + if not ldoc.no_space_before_args then + name = name..' ' + end + return name..item.args + else + return name + end + end + + function ldoc.display_name(item) + if ldoc.custom_display_name_handler then + return ldoc.custom_display_name_handler(item, ldoc.default_display_name) + else + return ldoc.default_display_name(item) + end + end + + function ldoc.no_spaces(s) + s = s:gsub('%s*$','') + return (s:gsub('%W','_')) + end + + function ldoc.module_typename(m) + return doc.presentation_name(m.type) + end + + function ldoc.is_list (t) + return type(t) == 'table' and t.append + end + + function ldoc.strip_header (s) + if not s then return s end + return s:gsub('^%s*#+%s+','') + end + + function ldoc.typename (tp) + if not tp or tp == '' or tp:match '^@' then return '' end + local optional + -- ?<type> is short for ?nil|<type> + if tp:match("^%?") and not tp:match '|' then + tp = '?|'..tp:sub(2) + end + local tp2 = tp:match("%?|?(.*)") + if tp2 then + optional = true + tp = tp2 + end + + local types = {} + for name in tp:gmatch("[^|]+") do + local sym = name:match '([%w%.%:]+)' + local ref,_ = markup.process_reference(sym,true) + if ref then + if ref.label and sym == name then + name = ref.label + end + types[#types+1] = ('<a class="type" href="%s">%s</a>'):format(ldoc.href(ref),name) + else + types[#types+1] = '<span class="type">'..name..'</span>' + end + end + local names = table.concat(types, ", ", 1, math.max(#types-1, 1)) + if #types > 1 then names = names.." or "..types[#types] end + if optional then + if names ~= '' then + if #types == 1 then names = "optional "..names end + else + names = "optional" + end + end + return names + end + + -- the somewhat tangled logic that controls whether a type appears in the + -- navigation sidebar. (At least it's no longer in the template ;)) + function ldoc.allowed_in_contents(type,module) + local allowed = true + if ldoc.kinds_allowed then + allowed = ldoc.kinds_allowed[type] + elseif ldoc.prettify_files and type == 'file' then + allowed = ldoc.prettify_files == 'show' or (module and module.type == 'file') + end + return allowed + end + + local function set_charset (ldoc,m) + m = m or ldoc.module + ldoc.doc_charset = (m and m.tags.charset) or ldoc.charset + end + + local module_template,_ = utils.readfile (path.join(args.template,ldoc.templ)) + if not module_template then + quit("template not found at '"..args.template.."' Use -l to specify directory containing ldoc.ltp") + end + + -- Runs a template on a module to generate HTML page. + local function templatize(template_str, ldoc, module) + local out, err = template.substitute(template_str, { + ldoc = ldoc, + module = module, + _escape = ldoc.template_escape + }) + if not out then + quit(("template failed for %s: %s"):format( + module and module.name or ldoc.output or "index", + err)) + end + if ldoc.postprocess_html then + out = ldoc.postprocess_html(out, module) + end + return cleanup_whitespaces(out) + end + + local css, custom_css = ldoc.css, ldoc.custom_css + ldoc.output = args.output + ldoc.ipairs = ipairs + ldoc.pairs = pairs + ldoc.print = print + + -- Bang out the index. + -- in single mode there is one module and the 'index' is the + -- documentation for that module. + ldoc.module = ldoc.single + if ldoc.single and args.one then + ldoc.kinds_allowed = {module = true, topic = true} + ldoc.one = true + end + ldoc.root = true + if ldoc.module then + ldoc.module.info = get_module_info(ldoc.module) + ldoc.module.ldoc = ldoc + save_and_set_ldoc(ldoc.module.tags.set) + end + set_charset(ldoc) + local out = templatize(module_template, ldoc, ldoc.module) + ldoc.root = false + restore_ldoc() + + check_directory(args.dir) -- make sure output directory is ok + + -- project icon + if ldoc.icon then + local dir_data = args.dir .. '/data' + if not path.isdir(dir_data) then + -- luacheck: push ignore lfs + lfs.mkdir(dir_data) + -- luacheck: pop + end + local file = require 'pl.file' + file.copy(ldoc.icon, dir_data) + end + + args.dir = args.dir .. path.sep + + if css then -- has CSS been copied? + check_file(args.dir..css, path.join(args.style,css)) + end + + if custom_css then -- has custom CSS been copied? + check_file(args.dir..custom_css, custom_css) + end + + -- write out the module index + out = cleanup_whitespaces(out) + writefile(args.dir..args.output..args.ext,out) + + -- in single mode, we exclude any modules since the module has been done; + -- ext step is then only for putting out any examples or topics + local mods = List() + for kind, modules in project() do + local lkind = kind:lower() + if not ldoc.single or ldoc.single and lkind ~= 'modules' then + mods:append {kind, lkind, modules} + end + end + + -- write out the per-module documentation + -- note that we reset the internal ordering of the 'kinds' so that + -- e.g. when reading a topic the other Topics will be listed first. + if css then + ldoc.css = '../'..css + end + if custom_css then + ldoc.custom_css = '../'..custom_css + end + for m in mods:iter() do + local kind, lkind, modules = unpack(m) + check_directory(args.dir..lkind) + project:put_kind_first(kind) + for m in modules() do + ldoc.module = m + ldoc.body = m.body + m.ldoc = ldoc + if m.tags.set then + save_and_set_ldoc(m.tags.set) + end + set_charset(ldoc) + m.info = get_module_info(m) + if ldoc.body and m.postprocess then + ldoc.body = m.postprocess(ldoc.body) + end + local out = templatize(module_template, ldoc, m) + writefile(args.dir..lkind..'/'..m.name..args.ext,out) + restore_ldoc() + end + end + if not args.quiet then print('output written to '..tools.abspath(args.dir)) end +end + +return html + diff --git a/Data/Libraries/LDoc/ldoc/html/_code_css.lua b/Data/Libraries/LDoc/ldoc/html/_code_css.lua new file mode 100644 index 0000000..36cffa1 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/html/_code_css.lua @@ -0,0 +1,19 @@ +return [[ + +/* styles for prettification of source */ +pre .comment { color: #558817; } +pre .constant { color: #a8660d; } +pre .escape { color: #844631; } +pre .keyword { color: #aa5050; font-weight: bold; } +pre .library { color: #0e7c6b; } +pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; } +pre .string { color: #8080ff; } +pre .number { color: #f8660d; } +pre .operator { color: #2239a8; font-weight: bold; } +pre .preprocessor, pre .prepro { color: #a33243; } +pre .global { color: #800080; } +pre .user-keyword { color: #800080; } +pre .prompt { color: #558817; } +pre .url { color: #272fc2; text-decoration: underline; } + +]] diff --git a/Data/Libraries/LDoc/ldoc/html/_reset_css.lua b/Data/Libraries/LDoc/ldoc/html/_reset_css.lua new file mode 100644 index 0000000..ef7e0d7 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/html/_reset_css.lua @@ -0,0 +1,66 @@ +return [[ +/* BEGIN RESET + +Copyright (c) 2010, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.com/yui/license.html +version: 2.8.2r1 +*/ +html { + color: #000; + background: #FFF; +} +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 { + margin: 0; + padding: 0; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +fieldset,img { + border: 0; +} +address,caption,cite,code,dfn,em,strong,th,var,optgroup { + font-style: inherit; + font-weight: inherit; +} +del,ins { + text-decoration: none; +} +li { + margin-left: 20px; +} +caption,th { + text-align: left; +} +h1,h2,h3,h4,h5,h6 { + font-size: 100%; + font-weight: bold; +} +q:before,q:after { + content: ''; +} +abbr,acronym { + border: 0; + font-variant: normal; +} +sup { + vertical-align: baseline; +} +sub { + vertical-align: baseline; +} +legend { + color: #000; +} +input,button,textarea,select,optgroup,option { + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; +} +input,button,textarea,select {*font-size:100%; +} +/* END RESET */ +]] diff --git a/Data/Libraries/LDoc/ldoc/html/ldoc_css.lua b/Data/Libraries/LDoc/ldoc/html/ldoc_css.lua new file mode 100644 index 0000000..1be506f --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/html/ldoc_css.lua @@ -0,0 +1,225 @@ +return require('ldoc.html._reset_css') .. [[ + +body { + margin-left: 1em; + margin-right: 1em; + font-family: arial, helvetica, geneva, sans-serif; + background-color: #ffffff; margin: 0px; +} + +code, tt { font-family: monospace; font-size: 1.1em; } +span.parameter { font-family:monospace; } +span.parameter:after { content:":"; } +span.types:before { content:"("; } +span.types:after { content:")"; } +.type { font-weight: bold; font-style:italic } + +body, p, td, th { font-size: .95em; line-height: 1.2em;} + +p, ul { margin: 10px 0 0 0px;} + +strong { font-weight: bold;} + +em { font-style: italic;} + +h1 { + font-size: 1.5em; + margin: 20px 0 20px 0; +} +h2, h3, h4 { margin: 15px 0 10px 0; } +h2 { font-size: 1.25em; } +h3 { font-size: 1.15em; } +h4 { font-size: 1.06em; } + +a:link { font-weight: bold; color: #004080; text-decoration: none; } +a:visited { font-weight: bold; color: #006699; text-decoration: none; } +a:link:hover { text-decoration: underline; } + +hr { + color:#cccccc; + background: #00007f; + height: 1px; +} + +blockquote { margin-left: 3em; } + +ul { list-style-type: disc; } + +p.name { + font-family: "Andale Mono", monospace; + padding-top: 1em; +} + +pre { + background-color: rgb(245, 245, 245); + border: 1px solid #C0C0C0; /* silver */ + padding: 10px; + margin: 10px 0 10px 0; + overflow: auto; + font-family: "Andale Mono", monospace; +} + +pre.example { + font-size: .85em; +} + +table.index { border: 1px #00007f; } +table.index td { text-align: left; vertical-align: top; } + +#container { + margin-left: 1em; + margin-right: 1em; + background-color: #f0f0f0; +} + +#product { + text-align: center; + border-bottom: 1px solid #cccccc; + background-color: #ffffff; +} + +#product big { + font-size: 2em; +} + +#main { + background-color: #f0f0f0; + border-left: 2px solid #cccccc; +} + +#navigation { + float: left; + width: 14em; + vertical-align: top; + background-color: #f0f0f0; + overflow: visible; +} + +#navigation h2 { + background-color:#e7e7e7; + font-size:1.1em; + color:#000000; + text-align: left; + padding:0.2em; + border-top:1px solid #dddddd; + border-bottom:1px solid #dddddd; +} + +#navigation ul +{ + font-size:1em; + list-style-type: none; + margin: 1px 1px 10px 1px; +} + +#navigation li { + text-indent: -1em; + display: block; + margin: 3px 0px 0px 22px; +} + +#navigation li li a { + margin: 0px 3px 0px -1em; +} + +#content { + margin-left: 14em; + padding: 1em; + width: 700px; + border-left: 2px solid #cccccc; + border-right: 2px solid #cccccc; + background-color: #ffffff; +} + +#about { + clear: both; + padding: 5px; + border-top: 2px solid #cccccc; + background-color: #ffffff; +} + +@media print { + body { + font: 12pt "Times New Roman", "TimeNR", Times, serif; + } + a { font-weight: bold; color: #004080; text-decoration: underline; } + + #main { + background-color: #ffffff; + border-left: 0px; + } + + #container { + margin-left: 2%; + margin-right: 2%; + background-color: #ffffff; + } + + #content { + padding: 1em; + background-color: #ffffff; + } + + #navigation { + display: none; + } + pre.example { + font-family: "Andale Mono", monospace; + font-size: 10pt; + page-break-inside: avoid; + } +} + +table.module_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.module_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.module_list td.name { background-color: #f0f0f0; min-width: 200px; } +table.module_list td.summary { width: 100%; } + + +table.function_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.function_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.function_list td.name { background-color: #f0f0f0; min-width: 200px; } +table.function_list td.summary { width: 100%; } + +ul.nowrap { + overflow:auto; + white-space:nowrap; +} + +dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;} +dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;} +dl.table h3, dl.function h3 {font-size: .95em;} + +/* stop sublists from having initial vertical space */ +ul ul { margin-top: 0px; } +ol ul { margin-top: 0px; } +ol ol { margin-top: 0px; } +ul ol { margin-top: 0px; } + +/* make the target distinct; helps when we're navigating to a function */ +a:target + * { + background-color: #FF9; +} + +]] +.. require('ldoc.html._code_css') diff --git a/Data/Libraries/LDoc/ldoc/html/ldoc_fixed_css.lua b/Data/Libraries/LDoc/ldoc/html/ldoc_fixed_css.lua new file mode 100644 index 0000000..98187c7 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/html/ldoc_fixed_css.lua @@ -0,0 +1,233 @@ +return require('ldoc.html._reset_css') .. [[ + +body { + margin-left: 1em; + margin-right: 1em; + font-family: arial, helvetica, geneva, sans-serif; + background-color: #ffffff; margin: 0px; +} + +code, tt { font-family: monospace; font-size: 1.1em; } +span.parameter { font-family:monospace; } +span.parameter:after { content:":"; } +span.types:before { content:"("; } +span.types:after { content:")"; } +.type { font-weight: bold; font-style:italic } + +body, p, td, th { font-size: .95em; line-height: 1.2em;} + +p, ul { margin: 10px 0 0 0px;} + +strong { font-weight: bold;} + +em { font-style: italic;} + +h1 { + font-size: 1.5em; + margin: 0 0 20px 0; +} +h2, h3, h4 { margin: 15px 0 10px 0; } +h2 { font-size: 1.25em; } +h3 { font-size: 1.15em; } +h4 { font-size: 1.06em; } + +a:link { font-weight: bold; color: #004080; text-decoration: none; } +a:visited { font-weight: bold; color: #006699; text-decoration: none; } +a:link:hover { text-decoration: underline; } + +hr { + color:#cccccc; + background: #00007f; + height: 1px; +} + +blockquote { margin-left: 3em; } + +ul { list-style-type: disc; } + +p.name { + font-family: "Andale Mono", monospace; + padding-top: 1em; +} + +pre { + background-color: rgb(245, 245, 245); + border: 1px solid #C0C0C0; /* silver */ + padding: 10px; + margin: 10px 0 10px 0; + overflow: auto; + font-family: "Andale Mono", monospace; +} + +pre.example { + font-size: .85em; +} + +table.index { border: 1px #00007f; } +table.index td { text-align: left; vertical-align: top; } + +#container { + margin-left: 1em; + margin-right: 1em; + background-color: #ffffff; +} + +#product { + text-align: center; + border-bottom: 1px solid #cccccc; + background-color: #ffffff; +} + +#product big { + font-size: 2em; +} + +#main { + background-color:#FFFFFF; // #f0f0f0; + border-left: 1px solid #cccccc; +} + +#navigation { + position: fixed; + top: 0; + left: 0; + float: left; + width: 14em; + vertical-align: top; + background-color:#FFFFFF; // #f0f0f0; + border-right: 2px solid #cccccc; + overflow: visible; + overflow-y: scroll; + height: 100%; + padding-left: 1em; +} + +#navigation h2 { + background-color:#FFFFFF;//:#e7e7e7; + font-size:1.1em; + color:#000000; + text-align: left; + padding:0.2em; + border-bottom:1px solid #dddddd; +} + +#navigation ul +{ + font-size:1em; + list-style-type: none; + margin: 1px 1px 10px 1px; +} + +#navigation li { + text-indent: -1em; + display: block; + margin: 3px 0px 0px 22px; +} + +#navigation li li a { + margin: 0px 3px 0px -1em; +} + +#content { + margin-left: 14em; + padding: 1em; + padding-left: 2em; + width: 700px; + border-left: 2px solid #cccccc; + // border-right: 2px solid #cccccc; + background-color: #ffffff; +} + +#about { + clear: both; + padding-left: 1em; + margin-left: 14em; // avoid the damn sidebar! + border-top: 2px solid #cccccc; + border-left: 2px solid #cccccc; + background-color: #ffffff; +} + +@media print { + body { + font: 12pt "Times New Roman", "TimeNR", Times, serif; + } + a { font-weight: bold; color: #004080; text-decoration: underline; } + + #main { + background-color: #ffffff; + border-left: 0px; + } + + #container { + margin-left: 2%; + margin-right: 2%; + background-color: #ffffff; + } + + #content { + padding: 1em; + background-color: #ffffff; + } + + #navigation { + display: none; + } + pre.example { + font-family: "Andale Mono", monospace; + font-size: 10pt; + page-break-inside: avoid; + } +} + +table.module_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.module_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.module_list td.name { background-color: #f0f0f0; ; min-width: 200px; } +table.module_list td.summary { width: 100%; } + +table.function_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.function_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.function_list td.name { background-color: #f6f6ff; ; min-width: 200px; } +table.function_list td.summary { width: 100%; } + +dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;} +dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;} +dl.table h3, dl.function h3 {font-size: .95em;} + +ul.nowrap { + overflow:auto; + whitespace:nowrap; +} + +/* stop sublists from having initial vertical space */ +ul ul { margin-top: 0px; } +ol ul { margin-top: 0px; } +ol ol { margin-top: 0px; } +ul ol { margin-top: 0px; } + +/* make the target distinct; helps when we're navigating to a function */ +a:target + * { + background-color: #FF9; +} + +]] +.. require('ldoc.html._code_css') diff --git a/Data/Libraries/LDoc/ldoc/html/ldoc_ltp.lua b/Data/Libraries/LDoc/ldoc/html/ldoc_ltp.lua new file mode 100644 index 0000000..31b09d7 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/html/ldoc_ltp.lua @@ -0,0 +1,324 @@ +return [==[ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html> +<meta http-equiv="Content-Type" content="text/html; charset=$(ldoc.doc_charset)"/> +<head> + <title>$(ldoc.title)</title> + <link rel="stylesheet" href="$(ldoc.css)" type="text/css" /> +# if ldoc.custom_css then -- add custom CSS file if configured. + <link rel="stylesheet" href="$(ldoc.custom_css)" type="text/css" /> +# end +</head> +<body> + +<div id="container"> + +<div id="product"> + <div id="product_logo"></div> + <div id="product_name"><big><b></b></big></div> + <div id="product_description"></div> +</div> <!-- id="product" --> + + +<div id="main"> + +# local no_spaces = ldoc.no_spaces +# local use_li = ldoc.use_li +# local display_name = ldoc.display_name +# local iter = ldoc.modules.iter +# local function M(txt,item) return ldoc.markup(txt,item,ldoc.plain) end +# local nowrap = ldoc.wrap and '' or 'nowrap' + +<!-- Menu --> + +<div id="navigation"> +<br/> +<h1>$(ldoc.project)</h1> + +# if ldoc.icon then +# if module then +<img src="../data/$(ldoc.icon)" /> +# else +<img src="data/$(ldoc.icon)" /> +# end +# end + +# if not ldoc.single and module then -- reference back to project index +<ul> + <li><a href="../$(ldoc.output).html">Index</a></li> +</ul> +# end + +# --------- contents of module ------------- +# if module and not ldoc.no_summary and #module.items > 0 then +<h2>Contents</h2> +<ul> +# for kind,items in module.kinds() do +<li><a href="#$(no_spaces(kind))">$(kind)</a></li> +# end +</ul> +# end + + +# if ldoc.no_summary and module and not ldoc.one then -- bang out the functions on the side +# for kind, items in module.kinds() do +<h2>$(kind)</h2> +<ul class="nowrap"> +# for item in items() do + <li><a href="#$(item.name)">$(display_name(item))</a></li> +# end +</ul> +# end +# end +# -------- contents of project ---------- +# local this_mod = module and module.name +# for kind, mods, type in ldoc.kinds() do +# if ldoc.allowed_in_contents(type,module) then +<h2>$(kind)</h2> +<ul class="$(kind=='Topics' and '' or 'nowrap')"> +# for mod in mods() do local name = display_name(mod) +# if mod.name == this_mod then + <li><strong>$(name)</strong></li> +# else + <li><a href="$(ldoc.ref_to_module(mod))">$(name)</a></li> +# end +# end +# end +</ul> +# end + +</div> + +<div id="content"> + +# if ldoc.body then -- verbatim HTML as contents; 'non-code' entries + $(ldoc.body) +# elseif module then -- module documentation +<h1>$(ldoc.module_typename(module)) <code>$(module.name)</code></h1> +<p>$(M(module.summary,module))</p> +<p>$(M(module.description,module))</p> +# if module.tags.include then + $(M(ldoc.include_file(module.tags.include))) +# end +# if module.see then +# local li,il = use_li(module.see) + <h3>See also:</h3> + <ul> +# for see in iter(module.see) do + $(li)<a href="$(ldoc.href(see))">$(see.label)</a>$(il) +# end -- for + </ul> +# end -- if see +# if module.usage then +# local li,il = use_li(module.usage) + <h3>Usage:</h3> + <ul> +# for usage in iter(module.usage) do + $(li)<pre class="example">$(ldoc.escape(usage))</pre>$(il) +# end -- for + </ul> +# end -- if usage +# if module.info then + <h3>Info:</h3> + <ul> +# for tag, value in module.info:iter() do + <li><strong>$(tag)</strong>: $(M(value,module))</li> +# end + </ul> +# end -- if module.info + + +# if not ldoc.no_summary then +# -- bang out the tables of item types for this module (e.g Functions, Tables, etc) +# for kind,items in module.kinds() do +<h2><a href="#$(no_spaces(kind))">$(kind)</a></h2> +<table class="function_list"> +# for item in items() do + <tr> + <td class="name" $(nowrap)><a href="#$(item.name)">$(display_name(item))</a></td> + <td class="summary">$(M(item.summary,item))</td> + </tr> +# end -- for items +</table> +#end -- for kinds + +<br/> +<br/> + +#end -- if not no_summary + +# --- currently works for both Functions and Tables. The params field either contains +# --- function parameters or table fields. +# local show_return = not ldoc.no_return_or_parms +# local show_parms = show_return +# for kind, items in module.kinds() do +# local kitem = module.kinds:get_item(kind) +# local has_description = kitem and ldoc.descript(kitem) ~= "" + <h2 class="section-header $(has_description and 'has-description')"><a name="$(no_spaces(kind))"></a>$(kind)</h2> + $(M(module.kinds:get_section_description(kind),nil)) +# if kitem then +# if has_description then + <div class="section-description"> + $(M(ldoc.descript(kitem),kitem)) + </div> +# end +# if kitem.usage then + <h3>Usage:</h3> + <pre class="example">$(ldoc.prettify(kitem.usage[1]))</pre> +# end +# end + <dl class="function"> +# for item in items() do + <dt> + <a name = "$(item.name)"></a> + <strong>$(display_name(item))</strong> +# if ldoc.prettify_files and ldoc.is_file_prettified[item.module.file.filename] then + <a style="float:right;" href="$(ldoc.source_ref(item))">line $(item.lineno)</a> +# end + </dt> + <dd> + $(M(ldoc.descript(item),item)) + +# if ldoc.custom_tags then +# for custom in iter(ldoc.custom_tags) do +# local tag = item.tags[custom[1]] +# if tag and not custom.hidden then +# local li,il = use_li(tag) + <h3>$(custom.title or custom[1]):</h3> + <ul> +# for value in iter(tag) do + $(li)$(custom.format and custom.format(value) or M(value))$(il) +# end -- for +# end -- if tag + </ul> +# end -- iter tags +# end + +# if show_parms and item.params and #item.params > 0 then +# local subnames = module.kinds:type_of(item).subnames +# if subnames then + <h3>$(subnames):</h3> +# end + <ul> +# for parm in iter(item.params) do +# local param,sublist = item:subparam(parm) +# if sublist then + <li><span class="parameter">$(sublist)</span>$(M(item.params.map[sublist],item)) + <ul> +# end +# for p in iter(param) do +# local name,tp,def = item:display_name_of(p), ldoc.typename(item:type_of_param(p)), item:default_of_param(p) + <li><span class="parameter">$(name)</span> +# if tp ~= '' then + <span class="types">$(tp)</span> +# end + $(M(item.params.map[p],item)) +# if def == true then + (<em>optional</em>) +# elseif def then + (<em>default</em> $(def)) +# end +# if item:readonly(p) then + <em>readonly</em> +# end + </li> +# end +# if sublist then + </li></ul> +# end +# end -- for + </ul> +# end -- if params + +# if show_return and item.retgroups then local groups = item.retgroups + <h3>Returns:</h3> +# for i,group in ldoc.ipairs(groups) do local li,il = use_li(group) + <ol> +# for r in group:iter() do local type, ctypes = item:return_type(r); local rt = ldoc.typename(type) + $(li) +# if rt ~= '' then + <span class="types">$(rt)</span> +# end + $(M(r.text,item))$(il) +# if ctypes then + <ul> +# for c in ctypes:iter() do + <li><span class="parameter">$(c.name)</span> + <span class="types">$(ldoc.typename(c.type))</span> + $(M(c.comment,item))</li> +# end + </ul> +# end -- if ctypes +# end -- for r + </ol> +# if i < #groups then + <h3>Or</h3> +# end +# end -- for group +# end -- if returns + +# if show_return and item.raise then + <h3>Raises:</h3> + $(M(item.raise,item)) +# end + +# if item.see then +# local li,il = use_li(item.see) + <h3>See also:</h3> + <ul> +# for see in iter(item.see) do + $(li)<a href="$(ldoc.href(see))">$(see.label)</a>$(il) +# end -- for + </ul> +# end -- if see + +# if item.usage then +# local li,il = use_li(item.usage) + <h3>Usage:</h3> + <ul> +# for usage in iter(item.usage) do + $(li)<pre class="example">$(ldoc.prettify(usage))</pre>$(il) +# end -- for + </ul> +# end -- if usage + +</dd> +# end -- for items +</dl> +# end -- for kinds + +# else -- if module; project-level contents + +# if ldoc.description then + <h2>$(M(ldoc.description,nil))</h2> +# end +# if ldoc.full_description then + <p>$(M(ldoc.full_description,nil))</p> +# end + +# for kind, mods in ldoc.kinds() do +<h2>$(kind)</h2> +# kind = kind:lower() +<table class="module_list"> +# for m in mods() do + <tr> + <td class="name" $(nowrap)><a href="$(no_spaces(kind))/$(m.name).html">$(m.name)</a></td> + <td class="summary">$(M(ldoc.strip_header(m.summary),m))</td> + </tr> +# end -- for modules +</table> +# end -- for kinds +# end -- if module + +</div> <!-- id="content" --> +</div> <!-- id="main" --> +<div id="about"> +<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc $(ldoc.version)</a></i> +<i style="float:right;">Last updated $(ldoc.updatetime) </i> +</div> <!-- id="about" --> +</div> <!-- id="container" --> +</body> +</html> +]==] + diff --git a/Data/Libraries/LDoc/ldoc/html/ldoc_md_ltp.lua b/Data/Libraries/LDoc/ldoc/html/ldoc_md_ltp.lua new file mode 100644 index 0000000..ca39766 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/html/ldoc_md_ltp.lua @@ -0,0 +1,17 @@ +return [[ +> local lev = ldoc.level or 2 +> local lev1,lev2 = ('#'):rep(lev),('#'):rep(lev+1) +> for kind, items in module.kinds() do +> local kitem = module.kinds:get_item(kind) +> if kitem then +$(lev1) $(ldoc.descript(kitem)) + +> end +> for item in items() do +$(lev2) $(ldoc.display_name(item)) + +$(ldoc.descript(item)) + +> end +> end +]] diff --git a/Data/Libraries/LDoc/ldoc/html/ldoc_new_css.lua b/Data/Libraries/LDoc/ldoc/html/ldoc_new_css.lua new file mode 100644 index 0000000..eb57e9b --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/html/ldoc_new_css.lua @@ -0,0 +1,292 @@ +return [[ +body { + color: #47555c; + font-size: 16px; + font-family: "Open Sans", sans-serif; + margin: 0; + background: #eff4ff; +} + +a:link { color: #008fee; } +a:visited { color: #008fee; } +a:hover { color: #22a7ff; } + +h1 { font-size:26px; font-weight: normal; } +h2 { font-size:22px; font-weight: normal; } +h3 { font-size:18px; font-weight: normal; } +h4 { font-size:16px; font-weight: bold; } + +hr { + height: 1px; + background: #c1cce4; + border: 0px; + margin: 15px 0; +} + +code, tt { + font-family: monospace; +} +span.parameter { + font-family: monospace; + font-weight: bold; + color: rgb(99, 115, 131); +} +span.parameter:after { + content:":"; +} +span.types:before { + content:"("; +} +span.types:after { + content:")"; +} +.type { + font-weight: bold; font-style:italic +} + +p.name { + font-family: "Andale Mono", monospace; +} + +#navigation { + float: left; + background-color: white; + border-right: 1px solid #d3dbec; + border-bottom: 1px solid #d3dbec; + + width: 14em; + vertical-align: top; + overflow: visible; +} + +#navigation br { + display: none; +} + +#navigation h1 { + background-color: white; + border-bottom: 1px solid #d3dbec; + padding: 15px; + margin-top: 0px; + margin-bottom: 0px; +} + +#navigation h2 { + font-size: 18px; + background-color: white; + border-bottom: 1px solid #d3dbec; + padding-left: 15px; + padding-right: 15px; + padding-top: 10px; + padding-bottom: 10px; + margin-top: 30px; + margin-bottom: 0px; +} + +#content h1 { + background-color: #2c3e67; + color: white; + padding: 15px; + margin: 0px; +} + +#content h2 { + background-color: #6c7ea7; + color: white; + padding: 15px; + padding-top: 15px; + padding-bottom: 15px; + margin-top: 0px; +} + +#content h2 a { + background-color: #6c7ea7; + color: white; + text-decoration: none; +} + +#content h2 a:hover { + text-decoration: underline; +} + +#content h3 { + font-style: italic; + padding-top: 15px; + padding-bottom: 4px; + margin-right: 15px; + margin-left: 15px; + margin-bottom: 5px; + border-bottom: solid 1px #bcd; +} + +#content h4 { + margin-right: 15px; + margin-left: 15px; + border-bottom: solid 1px #bcd; +} + +#content pre { + margin: 15px; +} + +pre { + background-color: rgb(50, 55, 68); + color: white; + border-radius: 3px; + /* border: 1px solid #C0C0C0; /* silver */ + padding: 15px; + overflow: auto; + font-family: "Andale Mono", monospace; +} + +#content ul pre.example { + margin-left: 0px; +} + +table.index { +/* border: 1px #00007f; */ +} +table.index td { text-align: left; vertical-align: top; } + +#navigation ul +{ + font-size:1em; + list-style-type: none; + margin: 1px 1px 10px 1px; +} + +#navigation li { + text-indent: -1em; + display: block; + margin: 3px 0px 0px 22px; +} + +#navigation li li a { + margin: 0px 3px 0px -1em; +} + +#content { + margin-left: 14em; +} + +#content p { + padding-left: 15px; + padding-right: 15px; +} + +#content table { + padding-left: 15px; + padding-right: 15px; + background-color: white; +} + +#content p, #content table, #content ol, #content ul, #content dl { + max-width: 900px; +} + +#about { + padding: 15px; + padding-left: 16em; + background-color: white; + border-top: 1px solid #d3dbec; + border-bottom: 1px solid #d3dbec; +} + +table.module_list, table.function_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; + margin: 15px; +} +table.module_list td, table.function_list td { + border-width: 1px; + padding-left: 10px; + padding-right: 10px; + padding-top: 5px; + padding-bottom: 5px; + border: solid 1px rgb(193, 204, 228); +} +table.module_list td.name, table.function_list td.name { + background-color: white; min-width: 200px; border-right-width: 0px; +} +table.module_list td.summary, table.function_list td.summary { + background-color: white; width: 100%; border-left-width: 0px; +} + +dl.function { + margin-right: 15px; + margin-left: 15px; + border-bottom: solid 1px rgb(193, 204, 228); + border-left: solid 1px rgb(193, 204, 228); + border-right: solid 1px rgb(193, 204, 228); + background-color: white; +} + +dl.function dt { + color: rgb(99, 123, 188); + font-family: monospace; + border-top: solid 1px rgb(193, 204, 228); + padding: 15px; +} + +dl.function dd { + margin-left: 15px; + margin-right: 15px; + margin-top: 5px; + margin-bottom: 15px; +} + +#content dl.function dd h3 { + margin-top: 0px; + margin-left: 0px; + padding-left: 0px; + font-size: 16px; + color: rgb(128, 128, 128); + border-bottom: solid 1px #def; +} + +#content dl.function dd ul, #content dl.function dd ol { + padding: 0px; + padding-left: 15px; + list-style-type: none; +} + +ul.nowrap { + overflow:auto; + white-space:nowrap; +} + +.section-description { + padding-left: 15px; + padding-right: 15px; +} + +/* stop sublists from having initial vertical space */ +ul ul { margin-top: 0px; } +ol ul { margin-top: 0px; } +ol ol { margin-top: 0px; } +ul ol { margin-top: 0px; } + +/* make the target distinct; helps when we're navigating to a function */ +a:target + * { + background-color: #FF9; +} + + +/* styles for prettification of source */ +pre .comment { color: #bbccaa; } +pre .constant { color: #a8660d; } +pre .escape { color: #844631; } +pre .keyword { color: #ffc090; font-weight: bold; } +pre .library { color: #0e7c6b; } +pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; } +pre .string { color: #8080ff; } +pre .number { color: #f8660d; } +pre .operator { color: #2239a8; font-weight: bold; } +pre .preprocessor, pre .prepro { color: #a33243; } +pre .global { color: #c040c0; } +pre .user-keyword { color: #800080; } +pre .prompt { color: #558817; } +pre .url { color: #272fc2; text-decoration: underline; } +]] diff --git a/Data/Libraries/LDoc/ldoc/html/ldoc_one_css.lua b/Data/Libraries/LDoc/ldoc/html/ldoc_one_css.lua new file mode 100644 index 0000000..956461f --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/html/ldoc_one_css.lua @@ -0,0 +1,202 @@ +return require('ldoc.html._reset_css') .. [[ + +body { + margin-left: 1em; + margin-right: 1em; + font-family: arial, helvetica, geneva, sans-serif; + background-color: #ffffff; margin: 0px; +} + +code, tt { font-family: monospace; font-size: 1.1em; } + +body, p, td, th { font-size: .95em; line-height: 1.2em;} + +p, ul { margin: 10px 0 0 10px;} + +strong { font-weight: bold;} + +em { font-style: italic;} + +h1 { + font-size: 1.5em; + margin: 0 0 20px 0; +} +h2, h3, h4 { margin: 15px 0 10px 0; } +h2 { font-size: 1.25em; } +h3 { font-size: 1.15em; } +h4 { font-size: 1.06em; } + +a:link { font-weight: bold; color: #004080; text-decoration: none; } +a:visited { font-weight: bold; color: #2808FF; text-decoration: none; } +a:link:hover { text-decoration: underline; } + +hr { + color:#cccccc; + background: #00007f; + height: 1px; +} + +blockquote { margin-left: 3em; } + +ul { list-style-type: disc; } + +p.name { + font-family: "Andale Mono", monospace; + padding-top: 1em; +} + +pre { + background-color: rgb(245, 245, 245); + border: 1px solid #C0C0C0; /* silver */ + padding: 10px; + margin: 10px 0 10px 0; + overflow: auto; + font-family: "Andale Mono", monospace; +} + +pre.example { + font-size: .85em; +} + +table.index { border: 1px #00007f; } +table.index td { text-align: left; vertical-align: top; } + +#container { + margin-left: 1em; + margin-right: 1em; + background-color: #f5f5f5; +} + +#product { + text-align: center; + border-bottom: 1px solid #cccccc; + background-color: #ffffff; +} + +#product big { + font-size: 2em; +} + +#main { + border-left: 2px solid #cccccc; + border-right: 2px solid #cccccc; +} + +#navigation { + float: top; + vertical-align: top; + background-color: #f5f5f5; + overflow: visible; +} + +#navigation h2 { + background-color:#e7e7e7; + font-size:1.1em; + color:#000000; + text-align: left; + padding:0.2em; + border-top:1px solid #dddddd; + border-bottom:1px solid #dddddd; +} + +#navigation ul +{ + font-size:1em; + list-style-type: none; + margin: 1px 1px 10px 1px; +} + +#navigation li { + text-indent: -1em; + display: block; + margin: 3px 0px 0px 22px; +} + +#navigation li li a { + margin: 0px 3px 0px -1em; +} + +#content { + padding: 1em; + background-color: #ffffff; +} + +#about { + clear: both; + padding: 5px; + border-top: 2px solid #cccccc; + background-color: #ffffff; +} + +@media print { + body { + font: 12pt "Times New Roman", "TimeNR", Times, serif; + } + a { font-weight: bold; color: #004080; text-decoration: underline; } + + #main { + background-color: #ffffff; + border-left: 0px; + } + + #container { + margin-left: 2%; + margin-right: 2%; + background-color: #ffffff; + } + + #content { + padding: 1em; + background-color: #ffffff; + } + + #navigation { + display: none; + } + pre.example { + font-family: "Andale Mono", monospace; + font-size: 10pt; + page-break-inside: avoid; + } +} + +table.module_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.module_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.module_list td.name { background-color: #f5f5f5; } +table.module_list td.summary { width: 100%; } + + +table.function_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.function_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.function_list td.name { + background-color: #f5f5f5; + white-space: normal; /* voids the "nowrap" in HTML */ +} +table.function_list td.summary { width: 100%; } + +dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;} +dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;} +dl.table h3, dl.function h3 {font-size: .95em;} + +]] +.. require('ldoc.html._code_css') diff --git a/Data/Libraries/LDoc/ldoc/html/ldoc_pale_css.lua b/Data/Libraries/LDoc/ldoc/html/ldoc_pale_css.lua new file mode 100644 index 0000000..ffc91a2 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/html/ldoc_pale_css.lua @@ -0,0 +1,225 @@ +return require('ldoc.html._reset_css') .. [[ + +body { + margin-left: 1em; + margin-right: 1em; + font-family: arial, helvetica, geneva, sans-serif; + background-color: #ffffff; margin: 0px; +} + +code, tt { font-family: monospace; font-size: 1.1em; } +span.parameter { font-family:monospace; } +span.parameter:after { content:":"; } +span.types:before { content:"("; } +span.types:after { content:")"; } +.type { font-weight: bold; font-style:italic } + +body, p, td, th { font-size: .95em; line-height: 1.2em;} + +p, ul { margin: 10px 0 0 0px;} + +strong { font-weight: bold;} + +em { font-style: italic;} + +h1 { + font-size: 1.5em; + margin: 0 0 20px 0; +} +h2, h3, h4 { margin: 15px 0 10px 0; } +h2 { font-size: 1.25em; } +h3 { font-size: 1.15em; } +h4 { font-size: 1.06em; } + +a:link { font-weight: bold; color: #004080; text-decoration: none; } +a:visited { font-weight: bold; color: #006699; text-decoration: none; } +a:link:hover { text-decoration: underline; } + +hr { + color:#cccccc; + background: #00007f; + height: 1px; +} + +blockquote { margin-left: 3em; } + +ul { list-style-type: disc; } + +p.name { + font-family: "Andale Mono", monospace; + padding-top: 1em; +} + +pre { + background-color: rgb(245, 245, 245); + border: 1px solid #C0C0C0; /* silver */ + padding: 10px; + margin: 10px 0 10px 0; + overflow: auto; + font-family: "Andale Mono", monospace; +} + +pre.example { + font-size: .85em; +} + +table.index { border: 1px #00007f; } +table.index td { text-align: left; vertical-align: top; } + +#container { + margin-left: 1em; + margin-right: 1em; + background-color: #ffffff; +} + +#product { + text-align: center; + border-bottom: 1px solid #cccccc; + background-color: #ffffff; +} + +#product big { + font-size: 2em; +} + +#main { + background-color:#FFFFFF; // #f0f0f0; + //border-left: 2px solid #cccccc; +} + +#navigation { + float: left; + width: 14em; + vertical-align: top; + background-color:#FFFFFF; // #f0f0f0; + border-right: 2px solid #cccccc; + overflow: visible; +} + +#navigation h2 { + background-color:#FFFFFF;//:#e7e7e7; + font-size:1.1em; + color:#000000; + text-align: left; + padding:0.2em; + //border-top:1px solid #dddddd; + border-bottom:1px solid #dddddd; +} + +#navigation ul +{ + font-size:1em; + list-style-type: none; + margin: 1px 1px 10px 1px; +} + +#navigation li { + text-indent: -1em; + display: block; + margin: 3px 0px 0px 22px; +} + +#navigation li li a { + margin: 0px 3px 0px -1em; +} + +#content { + margin-left: 14em; + padding: 1em; + width: 700px; + border-left: 2px solid #cccccc; + // border-right: 2px solid #cccccc; + background-color: #ffffff; +} + +#about { + clear: both; + padding: 5px; + border-top: 2px solid #cccccc; + background-color: #ffffff; +} + +@media print { + body { + font: 12pt "Times New Roman", "TimeNR", Times, serif; + } + a { font-weight: bold; color: #004080; text-decoration: underline; } + + #main { + background-color: #ffffff; + border-left: 0px; + } + + #container { + margin-left: 2%; + margin-right: 2%; + background-color: #ffffff; + } + + #content { + padding: 1em; + background-color: #ffffff; + } + + #navigation { + display: none; + } + pre.example { + font-family: "Andale Mono", monospace; + font-size: 10pt; + page-break-inside: avoid; + } +} + +table.module_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.module_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.module_list td.name { background-color: #f0f0f0; ; min-width: 200px; } +table.module_list td.summary { width: 100%; } + +table.function_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.function_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.function_list td.name { background-color: #f6f6ff; ; min-width: 200px; } +table.function_list td.summary { width: 100%; } + +dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;} +dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;} +dl.table h3, dl.function h3 {font-size: .95em;} + +ul.nowrap { + overflow:auto; + whitespace:nowrap; +} + +/* stop sublists from having initial vertical space */ +ul ul { margin-top: 0px; } +ol ul { margin-top: 0px; } +ol ol { margin-top: 0px; } +ul ol { margin-top: 0px; } + +/* make the target distinct; helps when we're navigating to a function */ +a:target + * { + background-color: #FF9; +} + +]] +.. require('ldoc.html._code_css') diff --git a/Data/Libraries/LDoc/ldoc/lang.lua b/Data/Libraries/LDoc/ldoc/lang.lua new file mode 100644 index 0000000..4ef1859 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/lang.lua @@ -0,0 +1,379 @@ +------------ +-- Language-dependent parsing of code. +-- This encapsulates the different strategies needed for parsing C and Lua +-- source code. + +local class = require 'pl.class' +local utils = require 'pl.utils' +local List = require 'pl.List' +local tools = require 'ldoc.tools' +local lexer = require 'ldoc.lexer' +local quit = utils.quit +local tnext = lexer.skipws + + +local Lang = class() + +function Lang:trim_comment (s) + return s:gsub(self.line_comment,'') +end + +function Lang:start_comment (v) + local line = v:match (self.start_comment_) + if line and self.end_comment_ and v:match (self.end_comment_) then + return nil + end + local block = v:match(self.block_comment) + return line or block, block +end + +function Lang:empty_comment (v) + return v:match(self.empty_comment_) +end + +function Lang:grab_block_comment(v,tok) + v = v:gsub(self.block_comment,'') + return tools.grab_block_comment(v,tok,self.end_comment) +end + +function Lang:find_module(tok,t,v) + return '...',t,v +end + +function Lang:item_follows(t,v) + return false +end + +function Lang:finalize() + self.empty_comment_ = self.start_comment_..'%s*$' +end + +function Lang:search_for_token (tok,type,value,t,v) + while t and not (t == type and v == value) do + if t == 'comment' and self:start_comment(v) then return nil,t,v end + t,v = tnext(tok) + end + return t ~= nil,t,v +end + +function Lang:parse_extra (tags,tok) +end + +function Lang:is_module_modifier () + return false +end + +function Lang:parse_module_modifier (tags, tok) + return nil, "@usage or @exports deduction not implemented for this language" +end + + +local Lua = class(Lang) + +function Lua:_init() + self.line_comment = '^%-%-+' -- used for stripping + self.start_comment_ = '^%-%-%-+' -- used for doc comment line start + self.block_comment = '^%-%-%[=*%[%-+' -- used for block doc comments + self.end_comment_ = '[^%-]%-%-+[^-]*\n$' ---- exclude --- this kind of comment --- + self.method_call = ':' + self:finalize() +end + +function Lua.lexer(fname) + local f,e = io.open(fname) + if not f then quit(e) end + return lexer.lua(f,{}),f +end + +function Lua:grab_block_comment(v,tok) + local equals = v:match('^%-%-%[(=*)%[') + if not equals then return v end + v = v:gsub(self.block_comment,'') + return tools.grab_block_comment(v,tok,'%]'..equals..'%]') +end + + +-- luacheck: push ignore 312 +function Lua:parse_module_call(tok,t,v) + t,v = tnext(tok) + if t == '(' then t,v = tnext(tok) end + if t == 'string' then -- explicit name, cool + return v,t,v + elseif t == '...' then -- we have to guess! + return '...',t,v + end +end +-- luacheck: pop + +-- If a module name was not provided, then we look for an explicit module() +-- call. However, we should not try too hard; if we hit a doc comment then +-- we should go back and process it. Likewise, module(...) also means +-- that we must infer the module name. +function Lua:find_module(tok,t,v) + local res + res,t,v = self:search_for_token(tok,'iden','module',t,v) + if not res then return nil,t,v end + return self:parse_module_call(tok,t,v) +end + +local function parse_lua_parameters (tags,tok) + tags.formal_args = tools.get_parameters(tok) + tags:add('class','function') +end + +local function parse_lua_function_header (tags,tok) + if not tags.name then + tags:add('name',tools.get_fun_name(tok)) + end + if not tags.name then return 'function has no name' end + parse_lua_parameters(tags,tok) +end + +local function parse_lua_table (tags,tok) + tags.formal_args = tools.get_parameters(tok,'}',function(s) + return s == ',' or s == ';' + end) +end + +--------------- function and variable inferrence ----------- +-- After a doc comment, there may be a local followed by: +-- [1] (l)function: function NAME +-- [2] (l)function: NAME = function +-- [3] table: NAME = { +-- [4] field: NAME = <anything else> (this is a module-level field) +-- +-- Depending on the case successfully detected, returns a function which +-- will be called later to fill in inferred item tags +function Lua:item_follows(t,v,tok) + local parser, case + local is_local = t == 'keyword' and v == 'local' + if is_local then t,v = tnext(tok) end + if t == 'keyword' and v == 'function' then -- case [1] + case = 1 + parser = parse_lua_function_header + elseif t == 'iden' then + local name,t,_ = tools.get_fun_name(tok,v) + if t ~= '=' then return nil,"not 'name = function,table or value'" end + t,v = tnext(tok) + if t == 'keyword' and v == 'function' then -- case [2] + tnext(tok) -- skip '(' + case = 2 + parser = function(tags,tok) + tags:add('name',name) + parse_lua_parameters(tags,tok) + end + elseif t == '{' then -- case [3] + case = 3 + parser = function(tags,tok) + tags:add('class','table') + tags:add('name',name) + parse_lua_table (tags,tok) + end + else -- case [4] + case = 4 + parser = function(tags) + tags:add('class','field') + tags:add('name',name) + end + end + elseif t == 'keyword' and v == 'return' then + t, v = tnext(tok) + if t == 'keyword' and v == 'function' then + -- return function(a, b, c) + tnext(tok) -- skip '(' + case = 2 + parser = parse_lua_parameters + elseif t == '{' then + -- return {...} + case = 5 + parser = function(tags,tok) + tags:add('class','table') + parse_lua_table(tags,tok) + end + else + return nil,'not returning function or table' + end + else + return nil,"not 'name=value' or 'return value'" + end + return parser, is_local, case +end + + +-- we only call the function returned by the item_follows above if there +-- is not already a name and a type. +-- Otherwise, this is called. Currrently only tries to fill in the fields +-- of a table from a table definition as identified above +function Lua:parse_extra (tags,tok,case) + if tags.class == 'table' and not tags.field and case == 3 then + parse_lua_table(tags,tok) + end +end + +-- For Lua, a --- @usage comment means that a long +-- string containing the usage follows, which we +-- use to update the module usage tag. Likewise, the @export +-- tag alone in a doc comment refers to the following returned +-- Lua table of functions + + +function Lua:is_module_modifier (tags) + return tags.summary == '' and (tags.usage or tags.export) +end + +-- Allow for private name convention. +function Lua:is_private_var (name) + return name:match '^_' or name:match '_$' +end + +function Lua:parse_module_modifier (tags, tok, F) + if tags.usage then + if tags.class ~= 'field' then return nil,"cannot deduce @usage" end + local t1= tnext(tok) + if t1 ~= '[' then return nil, t1..' '..': not a long string' end + local _, v = tools.grab_block_comment('',tok,'%]%]') + return true, v, 'usage' + elseif tags.export then + if tags.class ~= 'table' then return nil, "cannot deduce @export" end + for f in tags.formal_args:iter() do + if not self:is_private_var(f) then + F:export_item(f) + end + end + return true + end +end + + +-- note a difference here: we scan C/C++ code in full-text mode, not line by line. +-- This is because we can't detect multiline comments in line mode. +-- Note: this applies to C/C++ code used to generate _Lua_ documentation! + +local CC = class(Lang) + +function CC:_init() + self.line_comment = '^//+' + self.start_comment_ = '^///+' + self.block_comment = '^/%*%*+' + self.method_call = ':' + self:finalize() +end + +function CC.lexer(f) + local err + f,err = utils.readfile(f) + if not f then quit(err) end + return lexer.cpp(f,{},nil,true) +end + +function CC:grab_block_comment(v,tok) + v = v:gsub(self.block_comment,''):gsub('\n%s*%*','\n') + return 'comment',v:sub(1,-3) +end + +--- here the argument name is always last, and the type is composed of any tokens before +function CC:extract_arg (tl,idx) + idx = idx or 1 + local res = List() + for i = idx,#tl-1 do + res:append(tl[i][2]) + end + local type = res:join ' ' + return tl[#tl][2], type +end + +function CC:item_follows (t,v,tok) + if not self.extra.C then + return false + end + if t == 'iden' or t == 'keyword' then -- + local _ + if v == self.extra.export then -- this is not part of the return type! + _,v = tnext(tok) + end + -- types may have multiple tokens: example, const char *bonzo(...) + local return_type, name = v + _,v = tnext(tok) + name = v + t,v = tnext(tok) + while t ~= '(' do + return_type = return_type .. ' ' .. name + name = v + t,v = tnext(tok) + end + --print ('got',name,t,v,return_type) + return function(tags,tok) + if not tags.name then + tags:add('name',name) + end + tags:add('class','function') + if t == '(' then + tags.formal_args,t,_ = tools.get_parameters(tok,')',',',self) + if return_type ~= 'void' then + tags.formal_args.return_type = return_type + end + end + end + end + return false +end + +local Moon = class(Lua) + +function Moon:_init() + self.line_comment = '^%-%-+' -- used for stripping + self.start_comment_ = '^%s*%-%-%-+' -- used for doc comment line start + self.block_comment = '^%-%-%[=*%[%-+' -- used for block doc comments + self.end_comment_ = '[^%-]%-%-+\n$' ---- exclude --- this kind of comment --- + self.method_call = '\\' + self:finalize() +end + +--- much like Lua, BUT auto-assign parameters start with @ +function Moon:extract_arg (tl,idx) + idx = idx or 1 + local auto_assign = tl[idx][1] == '@' + if auto_assign then idx = idx + 1 end + local res = tl[idx][2] + return res +end + +function Moon:item_follows (t,v,tok) + if t == '.' then -- enclosed in with statement + t,v = tnext(tok) + end + if t == 'iden' then + local name,t,v = tools.get_fun_name(tok,v,'') + if name == 'class' then + local _ + name,_,_ = tools.get_fun_name(tok,v,'') + -- class! + return function(tags,tok) + tags:add('class','type') + tags:add('name',name) + end + elseif t == '=' or t == ':' then -- function/method + local _ + t,_ = tnext(tok) + return function(tags,tok) + if not tags.name then + tags:add('name',name) + end + if t == '(' then + tags.formal_args,t,_ = tools.get_parameters(tok,')',',',self) + else + tags.formal_args = List() + end + t,_ = tnext(tok) + tags:add('class','function') + if t ~= '>' then + tags.static = true + end + end + else + return nil, "expecting '=' or ':'" + end + end +end + +return { lua = Lua(), cc = CC(), moon = Moon() } diff --git a/Data/Libraries/LDoc/ldoc/lexer.lua b/Data/Libraries/LDoc/ldoc/lexer.lua new file mode 100644 index 0000000..aafb07d --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/lexer.lua @@ -0,0 +1,504 @@ +--- Lexical scanner for creating a sequence of tokens from text. <br> +-- <p><code>lexer.scan(s)</code> returns an iterator over all tokens found in the +-- string <code>s</code>. This iterator returns two values, a token type string +-- (such as 'string' for quoted string, 'iden' for identifier) and the value of the +-- token. +-- <p> +-- Versions specialized for Lua and C are available; these also handle block comments +-- and classify keywords as 'keyword' tokens. For example: +-- <pre class=example> +-- > s = 'for i=1,n do' +-- > for t,v in lexer.lua(s) do print(t,v) end +-- keyword for +-- iden i +-- = = +-- number 1 +-- , , +-- iden n +-- keyword do +-- </pre> +-- +-- Based on pl.lexer from Penlight + +local strfind = string.find +local strsub = string.sub +local append = table.insert + +local function assert_arg(idx,val,tp) + if type(val) ~= tp then + error("argument "..idx.." must be "..tp, 2) + end +end + +local lexer = {} + +local NUMBER1 = '^[%+%-]?%d+%.?%d*[eE][%+%-]?%d+' +local NUMBER2 = '^[%+%-]?%d+%.?%d*' +local NUMBER3 = '^0x[%da-fA-F]+' +local NUMBER4 = '^%d+%.?%d*[eE][%+%-]?%d+' +local NUMBER5 = '^%d+%.?%d*' +local IDEN = '^[%a_][%w_]*' +local WSPACE = '^%s+' +local STRING1 = [[^'.-[^\\]']] +local STRING2 = [[^".-[^\\]"]] +local STRING3 = "^((['\"])%2)" -- empty string +local PREPRO = '^#.-[^\\]\n' + +local plain_matches,lua_matches,cpp_matches,cpp_matches_no_string,lua_keyword,cpp_keyword + +local function tdump(tok) + return tok,tok +end + +local function ndump(tok,options) + if options and options.number then + tok = tonumber(tok) + end + return "number",tok +end + +-- regular strings, single or double quotes; usually we want them +-- without the quotes +local function sdump(tok,options) + if options and options.string then + tok = tok:sub(2,-2) + end + return "string",tok +end + +-- strings enclosed in back ticks +local function bdump(tok,options) + if options and options.string then + tok = tok:sub(2,-2) + end + return "backtick",tok +end + +-- long Lua strings need extra work to get rid of the quotes +local function sdump_l(tok,options) + if options and options.string then + tok = tok:sub(3,-3) + end + return "string",tok +end + +local function chdump(tok,options) + if options and options.string then + tok = tok:sub(2,-2) + end + return "char",tok +end + +local function cdump(tok) + return 'comment',tok +end + +local function wsdump (tok) + return "space",tok +end + +local function pdump (tok) + return 'prepro',tok +end + +local function plain_vdump(tok) + return "iden",tok +end + +local function lua_vdump(tok) + if lua_keyword[tok] then + return "keyword",tok + else + return "iden",tok + end +end + +local function cpp_vdump(tok) + if cpp_keyword[tok] then + return "keyword",tok + else + return "iden",tok + end +end + +local function count_lines(line, text) + local index, limit = 1, #text + while index <= limit do + local start, stop = text:find('\r\n', index, true) + if not start then + start, stop = text:find('[\r\n\f]', index) + if not start then break end + end + index = stop + 1 + line = line + 1 + end + return line +end + +local multiline = { comment = true, space = true } + + +--- create a plain token iterator from a string or file-like object. +-- @param s the string +-- @param matches an optional match table (set of pattern-action pairs) +-- @param filter a table of token types to exclude, by default {space=true} +-- @param options a table of options; by default, {number=true,string=true}, +-- which means convert numbers and strip string quotes. +function lexer.scan (s,matches,filter,options) + --assert_arg(1,s,'string') + local file = type(s) ~= 'string' and s + filter = filter or {space=true} + options = options or {number=true,string=true} + if filter then + if filter.space then filter[wsdump] = true end + if filter.comments then + filter[cdump] = true + end + end + if not matches then + if not plain_matches then + plain_matches = { + {WSPACE,wsdump}, + {NUMBER3,ndump}, + {IDEN,plain_vdump}, + {NUMBER1,ndump}, + {NUMBER2,ndump}, + {STRING3,sdump}, + {STRING1,sdump}, + {STRING2,sdump}, + {'^.',tdump} + } + end + matches = plain_matches + end + local i1,i2,tok,pat,fun + local line = 1 + if file then + s = file:read() + if not s then return nil end -- empty file + if s:match '^\239\187' then -- UTF-8 BOM Abomination + s = s:sub(4) + end + s = s ..'\n' + end + local sz = #s + local idx = 1 + if sz == 0 then return nil end -- empty file + + local res = {} + local mt = {} + mt.__index = mt + setmetatable(res,mt) + + function mt.lineno() return line end + + function mt.getline() + if idx < sz then + tok = strsub(s,idx,-2) + idx = sz + 1 + line = line + 1 + return tok + else + idx = sz + 1 + line = line + 1 + return file:read() + end + end + + function mt.next (tok) + local t,v = tok() + while t == 'space' do + t,v = tok() + end + return t,v + end + + function mt.__call () + if not s then return end + while true do + for _,m in ipairs(matches) do + pat,fun = m[1],m[2] + if fun == nil then error("no match for "..pat) end + i1,i2 = strfind(s,pat,idx) + if i1 then + tok = strsub(s,i1,i2) + idx = i2 + 1 + if not (filter and filter[fun]) then + lexer.finished = idx > sz + local t,v = fun(tok,options) + if not file and multiline[t] then + line = count_lines(line,v) + end + return t,v + end + end + end + if idx > sz then + if file then + line = line + 1 + s = file:read() + if not s then return end + s = s .. '\n' + idx ,sz = 1,#s + else + return + end + end + end + end + return res +end + +--- get everything in a stream upto a newline. +-- @param tok a token stream +-- @return a string +function lexer.getline (tok) + return tok:getline() +end + +--- get current line number. <br> +-- Only available if the input source is a file-like object. +-- @param tok a token stream +-- @return the line number and current column +function lexer.lineno (tok) + return tok:lineno() +end + +--- get the Lua keywords as a set-like table. +-- So <code>res["and"]</code> etc would be <code>true</code>. +-- @return a table +function lexer.get_keywords () + if not lua_keyword then + lua_keyword = { + ["and"] = true, ["break"] = true, ["do"] = true, + ["else"] = true, ["elseif"] = true, ["end"] = true, + ["false"] = true, ["for"] = true, ["function"] = true, + ["if"] = true, ["in"] = true, ["local"] = true, ["nil"] = true, + ["not"] = true, ["or"] = true, ["repeat"] = true, + ["return"] = true, ["then"] = true, ["true"] = true, + ["until"] = true, ["while"] = true + } + end + return lua_keyword +end + + +--- create a Lua token iterator from a string or file-like object. +-- Will return the token type and value. +-- @param s the string +-- @param filter a table of token types to exclude, by default {space=true,comments=true} +-- @param options a table of options; by default, {number=true,string=true}, +-- which means convert numbers and strip string quotes. +function lexer.lua(s,filter,options) + filter = filter or {space=true,comments=true} + lexer.get_keywords() + if not lua_matches then + lua_matches = { + {WSPACE,wsdump}, + {NUMBER3,ndump}, + {IDEN,lua_vdump}, + {NUMBER4,ndump}, + {NUMBER5,ndump}, + {STRING3,sdump}, + {STRING1,sdump}, + {STRING2,sdump}, + {'^`[^`]+`',bdump}, + {'^%-%-%[(=*)%[.-%]%1%]',cdump}, + {'^%-%-.-\n',cdump}, + {'^%-%-.-$',cdump}, + {'^%[(=*)%[.-%]%1%]',sdump_l}, + {'^==',tdump}, + {'^~=',tdump}, + {'^<=',tdump}, + {'^>=',tdump}, + {'^%.%.%.',tdump}, + {'^%.%.',tdump}, + {'^.',tdump} + } + end + return lexer.scan(s,lua_matches,filter,options) +end + +--- create a C/C++ token iterator from a string or file-like object. +-- Will return the token type type and value. +-- @param s the string +-- @param filter a table of token types to exclude, by default {space=true,comments=true} +-- @param options a table of options; by default, {number=true,string=true}, +-- which means convert numbers and strip string quotes. +function lexer.cpp(s,filter,options,no_string) + filter = filter or {comments=true} + if not cpp_keyword then + cpp_keyword = { + ["class"] = true, ["break"] = true, ["do"] = true, ["sizeof"] = true, + ["else"] = true, ["continue"] = true, ["struct"] = true, + ["false"] = true, ["for"] = true, ["public"] = true, ["void"] = true, + ["private"] = true, ["protected"] = true, ["goto"] = true, + ["if"] = true, ["static"] = true, ["const"] = true, ["typedef"] = true, + ["enum"] = true, ["char"] = true, ["int"] = true, ["bool"] = true, + ["long"] = true, ["float"] = true, ["true"] = true, ["delete"] = true, + ["double"] = true, ["while"] = true, ["new"] = true, + ["namespace"] = true, ["try"] = true, ["catch"] = true, + ["switch"] = true, ["case"] = true, ["extern"] = true, + ["return"] = true,["default"] = true,['unsigned'] = true,['signed'] = true, + ["union"] = true, ["volatile"] = true, ["register"] = true,["short"] = true, + } + end + if not cpp_matches then + cpp_matches = { + {WSPACE,wsdump}, + {PREPRO,pdump}, + {NUMBER3,ndump}, + {IDEN,cpp_vdump}, + {NUMBER4,ndump}, + {NUMBER5,ndump}, + {STRING3,sdump}, + {STRING1,chdump}, + {STRING2,sdump}, + {'^//.-\n',cdump}, + {'^//.-$',cdump}, + {'^/%*.-%*/',cdump}, + {'^==',tdump}, + {'^!=',tdump}, + {'^<=',tdump}, + {'^>=',tdump}, + {'^->',tdump}, + {'^&&',tdump}, + {'^||',tdump}, + {'^%+%+',tdump}, + {'^%-%-',tdump}, + {'^%+=',tdump}, + {'^%-=',tdump}, + {'^%*=',tdump}, + {'^/=',tdump}, + {'^|=',tdump}, + {'^%^=',tdump}, + {'^::',tdump}, + {'^%.%.%.',tdump}, + {'^.',tdump} + } + end + if not cpp_matches_no_string then + cpp_matches_no_string = { + {WSPACE,wsdump}, + {PREPRO,pdump}, + {NUMBER3,ndump}, + {IDEN,cpp_vdump}, + {NUMBER4,ndump}, + {NUMBER5,ndump}, + {'^//.-\n',cdump}, + {'^/%*.-%*/',cdump}, + {'^==',tdump}, + {'^!=',tdump}, + {'^<=',tdump}, + {'^>=',tdump}, + {'^->',tdump}, + {'^&&',tdump}, + {'^||',tdump}, + {'^%+%+',tdump}, + {'^%-%-',tdump}, + {'^%+=',tdump}, + {'^%-=',tdump}, + {'^%*=',tdump}, + {'^/=',tdump}, + {'^|=',tdump}, + {'^%^=',tdump}, + {'^::',tdump}, + {'^%.%.%.',tdump}, + {'^.',tdump} + } + end + return lexer.scan(s, + not no_string and cpp_matches or cpp_matches_no_string, + filter,options) +end + +--- get a list of parameters separated by a delimiter from a stream. +-- @param tok the token stream +-- @param endtoken end of list (default ')'). Can be '\n' +-- @param delim separator (default ',') +-- @return a list of token lists. +function lexer.get_separated_list(tok,endtoken,delim) + endtoken = endtoken or ')' + delim = delim or ',' + local function tappend (tl,t,val) + val = val or t + append(tl,{t,val}) + end + local is_end + if endtoken == '\n' then + is_end = function(t,val) + return t == 'space' and val:find '\n' + end + else + is_end = function (t) + return t == endtoken + end + end + local is_delim + if type(delim) == 'function' then + is_delim = delim + else + is_delim = function(t) + return t == delim + end + end + local parm_values = {} + local level = 1 -- used to count ( and ) + local tl = {} + local token,value + while true do + token,value=tok() + if not token then return nil,'EOS' end -- end of stream is an error! + if is_end(token,value) and level == 1 then + if next(tl) then + append(parm_values,tl) + end + break + elseif token == '(' then + level = level + 1 + tappend(tl,'(') + elseif token == ')' then + level = level - 1 + if level == 0 then -- finished with parm list + append(parm_values,tl) + break + else + tappend(tl,')') + end + elseif level == 1 and is_delim(token) then + append(parm_values,tl) -- a new parm + tl = {} + else + tappend(tl,token,value) + end + end + return parm_values,{token,value} +end + +--- get the next non-space token from the stream. +-- @param tok the token stream. +function lexer.skipws (tok) + return tok:next() +end + +local skipws = lexer.skipws + +--- get the next token, which must be of the expected type. +-- Throws an error if this type does not match! +-- @param tok the token stream +-- @param expected_type the token type +-- @param no_skip_ws whether we should skip whitespace +function lexer.expecting (tok,expected_type,no_skip_ws) + assert_arg(1,tok,'function') + assert_arg(2,expected_type,'string') + local t,v + if no_skip_ws then + t,v = tok() + else + t,v = skipws(tok) + end + if t ~= expected_type then error ("expecting "..expected_type,2) end + return v +end + +return lexer diff --git a/Data/Libraries/LDoc/ldoc/markdown.lua b/Data/Libraries/LDoc/ldoc/markdown.lua new file mode 100644 index 0000000..2044bb7 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/markdown.lua @@ -0,0 +1,1357 @@ +#!/usr/bin/env lua + +--[[ +# markdown.lua -- version 0.32 + +<http://www.frykholm.se/files/markdown.lua> + +**Author:** Niklas Frykholm, <niklas@frykholm.se> +**Date:** 31 May 2008 + +This is an implementation of the popular text markup language Markdown in pure Lua. +Markdown can convert documents written in a simple and easy to read text format +to well-formatted HTML. For a more thourough description of Markdown and the Markdown +syntax, see <http://daringfireball.net/projects/markdown>. + +The original Markdown source is written in Perl and makes heavy use of advanced +regular expression techniques (such as negative look-ahead, etc) which are not available +in Lua's simple regex engine. Therefore this Lua port has been rewritten from the ground +up. It is probably not completely bug free. If you notice any bugs, please report them to +me. A unit test that exposes the error is helpful. + +## Usage + + require "markdown" + markdown(source) + +``markdown.lua`` exposes a single global function named ``markdown(s)`` which applies the +Markdown transformation to the specified string. + +``markdown.lua`` can also be used directly from the command line: + + lua markdown.lua test.md + +Creates a file ``test.html`` with the converted content of ``test.md``. Run: + + lua markdown.lua -h + +For a description of the command-line options. + +``markdown.lua`` uses the same license as Lua, the MIT license. + +## License + +Copyright © 2008 Niklas Frykholm. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies +or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +## Version history + +- **0.32** -- 31 May 2008 + - Fix for links containing brackets +- **0.31** -- 1 Mar 2008 + - Fix for link definitions followed by spaces +- **0.30** -- 25 Feb 2008 + - Consistent behavior with Markdown when the same link reference is reused +- **0.29** -- 24 Feb 2008 + - Fix for <pre> blocks with spaces in them +- **0.28** -- 18 Feb 2008 + - Fix for link encoding +- **0.27** -- 14 Feb 2008 + - Fix for link database links with () +- **0.26** -- 06 Feb 2008 + - Fix for nested italic and bold markers +- **0.25** -- 24 Jan 2008 + - Fix for encoding of naked < +- **0.24** -- 21 Jan 2008 + - Fix for link behavior. +- **0.23** -- 10 Jan 2008 + - Fix for a regression bug in longer expressions in italic or bold. +- **0.22** -- 27 Dec 2007 + - Fix for crash when processing blocks with a percent sign in them. +- **0.21** -- 27 Dec 2007 + - Fix for combined strong and emphasis tags +- **0.20** -- 13 Oct 2007 + - Fix for < as well in image titles, now matches Dingus behavior +- **0.19** -- 28 Sep 2007 + - Fix for quotation marks " and ampersands & in link and image titles. +- **0.18** -- 28 Jul 2007 + - Does not crash on unmatched tags (behaves like standard markdown) +- **0.17** -- 12 Apr 2007 + - Fix for links with %20 in them. +- **0.16** -- 12 Apr 2007 + - Do not require arg global to exist. +- **0.15** -- 28 Aug 2006 + - Better handling of links with underscores in them. +- **0.14** -- 22 Aug 2006 + - Bug for *`foo()`* +- **0.13** -- 12 Aug 2006 + - Added -l option for including stylesheet inline in document. + - Fixed bug in -s flag. + - Fixed emphasis bug. +- **0.12** -- 15 May 2006 + - Fixed several bugs to comply with MarkdownTest 1.0 <http://six.pairlist.net/pipermail/markdown-discuss/2004-December/000909.html> +- **0.11** -- 12 May 2006 + - Fixed bug for escaping `*` and `_` inside code spans. + - Added license terms. + - Changed join() to table.concat(). +- **0.10** -- 3 May 2006 + - Initial public release. + +// Niklas +]] + + +-- Set up a table for holding local functions to avoid polluting the global namespace +local M = {} +local unpack = unpack or table.unpack +local MT = {__index = _G} +setmetatable(M, MT) + +---------------------------------------------------------------------- +-- Utility functions +---------------------------------------------------------------------- + +-- Locks table t from changes, writes an error if someone attempts to change the table. +-- This is useful for detecting variables that have "accidently" been made global. Something +-- I tend to do all too much. +function M.lock(t) + local function lock_new_index(t, k, v) + error("module has been locked -- " .. k .. " must be declared local", 2) + end + + local mt = {__newindex = lock_new_index} + if getmetatable(t) then + mt.__index = getmetatable(t).__index + end + setmetatable(t, mt) +end + +-- Returns the result of mapping the values in table t through the function f +local function map(t, f) + local out = {} + for k,v in pairs(t) do out[k] = f(v,k) end + return out +end + +-- Functional style if statement. (NOTE: no short circuit evaluation) +local function iff(t, a, b) if t then return a else return b end end + +-- Splits the text into an array of separate lines. +local function split(text, sep) + sep = sep or "\n" + local lines = {} + local pos = 1 + while true do + local b,e = text:find(sep, pos) + if not b then table.insert(lines, text:sub(pos)) break end + table.insert(lines, text:sub(pos, b-1)) + pos = e + 1 + end + return lines +end + +-- Converts tabs to spaces +local function detab(text) + local tab_width = 4 + local function rep(match) + local spaces = -match:len() + while spaces<1 do spaces = spaces + tab_width end + return match .. string.rep(" ", spaces) + end + text = text:gsub("([^\n]-)\t", rep) + return text +end + +-- Applies string.find for every pattern in the list and returns the first match +local function find_first(s, patterns, index) + local res = {} + for _,p in ipairs(patterns) do + local match = {s:find(p, index)} + if #match>0 and (#res==0 or match[1] < res[1]) then res = match end + end + return unpack(res) +end + +-- If a replacement array is specified, the range [start, stop] in the array is replaced +-- with the replacement array and the resulting array is returned. Without a replacement +-- array the section of the array between start and stop is returned. +local function splice(array, start, stop, replacement) + if replacement then + local n = stop - start + 1 + while n > 0 do + table.remove(array, start) + n = n - 1 + end + for i,v in ipairs(replacement) do + table.insert(array, start, v) + end + return array + else + local res = {} + for i = start,stop do + table.insert(res, array[i]) + end + return res + end +end + +-- Outdents the text one step. +local function outdent(text) + text = "\n" .. text + text = text:gsub("\n ? ? ?", "\n") + text = text:sub(2) + return text +end + +-- Indents the text one step. +local function indent(text) + text = text:gsub("\n", "\n ") + return text +end + +-- Does a simple tokenization of html data. Returns the data as a list of tokens. +-- Each token is a table with a type field (which is either "tag" or "text") and +-- a text field (which contains the original token data). +local function tokenize_html(html) + local tokens = {} + local pos = 1 + while true do + local start = find_first(html, {"<!%-%-", "<[a-z/!$]", "<%?"}, pos) + if not start then + table.insert(tokens, {type="text", text=html:sub(pos)}) + break + end + if start ~= pos then table.insert(tokens, {type="text", text = html:sub(pos, start-1)}) end + + local _, stop + if html:match("^<!%-%-", start) then + _,stop = html:find("%-%->", start) + elseif html:match("^<%?", start) then + _,stop = html:find("?>", start) + else + _,stop = html:find("%b<>", start) + end + if not stop then + -- error("Could not match html tag " .. html:sub(start,start+30)) + table.insert(tokens, {type="text", text=html:sub(start, start)}) + pos = start + 1 + else + table.insert(tokens, {type="tag", text=html:sub(start, stop)}) + pos = stop + 1 + end + end + return tokens +end + +---------------------------------------------------------------------- +-- Hash +---------------------------------------------------------------------- + +-- This is used to "hash" data into alphanumeric strings that are unique +-- in the document. (Note that this is not cryptographic hash, the hash +-- function is not one-way.) The hash procedure is used to protect parts +-- of the document from further processing. + +local HASH = { + -- Has the hash been inited. + inited = false, + + -- The unique string prepended to all hash values. This is to ensure + -- that hash values do not accidently coincide with an actual existing + -- string in the document. + identifier = "", + + -- Counter that counts up for each new hash instance. + counter = 0, + + -- Hash table. + table = {} +} + +-- Inits hashing. Creates a hash_identifier that doesn't occur anywhere +-- in the text. +local function init_hash(text) + HASH.inited = true + HASH.identifier = "" + HASH.counter = 0 + HASH.table = {} + + local s = "HASH" + local counter = 0 + local id + while true do + id = s .. counter + if not text:find(id, 1, true) then break end + counter = counter + 1 + end + HASH.identifier = id +end + +-- Returns the hashed value for s. +local function hash(s) + assert(HASH.inited) + if not HASH.table[s] then + HASH.counter = HASH.counter + 1 + local id = HASH.identifier .. HASH.counter .. "X" + HASH.table[s] = id + end + return HASH.table[s] +end + +---------------------------------------------------------------------- +-- Protection +---------------------------------------------------------------------- + +-- The protection module is used to "protect" parts of a document +-- so that they are not modified by subsequent processing steps. +-- Protected parts are saved in a table for later unprotection + +-- Protection data +local PD = { + -- Saved blocks that have been converted + blocks = {}, + + -- Block level tags that will be protected + tags = {"p", "div", "h1", "h2", "h3", "h4", "h5", "h6", "blockquote", + "pre", "table", "dl", "ol", "ul", "script", "noscript", "form", "fieldset", + "iframe", "math", "ins", "del"} +} + +-- Pattern for matching a block tag that begins and ends in the leftmost +-- column and may contain indented subtags, i.e. +-- <div> +-- A nested block. +-- <div> +-- Nested data. +-- </div> +-- </div> +local function block_pattern(tag) + return "\n<" .. tag .. ".-\n</" .. tag .. ">[ \t]*\n" +end + +-- Pattern for matching a block tag that begins and ends with a newline +local function line_pattern(tag) + return "\n<" .. tag .. ".-</" .. tag .. ">[ \t]*\n" +end + +-- Protects the range of characters from start to stop in the text and +-- returns the protected string. +local function protect_range(text, start, stop) + local s = text:sub(start, stop) + local h = hash(s) + PD.blocks[h] = s + text = text:sub(1,start) .. h .. text:sub(stop) + return text +end + +-- Protect every part of the text that matches any of the patterns. The first +-- matching pattern is protected first, etc. +local function protect_matches(text, patterns) + while true do + local start, stop = find_first(text, patterns) + if not start then break end + text = protect_range(text, start, stop) + end + return text +end + +-- Protects blocklevel tags in the specified text +local function protect(text) + -- First protect potentially nested block tags + text = protect_matches(text, map(PD.tags, block_pattern)) + -- Then protect block tags at the line level. + text = protect_matches(text, map(PD.tags, line_pattern)) + -- Protect <hr> and comment tags + text = protect_matches(text, {"\n<hr[^>]->[ \t]*\n"}) + text = protect_matches(text, {"\n<!%-%-.-%-%->[ \t]*\n"}) + return text +end + +-- Returns true if the string s is a hash resulting from protection +local function is_protected(s) + return PD.blocks[s] +end + +-- Unprotects the specified text by expanding all the nonces +local function unprotect(text) + for k,v in pairs(PD.blocks) do + v = v:gsub("%%", "%%%%") + text = text:gsub(k, v) + end + return text +end + + +---------------------------------------------------------------------- +-- Block transform +---------------------------------------------------------------------- + +-- The block transform functions transform the text on the block level. +-- They work with the text as an array of lines rather than as individual +-- characters. + +-- Returns true if the line is a ruler of (char) characters. +-- The line must contain at least three char characters and contain only spaces and +-- char characters. +local function is_ruler_of(line, char) + if not line:match("^[ %" .. char .. "]*$") then return false end + if not line:match("%" .. char .. ".*%" .. char .. ".*%" .. char) then return false end + return true +end + +-- Identifies the block level formatting present in the line +local function classify(line) + local info = {line = line, text = line} + + if line:match("^ ") then + info.type = "indented" + info.outdented = line:sub(5) + return info + end + + for _,c in ipairs({'*', '-', '_', '='}) do + if is_ruler_of(line, c) then + info.type = "ruler" + info.ruler_char = c + return info + end + end + + if line == "" then + info.type = "blank" + return info + end + + if line:match("^(#+)[ \t]*(.-)[ \t]*#*[ \t]*$") then + local m1, m2 = line:match("^(#+)[ \t]*(.-)[ \t]*#*[ \t]*$") + info.type = "header" + info.level = m1:len() + info.text = m2 + return info + end + + if line:match("^ ? ? ?(%d+)%.[ \t]+(.+)") then + local number, text = line:match("^ ? ? ?(%d+)%.[ \t]+(.+)") + info.type = "list_item" + info.list_type = "numeric" + info.number = 0 + number + info.text = text + return info + end + + if line:match("^ ? ? ?([%*%+%-])[ \t]+(.+)") then + local bullet, text = line:match("^ ? ? ?([%*%+%-])[ \t]+(.+)") + info.type = "list_item" + info.list_type = "bullet" + info.bullet = bullet + info.text= text + return info + end + + if line:match("^>[ \t]?(.*)") then + info.type = "blockquote" + info.text = line:match("^>[ \t]?(.*)") + return info + end + + if is_protected(line) then + info.type = "raw" + info.html = unprotect(line) + return info + end + + info.type = "normal" + return info +end + +-- Find headers constisting of a normal line followed by a ruler and converts them to +-- header entries. +local function headers(array) + local i = 1 + while i <= #array - 1 do + if array[i].type == "normal" and array[i+1].type == "ruler" and + (array[i+1].ruler_char == "-" or array[i+1].ruler_char == "=") then + local info = {line = array[i].line} + info.text = info.line + info.type = "header" + info.level = iff(array[i+1].ruler_char == "=", 1, 2) + table.remove(array, i+1) + array[i] = info + end + i = i + 1 + end + return array +end + +local block_transform, blocks_to_html, encode_code, span_transform, encode_backslash_escapes + +-- Find list blocks and convert them to protected data blocks +local function lists(array, sublist) + local function process_list(arr) + local function any_blanks(arr) + for i = 1, #arr do + if arr[i].type == "blank" then return true end + end + return false + end + + local function split_list_items(arr) + local acc = {arr[1]} + local res = {} + for i=2,#arr do + if arr[i].type == "list_item" then + table.insert(res, acc) + acc = {arr[i]} + else + table.insert(acc, arr[i]) + end + end + table.insert(res, acc) + return res + end + + local function process_list_item(lines, block) + while lines[#lines].type == "blank" do + table.remove(lines) + end + + local itemtext = lines[1].text + for i=2,#lines do + itemtext = itemtext .. "\n" .. outdent(lines[i].line) + end + if block then + itemtext = block_transform(itemtext, true) + if not itemtext:find("<pre>") then itemtext = indent(itemtext) end + return " <li>" .. itemtext .. "</li>" + else + local lines = split(itemtext) + lines = map(lines, classify) + lines = lists(lines, true) + lines = blocks_to_html(lines, true) + itemtext = table.concat(lines, "\n") + if not itemtext:find("<pre>") then itemtext = indent(itemtext) end + return " <li>" .. itemtext .. "</li>" + end + end + + local block_list = any_blanks(arr) + local items = split_list_items(arr) + local out = "" + for _, item in ipairs(items) do + out = out .. process_list_item(item, block_list) .. "\n" + end + if arr[1].list_type == "numeric" then + return "<ol>\n" .. out .. "</ol>" + else + return "<ul>\n" .. out .. "</ul>" + end + end + + -- Finds the range of lines composing the first list in the array. A list + -- starts with (^ list_item) or (blank list_item) and ends with + -- (blank* $) or (blank normal). + -- + -- A sublist can start with just (list_item) does not need a blank... + local function find_list(array, sublist) + local function find_list_start(array, sublist) + if array[1].type == "list_item" then return 1 end + if sublist then + for i = 1,#array do + if array[i].type == "list_item" then return i end + end + else + for i = 1, #array-1 do + if array[i].type == "blank" and array[i+1].type == "list_item" then + return i+1 + end + end + end + return nil + end + local function find_list_end(array, start) + local pos = #array + for i = start, #array-1 do + if array[i].type == "blank" and array[i+1].type ~= "list_item" + and array[i+1].type ~= "indented" and array[i+1].type ~= "blank" then + pos = i-1 + break + end + end + while pos > start and array[pos].type == "blank" do + pos = pos - 1 + end + return pos + end + + local start = find_list_start(array, sublist) + if not start then return nil end + return start, find_list_end(array, start) + end + + while true do + local start, stop = find_list(array, sublist) + if not start then break end + local text = process_list(splice(array, start, stop)) + local info = { + line = text, + type = "raw", + html = text + } + array = splice(array, start, stop, {info}) + end + + -- Convert any remaining list items to normal + for _,line in ipairs(array) do + if line.type == "list_item" then line.type = "normal" end + end + + return array +end + +-- Find and convert blockquote markers. +local function blockquotes(lines) + local function find_blockquote(lines) + local start + for i,line in ipairs(lines) do + if line.type == "blockquote" then + start = i + break + end + end + if not start then return nil end + + local stop = #lines + for i = start+1, #lines do + -- luacheck: push ignore 542 + if lines[i].type == "blank" or lines[i].type == "blockquote" then + elseif lines[i].type == "normal" then + if lines[i-1].type == "blank" then stop = i-1 break end + else + stop = i-1 break + end + -- luacheck: pop + end + while lines[stop].type == "blank" do stop = stop - 1 end + return start, stop + end + + local function process_blockquote(lines) + local raw = lines[1].text + for i = 2,#lines do + raw = raw .. "\n" .. lines[i].text + end + local bt = block_transform(raw) + if not bt:find("<pre>") then bt = indent(bt) end + return "<blockquote>\n " .. bt .. + "\n</blockquote>" + end + + while true do + local start, stop = find_blockquote(lines) + if not start then break end + local text = process_blockquote(splice(lines, start, stop)) + local info = { + line = text, + type = "raw", + html = text + } + lines = splice(lines, start, stop, {info}) + end + return lines +end + +-- Find and convert codeblocks. +local function codeblocks(lines) + local function find_codeblock(lines) + local start + for i,line in ipairs(lines) do + if line.type == "indented" then start = i break end + end + if not start then return nil end + + local stop = #lines + for i = start+1, #lines do + if lines[i].type ~= "indented" and lines[i].type ~= "blank" then + stop = i-1 + break + end + end + while lines[stop].type == "blank" do stop = stop - 1 end + return start, stop + end + + local function process_codeblock(lines) + local raw = detab(encode_code(outdent(lines[1].line))) + for i = 2,#lines do + raw = raw .. "\n" .. detab(encode_code(outdent(lines[i].line))) + end + return "<pre><code>" .. raw .. "\n</code></pre>" + end + + while true do + local start, stop = find_codeblock(lines) + if not start then break end + local text = process_codeblock(splice(lines, start, stop)) + local info = { + line = text, + type = "raw", + html = text + } + lines = splice(lines, start, stop, {info}) + end + return lines +end + +-- Convert lines to html code +function blocks_to_html(lines, no_paragraphs) + local out = {} + local i = 1 + while i <= #lines do + local line = lines[i] + if line.type == "ruler" then + table.insert(out, "<hr/>") + elseif line.type == "raw" then + table.insert(out, line.html) + elseif line.type == "normal" then + local s = line.line + + while i+1 <= #lines and lines[i+1].type == "normal" do + i = i + 1 + s = s .. "\n" .. lines[i].line + end + + if no_paragraphs then + table.insert(out, span_transform(s)) + else + table.insert(out, "<p>" .. span_transform(s) .. "</p>") + end + elseif line.type == "header" then + local s = "<h" .. line.level .. ">" .. span_transform(line.text) .. "</h" .. line.level .. ">" + table.insert(out, s) + else + table.insert(out, line.line) + end + i = i + 1 + end + return out +end + +-- Perform all the block level transforms +function block_transform(text, sublist) + local lines = split(text) + lines = map(lines, classify) + lines = headers(lines) + lines = lists(lines, sublist) + lines = codeblocks(lines) + lines = blockquotes(lines) + lines = blocks_to_html(lines) + local text = table.concat(lines, "\n") + return text +end + +---------------------------------------------------------------------- +-- Span transform +---------------------------------------------------------------------- + +-- Functions for transforming the text at the span level. + +-- These characters may need to be escaped because they have a special +-- meaning in markdown. +local escape_chars = "'\\`*_{}[]()>#+-.!'" +local escape_table = {} + +local function init_escape_table() + escape_table = {} + for i = 1,#escape_chars do + local c = escape_chars:sub(i,i) + escape_table[c] = hash(c) + end +end + +-- Adds a new escape to the escape table. +local function add_escape(text) + if not escape_table[text] then + escape_table[text] = hash(text) + end + return escape_table[text] +end + +-- Escape characters that should not be disturbed by markdown. +local function escape_special_chars(text) + local tokens = tokenize_html(text) + + local out = "" + for _, token in ipairs(tokens) do + local t = token.text + if token.type == "tag" then + -- In tags, encode * and _ so they don't conflict with their use in markdown. + t = t:gsub("%*", escape_table["*"]) + t = t:gsub("%_", escape_table["_"]) + else + t = encode_backslash_escapes(t) + end + out = out .. t + end + return out +end + +-- Encode backspace-escaped characters in the markdown source. +function encode_backslash_escapes(t) + for i=1,escape_chars:len() do + local c = escape_chars:sub(i,i) + t = t:gsub("\\%" .. c, escape_table[c]) + end + return t +end + +-- Unescape characters that have been encoded. +local function unescape_special_chars(t) + local tin = t + for k,v in pairs(escape_table) do + k = k:gsub("%%", "%%%%") + t = t:gsub(v,k) + end + if t ~= tin then t = unescape_special_chars(t) end + return t +end + +-- Encode/escape certain characters inside Markdown code runs. +-- The point is that in code, these characters are literals, +-- and lose their special Markdown meanings. +function encode_code(s) + s = s:gsub("%&", "&") + s = s:gsub("<", "<") + s = s:gsub(">", ">") + for k,v in pairs(escape_table) do + s = s:gsub("%"..k, v) + end + return s +end + +-- Handle backtick blocks. +local function code_spans(s) + s = s:gsub("\\\\", escape_table["\\"]) + s = s:gsub("\\`", escape_table["`"]) + + local pos = 1 + while true do + local start, stop = s:find("`+", pos) + if not start then return s end + local count = stop - start + 1 + -- Find a matching numbert of backticks + local estart, estop = s:find(string.rep("`", count), stop+1) + local brstart = s:find("\n", stop+1) + if estart and (not brstart or estart < brstart) then + local code = s:sub(stop+1, estart-1) + code = code:gsub("^[ \t]+", "") + code = code:gsub("[ \t]+$", "") + code = code:gsub(escape_table["\\"], escape_table["\\"] .. escape_table["\\"]) + code = code:gsub(escape_table["`"], escape_table["\\"] .. escape_table["`"]) + code = "<code>" .. encode_code(code) .. "</code>" + code = add_escape(code) + s = s:sub(1, start-1) .. code .. s:sub(estop+1) + pos = start + code:len() + else + pos = stop + 1 + end + end +end + +-- Encode alt text... enodes &, and ". +local function encode_alt(s) + if not s then return s end + s = s:gsub('&', '&') + s = s:gsub('"', '"') + s = s:gsub('<', '<') + return s +end + +local link_database + +-- Handle image references +local function images(text) + local function reference_link(alt, id) + alt = encode_alt(alt:match("%b[]"):sub(2,-2)) + id = id:match("%[(.*)%]"):lower() + if id == "" then id = text:lower() end + link_database[id] = link_database[id] or {} + if not link_database[id].url then return nil end + local url = link_database[id].url or id + url = encode_alt(url) + local title = encode_alt(link_database[id].title) + if title then title = " title=\"" .. title .. "\"" else title = "" end + return add_escape ('<img src="' .. url .. '" alt="' .. alt .. '"' .. title .. "/>") + end + + local function inline_link(alt, link) + alt = encode_alt(alt:match("%b[]"):sub(2,-2)) + local url, title = link:match("%(<?(.-)>?[ \t]*['\"](.+)['\"]") + url = url or link:match("%(<?(.-)>?%)") + url = encode_alt(url) + title = encode_alt(title) + if title then + return add_escape('<img src="' .. url .. '" alt="' .. alt .. '" title="' .. title .. '"/>') + else + return add_escape('<img src="' .. url .. '" alt="' .. alt .. '"/>') + end + end + + text = text:gsub("!(%b[])[ \t]*\n?[ \t]*(%b[])", reference_link) + text = text:gsub("!(%b[])(%b())", inline_link) + return text +end + +-- Handle anchor references +local function anchors(text) + local function reference_link(text, id) + text = text:match("%b[]"):sub(2,-2) + id = id:match("%b[]"):sub(2,-2):lower() + if id == "" then id = text:lower() end + link_database[id] = link_database[id] or {} + if not link_database[id].url then return nil end + local url = link_database[id].url or id + url = encode_alt(url) + local title = encode_alt(link_database[id].title) + if title then title = " title=\"" .. title .. "\"" else title = "" end + return add_escape("<a href=\"" .. url .. "\"" .. title .. ">") .. text .. add_escape("</a>") + end + + local function inline_link(text, link) + text = text:match("%b[]"):sub(2,-2) + local url, title = link:match("%(<?(.-)>?[ \t]*['\"](.+)['\"]") + title = encode_alt(title) + url = url or link:match("%(<?(.-)>?%)") or "" + url = encode_alt(url) + if title then + return add_escape("<a href=\"" .. url .. "\" title=\"" .. title .. "\">") .. text .. "</a>" + else + return add_escape("<a href=\"" .. url .. "\">") .. text .. add_escape("</a>") + end + end + + text = text:gsub("(%b[])[ \t]*\n?[ \t]*(%b[])", reference_link) + text = text:gsub("(%b[])(%b())", inline_link) + return text +end + +-- Handle auto links, i.e. <http://www.google.com/>. +local function auto_links(text) + local function link(s) + return add_escape("<a href=\"" .. s .. "\">") .. s .. "</a>" + end + -- Encode chars as a mix of dec and hex entitites to (perhaps) fool + -- spambots. + local function encode_email_address(s) + -- Use a deterministic encoding to make unit testing possible. + -- Code 45% hex, 45% dec, 10% plain. + local hex = {code = function(c) return "&#x" .. string.format("%x", c:byte()) .. ";" end, count = 1, rate = 0.45} + local dec = {code = function(c) return "&#" .. c:byte() .. ";" end, count = 0, rate = 0.45} + local plain = {code = function(c) return c end, count = 0, rate = 0.1} + local codes = {hex, dec, plain} + local function swap(t,k1,k2) local temp = t[k2] t[k2] = t[k1] t[k1] = temp end + + local out = "" + for i = 1,s:len() do + for _,code in ipairs(codes) do code.count = code.count + code.rate end + if codes[1].count < codes[2].count then swap(codes,1,2) end + if codes[2].count < codes[3].count then swap(codes,2,3) end + if codes[1].count < codes[2].count then swap(codes,1,2) end + + local code = codes[1] + local c = s:sub(i,i) + -- Force encoding of "@" to make email address more invisible. + if c == "@" and code == plain then code = codes[2] end + out = out .. code.code(c) + code.count = code.count - 1 + end + return out + end + local function mail(s) + s = unescape_special_chars(s) + local address = encode_email_address("mailto:" .. s) + local text = encode_email_address(s) + return add_escape("<a href=\"" .. address .. "\">") .. text .. "</a>" + end + -- links + text = text:gsub("<(https?:[^'\">%s]+)>", link) + text = text:gsub("<(ftp:[^'\">%s]+)>", link) + + -- mail + text = text:gsub("<mailto:([^'\">%s]+)>", mail) + text = text:gsub("<([-.%w]+%@[-.%w]+)>", mail) + return text +end + +-- Encode free standing amps (&) and angles (<)... note that this does not +-- encode free >. +local function amps_and_angles(s) + -- encode amps not part of &..; expression + local pos = 1 + while true do + local amp = s:find("&", pos) + if not amp then break end + local semi = s:find(";", amp+1) + local stop = s:find("[ \t\n&]", amp+1) + if not semi or (stop and stop < semi) or (semi - amp) > 15 then + s = s:sub(1,amp-1) .. "&" .. s:sub(amp+1) + pos = amp+1 + else + pos = amp+1 + end + end + + -- encode naked <'s + s = s:gsub("<([^a-zA-Z/?$!])", "<%1") + s = s:gsub("<$", "<") + + -- what about >, nothing done in the original markdown source to handle them + return s +end + +-- Handles emphasis markers (* and _) in the text. +local function emphasis(text) + for _, s in ipairs {"%*%*", "%_%_"} do + text = text:gsub(s .. "([^%s][%*%_]?)" .. s, "<strong>%1</strong>") + text = text:gsub(s .. "([^%s][^<>]-[^%s][%*%_]?)" .. s, "<strong>%1</strong>") + end + for _, s in ipairs {"%*", "%_"} do + text = text:gsub(s .. "([^%s_])" .. s, "<em>%1</em>") + text = text:gsub(s .. "(<strong>[^%s_]</strong>)" .. s, "<em>%1</em>") + text = text:gsub(s .. "([^%s_][^<>_]-[^%s_])" .. s, "<em>%1</em>") + text = text:gsub(s .. "([^<>_]-<strong>[^<>_]-</strong>[^<>_]-)" .. s, "<em>%1</em>") + end + return text +end + +-- Handles line break markers in the text. +local function line_breaks(text) + return text:gsub(" +\n", " <br/>\n") +end + +-- Perform all span level transforms. +function span_transform(text) + text = code_spans(text) + text = escape_special_chars(text) + text = images(text) + text = anchors(text) + text = auto_links(text) + text = amps_and_angles(text) + text = emphasis(text) + text = line_breaks(text) + return text +end + +---------------------------------------------------------------------- +-- Markdown +---------------------------------------------------------------------- + +-- Cleanup the text by normalizing some possible variations to make further +-- processing easier. +local function cleanup(text) + -- Standardize line endings + text = text:gsub("\r\n", "\n") -- DOS to UNIX + text = text:gsub("\r", "\n") -- Mac to UNIX + + -- Convert all tabs to spaces + text = detab(text) + + -- Strip lines with only spaces and tabs + while true do + local subs + text, subs = text:gsub("\n[ \t]+\n", "\n\n") + if subs == 0 then break end + end + + return "\n" .. text .. "\n" +end + +-- Strips link definitions from the text and stores the data in a lookup table. +local function strip_link_definitions(text) + local linkdb = {} + + local function link_def(id, url, title) + id = id:match("%[(.+)%]"):lower() + linkdb[id] = linkdb[id] or {} + linkdb[id].url = url or linkdb[id].url + linkdb[id].title = title or linkdb[id].title + return "" + end + + local def_no_title = "\n ? ? ?(%b[]):[ \t]*\n?[ \t]*<?([^%s>]+)>?[ \t]*" + local def_title1 = def_no_title .. "[ \t]+\n?[ \t]*[\"'(]([^\n]+)[\"')][ \t]*" + local def_title2 = def_no_title .. "[ \t]*\n[ \t]*[\"'(]([^\n]+)[\"')][ \t]*" + local def_title3 = def_no_title .. "[ \t]*\n?[ \t]+[\"'(]([^\n]+)[\"')][ \t]*" + + text = text:gsub(def_title1, link_def) + text = text:gsub(def_title2, link_def) + text = text:gsub(def_title3, link_def) + text = text:gsub(def_no_title, link_def) + return text, linkdb +end + +link_database = {} + +-- Main markdown processing function +local function markdown(text) + init_hash(text) + init_escape_table() + + text = cleanup(text) + text = protect(text) + text, link_database = strip_link_definitions(text) + text = block_transform(text) + text = unescape_special_chars(text) + return text +end + +---------------------------------------------------------------------- +-- End of module +---------------------------------------------------------------------- + +M.lock(M) + +-- Expose markdown function to the world +_G.markdown = M.markdown + +-- Class for parsing command-line options +local OptionParser = {} +OptionParser.__index = OptionParser + +-- Creates a new option parser +function OptionParser:new() + local o = {short = {}, long = {}} + setmetatable(o, self) + return o +end + +-- Calls f() whenever a flag with specified short and long name is encountered +function OptionParser:flag(short, long, f) + local info = {type = "flag", f = f} + if short then self.short[short] = info end + if long then self.long[long] = info end +end + +-- Calls f(param) whenever a parameter flag with specified short and long name is encountered +function OptionParser:param(short, long, f) + local info = {type = "param", f = f} + if short then self.short[short] = info end + if long then self.long[long] = info end +end + +-- Calls f(v) for each non-flag argument +function OptionParser:arg(f) + self.arg = f +end + +-- Runs the option parser for the specified set of arguments. Returns true if all arguments +-- where successfully parsed and false otherwise. +function OptionParser:run(args) + local pos = 1 + local param + while pos <= #args do + local arg = args[pos] + if arg == "--" then + -- luacheck: push ignore 512 + for i=pos+1,#args do + if self.arg then self.arg(args[i]) end + return true + end + -- luacheck: pop + end + if arg:match("^%-%-") then + local info = self.long[arg:sub(3)] + if not info then print("Unknown flag: " .. arg) return false end + if info.type == "flag" then + info.f() + pos = pos + 1 + else + param = args[pos+1] + if not param then print("No parameter for flag: " .. arg) return false end + info.f(param) + pos = pos+2 + end + elseif arg:match("^%-") then + for i=2,arg:len() do + local c = arg:sub(i,i) + local info = self.short[c] + if not info then print("Unknown flag: -" .. c) return false end + if info.type == "flag" then + info.f() + else + if i == arg:len() then + param = args[pos+1] + if not param then print("No parameter for flag: -" .. c) return false end + info.f(param) + pos = pos + 1 + else + param = arg:sub(i+1) + info.f(param) + end + break + end + end + pos = pos + 1 + else + if self.arg then self.arg(arg) end + pos = pos + 1 + end + end + return true +end + +-- Handles the case when markdown is run from the command line +local function run_command_line(arg) + -- Generate output for input s given options + local function run(s, options) + s = markdown(s) + if not options.wrap_header then return s end + local header + if options.header then + local f = io.open(options.header) or error("Could not open file: " .. options.header) + header = f:read("*a") + f:close() + else + header = [[ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html> +<head> + <meta http-equiv="content-type" content="text/html; charset=CHARSET" /> + <title>TITLE</title> + <link rel="stylesheet" type="text/css" href="STYLESHEET" /> +</head> +<body> +]] + local title = options.title or s:match("<h1>(.-)</h1>") or s:match("<h2>(.-)</h2>") or + s:match("<h3>(.-)</h3>") or "Untitled" + header = header:gsub("TITLE", title) + if options.inline_style then + local style = "" + local f = io.open(options.stylesheet) + if f then + style = f:read("*a") f:close() + else + error("Could not include style sheet " .. options.stylesheet .. ": File not found") + end + header = header:gsub('<link rel="stylesheet" type="text/css" href="STYLESHEET" />', + "<style type=\"text/css\"><!--\n" .. style .. "\n--></style>") + else + header = header:gsub("STYLESHEET", options.stylesheet) + end + header = header:gsub("CHARSET", options.charset) + end + local footer = "</body></html>" + if options.footer then + local f = io.open(options.footer) or error("Could not open file: " .. options.footer) + footer = f:read("*a") + f:close() + end + return header .. s .. footer + end + + -- Generate output path name from input path name given options. + local function outpath(path, options) + if options.append then return path .. ".html" end + local m = path:match("^(.+%.html)[^/\\]+$") if m then return m end + m = path:match("^(.+%.)[^/\\]*$") if m and path ~= m .. "html" then return m .. "html" end + return path .. ".html" + end + + -- Default commandline options + local options = { + wrap_header = true, + header = nil, + footer = nil, + charset = "utf-8", + title = nil, + stylesheet = "default.css", + inline_style = false + } + local help = [[ +Usage: markdown.lua [OPTION] [FILE] +Runs the markdown text markup to HTML converter on each file specified on the +command line. If no files are specified, runs on standard input. + +No header: + -n, --no-wrap Don't wrap the output in <html>... tags. +Custom header: + -e, --header FILE Use content of FILE for header. + -f, --footer FILE Use content of FILE for footer. +Generated header: + -c, --charset SET Specifies charset (default utf-8). + -i, --title TITLE Specifies title (default from first <h1> tag). + -s, --style STYLE Specifies style sheet file (default default.css). + -l, --inline-style Include the style sheet file inline in the header. +Generated files: + -a, --append Append .html extension (instead of replacing). +Other options: + -h, --help Print this help text. + -t, --test Run the unit tests. +]] + + local run_stdin = true + local op = OptionParser:new() + op:flag("n", "no-wrap", function () options.wrap_header = false end) + op:param("e", "header", function (x) options.header = x end) + op:param("f", "footer", function (x) options.footer = x end) + op:param("c", "charset", function (x) options.charset = x end) + op:param("i", "title", function(x) options.title = x end) + op:param("s", "style", function(x) options.stylesheet = x end) + op:flag("l", "inline-style", function(x) options.inline_style = true end) + op:flag("a", "append", function() options.append = true end) + op:flag("t", "test", function() + local n = arg[0]:gsub("markdown.lua", "markdown-tests.lua") + local f = io.open(n) + if f then + f:close() dofile(n) + else + error("Cannot find markdown-tests.lua") + end + run_stdin = false + end) + op:flag("h", "help", function() print(help) run_stdin = false end) + op:arg(function(path) + local file = io.open(path) or error("Could not open file: " .. path) + local s = file:read("*a") + file:close() + s = run(s, options) + file = io.open(outpath(path, options), "w") or error("Could not open output file: " .. outpath(path, options)) + file:write(s) + file:close() + run_stdin = false + end + ) + + if not op:run(arg) then + print(help) + run_stdin = false + end + + if run_stdin then + local s = io.read("*a") + s = run(s, options) + io.write(s) + end +end + +-- If we are being run from the command-line, act accordingly +if arg and arg[0]:find("markdown%.lua$") then + run_command_line(arg) +else + return markdown +end diff --git a/Data/Libraries/LDoc/ldoc/markup.lua b/Data/Libraries/LDoc/ldoc/markup.lua new file mode 100644 index 0000000..425fb07 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/markup.lua @@ -0,0 +1,420 @@ +-------------- +-- Handling markup transformation. +-- Currently just does Markdown, but this is intended to +-- be the general module for managing other formats as well. + +local doc = require 'ldoc.doc' +local utils = require 'pl.utils' +local stringx = require 'pl.stringx' +local prettify = require 'ldoc.prettify' +local concat = table.concat +local markup = {} + +local backtick_references + +-- inline <references> use same lookup as @see +local function resolve_inline_references (ldoc, txt, item, plain) + local do_escape = not plain and not ldoc.dont_escape_underscore + local res = (txt:gsub('@{([^}]-)}',function (name) + if name:match '^\\' then return '@{'..name:sub(2)..'}' end + local qname,label = utils.splitv(name,'%s*|') + if not qname then + qname = name + end + local ref, err + local custom_ref, refname = utils.splitv(qname,':') + if custom_ref and ldoc.custom_references then + custom_ref = ldoc.custom_references[custom_ref] + if custom_ref then + ref,err = custom_ref(refname) + end + end + if not ref then + ref,err = markup.process_reference(qname) + end + if not ref then + err = err .. ' ' .. qname + if item and item.warning then item:warning(err) + else + io.stderr:write('nofile error: ',err,'\n') + end + return '???' + end + if not label then + label = ref.label + end + if label and do_escape then -- a nastiness with markdown.lua and underscores + label = label:gsub('_','\\_') + end + local html = ldoc.href(ref) or '#' + label = ldoc.escape(label or qname) + local res = ('<a href="%s">%s</a>'):format(html,label) + return res + end)) + if backtick_references then + res = res:gsub('`([^`]+)`',function(name) + local ref,_ = markup.process_reference(name) + local label = name + if name and do_escape then + label = name:gsub('_', '\\_') + end + label = ldoc.escape(label) + if ref then + return ('<a href="%s">%s</a>'):format(ldoc.href(ref),label) + else + return '<code>'..label..'</code>' + end + end) + end + return res +end + +-- for readme text, the idea here is to create module sections at ## so that +-- they can appear in the contents list as a ToC. +function markup.add_sections(F, txt) + local sections, L, first = {}, 1, true + local title_pat + local lstrip = stringx.lstrip + for line in stringx.lines(txt) do + if first then + local level,header = line:match '^(#+)%s*(.+)' + if level then + level = level .. '#' + else + level = '##' + end + title_pat = '^'..level..'([^#]%s*.+)' + title_pat = lstrip(title_pat) + first = false + F.display_name = header + end + local title = line:match (title_pat) + if title then + --- Windows line endings are the cockroaches of text + title = title:gsub('\r$','') + -- Markdown allows trailing '#'... + title = title:gsub('%s*#+$','') + sections[L] = F:add_document_section(lstrip(title)) + end + L = L + 1 + end + F.sections = sections + return txt +end + +local function indent_line (line) + line = line:gsub('\t',' ') -- support for barbarians ;) + local indent = #line:match '^%s*' + return indent,line +end + +local function blank (line) + return not line:find '%S' +end + +local global_context, local_context + +-- before we pass Markdown documents to markdown/discount, we need to do three things: +-- - resolve any @{refs} and (optionally) `refs` +-- - any @lookup directives that set local context for ref lookup +-- - insert any section ids which were generated by add_sections above +-- - prettify any code blocks + +local function process_multiline_markdown(ldoc, txt, F, filename, deflang) + local res, L, append = {}, 0, table.insert + local err_item = { + warning = function (self,msg) + io.stderr:write(filename..':'..L..': '..msg,'\n') + end + } + local get = stringx.lines(txt) + local getline = function() + L = L + 1 + return get() + end + local function pretty_code (code, lang) + code = concat(code,'\n') + if code ~= '' then + local _ + -- If we omit the following '\n', a '--' (or '//') comment on the + -- last line won't be recognized. + code, _ = prettify.code(lang,filename,code..'\n',L,false) + code = resolve_inline_references(ldoc, code, err_item,true) + append(res,'<pre>') + append(res, code) + append(res,'</pre>') + else + append(res,code) + end + end + local indent,start_indent + local_context = nil + local line = getline() + while line do + local name = line:match '^@lookup%s+(%S+)' + if name then + local_context = name .. '.' + line = getline() + end + local fence = line:match '^```(.*)' + if fence then + local plain = fence=='' + line = getline() + local code = {} + while not line:match '^```' do + if not plain then + append(code, line) + else + append(res, ' '..line) + end + line = getline() + end + pretty_code (code,fence) + line = getline() -- skip fence + if not line then break end + end + indent, line = indent_line(line) + if indent >= 4 then -- indented code block + local code = {} + local plain + while indent >= 4 or blank(line) do + if not start_indent then + start_indent = indent + if line:match '^%s*@plain%s*$' then + plain = true + line = getline() + end + end + if not plain then + append(code,line:sub(start_indent + 1)) + else + append(res,line) + end + line = getline() + if line == nil then break end + indent, line = indent_line(line) + end + start_indent = nil + while #code > 1 and blank(code[#code]) do -- trim blank lines. + table.remove(code) + end + pretty_code (code,deflang) + else + local section = F and F.sections[L] + if section then + append(res,('<a name="%s"></a>'):format(section)) + end + line = resolve_inline_references(ldoc, line, err_item) + append(res,line) + line = getline() + end + end + res = concat(res,'\n') + return res +end + + +-- Handle markdown formatters +-- Try to get the one the user has asked for, but if it's not available, +-- try all the others we know about. If they don't work, fall back to text. + +local function generic_formatter(format) + local ok, f = pcall(require, format) + return ok and f +end + + +local formatters = +{ + markdown = function(format) + local ok, markdown = pcall(require, 'markdown') + if not ok then + print('format: using built-in markdown') + ok, markdown = pcall(require, 'ldoc.markdown') + end + return ok and markdown + end, + discount = function(format) + local ok, markdown = pcall(require, 'discount') + if ok then + -- luacheck: push ignore 542 + if 'function' == type(markdown) then + -- lua-discount by A.S. Bradbury, https://luarocks.org/modules/luarocks/lua-discount + elseif 'table' == type(markdown) and ('function' == type(markdown.compile) or 'function' == type(markdown.to_html)) then + -- discount by Craig Barnes, https://luarocks.org/modules/craigb/discount + -- result of apt-get install lua-discount (links against libmarkdown2) + local mysterious_debian_variant = markdown.to_html ~= nil + markdown = markdown.compile or markdown.to_html + return function(text) + local result, errmsg = markdown(text) + if result then + if mysterious_debian_variant then + return result + else + return result.body + end + else + io.stderr:write('LDoc discount failed with error ',errmsg) + os.exit(1) + end + end + else + ok = false + end + -- luacheck: pop + end + if not ok then + print('format: using built-in markdown') + ok, markdown = pcall(require, 'ldoc.markdown') + end + return ok and markdown + end, + lunamark = function(format) + local ok, lunamark = pcall(require, format) + if ok then + local writer = lunamark.writer.html.new() + local parse = lunamark.reader.markdown.new(writer, + { smart = true }) + return function(text) return parse(text) end + end + end, + commonmark = function(format) + local ok, cmark = pcall(require, 'cmark') + if ok then + return function(text) + local doc = cmark.parse_document(text, string.len(text), cmark.OPT_DEFAULT) + return cmark.render_html(doc, cmark.OPT_DEFAULT) + end + end + end +} + + +local function get_formatter(format) + local used_format = format + local formatter = (formatters[format] or generic_formatter)(format) + if not formatter then -- try another equivalent processor + for name, f in pairs(formatters) do + formatter = f(name) + if formatter then + print('format: '..format..' not found, using '..name) + used_format = name + break + end + end + end + return formatter, used_format +end + +local function text_processor(ldoc) + return function(txt,item) + if txt == nil then return '' end + -- hack to separate paragraphs with blank lines + txt = txt:gsub('\n\n','\n<p>') + return resolve_inline_references(ldoc, txt, item, true) + end +end + +local plain_processor + +local function markdown_processor(ldoc, formatter) + return function (txt,item,plain) + if txt == nil then return '' end + if plain then + if not plain_processor then + plain_processor = text_processor(ldoc) + end + return plain_processor(txt,item) + end + local is_file = utils.is_type(item,doc.File) + local is_module = not is_file and item and doc.project_level(item.type) + if is_file or is_module then + local deflang = 'lua' + if ldoc.parse_extra and ldoc.parse_extra.C then + deflang = 'c' + end + if is_module then + txt = process_multiline_markdown(ldoc, txt, nil, item.file.filename, deflang) + else + txt = process_multiline_markdown(ldoc, txt, item, item.filename, deflang) + end + else + txt = resolve_inline_references(ldoc, txt, item) + end + txt = formatter(txt) + -- We will add our own paragraph tags, if needed. + return (txt:gsub('^%s*<p>(.+)</p>%s*$','%1')) + end +end + +local function get_processor(ldoc, format) + if format == 'plain' then return text_processor(ldoc) end + + local formatter,actual_format = get_formatter(format) + if formatter then + markup.plain = false + -- AFAIK only markdown.lua has underscore-in-identifier problem... + if ldoc.dont_escape_underscore ~= nil then + ldoc.dont_escape_underscore = actual_format ~= 'markdown' + end + return markdown_processor(ldoc, formatter) + end + + print('format: '..format..' not found, falling back to text') + return text_processor(ldoc) +end + + +function markup.create (ldoc, format, pretty, user_keywords) + local processor + markup.plain = true + if format == 'backtick' then + ldoc.backtick_references = true + format = 'plain' + end + backtick_references = ldoc.backtick_references + global_context = ldoc.package and ldoc.package .. '.' + prettify.set_prettifier(pretty) + prettify.set_user_keywords(user_keywords) + + markup.process_reference = function(name,istype) + if local_context == 'none.' and not name:match '%.' then + return nil,'not found' + end + local mod = ldoc.single or ldoc.module or ldoc.modules[1] + local ref,err = mod:process_see_reference(name, ldoc.modules, istype) + if ref then return ref end + if global_context then + local qname = global_context .. name + ref = mod:process_see_reference(qname, ldoc.modules, istype) + if ref then return ref end + end + if local_context then + local qname = local_context .. name + ref = mod:process_see_reference(qname, ldoc.modules, istype) + if ref then return ref end + end + -- note that we'll return the original error! + return ref,err + end + + markup.href = function(ref) + return ldoc.href(ref) + end + + processor = get_processor(ldoc, format) + if not markup.plain and backtick_references == nil then + backtick_references = true + end + + markup.resolve_inline_references = function(txt, errfn) + return resolve_inline_references(ldoc, txt, errfn, markup.plain) + end + markup.processor = processor + prettify.resolve_inline_references = function(txt, errfn) + return resolve_inline_references(ldoc, txt, errfn, true) + end + return processor +end + +return markup diff --git a/Data/Libraries/LDoc/ldoc/parse.lua b/Data/Libraries/LDoc/ldoc/parse.lua new file mode 100644 index 0000000..11ade60 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/parse.lua @@ -0,0 +1,430 @@ +-- parsing code for doc comments + +local utils = require 'pl.utils' +local List = require 'pl.List' +-- local Map = require 'pl.Map' +local stringio = require 'pl.stringio' +local lexer = require 'ldoc.lexer' +local tools = require 'ldoc.tools' +local doc = require 'ldoc.doc' +local Item,File = doc.Item,doc.File +local unpack = utils.unpack + +------ Parsing the Source -------------- +-- This uses the lexer from PL, but it should be possible to use Peter Odding's +-- excellent Lpeg based lexer instead. + +local parse = {} + +local tnext, append = lexer.skipws, table.insert + +-- a pattern particular to LuaDoc tag lines: the line must begin with @TAG, +-- followed by the value, which may extend over several lines. +local luadoc_tag = '^%s*@(%w+)' +local luadoc_tag_value = luadoc_tag..'(.*)' +local luadoc_tag_mod_and_value = luadoc_tag..'%[([^%]]*)%](.*)' + +-- assumes that the doc comment consists of distinct tag lines +local function parse_at_tags(text) + local lines = stringio.lines(text) + local preamble, line = tools.grab_while_not(lines,luadoc_tag) + local tag_items = {} + local follows + while line do + local tag, mod_string, rest = line :match(luadoc_tag_mod_and_value) + if not tag then tag, rest = line :match (luadoc_tag_value) end + local modifiers + if mod_string then + modifiers = { } + for x in mod_string :gmatch "[^,]+" do + local k, v = x :match "^([^=]+)=(.*)$" + if not k then k, v = x, true end -- wuz x, x + modifiers[k] = v + end + end + -- follows: end of current tag + -- line: beginning of next tag (for next iteration) + follows, line = tools.grab_while_not(lines,luadoc_tag) + append(tag_items,{tag, rest .. '\n' .. follows, modifiers}) + end + return preamble,tag_items +end + +--local colon_tag = '%s*(%a+):%s' +local colon_tag = '%s*(%S-):%s' +local colon_tag_value = colon_tag..'(.*)' + +local function parse_colon_tags (text) + local lines = stringio.lines(text) + local preamble, line = tools.grab_while_not(lines,colon_tag) + local tag_items, follows = {} + while line do + local tag, rest = line:match(colon_tag_value) + follows, line = tools.grab_while_not(lines,colon_tag) + local value = rest .. '\n' .. follows + if tag:match '^[%?!]' then + tag = tag:gsub('^!','') + value = tag .. ' ' .. value + tag = 'tparam' + end + append(tag_items,{tag, value}) + end + return preamble,tag_items +end + +-- Tags are stored as an ordered multi map from strings to strings +-- If the same key is used, then the value becomes a list +local Tags = {} +Tags.__index = Tags + +function Tags.new (t,name) + local class + if name then + class = t + t = {} + end + t._order = List() + local tags = setmetatable(t,Tags) + if name then + tags:add('class',class) + tags:add('name',name) + end + return tags +end + +function Tags:add (tag,value,modifiers) + if modifiers then -- how modifiers are encoded + value = {value,modifiers=modifiers} + end + local ovalue = self:get(tag) + if ovalue then + ovalue:append(value) + value = ovalue + end + rawset(self,tag,value) + if not ovalue then + self._order:append(tag) + end +end + +function Tags:get (tag) + local ovalue = rawget(self,tag) + if ovalue then -- previous value? + if getmetatable(ovalue) ~= List then + ovalue = List{ovalue} + end + return ovalue + end +end + +function Tags:iter () + return self._order:iter() +end + +local function comment_contains_tags (comment,args) + return (args.colon and comment:find ': ') or (not args.colon and comment:find '@') +end + +-- This takes the collected comment block, and uses the docstyle to +-- extract tags and values. Assume that the summary ends in a period or a question +-- mark, and everything else in the preamble is the description. +-- If a tag appears more than once, then its value becomes a list of strings. +-- Alias substitution and @TYPE NAME shortcutting is handled by Item.check_tag +local function extract_tags (s,args) + local preamble,tag_items + if s:match '^%s*$' then return {} end + if args.colon then --and s:match ':%s' and not s:match '@%a' then + preamble,tag_items = parse_colon_tags(s) + else + preamble,tag_items = parse_at_tags(s) + end + local strip = tools.strip + local summary, description = preamble:match('^(.-[%.?])(%s.+)') + if not summary then + -- perhaps the first sentence did not have a . or ? terminating it. + -- Then try split at linefeed + summary, description = preamble:match('^(.-\n\n)(.+)') + if not summary then + summary = preamble + end + end -- and strip(description) ? + local tags = Tags.new{summary=summary and strip(summary) or '',description=description or ''} + for _,item in ipairs(tag_items) do + local tag, value, modifiers = Item.check_tag(tags,unpack(item)) + -- treat multiline values more gently.. + if not value:match '\n[^\n]+\n' then + value = strip(value) + end + + tags:add(tag,value,modifiers) + end + return tags --Map(tags) +end + + +-- parses a Lua or C file, looking for ldoc comments. These are like LuaDoc comments; +-- they start with multiple '-'. (Block commments are allowed) +-- If they don't define a name tag, then by default +-- it is assumed that a function definition follows. If it is the first comment +-- encountered, then ldoc looks for a call to module() to find the name of the +-- module if there isn't an explicit module name specified. + +local function parse_file(fname, lang, package, args) + local F = File(fname) + local module_found, first_comment = false,true + local current_item, module_item + + F.args = args + F.lang = lang + F.base = package + + local tok,f = lang.lexer(fname) + if not tok then return nil end + + local function lineno () + return tok:lineno() + end + + function F:warning (msg,kind,line) + line = line or lineno() + Item.had_warning = true + io.stderr:write(fname..':'..line..': '..msg,'\n') + end + + function F:error (msg) + self:warning(msg,'error') + io.stderr:write('LDoc error\n') + os.exit(1) + end + + local function add_module(tags,module_found,old_style) + tags:add('name',module_found) + tags:add('class','module') + local item = F:new_item(tags,lineno()) + item.old_style = old_style + module_item = item + end + + local mod + local t,v = tnext(tok) + -- with some coding styles first comment is standard boilerplate; option to ignore this. + if args.boilerplate and t == 'comment' then + -- hack to deal with boilerplate inside Lua block comments + if v:match '%s*%-%-%[%[' then lang:grab_block_comment(v,tok) end + t,v = tnext(tok) + end + if t == '#' then -- skip Lua shebang line, if present + while t and t ~= 'comment' do t,v = tnext(tok) end + if t == nil then + F:warning('empty file') + return nil + end + end + if lang.parse_module_call and t ~= 'comment' then + local prev_token + while t do + if prev_token ~= '.' and prev_token ~= ':' and t == 'iden' and v == 'module' then + break + end + prev_token = t + t, v = tnext(tok) + end + if not t then + if not args.ignore then + F:warning("no module() call found; no initial doc comment") + end + --return nil + else + mod,t,v = lang:parse_module_call(tok,t,v) + if mod and mod ~= '...' then + add_module(Tags.new{summary='(no description)'},mod,true) + first_comment = false + module_found = true + end + end + end + local ok, err = xpcall(function() + while t do + if t == 'comment' then + local comment = {} + local ldoc_comment,block = lang:start_comment(v) + + if ldoc_comment and block then + t,v = lang:grab_block_comment(v,tok) + end + + if lang:empty_comment(v) then -- ignore rest of empty start comments + t,v = tok() + if t == 'space' and not v:match '\n' then + t,v = tok() + end + end + + while t and t == 'comment' do + v = lang:trim_comment(v) + append(comment,v) + t,v = tok() + if t == 'space' and not v:match '\n' then + t,v = tok() + end + end + + if t == 'space' then t,v = tnext(tok) end + + local item_follows, tags, is_local, case, parse_error + if ldoc_comment then + comment = table.concat(comment) + if comment:match '^%s*$' then + ldoc_comment = nil + end + end + if ldoc_comment then + if first_comment then + first_comment = false + else + item_follows, is_local, case = lang:item_follows(t,v,tok) + if not item_follows then + parse_error = is_local + is_local = false + end + end + + if item_follows or comment_contains_tags(comment,args) then + tags = extract_tags(comment,args) + + -- explicitly named @module (which is recommended) + if doc.project_level(tags.class) then + module_found = tags.name + -- might be a module returning a single function! + if tags.param or tags['return'] then + local parms, ret = tags.param, tags['return'] + local name = tags.name + tags.param = nil + tags['return'] = nil + tags['class'] = nil + tags['name'] = nil + add_module(tags,name,false) + tags = { + summary = '', + name = 'returns...', + class = 'function', + ['return'] = ret, + param = parms + } + end + end + doc.expand_annotation_item(tags,current_item) + -- if the item has an explicit name or defined meaning + -- then don't continue to do any code analysis! + -- Watch out for the case where there are field or param tags + -- but no class, since these will be fixed up later as module/class + -- entities + if (tags.field or tags.param) and not tags.class then + parse_error = false + end + if tags.name then + if not tags.class then + F:warning("no type specified, assuming function: '"..tags.name.."'") + tags:add('class','function') + end + item_follows, is_local, parse_error = false, false, false + elseif args.no_args_infer then + F:error("No name and type provided (no_args_infer)") + elseif lang:is_module_modifier (tags) then + if not item_follows then + F:warning("@usage or @export followed by unknown code") + break + end + item_follows(tags,tok) + local res, value, tagname = lang:parse_module_modifier(tags,tok,F) + if not res then F:warning(value); break + else + if tagname then + module_item:set_tag(tagname,value) + end + -- don't continue to make an item! + ldoc_comment = false + end + end + end + if parse_error then + F:warning('definition cannot be parsed - '..parse_error) + end + end + -- some hackery necessary to find the module() call + if not module_found and ldoc_comment then + local old_style + module_found,t,v = lang:find_module(tok,t,v) + -- right, we can add the module object ... + old_style = module_found ~= nil + if not module_found or module_found == '...' then + -- we have to guess the module name + module_found = tools.this_module_name(package,fname) + end + if not tags then tags = extract_tags(comment,args) end + add_module(tags,module_found,old_style) + tags = nil + if not t then + F:warning('contains no items','warning',1) + break; + end -- run out of file! + -- if we did bump into a doc comment, then we can continue parsing it + end + + -- end of a block of document comments + if ldoc_comment and tags then + local line = lineno() + if t ~= nil then + if item_follows then -- parse the item definition + local err = item_follows(tags,tok) + if err then F:error(err) end + elseif parse_error then + F:warning('definition cannot be parsed - '..parse_error) + else + lang:parse_extra(tags,tok,case) + end + end + if is_local or tags['local'] then + tags:add('local',true) + end + -- support for standalone fields/properties of classes/modules + if (tags.field or tags.param) and not tags.class then + -- the hack is to take a subfield and pull out its name, + -- (see Tag:add above) but let the subfield itself go through + -- with any modifiers. + local fp = tags.field or tags.param + if type(fp) == 'table' then fp = fp[1] end + fp = tools.extract_identifier(fp) + tags:add('name',fp) + tags:add('class','field') + end + if tags.name then + current_item = F:new_item(tags,line) + current_item.inferred = item_follows ~= nil + if doc.project_level(tags.class) then + if module_item then + F:error("Module already declared!") + end + module_item = current_item + end + end + if not t then break end + end + end + if t ~= 'comment' then t,v = tok() end + end + end,debug.traceback) + if not ok then return F, err end + if f then f:close() end + return F +end + +function parse.file(name,lang, args) + local F,err = parse_file(name,lang,args.package,args) + if err or not F then return F,err end + local ok,err = xpcall(function() F:finish() end,debug.traceback) + if not ok then return F,err end + return F +end + +return parse diff --git a/Data/Libraries/LDoc/ldoc/prettify.lua b/Data/Libraries/LDoc/ldoc/prettify.lua new file mode 100644 index 0000000..1dc625c --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/prettify.lua @@ -0,0 +1,131 @@ +-- Making Lua source code look pretty. +-- A simple scanner based prettifier, which scans comments for @{ref} and code +-- for known modules and functions. +-- A module reference to an example `test-fun.lua` would look like +-- `@{example:test-fun}`. +local List = require 'pl.List' +local tablex = require 'pl.tablex' +local globals = require 'ldoc.builtin.globals' +local prettify = {} + +local user_keywords = {} + +local escaped_chars = { + ['&'] = '&', + ['<'] = '<', + ['>'] = '>', +} +local escape_pat = '[&<>]' + +local function escape(str) + return (str:gsub(escape_pat,escaped_chars)) +end + +local function span(t,val) + return ('<span class="%s">%s</span>'):format(t,val) +end + +local spans = {keyword=true,number=true,string=true,comment=true,global=true,backtick=true} + +local cpp_lang = {C = true, c = true, cpp = true, cxx = true, h = true} + +function prettify.lua (lang, fname, code, initial_lineno, pre, linenos) + local res, lexer = List(), require 'ldoc.lexer' + local tokenizer + local ik = 1 + if not cpp_lang[lang] then + tokenizer = lexer.lua + else + tokenizer = lexer.cpp + end + + if pre then + res:append '<pre>\n' + end + initial_lineno = initial_lineno or 0 + + local tok = tokenizer(code,{},{}) + local error_reporter = { + warning = function (self,msg) + io.stderr:write(fname..':'..tok:lineno()+initial_lineno..': '..msg,'\n') + end + } + local last_t, last_val + local t,val = tok() + if not t then return nil,"empty file" end + while t do + val = escape(val) + if linenos and tok:lineno() == linenos[ik] then + res:append('<a id="'..linenos[ik]..'"></a>') + ik = ik + 1 + end + if globals.functions[val] or globals.tables[val] then + t = 'global' + end + if user_keywords[val] then + res:append(span('user-keyword keyword-' .. val,val)) + elseif spans[t] then + if t == 'comment' or t == 'backtick' then -- may contain @{ref} or `..` + val = prettify.resolve_inline_references(val,error_reporter) + end + res:append(span(t,val)) + else + res:append(val) + end + last_t, last_val = t,val + t,val = tok() + end + if last_t == 'comment' then + res[#res] = span('comment',last_val:gsub('\r*\n$','')) + end + local last = res[#res] + if last:match '\n$' then + res[#res] = last:gsub('\n+','') + end + if pre then + res:append '</pre>\n' + end + return res:join () +end + +local lxsh + +local lxsh_highlighers = {bib=true,c=true,lua=true,sh=true} + +function prettify.code (lang,fname,code,initial_lineno,pre) + if not lxsh then + return prettify.lua (lang,fname, code, initial_lineno, pre) + else + if not lxsh_highlighers[lang] then + lang = 'lua' + end + code = lxsh.highlighters[lang](code, { + formatter = lxsh.formatters.html, + external = true + }) + if not pre then + code = code:gsub("^<pre.->(.-)%s*</pre>$", '%1') + end + return code + end +end + +function prettify.set_prettifier (pretty) + local ok + if pretty == 'lxsh' then + ok,lxsh = pcall(require,'lxsh') + if not ok then + print('pretty: '..pretty..' not found, using built-in Lua') + lxsh = nil + end + end +end + +function prettify.set_user_keywords(keywords) + if keywords then + user_keywords = tablex.makeset(keywords) + end +end + +return prettify + diff --git a/Data/Libraries/LDoc/ldoc/tools.lua b/Data/Libraries/LDoc/ldoc/tools.lua new file mode 100644 index 0000000..6918dab --- /dev/null +++ b/Data/Libraries/LDoc/ldoc/tools.lua @@ -0,0 +1,542 @@ +--------- +-- General utility functions for ldoc +-- @module tools + +local class = require 'pl.class' +local List = require 'pl.List' +local path = require 'pl.path' +local utils = require 'pl.utils' +local tablex = require 'pl.tablex' +local stringx = require 'pl.stringx' +local dir = require 'pl.dir' +local tools = {} +local M = tools +local append = table.insert +local lexer = require 'ldoc.lexer' +local quit = utils.quit + +-- at rendering time, can access the ldoc table from any module item, +-- or the item itself if it's a module +function M.item_ldoc (item) + local mod = item and (item.module or item) + return mod and mod.ldoc +end + +-- this constructs an iterator over a list of objects which returns only +-- those objects where a field has a certain value. It's used to iterate +-- only over functions or tables, etc. If the list of item has a module +-- with a context, then use that to pre-sort the fltered items. +-- (something rather similar exists in LuaDoc) +function M.type_iterator (list,field,value) + return function() + local fls = list:filter(function(item) + return item[field] == value + end) + local ldoc = M.item_ldoc(fls[1]) + if ldoc and ldoc.sort then + fls:sort(function(ia,ib) + return ia.name < ib.name + end) + end + return fls:iter() + end +end + +-- KindMap is used to iterate over a set of categories, called _kinds_, +-- and the associated iterator over all items in that category. +-- For instance, a module contains functions, tables, etc and we will +-- want to iterate over these categories in a specified order: +-- +-- for kind, items in module.kinds() do +-- print('kind',kind) +-- for item in items() do print(item.name) end +-- end +-- +-- The kind is typically used as a label or a Title, so for type 'function' the +-- kind is 'Functions' and so on. + +local KindMap = class() +M.KindMap = KindMap + +-- calling a KindMap returns an iterator. This returns the kind, the iterator +-- over the items of that type, and the actual type tag value. +function KindMap:__call () + local i = 1 + local klass = self.klass + return function() + local kind = klass.kinds[i] + if not kind then return nil end -- no more kinds + while not self[kind] do + i = i + 1 + kind = klass.kinds[i] + if not kind then return nil end + end + i = i + 1 + local type = klass.types_by_kind [kind].type + return kind, self[kind], type + end +end + +function KindMap:put_kind_first (kind) + -- find this kind in our kind list + local kinds = self.klass.kinds + local idx = tablex.find(kinds,kind) + -- and swop with the start! + if idx then + kinds[1],kinds[idx] = kinds[idx],kinds[1] + end +end + +function KindMap:type_of (item) + local klass = self.klass + local kind = klass.types_by_tag[item.type] + return klass.types_by_kind [kind] +end + +function KindMap:get_section_description (kind) + return self.klass.descriptions[kind] +end + +function KindMap:get_item (kind) + return self.klass.items_by_kind[kind] +end + +-- called for each new item. It does not actually create separate lists, +-- (although that would not break the interface) but creates iterators +-- for that item type if not already created. +function KindMap:add (item,items,description) + local group = item[self.fieldname] -- which wd be item's type or section + local kname = self.klass.types_by_tag[group] -- the kind name + if not self[kname] then + self[kname] = M.type_iterator (items,self.fieldname,group) + self.klass.descriptions[kname] = description + end + item.kind = kname:lower() +end + +-- KindMap has a 'class constructor' which is used to modify +-- any new base class. +function KindMap._class_init (klass) + klass.kinds = {} -- list in correct order of kinds + klass.types_by_tag = {} -- indexed by tag + klass.types_by_kind = {} -- indexed by kind + klass.descriptions = {} -- optional description for each kind + klass.items_by_kind = {} -- some kinds are items +end + + +function KindMap.add_kind (klass,tag,kind,subnames,item) + if not klass.types_by_kind[kind] then + klass.types_by_tag[tag] = kind + klass.types_by_kind[kind] = {type=tag,subnames=subnames} + if item then + klass.items_by_kind[kind] = item + end + append(klass.kinds,kind) + end +end + +----- some useful utility functions ------ + +function M.module_basepath() + local lpath = List.split(package.path,';') + for p in lpath:iter() do + local p = path.dirname(p) + if path.isabs(p) then + return p + end + end +end + +-- split a qualified name into the module part and the name part, +-- e.g 'pl.utils.split' becomes 'pl.utils' and 'split'. Also +-- must understand colon notation! +function M.split_dotted_name (s) + local s1,s2 = s:match '^(.+)[%.:](.+)$' + if s1 then -- we can split + return s1,s2 + else + return nil + end +--~ local s1,s2 = path.splitext(s) +--~ if s2=='' then return nil +--~ else return s1,s2:sub(2) +--~ end +end + +-- grab lines from a line iterator `iter` until the line matches the pattern. +-- Returns the joined lines and the line, which may be nil if we run out of +-- lines. +function M.grab_while_not(iter,pattern) + local line = iter() + local res = {} + while line and not line:match(pattern) do + append(res,line) + line = iter() + end + res = table.concat(res,'\n') + return res,line +end + + +function M.extract_identifier (value) + return value:match('([%.:%-_%w]+)(.*)$') +end + +function M.identifier_list (ls) + local ns = List() + if type(ls) == 'string' then ls = List{ns} end + for s in ls:iter() do + if s:match ',' then + ns:extend(List.split(s,'[,%s]+')) + else + ns:append(s) + end + end + return ns +end + +function M.strip (s) + return s:gsub('^%s+',''):gsub('%s+$','') +end + +-- Joins strings using a separator. +-- +-- Empty strings and nil arguments are ignored: +-- +-- assert(join('+', 'one', '', 'two', nil, 'three') == 'one+two+three') +-- assert(join(' ', '', '') == '') +-- +-- This is especially useful for the last case demonstrated above, +-- where "conventional" solutions (".." or table.concat) would result +-- in a spurious space. +function M.join(sep, ...) + local contents = {} + for i = 1, select('#', ...) do + local value = select(i, ...) + if value and value ~= "" then + contents[#contents + 1] = value + end + end + return table.concat(contents, sep) +end + +function M.check_directory(d) + if not path.isdir(d) then + if not dir.makepath(d) then + quit("Could not create "..d.." directory") + end + end +end + +function M.check_file (f,original) + if not path.exists(f) or path.getmtime(original) > path.getmtime(f) then + local text,err = utils.readfile(original) + local _ + if text then + _,err = utils.writefile(f,text) + end + if err then + quit("Could not copy "..original.." to "..f) + end + end +end + +function M.writefile(name,text) + local f,err = io.open(name,"wb") +--~ local ok,err = utils.writefile(name,text) + if err then quit(err) end + f:write(text) + f:close() +end + +function M.name_of (lpath) + local _ + lpath,_ = path.splitext(lpath) + return lpath +end + +function M.this_module_name (basename,fname) + if basename == '' then + return M.name_of(fname) + end + basename = path.abspath(basename) + if basename:sub(-1,-1) ~= path.sep then + basename = basename..path.sep + end + local lpath,cnt = fname:gsub('^'..utils.escape(basename),'') + --print('deduce',lpath,cnt,basename) + if cnt ~= 1 then quit("module(...) name deduction failed: base "..basename.." "..fname) end + lpath = lpath:gsub(path.sep,'.') + return (M.name_of(lpath):gsub('%.init$','')) +end + +function M.find_existing_module (name, dname, searchfn) + local fullpath,lua = searchfn(name) + local mod = true + if not fullpath then -- maybe it's a function reference? + -- try again with the module part + local mpath,fname = M.split_dotted_name(name) + if mpath then + fullpath,lua = searchfn(mpath) + else + fullpath = nil + end + if not fullpath then + return nil, "module or function '"..dname.."' not found on module path" + else + mod = fname + end + end + if not lua then return nil, "module '"..name.."' is a binary extension" end + return fullpath, mod +end + +function M.lookup_existing_module_or_function (name, docpath) + -- first look up on the Lua module path + local on_docpath + local fullpath, mod = M.find_existing_module(name,name,path.package_path) + -- no go; but see if we can find it on the doc path + if not fullpath then + fullpath, mod = M.find_existing_module("ldoc.builtin." .. name,name,path.package_path) + on_docpath = true +--~ fullpath, mod = M.find_existing_module(name, function(name) +--~ local fpath = package.searchpath(name,docpath) +--~ return fpath,true -- result must always be 'lua'! +--~ end) + end + return fullpath, mod, on_docpath -- `mod` can be the error message +end + + +--------- lexer tools ----- + +local tnext = lexer.skipws + +local function type_of (tok) return tok and tok[1] or 'end' end +local function value_of (tok) return tok[2] end + +-- This parses Lua formal argument lists. It will return a list of argument +-- names, which also has a comments field, which will contain any commments +-- following the arguments. ldoc will use these in addition to explicit +-- param tags. + +function M.get_parameters (tok,endtoken,delim,lang) + tok = M.space_skip_getter(tok) + local args = List() + args.comments = {} + local ltl,tt = lexer.get_separated_list(tok,endtoken,delim) + + if not ltl or not ltl[1] or #ltl[1] == 0 then return args end -- no arguments + + local strip_comment, extract_arg + + if lang then + strip_comment = utils.bind1(lang.trim_comment,lang) + extract_arg = utils.bind1(lang.extract_arg,lang) + else + strip_comment = function(text) + return text:match("%s*%-%-+%s*(.*)") + end + extract_arg = function(tl,idx) + idx = idx or 1 + local res = value_of(tl[idx]) + if res == '[' then -- we do allow array indices in tables now + res = '['..value_of(tl[idx + 1])..']' + end + return res + end + end + + local function set_comment (idx,tok) + local text = stringx.rstrip(value_of(tok)) + text = strip_comment(text) + local arg = args[idx] + local current_comment = args.comments[arg] + if current_comment then + text = current_comment .. " " .. text + end + args.comments[arg] = text + end + + local function add_arg (tl,idx) + local name, type = extract_arg(tl,idx) + args:append(name) + if type then + if not args.types then args.types = List() end + args.types:append(type) + end + end + + for i = 1,#ltl do + local tl = ltl[i] -- token list for argument + if #tl > 0 then + local j = 1 + if type_of(tl[1]) == 'comment' then + -- the comments for the i-1 th arg are in the i th arg... + if i > 1 then + while type_of(tl[j]) == 'comment' do + set_comment(i-1,tl[j]) + j = j + 1 + end + else -- first comment however is for the function return comment! + args.return_comment = strip_comment(value_of(tl[i])) + j = j + 1 + end + if #tl > 1 then + add_arg(tl,j) + end + else + add_arg(tl,1) + end + if i == #ltl and #tl > 1 then + while j <= #tl and type_of(tl[j]) ~= 'comment' do + j = j + 1 + end + if j > #tl then break end -- was no comments! + while type_of(tl[j]) == 'comment' do + set_comment(i,tl[j]) + j = j + 1 + end + end + else + return nil,"empty argument" + end + end + + -- we had argument comments + -- but the last one may be outside the parens! (Geoff style) + -- (only try this stunt if it's a function parameter list!) + if (not endtoken or endtoken == ')') and (#args > 0 or next(args.comments)) then + local n = #args + local last_arg = args[n] + if not args.comments[last_arg] then + while true do + tt = {tok()} + if type_of(tt) == 'comment' then + set_comment(n,tt) + else + break + end + end + end + end + -- return what token we ended on as well - can be token _past_ ')' + return args,tt[1],tt[2] +end + +-- parse a Lua identifier - contains names separated by . and (optionally) :. +-- Set `colon` to be the secondary separator, '' for none. +function M.get_fun_name (tok,first,colon) + local res = {} + local t,name,sep,_ + colon = colon or ':' + if not first then + t,name = tnext(tok) + else + t,name = 'iden',first + end + if t ~= 'iden' then return nil end + t,sep = tnext(tok) + while sep == '.' or sep == colon do + append(res,name) + append(res,sep) + _,name = tnext(tok) + t,sep = tnext(tok) + end + append(res,name) + return table.concat(res),t,sep +end + +-- space-skipping version of token iterator +function M.space_skip_getter(tok) + return function () + local t,v = tok() + while t and t == 'space' do + t,v = tok() + end + return t,v + end +end + +function M.quote (s) + return "'"..s.."'" +end + +-- The PL Lua lexer does not do block comments +-- when used in line-grabbing mode, so this function grabs each line +-- until we meet the end of the comment +function M.grab_block_comment (v,tok,patt) + local res = {v} + repeat + v = lexer.getline(tok) + if v:match (patt) then break end + append(res,v) + append(res,'\n') + until false + res = table.concat(res) + --print(res) + return 'comment',res +end + +local prel = path.normcase('/[^/]-/%.%.') + + +function M.abspath (f) + local count + local res = path.normcase(path.abspath(f)) + while true do + res,count = res:gsub(prel,'') + if count == 0 then break end + end + return res +end + +function M.getallfiles(root,mask) + local res = List(dir.getallfiles(root,mask)) + res:sort() + return res +end + +function M.expand_file_list (list, mask) + local exclude_list = list.exclude and M.files_from_list(list.exclude, mask) + local files = List() + local function process (f) + f = M.abspath(f) + if not exclude_list or exclude_list and exclude_list:index(f) == nil then + files:append(f) + end + end + for _,f in ipairs(list) do + if path.isdir(f) then + local dfiles = M.getallfiles(f,mask) + for f in dfiles:iter() do + process(f) + end + elseif path.isfile(f) then + process(f) + else + quit("file or directory does not exist: "..M.quote(f)) + end + end + return files +end + +function M.process_file_list (list, mask, operation, ...) + local files = M.expand_file_list(list,mask) + for f in files:iter() do + operation(f,...) + end +end + +function M.files_from_list (list, mask) + local excl = List() + M.process_file_list (list, mask, function(f) + excl:append(f) + end) + return excl +end + + + +return tools diff --git a/Data/Libraries/LDoc/run-tests.lua b/Data/Libraries/LDoc/run-tests.lua new file mode 100644 index 0000000..062c431 --- /dev/null +++ b/Data/Libraries/LDoc/run-tests.lua @@ -0,0 +1,20 @@ +local PWD = os.getenv("PWD") + +local run +if not arg[1] then + run = function (dir) + local cmd = 'cd '..dir..' && lua '..PWD..'/ldoc.lua --testing . && diff -r doc cdocs' + print(cmd) + os.execute(cmd) + end +elseif arg[1] == 'update' then + run = function (dir) + local cmd = 'cd '..dir..' && lua '..PWD..'/ldoc.lua --dir cdocs --testing .' + print(cmd) + os.execute(cmd) + end +end + +for _,d in ipairs{'tests','tests/example','tests/md-test'} do + run(d) +end diff --git a/Data/Libraries/LDoc/tests/annot/annot.lua b/Data/Libraries/LDoc/tests/annot/annot.lua new file mode 100644 index 0000000..7ebc278 --- /dev/null +++ b/Data/Libraries/LDoc/tests/annot/annot.lua @@ -0,0 +1,21 @@ +---------------- +-- Testing annotations +-- @module annot + +--- first fun. +function first() + if boo then + local bar = do_something() + if bar then + --- @fixme otherwise do what? + end + end +end + +--- second try. +function second() + --- @todo also handle foo case + if bar then + + end +end diff --git a/Data/Libraries/LDoc/tests/bad.lua b/Data/Libraries/LDoc/tests/bad.lua new file mode 100644 index 0000000..70df107 --- /dev/null +++ b/Data/Libraries/LDoc/tests/bad.lua @@ -0,0 +1,13 @@ +------- +-- @module bad + +local bad = {} + +-------- +-- inference fails! Have to explicitly +-- declare the function and its arguments +bad['entry'] = function(one) +end + +return bad + diff --git a/Data/Libraries/LDoc/tests/classes.lua b/Data/Libraries/LDoc/tests/classes.lua new file mode 100644 index 0000000..6248b23 --- /dev/null +++ b/Data/Libraries/LDoc/tests/classes.lua @@ -0,0 +1,25 @@ +---------------------- +-- a module containing some classes. +-- @module classes + +local _M = {} + +---- a useful class. +-- @type Bonzo + +_M.Bonzo = class() + +--- a method. +-- function one; reference to @{one.md.classes|documentation} +function Bonzo:one() + +end + +--- a metamethod +-- function __tostring +function Bonzo:__tostring() + +end + +return M + diff --git a/Data/Libraries/LDoc/tests/complex/lua/complex/convert/basic.lua b/Data/Libraries/LDoc/tests/complex/lua/complex/convert/basic.lua new file mode 100644 index 0000000..b11572c --- /dev/null +++ b/Data/Libraries/LDoc/tests/complex/lua/complex/convert/basic.lua @@ -0,0 +1,6 @@ +--- oh. + +--- convert. +function M.convert () + +end diff --git a/Data/Libraries/LDoc/tests/complex/lua/complex/display.lua b/Data/Libraries/LDoc/tests/complex/lua/complex/display.lua new file mode 100644 index 0000000..c184775 --- /dev/null +++ b/Data/Libraries/LDoc/tests/complex/lua/complex/display.lua @@ -0,0 +1,10 @@ +--- dee. + +--- display this. +function M.display_this() +end + +--- display that. +-- @see display_this +function M.display_that() +end diff --git a/Data/Libraries/LDoc/tests/complex/lua/complex/init.lua b/Data/Libraries/LDoc/tests/complex/lua/complex/init.lua new file mode 100644 index 0000000..25b2393 --- /dev/null +++ b/Data/Libraries/LDoc/tests/complex/lua/complex/init.lua @@ -0,0 +1,12 @@ +--- doo + +--- start. +function M.start() +end + +--- run. +-- @see complex.display.display_this +function M.run() +end + + diff --git a/Data/Libraries/LDoc/tests/complex/lua/complex/util/init.lua b/Data/Libraries/LDoc/tests/complex/lua/complex/util/init.lua new file mode 100644 index 0000000..1d068d3 --- /dev/null +++ b/Data/Libraries/LDoc/tests/complex/lua/complex/util/init.lua @@ -0,0 +1,7 @@ +--- wo. + +--- open. +-- @see convert.basic +function M.open () + +end diff --git a/Data/Libraries/LDoc/tests/complex/lua/complex/util/parse.lua b/Data/Libraries/LDoc/tests/complex/lua/complex/util/parse.lua new file mode 100644 index 0000000..6078c47 --- /dev/null +++ b/Data/Libraries/LDoc/tests/complex/lua/complex/util/parse.lua @@ -0,0 +1,7 @@ +--- wee + +--- parse. +-- @see util.open +function M.parse () + +end diff --git a/Data/Libraries/LDoc/tests/config.ld b/Data/Libraries/LDoc/tests/config.ld new file mode 100644 index 0000000..4c9cbae --- /dev/null +++ b/Data/Libraries/LDoc/tests/config.ld @@ -0,0 +1,5 @@ +format='markdown' +project = 'Basic Example' +file = {'types.lua','classes.lua'} +use_markdown_titles=true +topics = {'one.md','two.md'} diff --git a/Data/Libraries/LDoc/tests/easy/easy.lua b/Data/Libraries/LDoc/tests/easy/easy.lua new file mode 100644 index 0000000..00dca97 --- /dev/null +++ b/Data/Libraries/LDoc/tests/easy/easy.lua @@ -0,0 +1,8 @@ +--- simplified LDoc colon style. +-- You have to use -C flag or 'colon=true' for this one! +module 'easy' + +--- First one. +-- string: name +-- int: age +function first(name,age) end diff --git a/Data/Libraries/LDoc/tests/example/config.ld b/Data/Libraries/LDoc/tests/example/config.ld new file mode 100644 index 0000000..f0d8a38 --- /dev/null +++ b/Data/Libraries/LDoc/tests/example/config.ld @@ -0,0 +1,14 @@ +-- ldoc configuration file +title = "testmod docs" +project = "testmod" + +description = [[ +This description applies to the project as a whole. +]] + +alias("p","param") + +file = {'mod1.lua','modtest.lua','mylib.c'} + +new_type("macro","Macros") + diff --git a/Data/Libraries/LDoc/tests/example/laurent/config.ld b/Data/Libraries/LDoc/tests/example/laurent/config.ld new file mode 100644 index 0000000..5f4b8ae --- /dev/null +++ b/Data/Libraries/LDoc/tests/example/laurent/config.ld @@ -0,0 +1,3 @@ +style = true +template = true +file = 'mod1.lua' diff --git a/Data/Libraries/LDoc/tests/example/laurent/ldoc.css b/Data/Libraries/LDoc/tests/example/laurent/ldoc.css new file mode 100644 index 0000000..7c9023d --- /dev/null +++ b/Data/Libraries/LDoc/tests/example/laurent/ldoc.css @@ -0,0 +1,271 @@ +/* BEGIN RESET + +Copyright (c) 2010, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.com/yui/license.html +version: 2.8.2r1 +*/ +html { + color: #000; + background: #FFF; +} +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 { + margin: 0; + padding: 0; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +fieldset,img { + border: 0; +} +address,caption,cite,code,dfn,em,strong,th,var,optgroup { + font-style: inherit; + font-weight: inherit; +} +del,ins { + text-decoration: none; +} +li { + list-style: bullet; + margin-left: 20px; +} +caption,th { + text-align: left; +} +h1,h2,h3,h4,h5,h6 { + font-size: 100%; + font-weight: bold; +} +q:before,q:after { + content: ''; +} +abbr,acronym { + border: 0; + font-variant: normal; +} +sup { + vertical-align: baseline; +} +sub { + vertical-align: baseline; +} +legend { + color: #000; +} +input,button,textarea,select,optgroup,option { + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; +} +input,button,textarea,select {*font-size:100%; +} +/* END RESET */ + +body { + margin-left: 1em; + margin-right: 1em; + font-family: arial, helvetica, geneva, sans-serif; + background-color: #ffffff; margin: 0px; +} + +code, tt { font-family: monospace; } + +body, p, td, th { font-size: .95em; line-height: 1.2em;} + +p, ul { margin: 10px 0 0 10px;} + +strong { font-weight: bold;} + +em { font-style: italic;} + +h1 { + font-size: 1.5em; + margin: 0 0 20px 0; +} +h2, h3, h4 { margin: 15px 0 10px 0; } +h2 { font-size: 1.25em; } +h3 { font-size: 1.15em; } +h4 { font-size: 1.06em; } + +a:link { font-weight: bold; color: #004080; text-decoration: none; } +a:visited { font-weight: bold; color: #006699; text-decoration: none; } +a:link:hover { text-decoration: underline; } + +hr { + color:#cccccc; + background: #00007f; + height: 1px; +} + +blockquote { margin-left: 3em; } + +ul { list-style-type: disc; } + +p.name { + font-family: "Andale Mono", monospace; + padding-top: 1em; +} + +pre.example { + background-color: rgb(245, 245, 245); + border: 1px solid silver; + padding: 10px; + margin: 10px 0 10px 0; + font-family: "Andale Mono", monospace; + font-size: .85em; +} + +pre { + background-color: rgb(245, 245, 245); + border: 1px solid silver; + padding: 10px; + margin: 10px 0 10px 0; + font-family: "Andale Mono", monospace; +} + + +table.index { border: 1px #00007f; } +table.index td { text-align: left; vertical-align: top; } + +#container { + margin-left: 1em; + margin-right: 1em; + background-color: #f0f0f0; +} + +#product { + text-align: center; + border-bottom: 1px solid #cccccc; + background-color: #ffffff; +} + +#product big { + font-size: 2em; +} + +#main { + background-color: #f0f0f0; + border-left: 2px solid #cccccc; +} + +#navigation { + float: left; + width: 18em; + vertical-align: top; + background-color: #f0f0f0; + overflow: visible; + position: fixed; +} + +#navigation h2 { + background-color:#e7e7e7; + font-size:1.1em; + color:#000000; + text-align: left; + padding:0.2em; + border-top:1px solid #dddddd; + border-bottom:1px solid #dddddd; +} + +#navigation ul +{ + font-size:1em; + list-style-type: none; + margin: 1px 1px 10px 1px; +} + +#navigation li { + text-indent: -1em; + display: block; + margin: 3px 0px 0px 22px; +} + +#navigation li li a { + margin: 0px 3px 0px -1em; +} + +#content { + margin-left: 18em; + padding: 1em; + border-left: 2px solid #cccccc; + border-right: 2px solid #cccccc; + background-color: #ffffff; +} + +#about { + clear: both; + padding: 5px; + border-top: 2px solid #cccccc; + background-color: #ffffff; +} + +@media print { + body { + font: 12pt "Times New Roman", "TimeNR", Times, serif; + } + a { font-weight: bold; color: #004080; text-decoration: underline; } + + #main { + background-color: #ffffff; + border-left: 0px; + } + + #container { + margin-left: 2%; + margin-right: 2%; + background-color: #ffffff; + } + + #content { + padding: 1em; + background-color: #ffffff; + } + + #navigation { + display: none; + } + pre.example { + font-family: "Andale Mono", monospace; + font-size: 10pt; + page-break-inside: avoid; + } +} + +table.module_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.module_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.module_list td.name { background-color: #f0f0f0; } +table.module_list td.summary { width: 100%; } + + +table.function_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.function_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.function_list td.name { background-color: #f0f0f0; } +table.function_list td.summary { width: 100%; } + +dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;} +dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;} +dl.table h3, dl.function h3 {font-size: .95em;} + diff --git a/Data/Libraries/LDoc/tests/example/laurent/ldoc.ltp b/Data/Libraries/LDoc/tests/example/laurent/ldoc.ltp new file mode 100644 index 0000000..7e4341b --- /dev/null +++ b/Data/Libraries/LDoc/tests/example/laurent/ldoc.ltp @@ -0,0 +1,201 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> +<head> + <title>$(ldoc.title)</title> + <link rel="stylesheet" href="$(ldoc.css)" type="text/css" /> +</head> +<body> + +<div id="container"> + +<div id="product"> + <div id="product_logo"></div> + <div id="product_name"><big><b></b></big></div> + <div id="product_description"></div> +</div> <!-- id="product" --> + + +<div id="main"> + +# local no_spaces = ldoc.no_spaces +# local use_li = ldoc.use_li +# local display_name = ldoc.display_name +# local iter = ldoc.modules.iter +# local M = ldoc.markup + +<!-- Menu --> + +<div id="navigation"> + +<h1>$(ldoc.project)</h1> + +# if not ldoc.single and module then -- reference back to project index +<ul> + <li><a href="../$(ldoc.output).html">Index</a></li> +</ul> +# else +<p>$(ldoc.description)</p> +# end + + + +# -------- contents of project ---------- +# if not ldoc.no_summary then +# local this_mod = module and module.name +# for kind, mods, type in ldoc.kinds() do +# if not ldoc.kinds_allowed or ldoc.kinds_allowed[type] then +<h2>$(kind)</h2> +<ul> +# for mod in mods() do +# if mod.name == this_mod then -- highlight current module, link to others + <li><strong>$(mod.name)</strong></li> +# else + <li><a href="$(ldoc.ref_to_module(mod))">$(mod.name)</a></li> +# end +# end +# end +#end +</ul> +# else +<ul> +# for kind, items in module.kinds() do +<h2>$(kind)</h2> +# for item in items() do + <li><a href="#$(item.name)">$(display_name(item))</a></li> +# end end +</ul> +#end + +# --------- contents of module ------------- +# if module and not ldoc.no_summary and #module.items > 0 then +<h2>Contents</h2> +<ul> +# for kind,items in module.kinds() do +<li><a href="#$(no_spaces(kind))">$(kind)</a></li> +# end +</ul> +# end + +</div> + +<div id="content"> + +#if module then +<h1>$(ldoc.titlecase(module.type)) <code>$(module.name)</code></h1> +# end + +# if ldoc.body then -- verbatim HTML as contents; 'non-code' entries + $(ldoc.body) +# elseif module then -- module documentation +# ldoc.item = module -- context for M() +<p>$(M(module.summary))</p> +<p>$(M(module.description))</p> + +# if not ldoc.no_summary then +# -- bang out the tables of item types for this module (e.g Functions, Tables, etc) +# for kind,items in module.kinds() do +<h2><a href="#$(no_spaces(kind))">$(kind)</a></h2> +<table class="function_list"> +# for item in items() do + <tr> + <td class="name" nowrap><a href="#$(item.name)">$(display_name(item))</a></td> + <td class="summary">$(M(item.summary))</td> + </tr> +# end -- for items +</table> +#end -- for kinds + +<br/> +<br/> + +#end -- if not no_summary + +# --- currently works for both Functions and Tables. The params field either contains +# --- function parameters or table fields. +# local show_return = not ldoc.no_return_or_parms +# local show_parms = show_return +# for kind, items in module.kinds() do + <h2><a name="$(no_spaces(kind))"></a>$(kind)</h2> + $(M(module.kinds:get_section_description(kind))) + <dl class="function"> +# for item in items() do ldoc.item = item -- provides context for M() + <dt> + <a name = "$(item.name)"></a> + <strong>$(display_name(item))</strong> + </dt> + <dd> + $(M(item.summary..' <br />'..(item.description or ''))) + +# if show_parms and item.params and #item.params > 0 then + <h3>$(module.kinds:type_of(item).subnames):</h3> + <ul> +# for p in iter(item.params) do + <li><code><em>$(p)</em></code>: $(M(item.params[p]))</li> +# end -- for + </ul> +# end -- if params + +# if show_return and item.ret then +# local li,il = use_li(item.ret) + <h3>Returns:</h3> + <ol> +# for r in iter(item.ret) do + $(li)$(M(r))$(il) +# end -- for + </ol> +# end -- if returns + +# if item.usage then +# local li,il = use_li(item.usage) + <h3>Usage:</h3> + <ul> +# for usage in iter(item.usage) do + $(li)<pre class="example">$(usage)</pre>$(il) +# end -- for + </ul> +# end -- if usage + +# if item.see then +# local li,il = use_li(item.see) + <h3>see also:</h3> + <ul> +# for see in iter(item.see) do + $(li)<a href="$(ldoc.href(see))">$(see.label)</a>$(il) +# end -- for + </ul> +# end -- if see +</dd> +# end -- for items +</dl> +# end -- for kinds + +# else -- if module; project-level contents + +# if ldoc.description then + <p>$(M(ldoc.description))</p> +# end + +# for kind, mods in ldoc.kinds() do +<h2>$(kind)</h2> +# kind = kind:lower() +<table class="module_list"> +# for m in mods() do + <tr> + <td class="name" nowrap><a href="$(no_spaces(kind))/$(m.name).html">$(m.name)</a></td> + <td class="summary">$(M(m.summary))</td> + </tr> +# end -- for modules +</table> +# end -- for kinds +# end -- if module + +</div> <!-- id="content" --> +</div> <!-- id="main" --> +<div id="about"> +<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc</a></i> +</div> <!-- id="about" --> +</div> <!-- id="container" --> +</body> +</html>
\ No newline at end of file diff --git a/Data/Libraries/LDoc/tests/example/laurent/mod1.lua b/Data/Libraries/LDoc/tests/example/laurent/mod1.lua new file mode 100644 index 0000000..4b5c9b0 --- /dev/null +++ b/Data/Libraries/LDoc/tests/example/laurent/mod1.lua @@ -0,0 +1,61 @@ +--------------------------- +-- Test module providing bonzo.dog. +-- Rest is a longer description +-- @class module +-- @name mod1 + +--- zero function. Two new ldoc features here; item types +-- can be used directly as tags, and aliases for tags +-- can be defined in config.lp. +-- @function zero_fun +-- @param k1 first +-- @param k2 second + +--- first function. Some description +-- @param p1 first parameter +-- @param[opt] p2 second parameter +-- @param[optchain] p3 third parameter +function mod1.first_fun(p1,p2,p3) +end + +------------------------- +-- second function. +-- @param ... var args! +function mod1.second_function(...) +end + +------------ +-- third function. Can also provide parameter comments inline, +-- provided they follow this pattern. +function mod1.third_function( + alpha, -- correction A + beta, -- correction B + gamma -- factor C + ) +end + +----- +-- A useful macro. This is an example of a custom 'kind'. +-- @macro first_macro +-- @see second_function + +---- general configuration table +-- @table config +-- @field A alpha +-- @field B beta +-- @field C gamma +mod1.config = { + A = 1, + B = 2, + C = 3 +} + +--[[-- +Another function. Using a Lua block comment +@param p a parameter +]] +function mod1.zero_function(p) +end + + + diff --git a/Data/Libraries/LDoc/tests/example/mod1.lua b/Data/Libraries/LDoc/tests/example/mod1.lua new file mode 100644 index 0000000..5475818 --- /dev/null +++ b/Data/Libraries/LDoc/tests/example/mod1.lua @@ -0,0 +1,81 @@ +--------------------------- +-- Test module providing bonzo.dog. +-- Rest is a longer description +-- @class module +-- @name mod1 + +--- zero function. Two new ldoc features here; item types +-- can be used directly as tags, and aliases for tags +-- can be defined in config.lp. +-- @function zero_fun +-- @p k1 first +-- @p k2 second + +--- first function. Some description +-- @param p1 first parameter +-- @param p2 second parameter +function mod1.first_fun(p1,p2) +end + +------------------------- +-- second function. +-- @param ... var args! +function mod1.second_function(...) +end + +------------ +-- third function. Can also provide parameter comments inline, +-- provided they follow this pattern. +function mod1.third_function( + alpha, -- correction A + beta, -- correction B + gamma -- factor C + ) +end + +----- +-- A useful macro. This is an example of a custom 'kind'. +-- @macro first_macro +-- @see second_function + +---- general configuration table +-- @table config +-- @field A alpha +-- @field B beta +-- @field C gamma +mod1.config = { + A = 1, + B = 2, + C = 3 +} + +--[[-- +Another function. Using a Lua block comment +@param p a parameter +]] +function mod1.zero_function(p) +end + + +------- +-- Multiple params may match a varargs function. +-- Generally, ldoc tries to be strict about matching params and formal arguments, +-- but this is relaxed for varargs: `function other(p,...)` +-- @param p +-- @param q +-- @param r +function mod1.other(p,...) +-- something cunning with select(2,...) +end + +------- +-- A function with typed arguments. +-- The tparam tag is followed by the 'type'. There is no standard way +-- to represent Lua types, but you can adopt a convention. Type names +-- will be resolved. treturn must include a description after the type. +-- @tparam string name +-- @tparam number age +-- @treturn string modified age +function mod1.typed(name,age) + +end diff --git a/Data/Libraries/LDoc/tests/example/modtest.lua b/Data/Libraries/LDoc/tests/example/modtest.lua new file mode 100644 index 0000000..cefabf1 --- /dev/null +++ b/Data/Libraries/LDoc/tests/example/modtest.lua @@ -0,0 +1,18 @@ +------- +-- A script. +-- Scripts are not containers in the sense that modules are, +-- (although perhaps the idea of 'commands' could be adopted for some utilities) +-- It allows any upfront script comments to be included in the +-- documentation. Any long string marked with the 'usage' tag will also appear +-- in this area. +-- +-- @script modtest + +--- @usage +local usage = [[ +modtest NAME +where NAME is your favourite name! + +]] + +print ('hello',arg[1]) diff --git a/Data/Libraries/LDoc/tests/example/mylib.c b/Data/Libraries/LDoc/tests/example/mylib.c new file mode 100644 index 0000000..fd9c675 --- /dev/null +++ b/Data/Libraries/LDoc/tests/example/mylib.c @@ -0,0 +1,62 @@ +/// A sample C extension. +// Demonstrates using ldoc's C/C++ support. Can either use /// or /*** */ etc. +// @module mylib +#include <string.h> +#include <math.h> + +// includes for Lua +#include <lua.h> +#include <lauxlib.h> +#include <lualib.h> + +/*** +Create a table with given array and hash slots. +@function createtable +@param narr initial array slots, default 0 +@param nrec initial hash slots, default 0 +*/ +static int l_createtable (lua_State *L) { + int narr = luaL_optint(L,1,0); + int nrec = luaL_optint(L,2,0); + lua_createtable(L,narr,nrec); + return 1; +} + +/*** +Solve a quadratic equation. +@function solve +@tparam num a coefficient of x^2 +@tparam num b coefficient of x +@tparam num c constant +@treturn num first root +@treturn num second root +*/ +static int l_solve (lua_State *L) { + double a = lua_tonumber(L,1); // coeff of x*x + double b = lua_tonumber(L,2); // coef of x + double c = lua_tonumber(L,3); // constant + double abc = b*b - 4*a*c; + if (abc < 0.0) { + lua_pushnil(L); + lua_pushstring(L,"imaginary roots!"); + return 2; + } else { + abc = sqrt(abc); + a = 2*a; + lua_pushnumber(L,(-b + abc)/a); + lua_pushnumber(L,(+b - abc)/a); + return 2; + } +} + +static const luaL_reg mylib[] = { + {"createtable",l_createtable}, + {"solve",l_solve}, + {NULL,NULL} +}; + +int luaopen_mylib(lua_State *L) +{ + luaL_register (L, "mylib", mylib); + return 1; +} diff --git a/Data/Libraries/LDoc/tests/example/style/config.ld b/Data/Libraries/LDoc/tests/example/style/config.ld new file mode 100644 index 0000000..6a96275 --- /dev/null +++ b/Data/Libraries/LDoc/tests/example/style/config.ld @@ -0,0 +1,14 @@ +file = 'simple.lua' +project = 'simple' +description = [[ +a simple project + +##References + + - [Background]() + - [Discussion]() + +]] +style = true +template = true +format = 'markdown' diff --git a/Data/Libraries/LDoc/tests/example/style/ldoc.css b/Data/Libraries/LDoc/tests/example/style/ldoc.css new file mode 100644 index 0000000..3b270a1 --- /dev/null +++ b/Data/Libraries/LDoc/tests/example/style/ldoc.css @@ -0,0 +1,299 @@ +/* BEGIN RESET + +Copyright (c) 2010, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.com/yui/license.html +version: 2.8.2r1 +*/ +html { + color: #000; + background: #FFF; +} +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 { + margin: 0; + padding: 0; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +fieldset,img { + border: 0; +} +address,caption,cite,code,dfn,em,strong,th,var,optgroup { + font-style: inherit; + font-weight: inherit; +} +del,ins { + text-decoration: none; +} +li { + list-style: bullet; + margin-left: 20px; +} +caption,th { + text-align: left; +} +h1,h2,h3,h4,h5,h6 { + font-size: 100%; + font-weight: bold; +} +q:before,q:after { + content: ''; +} +abbr,acronym { + border: 0; + font-variant: normal; +} +sup { + vertical-align: baseline; +} +sub { + vertical-align: baseline; +} +legend { + color: #000; +} +input,button,textarea,select,optgroup,option { + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; +} +input,button,textarea,select {*font-size:100%; +} +/* END RESET */ + +body { + margin-left: 1em; + margin-right: 1em; + font-family: arial, helvetica, geneva, sans-serif; + background-color: #ffffff; margin: 0px; +} + +code, tt { font-family: monospace; } + +body, p, td, th { font-size: .95em; line-height: 1.2em;} + +p, ul { margin: 10px 0 0 10px;} + +strong { font-weight: bold;} + +em { font-style: italic;} + +h1 { + font-size: 1.5em; + margin: 0 0 20px 0; +} +h2, h3, h4 { margin: 15px 0 10px 0; } +h2 { font-size: 1.25em; } +h3 { font-size: 1.15em; } +h4 { font-size: 1.06em; } + +a:link { font-weight: bold; color: #004080; text-decoration: none; } +a:visited { font-weight: bold; color: #006699; text-decoration: none; } +a:link:hover { text-decoration: underline; } + +hr { + color:#cccccc; + background: #00007f; + height: 1px; +} + +blockquote { margin-left: 3em; } + +ul { list-style-type: disc; } + +p.name { + font-family: "Andale Mono", monospace; + padding-top: 1em; +} + +pre.example { + background-color: rgb(245, 245, 245); + border: 1px solid silver; + padding: 10px; + margin: 10px 0 10px 0; + font-family: "Andale Mono", monospace; + font-size: .85em; +} + +pre { + background-color: rgb(245, 245, 245); + border: 1px solid silver; + padding: 10px; + margin: 10px 0 10px 0; + font-family: "Andale Mono", monospace; +} + + +table.index { border: 1px #00007f; } +table.index td { text-align: left; vertical-align: top; } + +#container { + margin-left: 1em; + margin-right: 1em; + background-color: #f0f0f0; +} + +#product { + text-align: center; + border-bottom: 1px solid #cccccc; + background-color: #ffffff; +} + +#product big { + font-size: 2em; +} + +#main { + background-color: #f0f0ff; + border-left: 2px solid #cccccc; +} + +#navigation { + float: left; + width: 14em; + vertical-align: top; + background-color: #f0f0f0; + overflow: visible; +} + +#navigation h2 { + background-color:#e7e7e7; + font-size:1.1em; + color:#000000; + text-align: left; + padding:0.2em; + border-top:1px solid #dddddd; + border-bottom:1px solid #dddddd; +} + +#navigation ul +{ + font-size:1em; + list-style-type: none; + margin: 1px 1px 10px 1px; +} + +#navigation li { + text-indent: -1em; + display: block; + margin: 3px 0px 0px 22px; +} + +#navigation li li a { + margin: 0px 3px 0px -1em; +} + +#content { + margin-left: 14em; + width: 40em; + padding: 1em; + border-left: 2px solid #cccccc; + border-right: 2px solid #cccccc; + background-color: #f0ffff; +} + +#about { + clear: both; + padding: 5px; + border-top: 2px solid #cccccc; + background-color: #ffffff; +} + +@media print { + body { + font: 12pt "Times New Roman", "TimeNR", Times, serif; + } + a { font-weight: bold; color: #004080; text-decoration: underline; } + + #main { + background-color: #ffffff; + border-left: 0px; + } + + #container { + margin-left: 2%; + margin-right: 2%; + background-color: #ffffff; + } + + #content { + padding: 1em; + background-color: #ffffff; + } + + #navigation { + display: none; + } + pre.example { + font-family: "Andale Mono", monospace; + font-size: 10pt; + page-break-inside: avoid; + } +} + +table.module_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.module_list td.name { background-color: #f0f0f0; } +table.module_list td.summary { width: 100%; } + +table.file_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.file_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} + +table.file_list td.name { background-color: #fff0ff; } + +table.file_list td.summary { width: 100%; } + +table.function_list { + border-width: 1px; + border-style: solid; + border-color: #aaaaaa; + border-collapse: collapse; +} +table.function_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #eeeeee; +} + +table.function_list td.name { background-color: #f0f0ff; } + +table.function_list td.summary { width: 100%; } + +table.table_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.table_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} + +table.table_list td.name { background-color: #f0f0f0; } + +table.table_list td.summary { width: 100%; } + +dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;} +dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;} +dl.table h3, dl.function h3 {font-size: .95em;} diff --git a/Data/Libraries/LDoc/tests/example/style/ldoc.ltp b/Data/Libraries/LDoc/tests/example/style/ldoc.ltp new file mode 100644 index 0000000..24d786a --- /dev/null +++ b/Data/Libraries/LDoc/tests/example/style/ldoc.ltp @@ -0,0 +1,135 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> + <title>$(ldoc.title)</title> + <link rel="stylesheet" href="$(ldoc.css)" type="text/css" /> +</head> +<body> + +<div id="container"> + +<div id="product"> + <div id="product_logo"></div> + <div id="product_name"><big><b></b></big></div> + <div id="product_description"></div> +</div> <!-- id="product" --> + +<div id="main"> + +# local iter = ldoc.modules.iter +# local M = ldoc.markup + +<!-- Menu --> + +# local function no_spaces(s) return s:gsub('%s','_') end +# local function use_li(ls) +# if #ls > 1 then return '<li>','</li>' else return '','' end +# end +# local function display_name(item) +# if item.type == 'function' then return item.name..' '..item.args +# else return item.name end +# end + + +<div id="navigation"> +<h1>$(ldoc.project)</h1> +# if not ldoc.single then +<ul> + <li><a href="../index.html">Index</a></li> +</ul> +# else +<p>$(M(ldoc.description))</p> +# end + +# if module then +<hr/> +<ul> +# for kind, items in module.kinds() do +# for item in items() do + <li><a href="#$(item.name)">$(display_name(item))</a></li> +# end +# end +</ul> +# end + +</div> + +<div id="content"> + +# if module then + +<h1>Module <code>$(module.name)</code></h1> + +<p>$(M(module.summary))</p> +<p>$(M(module.description))</p> + +<br/> +<br/> + +# --- currently works for both Functions and Tables. The params field either contains +# --- function parameters or table fields. +# for kind, items in module.kinds() do + <dl class="function"> +# for item in items() do + <dt> + <a name = "$(item.name)"></a> + <strong>$(display_name(item))</strong> + </dt> + <dd> + $(M(item.summary)) + $(M(item.description)) + +# if item.usage then +# local li,il = use_li(item.usage) + <h3>Usage:</h3> + <ul> +# for usage in iter(item.usage) do + $(li)<pre class="example">$(usage)</pre>$(il) +# end -- for + </ul> +# end -- if usage + +# if item.see then +# local li,il = use_li(item.see) + <h3>see also:</h3> + <ul> +# for see in iter(item.see) do + $(li)<a href="$(see.mod).html#$(see.name)">$(see.label)</a>$(il) +# end -- for + </ul> +# end -- if see +</dd> +# end -- for items +</dl> +# end -- for kinds + +# else -- if module + +# if ldoc.description then + <p>$(M(ldoc.description))</p> +# end + +# for kind, mods in ldoc.kinds() do +<h2>$(kind)</h2> +# kind = kind:lower() +# for m in mods() do +<table class="module_list"> + <tr> + <td class="name"><a href="$(no_spaces(kind))/$(m.name).html">$(m.name)</a></td> + <td class="summary">$(M(m.summary))</td> + </tr> +# end -- for modules +</table> +# end -- for kinds +# end -- if module + +</div> <!-- id="content" --> +</div> <!-- id="main" --> +<div id="about"> +</div> <!-- id="about" --> +</div> <!-- id="container" --> +</body> +</html> + diff --git a/Data/Libraries/LDoc/tests/example/style/mod1.lua b/Data/Libraries/LDoc/tests/example/style/mod1.lua new file mode 100644 index 0000000..9ba0b21 --- /dev/null +++ b/Data/Libraries/LDoc/tests/example/style/mod1.lua @@ -0,0 +1,60 @@ +--------------------------- +-- Test module providing bonzo.dog. +-- Rest is a longer description +-- @class module +-- @name mod1 + +--- zero function. Two new ldoc features here; item types +-- can be used directly as tags, and aliases for tags +-- can be defined in config.lp. +-- @function zero_fun +-- @p k1 first +-- @p k2 second + +--- first function. Some description +-- @param p1 first parameter +-- @param p2 second parameter +function mod1.first_fun(p1,p2) +end + +------------------------- +-- second function. +-- @param ... var args! +function mod1.second_function(...) +end + +------------ +-- third function. Can also provide parameter comments inline, +-- provided they follow this pattern. +function mod1.third_function( + alpha, -- correction A + beta, -- correction B + gamma -- factor C + ) +end + +----- +-- A useful macro. This is an example of a custom 'kind'. +-- @macro first_macro +-- @see second_function + +---- general configuration table +-- @table config +-- @field A alpha +-- @field B beta +-- @field C gamma +mod1.config = { + A = 1, + B = 2, + C = 3 +} + +--[[-- +Another function. Using a Lua block comment +@param p a parameter +]] +function mod1.zero_function(p) +end + + + diff --git a/Data/Libraries/LDoc/tests/example/style/simple.lua b/Data/Libraries/LDoc/tests/example/style/simple.lua new file mode 100644 index 0000000..e569461 --- /dev/null +++ b/Data/Libraries/LDoc/tests/example/style/simple.lua @@ -0,0 +1,51 @@ +--------------- +-- Markdown-flavoured and very simple no-structure style. +-- +-- Here the idea is to structure the document entirely with [Markdown](). +-- +-- Using the default markdown processor can be a little irritating: you are +-- required to give a blank line before starting lists. The default stylesheet +-- is not quite right, either. +-- +module 'mod' + +--- Combine two strings _first_ and _second_ in interesting ways. +function combine(first,second) +end + +--- Combine a whole bunch of strings. +function combine_all(...) +end + +--- +-- Creates a constant capture. This pattern matches the empty string and +-- produces all given values as its captured values. +function lpeg.Cc([value, ...]) end + + +--- Split a string _str_. Returns the first part and the second part, so that +-- `combine(first,second)` is equal to _s_. +function split(s) +end + +--- Split a string _text_ into a table. +-- Returns: +-- +-- - `name` the name of the text +-- - `pairs` an array of pairs +-- - `key` +-- - `value` +-- - `length` +-- + +function split_table (text) +end + +--- A table of useful constants. +-- +-- - `alpha` first correction factor +-- - `beta` second correction factor +-- +-- @table constants + + diff --git a/Data/Libraries/LDoc/tests/factory/factory.lua b/Data/Libraries/LDoc/tests/factory/factory.lua new file mode 100644 index 0000000..e620ee0 --- /dev/null +++ b/Data/Libraries/LDoc/tests/factory/factory.lua @@ -0,0 +1,51 @@ +--- +-- Useful classes. +-- This is the enclosing module description. + +--- My class. +-- Describe our class +-- @factory Object + +local make_object +do + --- my private method + -- document here. (By default it will not show in docs.) + -- @private + local my_private_method = function(self) + ...more code here... + end + + --- my public method. + -- documentation here + -- @param arg + local method = function(self, arg) + .....some code here..... + return my_private_method(self) + end + + --- Another public method. + -- More details + local more = function(self) + end + + --- factory returning @{Object}. + -- @constructor + -- @param arg + -- @param arg2 + make_object = function(arg, arg2) + return + { + -- private fields + field_ = arg; + + -- public methods + method = method; + more = more; + } + end +end + +return { + make_object = make_object +} + diff --git a/Data/Libraries/LDoc/tests/factory/mymod.lua b/Data/Libraries/LDoc/tests/factory/mymod.lua new file mode 100644 index 0000000..d872047 --- /dev/null +++ b/Data/Libraries/LDoc/tests/factory/mymod.lua @@ -0,0 +1,21 @@ +--- mymod + +local mymod = {} + +--- everything! +function mymod.query ( + a, --string: first arg + b, --int: second arg + c --table: arg +) +end + + +--- for everything. +function mymod.answer ( + a, -- first arg + b, -- second arg + c) -- third arg +end + +return mymod diff --git a/Data/Libraries/LDoc/tests/funmod.lua b/Data/Libraries/LDoc/tests/funmod.lua new file mode 100644 index 0000000..f9eaef2 --- /dev/null +++ b/Data/Libraries/LDoc/tests/funmod.lua @@ -0,0 +1,13 @@ +------- +-- Summing values. +-- Returns a single function. +-- @param a first +-- @param b second +-- @param c third +-- @return sum of parameters +-- @module funmod + +return function(a,b,c) + return a + b + c +end + diff --git a/Data/Libraries/LDoc/tests/luadoc/config.ld b/Data/Libraries/LDoc/tests/luadoc/config.ld new file mode 100644 index 0000000..4f4e7aa --- /dev/null +++ b/Data/Libraries/LDoc/tests/luadoc/config.ld @@ -0,0 +1,5 @@ +project = 'LuaDoc' +title = "LuaDoc with LDoc" +package = 'luadoc' +-- point this to your Luarocks directory +file = [[c:\lua\lua\luadoc]] diff --git a/Data/Libraries/LDoc/tests/md-test/config.ld b/Data/Libraries/LDoc/tests/md-test/config.ld new file mode 100644 index 0000000..0c45580 --- /dev/null +++ b/Data/Libraries/LDoc/tests/md-test/config.ld @@ -0,0 +1,5 @@ +project = 'md-test' +title = 'Markdown Docs' +format = 'markdown' +file = 'mod2.lua' + diff --git a/Data/Libraries/LDoc/tests/md-test/mod2.lua b/Data/Libraries/LDoc/tests/md-test/mod2.lua new file mode 100644 index 0000000..4e73671 --- /dev/null +++ b/Data/Libraries/LDoc/tests/md-test/mod2.lua @@ -0,0 +1,25 @@ +--------------------- +-- Another test module. +-- This one uses _Markdown_ formating, and +-- so can include goodies such as `code` +-- and lists: +-- +-- - one +-- - two +-- - three +-- +-- @module mod2 + +--- really basic function. Can contain links such as +-- [this](http://lua-users.org/wiki/FindPage) +-- @param first like `gsb(x)` +-- @param second **bold** maybe? It can continue: +-- +-- - another point +-- - finish the damn list +-- @param third as before +function mod2.basic(first,second,third) + +end + + diff --git a/Data/Libraries/LDoc/tests/merge/config.ld b/Data/Libraries/LDoc/tests/merge/config.ld new file mode 100644 index 0000000..f08e90c --- /dev/null +++ b/Data/Libraries/LDoc/tests/merge/config.ld @@ -0,0 +1,2 @@ +merge=true +file={'merge1.lua','merge2.lua'} diff --git a/Data/Libraries/LDoc/tests/merge/merge1.lua b/Data/Libraries/LDoc/tests/merge/merge1.lua new file mode 100644 index 0000000..3bdbc36 --- /dev/null +++ b/Data/Libraries/LDoc/tests/merge/merge1.lua @@ -0,0 +1,7 @@ +---- +-- main module +-- @module merge + +---- first fun +function one() +end diff --git a/Data/Libraries/LDoc/tests/merge/merge2.lua b/Data/Libraries/LDoc/tests/merge/merge2.lua new file mode 100644 index 0000000..02bc63c --- /dev/null +++ b/Data/Libraries/LDoc/tests/merge/merge2.lua @@ -0,0 +1,19 @@ +---- +-- submodule +-- @module merge + +---- second fun +-- @param x +function two(x) +end + +--- extra stuff +-- @section extra + +--- third fun +function three () +end + +--- fourth fun +function four () +end diff --git a/Data/Libraries/LDoc/tests/mod1.ld b/Data/Libraries/LDoc/tests/mod1.ld new file mode 100644 index 0000000..42a6e53 --- /dev/null +++ b/Data/Libraries/LDoc/tests/mod1.ld @@ -0,0 +1,9 @@ +-- ldoc -c mod1.ld . +project = 'mod1' +description = 'showing various ldoc comment styles' +title = 'mod docs' +-- may be a table containing files and directories +file = 'mod1.lua' +-- show local functions as well! +all = true + diff --git a/Data/Libraries/LDoc/tests/mod1.lua b/Data/Libraries/LDoc/tests/mod1.lua new file mode 100644 index 0000000..a1156c2 --- /dev/null +++ b/Data/Libraries/LDoc/tests/mod1.lua @@ -0,0 +1,46 @@ +------ +-- always need a doc comment to start! +-- Can have a module with no internal doc comments, +-- although you will get a warning. At least we no +-- longer get a 'end-of-file' if there is no explicit +-- module name. + +----- not a doc comment ----- +-- a common style when just specifying an informative comment +-- May start with a doc comment but has trailing hyphens + +local g -- so g below must be marked as local + +--- simple. +--@param x a parameter +function _M.f(x) end + +--- implicit local function. +-- Local functions appear in dump but only in docs if you say --all +local function L(t,v) end + +--- explicit local function. +-- @local here +function g(a,b) end + +--- a table of this module +_M.contents = { + A = 'f', -- alpha + B = 'g' -- beta +} + +--- another way to do parameters. +function _M.kay( + a, -- ay + b, -- bee +) end + +--- a field of this module. +_M.constant = 'hello' + +--- functions can also be like so. +_M.why = function(x,y) +end + + + diff --git a/Data/Libraries/LDoc/tests/moonscript/List.moon b/Data/Libraries/LDoc/tests/moonscript/List.moon new file mode 100644 index 0000000..bd1272e --- /dev/null +++ b/Data/Libraries/LDoc/tests/moonscript/List.moon @@ -0,0 +1,65 @@ +---- +-- A list class that wraps a table +-- @classmod List +import insert,concat,remove from table + +class List + --- constructor passed a table `t`, which can be `nil`. + new: (t) => + @ls = t or {} + + --- append to list. + add: (item) => + insert @ls,item + + --- insert `item` at `idx` + insert: (idx,item) => + insert @ls,idx,item + + --- remove item at `idx` + remove: (idx) => remove @ls,idx + + --- length of list + len: => #@ls + + --- string representation + __tostring: => '['..(concat @ls,',')..']' + + --- return idx of first occurence of `item` + find: (item) => + for i = 1,#@ls + if @ls[i] == item then return i + + --- remove item by value + remove_value: (item) => + idx = self\find item + self\remove idx if idx + + --- remove a list of items + remove_values: (items) => + for item in *items do self\remove_value item + + --- create a sublist of items indexed by a table `indexes` + index_by: (indexes) => + List [@ls[idx] for idx in *indexes] + + --- make a copy of this list + copy: => List [v for v in *@ls] + + --- append items from the table or list `list` + extend: (list) => + other = if list.__class == List then list.ls else list + for v in *other do self\add v + self + + --- concatenate two lists, giving a new list + __concat: (l1,l2) -> l1\copy!\extend l2 + + --- an iterator over all items + iter: => + i,t,n = 0,@ls,#@ls + -> + i += 1 + if i <= n then t[i] + +return List diff --git a/Data/Libraries/LDoc/tests/moonscript/config.ld b/Data/Libraries/LDoc/tests/moonscript/config.ld new file mode 100644 index 0000000..7b7763b --- /dev/null +++ b/Data/Libraries/LDoc/tests/moonscript/config.ld @@ -0,0 +1,5 @@ +file = 'List.moon' +no_return_or_parms=true +no_summary=true +format = 'markdown' +--sort = true diff --git a/Data/Libraries/LDoc/tests/one.md b/Data/Libraries/LDoc/tests/one.md new file mode 100644 index 0000000..c27292c --- /dev/null +++ b/Data/Libraries/LDoc/tests/one.md @@ -0,0 +1,11 @@ +# Documentation + +## types + +A reference to @{types.first} + +A `first` topic + +## classes + +A `second` topic diff --git a/Data/Libraries/LDoc/tests/simple/problem.lua b/Data/Libraries/LDoc/tests/simple/problem.lua new file mode 100644 index 0000000..3848539 --- /dev/null +++ b/Data/Libraries/LDoc/tests/simple/problem.lua @@ -0,0 +1,19 @@ +--- this module has a comment. + +local local_two + +--- a local function +local function local_one () +end + +--- a local function, needing explicit tag. +-- @local here +function local_two () + +end + +--- A problem function. +-- @param p a parameter +function problem.fun(p) + return 42 +end diff --git a/Data/Libraries/LDoc/tests/simple/simple.lua b/Data/Libraries/LDoc/tests/simple/simple.lua new file mode 100644 index 0000000..15d2a39 --- /dev/null +++ b/Data/Libraries/LDoc/tests/simple/simple.lua @@ -0,0 +1,12 @@ +------------ +-- A little old-style module +local io = io +-- we'll look for this +module 'simple' + +-- if it were 'module (...)' then the name has to be deduced. + +--- return the answer. +function answer() + return 42 +end diff --git a/Data/Libraries/LDoc/tests/simple/simple_alias.lua b/Data/Libraries/LDoc/tests/simple/simple_alias.lua new file mode 100644 index 0000000..72d17af --- /dev/null +++ b/Data/Libraries/LDoc/tests/simple/simple_alias.lua @@ -0,0 +1,16 @@ +------------ +-- A new-style module. +-- Shows how @alias can be used to tell ldoc that a given name +-- is a shorthand for the full module name +-- @alias M + +local simple_alias = {} +local M = simple_alias + +--- return the answer. And complete the description +function M.answer() + return 42 +end + +return simple_alias + diff --git a/Data/Libraries/LDoc/tests/simple/tables.lua b/Data/Libraries/LDoc/tests/simple/tables.lua new file mode 100644 index 0000000..bdc612d --- /dev/null +++ b/Data/Libraries/LDoc/tests/simple/tables.lua @@ -0,0 +1,39 @@ +------------ +-- A module containing tables. +-- Shows how Lua table definitions can be conveniently parsed. +-- +-- There may be multiple comment lines per field/parameter, and +-- such comments may begin with `TYPE:` +-- +-- Functions also can be commented in a similar way, and the last +-- parameter's comment may be outside the parens. +-- +-- @alias M + +local tables = {} +local M = tables + +--- a function. +function M.one( + bonzo, -- dog + -- has its day! + frodo) --baggins +end + +--- first table. +-- @table one +M.one = { + A = 1, -- alpha + B = 2; -- beta +} + +--- second table. +-- we don't need an explicit table tag, since it +-- can be inferred from the context. +M.two = { + N = 10, -- int: no. of cases + L = 'label' -- string: case label +} + +return M + diff --git a/Data/Libraries/LDoc/tests/styles/colon.lua b/Data/Libraries/LDoc/tests/styles/colon.lua new file mode 100644 index 0000000..bb3ffea --- /dev/null +++ b/Data/Libraries/LDoc/tests/styles/colon.lua @@ -0,0 +1,35 @@ +---------------------- +-- Showing off Colon mode. +-- If you hate @ tags, you can use colons. However, you need to specify colon +-- mode explicitly -C or --colon, or `colon=true` in the config.ld. Be careful +-- not to use a colon followed by a space for any other purpose! +-- +-- So the incantation in this case is `ldoc -C colon.lua`. + +-- module: colon + + +--- first useless function. +-- Optional type specifiers are allowed in this format. +-- As an extension, '?T' is short for '?nil|T'. +-- Note how these types are rendered! +-- string: name +-- int: age +-- ?person3: options +-- treturn: ?table|string +function one (name,age,options) +end + +--- implicit table can always use colon notation. +person2 = { + id=true, -- string: official ID number + sex=true, -- string: one of 'M', 'F' or 'N' + spouse=true, -- ?person3: wife or husband +} + +--- explicit table in colon format. +-- Note how '!' lets you use a type name directly. +-- string: surname +-- string: birthdate +-- !person2: options +-- table: person3 diff --git a/Data/Libraries/LDoc/tests/styles/config/config.ld b/Data/Libraries/LDoc/tests/styles/config/config.ld new file mode 100644 index 0000000..d70b7bb --- /dev/null +++ b/Data/Libraries/LDoc/tests/styles/config/config.ld @@ -0,0 +1,2 @@ +no_return_or_parms=true +no_summary=true diff --git a/Data/Libraries/LDoc/tests/styles/four.lua b/Data/Libraries/LDoc/tests/styles/four.lua new file mode 100644 index 0000000..09f3bf0 --- /dev/null +++ b/Data/Libraries/LDoc/tests/styles/four.lua @@ -0,0 +1,59 @@ +------------ +-- Yet another module. +-- Description can continue after simple tags, if you +-- like - but to keep backwards compatibility, say 'not_luadoc=true' +-- @module four +-- @author bob, james +-- @license MIT +-- @copyright InfoReich 2013 + +--- a function with typed args. +-- Note the the standard tparam aliases, and how the 'opt' and 'optchain' +-- modifiers may also be used. If the Lua function has varargs, then +-- you may document an indefinite number of extra arguments! +-- @tparam ?string|Person name person's name +-- @int age +-- @string[opt='gregorian'] calender optional calendar +-- @int[opt=0] offset optional offset +-- @treturn string +-- @see file:write +function one (name,age,...) +end + +---- testing [opt] +-- @param one +-- @param[opt] two +-- @param three +-- @param[opt] four +function two (one,two,three,four) +end + +--- third useless function. +-- Can always put comments inline, may +-- be multiple. +-- note that first comment refers to return type! +function three ( -- person: + name, -- string: person's name + age -- int: + -- not less than zero! +) +end + +---- function with single optional arg +-- @param[opt] one +function four (one) +end + +--- an implicit table. +-- Again, we can use the comments +person = { + name = '', -- string: name of person + age = 0, -- int: +} + +--- an explicit table. +-- Can now use tparam aliases in table defns +-- @string name +-- @int age +-- @table person2 + diff --git a/Data/Libraries/LDoc/tests/styles/func.lua b/Data/Libraries/LDoc/tests/styles/func.lua new file mode 100644 index 0000000..ef05845 --- /dev/null +++ b/Data/Libraries/LDoc/tests/styles/func.lua @@ -0,0 +1,15 @@ +------------ +-- Get length of string. +-- A (silly) module which returns a single function +-- +-- @module func +-- @string some text +-- @param opts multibyte encoding options +-- @string opts.charset encoding used +-- @bool opts.strict be very pedantic +-- @bool verbose tell the world about everything +-- @return its length +return function(s,opts,verbose) + return #s +end + diff --git a/Data/Libraries/LDoc/tests/styles/multiple.lua b/Data/Libraries/LDoc/tests/styles/multiple.lua new file mode 100644 index 0000000..85e12b9 --- /dev/null +++ b/Data/Libraries/LDoc/tests/styles/multiple.lua @@ -0,0 +1,45 @@ +------ +-- Various ways of indicating errors +-- @module multiple + +----- +-- function with return groups. +-- @treturn[1] string result +-- @return[2] nil +-- @return[2] error message +function mul1 () end + +----- +-- function with return and error tag +-- @return result +-- @error message +function mul2 () end + +----- +-- function with multiple error tags +-- @return result +-- @error not found +-- @error bad format +function mul3 () end + +---- +-- function with inline return and errors +-- @string name +function mul4 (name) + if type(name) ~= 'string' then + --- @error[1] not a string + return nil, 'not a string' + end + if #name == 0 then + --- @error[2] zero-length string + return nil, 'zero-length string' + end + --- @treturn string converted to uppercase + return name:upper() +end +----- +-- function that raises an error. +-- @string filename +-- @treturn string result +-- @raise 'file not found' +function mul5(filename) end diff --git a/Data/Libraries/LDoc/tests/styles/one.lua b/Data/Libraries/LDoc/tests/styles/one.lua new file mode 100644 index 0000000..30e3145 --- /dev/null +++ b/Data/Libraries/LDoc/tests/styles/one.lua @@ -0,0 +1,23 @@ +--[[ +A non-doc comment +multi-line +probably containing license information! +Doesn't use module(), but module name is inferred from file name. +If you have initial licence comments that look like doc comments, +then set `boilerplate=true` +]] +------------ +-- Test module, +-- Actual blurb here! +---- + +local one = {} + +--- answer to everything. +function one.answer () + return 42 +end + +return one + + diff --git a/Data/Libraries/LDoc/tests/styles/opt.ld b/Data/Libraries/LDoc/tests/styles/opt.ld new file mode 100644 index 0000000..0895ddc --- /dev/null +++ b/Data/Libraries/LDoc/tests/styles/opt.ld @@ -0,0 +1,11 @@ +-- must have explicit optchain! +convert_opt = true + +format = 'markdown' + +-- want to include project source as well. +prettify_files = 'show' + +-- a custom tag! +custom_tags = {{'remark',title='Remarks'}} + diff --git a/Data/Libraries/LDoc/tests/styles/opt.lua b/Data/Libraries/LDoc/tests/styles/opt.lua new file mode 100644 index 0000000..6cdba2d --- /dev/null +++ b/Data/Libraries/LDoc/tests/styles/opt.lua @@ -0,0 +1,21 @@ +------------ +-- ### Functions with options and custom tags. +-- (use `ldoc -c opt.ld opt.lua` for converting.) +-- +-- @include opt.md + +---- testing [opt] +-- @param one +-- @param[opt] two +-- @param[opt] three +-- @param[opt] four +-- @remark use with caution! +function use_opt (one,two,three,four) +end + +--- an explicit table. +-- Can use tparam aliases in table defns +-- @string name +-- @int[opt=0] age +-- @table person2 + diff --git a/Data/Libraries/LDoc/tests/styles/opt.md b/Data/Libraries/LDoc/tests/styles/opt.md new file mode 100644 index 0000000..256f6b2 --- /dev/null +++ b/Data/Libraries/LDoc/tests/styles/opt.md @@ -0,0 +1,9 @@ +By default, an unbroken series of opt modifiers is converted to +'opt','optchain','optchain', so you get `(a[,b[,c])`. + +If `convert_opt` is specified, then no such conversion takes place; you then +must explicitly use `optchain`. + +The `@include` tag is only meaningful for project-level items like modules, +scripts, etc. The file is inserted into the document after being formatted. +In this case, you would usually specify `format="markdown"`. diff --git a/Data/Libraries/LDoc/tests/styles/priority_queue.lua b/Data/Libraries/LDoc/tests/styles/priority_queue.lua new file mode 100644 index 0000000..9dcc5ad --- /dev/null +++ b/Data/Libraries/LDoc/tests/styles/priority_queue.lua @@ -0,0 +1,101 @@ +-------------------------------------------------------------------------------- +--- Queue of objects sorted by priority. +-- @module lua-nucleo.priority_queue +-- This file is a part of lua-nucleo library. Note that if you wish to spread +-- the description after tags, then invoke with `not_luadoc=true`. +-- The flags here are `ldoc -X -f backtick priority_queue.lua`, which +-- also expands backticks. +-- @copyright lua-nucleo authors (see file `COPYRIGHT` for the license) +-------------------------------------------------------------------------------- + +local arguments, + method_arguments + = import 'lua-nucleo/args.lua' + { + 'arguments', + 'method_arguments' + } + +local lower_bound_gt + = import 'lua-nucleo/algorithm.lua' + { + 'lower_bound_gt' + } + +-------------------------------------------------------------------------------- + +local table_insert, table_remove = table.insert, table.remove + +-------------------------------------------------------------------------------- + +--- Priority Queue +-- @factory priority_queue +local make_priority_queue +do + local PRIORITY_KEY = 1 + local VALUE_KEY = 2 + + local insert = function(self, priority, value) + method_arguments( + s + "number", priority + ) + assert(value ~= nil, "value can't be nil") -- value may be of any type, except nil + + local queue = self.queue_ + local k = lower_bound_gt(queue, PRIORITY_KEY, priority) + + table_insert(queue, k, { [PRIORITY_KEY] = priority, [VALUE_KEY] = value }) + end + + local front = function(self) + method_arguments( + self + ) + + local queue = self.queue_ + local front_elem = queue[#queue] + + if front_elem == nil then + return nil + end + + return front_elem[PRIORITY_KEY], front_elem[VALUE_KEY] + end + + --- pop last value. + -- @return priority + -- @return value + local pop = function(self) + method_arguments( + self + ) + + local front_elem = table_remove(self.queue_) + + if front_elem == nil then + return nil + end + + return front_elem[PRIORITY_KEY], front_elem[VALUE_KEY] + end + + --- construct a `priority_queue`. + -- @constructor + make_priority_queue = function() + --- @export + return + { + insert = insert; + front = front; + pop = pop; + -- + queue_ = { }; + } + end +end + +return +{ + make_priority_queue = make_priority_queue; +} diff --git a/Data/Libraries/LDoc/tests/styles/struct.lua b/Data/Libraries/LDoc/tests/styles/struct.lua new file mode 100644 index 0000000..c28689a --- /dev/null +++ b/Data/Libraries/LDoc/tests/styles/struct.lua @@ -0,0 +1,13 @@ +------ +-- functions returning compound types +-- @module struct + +----- +-- returns a 'struct'. +-- @string name your name dammit +-- @tfield string arb stuff +-- @treturn st details of person +-- @tfield[st] string name of person +-- @tfield[st] int age of person +function struct(name) end + diff --git a/Data/Libraries/LDoc/tests/styles/subparams.lua b/Data/Libraries/LDoc/tests/styles/subparams.lua new file mode 100644 index 0000000..0e5e17e --- /dev/null +++ b/Data/Libraries/LDoc/tests/styles/subparams.lua @@ -0,0 +1,17 @@ +------------ +-- Parameters may have named subfields, if they are tables. +-- +-- @module subparams +module(...) + +------- +-- A function with subfield arguments. +-- @param s string +-- @param opts multibyte encoding options +-- @param opts.charset string +-- @param opts.strict bool +-- @param verbose bool +-- @return its length +function with_options (s,opts,verbose) +end + diff --git a/Data/Libraries/LDoc/tests/styles/three.lua b/Data/Libraries/LDoc/tests/styles/three.lua new file mode 100644 index 0000000..09c0ceb --- /dev/null +++ b/Data/Libraries/LDoc/tests/styles/three.lua @@ -0,0 +1,21 @@ +------------ +-- Alternative to no-magic style. +-- Description here +---- + +--- documented, but private +local function question () +end + +--- answer to everything. +-- @return magic number +local function answer () + return 42 +end + +--- @export +return { + answer = answer +} + + diff --git a/Data/Libraries/LDoc/tests/styles/two.lua b/Data/Libraries/LDoc/tests/styles/two.lua new file mode 100644 index 0000000..3976ed3 --- /dev/null +++ b/Data/Libraries/LDoc/tests/styles/two.lua @@ -0,0 +1,13 @@ +------------ +-- Classic Lua 5.1 module. +-- Description here +---- + +module 'two' + +--- answer to everything. +function answer () + return 42 +end + + diff --git a/Data/Libraries/LDoc/tests/styles/type.lua b/Data/Libraries/LDoc/tests/styles/type.lua new file mode 100644 index 0000000..cde0dd7 --- /dev/null +++ b/Data/Libraries/LDoc/tests/styles/type.lua @@ -0,0 +1,45 @@ +----- +-- module containing a class +-- @module type + +---- +-- Our class. Any function or table in this section belongs to `Bonzo` +-- @type Bonzo + +---- +-- make a new Bonzo. +-- @see Bonzo:dog +-- @string s name of Bonzo +function Bonzo.new(s) +end + +----- +-- get a string representation. +-- works with `tostring` +function Bonzo:__tostring() +end + +---- +-- Another method. +function Bonzo:dog () + +end + +---- +-- Private method. +-- You need -a flag or 'all=true' to see these +-- @local +function Bonzo:cat () + +end + + +---- +-- A subtable with fields. +-- @table Details +-- @string[readonly] name +-- @int[readonly] age + +--- +-- This is a simple field/property of the class. +-- @string[opt="Bilbo",readonly] frodo direct access to text diff --git a/Data/Libraries/LDoc/tests/styles/x.c b/Data/Libraries/LDoc/tests/styles/x.c new file mode 100644 index 0000000..fc8dffc --- /dev/null +++ b/Data/Libraries/LDoc/tests/styles/x.c @@ -0,0 +1,46 @@ +/*************** + * First comment is ignored, + * containing licenses, warnings, + * old-fashioned commit info and so forth + */ + +/** No-brainer C extension. +Description as before. +@module x +*/ +#include <lua.h> +#include <lauxlib.h> +#include <lualib.h> + +/*** +@string name +@int age +@table output +*/ + +/*** +Create a table with given array and hash slots. +Note that we can't (yet) deduce the name of +the Lua function. +@function createtable +@param narr initial array slots, default 0 +@param nrec initial hash slots, default 0 +@return table +*/ +static int l_createtable (lua_State *L) { + int narr = luaL_optint(L,1,0); + int nrec = luaL_optint(L,2,0); + lua_createtable(L,narr,nrec); + return 1; +} + +static const luaL_reg x[] = { + {"createtable",l_createtable}, + {NULL,NULL} +}; + +int luaopen_x(lua_State *L) +{ + luaL_register (L, "x", x); + return 1; +} diff --git a/Data/Libraries/LDoc/tests/submodule/config.ld b/Data/Libraries/LDoc/tests/submodule/config.ld new file mode 100644 index 0000000..8369015 --- /dev/null +++ b/Data/Libraries/LDoc/tests/submodule/config.ld @@ -0,0 +1,2 @@ +file = {'mylib/init.lua','mylib/extra.lua'} +if foo then print 'foo' end diff --git a/Data/Libraries/LDoc/tests/submodule/mylib/extra.lua b/Data/Libraries/LDoc/tests/submodule/mylib/extra.lua new file mode 100644 index 0000000..bb06b40 --- /dev/null +++ b/Data/Libraries/LDoc/tests/submodule/mylib/extra.lua @@ -0,0 +1,13 @@ +----------- +-- Extra module +-- @submodule mylib + +--- will appear in mylib's docs! +function E () + +end + +--- ditto +function F () + +end diff --git a/Data/Libraries/LDoc/tests/submodule/mylib/init.lua b/Data/Libraries/LDoc/tests/submodule/mylib/init.lua new file mode 100644 index 0000000..83bc90a --- /dev/null +++ b/Data/Libraries/LDoc/tests/submodule/mylib/init.lua @@ -0,0 +1,35 @@ +----------- +-- Main module. +-- This contains four functions, two of which are in +-- another section implicitly specified using the 'within' tag. +-- (This allows functions placed together to be classified +-- separately) +-- +-- Furthermore, the 'mylib.extra' functions will be added +-- as their own section, allowing you to document a logical module +-- spanning several files +-- +-- @module mylib + +--- first. +function A () + +end + +--- second, within its own section. +-- @within Utilities +function B () + +end + +--- third. +function C () + +end + +--- fourth, together with second. +-- @within Utilities +function D () + +end + diff --git a/Data/Libraries/LDoc/tests/two.md b/Data/Libraries/LDoc/tests/two.md new file mode 100644 index 0000000..0b2c3a9 --- /dev/null +++ b/Data/Libraries/LDoc/tests/two.md @@ -0,0 +1,9 @@ +# And another + +## First + +A `first` topic + +## Second + +A `second` topic diff --git a/Data/Libraries/LDoc/tests/types.lua b/Data/Libraries/LDoc/tests/types.lua new file mode 100644 index 0000000..7555608 --- /dev/null +++ b/Data/Libraries/LDoc/tests/types.lua @@ -0,0 +1,34 @@ +----------------------- +-- Module using tparam for typed parameters. +-- +-- @module types + +--- has typed parameters, `string` and `int`. +-- And never forget `E = m*c^2`. +-- Reference to `two.md.First` +-- +-- A reference to `mydata`. +-- @string name +-- @int age +-- @treturn mydata +function _M.first (name,age) + +end + +--- simple function returning something +-- @return bonzo dog! +function _M.simple() + +end + + +--- a table of this module. +-- @table mydata +_M.mydata = { + one = 1, -- alpha + two = 2, -- beta +} + + + + diff --git a/Data/Libraries/LDoc/tests/underscore.lua b/Data/Libraries/LDoc/tests/underscore.lua new file mode 100644 index 0000000..442a778 --- /dev/null +++ b/Data/Libraries/LDoc/tests/underscore.lua @@ -0,0 +1,39 @@ +--[[----------- + testing underscores and Markdown pre-formatting. + + A list may immediately follow a line, if it is indented. Necessary lines + will also be inserted after resuming current indentation. + - a list + - sublist (note the needed indentation for Markdown to recognize this) + - more + * of items + more than one line + - indeed + can keep going +Inline _see references_: look at @{_ONE_} and @{table.concat}. +Indented code blocks may also follow immediately. + function test(a,b) + return three(a,b) + end + @module underscore +]] + +---------- +-- A function. +-- Can also use @{_TWO_ |second function} +function _ONE_() end + +----------- +-- another function +-- @see string.format +function _TWO_() end + +------ +-- a longer summary. +-- @param a +-- @param b +-- @return one +-- - one-1 +-- - one-2 +-- @return two +function three(a,b) end diff --git a/Data/Libraries/LDoc/tests/usage/config.ld b/Data/Libraries/LDoc/tests/usage/config.ld new file mode 100644 index 0000000..f33e4ba --- /dev/null +++ b/Data/Libraries/LDoc/tests/usage/config.ld @@ -0,0 +1,15 @@ +project = 'usage' +file = 'usage.lua' +examples='usage.lua' +-- can specify the Markdown processor (falls back to markdown.lua) +format='markdown' +-- if you don't use markdown you may wish for backticks to be +-- expanded if they enclose a reference. +backtick_references = true +-- and the prettifier - this will use lxsh _if_ available +pretty='lxsh' +-- suppress @params and the summary at the top +no_return_or_parms=true +no_summary=true +not_luadoc=true + diff --git a/Data/Libraries/LDoc/tests/usage/usage.lua b/Data/Libraries/LDoc/tests/usage/usage.lua new file mode 100644 index 0000000..ba05136 --- /dev/null +++ b/Data/Libraries/LDoc/tests/usage/usage.lua @@ -0,0 +1,87 @@ +--[[-------- +A simple module with examples. + +Even without markdown formatting, blank lines are respected. + +@module usage +]] + +local usage = {} + +local helper + +--- a local helper function. +-- @local +function helper () +end + +---------- +-- A simple vector class. +-- +-- Supports arithmetic operations. +-- @usage +-- v = Vector.new {10,20,30} +-- assert (v == Vector{10,20,30}) +-- @type Vector + +local Vector = {} +usage.Vector = {} + + +---------- +-- Create a vector from an array `t`. +-- `Vector` is also callable! +function Vector.new (t) +end + +-- note that @function may have modifiers. Currently +-- we aren't doing anything with them, but LDoc no longer +-- complains (issue #45). Note also that one needs +-- explicit @param tags with explicit @function; 'static' +-- methods must have a @constructor or a @static tag. + +---------- +-- Create a vector from a string. +-- @usage +-- v = Vector.parse '[1,2,3]' +-- assert (v == Vector.new {1,2,3}) +-- @function[kind=ctor] parse +-- @static +-- @param s +function Vector.parse (s) +end + +-------- +-- Compare two vectors for equality. +function Vector:__eq (v) +end + +---------- +-- Add another vector, array or scalar `v` to this vector. +-- Returns new `Vector` +-- @usage assert(Vector.new{1,2,3}:add(1) == Vector{2,3,4}) +function Vector:add (v) +end + +---------- +-- set vector options. `opts` is a `Vector.Opts` table. +function Vector:options (opts) +end + +--[[----------------- +@table Vector.Opts +Options table format for `Vector:options` + + * `autoconvert`: try to convert strings to numbers + * `adder`: function used to perform addition and subtraction + * `multiplier`: function used to perform multiplication and division + +@usage + v = Vector {{1},{2}} + v:options {adder = function(x,y) return {x[1]+y[1]} end} + assert(v:add(1) == Vector{{2},{3}}) +]] + +return usage + + |