Implement Markdown definition lists (+ migration) (#20333)
Implements definition lists Markdown extension adopted in a few implementations including: * [Pandoc]( https://pandoc.org/MANUAL.html#definition-lists) * [kramdown]( https://kramdown.gettalong.org/quickref.html#definition-lists) * [PHP extra Markdown]( https://michelf.ca/projects/php-markdown/extra/#def-list) Also affected files have been migrated. RST definition lists are turned off for Markdown: this solves the problem of broken formatting mentioned in https://github.com/nim-lang/Nim/pull/20292.
This commit is contained in:
parent
846cc746a2
commit
088487f652
15 changed files with 266 additions and 97 deletions
|
|
@ -77,24 +77,29 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||||
## cases:
|
## cases:
|
||||||
##
|
##
|
||||||
## YES-cases:
|
## YES-cases:
|
||||||
|
## ```
|
||||||
## x <| x # for general trees
|
## x <| x # for general trees
|
||||||
## x[] <| x
|
## x[] <| x
|
||||||
## x[i] <| x
|
## x[i] <| x
|
||||||
## x.f <| x
|
## x.f <| x
|
||||||
|
## ```
|
||||||
##
|
##
|
||||||
## NO-cases:
|
## NO-cases:
|
||||||
|
## ```
|
||||||
## x !<| y # depending on type and symbol kind
|
## x !<| y # depending on type and symbol kind
|
||||||
## x[constA] !<| x[constB]
|
## x[constA] !<| x[constB]
|
||||||
## x.f !<| x.g
|
## x.f !<| x.g
|
||||||
## x.f !<| y.f iff x !<= y
|
## x.f !<| y.f iff x !<= y
|
||||||
|
## ```
|
||||||
##
|
##
|
||||||
## MAYBE-cases:
|
## MAYBE-cases:
|
||||||
##
|
##
|
||||||
|
## ```
|
||||||
## x[] ?<| y[] iff compatible type
|
## x[] ?<| y[] iff compatible type
|
||||||
##
|
##
|
||||||
##
|
##
|
||||||
## x[] ?<| y depending on type
|
## x[] ?<| y depending on type
|
||||||
##
|
## ```
|
||||||
if a.kind == b.kind:
|
if a.kind == b.kind:
|
||||||
case a.kind
|
case a.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ specialpaths is simpler because it doesn't need variables to be relocatable at
|
||||||
runtime (eg for use in testament)
|
runtime (eg for use in testament)
|
||||||
|
|
||||||
interpolation variables:
|
interpolation variables:
|
||||||
$nimr: such that `$nimr/lib/system.nim` exists (avoids confusion with $nim binary)
|
: $nimr: such that `$nimr/lib/system.nim` exists (avoids confusion with $nim binary)
|
||||||
in compiler, it's obtainable via getPrefixDir(); for other tools (eg koch),
|
in compiler, it's obtainable via getPrefixDir(); for other tools (eg koch),
|
||||||
this could be getCurrentDir() or getAppFilename().parentDir.parentDir,
|
this could be getCurrentDir() or getAppFilename().parentDir.parentDir,
|
||||||
depending on use case
|
depending on use case
|
||||||
|
|
|
||||||
|
|
@ -72,10 +72,10 @@ The replace filter replaces substrings in each line.
|
||||||
Parameters and their defaults:
|
Parameters and their defaults:
|
||||||
|
|
||||||
* `sub: string = ""`
|
* `sub: string = ""`
|
||||||
the substring that is searched for
|
: the substring that is searched for
|
||||||
|
|
||||||
* `by: string = ""`
|
* `by: string = ""`
|
||||||
the string the substring is replaced with
|
: the string the substring is replaced with
|
||||||
|
|
||||||
|
|
||||||
Strip filter
|
Strip filter
|
||||||
|
|
@ -87,14 +87,14 @@ each line.
|
||||||
Parameters and their defaults:
|
Parameters and their defaults:
|
||||||
|
|
||||||
* `startswith: string = ""`
|
* `startswith: string = ""`
|
||||||
strip only the lines that start with *startswith* (ignoring leading
|
: strip only the lines that start with *startswith* (ignoring leading
|
||||||
whitespace). If empty every line is stripped.
|
whitespace). If empty every line is stripped.
|
||||||
|
|
||||||
* `leading: bool = true`
|
* `leading: bool = true`
|
||||||
strip leading whitespace
|
: strip leading whitespace
|
||||||
|
|
||||||
* `trailing: bool = true`
|
* `trailing: bool = true`
|
||||||
strip trailing whitespace
|
: strip trailing whitespace
|
||||||
|
|
||||||
|
|
||||||
StdTmpl filter
|
StdTmpl filter
|
||||||
|
|
@ -109,19 +109,19 @@ statements need `end X` delimiters.
|
||||||
Parameters and their defaults:
|
Parameters and their defaults:
|
||||||
|
|
||||||
* `metaChar: char = '#'`
|
* `metaChar: char = '#'`
|
||||||
prefix for a line that contains Nim code
|
: prefix for a line that contains Nim code
|
||||||
|
|
||||||
* `subsChar: char = '$'`
|
* `subsChar: char = '$'`
|
||||||
prefix for a Nim expression within a template line
|
: prefix for a Nim expression within a template line
|
||||||
|
|
||||||
* `conc: string = " & "`
|
* `conc: string = " & "`
|
||||||
the operation for concatenation
|
: the operation for concatenation
|
||||||
|
|
||||||
* `emit: string = "result.add"`
|
* `emit: string = "result.add"`
|
||||||
the operation to emit a string literal
|
: the operation to emit a string literal
|
||||||
|
|
||||||
* `toString: string = "$"`
|
* `toString: string = "$"`
|
||||||
the operation that is applied to each expression
|
: the operation that is applied to each expression
|
||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,30 +45,30 @@ Or::
|
||||||
nim idetools --trackDirty:DIRTY_FILE,FILE,LINE,COL <switches> proj.nim
|
nim idetools --trackDirty:DIRTY_FILE,FILE,LINE,COL <switches> proj.nim
|
||||||
|
|
||||||
`proj.nim`
|
`proj.nim`
|
||||||
This is the main *project* filename. Most of the time you will
|
: This is the main *project* filename. Most of the time you will
|
||||||
pass in the same as **FILE**, but for bigger projects this is
|
pass in the same as **FILE**, but for bigger projects this is
|
||||||
the file which is used as main entry point for the program, the
|
the file which is used as main entry point for the program, the
|
||||||
one which users compile to generate a final binary.
|
one which users compile to generate a final binary.
|
||||||
|
|
||||||
`<switches>`
|
`<switches>`
|
||||||
This would be any of the other idetools available options, like
|
: This would be any of the other idetools available options, like
|
||||||
`--def` or `--suggest` explained in the following sections.
|
`--def` or `--suggest` explained in the following sections.
|
||||||
|
|
||||||
`COL`
|
`COL`
|
||||||
An integer with the column you are going to query. For the
|
: An integer with the column you are going to query. For the
|
||||||
compiler columns start at zero, so the first column will be
|
compiler columns start at zero, so the first column will be
|
||||||
**0** and the last in an 80 column terminal will be **79**.
|
**0** and the last in an 80 column terminal will be **79**.
|
||||||
|
|
||||||
`LINE`
|
`LINE`
|
||||||
An integer with the line you are going to query. For the compiler
|
: An integer with the line you are going to query. For the compiler
|
||||||
lines start at **1**.
|
lines start at **1**.
|
||||||
|
|
||||||
`FILE`
|
`FILE`
|
||||||
The file you want to perform the query on. Usually you will
|
: The file you want to perform the query on. Usually you will
|
||||||
pass in the same value as **proj.nim**.
|
pass in the same value as **proj.nim**.
|
||||||
|
|
||||||
`DIRTY_FILE`
|
`DIRTY_FILE`
|
||||||
The **FILE** parameter is enough for static analysis, but IDEs
|
: The **FILE** parameter is enough for static analysis, but IDEs
|
||||||
tend to have *unsaved buffers* where the user may still be in
|
tend to have *unsaved buffers* where the user may still be in
|
||||||
the middle of typing a line. In such situations the IDE can
|
the middle of typing a line. In such situations the IDE can
|
||||||
save the current contents to a temporary file and then use the
|
save the current contents to a temporary file and then use the
|
||||||
|
|
|
||||||
|
|
@ -398,11 +398,11 @@ Runtime type information
|
||||||
programming language:
|
programming language:
|
||||||
|
|
||||||
Garbage collection
|
Garbage collection
|
||||||
The old GCs use the RTTI for traversing arbitrary Nim types, but usually
|
: The old GCs use the RTTI for traversing arbitrary Nim types, but usually
|
||||||
only the `marker` field which contains a proc that does the traversal.
|
only the `marker` field which contains a proc that does the traversal.
|
||||||
|
|
||||||
Complex assignments
|
Complex assignments
|
||||||
Sequences and strings are implemented as
|
: Sequences and strings are implemented as
|
||||||
pointers to resizable buffers, but Nim requires copying for
|
pointers to resizable buffers, but Nim requires copying for
|
||||||
assignments. Apart from RTTI the compiler also generates copy procedures
|
assignments. Apart from RTTI the compiler also generates copy procedures
|
||||||
as a specialization.
|
as a specialization.
|
||||||
|
|
|
||||||
|
|
@ -1023,24 +1023,24 @@ Pre-defined integer types
|
||||||
These integer types are pre-defined:
|
These integer types are pre-defined:
|
||||||
|
|
||||||
`int`
|
`int`
|
||||||
the generic signed integer type; its size is platform-dependent and has the
|
: the generic signed integer type; its size is platform-dependent and has the
|
||||||
same size as a pointer. This type should be used in general. An integer
|
same size as a pointer. This type should be used in general. An integer
|
||||||
literal that has no type suffix is of this type if it is in the range
|
literal that has no type suffix is of this type if it is in the range
|
||||||
`low(int32)..high(int32)` otherwise the literal's type is `int64`.
|
`low(int32)..high(int32)` otherwise the literal's type is `int64`.
|
||||||
|
|
||||||
`int`\ XX
|
`int`\ XX
|
||||||
additional signed integer types of XX bits use this naming scheme
|
: additional signed integer types of XX bits use this naming scheme
|
||||||
(example: int16 is a 16-bit wide integer).
|
(example: int16 is a 16-bit wide integer).
|
||||||
The current implementation supports `int8`, `int16`, `int32`, `int64`.
|
The current implementation supports `int8`, `int16`, `int32`, `int64`.
|
||||||
Literals of these types have the suffix 'iXX.
|
Literals of these types have the suffix 'iXX.
|
||||||
|
|
||||||
`uint`
|
`uint`
|
||||||
the generic `unsigned integer`:idx: type; its size is platform-dependent and
|
: the generic `unsigned integer`:idx: type; its size is platform-dependent and
|
||||||
has the same size as a pointer. An integer literal with the type
|
has the same size as a pointer. An integer literal with the type
|
||||||
suffix `'u` is of this type.
|
suffix `'u` is of this type.
|
||||||
|
|
||||||
`uint`\ XX
|
`uint`\ XX
|
||||||
additional unsigned integer types of XX bits use this naming scheme
|
: additional unsigned integer types of XX bits use this naming scheme
|
||||||
(example: uint16 is a 16-bit wide unsigned integer).
|
(example: uint16 is a 16-bit wide unsigned integer).
|
||||||
The current implementation supports `uint8`, `uint16`, `uint32`,
|
The current implementation supports `uint8`, `uint16`, `uint32`,
|
||||||
`uint64`. Literals of these types have the suffix 'uXX.
|
`uint64`. Literals of these types have the suffix 'uXX.
|
||||||
|
|
@ -1135,12 +1135,12 @@ Pre-defined floating-point types
|
||||||
The following floating-point types are pre-defined:
|
The following floating-point types are pre-defined:
|
||||||
|
|
||||||
`float`
|
`float`
|
||||||
the generic floating-point type; its size used to be platform-dependent,
|
: the generic floating-point type; its size used to be platform-dependent,
|
||||||
but now it is always mapped to `float64`.
|
but now it is always mapped to `float64`.
|
||||||
This type should be used in general.
|
This type should be used in general.
|
||||||
|
|
||||||
`float`\ XX
|
`float`\ XX
|
||||||
an implementation may define additional floating-point types of XX bits using
|
: an implementation may define additional floating-point types of XX bits using
|
||||||
this naming scheme (example: `float64` is a 64-bit wide float). The current
|
this naming scheme (example: `float64` is a 64-bit wide float). The current
|
||||||
implementation supports `float32` and `float64`. Literals of these types
|
implementation supports `float32` and `float64`. Literals of these types
|
||||||
have the suffix 'fXX.
|
have the suffix 'fXX.
|
||||||
|
|
@ -2092,52 +2092,52 @@ that expects a proc of the calling convention `closure`.
|
||||||
Nim supports these `calling conventions`:idx:\:
|
Nim supports these `calling conventions`:idx:\:
|
||||||
|
|
||||||
`nimcall`:idx:
|
`nimcall`:idx:
|
||||||
is the default convention used for a Nim **proc**. It is the
|
: is the default convention used for a Nim **proc**. It is the
|
||||||
same as `fastcall`, but only for C compilers that support `fastcall`.
|
same as `fastcall`, but only for C compilers that support `fastcall`.
|
||||||
|
|
||||||
`closure`:idx:
|
`closure`:idx:
|
||||||
is the default calling convention for a **procedural type** that lacks
|
: is the default calling convention for a **procedural type** that lacks
|
||||||
any pragma annotations. It indicates that the procedure has a hidden
|
any pragma annotations. It indicates that the procedure has a hidden
|
||||||
implicit parameter (an *environment*). Proc vars that have the calling
|
implicit parameter (an *environment*). Proc vars that have the calling
|
||||||
convention `closure` take up two machine words: One for the proc pointer
|
convention `closure` take up two machine words: One for the proc pointer
|
||||||
and another one for the pointer to implicitly passed environment.
|
and another one for the pointer to implicitly passed environment.
|
||||||
|
|
||||||
`stdcall`:idx:
|
`stdcall`:idx:
|
||||||
This is the stdcall convention as specified by Microsoft. The generated C
|
: This is the stdcall convention as specified by Microsoft. The generated C
|
||||||
procedure is declared with the `__stdcall` keyword.
|
procedure is declared with the `__stdcall` keyword.
|
||||||
|
|
||||||
`cdecl`:idx:
|
`cdecl`:idx:
|
||||||
The cdecl convention means that a procedure shall use the same convention
|
: The cdecl convention means that a procedure shall use the same convention
|
||||||
as the C compiler. Under Windows the generated C procedure is declared with
|
as the C compiler. Under Windows the generated C procedure is declared with
|
||||||
the `__cdecl` keyword.
|
the `__cdecl` keyword.
|
||||||
|
|
||||||
`safecall`:idx:
|
`safecall`:idx:
|
||||||
This is the safecall convention as specified by Microsoft. The generated C
|
: This is the safecall convention as specified by Microsoft. The generated C
|
||||||
procedure is declared with the `__safecall` keyword. The word *safe*
|
procedure is declared with the `__safecall` keyword. The word *safe*
|
||||||
refers to the fact that all hardware registers shall be pushed to the
|
refers to the fact that all hardware registers shall be pushed to the
|
||||||
hardware stack.
|
hardware stack.
|
||||||
|
|
||||||
`inline`:idx:
|
`inline`:idx:
|
||||||
The inline convention means the caller should not call the procedure,
|
: The inline convention means the caller should not call the procedure,
|
||||||
but inline its code directly. Note that Nim does not inline, but leaves
|
but inline its code directly. Note that Nim does not inline, but leaves
|
||||||
this to the C compiler; it generates `__inline` procedures. This is
|
this to the C compiler; it generates `__inline` procedures. This is
|
||||||
only a hint for the compiler: it may completely ignore it, and
|
only a hint for the compiler: it may completely ignore it, and
|
||||||
it may inline procedures that are not marked as `inline`.
|
it may inline procedures that are not marked as `inline`.
|
||||||
|
|
||||||
`fastcall`:idx:
|
`fastcall`:idx:
|
||||||
Fastcall means different things to different C compilers. One gets whatever
|
: Fastcall means different things to different C compilers. One gets whatever
|
||||||
the C `__fastcall` means.
|
the C `__fastcall` means.
|
||||||
|
|
||||||
`thiscall`:idx:
|
`thiscall`:idx:
|
||||||
This is the thiscall calling convention as specified by Microsoft, used on
|
: This is the thiscall calling convention as specified by Microsoft, used on
|
||||||
C++ class member functions on the x86 architecture.
|
C++ class member functions on the x86 architecture.
|
||||||
|
|
||||||
`syscall`:idx:
|
`syscall`:idx:
|
||||||
The syscall convention is the same as `__syscall`:c: in C. It is used for
|
: The syscall convention is the same as `__syscall`:c: in C. It is used for
|
||||||
interrupts.
|
interrupts.
|
||||||
|
|
||||||
`noconv`:idx:
|
`noconv`:idx:
|
||||||
The generated C code will not have any explicit calling convention and thus
|
: The generated C code will not have any explicit calling convention and thus
|
||||||
use the C compiler's default calling convention. This is needed because
|
use the C compiler's default calling convention. This is needed because
|
||||||
Nim's default calling convention for procedures is `fastcall` to
|
Nim's default calling convention for procedures is `fastcall` to
|
||||||
improve speed.
|
improve speed.
|
||||||
|
|
|
||||||
|
|
@ -63,10 +63,10 @@ a location. A query location consists of:
|
||||||
|
|
||||||
|
|
||||||
``file.nim``
|
``file.nim``
|
||||||
This is the name of the module or include file the query refers to.
|
: This is the name of the module or include file the query refers to.
|
||||||
|
|
||||||
``dirtyfile.nim``
|
``dirtyfile.nim``
|
||||||
This is optional.
|
: This is optional.
|
||||||
|
|
||||||
The `file` parameter is enough for static analysis, but IDEs
|
The `file` parameter is enough for static analysis, but IDEs
|
||||||
tend to have *unsaved buffers* where the user may still be in
|
tend to have *unsaved buffers* where the user may still be in
|
||||||
|
|
@ -77,11 +77,11 @@ a location. A query location consists of:
|
||||||
|
|
||||||
|
|
||||||
``line``
|
``line``
|
||||||
An integer with the line you are going to query. For the compiler
|
: An integer with the line you are going to query. For the compiler
|
||||||
lines start at **1**.
|
lines start at **1**.
|
||||||
|
|
||||||
``col``
|
``col``
|
||||||
An integer with the column you are going to query. For the
|
: An integer with the column you are going to query. For the
|
||||||
compiler columns start at **0**.
|
compiler columns start at **0**.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,16 +75,16 @@ type
|
||||||
## comment".`
|
## comment".`
|
||||||
##
|
##
|
||||||
## `pattern: string`
|
## `pattern: string`
|
||||||
## the string that was used to create the pattern. For details on how
|
## : the string that was used to create the pattern. For details on how
|
||||||
## to write a pattern, please see `the official PCRE pattern
|
## to write a pattern, please see `the official PCRE pattern
|
||||||
## documentation.
|
## documentation.
|
||||||
## <https://www.pcre.org/original/doc/html/pcrepattern.html>`_
|
## <https://www.pcre.org/original/doc/html/pcrepattern.html>`_
|
||||||
##
|
##
|
||||||
## `captureCount: int`
|
## `captureCount: int`
|
||||||
## the number of captures that the pattern has.
|
## : the number of captures that the pattern has.
|
||||||
##
|
##
|
||||||
## `captureNameId: Table[string, int]`
|
## `captureNameId: Table[string, int]`
|
||||||
## a table from the capture names to their numeric id.
|
## : a table from the capture names to their numeric id.
|
||||||
##
|
##
|
||||||
##
|
##
|
||||||
## Options
|
## Options
|
||||||
|
|
@ -151,36 +151,36 @@ type
|
||||||
## execution. On failure, it is none, on success, it is some.
|
## execution. On failure, it is none, on success, it is some.
|
||||||
##
|
##
|
||||||
## `pattern: Regex`
|
## `pattern: Regex`
|
||||||
## the pattern that is being matched
|
## : the pattern that is being matched
|
||||||
##
|
##
|
||||||
## `str: string`
|
## `str: string`
|
||||||
## the string that was matched against
|
## : the string that was matched against
|
||||||
##
|
##
|
||||||
## `captures[]: string`
|
## `captures[]: string`
|
||||||
## the string value of whatever was captured at that id. If the value
|
## : the string value of whatever was captured at that id. If the value
|
||||||
## is invalid, then behavior is undefined. If the id is `-1`, then
|
## is invalid, then behavior is undefined. If the id is `-1`, then
|
||||||
## the whole match is returned. If the given capture was not matched,
|
## the whole match is returned. If the given capture was not matched,
|
||||||
## `nil` is returned. See examples for `match`.
|
## `nil` is returned. See examples for `match`.
|
||||||
##
|
##
|
||||||
## `captureBounds[]: HSlice[int, int]`
|
## `captureBounds[]: HSlice[int, int]`
|
||||||
## gets the bounds of the given capture according to the same rules as
|
## : gets the bounds of the given capture according to the same rules as
|
||||||
## the above. If the capture is not filled, then `None` is returned.
|
## the above. If the capture is not filled, then `None` is returned.
|
||||||
## The bounds are both inclusive. See examples for `match`.
|
## The bounds are both inclusive. See examples for `match`.
|
||||||
##
|
##
|
||||||
## `match: string`
|
## `match: string`
|
||||||
## the full text of the match.
|
## : the full text of the match.
|
||||||
##
|
##
|
||||||
## `matchBounds: HSlice[int, int]`
|
## `matchBounds: HSlice[int, int]`
|
||||||
## the bounds of the match, as in `captureBounds[]`
|
## : the bounds of the match, as in `captureBounds[]`
|
||||||
##
|
##
|
||||||
## `(captureBounds|captures).toTable`
|
## `(captureBounds|captures).toTable`
|
||||||
## returns a table with each named capture as a key.
|
## : returns a table with each named capture as a key.
|
||||||
##
|
##
|
||||||
## `(captureBounds|captures).toSeq`
|
## `(captureBounds|captures).toSeq`
|
||||||
## returns all the captures by their number.
|
## : returns all the captures by their number.
|
||||||
##
|
##
|
||||||
## `$: string`
|
## `$: string`
|
||||||
## same as `match`
|
## : same as `match`
|
||||||
pattern*: Regex ## The regex doing the matching.
|
pattern*: Regex ## The regex doing the matching.
|
||||||
## Not nil.
|
## Not nil.
|
||||||
str*: string ## The string that was matched against.
|
str*: string ## The string that was matched against.
|
||||||
|
|
@ -583,11 +583,11 @@ proc find*(str: string, pattern: Regex, start = 0, endpos = int.high): Option[Re
|
||||||
## positions.
|
## positions.
|
||||||
##
|
##
|
||||||
## `start`
|
## `start`
|
||||||
## The start point at which to start matching. `|abc` is `0`;
|
## : The start point at which to start matching. `|abc` is `0`;
|
||||||
## `a|bc` is `1`
|
## `a|bc` is `1`
|
||||||
##
|
##
|
||||||
## `endpos`
|
## `endpos`
|
||||||
## The maximum index for a match; `int.high` means the end of the
|
## : The maximum index for a match; `int.high` means the end of the
|
||||||
## string, otherwise it’s an inclusive upper bound.
|
## string, otherwise it’s an inclusive upper bound.
|
||||||
return str.matchImpl(pattern, start, endpos, 0)
|
return str.matchImpl(pattern, start, endpos, 0)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2064,7 +2064,22 @@ proc getWrappableIndent(p: RstParser): int =
|
||||||
elif nextIndent >= currentTok(p).col: # may be a definition list [case.2]
|
elif nextIndent >= currentTok(p).col: # may be a definition list [case.2]
|
||||||
result = currentTok(p).col
|
result = currentTok(p).col
|
||||||
else:
|
else:
|
||||||
result = nextIndent # [case.3]
|
result = nextIndent # allow parsing next lines [case.3]
|
||||||
|
|
||||||
|
proc getMdBlockIndent(p: RstParser): int =
|
||||||
|
## Markdown version of `getWrappableIndent`.
|
||||||
|
if currentTok(p).kind == tkIndent:
|
||||||
|
result = currentTok(p).ival
|
||||||
|
else:
|
||||||
|
var nextIndent = p.tok[tokenAfterNewline(p)-1].ival
|
||||||
|
# TODO: Markdown-compliant definition should allow nextIndent == currInd(p):
|
||||||
|
if nextIndent <= currInd(p): # parse only this line
|
||||||
|
result = currentTok(p).col
|
||||||
|
else:
|
||||||
|
result = nextIndent # allow parsing next lines [case.3]
|
||||||
|
|
||||||
|
template isRst(p: RstParser): bool = roPreferMarkdown notin p.s.options
|
||||||
|
template isMd(p: RstParser): bool = roPreferMarkdown in p.s.options
|
||||||
|
|
||||||
proc parseField(p: var RstParser): PRstNode =
|
proc parseField(p: var RstParser): PRstNode =
|
||||||
## Returns a parsed rnField node.
|
## Returns a parsed rnField node.
|
||||||
|
|
@ -2309,6 +2324,39 @@ proc isDefList(p: RstParser): bool =
|
||||||
p.tok[j].kind in {tkWord, tkOther, tkPunct} and
|
p.tok[j].kind in {tkWord, tkOther, tkPunct} and
|
||||||
p.tok[j - 2].symbol != "::"
|
p.tok[j - 2].symbol != "::"
|
||||||
|
|
||||||
|
proc `$`(t: Token): string = # for debugging only
|
||||||
|
result = "(" & $t.kind & " line=" & $t.line & " col=" & $t.col
|
||||||
|
if t.kind == tkIndent: result = result & " ival=" & $t.ival & ")"
|
||||||
|
else: result = result & " symbol=" & t.symbol & ")"
|
||||||
|
|
||||||
|
proc skipNewlines(p: RstParser, j: int): int =
|
||||||
|
result = j
|
||||||
|
while p.tok[result].kind != tkEof and p.tok[result].kind == tkIndent:
|
||||||
|
inc result # skip blank lines
|
||||||
|
|
||||||
|
proc skipNewlines(p: var RstParser) =
|
||||||
|
p.idx = skipNewlines(p, p.idx)
|
||||||
|
|
||||||
|
const maxMdRelInd = 3 ## In Markdown: maximum indentation that does not yet
|
||||||
|
## make the indented block a code
|
||||||
|
|
||||||
|
proc isMdRelInd(outerInd, nestedInd: int): bool =
|
||||||
|
result = outerInd <= nestedInd and nestedInd <= outerInd + maxMdRelInd
|
||||||
|
|
||||||
|
proc isMdDefBody(p: RstParser, j: int, termCol: int): bool =
|
||||||
|
let defCol = p.tok[j].col
|
||||||
|
result = p.tok[j].symbol == ":" and
|
||||||
|
isMdRelInd(termCol, defCol) and
|
||||||
|
p.tok[j+1].kind == tkWhite and
|
||||||
|
p.tok[j+2].kind in {tkWord, tkOther, tkPunct}
|
||||||
|
|
||||||
|
proc isMdDefListItem(p: RstParser, idx: int): bool =
|
||||||
|
var j = tokenAfterNewline(p, idx)
|
||||||
|
j = skipNewlines(p, j)
|
||||||
|
let termCol = p.tok[j].col
|
||||||
|
result = isMdRelInd(currInd(p), termCol) and
|
||||||
|
isMdDefBody(p, j, termCol)
|
||||||
|
|
||||||
proc isOptionList(p: RstParser): bool =
|
proc isOptionList(p: RstParser): bool =
|
||||||
result = match(p, p.idx, "-w") or match(p, p.idx, "--w") or
|
result = match(p, p.idx, "-w") or match(p, p.idx, "--w") or
|
||||||
match(p, p.idx, "/w") or match(p, p.idx, "//w")
|
match(p, p.idx, "/w") or match(p, p.idx, "//w")
|
||||||
|
|
@ -2381,8 +2429,10 @@ proc whichSection(p: RstParser): RstNodeKind =
|
||||||
result = rnEnumList
|
result = rnEnumList
|
||||||
elif isOptionList(p):
|
elif isOptionList(p):
|
||||||
result = rnOptionList
|
result = rnOptionList
|
||||||
elif isDefList(p):
|
elif isRst(p) and isDefList(p):
|
||||||
result = rnDefList
|
result = rnDefList
|
||||||
|
elif isMd(p) and isMdDefListItem(p, p.idx):
|
||||||
|
result = rnMdDefList
|
||||||
else:
|
else:
|
||||||
result = rnParagraph
|
result = rnParagraph
|
||||||
of tkWord, tkOther, tkWhite:
|
of tkWord, tkOther, tkWhite:
|
||||||
|
|
@ -2391,7 +2441,9 @@ proc whichSection(p: RstParser): RstNodeKind =
|
||||||
if isAdornmentHeadline(p, tokIdx): result = rnHeadline
|
if isAdornmentHeadline(p, tokIdx): result = rnHeadline
|
||||||
else: result = rnParagraph
|
else: result = rnParagraph
|
||||||
elif match(p, p.idx, "e) ") or match(p, p.idx, "e. "): result = rnEnumList
|
elif match(p, p.idx, "e) ") or match(p, p.idx, "e. "): result = rnEnumList
|
||||||
elif isDefList(p): result = rnDefList
|
elif isRst(p) and isDefList(p): result = rnDefList
|
||||||
|
elif isMd(p) and isMdDefListItem(p, p.idx):
|
||||||
|
result = rnMdDefList
|
||||||
else: result = rnParagraph
|
else: result = rnParagraph
|
||||||
else: result = rnLeaf
|
else: result = rnLeaf
|
||||||
|
|
||||||
|
|
@ -2921,6 +2973,36 @@ proc parseOptionList(p: var RstParser): PRstNode =
|
||||||
if currentTok(p).kind != tkEof: dec p.idx # back to tkIndent
|
if currentTok(p).kind != tkEof: dec p.idx # back to tkIndent
|
||||||
break
|
break
|
||||||
|
|
||||||
|
proc parseMdDefinitionList(p: var RstParser): PRstNode =
|
||||||
|
## Parses (Pandoc/kramdown/PHPextra) Mardkown definition lists.
|
||||||
|
result = newRstNodeA(p, rnMdDefList)
|
||||||
|
let termCol = currentTok(p).col
|
||||||
|
while true:
|
||||||
|
var item = newRstNode(rnDefItem)
|
||||||
|
var term = newRstNode(rnDefName)
|
||||||
|
parseLine(p, term)
|
||||||
|
skipNewlines(p)
|
||||||
|
inc p.idx, 2 # skip ":" and space
|
||||||
|
item.add(term)
|
||||||
|
while true:
|
||||||
|
var def = newRstNode(rnDefBody)
|
||||||
|
let indent = getMdBlockIndent(p)
|
||||||
|
pushInd(p, indent)
|
||||||
|
parseSection(p, def)
|
||||||
|
popInd(p)
|
||||||
|
item.add(def)
|
||||||
|
let j = skipNewlines(p, p.idx)
|
||||||
|
if isMdDefBody(p, j, termCol): # parse next definition body
|
||||||
|
p.idx = j + 2 # skip ":" and space
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
result.add(item)
|
||||||
|
let j = skipNewlines(p, p.idx)
|
||||||
|
if p.tok[j].col == termCol and isMdDefListItem(p, j):
|
||||||
|
p.idx = j # parse next item
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
proc parseDefinitionList(p: var RstParser): PRstNode =
|
proc parseDefinitionList(p: var RstParser): PRstNode =
|
||||||
result = nil
|
result = nil
|
||||||
var j = tokenAfterNewline(p) - 1
|
var j = tokenAfterNewline(p) - 1
|
||||||
|
|
@ -3094,6 +3176,7 @@ proc parseSection(p: var RstParser, result: PRstNode) =
|
||||||
of rnLeaf: rstMessage(p, meNewSectionExpected, "(syntax error)")
|
of rnLeaf: rstMessage(p, meNewSectionExpected, "(syntax error)")
|
||||||
of rnParagraph: discard
|
of rnParagraph: discard
|
||||||
of rnDefList: a = parseDefinitionList(p)
|
of rnDefList: a = parseDefinitionList(p)
|
||||||
|
of rnMdDefList: a = parseMdDefinitionList(p)
|
||||||
of rnFieldList:
|
of rnFieldList:
|
||||||
if p.idx > 0: dec p.idx
|
if p.idx > 0: dec p.idx
|
||||||
a = parseFields(p)
|
a = parseFields(p)
|
||||||
|
|
@ -3120,9 +3203,6 @@ proc parseSectionWrapper(p: var RstParser): PRstNode =
|
||||||
while result.kind == rnInner and result.len == 1:
|
while result.kind == rnInner and result.len == 1:
|
||||||
result = result.sons[0]
|
result = result.sons[0]
|
||||||
|
|
||||||
proc `$`(t: Token): string =
|
|
||||||
result = $t.kind & ' ' & t.symbol
|
|
||||||
|
|
||||||
proc parseDoc(p: var RstParser): PRstNode =
|
proc parseDoc(p: var RstParser): PRstNode =
|
||||||
result = parseSectionWrapper(p)
|
result = parseSectionWrapper(p)
|
||||||
if currentTok(p).kind != tkEof:
|
if currentTok(p).kind != tkEof:
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ type
|
||||||
rnBulletItem, # a bullet item
|
rnBulletItem, # a bullet item
|
||||||
rnEnumList, # an enumerated list
|
rnEnumList, # an enumerated list
|
||||||
rnEnumItem, # an enumerated item
|
rnEnumItem, # an enumerated item
|
||||||
rnDefList, # a definition list
|
rnDefList, rnMdDefList, # a definition list (RST/Markdown)
|
||||||
rnDefItem, # an item of a definition list consisting of ...
|
rnDefItem, # an item of a definition list consisting of ...
|
||||||
rnDefName, # ... a name part ...
|
rnDefName, # ... a name part ...
|
||||||
rnDefBody, # ... and a body part ...
|
rnDefBody, # ... and a body part ...
|
||||||
|
|
|
||||||
|
|
@ -1212,7 +1212,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||||
of rnBulletItem, rnEnumItem:
|
of rnBulletItem, rnEnumItem:
|
||||||
renderAux(d, n, "<li$2>$1</li>\n", "\\item $2$1\n", result)
|
renderAux(d, n, "<li$2>$1</li>\n", "\\item $2$1\n", result)
|
||||||
of rnEnumList: renderEnumList(d, n, result)
|
of rnEnumList: renderEnumList(d, n, result)
|
||||||
of rnDefList:
|
of rnDefList, rnMdDefList:
|
||||||
renderAux(d, n, "<dl$2 class=\"docutils\">$1</dl>\n",
|
renderAux(d, n, "<dl$2 class=\"docutils\">$1</dl>\n",
|
||||||
"\\begin{description}\n$2\n$1\\end{description}\n", result)
|
"\\begin{description}\n$2\n$1\\end{description}\n", result)
|
||||||
of rnDefItem: renderAux(d, n, result)
|
of rnDefItem: renderAux(d, n, result)
|
||||||
|
|
|
||||||
|
|
@ -825,10 +825,10 @@ proc rotateLeft*[T](arg: var openArray[T]; slice: HSlice[int, int];
|
||||||
## If an invalid range (`HSlice`) is passed, it raises `IndexDefect`.
|
## If an invalid range (`HSlice`) is passed, it raises `IndexDefect`.
|
||||||
##
|
##
|
||||||
## `slice`
|
## `slice`
|
||||||
## The indices of the element range that should be rotated.
|
## : The indices of the element range that should be rotated.
|
||||||
##
|
##
|
||||||
## `dist`
|
## `dist`
|
||||||
## The distance in amount of elements that the data should be rotated.
|
## : The distance in amount of elements that the data should be rotated.
|
||||||
## Can be negative, can be any number.
|
## Can be negative, can be any number.
|
||||||
##
|
##
|
||||||
## **See also:**
|
## **See also:**
|
||||||
|
|
@ -876,10 +876,10 @@ proc rotatedLeft*[T](arg: openArray[T]; slice: HSlice[int, int],
|
||||||
## If an invalid range (`HSlice`) is passed, it raises `IndexDefect`.
|
## If an invalid range (`HSlice`) is passed, it raises `IndexDefect`.
|
||||||
##
|
##
|
||||||
## `slice`
|
## `slice`
|
||||||
## The indices of the element range that should be rotated.
|
## : The indices of the element range that should be rotated.
|
||||||
##
|
##
|
||||||
## `dist`
|
## `dist`
|
||||||
## The distance in amount of elements that the data should be rotated.
|
## : The distance in amount of elements that the data should be rotated.
|
||||||
## Can be negative, can be any number.
|
## Can be negative, can be any number.
|
||||||
##
|
##
|
||||||
## **See also:**
|
## **See also:**
|
||||||
|
|
|
||||||
|
|
@ -180,15 +180,15 @@ The square brackets `[]` indicate an optional element.
|
||||||
The optional `align` flag can be one of the following:
|
The optional `align` flag can be one of the following:
|
||||||
|
|
||||||
`<`
|
`<`
|
||||||
Forces the field to be left-aligned within the available
|
: Forces the field to be left-aligned within the available
|
||||||
space. (This is the default for strings.)
|
space. (This is the default for strings.)
|
||||||
|
|
||||||
`>`
|
`>`
|
||||||
Forces the field to be right-aligned within the available space.
|
: Forces the field to be right-aligned within the available space.
|
||||||
(This is the default for numbers.)
|
(This is the default for numbers.)
|
||||||
|
|
||||||
`^`
|
`^`
|
||||||
Forces the field to be centered within the available space.
|
: Forces the field to be centered within the available space.
|
||||||
|
|
||||||
Note that unless a minimum field width is defined, the field width
|
Note that unless a minimum field width is defined, the field width
|
||||||
will always be the same size as the data to fill it, so that the alignment
|
will always be the same size as the data to fill it, so that the alignment
|
||||||
|
|
|
||||||
|
|
@ -78,19 +78,23 @@ proc floorDivPow2(x: int32; n: int32): int32 {.inline.} =
|
||||||
return x shr n
|
return x shr n
|
||||||
|
|
||||||
## Returns floor(log_10(2^e))
|
## Returns floor(log_10(2^e))
|
||||||
|
## ```c
|
||||||
## static inline int32_t FloorLog10Pow2(int32_t e)
|
## static inline int32_t FloorLog10Pow2(int32_t e)
|
||||||
## {
|
## {
|
||||||
## SF_ASSERT(e >= -1500);
|
## SF_ASSERT(e >= -1500);
|
||||||
## SF_ASSERT(e <= 1500);
|
## SF_ASSERT(e <= 1500);
|
||||||
## return FloorDivPow2(e * 1262611, 22);
|
## return FloorDivPow2(e * 1262611, 22);
|
||||||
## }
|
## }
|
||||||
|
## ```
|
||||||
## Returns floor(log_10(3/4 2^e))
|
## Returns floor(log_10(3/4 2^e))
|
||||||
|
## ```c
|
||||||
## static inline int32_t FloorLog10ThreeQuartersPow2(int32_t e)
|
## static inline int32_t FloorLog10ThreeQuartersPow2(int32_t e)
|
||||||
## {
|
## {
|
||||||
## SF_ASSERT(e >= -1500);
|
## SF_ASSERT(e >= -1500);
|
||||||
## SF_ASSERT(e <= 1500);
|
## SF_ASSERT(e <= 1500);
|
||||||
## return FloorDivPow2(e * 1262611 - 524031, 22);
|
## return FloorDivPow2(e * 1262611 - 524031, 22);
|
||||||
## }
|
## }
|
||||||
|
## ```
|
||||||
## Returns floor(log_2(10^e))
|
## Returns floor(log_2(10^e))
|
||||||
|
|
||||||
proc floorLog2Pow10(e: int32): int32 {.inline.} =
|
proc floorLog2Pow10(e: int32): int32 {.inline.} =
|
||||||
|
|
|
||||||
|
|
@ -423,21 +423,21 @@ suite "RST parsing":
|
||||||
.. Note:: deflist:
|
.. Note:: deflist:
|
||||||
>> quote
|
>> quote
|
||||||
continuation
|
continuation
|
||||||
""".toAst == expected)
|
""".toAst(rstOptions = preferRst) == expected)
|
||||||
|
|
||||||
check(dedent"""
|
check(dedent"""
|
||||||
.. Note::
|
.. Note::
|
||||||
deflist:
|
deflist:
|
||||||
>> quote
|
>> quote
|
||||||
continuation
|
continuation
|
||||||
""".toAst == expected)
|
""".toAst(rstOptions = preferRst) == expected)
|
||||||
|
|
||||||
check(dedent"""
|
check(dedent"""
|
||||||
.. Note::
|
.. Note::
|
||||||
deflist:
|
deflist:
|
||||||
>> quote
|
>> quote
|
||||||
>> continuation
|
>> continuation
|
||||||
""".toAst == expected)
|
""".toAst(rstOptions = preferRst) == expected)
|
||||||
|
|
||||||
# spaces are not significant between `>`:
|
# spaces are not significant between `>`:
|
||||||
check(dedent"""
|
check(dedent"""
|
||||||
|
|
@ -445,7 +445,7 @@ suite "RST parsing":
|
||||||
deflist:
|
deflist:
|
||||||
> > quote
|
> > quote
|
||||||
> > continuation
|
> > continuation
|
||||||
""".toAst == expected)
|
""".toAst(rstOptions = preferRst) == expected)
|
||||||
|
|
||||||
test "Markdown quoted blocks: de-indent handled well":
|
test "Markdown quoted blocks: de-indent handled well":
|
||||||
check(dedent"""
|
check(dedent"""
|
||||||
|
|
@ -616,27 +616,28 @@ suite "RST parsing":
|
||||||
check inputTilde.toAst == expected
|
check inputTilde.toAst == expected
|
||||||
|
|
||||||
test "option list has priority over definition list":
|
test "option list has priority over definition list":
|
||||||
check(dedent"""
|
for opt in [preferMarkdown, preferRst]:
|
||||||
--defusages
|
check(dedent"""
|
||||||
file
|
--defusages
|
||||||
-o set
|
file
|
||||||
""".toAst ==
|
-o set
|
||||||
dedent"""
|
""".toAst(rstOptions = opt) ==
|
||||||
rnOptionList
|
dedent"""
|
||||||
rnOptionListItem order=1
|
rnOptionList
|
||||||
rnOptionGroup
|
rnOptionListItem order=1
|
||||||
rnLeaf '--'
|
rnOptionGroup
|
||||||
rnLeaf 'defusages'
|
rnLeaf '--'
|
||||||
rnDescription
|
rnLeaf 'defusages'
|
||||||
rnInner
|
rnDescription
|
||||||
rnLeaf 'file'
|
rnInner
|
||||||
rnOptionListItem order=2
|
rnLeaf 'file'
|
||||||
rnOptionGroup
|
rnOptionListItem order=2
|
||||||
rnLeaf '-'
|
rnOptionGroup
|
||||||
rnLeaf 'o'
|
rnLeaf '-'
|
||||||
rnDescription
|
rnLeaf 'o'
|
||||||
rnLeaf 'set'
|
rnDescription
|
||||||
""")
|
rnLeaf 'set'
|
||||||
|
""")
|
||||||
|
|
||||||
test "items of 1 option list can be separated by blank lines":
|
test "items of 1 option list can be separated by blank lines":
|
||||||
check(dedent"""
|
check(dedent"""
|
||||||
|
|
@ -660,13 +661,13 @@ suite "RST parsing":
|
||||||
rnLeaf 'desc2'
|
rnLeaf 'desc2'
|
||||||
""")
|
""")
|
||||||
|
|
||||||
test "option list has priority over definition list":
|
test "definition list does not gobble up the following blocks":
|
||||||
check(dedent"""
|
check(dedent"""
|
||||||
defName
|
defName
|
||||||
defBody
|
defBody
|
||||||
|
|
||||||
-b desc2
|
-b desc2
|
||||||
""".toAst ==
|
""".toAst(rstOptions = preferRst) ==
|
||||||
dedent"""
|
dedent"""
|
||||||
rnInner
|
rnInner
|
||||||
rnDefList
|
rnDefList
|
||||||
|
|
@ -1054,7 +1055,7 @@ suite "RST indentation":
|
||||||
term2
|
term2
|
||||||
Definition2
|
Definition2
|
||||||
"""
|
"""
|
||||||
check(input.toAst == dedent"""
|
check(input.toAst(rstOptions = preferRst) == dedent"""
|
||||||
rnEnumList labelFmt=1)
|
rnEnumList labelFmt=1)
|
||||||
rnEnumItem
|
rnEnumItem
|
||||||
rnAdmonition adType=hint
|
rnAdmonition adType=hint
|
||||||
|
|
@ -1157,6 +1158,85 @@ suite "RST indentation":
|
||||||
# "template..." should be parsed as a definition list attached to ":test:":
|
# "template..." should be parsed as a definition list attached to ":test:":
|
||||||
check inputWrong.toAst != ast
|
check inputWrong.toAst != ast
|
||||||
|
|
||||||
|
test "Markdown definition lists work in conjunction with bullet lists":
|
||||||
|
check(dedent"""
|
||||||
|
* some term
|
||||||
|
: the definition
|
||||||
|
|
||||||
|
Paragraph.""".toAst ==
|
||||||
|
dedent"""
|
||||||
|
rnInner
|
||||||
|
rnBulletList
|
||||||
|
rnBulletItem
|
||||||
|
rnMdDefList
|
||||||
|
rnDefItem
|
||||||
|
rnDefName
|
||||||
|
rnLeaf 'some'
|
||||||
|
rnLeaf ' '
|
||||||
|
rnLeaf 'term'
|
||||||
|
rnDefBody
|
||||||
|
rnInner
|
||||||
|
rnLeaf 'the'
|
||||||
|
rnLeaf ' '
|
||||||
|
rnLeaf 'definition'
|
||||||
|
rnParagraph
|
||||||
|
rnLeaf 'Paragraph'
|
||||||
|
rnLeaf '.'
|
||||||
|
""")
|
||||||
|
|
||||||
|
test "Markdown definition lists work with blank lines and extra paragraphs":
|
||||||
|
check(dedent"""
|
||||||
|
Term1
|
||||||
|
|
||||||
|
: Definition1
|
||||||
|
|
||||||
|
Term2 *inline markup*
|
||||||
|
|
||||||
|
: Definition2
|
||||||
|
|
||||||
|
Paragraph2
|
||||||
|
|
||||||
|
Term3
|
||||||
|
: * point1
|
||||||
|
* point2
|
||||||
|
: term3definition2
|
||||||
|
""".toAst == dedent"""
|
||||||
|
rnMdDefList
|
||||||
|
rnDefItem
|
||||||
|
rnDefName
|
||||||
|
rnLeaf 'Term1'
|
||||||
|
rnDefBody
|
||||||
|
rnInner
|
||||||
|
rnLeaf 'Definition1'
|
||||||
|
rnDefItem
|
||||||
|
rnDefName
|
||||||
|
rnLeaf 'Term2'
|
||||||
|
rnLeaf ' '
|
||||||
|
rnEmphasis
|
||||||
|
rnLeaf 'inline'
|
||||||
|
rnLeaf ' '
|
||||||
|
rnLeaf 'markup'
|
||||||
|
rnDefBody
|
||||||
|
rnParagraph
|
||||||
|
rnLeaf 'Definition2'
|
||||||
|
rnParagraph
|
||||||
|
rnLeaf 'Paragraph2'
|
||||||
|
rnDefItem
|
||||||
|
rnDefName
|
||||||
|
rnLeaf 'Term3'
|
||||||
|
rnDefBody
|
||||||
|
rnBulletList
|
||||||
|
rnBulletItem
|
||||||
|
rnInner
|
||||||
|
rnLeaf 'point1'
|
||||||
|
rnBulletItem
|
||||||
|
rnInner
|
||||||
|
rnLeaf 'point2'
|
||||||
|
rnDefBody
|
||||||
|
rnInner
|
||||||
|
rnLeaf 'term3definition2'
|
||||||
|
""")
|
||||||
|
|
||||||
suite "Warnings":
|
suite "Warnings":
|
||||||
test "warnings for broken footnotes/links/substitutions":
|
test "warnings for broken footnotes/links/substitutions":
|
||||||
let input = dedent"""
|
let input = dedent"""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue