Index: /trunk/de.ugoe.cs.swe.bnftools.ebnf.ui/src/de/ugoe/cs/swe/bnftools/ui/formatter/EbnfFormatterVisitor.java
===================================================================
--- /trunk/de.ugoe.cs.swe.bnftools.ebnf.ui/src/de/ugoe/cs/swe/bnftools/ui/formatter/EbnfFormatterVisitor.java	(revision 36)
+++ /trunk/de.ugoe.cs.swe.bnftools.ebnf.ui/src/de/ugoe/cs/swe/bnftools/ui/formatter/EbnfFormatterVisitor.java	(revision 37)
@@ -69,5 +69,5 @@
 	}
 
-	private boolean isCommentNode(LeafNode node) {
+	protected boolean isCommentNode(LeafNode node) {
 		if ((node.getText().trim().startsWith("//") || node.getText().trim().startsWith("/*")) && (node.isHidden()))
 			return true;
@@ -75,5 +75,5 @@
 	}
 	
-	private void collectAllComments(CompositeNode node) {
+	protected void collectAllComments(CompositeNode node) {
 		for (int i=0; i < node.getChildren().size(); i++) {
 			AbstractNode currentNode = node.getChildren().get(i);
@@ -91,5 +91,5 @@
 	}
 
-	private boolean isSingleLineComment(String str) {
+	protected boolean isSingleLineComment(String str) {
 		if (str.startsWith("//"))
 			return true;
@@ -97,5 +97,5 @@
 	}
 	
-	private boolean isMultiLineComment(String str) {
+	protected boolean isMultiLineComment(String str) {
 		if (str.startsWith("/*"))
 			return true;
@@ -103,5 +103,5 @@
 	}
 
-	private boolean isWhitespace(char ch) {
+	protected boolean isWhitespace(char ch) {
 		if ((ch==' ') || (ch == '\t') || (ch == '\n') || (ch == '\r'))
 			return true;
@@ -109,5 +109,5 @@
 	}
 	
-	private void skipWhitespacesOriginalText() {
+	protected void skipWhitespacesOriginalText() {
 		while (bufferPositionOriginalText < originalText.length() && isWhitespace(originalText.charAt(bufferPositionOriginalText))) {
 			bufferPositionOriginalText++;
@@ -115,5 +115,5 @@
 	}
 
-	private void skipWhitespacesFormattedText(StringBuffer result) {
+	protected void skipWhitespacesFormattedText(StringBuffer result) {
 		while (bufferPositionFormattedText < formattedText.length() && isWhitespace(formattedText.charAt(bufferPositionFormattedText))) {
 			result.append(formattedText.substring(bufferPositionFormattedText, bufferPositionFormattedText+1));
@@ -122,5 +122,5 @@
 	}
 
-	private boolean isSingleLineCommentNext(String str, int position) {
+	protected boolean isSingleLineCommentNext(String str, int position) {
 		if ((str.charAt(position) == '/') && (str.charAt(position) == '/'))
 			return true;
@@ -128,5 +128,5 @@
 	}
 	
-	private boolean isMultiLineCommentNext(String str, int position) {
+	protected boolean isMultiLineCommentNext(String str, int position) {
 		if ((str.charAt(position) == '/') && (str.charAt(position) == '*'))
 			return true;
@@ -134,5 +134,5 @@
 	}
 		
-	private boolean isCommentNext(String str, int position) {
+	protected boolean isCommentNext(String str, int position) {
 		if (isSingleLineCommentNext(str, position) || isMultiLineCommentNext(str, position))
 			return true;
@@ -141,5 +141,5 @@
 	}
 	
-	private String scanBackWhitespaces(String str, int position) {
+	protected String scanBackWhitespaces(String str, int position) {
 		StringBuffer whiteSpaces = new StringBuffer();
 		int currentPosition = position;
@@ -151,5 +151,5 @@
 	}
 	
-	private String stripEndingNewline(String str) {
+	protected String stripEndingNewline(String str) {
 		int position = str.length() - 1;
 		while ((str.charAt(position) == '\n') || (str.charAt(position) == '\r')) {
@@ -159,5 +159,5 @@
 	}
 	
-	private int scanBackNewlinesCount(String str, int position) {
+	protected int scanBackNewlinesCount(String str, int position) {
 		int newLinesCount = 0;
 		int currentPosition = position;
@@ -179,5 +179,5 @@
 	}
 	
-	private void weaveComments() {
+	protected void weaveComments() {
 		bufferPositionOriginalText = 0;
 		bufferPositionFormattedTextNoWhitespaces = 0;
@@ -255,5 +255,5 @@
 	}
 
-	private void newLine() {
+	protected void newLine() {
 		buf.append("\n");
 		if ((ruleSpacingStack != null) && (!ruleSpacingStack.empty())) {
@@ -264,15 +264,15 @@
 	}
 	
-	private void text(String str) {
+	protected void text(String str) {
 		buf.append(str);
 		newLineOffsetCounter += str.length();
 	}
 
-	private void space() {
+	protected void space() {
 		buf.append(" ");
 		newLineOffsetCounter++;
 	}
 	
-	private void spaces(int count) {
+	protected void spaces(int count) {
 		for (int i=0; i < count; i++) {
 			buf.append(" ");
@@ -280,5 +280,5 @@
 	}
 
-	private boolean lastIsClosingParentheses() {
+	protected boolean lastIsClosingParentheses() {
 		char ch = buf.toString().charAt(buf.toString().length()-1);
 		if ((ch == ')') || (ch == ']') || (ch == '}'))
@@ -287,5 +287,5 @@
 	}
 
-	private void wrap() {
+	protected void wrap() {
 		if ((config.isWrapAfterThreshold()) && (newLineOffsetCounter > config.getWrapThreshold())) {
 			char last = buf.toString().charAt(buf.toString().length()-1);
Index: /trunk/de.ugoe.cs.swe.bnftools.ebnf.ui/src/de/ugoe/cs/swe/bnftools/ui/formatter/EbnfHtmlFormatterVisitor.java
===================================================================
--- /trunk/de.ugoe.cs.swe.bnftools.ebnf.ui/src/de/ugoe/cs/swe/bnftools/ui/formatter/EbnfHtmlFormatterVisitor.java	(revision 36)
+++ /trunk/de.ugoe.cs.swe.bnftools.ebnf.ui/src/de/ugoe/cs/swe/bnftools/ui/formatter/EbnfHtmlFormatterVisitor.java	(revision 37)
@@ -1,8 +1,17 @@
 package de.ugoe.cs.swe.bnftools.ui.formatter;
 
+import java.util.ArrayList;
+import java.util.Iterator;
+
 import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.parsetree.LeafNode;
+
+import de.ugoe.cs.swe.bnftools.ebnf.EtsiBnf;
+import de.ugoe.cs.swe.bnftools.ebnf.SectionHeading;
 
 public class EbnfHtmlFormatterVisitor extends EbnfFormatterVisitor {
 
+	private ArrayList<MetaTextEntry> metaTexts = new ArrayList<MetaTextEntry>();
+	
 	public EbnfHtmlFormatterVisitor(EObject rootNode, FormatterConfig config) {
 		super(rootNode, config);
@@ -11,4 +20,125 @@
 	}
 
+	protected void weaveComments() {
+		bufferPositionOriginalText = 0;
+		bufferPositionFormattedTextNoWhitespaces = 0;
+		bufferPositionFormattedText = 0;
+		
+		StringBuffer result = new StringBuffer();
+		formattedTextNoWhitespaces = buf.toString().replaceAll("[ \t\n\r]", "");
+		formattedText = buf.toString();
 
+		MetaTextEntry currentMetaText = null;
+		if (metaTexts.iterator().hasNext())
+			currentMetaText = metaTexts.iterator().next();
+
+		while (bufferPositionFormattedTextNoWhitespaces <= formattedTextNoWhitespaces.length()) {
+			skipWhitespacesOriginalText();
+			skipWhitespacesFormattedText(result);
+			
+			if (!(bufferPositionOriginalText < originalText.length()))
+				break;
+			
+			char formattedPositionNoWhitespaces;
+			if (bufferPositionFormattedTextNoWhitespaces == formattedTextNoWhitespaces.length()) {
+				formattedPositionNoWhitespaces = ' ';
+			} else {
+				formattedPositionNoWhitespaces = formattedTextNoWhitespaces.charAt(bufferPositionFormattedTextNoWhitespaces);
+			}
+			char originalPosition = originalText.charAt(bufferPositionOriginalText);
+			
+			if (formattedPositionNoWhitespaces != originalPosition) {
+				if (formattedPositionNoWhitespaces == ';') { // formatted text always outputs the optional semicolon, skip it if necessary
+					bufferPositionFormattedTextNoWhitespaces++;
+					bufferPositionFormattedText++;
+				} else if (isCommentNext(originalText, bufferPositionOriginalText)) {
+					LeafNode currentComment = allComments.get(allCommentsPosition); 
+					if (currentComment.getTotalOffset() == bufferPositionOriginalText) {
+						if (isMultiLineComment(currentComment.getText())) {
+							int newLinesCount = scanBackNewlinesCount(originalText, bufferPositionOriginalText-1);
+							if (newLinesCount > 0) {
+								if (scanBackNewlinesCount(result.toString(), result.toString().length()-1) == 0) {
+									result.append("\n\n");
+								}
+								
+								result.append(currentComment.getText());
+								result.append("\n");
+							} else {
+								String lastWhiteSpaces = scanBackWhitespaces(result.toString(), result.toString().length()-1);
+								result.delete(result.toString().length() - lastWhiteSpaces.length(), result.toString().length());
+								result.append(" " + stripEndingNewline(currentComment.getText()));
+								result.append(lastWhiteSpaces);
+							}
+						} else if (isSingleLineComment(currentComment.getText())) {
+							int newLinesCount = scanBackNewlinesCount(originalText, bufferPositionOriginalText-1);
+							String lastWhiteSpaces = scanBackWhitespaces(result.toString(), result.toString().length()-1);
+							result.delete(result.toString().length() - lastWhiteSpaces.length(), result.toString().length());
+							if (newLinesCount > 0) {
+								result.append("\n\n" + stripEndingNewline(currentComment.getText()));
+							} else {
+								result.append(" " + stripEndingNewline(currentComment.getText()));
+							}
+							result.append(lastWhiteSpaces);
+						}
+						bufferPositionOriginalText+=currentComment.getLength();
+						allCommentsPosition++;
+					}
+				} else { // disaster handling: return original unformatted text!
+					System.err.println("Disaster Recovery: returning original text!!");
+					buf = new StringBuffer();
+					buf.append(originalText);
+					return;
+				}
+			} else {
+				if ((currentMetaText != null) && (bufferPositionFormattedText >= currentMetaText.getOffset())) {
+					result.append(currentMetaText.getText());
+					metaTexts.remove(currentMetaText);
+					if (metaTexts.iterator().hasNext())
+						currentMetaText = metaTexts.iterator().next();
+					else
+						currentMetaText = null;
+				}
+				
+				result.append(formattedText.substring(bufferPositionFormattedText, bufferPositionFormattedText+1));
+				bufferPositionOriginalText++;
+				bufferPositionFormattedText++;
+				bufferPositionFormattedTextNoWhitespaces++;
+				
+				if ((currentMetaText != null) && (bufferPositionFormattedText >= currentMetaText.getOffset())) {
+					result.append(currentMetaText.getText());
+					metaTexts.remove(currentMetaText);
+					if (metaTexts.iterator().hasNext())
+						currentMetaText = metaTexts.iterator().next();
+					else
+						currentMetaText = null;
+				}
+			}
+		}
+		buf = result;
+	}
+	
+	protected void metaText(String str) {
+		MetaTextEntry metaTextEntry = new MetaTextEntry(str, buf.length());
+		metaTexts.add(metaTextEntry);
+	}
+
+	// -----------------------------------------------------------------------------
+	
+	protected void visitBefore(SectionHeading node) {
+		if (!lastWasSectionHeading && !buf.substring(buf.length()-2).equals("\n\n"))
+			newLine();
+		
+		lastWasSectionHeading=true;
+		
+		metaText("<h1>");
+		text(node.getSectionHeader().replaceAll("[\n\r]", ""));
+		metaText("</h1>");
+	}
+
+	protected void visitAfter(SectionHeading node) {
+	}
+
+	protected void visitAfter(EtsiBnf node) {
+		weaveComments();
+	}
 }
Index: /trunk/de.ugoe.cs.swe.bnftools.ebnf.ui/src/de/ugoe/cs/swe/bnftools/ui/formatter/MetaTextEntry.java
===================================================================
--- /trunk/de.ugoe.cs.swe.bnftools.ebnf.ui/src/de/ugoe/cs/swe/bnftools/ui/formatter/MetaTextEntry.java	(revision 37)
+++ /trunk/de.ugoe.cs.swe.bnftools.ebnf.ui/src/de/ugoe/cs/swe/bnftools/ui/formatter/MetaTextEntry.java	(revision 37)
@@ -0,0 +1,33 @@
+package de.ugoe.cs.swe.bnftools.ui.formatter;
+
+public class MetaTextEntry {
+	private String text;
+	private int offset;
+
+	public MetaTextEntry(String text, int offset) {
+		this.text = text;
+		this.offset = offset;
+	}
+
+	public String getText() {
+		return text;
+	}
+
+	public void setText(String text) {
+		this.text = text;
+	}
+
+	public int getOffset() {
+		return offset;
+	}
+
+	public void setOffset(int offset) {
+		this.offset = offset;
+	}
+
+	@Override
+	public String toString() {
+		return "MetaTextEntry [text=" + text + ", offset=" + offset + "]";
+	}
+
+}
