bonus2: complete bonus 2
git-svn-id: svn+ssh://atelier.inf.usi.ch/home/bevilj/group-1@167 a672b425-5310-4d7a-af5c-997e18724b81
This commit is contained in:
parent
f79da2c9fc
commit
8b65602402
18 changed files with 806 additions and 304 deletions
bonus2
|
@ -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
|
65
bonus2/ReadMe.md
Normal file
65
bonus2/ReadMe.md
Normal file
|
@ -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
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018. Bevilacqua Joey
|
||||
* Copyright (c) 2018 Bevilacqua Joey.
|
||||
*/
|
||||
|
||||
buildscript {
|
||||
|
|
BIN
bonus2/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
bonus2/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
9
bonus2/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
9
bonus2/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -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
|
172
bonus2/gradlew
vendored
Executable file
172
bonus2/gradlew
vendored
Executable file
|
@ -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" "$@"
|
84
bonus2/gradlew.bat
vendored
Normal file
84
bonus2/gradlew.bat
vendored
Normal file
|
@ -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
|
|
@ -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
|
||||
---
|
||||
<!--
|
||||
Copyright (c) 2018. Bevilacqua Joey
|
||||
-->
|
||||
<p>
|
||||
The <code>cd</code> command is used to change the working directory<br>
|
||||
The name stands for <i>Change Directory</i>.<br>
|
||||
Did you ever hear the tragedy of <b>Darth Plagueis</b> <i>The Wise</i>?<br>
|
||||
<code>I thought not</code>. It’s not a story the Jedi would tell you.</br>
|
||||
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 <u>create life…</u><br>
|
||||
He had such a knowledge of the dark side that he could even keep the ones he cared about from dying.<br>
|
||||
The dark side of the Force is a pathway to many abilities some consider to be unnatural.<br>
|
||||
He became so powerful… the only thing he was afraid of was losing his power, which eventually, of course, he did.<br>
|
||||
Unfortunately, he taught his apprentice everything he knew, then his apprentice killed him in his sleep.<br>
|
||||
<b>Ironic</b>. He could save others from death, but not himself.<br>
|
||||
|
||||
The default cd command syntax is:
|
||||
<h1>Surprise</h1>
|
||||
|
||||
<pre>
|
||||
cd [flags] [path]
|
||||
A surprise to be sure,
|
||||
but a welcome one.
|
||||
</pre>
|
||||
|
||||
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.<br><br>
|
||||
|
||||
<h3>Change the working directory</h3>
|
||||
Let's see how to use the command <code>cd</code> in order to change the working directory
|
||||
|
||||
<pre>
|
||||
pwd
|
||||
~
|
||||
cd Desktop/multimedia
|
||||
pwd
|
||||
~/Desktop/multimedia
|
||||
</pre>
|
||||
|
||||
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.<br>
|
||||
|
||||
<b>Notice:</b> If you want to move to a directory which is not contained in the
|
||||
current working directory, you <u>MUST</u> use the <a href="foo.html">absolute path</a>.
|
||||
<table>
|
||||
<tr>
|
||||
<td>Take a</td>
|
||||
<td><b>seat</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://google.com">This</a> is where</td>
|
||||
<td>The fun begins</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<h1>Header 1</h1>
|
||||
<h3>Fish</h3>
|
||||
|
||||
<h2>Header 2</h2>
|
||||
<h2>Fish</h2>
|
||||
|
||||
<h4>Header 4</h4>
|
||||
<h1>Fish</h1>
|
||||
|
||||
There's always bigger fish<br>
|
||||
|
||||
[visible confusion]
|
||||
|
||||
<ul>
|
||||
<li>A</li>
|
||||
<li>B: Hello there</li>
|
||||
<li>C</li>
|
||||
<li>D</li>
|
||||
<li><u>Hello there</u></li>
|
||||
<li>General Kenobi</li>
|
||||
<li>You're a <b>bold</b> one</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>The</th>
|
||||
<th>negotiations</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>where</td>
|
||||
<td>short</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>I'll try</td>
|
||||
<td><i>spinning</i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>that's a</td>
|
||||
<td>good trick</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</p>
|
||||
|
|
59
bonus2/src/ch/usi/inf/atelier/group1/HtmlParser.kt
Normal file
59
bonus2/src/ch/usi/inf/atelier/group1/HtmlParser.kt
Normal file
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
|
@ -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<String>) {
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
261
bonus2/src/ch/usi/inf/atelier/group1/jekyll/HtmlToLatexWriter.kt
Normal file
261
bonus2/src/ch/usi/inf/atelier/group1/jekyll/HtmlToLatexWriter.kt
Normal file
|
@ -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("<b>", "</b>", "\\textbf{", "}")
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace <br> with a LaTeX newline
|
||||
*/
|
||||
fun changeBr() {
|
||||
content = content.replaceTag("<br>", null, "\\\\", null)
|
||||
.replaceTag("</br>", null, "\\\\", null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace <code> with LaTeX \texttt
|
||||
*/
|
||||
fun changeCode() {
|
||||
content = content.replaceTag("<code>", "</code>", "\\texttt{", "}")
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace <i> with LaTeX \emph
|
||||
*/
|
||||
fun changeItalics() {
|
||||
content = content.replaceTag("<i>", "</i>", "\\emph{", "}")
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace <a> with LaTeX footNote url
|
||||
*/
|
||||
fun changeLink() {
|
||||
val pattern = Pattern.compile("<a href=\"(.*?)\"(.*?)>(.*?)</a>")
|
||||
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 <ul> and <ol> with LaTeX itemize
|
||||
*/
|
||||
fun changeList() {
|
||||
content = content.replaceTag("<ul>", "</ul>", "\\begin{itemize}", "\\end{itemize}")
|
||||
.replaceTag("<ol>", "</ol>", "\\begin{itemize}", "\\end{itemize}")
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace <li> with LaTeX itemize item
|
||||
*/
|
||||
fun changeListItem() {
|
||||
content = content.replaceTag("<li>", "</li>", "\\item ", "")
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace <pre> with LaTeX verbatim
|
||||
*/
|
||||
fun changeMono() {
|
||||
content = content.replaceTag("<pre>", "</pre>", "\\begin{verbatim}", "\\end{verbatim}")
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace <p>, empty <a>, <h4> and <h5> with LaTeX plain text
|
||||
*/
|
||||
fun changeParagraph() {
|
||||
content = content.replaceTag("<h4>", "</h4>", "", "")
|
||||
.replaceTag("<h5>", "</h5>", "", "")
|
||||
.replaceTag("<p>", "</p>", "\n", "")
|
||||
.replaceTag("<a>", "</a>", "", "")
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace <h1> with LaTeX \section
|
||||
*/
|
||||
fun changeSection() {
|
||||
content = content.replaceTag("<h1>", "</h1>", "\\section{", "}\n")
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace <h2> with LaTeX \subsection
|
||||
*/
|
||||
fun changeSubSection() {
|
||||
content = content.replaceTag("<h2>", "</h2>", "\\subsection{", "}\n")
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace <h3> with LaTeX \subsubsection
|
||||
*/
|
||||
fun changeSubSubSection() {
|
||||
content = content.replaceTag("<h3>", "</h3>", "\\subsubsection{", "}\n")
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace <table> with LaTex tabular
|
||||
*/
|
||||
fun changeTable() {
|
||||
val pattern = Pattern.compile("(?:<table>((?:.*?\\r?\\n?)*)</table>)+")
|
||||
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<String>()
|
||||
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 <ul> with LaTeX \underline
|
||||
*/
|
||||
fun changeUnderline() {
|
||||
content = content.replaceTag("<u>", "</u>", "\\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}"
|
||||
}
|
||||
}
|
|
@ -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<String, String>()
|
||||
|
||||
/**
|
||||
* 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 = "---"
|
|
@ -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"
|
||||
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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() = "</${substring(1, length)}"
|
|
@ -1,15 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2018. Bevilacqua Joey
|
||||
* Copyright (c) 2018 Bevilacqua Joey.
|
||||
*/
|
||||
package ch.usi.inf.atelier.group1.util.extensions
|
||||
|
||||
import ch.usi.inf.atelier.group1.html.JekyllHtmlFile
|
||||
import ch.usi.inf.atelier.group1.tex.TexDocument
|
||||
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 java.io.File
|
||||
import java.io.FileWriter
|
||||
|
||||
fun TexDocument.writeJekyllHeader(file: JekyllHtmlFile) {
|
||||
/**
|
||||
* Insert author and title from Jekyll file
|
||||
*/
|
||||
fun HtmlToLatexWriter.insertJekyllHeader(file: JekyllPage) {
|
||||
val title = file.header["title"] ?: "Unknown title"
|
||||
val author = file.header["author"] ?: "Unknown author"
|
||||
|
||||
setTitle(title)
|
||||
setAuthor(author)
|
||||
addTitle(title)
|
||||
addAuthor(author)
|
||||
}
|
||||
|
||||
fun HtmlToLatexWriter.writeTo(path: String) {
|
||||
val outDir = File("out", File(path).parent)
|
||||
|
||||
if (!outDir.exists()) {
|
||||
outDir.mkdirs()
|
||||
}
|
||||
|
||||
val file = File("out", path)
|
||||
|
||||
val writer = FileWriter(file, false)
|
||||
|
||||
Log.i("${file.path} created")
|
||||
|
||||
writer.write(toString())
|
||||
writer.flush()
|
||||
writer.close()
|
||||
}
|
Loading…
Reference in a new issue