aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Analysis/CommentsAPI.kt2
-rw-r--r--src/Formats/MarkdownFormatService.kt4
-rw-r--r--src/Formats/StructuredFormatService.kt24
-rw-r--r--src/Formats/TextFormatService.kt3
-rw-r--r--src/Kotlin/ContentBuilder.kt79
-rw-r--r--src/Kotlin/Diagnostics.kt (renamed from src/Model/Diagnostics.kt)4
-rw-r--r--src/Kotlin/DocumentationBuildingVisitor.kt (renamed from src/Model/DocumentationBuildingVisitor.kt)1
-rw-r--r--src/Kotlin/DocumentationContext.kt47
-rw-r--r--src/Kotlin/DocumentationNodeBuilder.kt (renamed from src/Model/DocumentationNodeBuilder.kt)94
-rw-r--r--src/Markdown/MarkdownProcessor.kt62
-rw-r--r--src/Markdown/_MarkdownLexer.flex40
-rw-r--r--src/Markdown/markdown.bnf42
-rw-r--r--src/Model/Content.kt88
-rw-r--r--src/Model/DocumentationContent.kt150
-rw-r--r--src/Model/DocumentationModule.kt23
-rw-r--r--src/Model/DocumentationNode.kt7
16 files changed, 350 insertions, 320 deletions
diff --git a/src/Analysis/CommentsAPI.kt b/src/Analysis/CommentsAPI.kt
index 5df4bd38..a17b6aa4 100644
--- a/src/Analysis/CommentsAPI.kt
+++ b/src/Analysis/CommentsAPI.kt
@@ -31,5 +31,5 @@ fun KDoc?.extractText(): String {
comment.substring(0, comment.length - 2)
else
comment).trim()
- }.filter { it.any() }.join("\n")
+ }.join("\n")
} \ No newline at end of file
diff --git a/src/Formats/MarkdownFormatService.kt b/src/Formats/MarkdownFormatService.kt
index d7530a25..3b87835f 100644
--- a/src/Formats/MarkdownFormatService.kt
+++ b/src/Formats/MarkdownFormatService.kt
@@ -16,10 +16,6 @@ public open class MarkdownFormatService(locationService: LocationService,
return text.htmlEscape()
}
- override public fun formatText(text: RichString): String {
- return text.toString().htmlEscape()
- }
-
override public fun formatCode(code: String): String {
return "`$code`"
}
diff --git a/src/Formats/StructuredFormatService.kt b/src/Formats/StructuredFormatService.kt
index 0c58f553..b1e614f6 100644
--- a/src/Formats/StructuredFormatService.kt
+++ b/src/Formats/StructuredFormatService.kt
@@ -28,19 +28,17 @@ public abstract class StructuredFormatService(val locationService: LocationServi
public abstract fun formatCode(code: String): String
public abstract fun formatBreadcrumbs(items: Iterable<FormatLink>): String
- open fun formatText(text: RichString): String {
+ open fun formatText(nodes: Iterable<ContentNode>): String {
+ return nodes.map { formatText(it) }.join("")
+ }
+
+ open fun formatText(text: ContentNode): String {
return StringBuilder {
- for (slice in text.slices) {
- val style = slice.style
- when (style) {
- is NormalStyle -> append(slice.text)
- is BoldStyle -> append(formatBold(slice.text))
- is CodeStyle -> append(formatCode(slice.text))
- is LinkStyle -> {
- val node = resolutionService.resolve(style.link)
- val location = locationService.location(node)
- append(formatLink(slice.text, location))
- }
+ for (node in text.children) {
+ when (node) {
+ is ContentText -> append(node.text)
+ is ContentEmphasis -> append(formatBold(formatText(node.children)))
+ else -> append(formatText(node.children))
}
}
}.toString()
@@ -67,7 +65,7 @@ public abstract class StructuredFormatService(val locationService: LocationServi
if (label.startsWith("$"))
continue
appendLine(to, formatBold(formatText(label)))
- appendLine(to, formatText(section.text))
+ appendLine(to, formatText(section))
appendLine(to)
}
}
diff --git a/src/Formats/TextFormatService.kt b/src/Formats/TextFormatService.kt
index 77a0bb65..8fea5a6a 100644
--- a/src/Formats/TextFormatService.kt
+++ b/src/Formats/TextFormatService.kt
@@ -9,12 +9,9 @@ public class TextFormatService(val signatureGenerator: LanguageService) : Format
appendln(signatureGenerator.render(node))
appendln()
appendln(node.doc.summary)
- for (n in 0..node.doc.summary.length())
- append("=")
for ((label,section) in node.doc.sections) {
appendln(label)
- appendln(section.text)
}
}
}
diff --git a/src/Kotlin/ContentBuilder.kt b/src/Kotlin/ContentBuilder.kt
new file mode 100644
index 00000000..78bd7eaf
--- /dev/null
+++ b/src/Kotlin/ContentBuilder.kt
@@ -0,0 +1,79 @@
+package org.jetbrains.dokka
+
+import org.jetbrains.markdown.MarkdownElementTypes
+import java.util.ArrayDeque
+
+public fun MarkdownTree.toContent(): Content {
+ val nodeStack = ArrayDeque<ContentNode>()
+ nodeStack.push(Content())
+
+ visit {(node, text, processChildren) ->
+ val parent = nodeStack.peek()!!
+ val nodeType = node.getTokenType()
+ val nodeText = getNodeText(node)
+ when (nodeType) {
+ MarkdownElementTypes.BULLET_LIST -> {
+ nodeStack.push(ContentList())
+ processChildren()
+ parent.children.add(nodeStack.pop())
+ }
+ MarkdownElementTypes.ORDERED_LIST -> {
+ nodeStack.push(ContentList()) // TODO: add list kind
+ processChildren()
+ parent.children.add(nodeStack.pop())
+ }
+ MarkdownElementTypes.HORIZONTAL_RULE -> {
+ }
+ MarkdownElementTypes.LIST_BLOCK -> {
+ nodeStack.push(ContentBlock())
+ processChildren()
+ parent.children.add(nodeStack.pop())
+ }
+ MarkdownElementTypes.EMPH -> {
+ nodeStack.push(ContentEmphasis())
+ processChildren()
+ parent.children.add(nodeStack.pop())
+ }
+ MarkdownElementTypes.STRONG -> {
+ nodeStack.push(ContentStrong())
+ processChildren()
+ parent.children.add(nodeStack.pop())
+ }
+ MarkdownElementTypes.ANONYMOUS_SECTION -> {
+ nodeStack.push(ContentSection(""))
+ processChildren()
+ parent.children.add(nodeStack.pop())
+ }
+ MarkdownElementTypes.NAMED_SECTION -> {
+ val label = findChildByType(node, MarkdownElementTypes.SECTION_NAME)?.let { getNodeText(it) } ?: ""
+ nodeStack.push(ContentSection(label))
+ processChildren()
+ parent.children.add(nodeStack.pop())
+ }
+ MarkdownElementTypes.PLAIN_TEXT -> {
+ nodeStack.push(ContentText(nodeText))
+ processChildren()
+ parent.children.add(nodeStack.pop())
+ }
+ MarkdownElementTypes.END_LINE -> {
+ nodeStack.push(ContentText(nodeText))
+ processChildren()
+ parent.children.add(nodeStack.pop())
+ }
+ MarkdownElementTypes.BLANK_LINE -> {
+ processChildren()
+ }
+ MarkdownElementTypes.PARA -> {
+ nodeStack.push(ContentBlock())
+ processChildren()
+ parent.children.add(nodeStack.pop())
+ }
+ else -> {
+ processChildren()
+ }
+ }
+ }
+ return nodeStack.pop() as Content
+}
+
+
diff --git a/src/Model/Diagnostics.kt b/src/Kotlin/Diagnostics.kt
index 1077da7c..5548bc01 100644
--- a/src/Model/Diagnostics.kt
+++ b/src/Kotlin/Diagnostics.kt
@@ -4,11 +4,11 @@ import org.jetbrains.jet.lang.descriptors.*
import org.jetbrains.jet.lang.resolve.name.*
import org.jetbrains.jet.lang.resolve.BindingContext
-fun BindingContext.checkResolveChildren(node: DocumentationNode) {
+fun DocumentationContext.checkResolveChildren(node: DocumentationNode) {
if (node.kind != DocumentationNode.Kind.Module && node.kind != DocumentationNode.Kind.Package) {
// TODO: we don't resolve packages and modules for now
- val parentScope = getResolutionScope(node.descriptor)
+ val parentScope = getResolutionScope(node)
for (item in node.details + node.members) {
val symbolName = item.name
val symbol: DeclarationDescriptor? = when (item.kind) {
diff --git a/src/Model/DocumentationBuildingVisitor.kt b/src/Kotlin/DocumentationBuildingVisitor.kt
index 6118b0f5..5654903b 100644
--- a/src/Model/DocumentationBuildingVisitor.kt
+++ b/src/Kotlin/DocumentationBuildingVisitor.kt
@@ -5,6 +5,7 @@ import org.jetbrains.jet.lang.resolve.name.*
import org.jetbrains.jet.lang.resolve.*
public data class DocumentationOptions(val includeNonPublic : Boolean = false)
+
class DocumentationBuildingVisitor(val context: BindingContext,
val options: DocumentationOptions,
private val worker: DeclarationDescriptorVisitor<DocumentationNode, DocumentationNode>)
diff --git a/src/Kotlin/DocumentationContext.kt b/src/Kotlin/DocumentationContext.kt
new file mode 100644
index 00000000..1491aa2d
--- /dev/null
+++ b/src/Kotlin/DocumentationContext.kt
@@ -0,0 +1,47 @@
+package org.jetbrains.dokka
+
+import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
+import org.jetbrains.jet.lang.resolve.BindingContext
+import org.jetbrains.jet.lang.resolve.scopes.JetScope
+import org.jetbrains.jet.lang.descriptors.ModuleDescriptor
+import org.jetbrains.jet.lang.resolve.name.FqName
+
+public class DocumentationContext(val bindingContext: BindingContext) {
+ val descriptorToNode = hashMapOf<DeclarationDescriptor, DocumentationNode>()
+ val nodeToDescriptor = hashMapOf<DocumentationNode, DeclarationDescriptor>()
+
+ fun register(descriptor: DeclarationDescriptor, node: DocumentationNode) {
+ descriptorToNode.put(descriptor, node)
+ nodeToDescriptor.put(node, descriptor)
+ }
+
+ fun getResolutionScope(node: DocumentationNode): JetScope {
+ val descriptor = nodeToDescriptor[node] ?: throw IllegalArgumentException("Node is not known to this context")
+ return bindingContext.getResolutionScope(descriptor)
+ }
+
+ fun parseDocumentation(descriptor: DeclarationDescriptor): Content {
+ val docText = bindingContext.getDocumentationElements(descriptor).map { it.extractText() }.join("\n")
+ val tree = MarkdownProcessor.parse(docText)
+ println(tree.toTestString())
+ val content = tree.toContent()
+ return content
+ }
+}
+
+fun BindingContext.createDocumentationModule(name: String,
+ module: ModuleDescriptor,
+ packages: Set<FqName>,
+ options: DocumentationOptions = DocumentationOptions()): DocumentationModule {
+ val documentationModule = DocumentationModule(name)
+ val context = DocumentationContext(this)
+ val visitor = DocumentationNodeBuilder(context)
+ for (packageName in packages) {
+ val pkg = module.getPackage(packageName)
+ pkg!!.accept(DocumentationBuildingVisitor(this, options, visitor), documentationModule)
+ }
+
+ // TODO: Uncomment for resolve verification
+ // checkResolveChildren(documentationModule)
+ return documentationModule
+}
diff --git a/src/Model/DocumentationNodeBuilder.kt b/src/Kotlin/DocumentationNodeBuilder.kt
index f724c444..535f037f 100644
--- a/src/Model/DocumentationNodeBuilder.kt
+++ b/src/Kotlin/DocumentationNodeBuilder.kt
@@ -1,12 +1,23 @@
package org.jetbrains.dokka
-import org.jetbrains.jet.lang.resolve.*
-import org.jetbrains.jet.lang.descriptors.*
-import org.jetbrains.jet.lang.descriptors.impl.*
-import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
+import org.jetbrains.jet.lang.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies
+import org.jetbrains.jet.lang.descriptors.MemberDescriptor
+import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
import org.jetbrains.jet.lang.types.JetType
+import org.jetbrains.jet.lang.descriptors.Named
+import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor
+import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor
+import org.jetbrains.jet.lang.descriptors.ClassDescriptor
+import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
+import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
+import org.jetbrains.jet.lang.descriptors.PropertyDescriptor
+import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor
+import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor
+import org.jetbrains.jet.lang.descriptors.PackageFragmentDescriptor
+import org.jetbrains.jet.lang.descriptors.ClassKind
+import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
-class DocumentationNodeBuilder(val context: BindingContext) : DeclarationDescriptorVisitorEmptyBodies<DocumentationNode, DocumentationNode>() {
+class DocumentationNodeBuilder(val context: DocumentationContext) : DeclarationDescriptorVisitorEmptyBodies<DocumentationNode, DocumentationNode>() {
fun reference(from: DocumentationNode, to: DocumentationNode, kind: DocumentationReference.Kind) {
from.addReferenceTo(to, kind)
@@ -18,13 +29,13 @@ class DocumentationNodeBuilder(val context: BindingContext) : DeclarationDescrip
fun addModality(descriptor: MemberDescriptor, data: DocumentationNode) {
val modifier = descriptor.getModality().name().toLowerCase()
- val node = DocumentationNode(descriptor, modifier, DocumentationContent.Empty, DocumentationNode.Kind.Modifier)
+ val node = DocumentationNode(modifier, Content.Empty, DocumentationNode.Kind.Modifier)
reference(data, node, DocumentationReference.Kind.Detail)
}
fun addVisibility(descriptor: MemberDescriptor, data: DocumentationNode) {
val modifier = descriptor.getVisibility().toString()
- val node = DocumentationNode(descriptor, modifier, DocumentationContent.Empty, DocumentationNode.Kind.Modifier)
+ val node = DocumentationNode(modifier, Content.Empty, DocumentationNode.Kind.Modifier)
reference(data, node, DocumentationReference.Kind.Detail)
}
@@ -37,7 +48,7 @@ class DocumentationNodeBuilder(val context: BindingContext) : DeclarationDescrip
is Named -> classifierDescriptor.getName().asString()
else -> "<anonymous>"
}
- val node = DocumentationNode(descriptor, name, DocumentationContent.Empty, DocumentationNode.Kind.Type)
+ val node = DocumentationNode(name, Content.Empty, DocumentationNode.Kind.Type)
reference(data, node, DocumentationReference.Kind.Detail)
for (param in t.getArguments())
@@ -45,14 +56,17 @@ class DocumentationNodeBuilder(val context: BindingContext) : DeclarationDescrip
}
override fun visitDeclarationDescriptor(descriptor: DeclarationDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val doc = context.getDocumentation(descriptor!!)
- val node = DocumentationNode(descriptor, descriptor.getName().asString(), doc, DocumentationNode.Kind.Unknown)
+ descriptor!!
+ val doc = context.parseDocumentation(descriptor)
+ val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Unknown)
reference(data!!, node, DocumentationReference.Kind.Link)
+ context.register(descriptor, node)
return node
}
override fun visitReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val node = DocumentationNode(descriptor!!, descriptor.getName().asString(), DocumentationContent.Empty, DocumentationNode.Kind.Receiver)
+ descriptor!!
+ val node = DocumentationNode(descriptor.getName().asString(), Content.Empty, DocumentationNode.Kind.Receiver)
reference(data!!, node, DocumentationReference.Kind.Detail)
addType(descriptor, descriptor.getType(), node)
@@ -61,8 +75,9 @@ class DocumentationNodeBuilder(val context: BindingContext) : DeclarationDescrip
}
override fun visitValueParameterDescriptor(descriptor: ValueParameterDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val doc = context.getDocumentation(descriptor!!)
- val node = DocumentationNode(descriptor, descriptor.getName().asString(), doc, DocumentationNode.Kind.Parameter)
+ descriptor!!
+ val doc = context.parseDocumentation(descriptor)
+ val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Parameter)
reference(data!!, node, DocumentationReference.Kind.Detail)
addType(descriptor, descriptor.getType(), node)
@@ -71,83 +86,92 @@ class DocumentationNodeBuilder(val context: BindingContext) : DeclarationDescrip
}
override fun visitClassDescriptor(descriptor: ClassDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val doc = context.getDocumentation(descriptor!!)
- val node = DocumentationNode(descriptor, descriptor.getName().asString(), doc, when (descriptor.getKind()) {
- ClassKind.OBJECT -> DocumentationNode.Kind.Object
- ClassKind.CLASS_OBJECT -> DocumentationNode.Kind.Object
- ClassKind.TRAIT -> DocumentationNode.Kind.Interface
- ClassKind.ENUM_CLASS -> DocumentationNode.Kind.Enum
- ClassKind.ENUM_ENTRY -> DocumentationNode.Kind.EnumItem
+ descriptor!!
+ val doc = context.parseDocumentation(descriptor)
+ val node = DocumentationNode(descriptor.getName().asString(), doc, when (descriptor.getKind()) {
+ ClassKind.OBJECT -> org.jetbrains.dokka.DocumentationNode.Kind.Object
+ ClassKind.CLASS_OBJECT -> org.jetbrains.dokka.DocumentationNode.Kind.Object
+ ClassKind.TRAIT -> org.jetbrains.dokka.DocumentationNode.Kind.Interface
+ ClassKind.ENUM_CLASS -> org.jetbrains.dokka.DocumentationNode.Kind.Enum
+ ClassKind.ENUM_ENTRY -> org.jetbrains.dokka.DocumentationNode.Kind.EnumItem
else -> DocumentationNode.Kind.Class
})
reference(data!!, node, DocumentationReference.Kind.Member)
addModality(descriptor, node)
addVisibility(descriptor, node)
+ context.register(descriptor, node)
return node
}
override fun visitFunctionDescriptor(descriptor: FunctionDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val doc = context.getDocumentation(descriptor!!)
- val node = DocumentationNode(descriptor, descriptor.getName().asString(), doc, DocumentationNode.Kind.Function)
+ descriptor!!
+ val doc = context.parseDocumentation(descriptor)
+ val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Function)
reference(data!!, node, DocumentationReference.Kind.Member)
addType(descriptor, descriptor.getReturnType(), node)
addModality(descriptor, node)
addVisibility(descriptor, node)
-
+ context.register(descriptor, node)
return node
}
override fun visitTypeParameterDescriptor(descriptor: TypeParameterDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val doc = context.getDocumentation(descriptor!!)
- val node = DocumentationNode(descriptor, descriptor.getName().asString(), doc, DocumentationNode.Kind.TypeParameter)
+ descriptor!!
+ val doc = context.parseDocumentation(descriptor)
+ val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.TypeParameter)
reference(data!!, node, DocumentationReference.Kind.Detail)
val builtIns = KotlinBuiltIns.getInstance()
for (constraint in descriptor.getUpperBounds()) {
if (constraint == builtIns.getDefaultBound())
continue
- val constraintNode = DocumentationNode(descriptor, constraint.toString(), DocumentationContent.Empty, DocumentationNode.Kind.UpperBound)
+ val constraintNode = DocumentationNode(constraint.toString(), Content.Empty, DocumentationNode.Kind.UpperBound)
reference(node, constraintNode, DocumentationReference.Kind.Detail)
}
for (constraint in descriptor.getLowerBounds()) {
if (builtIns.isNothing(constraint))
continue
- val constraintNode = DocumentationNode(descriptor, constraint.toString(), DocumentationContent.Empty, DocumentationNode.Kind.LowerBound)
+ val constraintNode = DocumentationNode(constraint.toString(), Content.Empty, DocumentationNode.Kind.LowerBound)
reference(node, constraintNode, DocumentationReference.Kind.Detail)
}
return node
}
override fun visitPropertyDescriptor(descriptor: PropertyDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val doc = context.getDocumentation(descriptor!!)
- val node = DocumentationNode(descriptor, descriptor.getName().asString(), doc, DocumentationNode.Kind.Property)
+ descriptor!!
+ val doc = context.parseDocumentation(descriptor)
+ val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Property)
reference(data!!, node, DocumentationReference.Kind.Member)
addType(descriptor, descriptor.getType(), node)
addModality(descriptor, node)
addVisibility(descriptor, node)
+ context.register(descriptor, node)
return node
}
override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val doc = context.getDocumentation(descriptor!!)
- val node = DocumentationNode(descriptor, descriptor.getName().asString(), doc, DocumentationNode.Kind.Constructor)
+ descriptor!!
+ val doc = context.parseDocumentation(descriptor)
+ val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Constructor)
reference(data!!, node, DocumentationReference.Kind.Member)
addVisibility(descriptor, node)
-
+ context.register(descriptor, node)
return node
}
override fun visitPackageViewDescriptor(descriptor: PackageViewDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val node = DocumentationNode(descriptor!!, descriptor.getFqName().asString(), DocumentationContent.Empty, DocumentationNode.Kind.Package)
+ descriptor!!
+ val node = DocumentationNode(descriptor.getFqName().asString(), Content.Empty, DocumentationNode.Kind.Package)
reference(data!!, node, DocumentationReference.Kind.Member)
return node
}
override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor?, data: DocumentationNode?): DocumentationNode? {
- val node = DocumentationNode(descriptor!!, descriptor.fqName.asString(), DocumentationContent.Empty, DocumentationNode.Kind.Package)
+ descriptor!!
+ val node = DocumentationNode(descriptor.fqName.asString(), Content.Empty, DocumentationNode.Kind.Package)
reference(data!!, node, DocumentationReference.Kind.Member)
return node
}
-}
+} \ No newline at end of file
diff --git a/src/Markdown/MarkdownProcessor.kt b/src/Markdown/MarkdownProcessor.kt
index fe6e8436..19d5a8fb 100644
--- a/src/Markdown/MarkdownProcessor.kt
+++ b/src/Markdown/MarkdownProcessor.kt
@@ -9,12 +9,11 @@ import com.intellij.lang.LighterASTNode
import com.intellij.util.diff.FlyweightCapableTreeStructure
import com.intellij.openapi.util.Ref
import org.jetbrains.markdown.lexer.MarkdownLexer
+import com.intellij.psi.tree.IElementType
-public class MarkdownProcessor {
- class object {
- val EXPR_LANGUAGE = object : Language("MARKDOWN") {}
- val DOCUMENT = IFileElementType("DOCUMENT", EXPR_LANGUAGE);
- }
+public object MarkdownProcessor {
+ val EXPR_LANGUAGE = object : Language("MARKDOWN") {}
+ val DOCUMENT = IFileElementType("DOCUMENT", EXPR_LANGUAGE);
public fun parse(markdown: String): MarkdownTree {
val parser = MarkdownParser()
@@ -30,6 +29,28 @@ public class MarkdownTree(private val text: String, private val structure: Flywe
visit(structure.getRoot(), action)
}
+ fun findChildByType(node: LighterASTNode, findType: IElementType) : LighterASTNode? {
+ val ref = Ref.create<Array<LighterASTNode>?>()
+ val count = structure.getChildren(node, ref)
+ val children = ref.get()
+ if (children != null) {
+ for (index in 0..count - 1) {
+ val child = children[index]
+ val nodeType = child.getTokenType()
+ if (nodeType == findType)
+ return child
+ val nestedChild = findChildByType(child, findType)
+ if (nestedChild != null)
+ return nestedChild
+ }
+ }
+ return null
+ }
+
+ fun getNodeText(node: LighterASTNode) : String {
+ return text.substring(node.getStartOffset(), node.getEndOffset())
+ }
+
fun visit(node: LighterASTNode, action: (LighterASTNode, String, visitChildren: () -> Unit) -> Unit) {
action(node, text) {
val ref = Ref.create<Array<LighterASTNode>?>()
@@ -46,7 +67,7 @@ public class MarkdownTree(private val text: String, private val structure: Flywe
}
-public fun MarkdownTree.dump(): String {
+public fun MarkdownTree.toTestString(): String {
val sb = StringBuilder()
var level = 0
visit {(node, text, visitChildren) ->
@@ -64,29 +85,25 @@ public fun MarkdownTree.dump(): String {
public fun MarkdownTree.toHtml(): String {
val sb = StringBuilder()
- var level = 0
visit {(node, text, processChildren) ->
val nodeType = node.getTokenType()
val nodeText = text.substring(node.getStartOffset(), node.getEndOffset())
- val indent = " ".repeat(level * 2)
when (nodeType) {
MarkdownElementTypes.BULLET_LIST -> {
- sb.appendln("$indent<ul>")
- level++
+ sb.appendln("<ul>")
processChildren()
- level--
- sb.appendln("$indent</ul>")
+ sb.appendln("</ul>")
}
MarkdownElementTypes.HORIZONTAL_RULE -> {
- sb.appendln("$indent<hr/>")
+ sb.appendln("<hr/>")
}
MarkdownElementTypes.ORDERED_LIST -> {
- sb.appendln("$indent<ol>")
+ sb.appendln("<ol>")
processChildren()
- sb.appendln("$indent</ol>")
+ sb.appendln("</ol>")
}
MarkdownElementTypes.LIST_BLOCK -> {
- sb.append("$indent<li>")
+ sb.append("<li>")
processChildren()
sb.appendln("</li>")
}
@@ -110,14 +127,9 @@ public fun MarkdownTree.toHtml(): String {
sb.appendln()
}
MarkdownElementTypes.PARA -> {
- sb.appendln("$indent<p>")
- processChildren()
- sb.appendln("$indent</p>")
- }
- MarkdownElementTypes.VERBATIM -> {
- sb.appendln("$indent<pre><code>")
+ sb.append("<p>")
processChildren()
- sb.appendln("$indent</code></pre>")
+ sb.appendln("</p>")
}
else -> {
processChildren()
@@ -129,8 +141,8 @@ public fun MarkdownTree.toHtml(): String {
fun markdownToHtml(markdown: String): String {
- val markdownTree = MarkdownProcessor().parse(markdown)
- val ast = markdownTree.dump()
+ val markdownTree = MarkdownProcessor.parse(markdown)
+ val ast = markdownTree.toTestString()
return markdownTree.toHtml()
}
diff --git a/src/Markdown/_MarkdownLexer.flex b/src/Markdown/_MarkdownLexer.flex
deleted file mode 100644
index 0a15e41a..00000000
--- a/src/Markdown/_MarkdownLexer.flex
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.jetbrains.markdown.lexer;
-
-import com.intellij.lexer.*;
-import com.intellij.psi.tree.IElementType;
-import static org.jetbrains.markdown.MarkdownElementTypes.*;
-
-%%
-
-%{
- public _MarkdownLexer() {
- this((java.io.Reader)null);
- }
-%}
-
-%public
-%class _MarkdownLexer
-%implements FlexLexer
-%function advance
-%type IElementType
-%unicode
-
-Newline="\r"|"\n"|"\r\n"
-Spacechar=[\ \t\f]
-Number=[0-9]+(\.[0-9]*)?
-String=[^~\*_`&\[\]()<!#\\ \t\n\r]+
-AnyChar=.
-Line=!'\r' !'\n' .* {Newline}
-
-%%
-<YYINITIAL> {
- {Spacechar} { return SPACECHAR; }
- {Newline} { return NEWLINE; }
- "\\357\\273\\277" { return BOM; }
-
- {Number} { return NUMBER; }
- {String} { return STRING; }
- {AnyChar} { return ANYCHAR; }
-
- [^] { return com.intellij.psi.TokenType.BAD_CHARACTER; }
-}
diff --git a/src/Markdown/markdown.bnf b/src/Markdown/markdown.bnf
index ca254295..79e9e0b4 100644
--- a/src/Markdown/markdown.bnf
+++ b/src/Markdown/markdown.bnf
@@ -21,35 +21,35 @@
}
-Document ::= BOM? ( Block )*
+Document ::= BOM? Whitespace* AnonymousSection? (Whitespace* NamedSection)*
-private OptionalSpace ::= Spacechar*
-private RequiredSpace ::= Spacechar+
-private NonindentSpace ::= (" " | " " | " ")?
+AnonymousSection ::= SectionBody
+NamedSection ::= SectionHeader SectionBody
+private SectionHeader ::= '$' SectionName OptionalSpace ':' OptionalSpace
+SectionName ::= SectionNameStart | '{' OptionalSpace SectionNameStart (Spacechar+ String)* OptionalSpace '}'
+private SectionNameStart ::= '$'? String
+SectionBody::= Block*
BlankLine ::= OptionalSpace Newline
Whitespace ::= Spacechar | Newline
+private OptionalSpace ::= Spacechar*
+private NonindentSpace ::= (" " | " " | " ")?
+
EndLine ::= TerminalEndline | NormalEndline
-private NormalEndline ::= OptionalSpace Newline !BlankLine
-private TerminalEndline ::= (OptionalSpace Newline <<eof>>) | (OptionalSpace <<eof>>)
+private NormalEndline ::= Newline !BlankLine
+private TerminalEndline ::= OptionalSpace <<eof>>
private Indent ::= "\t" | " "
-NonblankIndentedLine ::= !BlankLine IndentedLine
-IndentedLine ::= Indent PlainText
// ---- BLOCKS ----
-private Block ::= BlankLine* (
- Para
- | Verbatim
- | OrderedList
- | BulletList
- | Inlines
- )
-
-Para ::= NonindentSpace Inlines (BlankLine | TerminalEndline)
+Block ::= BlankLine* (
+ OrderedList
+ | BulletList
+ | HorizontalRule
+ | Para
+ )
-Verbatim ::= VerbatimItem+
-VerbatimItem ::= BlankLine* NonblankIndentedLine
+Para ::= Inlines (BlankLine | TerminalEndline)?
HorizontalRule ::= NonindentSpace
( '*' OptionalSpace '*' OptionalSpace '*' (OptionalSpace '*')*
@@ -74,8 +74,8 @@ ListContinuationBlock ::= BlankLine* (Indent ListBlock)+
// ---- INLINES ----
private Inlines ::= (!EndLine Inline | EndLine &Inline )+ EndLine?
-private Inline ::= Strong | Emph | Link | PlainText
-PlainText ::= (String | Number | Spacechar)+
+Inline ::= Strong | Emph | Link | PlainText
+PlainText ::= (String | Number | Spacechar+)+
Emph ::= EmphStar | EmphUnderscore
private EmphStar ::= '*' !Whitespace (!'*' Inline)+ '*'
diff --git a/src/Model/Content.kt b/src/Model/Content.kt
new file mode 100644
index 00000000..eb092cb2
--- /dev/null
+++ b/src/Model/Content.kt
@@ -0,0 +1,88 @@
+package org.jetbrains.dokka
+
+import kotlin.properties.Delegates
+
+public abstract class ContentNode {
+ val children = arrayListOf<ContentNode>()
+
+ class object {
+ val empty = ContentEmpty
+ }
+
+ fun isEmpty() = children.isEmpty()
+}
+
+public object ContentEmpty : ContentNode( )
+
+public class ContentText(val text : String) : ContentNode( )
+public class ContentBlock() : ContentNode( )
+public class ContentEmphasis() : ContentNode()
+public class ContentStrong() : ContentNode()
+public class ContentList() : ContentNode()
+public class ContentSection(public val label: String) : ContentNode()
+
+public class Content() : ContentNode() {
+ public val sections: Map<String, ContentSection> by Delegates.lazy {
+ val map = hashMapOf<String, ContentSection>()
+ for (child in children) {
+ if (child is ContentSection)
+ map.put(child.label, child)
+ }
+
+ if ("\$summary" !in map && "\$description" !in map) {
+ // no explicit summary and description, convert anonymous section
+ val anonymous = map[""]
+ if (anonymous != null) {
+ map.remove("")
+ val summary = ContentSection("\$summary")
+ val description = ContentSection("\$description")
+
+ val summaryNodes = anonymous.children.take(1)
+ val descriptionNodes = anonymous.children.drop(1)
+
+ if (summaryNodes.any()) {
+ summary.children.addAll(summaryNodes)
+ map.put("\$summary", summary)
+ }
+
+ if (descriptionNodes.any()) {
+ description.children.addAll(descriptionNodes)
+ map.put("\$description", description)
+ }
+ }
+ }
+ map
+ }
+
+ public val summary: ContentNode get() = sections["\$summary"] ?: ContentNode.empty
+ public val description: ContentNode get() = sections["\$description"] ?: ContentNode.empty
+
+ override fun equals(other: Any?): Boolean {
+ if (other !is Content)
+ return false
+ if (sections.size != other.sections.size)
+ return false
+ for (keys in sections.keySet())
+ if (sections[keys] != other.sections[keys])
+ return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ return sections.map { it.hashCode() }.sum()
+ }
+
+ override fun toString(): String {
+ if (sections.isEmpty())
+ return "<empty>"
+ return sections.values().joinToString()
+ }
+
+ val isEmpty: Boolean
+ get() = sections.none()
+
+ class object {
+ val Empty = Content()
+ }
+}
diff --git a/src/Model/DocumentationContent.kt b/src/Model/DocumentationContent.kt
deleted file mode 100644
index 77e8c764..00000000
--- a/src/Model/DocumentationContent.kt
+++ /dev/null
@@ -1,150 +0,0 @@
-package org.jetbrains.dokka
-
-import org.jetbrains.jet.lang.descriptors.*
-import org.jetbrains.jet.lang.resolve.BindingContext
-
-public class DocumentationContentSection(public val label: String, public val text: RichString) {
- override fun toString(): String {
- return "$label = $text"
- }
-}
-
-public class DocumentationContent(public val sections: Map<String, DocumentationContentSection>) {
-
- public val summary: RichString get() = sections["\$summary"]?.text ?: RichString.empty
- public val description: RichString get() = sections["\$description"]?.text ?: RichString.empty
-
- override fun equals(other: Any?): Boolean {
- if (other !is DocumentationContent)
- return false
- if (sections.size != other.sections.size)
- return false
- for (keys in sections.keySet())
- if (sections[keys] != other.sections[keys])
- return false
-
- return true
- }
-
- override fun hashCode(): Int {
- return sections.map { it.hashCode() }.sum()
- }
-
- override fun toString(): String {
- if (sections.isEmpty())
- return "<empty>"
- return sections.values().joinToString()
- }
-
- val isEmpty: Boolean
- get() = description.isEmpty() && sections.none()
-
- class object {
- val Empty = DocumentationContent(mapOf())
- }
-}
-
-
-fun BindingContext.getDocumentation(descriptor: DeclarationDescriptor): DocumentationContent {
- val docText = getDocumentationElements(descriptor).map { it.extractText() }.join("\n")
- val sections = docText.parseSections()
- sections.createSummaryAndDescription()
- return DocumentationContent(sections)
-}
-
-fun MutableMap<String, DocumentationContentSection>.createSummaryAndDescription() {
-
- val summary = get("\$summary")
- val description = get("\$description")
- if (summary != null && description == null) {
- return
- }
-
- if (summary == null && description != null) {
- return
- }
-
- val unnamed = get("")
- if (unnamed == null) {
- return
- }
-
- val split = unnamed.text.splitBy("\n")
- remove("")
- if (!split.first.isEmpty())
- put("\$summary", DocumentationContentSection("\$summary", split.first))
- if (!split.second.isEmpty())
- put("\$description", DocumentationContentSection("\$description", split.second))
-}
-
-fun String.parseLabel(index: Int): Pair<String, Int> {
- val c = get(index)
- when {
- Character.isJavaIdentifierStart(c) -> {
- for (end in index + 1..length - 1) {
- if (!Character.isJavaIdentifierPart(get(end))) {
- return substring(index, end) to end
- }
- }
- return substring(index, length) to length
- }
- c == '$' -> {
- for (end in index + 1..length - 1) {
- if (Character.isWhitespace(get(end))) {
- return substring(index, end) to end
- }
- }
- return substring(index, length) to length
- }
- c == '{' -> {
- val end = indexOf('}', index + 1)
- return substring(index + 1, end) to end + 1
- }
- }
- return "" to -1
-}
-
-fun String.parseSections(): MutableMap<String, DocumentationContentSection> {
- val sections = hashMapOf<String, DocumentationContentSection>()
- var currentLabel = ""
- var currentSectionStart = 0
- var currentIndex = 0
-
- while (currentIndex < length) {
- if (get(currentIndex) == '$') {
- val (label, index) = parseLabel(currentIndex + 1)
- if (index != -1 && index < length() && get(index) == ':') {
- // section starts, add previous section
- val currentContent = substring(currentSectionStart, currentIndex).trim()
- val section = DocumentationContentSection(currentLabel, currentContent.toRichString())
- sections.put(section.label, section)
-
- currentLabel = label
- currentIndex = index + 1
- currentSectionStart = currentIndex
- continue
- }
- }
- currentIndex++
-
- }
-
- val currentContent = substring(currentSectionStart, currentIndex).trim()
- val section = DocumentationContentSection(currentLabel, currentContent.toRichString())
- sections.put(section.label, section)
- return sections
-}
-
-fun String.toRichString() : RichString {
- val content = RichString()
- for(index in indices) {
- val ch = get(index)
- when {
- ch == '\\' -> continue
- ch == '*' && index < length-1 && !get(index + 1).isWhitespace() -> ch
- }
- }
-
- content.addSlice(this, NormalStyle)
- return content
-} \ No newline at end of file
diff --git a/src/Model/DocumentationModule.kt b/src/Model/DocumentationModule.kt
index 78ebda04..6084ea5e 100644
--- a/src/Model/DocumentationModule.kt
+++ b/src/Model/DocumentationModule.kt
@@ -1,30 +1,11 @@
package org.jetbrains.dokka
-import org.jetbrains.jet.lang.resolve.BindingContext
-import org.jetbrains.jet.lang.descriptors.*
-import org.jetbrains.jet.lang.resolve.name.FqName
-
-public class DocumentationModule(name: String, val module: ModuleDescriptor) : DocumentationNode(module, name, DocumentationContent.Empty, DocumentationNode.Kind.Module) {
+public class DocumentationModule(name: String) : DocumentationNode(name, Content.Empty, DocumentationNode.Kind.Module) {
fun merge(other: DocumentationModule): DocumentationModule {
- val model = DocumentationModule(name, module)
+ val model = DocumentationModule(name)
model.addAllReferencesFrom(other)
model.addAllReferencesFrom(this)
return model
}
}
-fun BindingContext.createDocumentationModule(name: String,
- module: ModuleDescriptor,
- packages: Set<FqName>,
- options : DocumentationOptions = DocumentationOptions()): DocumentationModule {
- val documentationModule = DocumentationModule(name, module)
- val visitor = DocumentationNodeBuilder(this)
- for (packageName in packages) {
- val pkg = module.getPackage(packageName)
- pkg!!.accept(DocumentationBuildingVisitor(this, options, visitor), documentationModule)
- }
-
- // TODO: Uncomment for resolve verification
- // checkResolveChildren(documentationModule)
- return documentationModule
-}
diff --git a/src/Model/DocumentationNode.kt b/src/Model/DocumentationNode.kt
index c96c383d..198e549b 100644
--- a/src/Model/DocumentationNode.kt
+++ b/src/Model/DocumentationNode.kt
@@ -1,12 +1,9 @@
package org.jetbrains.dokka
-import org.jetbrains.jet.lang.descriptors.*
import java.util.LinkedHashSet
-
-public open class DocumentationNode(val descriptor: DeclarationDescriptor,
- val name: String,
- val doc: DocumentationContent,
+public open class DocumentationNode(val name: String,
+ val doc: Content,
val kind: DocumentationNode.Kind) {
private val references = LinkedHashSet<DocumentationReference>()