/**
* Copyright (c) 2011 Cloudsmith Inc. and other contributors, as listed below.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cloudsmith
*
*/
package org.cloudsmith.geppetto.ruby;
import org.cloudsmith.geppetto.common.CharSequences;
/**
* Processes documentation text found in ruby code. The main problem is determining the "natural margin" as it is ambiguous.
*
*
*/
public class RubyDocProcessorSimple {
private enum State {
start, para, pre;
};
/**
* Substitutes '*text*' with '<b>text</b>', and '`text`' with '<tt>text</tt>', and
* appends the text and a new line.
*
* @param s
* @param builder
*/
static private void appendNonVerbatimLine(String s, StringBuilder builder) {
s = s.replaceAll("\\*\\*([^\\*]+)\\*\\*", "<strong>$1</strong>");
s = s.replaceAll("\\*([^\\*]+)\\*", "<b>$1</b>");
s = s.replaceAll("`([^`]+)`", "<tt>$1</tt>");
builder.append(s).append("\n");
}
static public String asHTML(String s) {
if(s == null || s.length() < 1)
return s;
int minPos = Integer.MAX_VALUE;
String[] lines = s.split("\\n");
for(int i = 1; i < lines.length; i++) {
int idx = CharSequences.indexOfNonWhitespace(lines[i], 0);
if(idx >= 0)
minPos = Math.min(minPos, idx);
}
// trim left margin
// first line is problematic, since initial whitespace is inconsistently used in the source
// If it starts with whitespace, assume it is at the natural margin.
final int naturalMargin = minPos;
// always trim the first line - hope it is never a verbatim (how can it be detected? - indented from what?)
if(lines.length > 0)
lines[0] = CharSequences.trim(lines[0]).toString();
for(int i = 1; i < lines.length; i++)
lines[i] = CharSequences.trim(lines[i], naturalMargin, lines[i].length()).toString();
State flowState = State.start;
StringBuilder builder = new StringBuilder();
for(int i = 0; i < lines.length; i++) {
String line = lines[i];
int firstCharPos = CharSequences.indexOfNonWhitespace(line, 0);
boolean verbatimLine = firstCharPos > 0;
boolean emptyLine = firstCharPos < 0;
if(flowState == State.start) {
if(emptyLine)
continue; // skip empty leading lines
if(verbatimLine) {
flowState = State.pre;
builder.append("<pre>");
builder.append(line).append("\n");
}
else {
flowState = State.para;
builder.append("<p>");
appendNonVerbatimLine(line, builder);
}
}
else if(flowState == State.para) {
if(verbatimLine) {
builder.append("</p>\n<pre>");
flowState = State.pre;
builder.append(line).append("\n");
}
else if(emptyLine) {
// start new para
builder.append("</p>\n<p>");
}
else {
appendNonVerbatimLine(line, builder);
}
}
else if(flowState == State.pre) {
if(verbatimLine) {
builder.append(line).append("\n");
}
else if(emptyLine) {
builder.append("\n");
}
else {
// break pre
flowState = State.para;
builder.append("</pre>\n<p>");
appendNonVerbatimLine(line, builder);
}
}
}
switch(flowState) {
case pre:
builder.append("</pre>");
break;
case para:
builder.append("</p>");
break;
case start:
// no content
break;
}
return builder.toString();
}
}