diff --git a/bonus2/.svnignore b/bonus2/.svnignore index 917d690..8ce9a04 100644 --- a/bonus2/.svnignore +++ b/bonus2/.svnignore @@ -1,13 +1,13 @@ *.iml .idea .gradle -/local.properties -/.idea/workspace.xml -/.idea/libraries +local.properties +.idea/workspace.xml +.idea/libraries .DS_Store -/build -/captures -/lib +build +captures +lib *.jar -/dist - +dist +res \ No newline at end of file diff --git a/bonus2/ReadMe.md b/bonus2/ReadMe.md new file mode 100644 index 0000000..dcfce30 --- /dev/null +++ b/bonus2/ReadMe.md @@ -0,0 +1,65 @@ +# Bonus 2 + +Author: Bevilacqua Joey + +Language: Kotlin + +## Build + +To compile this exercise `gradle` and `java-1.8` are needed. + +To create a working jar executable, run + +``` +./gradlew shadowJar +``` + +The output jar will be available at this path: `build/libs/bonus2.jar` + +## Execute + +``` +java -jar bonus2.jar [file1.html] [file2.html] [directory] +``` + +Both files and directories can be passed as parameter, even at the same. + +If a directory is passed as parameter, the program will attemp to +recursively search for Jekyll html files. + +The converted LaTeX files will be created in the `out` directory with +subdirectories matching the absolute path of the files passed as argument. + +Note that the program will not work with plain html files, +it requires Jekyll html files instead. + +A test file is available for reference under the directory `res`. + +## Supported tags + +### HTML tags + +* b -> textbf +* br -> \\ +* code -> texttt +* i -> emph +* a -> emph footnote url +* ul -> itemize +* ol -> itemize +* li -> item +* pre -> verbatim +* h1 -> section +* h2 -> subsection +* h3 -> subsubsection +* h4 -> plainText +* h5 -> plainText +* p -> plainText +* table -> table tabular +* u -> underline + +### Extra + +* comments are removed +* jekyll author -> LaTeX author +* jekyll title -> LaTeX title + diff --git a/bonus2/build.gradle b/bonus2/build.gradle index 0cb9257..61d6744 100644 --- a/bonus2/build.gradle +++ b/bonus2/build.gradle @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018. Bevilacqua Joey + * Copyright (c) 2018 Bevilacqua Joey. */ buildscript { diff --git a/bonus2/gradle/wrapper/gradle-wrapper.jar b/bonus2/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..1948b90 Binary files /dev/null and b/bonus2/gradle/wrapper/gradle-wrapper.jar differ diff --git a/bonus2/gradle/wrapper/gradle-wrapper.properties b/bonus2/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..6a63515 --- /dev/null +++ b/bonus2/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,9 @@ +# +# Copyright (c) 2018 Bevilacqua Joey. +# + +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/bonus2/gradlew b/bonus2/gradlew new file mode 100755 index 0000000..cccdd3d --- /dev/null +++ b/bonus2/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/bonus2/gradlew.bat b/bonus2/gradlew.bat new file mode 100644 index 0000000..e95643d --- /dev/null +++ b/bonus2/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/bonus2/res/test.html b/bonus2/res/test.html index 0170136..6a09b9c 100644 --- a/bonus2/res/test.html +++ b/bonus2/res/test.html @@ -1,59 +1,77 @@ --- layout: page -category-title: Basic commands +category-title: Knowledge category-page: basic -tags: directory change navigate -author: Alessandro Marinelli -title: cd +tags: tragedy know +author: Sheev Palpatine +title: The Tragedy previous-page: pages/cmd/basic/open.html next-page: pages/cmd/basic/ls.html --- -

-The cd command is used to change the working directory
-The name stands for Change Directory.
+Did you ever hear the tragedy of Darth Plagueis The Wise?
+I thought not. It’s not a story the Jedi would tell you.
+It’s a Sith legend. Darth Plagueis was a Dark Lord of the Sith, +so powerful and so wise he could use the Force to influence the midichlorians to create life…
+He had such a knowledge of the dark side that he could even keep the ones he cared about from dying.
+The dark side of the Force is a pathway to many abilities some consider to be unnatural.
+He became so powerful… the only thing he was afraid of was losing his power, which eventually, of course, he did.
+Unfortunately, he taught his apprentice everything he knew, then his apprentice killed him in his sleep.
+Ironic. He could save others from death, but not himself.
-The default cd command syntax is: +

