blob: 80d97941c81411657d4d7f29d8fffc5aee69bba9 [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2018-2022 Robert Bosch GmbH and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Robert Bosch GmbH - initial API and implementation
********************************************************************************
*/
package org.eclipse.app4mc.help.modifier;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.app4mc.help.modifier.util.Heading;
import org.eclipse.app4mc.help.modifier.util.HeadingIterator;
public class APP4MC_Help_Step_1_UpdateTOC {
public static void main(final String[] args) {
String inputFilePath = "";
try (Scanner scanner = new Scanner(System.in)) {
System.out.println("Provide the location of input HTML file :");
inputFilePath = scanner.nextLine(); // ".../help/advanced/printc223.html";
}
execute(inputFilePath);
}
public static File execute(final String inputFilePath) {
final File inputFile = new File(inputFilePath);
if (inputFile.exists() == false) {
System.err.println("provide a valid input HTML location");
System.exit(-1);
}
System.out.println("Reading input file : " + inputFilePath);
final List<Heading> toc = new ArrayList<Heading>();
final StringBuffer sb = new StringBuffer();
try (BufferedReader br = new BufferedReader(
new InputStreamReader(new FileInputStream(inputFile), StandardCharsets.UTF_8))) {
boolean isInToc = false;
boolean isAfterToc = false;
int tocLevel = 0;
final HeadingIterator headings = new HeadingIterator(toc);
while (br.ready()) {
final String readLine = br.readLine();
/*-
* =======================================================================
* STEP 1 : Copy lines before table of contents
* ======================================================================
*/
if (readLine.trim().startsWith("<div id=\"toc_content\">")) {
isInToc = true;
appendln(sb, readLine);
continue;
}
if (!(isInToc || isAfterToc)) {
appendln(sb, readLine);
continue;
}
/*-
* =======================================================================
* STEP 2 : Extract table of contents
* ======================================================================
*/
if (isInToc) {
if (readLine.startsWith("<div class=\"toc_")) { // entry or sub_entry
tocLevel++;
}
else if (readLine.contains("<a href=\"#")) {
final Heading entry = new Heading();
entry.level = tocLevel;
entry.number = readLine.substring(0, readLine.indexOf(". "));
entry.text = readLine.substring(readLine.indexOf("\">")+2, readLine.indexOf("</a>"));
toc.add(entry);
}
else if (readLine.startsWith("</div>")) {
tocLevel--;
if(tocLevel < 0) {
isInToc = false;
isAfterToc = true;
}
}
appendln(sb, readLine);
continue;
}
/*-
* =======================================================================
* STEP 3 : Modify headings
* ======================================================================
*/
if (isAfterToc) {
if (readLine.matches(".*<h\\d.*")) {
// heading line found
while (!readLine.replaceAll("\\W", "")
.contains(headings.current().text.replaceAll("\\W", ""))) {
// *** insert missing heading
// System.out.println("found: >" + readLine + "<");
// System.out.println("inserted: >" + headings.current() + "<");
appendlnHeading(sb, headings.current());
headings.next();
}
// *** modify existing heading
// include user defined id but ignore generic ones
String hID = extractHeadingId(readLine);
if (! hID.contains("-")) hID = null;
appendlnHeading(sb, headings.current(), hID);
headings.next();
// debug info: original line
// appendln(sb, "<!-- " + readLine.trim() + " -->");
}
else {
// other lines
appendln(sb, readLine);
}
continue;
}
}
}
catch (final Exception e) {
e.printStackTrace();
System.err.println("Error reading HTML file : " + inputFilePath);
}
/*-
* =======================================================================
* STEP 3 : generating output HTML file
* ======================================================================
*/
final File htmlFile = new File(inputFile.getParentFile(), "app4mc-help_1_updated_headings.html");
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(htmlFile), StandardCharsets.UTF_8))) {
bw.write(sb.toString());
bw.close();
System.out.println("Generated modified HTML file at : " + htmlFile.getAbsolutePath());
} catch (final IOException e) {
e.printStackTrace();
System.err.println("Error writing file : " + htmlFile.getAbsolutePath());
}
/*-
* =======================================================================
* STEP 4 : generating toc file
* ======================================================================
*/
HeadingIterator nodes = new HeadingIterator(toc);
final File tocFile = new File(inputFile.getParentFile(), "app4mc-help_toc.html");
try (PrintStream out = new PrintStream(new FileOutputStream(tocFile))) {
out.println("<!DOCTYPE html>");
out.println("<html lang=\"en-US\">");
out.println(" <head>");
out.println(" <meta charset=\"utf-8\" />");
out.println(" <link rel=\"stylesheet\" href=\"css/toc-style.css\" type=\"text/css\">");
out.println(" </head>");
out.println(" <body>");
out.println(" <h1>Contents</h1>");
out.println(" <div class=\"toc-tree\">");
writeNodeList(out, nodes);
out.println(" </div>");
out.println(" </body>");
out.println("</html>");
} catch (final IOException e) {
e.printStackTrace();
System.err.println("Error writing file : " + tocFile.getAbsolutePath());
}
return htmlFile; // for further processing
}
// ========== Functions for TOC export ==========
private static void writeNodeList(PrintStream out, HeadingIterator headings) {
int listLevel = headings.current().level;
out.println("<ul>");
while (headings.current().level == listLevel) {
if (hasSubElements(headings)) {
writeExpandableNode(out, headings);
} else {
writeLeafNode(out, headings);
}
}
out.println("</ul>");
}
private static void writeExpandableNode(PrintStream out, HeadingIterator headings) {
final Heading h = headings.current();
// output pattern: <li> <input type="checkbox" id="toc1.2.3" />
// <label for="toc1.2.3"><a href="#section1.2.3">Text</a></label>
// ...
// </li>
out.println("<li>" + getInput(h) + getLabel(h, getLink(h)));
headings.next();
writeNodeList(out, headings);
out.println("</li>");
}
private static void writeLeafNode(PrintStream out, HeadingIterator headings) {
final Heading h = headings.current();
//output pattern: <li><label class="leaf"><a href="#section1.2.3">Text</a></label></li>
out.println("<li><label class=\"leaf\">" + getLink(h) + "</label></li>");
headings.next();
}
private static boolean hasSubElements(HeadingIterator headings) {
return headings.current().level < headings.preview().level;
}
private static String getInput(Heading h) {
// pattern: <input type="checkbox" id="toc1.2.3" />
return "<input type=\"checkbox\" id=\"toc" + h.number + "\" />";
}
private static String getLabel(Heading h, String text) {
// pattern: <label for="toc1.2.3">text</label>
return "<label for=\"toc" + h.number + "\">" + text + "</label>";
}
private static String getLink(Heading h) {
// pattern: <a href="#section1.2.3">Text</a>
return "<a href=\"#section" + h.number + "\">" + h.text + "</a>";
}
// ========== Functions for Headings modification ==========
private static void appendlnHeading(final StringBuffer sb, final Heading heading) {
appendlnHeading(sb, heading, null);
}
private static void appendlnHeading(final StringBuffer sb, final Heading heading, final String id) {
sb.append(System.getProperty("line.separator"));
sb.append(System.getProperty("line.separator"));
sb.append("<h" + heading.level);
if (id != null && id != "") {
sb.append(" id=\"" + id + "\"");
}
sb.append(">");
sb.append("<a id=\"section" + heading.number + "\">");
if (heading.level <= 3) {
sb.append(heading.number + " ");
}
sb.append("</a>");
sb.append(heading.text);
sb.append("</h" + heading.level + ">");
sb.append(System.getProperty("line.separator"));
}
private static void appendln(final StringBuffer sb, final String line) {
sb.append(line);
sb.append(System.getProperty("line.separator"));
}
private static String extractHeadingId(String input) {
String result = null;
final Pattern idPattern = Pattern.compile(".*<h\\d\\s+id\\=\"(?<anchorDef>.*?)\">.*");
final Matcher mID = idPattern.matcher(input);
while (mID.find()) {
result = mID.group("anchorDef");
// System.out.println("AnchorDef : >" + result + "<");
}
return result;
}
}