Added file and inline link anchors.
* Auto-link for documents. If there is an `org` directive in the first doc block of the file then it is used as the file link definition. If there is no such `org` directive then on is created automatically. This resolves issue #0008. There is a new LinkAnchor type for these links: `LinkType.FileLink` * Multiple `org` directives per DocBlock are now allowed. There is a new LinkAnchor link type for these link: `LinkType.InlineLink`. * Refactored `LinkType.OrgLink` to be `LinkType.BlockLink`. * Tweaked CSS * Refactored `LiterateMarkdownGenerator.emit(DocBlock)` for simplicity.
This commit is contained in:
parent
051cd54dcd
commit
a86b55726f
@ -1,16 +0,0 @@
|
||||
Fix delimited doc block behavior.
|
||||
=================================
|
||||
|
||||
Delimited doc blocks require that the start token be the first non-space token
|
||||
on the line it is on and that the end token be on it's own line. This is not in
|
||||
line with the general nature of delimited comment blocks, which do not place
|
||||
any restrictions on what comes before the start delimiter or after the end
|
||||
delimiter.
|
||||
|
||||
|
||||
----
|
||||
|
||||
========= ===================
|
||||
Created : 2011-09-07
|
||||
Resolved: 2011-12-25T23:26:07
|
||||
========= ===================
|
@ -7,9 +7,10 @@ line with the general nature of delimited comment blocks, which do not place
|
||||
any restrictions on what comes before the start delimiter or after the end
|
||||
delimiter.
|
||||
|
||||
|
||||
----
|
||||
|
||||
========= ==========
|
||||
Created: 2011-09-07
|
||||
Resolved: YYYY-MM-DD
|
||||
========= ==========
|
||||
========= ===================
|
||||
Created : 2011-09-07
|
||||
Resolved: 2011-12-25T23:26:07
|
||||
========= ===================
|
||||
|
18
doc/issues/0010fs5.rst
Normal file
18
doc/issues/0010fs5.rst
Normal file
@ -0,0 +1,18 @@
|
||||
Modify `org` behavior to include simple anchors.
|
||||
================================================
|
||||
|
||||
Currently JLP supports at most one `org` directive per block which identifies the block.
|
||||
It would be useful to support multiple `org` directives within a block, particularly
|
||||
when there is a large block that may have many interesting internal targets. Maybe the
|
||||
`org` directive should be handled differently when it is used multiple times within a
|
||||
block. This would be discovered in the generator parse phase and we could change the
|
||||
LinkAnchor type at that time. During the parse phase we emit the new type of anchors
|
||||
as `<a id="link-name"/>` into the document. We would also change our search for block
|
||||
ids to inly look for the single-occurance type of `orgs`.
|
||||
|
||||
----
|
||||
|
||||
========= ===================
|
||||
Created : 2012-01-05T11:40:35
|
||||
Resolved: 2012-01-06T14:32:46
|
||||
========= ===================
|
@ -1,7 +1,7 @@
|
||||
#Wed, 04 Jan 2012 18:05:01 -0600
|
||||
#Fri, 06 Jan 2012 12:20:57 -0600
|
||||
name=jlp
|
||||
version=1.4
|
||||
build.number=11
|
||||
version=1.5
|
||||
build.number=6
|
||||
lib.local=true
|
||||
release.dir=release
|
||||
main.class=com.jdblabs.jlp.JLPMain
|
||||
|
@ -15,6 +15,12 @@ h1, h2, h3, h4, h5, h6 { margin: 0 0 15px 0; }
|
||||
|
||||
h1 { margin-top: 40px; }
|
||||
|
||||
hr {
|
||||
background-color: black;
|
||||
color: black;
|
||||
border: none;
|
||||
height: 1px; }
|
||||
|
||||
dt { font-weight: bold; }
|
||||
|
||||
ul {
|
||||
@ -36,17 +42,17 @@ td.docs, th.docs {
|
||||
vertical-align: top;
|
||||
text-align: left; }
|
||||
|
||||
.docs pre {
|
||||
background: #f8f8ff;
|
||||
border: 1px solid #dedede;
|
||||
margin: 15px 0 15px;
|
||||
padding-left: 15px; }
|
||||
|
||||
.docs tt, .docs code {
|
||||
.docs tt, .docs code, .docs pre {
|
||||
background: #f8f8ff;
|
||||
border: 1px solid #dedede;
|
||||
padding: 0 0.2em; }
|
||||
|
||||
.docs pre {
|
||||
margin: 15px 0 15px;
|
||||
padding-left: 15px; }
|
||||
|
||||
.docs pre > code { border: none; }
|
||||
|
||||
.docs table {
|
||||
border: thin solid #dedede;
|
||||
margin-left: 60px; }
|
||||
|
@ -18,7 +18,7 @@ import org.slf4j.LoggerFactory
|
||||
*/
|
||||
public class JLPMain {
|
||||
|
||||
public static final String VERSION = "1.4"
|
||||
public static final String VERSION = "1.5"
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(JLPMain.class)
|
||||
|
||||
|
@ -20,12 +20,12 @@ import com.jdblabs.jlp.ast.ASTNode
|
||||
*/
|
||||
public class LinkAnchor {
|
||||
|
||||
public enum LinkType { OrgLink, FileLink }
|
||||
public enum LinkType { InlineLink, BlockLink, FileLink }
|
||||
|
||||
/// The anchor id. This comes from the text after the directive.
|
||||
public String id
|
||||
|
||||
public LinkType type
|
||||
public LinkType type = LinkType.BlockLink
|
||||
public ASTNode source
|
||||
public String sourceDocId
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
package com.jdblabs.jlp
|
||||
|
||||
import com.jdblabs.jlp.ast.*
|
||||
import com.jdblabs.jlp.LinkAnchor.LinkType
|
||||
import com.jdblabs.jlp.ast.Directive.DirectiveType
|
||||
|
||||
import org.pegdown.Extensions
|
||||
@ -38,6 +39,56 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator {
|
||||
/** ### Parse phase implementation. ### */
|
||||
// ===================================
|
||||
|
||||
/** Override the parse phase for [`SourceFile`] nodes. We are interested in
|
||||
* detecting an `org` directive in the first DocBlock, or automatically
|
||||
* creating one if it is not defined. The first `org` directive (found or
|
||||
* created) will create a FileLink type LinkAnchor.
|
||||
*/
|
||||
|
||||
protected void parse(SourceFile sourceFile) {
|
||||
/// First we look for an `org` directive in the first block.
|
||||
def firstOrg = sourceFile.blocks[0].docBlock.directives.find {
|
||||
it.type == DirectiveType.Org }
|
||||
|
||||
/// And we create one if there are none.
|
||||
if (!firstOrg) {
|
||||
def docBlock = sourceFile.blocks[0].docBlock
|
||||
firstOrg = new Directive(processor.currentDocId, 'org', 0, docBlock)
|
||||
docBlock.directives << firstOrg }
|
||||
|
||||
/// Now parse the file as usual.
|
||||
super.parse(sourceFile)
|
||||
|
||||
/// And mark the first `org` as a FileLink
|
||||
processor.linkAnchors[firstOrg.value].type = LinkType.FileLink}
|
||||
|
||||
/** Override the parse phase for [`DocBlock`] nodes. We are interested in
|
||||
* detecting a block that has multilple `org` directives. When there are
|
||||
* multiple org directives in one block we change the LinkAnchor type from
|
||||
* block-level links to specific anchors in the text. This allows the
|
||||
* author to create a link to exact points within the document.
|
||||
*
|
||||
* [`DocBlock`]: jlp://jlp.jdb-labs.com/ast/DocBlock
|
||||
*/
|
||||
protected void parse(DocBlock docBlock) {
|
||||
/// First parse the block as usual.
|
||||
super.parse(docBlock)
|
||||
|
||||
/// Look for multiple `org` directives.
|
||||
def orgDirectives = docBlock.directives.findAll {it.type == DirectiveType.Org }
|
||||
|
||||
/// If we have multiple `org` directives in one [`DocBlock`] then we
|
||||
/// want to change the corresponding [`LinkAnchors`] to type
|
||||
/// `AnchorType`.
|
||||
///
|
||||
/// [`DocBlock`]: jlp://jlp.jdb-labs.com/ast/DocBlock
|
||||
/// [`LinkAnchors`]: jlp://jlp.jdb-labs.com/LinkAnchor
|
||||
if (orgDirectives.size() > 1) {
|
||||
orgDirectives.each { directive ->
|
||||
/// Get the LinkAnchor for this `org` link.
|
||||
def linkAnchor = processor.linkAnchors[directive.value]
|
||||
linkAnchor.type = LinkType.InlineLink }}}
|
||||
|
||||
/** Implement the parse phase for [`Directive`] nodes. We are interested
|
||||
* specifically in saving the link anchor information from *org*
|
||||
* directives.
|
||||
@ -139,10 +190,12 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator {
|
||||
protected String emit(Block block) {
|
||||
StringBuilder sb = new StringBuilder()
|
||||
|
||||
/// Look for an `@org` directive in the `Block` (already found in the
|
||||
/// parse phase)..
|
||||
Directive orgDir = block.docBlock.directives.find {
|
||||
it.type == DirectiveType.Org }
|
||||
/// Look for an `@org` directive in the `Block` that is marked as a
|
||||
/// block link (we may have many `orgs` in a block that are not block
|
||||
/// links).
|
||||
Directive orgDir = block.docBlock.directives.find { directive ->
|
||||
directive.type == DirectiveType.Org &&
|
||||
processor.linkAnchors[directive.value]?.type == LinkType.BlockLink }
|
||||
|
||||
/// Create the `tr` that will hold the `Block`. If we found an `@org`
|
||||
/// directive we will add the id here.
|
||||
@ -172,42 +225,15 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator {
|
||||
/// Later we will need a string builder to hold our result.
|
||||
StringBuilder sb
|
||||
|
||||
/** Add all the directives. We are also assigning priorities here that
|
||||
* we will use along with the line numbers to sort the elements. Our
|
||||
* goal is to preserve the order of doc blocks and doc-block-like
|
||||
* elements (examples, api documentation, etc.) while pushing orgs
|
||||
* and potentially other directives to the top. We used to re-order
|
||||
* authorship and copyright tags but stopped: in literate-style docs
|
||||
* the author should have control over their placement and in api-style
|
||||
* docs we are chopping the whole block up anyways (and this is not
|
||||
* that code). Given that the only item being re-ordered is *orgs*,
|
||||
* which do not print anyways, it may be better to cut this out and
|
||||
* just emit the blocks in their original order, or sort by line number
|
||||
* only. */
|
||||
emitQueue = docBlock.directives.collect { directive ->
|
||||
def queueItem = [lineNumber: directive.lineNumber, value: directive]
|
||||
switch(directive.type) {
|
||||
case DirectiveType.Org: queueItem.priority = 0; break
|
||||
default: queueItem.priority = 50; break }
|
||||
|
||||
return queueItem }
|
||||
|
||||
/// Add all the doc text blocks.
|
||||
emitQueue.addAll(docBlock.docTexts.collect { docText ->
|
||||
[lineNumber: docText.lineNumber, priority: 50, value: docText] })
|
||||
|
||||
|
||||
/// Sort the emit queue by priority, then line number.
|
||||
emitQueue.sort(
|
||||
{i1, i2 -> i1.priority != i2.priority ?
|
||||
i1.priority - i2.priority :
|
||||
i1.lineNumber - i2.lineNumber} as Comparator)
|
||||
/** We want to treat the whole block as one markdown chunk so we will
|
||||
* concatenate the directives and texts and send the whole block at
|
||||
* once to the markdown processor.
|
||||
*/
|
||||
emitQueue = docBlock.directives + docBlock.docTexts
|
||||
emitQueue.sort { it.lineNumber }
|
||||
|
||||
/** Finally, we want to treat the whole block as one markdown chunk so
|
||||
* we will concatenate the values in the emit queue and then send the
|
||||
* whole block at once to the markdown processor. */
|
||||
sb = new StringBuilder()
|
||||
emitQueue.each { queueItem -> sb.append(emit(queueItem.value)) }
|
||||
emitQueue.each { queueItem -> sb.append(emit(queueItem)) }
|
||||
|
||||
return processMarkdown(sb.toString())
|
||||
}
|
||||
@ -244,7 +270,6 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator {
|
||||
processMarkdown(directive.value) + "</div>\n"
|
||||
|
||||
/// `@author` directive is turned into a definition list.
|
||||
|
||||
case DirectiveType.Author:
|
||||
return "Author\n: ${directive.value}\n"
|
||||
|
||||
@ -258,9 +283,15 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator {
|
||||
// TODO:
|
||||
// case DirectiveType.Include:
|
||||
|
||||
/// An `@org` directive is ignored here. We already emitted the id
|
||||
/// when we started the block.
|
||||
case DirectiveType.Org: return "" } }
|
||||
/// An `@org` directive may be emitted if the [`LinkAnchor`] is an
|
||||
/// `InlineLink` type.
|
||||
///
|
||||
/// [`LinkAnchor`]: jlp://jlp.jdb-labs.com/LinkAnchor
|
||||
case DirectiveType.Org:
|
||||
def link = processor.linkAnchors[directive.value]
|
||||
if (link.type == LinkType.InlineLink) {
|
||||
return "<a id='${directive.value}'></a>\n" }
|
||||
else { return "" }}}
|
||||
|
||||
/** This is a helper method to process a block of text as Markdown. We need
|
||||
* to do some additional processing to deal with `jlp://` org links that
|
||||
|
@ -4,6 +4,7 @@
|
||||
*/
|
||||
package com.jdblabs.jlp
|
||||
|
||||
import com.jdblabs.jlp.LinkAnchor.LinkType
|
||||
import com.jdbernard.util.JarUtils
|
||||
import java.util.jar.JarInputStream
|
||||
import org.parboiled.BaseParser
|
||||
@ -213,11 +214,15 @@ public class Processor {
|
||||
|
||||
if (!linkAnchor) {
|
||||
// We do not have any reference to this id.
|
||||
/* TODO: log error */
|
||||
log.warn("Unable to resolve a jlp link: {}.", link)
|
||||
return "broken_link(${linkId})" }
|
||||
|
||||
/// If this is a `FileLink` then we do not need the actual
|
||||
/// linkId, just the file being linked to.
|
||||
if (linkAnchor.type == LinkType.FileLink) { linkId = "" }
|
||||
|
||||
/// This link points to a location in this document.
|
||||
else if (targetDoc.sourceDocId == linkAnchor.sourceDocId) {
|
||||
if (targetDoc.sourceDocId == linkAnchor.sourceDocId) {
|
||||
return "#${linkId}" }
|
||||
|
||||
/// The link should point to a different document.
|
||||
|
Loading…
Reference in New Issue
Block a user