Surprise

-cd [flags] [path]
+A surprise to be sure,
+    but a welcome one.
 
-Where [flags] are the cd flags, read below for more info,and [path] is the -path (absolute or relative), of the directory which we want to make as working directory.

- -

Change the working directory

-Let's see how to use the command cd in order to change the working directory - -
-pwd
-    ~
-cd Desktop/multimedia
-pwd
-    ~/Desktop/multimedia
-
- -As you can see, we changed the working directory from ~ (which stands for HOME), -to "multimedia". Now our Shell will work on the directory "multimedia" -until a new cd will occour.
- -Notice: If you want to move to a directory which is not contained in the -current working directory, you MUST use the absolute path. + + + + + + + + + +
Take aseat
This is whereThe fun begins
-

Header 1

+

Fish

-

Header 2

+

Fish

-

Header 4

+

Fish

+ +There's always bigger fish
+ +[visible confusion] + + + + + + + + + + + + + + + + + + +
Thenegotiations
whereshort
I'll tryspinning
that's agood trick
+

diff --git a/bonus2/src/ch/usi/inf/atelier/group1/HtmlParser.kt b/bonus2/src/ch/usi/inf/atelier/group1/HtmlParser.kt new file mode 100644 index 0000000..01c1ac0 --- /dev/null +++ b/bonus2/src/ch/usi/inf/atelier/group1/HtmlParser.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018 Bevilacqua Joey. + */ + +package ch.usi.inf.atelier.group1 + +import ch.usi.inf.atelier.group1.jekyll.HtmlToLatexWriter +import ch.usi.inf.atelier.group1.jekyll.JekyllPage +import ch.usi.inf.atelier.group1.util.Log +import ch.usi.inf.atelier.group1.util.extensions.insertJekyllHeader +import ch.usi.inf.atelier.group1.util.extensions.writeTo +import java.io.File + +class HtmlParser(private val input: File) { + private val file = JekyllPage(input) + private val output = HtmlToLatexWriter(file.content) + + fun parse(): String { + if (!file.isValid()) { + Log.e(IllegalArgumentException("This file is not valid")) + } + + /* + if (file.header["author"] == "Marwan Announ") { + throw IllegalStateException("Invalid fuckery. Please don\'t attemp to parse this shit. Kthxbye") + } + */ + + output.run { + start() + insertJekyllHeader(file) + beginDocument() + + changeBold() + changeBr() + changeCode() + changeItalics() + changeLink() + changeList() + changeListItem() + changeMono() + changeParagraph() + changeSection() + changeSubSection() + changeSubSubSection() + changeTable() + changeUnderline() + + stripComments() + + endDocument() + + writeTo(input.absolutePath.replace(".html", ".tex")) + } + + return output.toString() + } + +} \ No newline at end of file diff --git a/bonus2/src/ch/usi/inf/atelier/group1/Main.kt b/bonus2/src/ch/usi/inf/atelier/group1/Main.kt index 6b8688d..14cba04 100644 --- a/bonus2/src/ch/usi/inf/atelier/group1/Main.kt +++ b/bonus2/src/ch/usi/inf/atelier/group1/Main.kt @@ -1,17 +1,34 @@ /* - * Copyright (c) 2018. Bevilacqua Joey + * Copyright (c) 2018 Bevilacqua Joey. */ package ch.usi.inf.atelier.group1 -import ch.usi.inf.atelier.group1.html.HtmlParser +import java.io.File object Main { @JvmStatic fun main(args: Array) { - for (arg in args) { - println(HtmlParser(arg).parse()) + args.forEach(this::convert) + } + + /** + * Convert html files to LaTex files + * + * @param path of the file (or directory containing files) to be converted + */ + private fun convert(path: String) { + val file = File(path) + + if (!file.isDirectory) { + HtmlParser(file).parse() + return } + + // Recursively search for other html files inside a directory + file.listFiles().filter { it.name.endsWith(".html") || it.isDirectory } + .map { it.path } + .forEach(this::convert) } } \ No newline at end of file diff --git a/bonus2/src/ch/usi/inf/atelier/group1/html/HtmlParser.kt b/bonus2/src/ch/usi/inf/atelier/group1/html/HtmlParser.kt deleted file mode 100644 index 2cfa3cf..0000000 --- a/bonus2/src/ch/usi/inf/atelier/group1/html/HtmlParser.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2018. Bevilacqua Joey - */ -package ch.usi.inf.atelier.group1.html - -import ch.usi.inf.atelier.group1.tex.TexDocument -import ch.usi.inf.atelier.group1.util.Log -import ch.usi.inf.atelier.group1.util.extensions.writeJekyllHeader -import org.jsoup.Jsoup -import org.jsoup.nodes.Element -import java.io.File - -class HtmlParser(path: String) { - private val file = JekyllHtmlFile(File(path)) - private val document = Jsoup.parse(file.content) - private val texDocument = TexDocument() - - fun parse(): String { - if (!file.isValid()) { - return "" - } - - texDocument.start() - texDocument.writeJekyllHeader(file) - texDocument.beginDocument() - - document.body().children().forEach { element -> parseToTex(element) } - - texDocument.endDocument() - - return texDocument.toString() - } - - private fun parseToTex(element: Element) { - val text = element.ownText() - - // TODO: fix span elements inside the paragraph senteces (tag-less items) - - texDocument.apply { - when (element.tagName()) { - TAG_BOLD -> addBold(text) - TAG_BR -> addBr() - TAG_CODE -> addCode(text) - TAG_H1 -> addSection(text) - TAG_H2 -> addSubSection(text) - TAG_H3, TAG_H4 -> addSubSubSection(text) - TAG_ITALICS -> addItalics(text) - TAG_LINK -> addLink(text, element.attr("href")) - TAG_P -> addParagraph(text) - TAG_PRE -> addPre(text) - TAG_UL -> element.parseList() - "", null -> addText(element.text()) - } - } - } - - private fun Element.parseList() { - texDocument.apply { - beginList() - - children().filter { TAG_LI == it.tagName() } - .forEach { e -> addListItem(e.text()) } - - endList() - } - } - - companion object { - private const val TAG_BOLD = "b" - private const val TAG_BR = "br" - private const val TAG_CODE = "code" - private const val TAG_H1 = "h1" - private const val TAG_H2 = "h2" - private const val TAG_H3 = "h3" - private const val TAG_H4 = "h4" - private const val TAG_ITALICS = "i" - private const val TAG_LI = "li" - private const val TAG_LINK = "a" - private const val TAG_P = "p" - private const val TAG_PRE = "pre" - private const val TAG_UL = "ul" - } -} \ No newline at end of file diff --git a/bonus2/src/ch/usi/inf/atelier/group1/jekyll/HtmlToLatexWriter.kt b/bonus2/src/ch/usi/inf/atelier/group1/jekyll/HtmlToLatexWriter.kt new file mode 100644 index 0000000..08c08ac --- /dev/null +++ b/bonus2/src/ch/usi/inf/atelier/group1/jekyll/HtmlToLatexWriter.kt @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2018 Bevilacqua Joey. + */ +package ch.usi.inf.atelier.group1.jekyll + +import org.jsoup.Jsoup +import org.jsoup.parser.Parser +import java.util.regex.Pattern + +class HtmlToLatexWriter(private var content: String) { + private val document = StringBuilder() + + /** + * Prepare the Latex file + * and insert the header + */ + fun start() { + document.clear() + + insert(HEADER, afterLine = true) + } + + /** + * Begin the document and insert the title + * and table of contents automatically + */ + fun beginDocument() { + insert("\\begin{document}", afterLine = true) + insert("\\maketitle", afterLine = true) + insert("\\tableofcontents\\") + } + + /** + * End the document + */ + fun endDocument() { + insert(content) + insert("\\end{document}", afterLine = true) + } + + /** + * Insert a bold text in the document + */ + fun changeBold() { + content = content.replaceTag("", "", "\\textbf{", "}") + } + + /** + * Replace
with a LaTeX newline + */ + fun changeBr() { + content = content.replaceTag("
", null, "\\\\", null) + .replaceTag("
", null, "\\\\", null) + } + + /** + * Replace with LaTeX \texttt + */ + fun changeCode() { + content = content.replaceTag("", "", "\\texttt{", "}") + } + + /** + * Replace with LaTeX \emph + */ + fun changeItalics() { + content = content.replaceTag("", "", "\\emph{", "}") + } + + /** + * Replace with LaTeX footNote url + */ + fun changeLink() { + val pattern = Pattern.compile("(.*?)") + val matcher = pattern.matcher(content) + + while (matcher.find()) { + val text = matcher.group(3) + val url = matcher.group(1) + + content = content.replace(matcher.group(0), LINK.format(url, text)) + } + } + + /** + * Replace
    and
      with LaTeX itemize + */ + fun changeList() { + content = content.replaceTag("
        ", "
      ", "\\begin{itemize}", "\\end{itemize}") + .replaceTag("
        ", "
      ", "\\begin{itemize}", "\\end{itemize}") + } + + /** + * Replace
    1. with LaTeX itemize item + */ + fun changeListItem() { + content = content.replaceTag("
    2. ", "
    3. ", "\\item ", "") + } + + /** + * Replace
       with LaTeX verbatim
      +     */
      +    fun changeMono() {
      +        content = content.replaceTag("
      ", "
      ", "\\begin{verbatim}", "\\end{verbatim}") + } + + /** + * Replace

      , empty ,

      and
      with LaTeX plain text + */ + fun changeParagraph() { + content = content.replaceTag("

      ", "

      ", "", "") + .replaceTag("
      ", "
      ", "", "") + .replaceTag("

      ", "

      ", "\n", "") + .replaceTag("
      ", "", "", "") + } + + /** + * Replace

      with LaTeX \section + */ + fun changeSection() { + content = content.replaceTag("

      ", "

      ", "\\section{", "}\n") + } + + /** + * Replace

      with LaTeX \subsection + */ + fun changeSubSection() { + content = content.replaceTag("

      ", "

      ", "\\subsection{", "}\n") + } + + /** + * Replace

      with LaTeX \subsubsection + */ + fun changeSubSubSection() { + content = content.replaceTag("

      ", "

      ", "\\subsubsection{", "}\n") + } + + /** + * Replace with LaTex tabular + */ + fun changeTable() { + val pattern = Pattern.compile("(?:
      ((?:.*?\\r?\\n?)*)
      )+") + val matcher = pattern.matcher(content) + + while (matcher.find()) { + val document = Jsoup.parse(matcher.group(0), "", Parser.xmlParser()) + val table = document.select("table")[0] + val rows = table.select("tr") + + val columnsDump = ArrayList() + var colCount = 0 + + for (row in rows) { + var columns = row.select("td") + if (columns.isEmpty()) { + // Maybe this is an header + columns = row.select("th") + } + + if (colCount == 0) { + colCount = columns.size + } + + val dump = StringBuilder() + columns.map { it.wholeText() }.forEach { dump.append("$it &") } + + // Replace the last & with a LaTeX newLine + columnsDump.add(dump.removeSuffix("&").append("\\\\\n")) + } + + // Build the LaTeX table + val latexTable = StringBuilder().run { + append("\\begin{table}[h]\n\\begin{tabular}{${"l".repeat(colCount)}}\n") + columnsDump.forEach { append(" $it") } + append("\\end{tabular}\n\\end{table}") + toString() + } + + content = content.replace(matcher.group(0), latexTable) + } + } + + /** + * Replace
        with LaTeX \underline + */ + fun changeUnderline() { + content = content.replaceTag("", "", "\\underline{", "}") + } + + /** + * Add an author to the document + * + * @param author the text being inserted + */ + fun addAuthor(author: String) { + insert(AUTHOR.format(author), true, true) + } + + /** + * Add a title to the document + * + * @param title the text being inserted + */ + fun addTitle(title: String) { + insert(TITLE.format(title), true, true) + } + + /** + * Remove the html comments + */ + fun stripComments() { + content = content.replace(Regex("(?s)"), "") + } + + /** + * Insert content into the document + * + * @param string the content being inserted + * @param preLine whether a newLine char should be inserted before the content + * @param afterLine whether a newLine char should be inserted after the content + */ + private fun insert(string: String, preLine: Boolean = false, afterLine: Boolean = false) { + document.apply { + if (preLine) { + append("\n") + } + + append(string) + + if (afterLine) { + append("\n") + } + } + } + + private fun String.replaceTag(oldOpen: String, oldClose: String?, + newOpen: String, newClose: String?): String { + var replaced = replace(oldOpen, newOpen) + + if (oldClose != null && newClose != null) { + replaced = replaced.replace(oldClose, newClose) + } + + return replaced + } + + private fun CharSequence.append(append: String) = "${toString()}$append" + + override fun toString() = document.toString() + + companion object { + private const val AUTHOR = "\\author{%1\$s}" + private const val TITLE = "\\title{%1\$s}" + private const val LINK = "\\underline{\\href{%1\$s}{%2\$s}}" + + private const val HEADER = + "\\documentclass[hidelinks,12pt,a4paper,numbers=enddot]{scrartcl}\n\n" + + "\\usepackage[margin=2cm]{geometry}\n" + + "\\usepackage{hyperref}" + } +} \ No newline at end of file diff --git a/bonus2/src/ch/usi/inf/atelier/group1/html/JekyllHtmlFile.kt b/bonus2/src/ch/usi/inf/atelier/group1/jekyll/JekyllPage.kt similarity index 71% rename from bonus2/src/ch/usi/inf/atelier/group1/html/JekyllHtmlFile.kt rename to bonus2/src/ch/usi/inf/atelier/group1/jekyll/JekyllPage.kt index 0cc09f0..75bd0ba 100644 --- a/bonus2/src/ch/usi/inf/atelier/group1/html/JekyllHtmlFile.kt +++ b/bonus2/src/ch/usi/inf/atelier/group1/jekyll/JekyllPage.kt @@ -1,15 +1,22 @@ /* - * Copyright (c) 2018. Bevilacqua Joey + * Copyright (c) 2018 Bevilacqua Joey. */ -package ch.usi.inf.atelier.group1.html +package ch.usi.inf.atelier.group1.jekyll import ch.usi.inf.atelier.group1.util.extensions.getContent import java.io.BufferedReader import java.io.File import java.io.StringReader -class JekyllHtmlFile(file: File) { +class JekyllPage(file: File) { + /** + * The jekyll header variables + */ val header = HashMap() + + /** + * The jekyll html code + */ val content: String init { @@ -28,12 +35,14 @@ class JekyllHtmlFile(file: File) { isIteratingInHeader = HEADER_END != line if (isIteratingInHeader) { + // Import a jekyll variable val values = line.split(":") if (values.size == 2) { header[values[0]] = values[1].trim() } } } else { + // Import html code contentBuilder.append(line).append('\n') } @@ -43,10 +52,14 @@ class JekyllHtmlFile(file: File) { content = contentBuilder.toString() } + /** + * Check whether the imported file actually had valid content + * + * @return true if the header and the content aren't empty + */ fun isValid() = header.isNotEmpty() && content.isNotBlank() - override fun toString() = - "Header:\n$header\nContent:\n$content" + override fun toString() = "Header:\n$header\nContent:\n$content" companion object { private const val HEADER_START = "---" diff --git a/bonus2/src/ch/usi/inf/atelier/group1/tex/TexDocument.kt b/bonus2/src/ch/usi/inf/atelier/group1/tex/TexDocument.kt deleted file mode 100644 index 75dead2..0000000 --- a/bonus2/src/ch/usi/inf/atelier/group1/tex/TexDocument.kt +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2018. Bevilacqua Joey - */ -package ch.usi.inf.atelier.group1.tex - -class TexDocument { - private val document = StringBuilder() - - fun start() { - document.clear() - - insert(HEADER, false, true) - } - - fun beginDocument() { - insert("\\begin{document}", false, true) - insert("\\maketitle", false, true) - insert("\\tableofcontents", false, true) - insert("\\newpage", false, true) - } - - fun endDocument() { - insert("\\end{document}", false, true) - } - - fun addParagraph(content: String) { - if (content.isNotBlank()) { - insert(content, true, true) - } - } - - fun addText(content: String) { - if (content.isNotBlank()) { - insert(content, false, true) - } - } - - fun addSection(content: String) { - insert(SECTION.format(content, content.trim().toLowerCase()), false, true) - } - - fun addSubSection(content: String) { - insert(SUB_SECTION.format(content), false, true) - } - - fun addSubSubSection(content: String) { - insert(SUB_SUB_SECTION.format(content), false, true) - } - - fun addBold(content: String) { - insert(BOLD.format(content), false, false) - } - - fun addItalics(content: String) { - insert(ITALICS.format(content), false, false) - } - - fun addCode(content: String) { - insert(CODE.format(content), false, false) - } - - fun addPre(content: String) { - insert(PRE.format(content), false, true) - } - - fun addLink(content: String, url: String) { - insert(LINK.format(content, url), false, true) - } - - fun beginList() { - insert("\\begin{itemize}", false, true) - } - - fun endList() { - insert("\\end{itemize}", false, true) - - } - - fun addListItem(content: String) { - insert(LIST_ITEM.format(content), false, true) - } - - fun addBr() { - insert("", false, false) - } - - fun setAuthor(content: String) { - insert(AUTHOR.format(content), false, true) - } - - fun setTitle(content: String) { - insert(TITLE.format(content), false, true) - } - - private fun insert(string: String, newLine: Boolean, endLine: Boolean) { - document.apply { - append(string) - if(newLine) { - append("\\\\") - } - if (endLine) { - append("\n") - } - } - } - - override fun toString() = document.toString() - - companion object { - private const val AUTHOR = "\\author{%1\$s}\n" - private const val BOLD = "\\textbf{%1\$s}" - private const val CODE = "\\texttt{%1\$s}" - private const val ITALICS = "\\emph{%1\$s}" - private const val LINK = "\\emph{%1\$s} \\footnote{\\url{%2\$s}}" - private const val LIST_ITEM = "\\item %1\$s" - private const val PRE = "\n\\begin{verbatim}\n%1\$s\n\\end{verbatim}" - private const val SECTION = "\\section{%1\$s}\\label{%2\$s}" - private const val SUB_SECTION = "\\subsection{%1\$s}" - private const val SUB_SUB_SECTION = "\\subsubsection{%1\$s}" - private const val TITLE = "\\title{%1\$s}\n" - - private const val HEADER = - "\\documentclass[hidelinks,12pt,a4paper,numbers=enddot]{scrartcl}\n\n" + - "\\usepackage[margin=2cm]{geometry}\n" + - "\\usepackage{hyperref}\n" - - } -} \ No newline at end of file diff --git a/bonus2/src/ch/usi/inf/atelier/group1/util/Log.kt b/bonus2/src/ch/usi/inf/atelier/group1/util/Log.kt index 88ad775..db2dd99 100644 --- a/bonus2/src/ch/usi/inf/atelier/group1/util/Log.kt +++ b/bonus2/src/ch/usi/inf/atelier/group1/util/Log.kt @@ -1,21 +1,28 @@ /* - * Copyright (c) 2018. Bevilacqua Joey + * Copyright (c) 2018 Bevilacqua Joey. */ package ch.usi.inf.atelier.group1.util -import java.lang.Exception +import java.text.SimpleDateFormat +import java.util.* object Log { - fun e(message: String = "", exception: Exception) { - e("$message: ${exception.message ?: "Unknown error"}") - } - - fun e(message: String) { - System.err.println(message) + fun e(exception: Exception) { + print('E', exception.message ?: "Unknown error", true) } fun i(obj: Any) { - println(obj.toString()) + print('I', obj.toString(), false) + } + + private fun print(prefix: Char, message: String, isErr: Boolean) { + val time = SimpleDateFormat("yyyy-MM-dd hh:mm").format(Date()) + + if (isErr) { + System.err.println("$prefix $time\t$message") + } else { + System.out.println("$prefix $time\t$message") + } } } \ No newline at end of file diff --git a/bonus2/src/ch/usi/inf/atelier/group1/util/extensions/File.kt b/bonus2/src/ch/usi/inf/atelier/group1/util/extensions/File.kt index af437dd..3399725 100644 --- a/bonus2/src/ch/usi/inf/atelier/group1/util/extensions/File.kt +++ b/bonus2/src/ch/usi/inf/atelier/group1/util/extensions/File.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018. Bevilacqua Joey + * Copyright (c) 2018 Bevilacqua Joey. */ package ch.usi.inf.atelier.group1.util.extensions @@ -9,6 +9,11 @@ import java.io.File import java.io.FileReader import java.io.IOException +/** + * Get the content of the file as String + * + * @return this File content + */ fun File.getContent(): String { val content = StringBuilder() try { diff --git a/bonus2/src/ch/usi/inf/atelier/group1/util/extensions/String.kt b/bonus2/src/ch/usi/inf/atelier/group1/util/extensions/String.kt deleted file mode 100644 index c39e71f..0000000 --- a/bonus2/src/ch/usi/inf/atelier/group1/util/extensions/String.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2018. Bevilacqua Joey - */ -package ch.usi.inf.atelier.group1.util.extensions - -import ch.usi.inf.atelier.group1.util.Log -import java.io.File -import java.io.IOException - -fun String.toFile(): File? { - try { - File(this) - } catch (e: IOException) { - Log.e("Failed to open $this as File", e) - throw e - } - - return null -} - -fun String.getClosingTag() = "