From 8233414683d15b55fec1e1cc2e9227acc51ede72 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 8 Jan 2025 01:25:07 +1100 Subject: Version 1.00, initial commit --- LICENSE | 5 ++ README.md | 93 +++++++++++++++++++++ config | 17 ++++ ds-static | 230 +++++++++++++++++++++++++++++++++++++++++++++++++++ templates/core/entry | 5 ++ templates/core/index | 11 +++ templates/core/page | 12 +++ templates/footer | 1 + templates/header | 1 + 9 files changed, 375 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 config create mode 100755 ds-static create mode 100644 templates/core/entry create mode 100644 templates/core/index create mode 100644 templates/core/page create mode 100644 templates/footer create mode 100644 templates/header diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f12af71 --- /dev/null +++ b/LICENSE @@ -0,0 +1,5 @@ +Copyright (C) 2024 by Aleksei Eaves alekseijeaves@protonmail.com + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7ff4918 --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +# DS-Static + +DS-Static, the Dead Simple Static Website Generator. + + +## Who DS-Static is For + +I had the idea for DS-Static when trying to find a static generator for my website and ran into some problems. + +- I previously used Makesite, but I wasn't in the mood to read and change it's source again. +- I searched other static generators, but disliked their technical complexity, i.e using Node.JS +- Others nad much user complexity, such as Hugo. I wanted a generator that would be more efficient to learn and use, than it would be to hand-write my HTML, assuming I regularly use it. + +Feeling there was nothing that fit the bill, I decided to write my own. I have written two other static site generators in the past but they were too obtuse for others to pick up. I wanted other people to make use of this too. + +I devised a set of goals. + +- Technically uncomplicated, keep LOC low. +- Conceptually simple, quick to start using. +- No requirement to read or modify source code. + +Of these I kept the first two, the third is technically broken but the code modification of the user is minimal, i.e setting some variables and maybe changing the shebang line. + +If you are creating a personal or business website, a blog, a gallery, or some other sort of content-focused website, are familiar with HTML/CSS, and have similar requirements to me, you may find DS-Static useful for yourself. + + +## Installation + +1. If you do not have it already, install **Tcl**. The program was written for Tcl 8.6 and above, but will likely run fine on slightly older versions. +2. Check the shebang line of `main.tcl` points to your Tcl interpreter. On Linux systems this is usually `/bin/tclsh` (the default) but across systems it can differ. Run `whereis tclsh && whereis tcl8.6` to find where yours is located. +3. If you do not have it already, install **pandoc**. + + +## Usage of Program + +### Instructions for Use + +1. Read and modify `config`. + a. `d_source` is the source of content. + b. `d_output` is where generated files are put. + c. `replacement` is a dictionary for simple, global replacements. +2. Write templates in `templates/` directory. Templates are written using Tags; read the next section regarding their use. +3. Populate your `d_source` directory with content. + + +### Warnings and Notes + +- User errors are likely to present as Tcl errors. +- A loop in the template layout will cause a 'waiting' program. +- Files in the output directory will be overwritten. + + +## Tags + +DS-Static's fundamental concept is the tag, which are HTML comments that take on special meaning in this program. There are three types. + +**Templates** are HTML snippets contained in `templates/`. + +**Variables** are 'global' key-value pairs, specified before runtime in the `config` file. + +**Document Variables** are 'local' key-value pairs, specified within a document. + + +### Templates + +Template tags are of the form ``, i.e uppercase HTML comments by convention. + +Templates can be organized into folders for your convenience, and are then addressed as `` + +There are three templates used within the program you must not delete (though you can and should modify) in `templates/core/`. +- `index` is used for generating an index for many files. +- `entry` is used for an entry in the aforementioned index. +- `page` is the default template for a markdown page. + +A reserved template tag is `` which is not an actual file, but is internally used as the placeholder for where post contents may go internally. + +A warning for templates; the program does not check for recursive templates. It is the user's responsibility to write templates in a hierarchical manner. + + +### Variables + +Variable tags are of the form ``, i.e lowercase HTML comments by convention. + +In the file `config.tcl` the user will find a variable named *replacement*, which is a Tcl dictionary. There is documentation explaining how the dictionary works, but I hope it should be straightforward to see. + + +### Document Variables + +Document Variables are of the form ``. The case and whitespace is to the users preference. + +In either a Markdown or a HTML document, the user can include these for certain parameters they wish to configure, such as title, subtitle, author, or other document metadata. + +Two pieces of metadata are automatically generated; *date* which is the last modified date, and *filename* which is the relative address. diff --git a/config b/config new file mode 100644 index 0000000..64e425d --- /dev/null +++ b/config @@ -0,0 +1,17 @@ +## The d_source and d_output variable values are written between the braces. +## They respectively represent where content is sourced, and where the output +## will go. + +variable d_source {} +variable d_output {} + +## Replacement is a Tcl dictionary. Following 'dict create', you can +## enter your own parameters in the form +## {} {value} [...] +## in sequence. + +variable replacement \ + [dict create \ + {} {/style/main.css} \ + {} {/style/article.css} \ + ]; ## Do not delete this line! diff --git a/ds-static b/ds-static new file mode 100755 index 0000000..59b8efb --- /dev/null +++ b/ds-static @@ -0,0 +1,230 @@ +#!/bin/tclsh + +#################### +#### Initialization + + +### pushd + popd + +variable directory_stack [list] + +proc pushd {arg} { + lappend ::directory_stack [pwd] + cd $arg +} + +proc popd {} { + cd [lindex $::directory_stack end] + set ::directory_stack [lrange $::directory_stack 0 end-1] +} + + +### Config Verification + +source config + +# If the directories haven't been configured, halt and tell user. +if ![file exists $::d_source] { + puts "d_source is not configured." + exit +} +if ![file exists $::d_output] { + puts "d_output is not configured." + exit +} + + +### Normalize directories. + +set ::d_source [file normalize $::d_source] +set ::d_output [file normalize $::d_output] + + +### Load templates + +variable templates [dict create] + +foreach template [exec find templates | grep -v ~$] { + if [file isfile $template] { + set fd [open $template] + dict set ::templates \ + "" [read $fd] + close $fd + } +} + + +#################### +#### Main Functions + + +### Extract all key-value variables from a document, of the form +proc document-variables {filename} { + + ## Retrieve text. + + set fd [open $filename] + variable text [gets $fd] + close $fd + + ## The generated variables. + + variable variables [dict create] + + dict append variables \ + [string range \ + [string map ".md .html" [file normalize $filename]] \ + [string length $::d_source] end] + + dict append variables \ + [clock format [file mtime $filename] -format "%d %b %Y"] + + ## The document variables. + + variable matches \ + [regexp -all -inline {} $text] + + # For each match, skipping the extra match information, + for {set i 0} {$i < [llength $matches]} {incr i 3} { + set match [lindex $matches $i] + + # Get position of ':' + regexp -indices {:} $match offset + set offset [lindex $offset 0] + + # Extract key-value into dictionary + dict append variables \ + "" \ + [string trim [string range $match [expr $offset+1] end-3]] + + } + + return $variables +} + + + +## This function takes three arguments. base-template and content is +## clear enough, but variables are the page specific variables, in the +## form of a dictionary. +## Puts the content into the base-tmplate, and then replaces all tags +## with their templates, variables, etc. +proc process-tags {base_template content variables} { + + ## Get basic template and content. + + set content [string map \ + [list $content] \ + [dict get $::templates $base_template]] + + ## Process templates. + + variable content_old {} + while {![string equal $content $content_old]} { + set content_old $content + set content [string map $::templates $content] + } + + ## Replace variables. + + set content [string map $variables [string map $::replacement $content]] + + return $content +} + + + +## Process the document and output the result. +proc process-doc {source_file} { + + set source_file [file normalize $source_file] + + ## Grab the document variables + set document_vars [document-variables $source_file] + + ## Open file contents + variable content {} + if [string equal [file extension $source_file] .html] { + set content [exec cat $source_file] + } elseif [string equal [file extension $source_file] .md] { + set content [exec pandoc -f markdown -t html $source_file] + } + + ## Process and return + return [process-tags $content $document_vars] + +} + + + + +## Generate an index of the current directory, assuming .md files. +proc generate-index {} { + + variable index_content {} + + foreach item [exec ls -t | grep -v ~$] { + if [file isfile $item] { + append index_content \ + [string map \ + [document-variables $item] \ + [dict get $::templates ]] + } + } + + + ## Process and write to file. + return [process-tags $index_content {}] +} + + +## The primary loop of the program. +proc main {} { + + ## For everything, except backups and index.html + foreach item [exec ls -t | grep -v ~$ | grep -v index.html] { + ## Enter directories and generate content. + if [file isdirectory $item] { + # Execute mainloop inside. + file mkdir [string map "$::d_source $::d_output" [file normalize $item]] + pushd $item + main + popd + } else { + set output_file [string map "$::d_source $::d_output .md .html" [file normalize $item]] + puts -nonewline "Generating $output_file..." + set fd [open $output_file w] + puts $fd [process-doc $item] + close $fd + puts " done." + } + } + + set output_file [string map "$::d_source $::d_output" "[pwd]/index.html"] + puts -nonewline "Generating $output_file..." + set fd [open $output_file w] + ## If index.html exists + if [file exists "index.html"] { + puts $fd [process-doc index.html] + } elseif [file exists "index.md"] { + puts $fd [process-doc index.md] + } else { + puts $fd [generate-index] + } + close $fd + puts " done." + +} + + + +#################### +#### Execute + +cd $d_source + +## Execute while timing. +set executed_time \ + [time {main} 1] + +puts "Finished in [expr [lindex $executed_time 0] / 1000000.0]s" diff --git a/templates/core/entry b/templates/core/entry new file mode 100644 index 0000000..ae3af04 --- /dev/null +++ b/templates/core/entry @@ -0,0 +1,5 @@ +
+
+ +
+
diff --git a/templates/core/index b/templates/core/index new file mode 100644 index 0000000..9d53d86 --- /dev/null +++ b/templates/core/index @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/templates/core/page b/templates/core/page new file mode 100644 index 0000000..10937cc --- /dev/null +++ b/templates/core/page @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/templates/footer b/templates/footer new file mode 100644 index 0000000..4a8bf4d --- /dev/null +++ b/templates/footer @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/header b/templates/header new file mode 100644 index 0000000..68adf2e --- /dev/null +++ b/templates/header @@ -0,0 +1 @@ +
\ No newline at end of file -- cgit v1.2.3