Initial bonus 2 implementation
git-svn-id: svn+ssh://atelier.inf.usi.ch/home/bevilj/group-1@153 a672b425-5310-4d7a-af5c-997e18724b81
This commit is contained in:
parent
41c838f196
commit
2b3e9fa689
13
bonus2/.svnignore
Normal file
13
bonus2/.svnignore
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
*.iml
|
||||||
|
.idea
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/libraries
|
||||||
|
.DS_Store
|
||||||
|
/build
|
||||||
|
/captures
|
||||||
|
/lib
|
||||||
|
*.jar
|
||||||
|
/dist
|
||||||
|
|
13
bonus2/bonus2.iml
Normal file
13
bonus2/bonus2.iml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module external.linked.project.id="bonus2" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/out" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
55
bonus2/build.gradle
Normal file
55
bonus2/build.gradle
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018. Bevilacqua Joey
|
||||||
|
*/
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
ext.kotlin_version = '1.3.0'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'kotlin'
|
||||||
|
apply plugin: 'com.github.johnrengelman.shadow'
|
||||||
|
apply plugin: 'application'
|
||||||
|
|
||||||
|
defaultTasks 'run'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
|
implementation 'org.jsoup:jsoup:1.11.3'
|
||||||
|
}
|
||||||
|
|
||||||
|
mainClassName = 'ch.usi.inf.atelier.group1.Main'
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main.java.srcDirs += 'src'
|
||||||
|
}
|
||||||
|
|
||||||
|
task sourcesJar(type: Jar) {
|
||||||
|
classifier = 'sources'
|
||||||
|
from 'src'
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
manifest {
|
||||||
|
attributes 'Main-Class': 'ch.usi.inf.atelier.group1.MainKt'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowJar {
|
||||||
|
baseName = 'bonus2'
|
||||||
|
classifier = null
|
||||||
|
version = null
|
||||||
|
}
|
59
bonus2/res/test.html
Normal file
59
bonus2/res/test.html
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
---
|
||||||
|
layout: page
|
||||||
|
category-title: Basic commands
|
||||||
|
category-page: basic
|
||||||
|
tags: directory change navigate
|
||||||
|
author: Alessandro Marinelli
|
||||||
|
title: cd
|
||||||
|
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>
|
||||||
|
|
||||||
|
The default cd command syntax is:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
cd [flags] [path]
|
||||||
|
</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>.
|
||||||
|
|
||||||
|
|
||||||
|
<h1>Header 1</h1>
|
||||||
|
|
||||||
|
<h2>Header 2</h2>
|
||||||
|
|
||||||
|
<h4>Header 4</h4>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>A</li>
|
||||||
|
<li>B: Hello there</li>
|
||||||
|
<li>C</li>
|
||||||
|
<li>D</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</p>
|
17
bonus2/src/ch/usi/inf/atelier/group1/Main.kt
Normal file
17
bonus2/src/ch/usi/inf/atelier/group1/Main.kt
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018. Bevilacqua Joey
|
||||||
|
*/
|
||||||
|
package ch.usi.inf.atelier.group1
|
||||||
|
|
||||||
|
import ch.usi.inf.atelier.group1.html.HtmlParser
|
||||||
|
|
||||||
|
object Main {
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
|
||||||
|
for (arg in args) {
|
||||||
|
println(HtmlParser(arg).parse())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
83
bonus2/src/ch/usi/inf/atelier/group1/html/HtmlParser.kt
Normal file
83
bonus2/src/ch/usi/inf/atelier/group1/html/HtmlParser.kt
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
}
|
||||||
|
}
|
55
bonus2/src/ch/usi/inf/atelier/group1/html/JekyllHtmlFile.kt
Normal file
55
bonus2/src/ch/usi/inf/atelier/group1/html/JekyllHtmlFile.kt
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018. Bevilacqua Joey
|
||||||
|
*/
|
||||||
|
package ch.usi.inf.atelier.group1.html
|
||||||
|
|
||||||
|
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) {
|
||||||
|
val header = HashMap<String, String>()
|
||||||
|
val content: String
|
||||||
|
|
||||||
|
init {
|
||||||
|
val fileContent = file.getContent()
|
||||||
|
val contentBuilder = StringBuilder()
|
||||||
|
|
||||||
|
var isIteratingInHeader = false
|
||||||
|
var line: String? = ""
|
||||||
|
|
||||||
|
val reader = BufferedReader(StringReader(fileContent))
|
||||||
|
|
||||||
|
while (line != null) {
|
||||||
|
if (!isIteratingInHeader && HEADER_START == line) {
|
||||||
|
isIteratingInHeader = true
|
||||||
|
} else if (isIteratingInHeader) {
|
||||||
|
isIteratingInHeader = HEADER_END != line
|
||||||
|
|
||||||
|
if (isIteratingInHeader) {
|
||||||
|
val values = line.split(":")
|
||||||
|
if (values.size == 2) {
|
||||||
|
header[values[0]] = values[1].trim()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
contentBuilder.append(line).append('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
line = reader.readLine()
|
||||||
|
}
|
||||||
|
|
||||||
|
content = contentBuilder.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isValid() = header.isNotEmpty() && content.isNotBlank()
|
||||||
|
|
||||||
|
override fun toString() =
|
||||||
|
"Header:\n$header\nContent:\n$content"
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val HEADER_START = "---"
|
||||||
|
private const val HEADER_END = "---"
|
||||||
|
}
|
||||||
|
}
|
128
bonus2/src/ch/usi/inf/atelier/group1/tex/TexDocument.kt
Normal file
128
bonus2/src/ch/usi/inf/atelier/group1/tex/TexDocument.kt
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
21
bonus2/src/ch/usi/inf/atelier/group1/util/Log.kt
Normal file
21
bonus2/src/ch/usi/inf/atelier/group1/util/Log.kt
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018. Bevilacqua Joey
|
||||||
|
*/
|
||||||
|
package ch.usi.inf.atelier.group1.util
|
||||||
|
|
||||||
|
import java.lang.Exception
|
||||||
|
|
||||||
|
object Log {
|
||||||
|
|
||||||
|
fun e(message: String = "", exception: Exception) {
|
||||||
|
e("$message: ${exception.message ?: "Unknown error"}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun e(message: String) {
|
||||||
|
System.err.println(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun i(obj: Any) {
|
||||||
|
println(obj.toString())
|
||||||
|
}
|
||||||
|
}
|
28
bonus2/src/ch/usi/inf/atelier/group1/util/extensions/File.kt
Normal file
28
bonus2/src/ch/usi/inf/atelier/group1/util/extensions/File.kt
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018. Bevilacqua Joey
|
||||||
|
*/
|
||||||
|
package ch.usi.inf.atelier.group1.util.extensions
|
||||||
|
|
||||||
|
import ch.usi.inf.atelier.group1.util.Log
|
||||||
|
import java.io.BufferedReader
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileReader
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
fun File.getContent(): String {
|
||||||
|
val content = StringBuilder()
|
||||||
|
try {
|
||||||
|
val reader = BufferedReader(FileReader(this))
|
||||||
|
var line: String? = ""
|
||||||
|
|
||||||
|
while (line != null) {
|
||||||
|
content.append(line)
|
||||||
|
.append('\n')
|
||||||
|
line = reader.readLine()
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.e(exception = e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return content.toString()
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* 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)}"
|
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
fun TexDocument.writeJekyllHeader(file: JekyllHtmlFile) {
|
||||||
|
val title = file.header["title"] ?: "Unknown title"
|
||||||
|
val author = file.header["author"] ?: "Unknown author"
|
||||||
|
|
||||||
|
setTitle(title)
|
||||||
|
setAuthor(author)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user