12 votes

Your blog probably doesn’t need a static site generator

21 comments

  1. [7]
    ubergeek
    Link
    Dear gods, that it an awful amount of manual work for something that is stupidly simple to automate. I mean, don't get me wrong, it'd be nice to get back to minimalism, but ya should have some...

    When I want to post something, I first write it in a text file, copy my last blog post’s HTML file, paste in my new article, make some slight adjustments, update my list of posts, add it to my RSS file, and that’s basically it.

    Dear gods, that it an awful amount of manual work for something that is stupidly simple to automate.

    I mean, don't get me wrong, it'd be nice to get back to minimalism, but ya should have some formatting in the document, and such. I mean my cms system could probably be scaled back a little, but even it just keeps site layout separate from content, so I can swap styling and page layout, without touching all of the content (Which is just markdown).

    20 votes
    1. [2]
      mrbig
      Link Parent
      You could automate all that using Emacs or another scriptable editor/platform. But since static site generators exist, it's probably not worth the effort.

      You could automate all that using Emacs or another scriptable editor/platform.

      But since static site generators exist, it's probably not worth the effort.

      4 votes
      1. ubergeek
        Link Parent
        Probably. And not with much difficulty, either.

        Probably. And not with much difficulty, either.

    2. [4]
      mozz
      Link Parent
      What do you need that couldn't be accomplished by maintaining a simple CSS file?

      but even it just keeps site layout separate from content, so I can swap styling and page layout, without touching all of the content

      What do you need that couldn't be accomplished by maintaining a simple CSS file?

      3 votes
      1. [3]
        ubergeek
        Link Parent
        Not having to write HTML code for pages. The site layout is generally managed by CSS. The rendering just takes markdown and turns it into html for me. You can see it in action at https...

        Not having to write HTML code for pages.

        The site layout is generally managed by CSS. The rendering just takes markdown and turns it into html for me.

        You can see it in action at https ://thunix.net/~ubergeek

        The code is here: https ://tildegit.org/ubergeek/wiki.php

        It's really not much, but it works well for what I need it to do: Allow me to write content, and not worry much about the rest.

        3 votes
        1. [2]
          ThatFanficGuy
          Link Parent
          You could still maintain a simple CSS file and have your Markdown convert to HTML when time comes, FYI. They needn't be the same process. I might be misunderstanding the problem here.

          You could still maintain a simple CSS file and have your Markdown convert to HTML when time comes, FYI. They needn't be the same process.

          I might be misunderstanding the problem here.

          1 vote
          1. ubergeek
            Link Parent
            I think so... The "cms" I used pretty much works exactly as you described here.

            I think so... The "cms" I used pretty much works exactly as you described here.

  2. cptcobalt
    Link
    Politely, I don't think user's site exactly has the legacy I'd expect it to have. Yeah, HTML-only surely feels liberating. But, considering that all the content on the site is under a month old, I...

    Politely, I don't think user's site exactly has the legacy I'd expect it to have.

    Yeah, HTML-only surely feels liberating. But, considering that all the content on the site is under a month old, I can say with confidence that they haven't yet found the major issues with their workflow—stuff you only learn from months of living on your workflow.

    For instance, consider the following: How many of you traveled to other pages on their site? I'm pretty confident that not many did. There are no links on the page, not even to go up a level or go back home. So you had to manually edit the URL in your browser.

    Here's where a static site generator or CMS matters. When they realize that it's a terrible experience to trundle along their site, it's only just updating one template file to add even some sort of navigation/structure on the site. Continuing with an HTML-only trajectory will put them in a situation they'll have to update ~10 pages now—more, as the site grows.

    Let's see where their workflow is in a year, and how often the content is updated and maintained. If there are hundreds of pages of content, well, maybe they've got a point. But right now the site is too new for there to give any significance to their perspective.

    15 votes
  3. [3]
    minimaltyp0s
    Link
    An odd conclusion when the main thrust of the article is against using the esoteric incantations of other static site generators.

    You may find it unnecessarily manual, but I’ve come to realize that if I’m not willing to perform these few steps, then what I have to post may not be worthy in the first place

    An odd conclusion when the main thrust of the article is against using the esoteric incantations of other static site generators.

    13 votes
    1. [2]
      anahata
      Link Parent
      Right? The author claims to want to focus on writing without distraction, and then burdens themselves with the distraction of having to manage HTML. It's clear that the author prefers a different...

      Right? The author claims to want to focus on writing without distraction, and then burdens themselves with the distraction of having to manage HTML. It's clear that the author prefers a different kind and level of technological distraction than static site generators. I have deeper objections to this piece that I'll be putting in a top-level comment, but I wanted to highlight this particular bit.

      7 votes
      1. ThatFanficGuy
        Link Parent
        I'd rather write all of my web things manually. I'd also rather not stick my preferences into someone else's face as if it's providence from God. The only benefit derived from sharing tastes is...

        I'd rather write all of my web things manually.

        I'd also rather not stick my preferences into someone else's face as if it's providence from God.

        The only benefit derived from sharing tastes is opening the other person up to possibilities. Acting as if those possiblities are inherently better by default is bad faith.

        I may be a nose-to-the-grindwheel motherfucker, but that doesn't mean others want to be.

        3 votes
  4. whbboyd
    Link
    I wrote my site in static HTML for a long time. It sucked. Generation is way better. With hand-edited documents, you will forget to update something, pages will get out of sync, maintaining...

    I wrote my site in static HTML for a long time.

    It sucked. Generation is way better. With hand-edited documents, you will forget to update something, pages will get out of sync, maintaining something like a tag list becomes inconceivably laborious.

    Even with my… extremely low output, using a static generator has saved me loads of time and made my site more consistent. If it's the messing around with HTML you miss, write your own template—I found it very straightforward in Pelican.

    10 votes
  5. [3]
    anahata
    Link
    Another tech writer, another "you should do things the way I do them because it's objectively better" post. I have very little patience for articles like this. They are scant on fact-based...

    Another tech writer, another "you should do things the way I do them because it's objectively better" post. I have very little patience for articles like this. They are scant on fact-based arguments and rely heavily on opinion presented as facts, often with contradictions.

    The big contradiction for me here is that the author doesn't want the distraction of static site generators but does want the distraction of having to wrangle HTML and CSS manually. We each have a different level and kind of distraction or effort that we're comfortable investing in a task before we say "that's too much, man!". For me, touching anything to do with the frontend is too much. I hate working with HTML, CSS, JS, any of it. But I'm completely happy to write some code in whatever language I'm happy with at the time (and in the past have used Makefiles because that's exactly what they were made for).

    I will also point out that the styling on the author's site is rather minimal, which is rather different than the theming used by static site generators. This is an orthogonal choice to the plain HTML approach. I think that this is actually what the author wanted, a minimal design rather than just static HTML. The article mentions struggling with theming, and the result is a minimally-themed blog. And this is fine, but it should be stated outright that that's what the author wanted. It's absolutely possible to do that with a static site generator, but it needs more work, so I think this is where the frustration came from.

    8 votes
    1. [2]
      mozz
      (edited )
      Link Parent
      I also hate the type of article that you're describing, but I came out of this with the complete opposite feeling. I can't pick out a single argument from this article that's framed as an...

      Another tech writer, another "you should do things the way I do them because it's objectively better" post. I have very little patience for articles like this. They are scant on fact-based arguments and rely heavily on opinion presented as facts, often with contradictions.

      I also hate the type of article that you're describing, but I came out of this with the complete opposite feeling. I can't pick out a single argument from this article that's framed as an objective truth. The author is simply describing their personal experience with these tools and offering up a solution for others who have had similar problems.

      9 votes
      1. anahata
        Link Parent
        I think my reaction may be colored by the post title, which definitely does read that way to me. That pushed me to read the article in a different light. Upon rereading, I don't see arguments...

        I think my reaction may be colored by the post title, which definitely does read that way to me. That pushed me to read the article in a different light. Upon rereading, I don't see arguments addressed directly at the audience, but that title... woof. I realize it was written that way to grab attention, so I think, ultimately, my issue is with clickbaity headlines. Who knew? :)

        5 votes
  6. balooga
    Link
    The author strikes me as the sort of person who spends more time tweaking his mod list in Skyrim than actually playing the game. By which I mean no offense, that's a perfectly fine way to get...

    The author strikes me as the sort of person who spends more time tweaking his mod list in Skyrim than actually playing the game. By which I mean no offense, that's a perfectly fine way to get enjoyment from something. But it seems like he's blaming tool configuration for distracting him from blogging, rather than using the tools to blog more efficiently. I've spent a lot of time configuring CMS and static site generators, I can relate.

    There is an art to implementing any software plan expediently and knowing when to call it "done." LIke @cptcobalt pointed out, publishing two "blog posts" does not indicate a successful workflow. If it were my site I'd likely be burned out by the tenth. Writing the posts themselves shouldn't be too painful, but manually writing the links to them and maintaining the RSS feed will be.

    Aside: It's probably worth pointing out that an article document with zero hyperlinks is user-hostile. Even by the web 1.0 standards that inspire "brutalist web design," that's poor UX. The RSS feed is also non-discoverable. A site doesn't need bloated gimmicks, but there are basic accommodations we should all try to make as a baseline when publishing for the web.

    7 votes
  7. cardigan
    Link
    It's interesting that the comments here so far have been so focused on the author's methodology. It goes to show how prevalent the idea of bikeshedding as an end in itself really is. The point...

    It's interesting that the comments here so far have been so focused on the author's methodology. It goes to show how prevalent the idea of bikeshedding as an end in itself really is. The point isn't that editing HTML is really any easier than doing it automatically, but rather that this is just the way they've found that lets them do the task at hand instead of being too concerned about how they're going to do it.

    4 votes
  8. reese
    Link
    I mean, the author has a good point that we shouldn't ignore. Many static site generation tools are ridiculous, but the conclusion to abandon them altogether on that fact alone is hasty. The...

    The story always ended the same way — knee-deep in Jekyll/Hugo/Hexo/etc’s documentation, trying to grok the internals and what the hell was going on underneath the hood. I was editing themes, making my own themes, and doing everything unrelated to actually writing.

    I mean, the author has a good point that we shouldn't ignore.

    Many static site generation tools are ridiculous, but the conclusion to abandon them altogether on that fact alone is hasty. The problem with static site generation is in finding (or building) the tool that works for you. As the author points out, you also do not want to spend so much time building or tweaking themes that your blogging suffers. I rewrote my blog a few times before honing in on 11ty, which, for me, strikes the perfect balance between ease of use and customization. I don't think there is a formal notion of themes in 11ty—you just fork the project/site with the template engine and features you prefer.

    3 votes
  9. seizethegoddamngap
    Link
    Ha! By sheer coincidence, I set up my first static site generator blog last night with Hugo and NGINX. Still not working how it should, but I'll figure it out. For me, an SSG/CMS is probably going...

    Ha! By sheer coincidence, I set up my first static site generator blog last night with Hugo and NGINX. Still not working how it should, but I'll figure it out.

    For me, an SSG/CMS is probably going to be the way to go for now. I'm a Network tech that barely knows Bash/RegEx, and still have Python to learn.

    2 votes
  10. DaveJarvis
    Link
    Here's a script that statically generates my blog from Markdown files. There are a few handy features: Minification. Minify CSS and HTML, no JavaScript (yet). Templates. Site templates (header,...

    Here's a script that statically generates my blog from Markdown files. There are a few handy features:

    • Minification. Minify CSS and HTML, no JavaScript (yet).
    • Templates. Site templates (header, footer, etc.) using FMPP.
    • Two-pass build. Minify fonts by removing unused glyphs using pyftsubset.
    • RSS Feed. Bare bones XML, nothing fancy.

    The script itself could be simplified significantly by reusing the build script and other techniques discussed at length on the blog. (The shoemaker always wears the worst shoes?)

    #!/bin/bash
    
    # Static website build script
    
    # Directory where script resides
    readonly SCRIPT_SRC="$(dirname "${BASH_SOURCE[0]}")"
    readonly SCRIPT_DIR="$(cd "$SCRIPT_SRC" >/dev/null 2>&1 && pwd)"
    
    # Used to display usage
    readonly SCRIPT_NAME=$(basename $0)
    
    TPL_DIR="$SCRIPT_DIR/template"
    INC_DIR="$TPL_DIR/includes"
    
    # -----------------------------------------------------------------------------
    # Script starts here
    # -----------------------------------------------------------------------------
    main() {
      parse_commandline "$@"
    
      if [ -n "$ARG_HELP" ]; then
        show_usage
        exit 3
      fi
    
      check_requirements
    
      find $ARG_INPUT_DIR -type f -name "*.md" | while read file; do
        build_file "$file"
      done
    
      if [ -n "$ARG_RSS" ]; then
        build_blog_feed
      fi
    
      if [ -n "$ARG_NAV" ]; then
        build_blog_nav
        build_file "blog/index.md"
      fi
    
      if [ -n "$ARG_COMMIT_MESSAGE" ]; then
        commit
      fi
    }
    
    # -----------------------------------------------------------------------------
    # Build a static web page.
    #
    # $1 - Full path to the file to convert from 
    # -----------------------------------------------------------------------------
    build_file() {
      DIR_MARKDOWN=$(dirname $1)
      FILE_MARKDOWN=$(basename $1)
      FILE_HTML=$(basename $1 .md).html
      log "Enter $DIR_MARKDOWN"
    
      pushd $DIR_MARKDOWN > /dev/null
    
      # Extract only those glyphs shown on the web page. This is accomplished
      # by first generating the full web page without CSS, then by using Lynx
      # to render the template-generated web page as text only.
    	if [ -n "$ARG_FONT" ]; then
        > $INC_DIR/css/main.min.css
        convert_markdown "$FILE_MARKDOWN"
        apply_templates "$FILE_HTML" "$DIR_MARKDOWN"
    
    		minify_fonts "$FILE_HTML"
    	fi
    
      minify_artefacts
      convert_markdown "$FILE_MARKDOWN"
      apply_templates "$FILE_HTML" "$DIR_MARKDOWN"
    
      minify_html "$FILE_HTML"
    
      popd > /dev/null
    }
    
    # -----------------------------------------------------------------------------
    # Build the blog navigation file.
    # -----------------------------------------------------------------------------
    build_blog_nav() {
      log "Build blog navigation links"
    
      local -r FILE_BLOG="blog/index.md"
    
      printf "| Post | Date |\n" > "${FILE_BLOG}"
      printf "| ---- + ---- |\n" >> "${FILE_BLOG}"
    
      find blog -mindepth 2 -type f -name "*.html" | sort -n | while read file; do
        # Make the blog directory path relative to "/blog"
        local blog_dir=$(dirname "${file}" | cut -d "/" -f1 --complement)
        local blog_item_title="$(css_select "h1" "$file")"
        local blog_item_abstract="$(css_select "div.abstract > p" "$file")"
        local blog_item_byline="$(css_select "div.byline > p" "$file")"
    
        blog_item_byline=$(echo "${blog_item_byline}" | \
          sed -e "s/.*, \(.*\) <a.*/\1/g")
    
        printf "| [%s](%s) | %s |\n" \
          "${blog_item_title}" "${blog_dir}" "${blog_item_byline}" >> "${FILE_BLOG}"
      done
    }
    
    # -----------------------------------------------------------------------------
    # Build the blog RSS feed.
    # -----------------------------------------------------------------------------
    build_blog_feed() {
      log "Build blog feed"
    
      pushd $SCRIPT_DIR >/dev/null 2>&1
    
      local rss_title="My Blog"
      local rss_description="Blog Description"
      local rss_language="en-ca"
      local rss_build_date="$(date -R)"
      local rss_domain="https://domain.com"
      local rss_ttl=4320
    
      local blog_rss_file=news/blog.rss
    
    cat > $blog_rss_file <<EOT
    <?xml version="1.0" encoding="utf-8"?>
    <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
      <channel>
        <atom:link href="$rss_domain/path/$blog_rss_file" rel="self" type="application/rss+xml" />
        <title>$rss_title</title>
        <link>$rss_domain</link>
        <description>$rss_description</description>
        <language>$rss_language</language>
        <lastBuildDate>$rss_build_date</lastBuildDate>
    EOT
    
      find blog -type f -name "*.html" | sort -n | while read file; do
        if [[ -n "${ARG_EXCLUDES}" && "${file}" =~ "${ARG_EXCLUDES}" ]]; then
          log "Excluding $file"
          continue
        fi
    
        local rss_item_link="$(dirname $rss_domain/$file)"
        local rss_item_guid="$rss_item_link"
        local rss_item_title="$(css_select "h1" "$file")"
        local rss_item_abstract="$(css_select "div.abstract > p" "$file")"
        local rss_item_published="$(date -R -r "$file")"
    
        log "Blog title: '$rss_item_title'"
    
    cat >> $blog_rss_file <<EOT
        <item>
          <title>$rss_item_title</title>
          <description>$rss_item_abstract</description>
          <link>$rss_item_link</link>
          <guid>$rss_item_guid</guid>
          <pubDate>$rss_item_published</pubDate>
        </item>
    EOT
      done
    
    cat >> $blog_rss_file <<EOT
      </channel>
    </rss>
    EOT
    
      popd >/dev/null 2>&1
    }
    
    # -----------------------------------------------------------------------------
    # Extracts a CSS element from a file.
    #
    # $1 - The CSS element to find
    # $2 - The HTML file to select from
    # -----------------------------------------------------------------------------
    css_select() {
      echo "$(hxnormalize -i 0 -l 2048 -x "$2" | hxselect -c "$1")"
    }
    
    # -----------------------------------------------------------------------------
    # Uses pandoc to convert a Markdown file to HTML.
    #
    # $1 - The markdown file to convert to the HTML body.
    # -----------------------------------------------------------------------------
    convert_markdown() {
      log "Convert $1 to .../html/body.html"
    
      local -r FILE_HTML="$INC_DIR/html/body.html"
      local -r FILE_TOC="$INC_DIR/html/toc.html"
      local -r XPATH="//html/body/nav/ul/*/ul"
    
      if [[ "${PWD}" == *blog* ]]; then
        echo "<nav class='toc'>" > "${FILE_TOC}"
        pandoc -s --toc "$1" 2> /dev/null | \
          xmllint --html --xpath "${XPATH}" - 2> /dev/null >> "${FILE_TOC}"
        echo "</nav" >> "${FILE_TOC}"
      fi
    
      pandoc "$1" \
        -f markdown-tex_math_dollars-raw_tex-auto_identifiers+auto_identifiers \
        -o "$FILE_HTML"
    }
    
    # -----------------------------------------------------------------------------
    # Uses Closure to merge and minify all CSS files.
    # -----------------------------------------------------------------------------
    minify_artefacts() {
      log "Minify CSS"
      closure.sh --allow-unrecognized-properties \
        $SCRIPT_DIR/css/*.css > "$INC_DIR/css/main.min.css"
    }
    
    # -----------------------------------------------------------------------------
    # Uses FMPP to inject a web page body into a standard template.
    #
    # $1 - The web page template.
    # -----------------------------------------------------------------------------
    apply_templates() {
      log "Generate $1 using files from template directory"
    
      # Extract the full path to the resource being transformed into HTML.
      RESOURCE_DIR=${2#./}
    
      fmpp --interpolation-syntax squareBracket -S "$TPL_DIR" \
        -Q \
        -D "resource:$RESOURCE_DIR" \
        -O . "$1"
    }
    
    # -----------------------------------------------------------------------------
    # Uses HTML Tidy to remove all the whitespace from the HTML.
    #
    # $1 - The web page to minify.
    # -----------------------------------------------------------------------------
    minify_html() {
      log "Minify ${1}"
      tidy -m -q \
        --wrap 0 \
        --preserve-entities yes \
        --tidy-mark no \
        --vertical-space auto \
        --doctype html5 \
        "$1"
    }
    
    # -----------------------------------------------------------------------------
    # Uses numerous tools to remove glyphs from font files. Repackages the
    # slimmed font file as WOFF.
    # -----------------------------------------------------------------------------
    minify_fonts() {
      log "Minify fonts based on text from ${1}"
      # Create a string of all unique characters used in the HTML files
      CHARSET=$(lynx -dump -nolist "$1" \
        | sed 's/./&\n/g' \
        | sort -u \
        | uniq \
        | tr -d '\n')
    
      log "Glyphs: $CHARSET"
    
      # Make parsing filenames easier by jumping into the fonts directory
      pushd fonts > /dev/null
    
      # Create subsets and generate WOFFs from TTFs
      for i in *; do
        log "Remove glyphs from ${i}"
        FILE_FONT=ss_$i
        TEMPDIR=/tmp
        pyftsubset $i --text="$CHARSET" --output-file="$TEMPDIR/$FILE_FONT"
        sfnt2woff $TEMPDIR/$FILE_FONT
    
        FILE_WOFF="${FILE_FONT%.*}".woff
        FILE_WOFF_BASE64=$TEMPDIR/$FILE_WOFF.b64
    
        # Convert WOFFs to base64 for inlining, without line wrapping
        base64 -w 0 $TEMPDIR/$FILE_WOFF > $FILE_WOFF_BASE64
    
        # Extract all the font attributes (the name/family will not include weight)
        FONT_NAME=${i%.*}
        FONT_FAMILY=${i%-*}
        FONT_WEIGHT=${i#*-}
        FONT_WEIGHT=${FONT_WEIGHT%.*}
    
        CSS_FONT_WEIGHT=400
        CSS_FONT_STYLE=normal
    
        log "Parse font family ${FONT_NAME}"
        case "$FONT_WEIGHT" in
          ExtraLight|UltraLight)
          CSS_FONT_WEIGHT=100
          ;;
          Light|Thin)
          CSS_FONT_WEIGHT=200
          ;;
          Book|Demi)
          CSS_FONT_WEIGHT=300
          ;;
          Medium)
          CSS_FONT_WEIGHT=500
          ;;
          SemiBold|DemiBold)
          CSS_FONT_WEIGHT=600
          ;;
          Bold)
          CSS_FONT_WEIGHT=700
          ;;
          Black|ExtraBold|Heavy)
          CSS_FONT_WEIGHT=800
          ;;
          ExtraBlack|Fat|Poster|UltraBlack)
          CSS_FONT_WEIGHT=900
          ;;
          Italic)
          CSS_FONT_STYLE=italic;
          ;;
          Oblique)
          CSS_FONT_STYLE=oblique;
          ;;
          LightItalic|ThinItalic)
          CSS_FONT_WEIGHT=200
          CSS_FONT_STYLE=italic;
          ;;
          MediumItalic)
          CSS_FONT_WEIGHT=500
          CSS_FONT_STYLE=italic;
          ;;
          BoldItalic)
          CSS_FONT_WEIGHT=500
          CSS_FONT_STYLE=italic;
          ;;
          BoldOblique)
          CSS_FONT_WEIGHT=500
          CSS_FONT_STYLE=oblique;
          ;;
        esac
    
        log "Font weight: ${CSS_FONT_WEIGHT}"
        log "Font style: ${CSS_FONT_STYLE}"
    
      # Create font-faces for each font
        cat > ../css/font-$FONT_NAME.css << EOF
    @font-face {
      font-family: '${FONT_FAMILY}';
      src: url(data:font/woff;charset=utf-8;base64,$(cat $FILE_WOFF_BASE64)) format('woff');
      font-weight: ${CSS_FONT_WEIGHT};
      font-style: ${CSS_FONT_STYLE};
      font-display: block;
    }
    EOF
    
      done
    
      popd > /dev/null
    }
    
    # -----------------------------------------------------------------------------
    # Commits all changes to the repository.
    # -----------------------------------------------------------------------------
    commit() {
      log "Commit: '$ARG_COMMIT_MESSAGE'"
      git commit -a -m "$ARG_COMMIT_MESSAGE"
      git push origin master
    }
    
    # -----------------------------------------------------------------------------
    # Checks for required utilities and exits if not found.
    # -----------------------------------------------------------------------------
    check_requirements() {
      required pyftsubset "https://github.com/fonttools/fonttools"
      required base64 "https://linux.die.net/man/1/base64"
      required tidy "https://github.com/htacg/tidy-html5"
      required fmpp "http://fmpp.sourceforge.net"
      required pandoc "http://pandoc.org"
      required closure.sh "https://developers.google.com/closure"
      required sfnt2woff "https://github.com/kseo/sfnt2woff"
      required git "https://git-scm.com"
      required xmllint "http://xmlsoft.org/xmllint.html"
    }
    
    # -----------------------------------------------------------------------------
    # Checks for a required utility and exits if not found.
    #
    # $1 - Command to execute.
    # $2 - Where to find the command.
    # -----------------------------------------------------------------------------
    required() {
      if ! command -v $1 > /dev/null 2>&1; then
        warning "Install $1 from $2"
        exit 1
      fi
    }
    
    # -----------------------------------------------------------------------------
    # Prints coloured text to standard output.
    # -----------------------------------------------------------------------------
    coloured_text() {
      printf "%b$1%b\n" "$2" "$COLOUR_OFF"
    }
    
    # -----------------------------------------------------------------------------
    # Prints a warning message to standard output.
    # -----------------------------------------------------------------------------
    warning() {
      coloured_text "$1" "$COLOUR_WARNING"
    }
    
    # -----------------------------------------------------------------------------
    # Writes a message to standard output.
    # -----------------------------------------------------------------------------
    log() {
      if [ -n "$ARG_VERBOSE" ]; then
        printf "[$(date +%H:%I:%S.%4N)] "
        coloured_text "$1" "$COLOUR_LOGGING"
      fi
    }
    
    # -----------------------------------------------------------------------------
    # Sets the global command line argument values.
    # -----------------------------------------------------------------------------
    parse_commandline() {
      while [ "$#" -gt "0" ]; do
        local consume=1
    
        case "$1" in
          -c|--commit)
            ARG_COMMIT_MESSAGE="$2"
            consume=2
          ;;
          -V|--verbose)
            ARG_VERBOSE="true"
          ;;
          -h|-\?|--help)
            ARG_HELP="true"
          ;;
          -f|--font)
            ARG_FONT="true"
          ;;
          -i|--input)
            ARG_INPUT_DIR="$2"
            consume=2
          ;;
          -n|--nav)
            ARG_NAV="true"
          ;;
          -r|--rss)
            ARG_RSS="true"
          ;;
          -x|--exclude)
            ARG_EXCLUDES="$2"
            consume=2
          ;;
          *)
            # Skip argument
          ;;
        esac
    
        shift $consume
      done
    }
    
    # -----------------------------------------------------------------------------
    # Shows accepted command line parameters.
    # -----------------------------------------------------------------------------
    show_usage() {
      printf "Usage: $SCRIPT_NAME\n" >&2
      printf "  -c, --commit Commit changes to the repository\n" >&2
      printf "  -f, --font Regenerate minified fonts\n" >&2
      printf "  -h, --help Show this help message\n" >&2
      printf "  -i, --input Specifies top-level directory to scan\n" >&2
      printf "  -n, --nav Build navigation menu\n" >&2
      printf "  -r, --rss Update RSS feed\n" >&2
      printf "  -V, --verbose Show messages while running\n" >&2
      printf "  -x, --exclude Skip given directories\n" >&2
    }
    
    # ANSI colour escape sequences
    readonly COLOUR_BLUE='\033[1;34m'
    readonly COLOUR_PINK='\033[1;35m'
    readonly COLOUR_DKGRAY='\033[30m'
    readonly COLOUR_DKRED='\033[31m'
    readonly COLOUR_YELLOW='\033[1;33m'
    readonly COLOUR_OFF='\033[0m'
    
    # Colour definitions used by script
    readonly COLOUR_LOGGING=$COLOUR_BLUE
    readonly COLOUR_WARNING=$COLOUR_YELLOW
    
    # Set to anything to show help and exit
    unset ARG_HELP
    unset ARG_VERBOSE
    unset ARG_FONT
    unset ARG_COMMIT_MESSAGE
    unset ARG_EXCLUDES
    unset ARG_RSS
    unset ARG_NAV
    
    # Assume current working directory is the directory to scan for Markdown
    ARG_INPUT_DIR=.
    
    main "$@"
    
    2 votes
  11. xxzozaxx
    Link
    I really consider write my blog (doesn't exist yet) in HTML. no markdown, no org-mode (original plan),

    I really consider write my blog (doesn't exist yet) in HTML. no markdown, no org-mode (original plan),

    1 vote