Escape regular expression characters in a String, an Array of Strings or any Object having a proper toString-method
Detect and return the language that a given file is written in. The language is also annotated with a name property, matching the language's key in LANGUAGES.
If the matcher is a string, we assume that it's a file extension. Stick it in a regex:
Map a list of file paths to relative target paths by stripping prefixes.
Ensure that we're dealing with absolute paths across the board.
And that the strip prefixes all end with a /, avoids absolute target path.
Prefixes are stripped in the order of most specific to least (# of directories deep)
We also strip the extension under the assumption that the consumer of this path map is going to substitute in their own. Plus, if they care about the extension, they can get it from the keys of the map.
Attempt to guess strip prefixes for a given set of arguments.
Most globs look something like dir/*/.ext, so strip up to the leading *
For now, we try to avoid ambiguous situations by guessing the FIRST directory given. The assumption is that you don't want merged paths, but probably did specify the most important source directory first.
How many directories deep is a given path?
Split source code into segments (comment + code pairs)
Always strip shebangs - but don't shift it off the array to avoid the perf hit of walking the array to update indices.
Special case: If the language is comments-only, we can skip pygments
Special case: If the language is code-only, we can shorten the process
Enforced whitespace after the comment token
This flag indicates if the end-mark of block-comments (the blockEnds
list above) must correspond to the initial block-mark (the blockStarts
above). If this flag is missing it defaults to true. The main idea
is to embed sample block-comments with syntax A in another block-comment
with syntax B. This useful in handlebar's mixed syntax or other language
combinations like html+php, which are supported by pygmentize.
This map is used to lookup corresponding line- and end-marks.
No need to match for any particular real content in aBlockStart, as
either aBlockLine, aBlockEnd or the inBlock catch-all fallback
handles the real content, in the implementation below.
A special case used to capture empty block-comment lines, like the one below this line …
… and above this line.
Strip final space only if one is required, hence yet present.
A dirty lap-dance performed here …
… and the corresponding gang-bang here. 8-)
If available we start in literal parsing mode.
Variables used in temporary assignments have been collected here for documentation purposes only.
This flag indicates if the previous line was empty, hence literate code
must always be surrounded (or at least introduced) by an indicator,
which is usually a empty line. This is needed to distinguish code from
bullet-lists or the like, which may accidently match the start of a line
of code. The initial value true allows us to immediately start with
code, although this is quite unusual.
Now iterate over each line
Skip empty code-lines (often used to close a code-block). TODO: Skipping empty code-lines is certainly not perfect yet!
The previous cycle contained literate comments - If one absolutely wants to separate code from comments into independent segments this block must be enabled.
TODO: Implement a better literal-segments solution: If the current segment contains just one empty line, merge the code with the previous segment, and make the previous segment the current
Process the matching literate code as if it isn't literate, hence
we continue further processing of this line and therefore no
continue-statement occurs here. Compare this to the following
else-statement.
A code-block requires an introducing indicator, to distinguish code
from nested bullet-list or the like, as described in the canCode
flag initialization above.
The previous cycle contained literate code, so let's start a new segment, as in literate mode we separate code from comments in independent segments, as overlapping makes no sense in most cases.
TODO: Implement a better literal-segments solution. Idea: (a) Use horizontal lines as split marks (b) Use previous headline (c) Optimize splitArray afterwards ? (d) Combine any of the above
From the previous cycle are comments left not being literate, so let's start a new segment and reset folding state.
Collect this line, even empty ones in literal mode
Switch to plain literal comments
We skip further processing this line. A literal is as it is.
Match that line to the language's block-comment syntax, if it exists
Reusing match as a placeholder.
Strip the block-comments start, preserving any inline stuff.
We don't touch the line itself, as we still need it.
If we found a linemark, prepend it (back) to the blockline, if it
does not correspond to the initial blockmark.
Check if this block-comment is collapsible.
We always start a new segment if the current one is not empty or already folded.
Let's strip the “^” character from our original line, for later use.
Also strip it from our blockline.
Check if this block-comment stays embedded in the code.
Let's strip the “}” character from our original line, for later use.
Also strip it from our blockline.
Block-comments are an important tool to structure code into larger segments, therefore we always start a new segment if the current one is not empty.
This flag is triggered above.
Catch all lines, unless there is a blockline from above.
Match a block-comment's end, even when inFolded or inIgnored flags
are true …
Reusing match as a placeholder.
The endmark must correspond to the blockmark's.
Ensure to leave the block-comment, especially single-lines like this one.
Match a block-comment's line, when inFolded or inIgnored are false.
Reusing match as a placeholder.
If we found a linemark, prepend it (back) to the comment,
if it does not correspond to the initial blockmark.
Make sure that the next cycle starts fresh, if we are going to leave the block.
If the foldMarker is empty assign blockline to foldMarker …
… and collect the blockline as code.
The previous cycle contained code, so lets start a new segment.
A special case as described in the initialization of aEmptyLine.
Collect all but empty start- and end-block-comment lines, hence
single-line block-comments simultaneous matching aBlockStart
and aBlockEnd have a false inBlock flag at this point, are
included.
Strip leading indention from block-comment like the one above
to align their content with the initial blockmark.
The code may occure immediatly after a block-comment end.
Make sure the next cycle starts fresh.
Match that line to the language's single line comment syntax. However, we treat all comments beginning with } as inline code commentary and comments starting with ^ cause that comment and the following code block to start folded.
Uses match as a placeholder.
Let's strip the “}” character from our documentation
The previous cycle contained code, so lets start a new segment and stop any folding.
It's always a good idea to put a comment before folded content like this one here, because folded comments always have their own code-segment in their current implementation (see above). Without a leading comment, the folded code's segment would just follow the above's code segment, which looks visually not so appealing in the narrowed single-column-view.
TODO: Alternative (a): Improve folded comments to not start a new segment, like embedded comments from above. (preferred solution)
TODO: Alternative (b): Improve folded comments visual appearance in single-column view. (easy solution)
Let's strip the “^” character from our documentation
And collect it as code.
We surely (should) have raw code at this point.
Class Segment is in namespace groc.Utils
Just a convenient prototype for building segments
Annotate an array of segments by running their code through Pygments.
Don't bother spawning pygments if we have nothing to highlight
This appears to only occur when pygmentize is missing:
Lack of pygments is a one time setup task, we don't feel bad about killing the process off until the user does so. It's a hard requirement.
We'll just split the output at the end. pygmentize doesn't stream its output, and a given source file is small enough that it shouldn't matter.
v0.8 changed exit/close event semantics.
We can't include either of the following words ANYWHERE directly adjacent to each other Otherwise, our regex (~10 lines below) will split on them, and the number of code blocks and comment blocks will not be equal.
pygments spits it out wrapped in <div class="highlight"><pre>...</pre></div>. We want to
manage the styling ourselves, so remove that.
Extract our segments from the pygmentized source.
Attach highlighted source to the highlightedCode property of a Segment.
Rather than spawning pygments for each segment, we stream it all in, separated by 'magic' comments so that we can split the highlighted source back into segments. To further complicate things, pygments doesn't let us cheat with indentation-aware languages: We have to match the indentation of the line following the divider comment.
Double negative: match characters that are spaces but not newlines
a {type} is an automatically linked {value}
If the value is empty, strip the empty suffix. The simpler
tag.markdown.replace / \*\*$/, '' erroneously fails
Annotate an array of segments by running their comments through showdown.
showdown generates header ids by lowercasing & dropping non-word characters. We'd like something a bit more readable.
We attach the rendered markdown to the comment
As well as the extracted headers to aid in outline building.
Sometimes you just don't want any of them hanging around.
Given a title, convert it into a URL-friendly slug.
replacer is a function that is given the match object, and returns the string to replace with.
Miscellaneous code fragments reside here.
TODO: should be migrated into
lib/utils.