From 1bbc92d653de8ae6b004b2fc6bfa5f4a420ece34 Mon Sep 17 00:00:00 2001
From: Artem Tanyhin
Date: Tue, 11 Oct 2022 21:50:22 -0400
Subject: [PATCH] Refactored code to improve maintainability
* split utils into smaller files
* refactor accepted filetypes
* refactor name and extension conversion
* refactor inline markdown parsing
* Implemented italics, bold, and href using regexp
---
ssgo.go | 10 +-
test/Markdown File.md | 6 +-
utils/help.go | 23 ++
utils/html-generation.go | 193 +++++++++++++++++
utils/input-processing.go | 147 +++++++++++++
utils/markdown.go | 68 ++++++
utils/settings.go | 10 +
utils/utils.go | 429 --------------------------------------
8 files changed, 448 insertions(+), 438 deletions(-)
create mode 100644 utils/help.go
create mode 100644 utils/html-generation.go
create mode 100644 utils/input-processing.go
create mode 100644 utils/markdown.go
create mode 100644 utils/settings.go
delete mode 100644 utils/utils.go
diff --git a/ssgo.go b/ssgo.go
index 8f8c6a3..e68a52c 100644
--- a/ssgo.go
+++ b/ssgo.go
@@ -4,19 +4,16 @@ import (
"fmt"
"os"
- "github.com/devils2ndself/SSGo/utils"
+ utils "github.com/devils2ndself/SSGo/utils"
flag "github.com/spf13/pflag"
)
const version string = "0.3"
-const defaultOutput string= "dist"
-
func main() {
-
var (
input string = ""
- output string = defaultOutput
+ output string = utils.DefaultOutput
displayHelp bool = false
displayVersion bool = false
config string = ""
@@ -24,7 +21,7 @@ func main() {
// Flag initialization
flag.StringVarP(&input, "input", "i", "", utils.InputHelpMessage)
- flag.StringVarP(&output, "output", "o", defaultOutput, utils.OutputHelpMessage)
+ flag.StringVarP(&output, "output", "o", utils.DefaultOutput, utils.OutputHelpMessage)
flag.BoolVarP(&displayHelp, "help", "h", false, utils.HelpHelpMessage)
flag.BoolVarP(&displayVersion, "version", "v", false, utils.VersionHelpMessage)
flag.StringVarP(&config, "config", "c", "", utils.ConfigHelpMessage)
@@ -47,5 +44,4 @@ func main() {
fmt.Println("Invalid call. Use 'ssgo [-h | --help]' for available commands.")
}
}
-
}
\ No newline at end of file
diff --git a/test/Markdown File.md b/test/Markdown File.md
index 0ae482b..0a6c58f 100644
--- a/test/Markdown File.md
+++ b/test/Markdown File.md
@@ -7,7 +7,9 @@ This is a paragraph with `inline code`, isn't it `cool`??``
# Heading 1 with `code`
-Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc sit amet tincidunt nulla. Maecenas nec felis vel nulla faucibus ornare. Integer vitae ipsum fringilla, dapibus enim ac, imperdiet felis. Fusce placerat tortor vitae tortor laoreet vehicula. Donec dictum sit amet quam ut faucibus. Mauris vel tellus tristique, congue sem ut, condimentum erat. Aliquam erat volutpat. Interdum et malesuada fames ac ante ipsum primis in faucibus. Mauris volutpat erat lacus, egestas viverra enim mattis sed.
+Lorem **ipsum dolor** *sit* _amet_, __consectetur adipiscing__ elit. Nunc sit amet tincidunt nulla. Maecenas nec felis vel nulla faucibus ornare. Integer vitae ipsum fringilla, dapibus enim ac, imperdiet felis. Fusce placerat tortor vitae tortor laoreet vehicula. Donec dictum sit amet quam ut faucibus. Mauris vel tellus tristique, congue sem ut, condimentum erat. Aliquam erat volutpat. Interdum et malesuada fames ac ante ipsum primis in faucibus. Mauris volutpat erat lacus, egestas viverra enim mattis sed.
+
+Here's a link to Google: [Google](google.com)
---
Testing horizontal Rule
@@ -21,7 +23,7 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit.
---
-Vivamus ultrices erat in maximus pellentesque. Donec ut dui velit. Fusce convallis rutrum pharetra. Aliquam turpis leo, cursus sit amet tincidunt sed, sodales at odio. Phasellus sollicitudin turpis nisl, vitae elementum massa tincidunt volutpat. Donec porttitor venenatis libero, vitae bibendum nunc consectetur sit amet.
+__Vivamus ultrices erat in maximus pellentesque.__ _Donec ut dui velit._ **Fusce convallis rutrum pharetra.** *Aliquam turpis leo, cursus sit amet tincidunt sed, **sodales at odio.*** Phasellus sollicitudin turpis nisl, vitae elementum massa tincidunt volutpat. Donec porttitor venenatis libero, vitae bibendum nunc consectetur sit amet.
---
Praesent dignissim, eros pellentesque maximus facilisis, dui odio hendrerit purus, nec condimentum nibh risus et neque. Morbi bibendum eros nec pulvinar molestie. Mauris venenatis nec quam sit amet fringilla. Vivamus auctor dictum ante, finibus aliquam ante tincidunt ac. Quisque in pulvinar neque. Aliquam id est lacus. Ut est ipsum, volutpat nec nisl ac, ornare ultricies metus. Vivamus ornare, sem in molestie dapibus, metus urna consectetur diam, non posuere ante odio quis eros. Interdum et malesuada fames ac ante ipsum primis in faucibus.
diff --git a/utils/help.go b/utils/help.go
new file mode 100644
index 0000000..246701e
--- /dev/null
+++ b/utils/help.go
@@ -0,0 +1,23 @@
+package utils
+
+import "fmt"
+
+const (
+ InputHelpMessage string = "Path to a .txt / .md file OR a folder containing .txt / .md files to be turned into HTML"
+ OutputHelpMessage string = "Optional. Additionaly changes the output path of generated HTML"
+ HelpHelpMessage string = "Display detailed help message"
+ VersionHelpMessage string = "Display installed version of SSGo"
+ ConfigHelpMessage string = "Path to a .json file containing SSGo configuration options"
+)
+
+func PrintHelp() {
+ fmt.Println("Basic usage: ssgo [flag] [value]")
+ fmt.Println("Flags:")
+ fmt.Println("\t[-i | --input] [path] \t- " + InputHelpMessage)
+ fmt.Println("\t \t For paths with spaces, please enclose them into double quotation marks, e.g. \"some path\"")
+ fmt.Println("\t \t By default, places generated HTML into ./dist.")
+ fmt.Println("\t[-o | --output] [out path] \t- " + OutputHelpMessage)
+ fmt.Println("\n\t[-v | --version] \t- " + HelpHelpMessage)
+ fmt.Println("\t[-h | --help] \t- " + VersionHelpMessage)
+ fmt.Println("\t[-c | --config] \t- " + ConfigHelpMessage)
+}
\ No newline at end of file
diff --git a/utils/html-generation.go b/utils/html-generation.go
new file mode 100644
index 0000000..5ef1bc6
--- /dev/null
+++ b/utils/html-generation.go
@@ -0,0 +1,193 @@
+package utils
+
+import (
+ "bufio"
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+const (
+ beforeTitleHTML string = "\n\n\n\n\n"
+ afterTitleHTML string = "\n\n\n\n"
+ closingHTML string = "\n\n"
+)
+
+// Takes path to .txt file as an input, reads it, and creates name.html in output folder
+func GenerateHTML(input string, output string, name string) {
+
+ // Create new empty .html file
+ newFile, err := os.Create(output + "/" + name + ".html")
+ if err != nil {
+ log.Fatal(err)
+ }
+ if debug {
+ log.Println("File created at " + output + "/" + name + ".html")
+ }
+ defer newFile.Close()
+
+ txtFile, err := os.Open(input)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer txtFile.Close()
+
+ scanner := bufio.NewScanner(txtFile)
+
+ var titleExists bool = true
+ var title string = name
+
+ // Check title
+ scanner.Scan()
+ firstLine := scanner.Text()
+ if len(firstLine) != 0 {
+ for i := 0; i < 2; i++ {
+ if !scanner.Scan() {
+ break
+ }
+ if len(scanner.Text()) != 0 {
+ titleExists = false
+ }
+ }
+ if titleExists {
+ title = firstLine
+ }
+ }
+
+ // Writing HTML head to buffer
+ writer := bufio.NewWriter(newFile)
+ _, werr := writer.WriteString(beforeTitleHTML + title + afterTitleHTML)
+ if werr != nil {
+ log.Fatal("Error writing to buffer!")
+ }
+
+ // Write title or restart Scanner
+ if titleExists {
+ if debug {
+ fmt.Println("Title:", title)
+ }
+ firstLine = "
" + title + "
\n"
+ _, werr = writer.WriteString(firstLine)
+ if werr != nil {
+ log.Fatal("Error writing to buffer!")
+ }
+ } else {
+ if debug {
+ fmt.Println("No title found")
+ }
+ // If title does not exist, restart Scanner by opening another instance of the same file
+ // This way, it will read again from the first line
+ reTxtFile, err := os.Open(input)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer reTxtFile.Close()
+
+ scanner = bufio.NewScanner(reTxtFile)
+ }
+
+ paragraphOpen := false
+ paragraphDelimiterFound := false
+ firstNonMarkdownLineWritten := false
+
+ // Scan line by line and append to html buffer
+ for scanner.Scan() {
+ text := strings.TrimSpace(scanner.Text())
+ if text != "" {
+ // Write closing
tag if delimiter was found and opening
was previously written
+ if paragraphOpen && paragraphDelimiterFound {
+ _, werr = writer.WriteString("
\n")
+ if werr != nil {
+ log.Fatal("Error writing to new file!")
+ }
+ paragraphOpen = false
+ }
+
+ // Parse markdown file
+ markdownValid := false
+
+ if filepath.Ext(input) == ".md" {
+ if CheckHorizontalRule(text) {
+ // First, close existing paragraph
+ if paragraphOpen {
+ _, werr = writer.WriteString("\n")
+ if werr != nil {
+ log.Fatal("Error writing to new file!")
+ }
+ paragraphOpen = false
+ }
+ // Set delimeter to true, as this is exactly as blank line
+ paragraphDelimiterFound = true
+ _, werr = writer.WriteString("\n")
+ if werr != nil {
+ log.Fatal("Error writing to new file!")
+ }
+ markdownValid = true
+
+ } else {
+ // Turn inline Markdown features to HTML
+ text = GenerateInlineMarkdownHtml(text)
+ // If prefix is a heading or similar markdown feature
+ // that overwrites regular paragraph, change it
+ if prefix, validPrefix := CheckMarkdownPrefix(text); validPrefix {
+ // We don't want to put headers inside
tags
+ if paragraphOpen {
+ _, werr = writer.WriteString("
\n")
+ if werr != nil {
+ log.Fatal("Error writing to new file!")
+ }
+ paragraphOpen = false
+ // This is set to true so for next non markdown text a new
is written first
+ paragraphDelimiterFound = true
+ }
+ _, werr = writer.WriteString(GeneratePrefixMarkdownHtml(prefix, text))
+ if werr != nil {
+ log.Fatal("Error writing to new file!")
+ }
+ markdownValid = true
+ }
+ }
+ }
+
+ if !markdownValid {
+ // Write opening
tag is this is the first non markdown line
+ if !firstNonMarkdownLineWritten {
+ text = "
" + text
+ paragraphOpen = true
+ firstNonMarkdownLineWritten = true
+ }
+
+ // If last read line was a paragraph delimiter, write opening
first
+ if !paragraphOpen && paragraphDelimiterFound {
+ text = "
" + closingHTML)
+ if w2err != nil {
+ log.Fatal("Error writing to new file!")
+ }
+
+ // Writing buffer to the file
+ if debug {
+ log.Println("Writing buffer to file...")
+ }
+ writer.Flush()
+}
\ No newline at end of file
diff --git a/utils/input-processing.go b/utils/input-processing.go
new file mode 100644
index 0000000..12c0ed7
--- /dev/null
+++ b/utils/input-processing.go
@@ -0,0 +1,147 @@
+package utils
+
+import (
+ "encoding/json"
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+type File struct {
+ path string ""
+ name string ""
+}
+
+// Takes path to .json file, reads it, and calls ProcessInput using contained options
+func ProcessConfig(config string) {
+
+ // Read config .json file
+ configFile, err := os.ReadFile(config)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Assign json values to options struct
+ options := struct {
+ Input string `json:"input"`
+ Output string `json:"output"`
+ }{
+ Output: "dist",
+ }
+ json.Unmarshal(configFile, &options)
+
+ // Call ProcessInput using config file options
+ ProcessInput(options.Input, options.Output)
+}
+
+// Takes input path, validates single .txt file OR folder and checks all files in the folder
+func ProcessInput(input string, output string) {
+
+ if debug {
+ fmt.Println("Input: " + input)
+ }
+
+ // Reads stats about input path
+ fileInfo, err := os.Stat(input)
+ if os.IsNotExist(err) {
+ log.Fatal("Error! No such file or directory!")
+ }
+
+ // If input is directory
+ if fileInfo.IsDir() {
+ var files []File
+ fmt.Println("Looking for .txt / .md files in the directory...")
+
+ // Walks through all elements in the directory
+ filepath.Walk(input, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ log.Fatalf(err.Error())
+ }
+ // If file
+ if !info.IsDir() {
+ name, ext := getNameAndExt(info.Name())
+
+ // If .txt, add file to files slice
+ if _, exists := AcceptedInputFileTypes[ext]; exists {
+ fmt.Printf("\tFile: %s\n", path)
+ var f File = File{path: path, name: name}
+ files = append(files, f)
+ }
+ }
+ return nil
+ })
+
+ // If there is at least 1 .txt file
+ if len(files) != 0 {
+ // Prepare output directory
+ prepareOutput(output)
+ // Generate .html for each .txt file in the input directory
+ for i := 0; i < len(files); i++ {
+ GenerateHTML(files[i].path, output, files[i].name)
+ }
+ } else {
+ log.Fatal("No .txt / .md files in the directory!")
+ }
+
+ } else {
+ //If input is a file
+ name, ext := getNameAndExt(fileInfo.Name())
+
+ if _, exists := AcceptedInputFileTypes[ext]; !exists {
+ log.Fatal("Error! Input file is not a .txt or .md file")
+ }
+
+ // Prepare output directory
+ prepareOutput(output)
+
+ GenerateHTML(input, output, name)
+ }
+ fmt.Println("Done! Check '" + output + "' directory to see generated HTML.")
+}
+
+// Returns split name and extension of a filename
+func getNameAndExt(basename string) (string, string) {
+ var (
+ ext string = filepath.Ext(basename)
+ name string = strings.TrimSuffix(basename, ext)
+ )
+ return name, ext
+}
+
+// Checks output string and make/clear directory
+func prepareOutput(output string) {
+
+ output = strings.TrimSpace(output)
+ if output == "" {
+ log.Fatal("Error! Output directory string is empty!")
+ }
+
+ if debug {
+ fmt.Println("Output folder: " + output)
+ }
+
+ out, outerr := os.Stat(output)
+
+ if os.IsNotExist(outerr) {
+ // Output path doesn't exist, create a new directory
+ if err := os.Mkdir(output, os.ModePerm); err != nil {
+ log.Fatal(err)
+ }
+ } else if !out.IsDir() {
+ // If path exists but is not a directory
+ log.Fatal("Error! Output path exists, but is not a directory!")
+ } else if output == "dist" {
+ // Limiting to only dist folder in order to prevent unwwanted deletions
+ // If directory exists, delete it and re-create to get rid of the previous contents
+ fmt.Println("Removing previous compilations from the output folder...")
+ err := os.RemoveAll(output)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := os.Mkdir(output, os.ModePerm); err != nil {
+ log.Fatal(err)
+ }
+ }
+}
\ No newline at end of file
diff --git a/utils/markdown.go b/utils/markdown.go
new file mode 100644
index 0000000..1ea4b64
--- /dev/null
+++ b/utils/markdown.go
@@ -0,0 +1,68 @@
+package utils
+
+import (
+ "fmt"
+ "regexp"
+ "strings"
+)
+
+// Checks if line of text is markdown hotizontal rule.
+// Returns true if text is horizontal rule
+func CheckHorizontalRule(text string) bool {
+ acceptedPrefixes := [3]string{"---", "***", "___"}
+
+ for _, prefix := range acceptedPrefixes {
+ if strings.HasPrefix(text, prefix) {
+ currentChar := rune(prefix[0])
+ for _, char := range text {
+ if char != currentChar {
+ return false
+ }
+ }
+ return true
+ }
+ }
+
+ return false
+}
+
+// Checks if line of text has markdown prefixes, currently used for checking headings.
+// Returns true if any of the appropriate prefixes are found
+func CheckMarkdownPrefix(text string) (string, bool) {
+ acceptedPrefixes := [2]string{"# ", "## "}
+
+ for _, prefix := range acceptedPrefixes {
+ if strings.HasPrefix(text, prefix) {
+ return prefix, true
+ }
+ }
+
+ return "", false
+}
+
+// Replaces inline markdown features into HTML, currently used for `code blocks`.
+// Takes a line of text and returns that line processed into HTML (if found)
+func GenerateInlineMarkdownHtml(text string) string {
+ text = regexp.MustCompile(`\*\*(.*?)\*\*`).ReplaceAllString(text, `$1`)
+ text = regexp.MustCompile(`__(.*?)__`).ReplaceAllString(text, `$1`)
+ text = regexp.MustCompile(`_(.*?)_`).ReplaceAllString(text, `$1`)
+ text = regexp.MustCompile(`\*(.*?)\*`).ReplaceAllString(text, `$1`)
+ text = regexp.MustCompile("`(.*?)`").ReplaceAllString(text, `$1`)
+ text = regexp.MustCompile(`\[(.*?)\]\((.*?)\)`).ReplaceAllString(text, `$1`)
+ return text
+}
+
+// Replaces markdown prefixes into HTML tags.
+// Takes a prefix (#) & line of text and returns that line proccessed into HTML
+func GeneratePrefixMarkdownHtml(prefix string, text string) string {
+ prefixesHtmlFormatStrings := map[string]string{
+ "# ": "
%s
",
+ "## ": "
%s
",
+ }
+
+ if formatString, found := prefixesHtmlFormatStrings[prefix]; found {
+ return fmt.Sprintf(formatString, strings.Replace(text, prefix, "", 1)) + "\n"
+ }
+
+ return text
+}
diff --git a/utils/settings.go b/utils/settings.go
new file mode 100644
index 0000000..ee52a69
--- /dev/null
+++ b/utils/settings.go
@@ -0,0 +1,10 @@
+package utils
+
+const debug bool = false
+const DefaultOutput string = "dist"
+
+// Hashset for easier lookup
+var AcceptedInputFileTypes = map[string]bool{
+ ".txt": true,
+ ".md": true,
+}
\ No newline at end of file
diff --git a/utils/utils.go b/utils/utils.go
deleted file mode 100644
index df684c1..0000000
--- a/utils/utils.go
+++ /dev/null
@@ -1,429 +0,0 @@
-package utils
-
-import (
- "bufio"
- "encoding/json"
- "fmt"
- "log"
- "os"
- "path/filepath"
- "strings"
-)
-
-const debug bool = false
-
-type File struct {
- path string ""
- name string ""
-}
-
-const (
- beforeTitleHTML string = "\n\n\n\n\n"
- afterTitleHTML string = "\n\n\n\n"
- closingHTML string = "\n\n"
-)
-
-const (
- InputHelpMessage string = "Path to a .txt / .md file OR a folder containing .txt / .md files to be turned into HTML"
- OutputHelpMessage string = "Optional. Additionaly changes the output path of generated HTML"
- HelpHelpMessage string = "Display detailed help message"
- VersionHelpMessage string = "Display installed version of SSGo"
- ConfigHelpMessage string = "Path to a .json file containing SSGo configuration options"
-)
-
-func PrintHelp() {
-
- fmt.Println("Basic usage: ssgo [flag] [value]")
- fmt.Println("Flags:")
- fmt.Println("\t[-i | --input] [path] \t- " + InputHelpMessage)
- fmt.Println("\t \t For paths with spaces, please enclose them into double quotation marks, e.g. \"some path\"")
- fmt.Println("\t \t By default, places generated HTML into ./dist.")
- fmt.Println("\t[-o | --output] [out path] \t- " + OutputHelpMessage)
- fmt.Println("\n\t[-v | --version] \t- " + HelpHelpMessage)
- fmt.Println("\t[-h | --help] \t- " + VersionHelpMessage)
- fmt.Println("\t[-c | --config] \t- " + ConfigHelpMessage)
-}
-
-
-// Checks output string and make/clear directory
-func prepareOutput(output string) {
-
- output = strings.TrimSpace(output)
- if debug {
- fmt.Println("Output folder: " + output)
- }
-
- if output == "" {
- log.Fatal("Error! Output directory string is empty!")
- }
-
- out, outerr := os.Stat(output)
-
- if os.IsNotExist(outerr) {
- // Output path doesn't exist
- if err := os.Mkdir(output, os.ModePerm); err != nil {
- log.Fatal(err)
- }
- } else if !out.IsDir() {
- // If path exists but is not a directory
- log.Fatal("Error! Output path exists, but is not a directory!")
- } else if output == "dist" {
- // Limiting to only dist folder in order to prevent unwwanted deletions
- // If directory exists, delete it and re-create to get rid of the previous contents
- fmt.Println("Removing previous compilations from the output folder...")
- err := os.RemoveAll(output)
- if err != nil {
- log.Fatal(err)
- }
- if err := os.Mkdir(output, os.ModePerm); err != nil {
- log.Fatal(err)
- }
- }
-}
-
-
-// Takes input path, validates single .txt file OR folder and checks all files in the folder
-func ProcessInput(input string, output string) {
-
- if debug {
- fmt.Println("Input: " + input)
- }
-
- // Reads stats about input path
- fileInfo, err := os.Stat(input)
-
- if os.IsNotExist(err) {
- log.Fatal("Error! No such file or directory!")
- }
-
- // If input is directory
- if fileInfo.IsDir() {
-
- var files []File
-
- fmt.Println("Looking for .txt / .md files in the directory...")
-
- // Walks through all elements in the directory
- filepath.Walk(input, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- log.Fatalf(err.Error())
- }
- // If file
- if !info.IsDir() {
- var (
- basename string = info.Name()
- ext string = filepath.Ext(basename)
- name string = strings.TrimSuffix(basename, ext)
- )
-
- // If .txt, add file to files slice
- if ext == ".txt" || ext == ".md" {
- fmt.Printf("\tFile: %s\n", path)
- var f File = File{path: path, name: name}
- files = append(files, f)
- }
- }
- return nil
- })
-
- // If there is at least 1 .txt file
- if len(files) != 0 {
- // Prepare output directory
- prepareOutput(output)
- // Generate .html for each .txt file in the input directory
- for i := 0; i < len(files); i++ {
- GenerateHTML(files[i].path, output, files[i].name)
- }
- } else {
- log.Fatal("No .txt / .md files in the directory!")
- }
-
- } else {
- //If input is a file
- var (
- basename string = fileInfo.Name()
- ext string = filepath.Ext(basename)
- name string = strings.TrimSuffix(basename, ext)
- )
-
- if ext != ".txt" && ext != ".md" {
- log.Fatal("Error! Input file is not a .txt or .md file")
- }
-
- // Prepare output directory
- prepareOutput(output)
-
- GenerateHTML(input, output, name)
- }
- fmt.Println("Done! Check '" + output + "' directory to see generated HTML.")
-}
-
-// Takes path to .json file, reads it, and calls ProcessInput using contained options
-func ProcessConfig(config string) {
-
- // Read config .json file
- configFile, err := os.ReadFile(config)
- if err != nil {
- log.Fatal(err)
- }
-
- // Assign json values to options struct
- options := struct {
- Input string `json:"input"`
- Output string `json:"output"`
- }{
- Output: "dist",
- }
- json.Unmarshal(configFile, &options)
-
- // Call ProcessInput using config file options
- ProcessInput(options.Input, options.Output)
-}
-
-// Takes path to .txt file as an input, reads it, and creates name.html in output folder
-func GenerateHTML(input string, output string, name string) {
-
- // Create new empty .html file
- newFile, err := os.Create(output + "/" + name + ".html")
- if err != nil {
- log.Fatal(err)
- }
- if debug {
- log.Println("File created at " + output + "/" + name + ".html")
- }
- defer newFile.Close()
-
- txtFile, err := os.Open(input)
- if err != nil {
- log.Fatal(err)
- }
- defer txtFile.Close()
-
- scanner := bufio.NewScanner(txtFile)
-
- var titleExists bool = true
- var title string = name
-
- // Check title
- scanner.Scan()
- firstLine := scanner.Text()
- if len(firstLine) != 0 {
- for i := 0; i < 2; i++ {
- if !scanner.Scan() {
- break
- }
- if len(scanner.Text()) != 0 {
- titleExists = false
- }
- }
- if titleExists {
- title = firstLine
- }
- }
-
- // Writing HTML head to buffer
- writer := bufio.NewWriter(newFile)
- _, werr := writer.WriteString(beforeTitleHTML + title + afterTitleHTML)
- if werr != nil {
- log.Fatal("Error writing to buffer!")
- }
-
- // Write title or restart Scanner
- if titleExists {
- if debug {
- fmt.Println("Title:", title)
- }
- firstLine = "
" + title + "
\n"
- _, werr = writer.WriteString(firstLine)
- if werr != nil {
- log.Fatal("Error writing to buffer!")
- }
- } else {
- if debug {
- fmt.Println("No title found")
- }
- // If title does not exist, restart Scanner by opening another instance of the same file
- // This way, it will read again from the first line
- reTxtFile, err := os.Open(input)
- if err != nil {
- log.Fatal(err)
- }
- defer reTxtFile.Close()
-
- scanner = bufio.NewScanner(reTxtFile)
- }
-
- paragraphOpen := false
- paragraphDelimiterFound := false
- firstNonMarkdownLineWritten := false
-
- // Scan line by line and append to html buffer
- for scanner.Scan() {
- text := strings.TrimSpace(scanner.Text())
- if text != "" {
- // Write closing tag if delimiter was found and opening
was previously written
- if paragraphOpen && paragraphDelimiterFound {
- _, werr = writer.WriteString("
\n")
- if werr != nil {
- log.Fatal("Error writing to new file!")
- }
- paragraphOpen = false
- }
-
- // Parse markdown file
- markdownValid := false
-
- if filepath.Ext(input) == ".md" {
- if CheckHorizontalRule(text) {
- // First, close existing paragraph
- if paragraphOpen {
- _, werr = writer.WriteString("\n")
- if werr != nil {
- log.Fatal("Error writing to new file!")
- }
- paragraphOpen = false
- }
- // Set delimeter to true, as this is exactly as blank line
- paragraphDelimiterFound = true
- _, werr = writer.WriteString("\n")
- if werr != nil {
- log.Fatal("Error writing to new file!")
- }
- markdownValid = true
-
- } else {
- // Turn inline Markdown features to HTML
- text = GenerateInlineMarkdownHtml(text)
- // If prefix is a heading or similar markdown feature
- // that overwrites regular paragraph, change it
- if prefix, validPrefix := CheckMarkdownPrefix(text); validPrefix {
- // We don't want to put headers inside
tags
- if paragraphOpen {
- _, werr = writer.WriteString("
\n")
- if werr != nil {
- log.Fatal("Error writing to new file!")
- }
- paragraphOpen = false
- // This is set to true so for next non markdown text a new
is written first
- paragraphDelimiterFound = true
- }
- _, werr = writer.WriteString(GeneratePrefixMarkdownHtml(prefix, text))
- if werr != nil {
- log.Fatal("Error writing to new file!")
- }
- markdownValid = true
- }
- }
- }
-
- if !markdownValid {
- // Write opening
tag is this is the first non markdown line
- if !firstNonMarkdownLineWritten {
- text = "
" + text
- paragraphOpen = true
- firstNonMarkdownLineWritten = true
- }
-
- // If last read line was a paragraph delimiter, write opening
first
- if !paragraphOpen && paragraphDelimiterFound {
- text = "