diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,12 @@
 # Changelog
 All notable changes to this project will be documented in this file.
 
-## 0.4.0.0 (in development)
+## 0.4.1.0 (released 2021-03-14)
+- [#69] Improve console output
+- [#71] Add support for _Go_ language
+- [#72] FIXED: Headroom doctest not passing with hashable-1.3.1.0
+
+## 0.4.0.0 (released 2021-03-04)
 - [#57] FIXED: put-before/put-after in commented code breaks header detection
 - [#58] BREAKING CHANGE: Extend configuration for defining header margins
 - [#59] Check compatibility of loaded YAML configuration
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 __Headroom__ also offers much more than just [adding, replacing or dropping][doc:running-headroom] license headers. It can also [update years in copyrights][doc:post-processing] for you, provides [content-aware templates][doc:templates] for some source code file types, and much more!
 
-[![asciicast](https://asciinema.org/a/4Pfxdss0V4msFjjt2z6mgCZCp.svg)](https://asciinema.org/a/4Pfxdss0V4msFjjt2z6mgCZCp)
+[![asciicast](https://asciinema.org/a/DkSBMZPHMJvJ4jyDtvT9ehfs8.svg)](https://asciinema.org/a/DkSBMZPHMJvJ4jyDtvT9ehfs8)
 
 ## Main Features
 - __License Header Management__ - [Add, replace or drop license headers][doc:running-headroom] in your source code files with a single command. What's more, contrary to many similar tools, _Headroom_ allows you to also replace/drop headers that weren't previously generated by _Headroom_, using smart header auto-detection.
diff --git a/embedded/default-config.yaml b/embedded/default-config.yaml
--- a/embedded/default-config.yaml
+++ b/embedded/default-config.yaml
@@ -133,6 +133,18 @@
       starts-with: ^\/\*
       ends-with: \*\/$
 
+  ## Go configuration
+  go:
+    file-extensions: ["go"]
+    margin-top-code: 0
+    margin-top-file: 0
+    margin-bottom-code: 0
+    margin-bottom-file: 0
+    put-after: []
+    put-before: []
+    line-comment:
+      prefixed-by: ^\/\/
+
   ## Haskell configuration
   haskell:
     file-extensions: ["hs"]
diff --git a/embedded/license/apache2/go.mustache b/embedded/license/apache2/go.mustache
new file mode 100644
--- /dev/null
+++ b/embedded/license/apache2/go.mustache
@@ -0,0 +1,14 @@
+// {{ project }}
+// Copyright {{ year }} {{ author }}
+// 
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// 
+// http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+// or implied. See the License for the specific language governing
+// permissions and limitations under the License.
diff --git a/embedded/license/bsd3/go.mustache b/embedded/license/bsd3/go.mustache
new file mode 100644
--- /dev/null
+++ b/embedded/license/bsd3/go.mustache
@@ -0,0 +1,27 @@
+// {{ project }}
+// Copyright (c) {{ year }} {{ author }}
+// All rights reserved.
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// 
+// 1. Redistributions of source code must retain the above copyright notice,
+//    this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+// 3. Neither the name of copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
diff --git a/embedded/license/gpl2/go.mustache b/embedded/license/gpl2/go.mustache
new file mode 100644
--- /dev/null
+++ b/embedded/license/gpl2/go.mustache
@@ -0,0 +1,17 @@
+// {{ project }}
+// Copyright (c) {{ year }} {{ author }}
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or (at
+// your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
diff --git a/embedded/license/gpl3/go.mustache b/embedded/license/gpl3/go.mustache
new file mode 100644
--- /dev/null
+++ b/embedded/license/gpl3/go.mustache
@@ -0,0 +1,15 @@
+// {{ project }}
+// Copyright (C) {{ year }} {{ author }}
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see http://www.gnu.org/licenses/.
diff --git a/embedded/license/mit/go.mustache b/embedded/license/mit/go.mustache
new file mode 100644
--- /dev/null
+++ b/embedded/license/mit/go.mustache
@@ -0,0 +1,22 @@
+// The MIT License
+// 
+// {{ project }}
+// Copyright (c) {{ year }} {{ author }}
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
diff --git a/embedded/license/mpl2/go.mustache b/embedded/license/mpl2/go.mustache
new file mode 100644
--- /dev/null
+++ b/embedded/license/mpl2/go.mustache
@@ -0,0 +1,6 @@
+// {{ project }}
+// Copyright (c) {{ year }} {{ author }}
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, version 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
diff --git a/headroom.cabal b/headroom.cabal
--- a/headroom.cabal
+++ b/headroom.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 4c5eb45fc45946807c2cbd5814cbf57038cb7e09f142e29767fede026dbdd86f
+-- hash: bc01e405c33597c1c0babea2ec25e31272b14935d2f13583270a27fd70c62400
 
 name:           headroom
-version:        0.4.0.0
+version:        0.4.1.0
 synopsis:       License Header Manager
 description:    Would you like to have nice, up-to-date license/copyright headers in your source code files but hate to manage them by hand? Then Headroom is the right tool for you! Now you can define your license header as Mustache template, put all the variables (such as author's name, year, etc.) into the YAML config file and Headroom will take care to add such license headers to all your source code files.
 category:       Utils
@@ -28,6 +28,7 @@
     embedded/license/apache2/c.mustache
     embedded/license/apache2/cpp.mustache
     embedded/license/apache2/css.mustache
+    embedded/license/apache2/go.mustache
     embedded/license/apache2/haskell.mustache
     embedded/license/apache2/html.mustache
     embedded/license/apache2/java.mustache
@@ -39,6 +40,7 @@
     embedded/license/bsd3/c.mustache
     embedded/license/bsd3/cpp.mustache
     embedded/license/bsd3/css.mustache
+    embedded/license/bsd3/go.mustache
     embedded/license/bsd3/haskell.mustache
     embedded/license/bsd3/html.mustache
     embedded/license/bsd3/java.mustache
@@ -50,6 +52,7 @@
     embedded/license/gpl2/c.mustache
     embedded/license/gpl2/cpp.mustache
     embedded/license/gpl2/css.mustache
+    embedded/license/gpl2/go.mustache
     embedded/license/gpl2/haskell.mustache
     embedded/license/gpl2/html.mustache
     embedded/license/gpl2/java.mustache
@@ -61,6 +64,7 @@
     embedded/license/gpl3/c.mustache
     embedded/license/gpl3/cpp.mustache
     embedded/license/gpl3/css.mustache
+    embedded/license/gpl3/go.mustache
     embedded/license/gpl3/haskell.mustache
     embedded/license/gpl3/html.mustache
     embedded/license/gpl3/java.mustache
@@ -72,6 +76,7 @@
     embedded/license/mit/c.mustache
     embedded/license/mit/cpp.mustache
     embedded/license/mit/css.mustache
+    embedded/license/mit/go.mustache
     embedded/license/mit/haskell.mustache
     embedded/license/mit/html.mustache
     embedded/license/mit/java.mustache
@@ -83,6 +88,7 @@
     embedded/license/mpl2/c.mustache
     embedded/license/mpl2/cpp.mustache
     embedded/license/mpl2/css.mustache
+    embedded/license/mpl2/go.mustache
     embedded/license/mpl2/haskell.mustache
     embedded/license/mpl2/html.mustache
     embedded/license/mpl2/java.mustache
@@ -98,6 +104,7 @@
     test-data/code-samples/cpp/sample2.cpp
     test-data/code-samples/css/sample1.css
     test-data/code-samples/css/sample2.css
+    test-data/code-samples/go/sample1.go
     test-data/code-samples/haskell/full.hs
     test-data/code-samples/haskell/header.hs
     test-data/code-samples/haskell/sample1.hs
@@ -150,6 +157,7 @@
       Headroom.FileSupport.C
       Headroom.FileSupport.CPP
       Headroom.FileSupport.CSS
+      Headroom.FileSupport.Go
       Headroom.FileSupport.Haskell
       Headroom.FileSupport.Haskell.Haddock
       Headroom.FileSupport.HTML
@@ -254,6 +262,7 @@
       Headroom.FileSupport.CPPSpec
       Headroom.FileSupport.CSpec
       Headroom.FileSupport.CSSSpec
+      Headroom.FileSupport.GoSpec
       Headroom.FileSupport.Haskell.HaddockSpec
       Headroom.FileSupport.HaskellSpec
       Headroom.FileSupport.HTMLSpec
diff --git a/src/Headroom/Command/Run.hs b/src/Headroom/Command/Run.hs
--- a/src/Headroom/Command/Run.hs
+++ b/src/Headroom/Command/Run.hs
@@ -105,7 +105,6 @@
 import           Headroom.Variables.Types            ( Variables(..) )
 import           RIO
 import           RIO.FilePath                        ( takeBaseName )
-import qualified RIO.List                           as L
 import qualified RIO.Map                            as M
 import qualified RIO.Text                           as T
 
@@ -203,18 +202,19 @@
   startTS            <- liftIO getPOSIXTime
   templates          <- loadTemplates
   sourceFiles        <- findSourceFiles (M.keys templates)
+  _                  <- logInfo "-----"
   (total, processed) <- processSourceFiles templates sourceFiles
   endTS              <- liftIO getPOSIXTime
-  logInfo "-----"
-  logInfo $ mconcat
+  when (processed > 0) $ logStickyDone "-----"
+  logStickyDone $ mconcat
     [ "Done: "
     , if isCheck then "outdated " else "modified "
     , display processed
     , if isCheck then ", up-to-date " else ", skipped "
     , display (total - processed)
-    , " file(s) in "
+    , " files in "
     , displayShow (endTS - startTS)
-    , " second(s)."
+    , " seconds."
     ]
   warnOnDryRun
   when (not croDryRun && isCheck && processed > 0) (exitWith $ ExitFailure 1)
@@ -239,12 +239,13 @@
   files <-
     mconcat <$> mapM (fsFindFilesByTypes cLicenseHeaders fileTypes) cSourcePaths
   let files' = excludePaths cExcludedPaths files
+  -- Found
   logInfo $ mconcat
     [ "Found "
-    , display $ L.length files'
-    , " source file(s) (excluded "
-    , display $ L.length files - L.length files'
-    , " file(s))"
+    , display $ length files'
+    , " files to process (excluded "
+    , display $ length files - length files'
+    , ")"
     ]
   pure files'
 
@@ -265,7 +266,7 @@
       withTemplate = mapMaybe (template cLicenseHeaders) paths
   cVars     <- compileVariables (dVars <> cVariables)
   processed <- mapM (process cVars dVars) (zipWithProgress withTemplate)
-  pure (L.length withTemplate, L.length . filter (== True) $ processed)
+  pure (length withTemplate, length . filter (== True) $ processed)
  where
   fileType c p = fileExtension p >>= fileTypeByExt c
   template c p = (, p) <$> (fileType c p >>= \ft -> M.lookup ft templates)
@@ -299,9 +300,10 @@
   let result  = raFunc source
       changed = raProcessed && (source /= result)
       message = if changed then raProcessedMsg else raSkippedMsg
+      logFn   = if changed then logInfo else logSticky
       isCheck = cRunMode == Check
   logDebug $ "Header info: " <> displayShow headerInfo
-  logInfo $ mconcat [display progress, " ", display message, fromString path]
+  logFn $ mconcat [display progress, " ", display message, fromString path]
   when (not croDryRun && not isCheck && changed)
        (writeFileUtf8 path $ toText result)
   pure changed
@@ -357,8 +359,7 @@
       (t, ) <$> (fsLoadFile p >>= parseTemplate (Just $ T.pack p) . T.strip)
     )
     withTypes
-  logInfo
-    $ mconcat ["Found ", display $ L.length parsed, " license template(s)"]
+  logInfo $ mconcat ["Found ", display $ length parsed, " license templates"]
   pure $ M.fromList parsed
   where extensions = toList $ templateExtensions @TemplateType
 
diff --git a/src/Headroom/Configuration.hs b/src/Headroom/Configuration.hs
--- a/src/Headroom/Configuration.hs
+++ b/src/Headroom/Configuration.hs
@@ -115,6 +115,7 @@
   hscC          <- makeHeaderConfig C (hscC pt)
   hscCpp        <- makeHeaderConfig CPP (hscCpp pt)
   hscCss        <- makeHeaderConfig CSS (hscCss pt)
+  hscGo         <- makeHeaderConfig Go (hscGo pt)
   hscHaskell    <- makeHeaderConfig Haskell (hscHaskell pt)
   hscHtml       <- makeHeaderConfig HTML (hscHtml pt)
   hscJava       <- makeHeaderConfig Java (hscJava pt)
diff --git a/src/Headroom/Configuration/Types.hs b/src/Headroom/Configuration/Types.hs
--- a/src/Headroom/Configuration/Types.hs
+++ b/src/Headroom/Configuration/Types.hs
@@ -431,6 +431,8 @@
   -- ^ configuration for /C++/ programming language
   , hscCss        :: HeaderConfig p
   -- ^ configuration for /CSS/
+  , hscGo         :: HeaderConfig p
+  -- ^ configuration for /Go/
   , hscHaskell    :: HeaderConfig p
   -- ^ configuration for /Haskell/ programming language
   , hscHtml       :: HeaderConfig p
@@ -471,6 +473,7 @@
     hscC          <- obj .:? "c" .!= mempty
     hscCpp        <- obj .:? "cpp" .!= mempty
     hscCss        <- obj .:? "css" .!= mempty
+    hscGo         <- obj .:? "go" .!= mempty
     hscHaskell    <- obj .:? "haskell" .!= mempty
     hscHtml       <- obj .:? "html" .!= mempty
     hscJava       <- obj .:? "java" .!= mempty
diff --git a/src/Headroom/Embedded.hs b/src/Headroom/Embedded.hs
--- a/src/Headroom/Embedded.hs
+++ b/src/Headroom/Embedded.hs
@@ -53,6 +53,7 @@
     C          -> $(embedTemplate Apache2 C)
     CPP        -> $(embedTemplate Apache2 CPP)
     CSS        -> $(embedTemplate Apache2 CSS)
+    Go         -> $(embedTemplate Apache2 Go)
     Haskell    -> $(embedTemplate Apache2 Haskell)
     HTML       -> $(embedTemplate Apache2 HTML)
     Java       -> $(embedTemplate Apache2 Java)
@@ -65,6 +66,7 @@
     C          -> $(embedTemplate BSD3 C)
     CPP        -> $(embedTemplate BSD3 CPP)
     CSS        -> $(embedTemplate BSD3 CSS)
+    Go         -> $(embedTemplate BSD3 Go)
     Haskell    -> $(embedTemplate BSD3 Haskell)
     HTML       -> $(embedTemplate BSD3 HTML)
     Java       -> $(embedTemplate BSD3 Java)
@@ -77,6 +79,7 @@
     C          -> $(embedTemplate GPL2 C)
     CPP        -> $(embedTemplate GPL2 CPP)
     CSS        -> $(embedTemplate GPL2 CSS)
+    Go         -> $(embedTemplate GPL2 Go)
     Haskell    -> $(embedTemplate GPL2 Haskell)
     HTML       -> $(embedTemplate GPL2 HTML)
     Java       -> $(embedTemplate GPL2 Java)
@@ -89,6 +92,7 @@
     C          -> $(embedTemplate GPL3 C)
     CPP        -> $(embedTemplate GPL3 CPP)
     CSS        -> $(embedTemplate GPL3 CSS)
+    Go         -> $(embedTemplate GPL3 Go)
     Haskell    -> $(embedTemplate GPL3 Haskell)
     HTML       -> $(embedTemplate GPL3 HTML)
     Java       -> $(embedTemplate GPL3 Java)
@@ -101,6 +105,7 @@
     C          -> $(embedTemplate MIT C)
     CPP        -> $(embedTemplate MIT CPP)
     CSS        -> $(embedTemplate MIT CSS)
+    Go         -> $(embedTemplate MIT Go)
     Haskell    -> $(embedTemplate MIT Haskell)
     HTML       -> $(embedTemplate MIT HTML)
     Java       -> $(embedTemplate MIT Java)
@@ -113,6 +118,7 @@
     C          -> $(embedTemplate MPL2 C)
     CPP        -> $(embedTemplate MPL2 CPP)
     CSS        -> $(embedTemplate MPL2 CSS)
+    Go         -> $(embedTemplate MPL2 Go)
     Haskell    -> $(embedTemplate MPL2 Haskell)
     HTML       -> $(embedTemplate MPL2 HTML)
     Java       -> $(embedTemplate MPL2 Java)
diff --git a/src/Headroom/FileSupport.hs b/src/Headroom/FileSupport.hs
--- a/src/Headroom/FileSupport.hs
+++ b/src/Headroom/FileSupport.hs
@@ -30,6 +30,7 @@
 import qualified Headroom.FileSupport.C             as C
 import qualified Headroom.FileSupport.CPP           as CPP
 import qualified Headroom.FileSupport.CSS           as CSS
+import qualified Headroom.FileSupport.Go            as Go
 import qualified Headroom.FileSupport.Haskell       as Haskell
 import qualified Headroom.FileSupport.HTML          as HTML
 import qualified Headroom.FileSupport.Java          as Java
@@ -57,6 +58,7 @@
 fileSupport C          = C.fileSupport
 fileSupport CPP        = CPP.fileSupport
 fileSupport CSS        = CSS.fileSupport
+fileSupport Go         = Go.fileSupport
 fileSupport Haskell    = Haskell.fileSupport
 fileSupport HTML       = HTML.fileSupport
 fileSupport Java       = Java.fileSupport
@@ -91,5 +93,3 @@
           | otherwise            -> (0, Code)
     put ns
     pure res
-
-
diff --git a/src/Headroom/FileSupport/C.hs b/src/Headroom/FileSupport/C.hs
--- a/src/Headroom/FileSupport/C.hs
+++ b/src/Headroom/FileSupport/C.hs
@@ -26,7 +26,7 @@
                                                      , SyntaxAnalysis(..)
                                                      , defaultFileSupport
                                                      )
-import           Headroom.FileType.Types             ( FileType(..) )
+import           Headroom.FileType.Types             ( FileType(C) )
 
 
 ------------------------------  PUBLIC FUNCTIONS  ------------------------------
diff --git a/src/Headroom/FileSupport/CPP.hs b/src/Headroom/FileSupport/CPP.hs
--- a/src/Headroom/FileSupport/CPP.hs
+++ b/src/Headroom/FileSupport/CPP.hs
@@ -26,7 +26,7 @@
                                                      , SyntaxAnalysis(..)
                                                      , defaultFileSupport
                                                      )
-import           Headroom.FileType.Types             ( FileType(..) )
+import           Headroom.FileType.Types             ( FileType(CPP) )
 
 
 ------------------------------  PUBLIC FUNCTIONS  ------------------------------
diff --git a/src/Headroom/FileSupport/CSS.hs b/src/Headroom/FileSupport/CSS.hs
--- a/src/Headroom/FileSupport/CSS.hs
+++ b/src/Headroom/FileSupport/CSS.hs
@@ -26,7 +26,7 @@
                                                      , SyntaxAnalysis(..)
                                                      , defaultFileSupport
                                                      )
-import           Headroom.FileType.Types             ( FileType(..) )
+import           Headroom.FileType.Types             ( FileType(CSS) )
 
 
 ------------------------------  PUBLIC FUNCTIONS  ------------------------------
diff --git a/src/Headroom/FileSupport/Go.hs b/src/Headroom/FileSupport/Go.hs
new file mode 100644
--- /dev/null
+++ b/src/Headroom/FileSupport/Go.hs
@@ -0,0 +1,44 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE QuasiQuotes       #-}
+
+{-|
+Module      : Headroom.FileSupport.Go
+Description : Support for /Go/ source code files
+Copyright   : (c) 2019-2021 Vaclav Svejcar
+License     : BSD-3-Clause
+Maintainer  : vaclav.svejcar@gmail.com
+Stability   : experimental
+Portability : POSIX
+
+Basic support for /Go language/ source code files. This implementation doesn't
+extract any variables or template data.
+-}
+
+module Headroom.FileSupport.Go
+  ( fileSupport
+  )
+where
+
+import           Headroom.Data.Regex                 ( isMatch
+                                                     , re
+                                                     )
+import           Headroom.FileSupport.Types          ( FileSupport(..)
+                                                     , SyntaxAnalysis(..)
+                                                     , defaultFileSupport
+                                                     )
+import           Headroom.FileType.Types             ( FileType(Go) )
+
+
+------------------------------  PUBLIC FUNCTIONS  ------------------------------
+
+-- | Implementation of 'FileSupport' for /C/.
+fileSupport :: FileSupport
+fileSupport = defaultFileSupport Go syntaxAnalysis
+
+
+------------------------------  PRIVATE FUNCTIONS  -----------------------------
+
+syntaxAnalysis :: SyntaxAnalysis
+syntaxAnalysis = SyntaxAnalysis { saIsCommentStart = isMatch [re|^\/\*|^\/\/|]
+                                , saIsCommentEnd   = isMatch [re|\*\/$|^\/\/|]
+                                }
diff --git a/src/Headroom/FileSupport/HTML.hs b/src/Headroom/FileSupport/HTML.hs
--- a/src/Headroom/FileSupport/HTML.hs
+++ b/src/Headroom/FileSupport/HTML.hs
@@ -26,7 +26,7 @@
                                                      , SyntaxAnalysis(..)
                                                      , defaultFileSupport
                                                      )
-import           Headroom.FileType.Types             ( FileType(..) )
+import           Headroom.FileType.Types             ( FileType(HTML) )
 
 
 ------------------------------  PUBLIC FUNCTIONS  ------------------------------
diff --git a/src/Headroom/FileSupport/Haskell.hs b/src/Headroom/FileSupport/Haskell.hs
--- a/src/Headroom/FileSupport/Haskell.hs
+++ b/src/Headroom/FileSupport/Haskell.hs
@@ -60,7 +60,7 @@
 import           Headroom.Configuration.Types        ( HeaderConfig(..)
                                                      , HeaderSyntax
                                                      )
-import           Headroom.FileType.Types             ( FileType(..) )
+import           Headroom.FileType.Types             ( FileType(Haskell) )
 import           Headroom.Header.Types               ( HeaderTemplate(..) )
 import           Headroom.SourceCode                 ( LineType(..)
                                                      , SourceCode(..)
diff --git a/src/Headroom/FileSupport/JS.hs b/src/Headroom/FileSupport/JS.hs
--- a/src/Headroom/FileSupport/JS.hs
+++ b/src/Headroom/FileSupport/JS.hs
@@ -26,7 +26,7 @@
                                                      , SyntaxAnalysis(..)
                                                      , defaultFileSupport
                                                      )
-import           Headroom.FileType.Types             ( FileType(..) )
+import           Headroom.FileType.Types             ( FileType(JS) )
 
 
 ------------------------------  PUBLIC FUNCTIONS  ------------------------------
diff --git a/src/Headroom/FileSupport/Java.hs b/src/Headroom/FileSupport/Java.hs
--- a/src/Headroom/FileSupport/Java.hs
+++ b/src/Headroom/FileSupport/Java.hs
@@ -38,7 +38,7 @@
 import           Headroom.FileSupport.Types          ( FileSupport(..)
                                                      , SyntaxAnalysis(..)
                                                      )
-import           Headroom.FileType.Types             ( FileType(..) )
+import           Headroom.FileType.Types             ( FileType(Java) )
 import           Headroom.Header.Types               ( HeaderTemplate )
 import           Headroom.SourceCode                 ( LineType(..)
                                                      , SourceCode(..)
diff --git a/src/Headroom/FileSupport/PureScript.hs b/src/Headroom/FileSupport/PureScript.hs
--- a/src/Headroom/FileSupport/PureScript.hs
+++ b/src/Headroom/FileSupport/PureScript.hs
@@ -40,7 +40,7 @@
 import           Headroom.FileSupport.Types          ( FileSupport(..)
                                                      , SyntaxAnalysis(..)
                                                      )
-import           Headroom.FileType.Types             ( FileType(..) )
+import           Headroom.FileType.Types             ( FileType(PureScript) )
 import           Headroom.Header.Types               ( HeaderTemplate )
 import           Headroom.SourceCode                 ( LineType(..)
                                                      , SourceCode(..)
diff --git a/src/Headroom/FileSupport/Rust.hs b/src/Headroom/FileSupport/Rust.hs
--- a/src/Headroom/FileSupport/Rust.hs
+++ b/src/Headroom/FileSupport/Rust.hs
@@ -26,7 +26,7 @@
                                                      , SyntaxAnalysis(..)
                                                      , defaultFileSupport
                                                      )
-import           Headroom.FileType.Types             ( FileType(..) )
+import           Headroom.FileType.Types             ( FileType(Rust) )
 
 
 ------------------------------  PUBLIC FUNCTIONS  ------------------------------
diff --git a/src/Headroom/FileSupport/Scala.hs b/src/Headroom/FileSupport/Scala.hs
--- a/src/Headroom/FileSupport/Scala.hs
+++ b/src/Headroom/FileSupport/Scala.hs
@@ -26,7 +26,7 @@
                                                      , SyntaxAnalysis(..)
                                                      , defaultFileSupport
                                                      )
-import           Headroom.FileType.Types             ( FileType(..) )
+import           Headroom.FileType.Types             ( FileType(Scala) )
 
 
 ------------------------------  PUBLIC FUNCTIONS  ------------------------------
diff --git a/src/Headroom/FileSupport/Shell.hs b/src/Headroom/FileSupport/Shell.hs
--- a/src/Headroom/FileSupport/Shell.hs
+++ b/src/Headroom/FileSupport/Shell.hs
@@ -26,7 +26,7 @@
                                                      , SyntaxAnalysis(..)
                                                      , defaultFileSupport
                                                      )
-import           Headroom.FileType.Types             ( FileType(..) )
+import           Headroom.FileType.Types             ( FileType(Shell) )
 
 
 ------------------------------  PUBLIC FUNCTIONS  ------------------------------
diff --git a/src/Headroom/FileType.hs b/src/Headroom/FileType.hs
--- a/src/Headroom/FileType.hs
+++ b/src/Headroom/FileType.hs
@@ -70,6 +70,7 @@
   C          -> hscC
   CPP        -> hscCpp
   CSS        -> hscCss
+  Go         -> hscGo
   Haskell    -> hscHaskell
   HTML       -> hscHtml
   Java       -> hscJava
diff --git a/src/Headroom/FileType/Types.hs b/src/Headroom/FileType/Types.hs
--- a/src/Headroom/FileType/Types.hs
+++ b/src/Headroom/FileType/Types.hs
@@ -26,6 +26,8 @@
   -- ^ support for /C++/ programming language
   | CSS
   -- ^ support for /CSS/
+  | Go
+  -- ^ support for /Go/ programming language
   | Haskell
   -- ^ support for /Haskell/ programming language
   | HTML
diff --git a/src/Headroom/UI/Progress.hs b/src/Headroom/UI/Progress.hs
--- a/src/Headroom/UI/Progress.hs
+++ b/src/Headroom/UI/Progress.hs
@@ -20,7 +20,6 @@
 where
 
 import           RIO
-import qualified RIO.List                           as L
 import qualified RIO.Text                           as T
 import           Text.Printf                         ( printf )
 
@@ -35,7 +34,7 @@
   textDisplay (Progress current total) = T.pack
     $ mconcat ["[", currentS, " of ", totalS, "]"]
    where
-    format   = "%" <> (show . L.length $ totalS) <> "d"
+    format   = "%" <> (show . length $ totalS) <> "d"
     currentS = printf format current
     totalS   = show total
 
@@ -50,5 +49,5 @@
                 -- ^ zipped result
 zipWithProgress list = zip progresses list
  where
-  listLength = L.length list
+  listLength = length list
   progresses = fmap (`Progress` listLength) [1 .. listLength]
diff --git a/src/Headroom/Variables.hs b/src/Headroom/Variables.hs
--- a/src/Headroom/Variables.hs
+++ b/src/Headroom/Variables.hs
@@ -84,8 +84,10 @@
 -- Note that recursive variable reference and/or cyclic references are not
 -- supported.
 --
--- >>> compileVariables $ mkVariables [("name", "John"), ("msg", "Hello, {{ name }}")]
--- Variables (fromList [("msg","Hello, John"),("name","John")])
+-- >>> let compiled = compileVariables $ mkVariables [("name", "John"), ("msg", "Hello, {{ name }}")]
+-- >>> let expected = mkVariables [("name", "John"), ("msg", "Hello, John")]
+-- >>> compiled == Just expected
+-- True
 compileVariables :: (MonadThrow m)
                  => Variables
                  -- ^ input variables to compile
diff --git a/test-data/code-samples/go/sample1.go b/test-data/code-samples/go/sample1.go
new file mode 100644
--- /dev/null
+++ b/test-data/code-samples/go/sample1.go
@@ -0,0 +1,16 @@
+
+// This is the
+// header
+
+package main
+
+// this is not the header
+import "fmt"
+func main() {
+    /* another comment */
+    fmt.Println("hello world")
+
+    /*
+     * block comment
+     */
+}
diff --git a/test/Headroom/Command/RunSpec.hs b/test/Headroom/Command/RunSpec.hs
--- a/test/Headroom/Command/RunSpec.hs
+++ b/test/Headroom/Command/RunSpec.hs
@@ -73,7 +73,7 @@
 spec = do
   describe "loadBuiltInTemplates" $ do
     it "should load correct number of built-in templates" $ do
-      M.size <$> runRIO env (loadBuiltInTemplates BSD3) `shouldReturn` 11
+      M.size <$> runRIO env (loadBuiltInTemplates BSD3) `shouldReturn` 12
 
 
   describe "loadTemplateFiles" $ do
diff --git a/test/Headroom/FileSupport/GoSpec.hs b/test/Headroom/FileSupport/GoSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Headroom/FileSupport/GoSpec.hs
@@ -0,0 +1,36 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards   #-}
+
+module Headroom.FileSupport.GoSpec
+  ( spec
+  )
+where
+
+import           Headroom.FileSupport.Go
+import           Headroom.FileSupport.Types          ( FileSupport(..)
+                                                     , SyntaxAnalysis(..)
+                                                     )
+import           RIO
+import           Test.Hspec
+
+
+spec :: Spec
+spec = do
+
+  describe "fsSyntaxAnalysis" $ do
+    it "correctly detects comment starts/ends" $ do
+      let samples =
+            [ ("non comment line"             , (False, False))
+            , ("// single line comment"       , (True, True))
+            , ("not // single line comment"   , (False, False))
+            , ("/* block comment start"       , (True, False))
+            , ("block comment end */"         , (False, True))
+            , ("/* block comment start/end */", (True, True))
+            ]
+      all checkSyntaxAnalysis samples `shouldBe` True
+
+ where
+  checkSyntaxAnalysis (l, (s, e)) =
+    let SyntaxAnalysis {..} = fsSyntaxAnalysis fileSupport
+    in  saIsCommentStart l == s && saIsCommentEnd l == e
diff --git a/test/Headroom/FileSupportSpec.hs b/test/Headroom/FileSupportSpec.hs
--- a/test/Headroom/FileSupportSpec.hs
+++ b/test/Headroom/FileSupportSpec.hs
@@ -90,6 +90,28 @@
             ]
       analyzeSourceCode (fileSupport CSS) sample `shouldBe` expected
 
+    it "analyzes Go source code" $ do
+      sample <- loadFile $ codeSamples </> "go" </> "sample1.go"
+      let expected = SourceCode
+            [ (Code   , "")
+            , (Comment, "// This is the")
+            , (Comment, "// header")
+            , (Code   , "")
+            , (Code   , "package main")
+            , (Code   , "")
+            , (Comment, "// this is not the header")
+            , (Code   , "import \"fmt\"")
+            , (Code   , "func main() {")
+            , (Comment, "    /* another comment */")
+            , (Code, "    fmt.Println(\"hello world\")")
+            , (Code   , "")
+            , (Comment, "    /*")
+            , (Comment, "     * block comment")
+            , (Comment, "     */")
+            , (Code   , "}")
+            ]
+      analyzeSourceCode (fileSupport Go) sample `shouldBe` expected
+
     it "analyzes Haskell source code" $ do
       sample <- loadFile $ codeSamples </> "haskell" </> "full.hs"
       let expected = SourceCode
diff --git a/test/Headroom/HeaderSpec.hs b/test/Headroom/HeaderSpec.hs
--- a/test/Headroom/HeaderSpec.hs
+++ b/test/Headroom/HeaderSpec.hs
@@ -393,6 +393,7 @@
       sampleCpp2         <- loadSample CPP $ "cpp" </> "sample2.cpp"
       sampleCss1         <- loadSample CSS $ "css" </> "sample1.css"
       sampleCss2         <- loadSample CSS $ "css" </> "sample2.css"
+      sampleGo           <- loadSample Go $ "go" </> "sample1.go"
       sampleHs1          <- loadSample Haskell $ "haskell" </> "sample1.hs"
       sampleHs2          <- loadSample Haskell $ "haskell" </> "sample2.hs"
       sampleHtml1        <- loadSample HTML $ "html" </> "sample1.html"
@@ -410,6 +411,7 @@
       findHeader hscCpp sampleCpp2 `shouldBe` Nothing
       findHeader hscCss sampleCss1 `shouldBe` Just (1, 4)
       findHeader hscCss sampleCss2 `shouldBe` Nothing
+      findHeader hscGo sampleGo `shouldBe` Just (1, 2)
       findHeader hscHaskell sampleHs1 `shouldBe` Just (1, 3)
       findHeader hscHaskell sampleHs2 `shouldBe` Nothing
       findHeader hscHtml sampleHtml1 `shouldBe` Just (1, 4)
