Compare commits

...

32 commits

Author SHA1 Message Date
Yann Esposito (Yogsototh) 9ddc693b3a
New system in place 2020-06-27 14:57:04 +02:00
Yann Esposito (Yogsototh) eff4b0bbf6
remove js entirely 2020-06-27 14:25:53 +02:00
Yann Esposito (Yogsototh) 8ebe8bed51
Merge branch 'shake' 2020-06-25 18:43:33 +02:00
Yann Esposito (Yogsototh) 53fa733209
minor fix 2020-06-25 17:42:33 +02:00
Yann Esposito (Yogsototh) 78008d3df4
fixed almos everything 2020-06-25 17:23:59 +02:00
Yann Esposito (Yogsototh) 6c3f4f3031
updated and mostly feature equal 2020-06-25 16:28:35 +02:00
Yann Esposito (Yogsototh) f12936254a
better templates 2020-06-25 15:27:00 +02:00
Yann Esposito (Yogsototh) 931d9c4483
improvements 2020-06-25 14:22:58 +02:00
Yann Esposito (Yogsototh) 62461dc616
update 2020-06-25 13:08:18 +02:00
Yann Esposito (Yogsototh) 4df922b475
fix archive build 2020-06-25 07:10:00 +02:00
Yann Esposito (Yogsototh) c34fa83504
Neil Mitchell help https://github.com/ndmitchell/shake/issues/767 2020-06-25 07:06:16 +02:00
Yann Esposito (Yogsototh) 0a1aef7425
archive working, site working 2020-06-24 18:36:56 +02:00
Yann Esposito (Yogsototh) 0e44c7d427
right track 2020-06-23 23:58:09 +02:00
Yann Esposito (Yogsototh) 4b8a5d3c89
Merge branch 'shake' of gitea.esy.fun:yogsototh/her.esy.fun into shake 2020-06-23 19:29:20 +02:00
Yann Esposito (Yogsototh) aef6f81274
Fixes 2020-06-23 19:28:41 +02:00
Yann Esposito (Yogsototh) 3a13435710
updated with niv 2020-06-23 16:55:38 +02:00
Yann Esposito (Yogsototh) d47ad32074
updated hlint 2020-06-23 16:14:53 +02:00
Yann Esposito (Yogsototh) 2bdc881cc9
closer 2020-06-23 09:15:03 +02:00
Yann Esposito (Yogsototh) d201cf8b1b
wip 2020-06-23 08:44:02 +02:00
Yann Esposito (Yogsototh) c1a00e1c09
closer 2020-06-23 00:20:38 +02:00
Yann Esposito (Yogsototh) e5d9673fc4
right track 2020-06-22 23:01:47 +02:00
Yann Esposito (Yogsototh) f3be772986
mostly works 2020-06-22 22:13:12 +02:00
Yann Esposito (Yogsototh) a706933d96
remove ignored files 2020-06-22 14:32:03 +02:00
Yann Esposito (Yogsototh) 5359765bf5
updated 2020-06-22 12:27:55 +02:00
Yann Esposito (Yogsototh) b81339a51e
progress 2020-06-22 12:08:07 +02:00
Yann Esposito (Yogsototh) e3a33d9ecf
starting to work 2020-06-22 11:44:11 +02:00
Yann Esposito (Yogsototh) 1eb4a6de5a
save 2020-06-22 09:39:44 +02:00
Yann Esposito (Yogsototh) 1e0d4c8fad
forgot some gitignore 2020-06-21 15:52:33 +02:00
Yann Esposito (Yogsototh) fcd406a3d9
Merge branch 'master' into shake 2020-06-21 15:50:53 +02:00
Yann Esposito (Yogsototh) 536f0ed5e6
wip 2020-06-14 13:19:13 +02:00
Yann Esposito (Yogsototh) 0f62b038df
minor fixes 2020-05-25 22:30:22 +02:00
Yann Esposito (Yogsototh) a7df9b3959
move to shake 2020-05-25 22:28:06 +02:00
29 changed files with 875 additions and 603 deletions

4
.gitignore vendored
View file

@ -1,3 +1,7 @@
_cache/
_site/
_optim/
src/archive.org
.direnv/
_shake/
.shake/

63
.hlint.yaml Normal file
View file

@ -0,0 +1,63 @@
# HLint configuration file
# https://github.com/ndmitchell/hlint
##########################
# This file contains a template configuration file, which is typically
# placed as .hlint.yaml in the root of your project
# Specify additional command line arguments
#
# - arguments: [--color, --cpp-simple, -XQuasiQuotes]
# Control which extensions/flags/modules/functions can be used
#
# - extensions:
# - default: false # all extension are banned by default
# - name: [PatternGuards, ViewPatterns] # only these listed extensions can be used
# - {name: CPP, within: CrossPlatform} # CPP can only be used in a given module
#
# - flags:
# - {name: -w, within: []} # -w is allowed nowhere
#
# - modules:
# - {name: [Data.Set, Data.HashSet], as: Set} # if you import Data.Set qualified, it must be as 'Set'
# - {name: Control.Arrow, within: []} # Certain modules are banned entirely
#
# - functions:
# - {name: unsafePerformIO, within: []} # unsafePerformIO can only appear in no modules
# Add custom hints for this project
#
# Will suggest replacing "wibbleMany [myvar]" with "wibbleOne myvar"
# - error: {lhs: "wibbleMany [x]", rhs: wibbleOne x}
# Turn on hints that are off by default
#
# Ban "module X(module X) where", to require a real export list
# - warn: {name: Use explicit module export list}
#
# Replace a $ b $ c with a . b $ c
# - group: {name: dollar, enabled: true}
#
# Generalise map to fmap, ++ to <>
# - group: {name: generalise, enabled: true}
# Ignore some builtin hints
# - ignore: {name: Use let}
# - ignore: {name: Use const, within: SpecialModule} # Only within certain modules
# Define some custom infix operators
# - fixity: infixr 3 ~^#^~
# To generate a suitable file for HLint do:
# $ hlint --default > .hlint.yaml
# Protolude does not use String and prefer Text so String is undefined and we should use [Char]
- ignore: {name: Use String}

385
Shakefile.hs Normal file
View file

@ -0,0 +1,385 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoImplicitPrelude #-}
import Protolude
import Development.Shake
-- import Development.Shake.Command
import Development.Shake.FilePath
import Data.Time.Format.ISO8601 (iso8601Show)
import qualified Data.Time.Clock as Clock
import Control.Monad.Fail
import Data.Aeson
-- import qualified Text.Megaparsec as Megaparsec
import Data.Default ( Default(def) )
import qualified Data.Text as T
import Text.Mustache
import Text.Pandoc.Class (PandocMonad)
import qualified Text.Pandoc.Class as Pandoc
import Text.Pandoc.Definition ( Pandoc(..)
, Block(..)
, Inline(..)
, MetaValue(..)
, nullMeta
, docTitle
, docDate
, docAuthors
, lookupMeta
)
import Text.Pandoc.Options ( ReaderOptions(..)
, WriterOptions(..)
, ObfuscationMethod(..)
, HTMLMathMethod(..)
)
import qualified Text.Pandoc.Readers as Readers
import Text.Pandoc.Walk (Walkable(..))
import qualified Text.Pandoc.Writers as Writers
main :: IO ()
main = shakeArgs shOpts buildRules
where
shOpts =
shakeOptions
{ shakeVerbosity = Chatty
, shakeLintInside = ["\\"]
}
-- Configuration
-- Should probably go in a Reader Monad
srcDir :: FilePath
srcDir = "src"
siteDir :: FilePath
siteDir = "_site"
optimDir :: FilePath
optimDir = "_optim"
-- BlogPost data structure (a bit of duplication because the metas are in Pandoc)
data BlogPost =
BlogPost { postTitle :: T.Text
, postDate :: T.Text
, postAuthor :: T.Text
, postUrl :: FilePath
, postSrc :: FilePath
, postTags :: [T.Text]
, postDescr :: T.Text
, postToc :: Bool
, postBody :: Pandoc
}
inlineToText :: PandocMonad m => [Inline] -> m T.Text
inlineToText inline =
Writers.writeAsciiDoc def (Pandoc nullMeta [Plain inline])
reformatDate :: Text -> Text
reformatDate = T.takeWhile (/= ' ') . (T.dropAround dateEnvelope)
where
dateEnvelope ' ' = True
dateEnvelope '\n' = True
dateEnvelope '\t' = True
dateEnvelope '[' = True
dateEnvelope ']' = True
dateEnvelope _ = False
getBlogpostFromMetas
:: (MonadIO m, MonadFail m) => [Char] -> Bool -> Pandoc -> m BlogPost
getBlogpostFromMetas path toc pandoc@(Pandoc meta _) = do
eitherBlogpost <- liftIO $ Pandoc.runIO $ do
title <- fmap (T.dropEnd 1) $ inlineToText $ docTitle meta
date <- fmap reformatDate $ inlineToText $ docDate meta
author <- case head $ docAuthors meta of
Just m -> inlineToText m
Nothing -> return ""
let tags = tagsToList $ lookupMeta "keywords" meta
description = descr $ lookupMeta "description" meta
url = "/" </> dropDirectory1 path -<.> "org"
return $ BlogPost title date author url path tags description toc pandoc
case eitherBlogpost of
Left _ -> fail "BAD"
Right bp -> return bp
where
tagsToList (Just (MetaList ms)) = map toStr ms
tagsToList _ = []
descr (Just (MetaString t)) = t
descr _ = ""
toStr (MetaString t) = t
toStr (MetaInlines inlines) = T.intercalate " " $ map inlineToTxt inlines
toStr _ = ""
inlineToTxt (Str t) = t
inlineToTxt _ = ""
sortByPostDate :: [BlogPost] -> [BlogPost]
sortByPostDate =
sortBy (\a b-> compare (postDate b) (postDate a))
build :: FilePath -> FilePath
build = (</>) siteDir
genAllDeps :: [FilePattern] -> Action [FilePath]
genAllDeps patterns = do
allMatchedFiles <- getDirectoryFiles srcDir patterns
allMatchedFiles &
filter ((/= "html") . takeExtension) &
filter (null . takeExtension) &
map (siteDir </>) &
return
buildRules :: Rules ()
buildRules = do
cleanRule
allRule
fullRule
getPost <- mkGetPost
getPosts <- mkGetPosts getPost
getTemplate <- mkGetTemplate
build "**" %> \out -> do
let asset = dropDirectory1 out
case (takeExtension asset) of
".html" -> do
if out == siteDir </> "archive.html"
then buildArchive getPosts getTemplate out
else genHtmlAction getPost getTemplate out
".txt" -> do
txtExists <- doesFileExist (srcDir </> asset)
if txtExists
then copyFileChanged (srcDir </> asset) out
else genAsciiAction getPost out
".jpg" -> compressImage asset
".jpeg" -> compressImage asset
".gif" -> compressImage asset
".png" -> compressImage asset
_ -> copyFileChanged (srcDir </> asset) out
optimDir </> "rss.xml" %> \_ -> do
needAll
command_[] "engine/pre-deploy.sh" []
buildArchive
:: (() -> Action [BlogPost])
-> (FilePath -> Action Template) -> [Char] -> Action ()
buildArchive getPosts getTemplate out = do
css <- genAllDeps ["//*.css"]
posts <- fmap sortByPostDate $ getPosts ()
need $ css <> map postSrc posts
let
title :: Text
title = "#+title: Posts"
articleList = toS $ T.intercalate "\n" $ map postInfo posts
fileContent = title <> "\n\n" <> articleList
eitherResult <- liftIO $ Pandoc.runIO $ Readers.readOrg (def { readerStandalone = True }) (toS fileContent)
bp <- case eitherResult of
Left _ -> fail "BAD"
Right pandoc -> getBlogpostFromMetas out False pandoc
innerHtml <- genHtml bp
template <- getTemplate ("templates" </> "main.mustache")
let htmlContent =
renderMustache template
$ object [ "title" .= postTitle bp
, "author" .= postAuthor bp
, "date" .= postDate bp
, "tags" .= postTags bp
, "description" .= postDescr bp
, "body" .= innerHtml
]
writeFile' out (toS htmlContent)
postInfo :: BlogPost -> Text
postInfo bp =
"- " <> date <> ": " <> orglink
where
date = T.takeWhile (/= ' ') (postDate bp)
orglink = "[[file:" <> (toS (postUrl bp)) <> "][" <> (postTitle bp) <> "]]"
replaceLinks :: Pandoc -> Pandoc
replaceLinks = walk replaceOrgLink
where
replaceOrgLink :: Inline -> Inline
replaceOrgLink lnk@(Link attr inl (url,txt)) =
if takeExtension (toS url) == ".org"
then Link attr inl ((toS (toS url -<.> ".html")),txt)
else lnk
replaceOrgLink x = x
orgContentToText :: (MonadIO m, MonadFail m) => Text -> m Text
orgContentToText org = do
eitherResult <- liftIO $ Pandoc.runIO $ Readers.readOrg (def { readerStandalone = True }) org
pandoc <- case eitherResult of
Left _ -> fail "BAD"
Right p -> return p
eitherHtml <- liftIO $ Pandoc.runIO $ Writers.writeHtml5String (def {writerEmailObfuscation = ReferenceObfuscation}) pandoc
case eitherHtml of
Left _ -> fail "BAD"
Right innerHtml -> return innerHtml
postamble :: (MonadIO m, MonadFail m) => Text -> BlogPost -> m Text
postamble now bp =
orgContentToText $ unlines $
[ "@@html:<footer>@@"
, "@@html:<i>Any comment? Click on my email below and I'll add it.</i>@@"
, ""
, "| author | @@html:<span class=\"author\">@@ [[mailto:Yann Esposito <yann@esposito.host>?subject=yblog: " <> (postTitle bp) <> "][Yann Esposito <yann@esposito.host>]] @@html:</span>@@ |"
, "| tags | " <> T.intercalate " " (map ("#"<>) (postTags bp)) <> " |"
, "| date | " <> postDate bp <> " |"
, "| rss | [[file:/rss.xml][RSS]] ([[https://validator.w3.org/feed/check.cgi?url=https%3A%2F%2Fher.esy.fun%2Frss.xml][validate]]) |"
, "| size | @@html:<div class=\"web-file-size\">XXK (html XXK, css XXK, img XXK)</div>@@ |"
, "| gz | @@html:<div class=\"gzweb-file-size\">XXK (html XXK, css XXK, img XXK)</div>@@ |"
, "| generated | " <> now <> " |"
, ""
, "@@html:</footer>@@"
]
genHtml :: (MonadIO m, MonadFail m) => BlogPost -> m Text
genHtml bp = do
let htmlBody = replaceLinks (postBody bp)
eitherHtml <- liftIO $
Pandoc.runIO $
Writers.writeHtml5String
(def { writerTableOfContents = postToc bp
, writerEmailObfuscation = ReferenceObfuscation
, writerHTMLMathMethod = MathML
})
htmlBody
body <- case eitherHtml of
Left _ -> fail "BAD"
Right innerHtml -> return innerHtml
now <- liftIO Clock.getCurrentTime
footer <- postamble (toS (iso8601Show now)) bp
return (body <> footer)
origin :: Text
origin = "https://her.esy.fun"
genHtmlAction
:: (FilePath -> Action BlogPost)
-> (FilePath -> Action Template) -> [Char] -> Action ()
genHtmlAction getPost getTemplate out = do
let isPost = takeDirectory1 (dropDirectory1 out) == "posts"
template <- getTemplate ("templates" </> if isPost then "post.mustache" else "main.mustache")
let srcFile = srcDir </> (dropDirectory1 (out -<.> "org"))
liftIO $ putText $ "need: " <> (toS srcFile) <> " -> " <> (toS out)
need [srcFile]
bp <- getPost srcFile
innerHtml <- genHtml bp
let htmlContent =
renderMustache template
$ object [ "title" .= postTitle bp
, "author" .= postAuthor bp
, "date" .= postDate bp
, "tags" .= postTags bp
, "description" .= postDescr bp
, "body" .= innerHtml
, "orgsource" .= T.pack (postUrl bp -<.> "org")
, "txtsource" .= T.pack (postUrl bp -<.> "txt")
, "permalink" .= T.pack (toS origin <> postUrl bp)
]
writeFile' out (toS htmlContent)
genAscii :: (MonadIO m, MonadFail m) => BlogPost -> m Text
genAscii bp = do
eitherAscii <- liftIO $ Pandoc.runIO $ Writers.writePlain def (postBody bp)
case eitherAscii of
Left _ -> fail "BAD"
Right innerAscii -> return innerAscii
genAsciiAction
:: (FilePath -> Action BlogPost)
-> [Char] -> Action ()
genAsciiAction getPost out = do
let srcFile = srcDir </> (dropDirectory1 (out -<.> "org"))
need [srcFile]
bp <- getPost srcFile
innerAscii <- genAscii bp
let preamble = postTitle bp <> "\n"
<> T.replicate (T.length (postTitle bp)) "=" <> "\n\n"
<> postAuthor bp <> "\n"
<> postDate bp <> "\n"
<> toS origin <> toS (postUrl bp) <> "\n\n"
writeFile' out (toS (preamble <> toS innerAscii))
allHtmlAction :: Action ()
allHtmlAction = do
allOrgFiles <- getDirectoryFiles srcDir ["//*.org"]
let allHtmlFiles = map (-<.> "html") allOrgFiles
need (map build allHtmlFiles)
allAsciiAction :: Action ()
allAsciiAction = do
allOrgFiles <- getDirectoryFiles srcDir ["//*.org"]
let allAsciiFiles = map (-<.> "txt") allOrgFiles
need (map build allAsciiFiles)
compressImage :: FilePath -> Action ()
compressImage img = do
let src = srcDir </> img
dst = siteDir </> img
need [src]
let dir = takeDirectory dst
dirExists <- doesDirectoryExist dir
when (not dirExists) $
command [] "mkdir" ["-p", dir]
command_ [] "convert" [ src
, "-strip"
, "-resize","320x320>"
, "-interlace","Plane"
, "-quality","85"
, "-define","filter:blur=0.75"
, "-filter","Gaussian"
, "-ordered-dither","o4x4,4"
, dst ]
needAll = do
allAssets <- filter (/= ".DS_Store") <$> getDirectoryFiles srcDir ["**"]
need (map build $ allAssets <> ["archive.html"])
allHtmlAction
allAsciiAction
allRule :: Rules ()
allRule = phony "all" needAll
fullRule :: Rules ()
fullRule = phony "full" $ need [optimDir </> "rss.xml"]
cleanRule :: Rules ()
cleanRule =
phony "clean" $ do
putInfo "Cleaning files in _site and _optim"
forM_ [siteDir,optimDir] $ flip removeFilesAfter ["**"]
mkGetTemplate :: Rules (FilePath -> Action Template)
mkGetTemplate = newCache $ \path -> do
fileContent <- readFile' path
let res = compileMustacheText "page" (toS fileContent)
case res of
Left _ -> fail "BAD"
Right template -> return template
tocRequested :: Text -> Bool
tocRequested fc =
let toc = fc & T.lines
& map T.toLower
& filter (T.isPrefixOf (T.pack "#+options: "))
& head
& fmap (filter (T.isPrefixOf (T.pack "toc:")) . T.words)
in toc == Just ["toc:t"]
mkGetPost :: Rules (FilePath -> Action BlogPost)
mkGetPost = newCache $ \path -> do
fileContent <- readFile' path
let toc = tocRequested (toS fileContent)
eitherResult <- liftIO $ Pandoc.runIO $ Readers.readOrg (def { readerStandalone = True }) (toS fileContent)
case eitherResult of
Left _ -> fail "BAD"
Right pandoc -> getBlogpostFromMetas path toc pandoc
mkGetPosts :: (FilePath -> Action b) -> Rules (() -> Action [b])
mkGetPosts getPost =
newCache $ \() -> mapM getPost =<< getDirectoryFiles "" ["src/posts//*.org"]

2
_optim/.gitignore vendored
View file

@ -1,2 +0,0 @@
*
!.gitignore

2
_site/.gitignore vendored
View file

@ -1,2 +0,0 @@
*
!.gitignore

3
build.sh Executable file
View file

@ -0,0 +1,3 @@
#!/bin/sh
mkdir -p _shake
ghc --make Shakefile.hs -rtsopts -threaded -with-rtsopts=-I0 -outputdir=_shake -o _shake/build && _shake/build "$@"

View file

@ -1,9 +1,3 @@
#!/usr/bin/env bash
cd "$(git rev-parse --show-toplevel)" || exit 1
echo "* org-publish"
emacs -nw \
--load project.el \
--eval "(progn (org-publish \"blog\") (evil-quit))"
echo "* org-publish [done]"
#!/bin/sh
mkdir -p _shake
ghc --make Shakefile.hs -rtsopts -threaded -with-rtsopts=-I0 -outputdir=_shake -o _shake/build && _shake/build "$@"

View file

@ -1,9 +1,3 @@
#!/usr/bin/env nix-shell
#!nix-shell --pure
#!nix-shell -i bash
#!nix-shell -I nixpkgs="https://github.com/NixOS/nixpkgs/archive/19.09.tar.gz"
#!nix-shell -p bash minify
# nix-shell -p nodePackages.clean-css
#!/usr/bin/env bash
minify "$1" > "$2"

View file

@ -1,6 +1,4 @@
#!/usr/bin/env nix-shell
#!nix-shell -i zsh
#!nix-shell -I nixpkgs="https://github.com/NixOS/nixpkgs/archive/19.09.tar.gz"
#!/usr/bin/env zsh
cd "$(git rev-parse --show-toplevel)" || exit 1

View file

@ -1,6 +1,4 @@
#!/usr/bin/env nix-shell
#!nix-shell -i zsh
#!nix-shell -I nixpkgs="https://github.com/NixOS/nixpkgs/archive/19.09.tar.gz"
#!/usr/bin/env zsh
cd "$(git rev-parse --show-toplevel)" || exit 1
# Directory

View file

@ -1,6 +1,4 @@
#!/usr/bin/env nix-shell
#!nix-shell -i zsh
#!nix-shell -I nixpkgs="https://github.com/NixOS/nixpkgs/archive/19.09.tar.gz"
#!/usr/bin/env zsh
cd "$(git rev-parse --show-toplevel)" || exit 1
webdir="_optim"

View file

@ -1,6 +1,4 @@
#!/usr/bin/env nix-shell
#!nix-shell -i zsh
#!nix-shell -I nixpkgs="https://github.com/NixOS/nixpkgs/archive/19.09.tar.gz"
#!/usr/bin/env zsh
cd "$(git rev-parse --show-toplevel)" || exit 1
webdir="_optim"

View file

@ -1,11 +0,0 @@
# { pkgs ? import <nixpkgs> {} }:
{ pkgs ? import (fetchTarball https://github.com/NixOS/nixpkgs/archive/19.09.tar.gz) {} }:
pkgs.mkShell {
buildInputs = [ pkgs.coreutils
pkgs.html-xml-utils
pkgs.zsh
pkgs.perl
pkgs.perlPackages.URI
pkgs.minify
];
}

View file

@ -1,6 +1,4 @@
#!/usr/bin/env nix-shell
#!nix-shell -i zsh
#!nix-shell -I nixpkgs="https://github.com/NixOS/nixpkgs/archive/19.09.tar.gz"
#!/usr/bin/env zsh
cd "$(git rev-parse --show-toplevel)" || exit 1
webdir="_optim"
@ -31,7 +29,7 @@ for fic in $filelist; do
htmlsize=$(sizeof $fic)
debug HTML: $htmlsize
gzhtmlsize=$( gzip -c $fic|wc -c )
debug GZHTML: $gzhtmlsize

38
nix/sources.json Normal file
View file

@ -0,0 +1,38 @@
{
"niv": {
"branch": "master",
"description": "Easy dependency management for Nix projects",
"homepage": "https://github.com/nmattia/niv",
"owner": "nmattia",
"repo": "niv",
"rev": "f73bf8d584148677b01859677a63191c31911eae",
"sha256": "0jlmrx633jvqrqlyhlzpvdrnim128gc81q5psz2lpp2af8p8q9qs",
"type": "tarball",
"url": "https://github.com/nmattia/niv/archive/f73bf8d584148677b01859677a63191c31911eae.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"nixpkgs": {
"branch": "nixpkgs-unstable",
"description": "A read-only mirror of NixOS/nixpkgs tracking the released channels. Send issues and PRs to",
"homepage": "https://github.com/NixOS/nixpkgs",
"owner": "NixOS",
"repo": "nixpkgs-channels",
"rev": "a84cbb60f0296210be03c08d243670dd18a3f6eb",
"sha256": "04j07c98iy66hpzha7brz867dcl9lkflck43xvz09dfmlvqyzmiz",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs-channels/archive/a84cbb60f0296210be03c08d243670dd18a3f6eb.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"shake": {
"branch": "master",
"description": "Shake build system",
"homepage": "http://shakebuild.com",
"owner": "ndmitchell",
"repo": "shake",
"rev": "4536d9ce5cef0e56395fd61ccef9816c9b420fd1",
"sha256": "1s7hjhcc09l026jaca3ndbb103s9d7qlx4vqzx2s6j4rr751nd70",
"type": "tarball",
"url": "https://github.com/ndmitchell/shake/archive/4536d9ce5cef0e56395fd61ccef9816c9b420fd1.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
}
}

134
nix/sources.nix Normal file
View file

@ -0,0 +1,134 @@
# This file has been generated by Niv.
let
#
# The fetchers. fetch_<type> fetches specs of type <type>.
#
fetch_file = pkgs: spec:
if spec.builtin or true then
builtins_fetchurl { inherit (spec) url sha256; }
else
pkgs.fetchurl { inherit (spec) url sha256; };
fetch_tarball = pkgs: spec:
if spec.builtin or true then
builtins_fetchTarball { inherit (spec) url sha256; }
else
pkgs.fetchzip { inherit (spec) url sha256; };
fetch_git = spec:
builtins.fetchGit { url = spec.repo; inherit (spec) rev ref; };
fetch_builtin-tarball = spec:
builtins.trace
''
WARNING:
The niv type "builtin-tarball" will soon be deprecated. You should
instead use `builtin = true`.
$ niv modify <package> -a type=tarball -a builtin=true
''
builtins_fetchTarball { inherit (spec) url sha256; };
fetch_builtin-url = spec:
builtins.trace
''
WARNING:
The niv type "builtin-url" will soon be deprecated. You should
instead use `builtin = true`.
$ niv modify <package> -a type=file -a builtin=true
''
(builtins_fetchurl { inherit (spec) url sha256; });
#
# Various helpers
#
# The set of packages used when specs are fetched using non-builtins.
mkPkgs = sources:
let
sourcesNixpkgs =
import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) {};
hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
hasThisAsNixpkgsPath = <nixpkgs> == ./.;
in
if builtins.hasAttr "nixpkgs" sources
then sourcesNixpkgs
else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
import <nixpkgs> {}
else
abort
''
Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
add a package called "nixpkgs" to your sources.json.
'';
# The actual fetching function.
fetch = pkgs: name: spec:
if ! builtins.hasAttr "type" spec then
abort "ERROR: niv spec ${name} does not have a 'type' attribute"
else if spec.type == "file" then fetch_file pkgs spec
else if spec.type == "tarball" then fetch_tarball pkgs spec
else if spec.type == "git" then fetch_git spec
else if spec.type == "builtin-tarball" then fetch_builtin-tarball spec
else if spec.type == "builtin-url" then fetch_builtin-url spec
else
abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
# Ports of functions for older nix versions
# a Nix version of mapAttrs if the built-in doesn't exist
mapAttrs = builtins.mapAttrs or (
f: set: with builtins;
listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
);
# fetchTarball version that is compatible between all the versions of Nix
builtins_fetchTarball = { url, sha256 }@attrs:
let
inherit (builtins) lessThan nixVersion fetchTarball;
in
if lessThan nixVersion "1.12" then
fetchTarball { inherit url; }
else
fetchTarball attrs;
# fetchurl version that is compatible between all the versions of Nix
builtins_fetchurl = { url, sha256 }@attrs:
let
inherit (builtins) lessThan nixVersion fetchurl;
in
if lessThan nixVersion "1.12" then
fetchurl { inherit url; }
else
fetchurl attrs;
# Create the final "sources" from the config
mkSources = config:
mapAttrs (
name: spec:
if builtins.hasAttr "outPath" spec
then abort
"The values in sources.json should not have an 'outPath' attribute"
else
spec // { outPath = fetch config.pkgs name spec; }
) config.sources;
# The "config" used by the fetchers
mkConfig =
{ sourcesFile ? ./sources.json
, sources ? builtins.fromJSON (builtins.readFile sourcesFile)
, pkgs ? mkPkgs sources
}: rec {
# The sources, i.e. the attribute set of spec name to spec
inherit sources;
# The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
inherit pkgs;
};
in
mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }

View file

@ -1,447 +0,0 @@
;; sign it with
;; gpg --local-user yann@esposito.host --output project.el.sig --detach-sign project.el
(defvar websiteorigin "https://her.esy.fun")
(defvar root-dir (projectile-project-root))
(defvar base-dir (concat root-dir "src"))
(defvar publish-dir (concat root-dir "_site"))
(defvar draft-publish-dir (concat root-dir "_full"))
(defvar assets-dir (concat base-dir "/"))
(defvar publish-assets-dir (concat publish-dir "/"))
(defvar draft-publish-assets-dir (concat draft-publish-dir "/"))
(defvar posts-dir (concat base-dir "/posts"))
(defvar rss-title "Subscribe to articles")
(defvar css-path "/css/y.css")
(defvar author-name "Yann Esposito")
(defvar author-email "yann@esposito.host")
(require 'org)
(require 'ox-publish)
(require 'ox-html)
(require 'org-element)
;; (setq org-link-file-path-type 'relative)
(setq org-publish-timestamp-directory
(concat (projectile-project-root) "_cache/"))
(defvar org-blog-head
(concat
"<link rel=\"stylesheet\" href=\"" css-path "\"/>"
"<link rel=\"alternate\" type=\"application/rss+xml\" href=\"/rss.xml\" />"
"<link rel=\"icon\" href=\"/favicon.ico\">"))
(defun menu (lst)
"Blog menu"
(concat
"<nav>"
(mapconcat 'identity
(append
'("<a href=\"/index.html\">Home</a>"
"<a href=\"/archive.html\">Posts</a>"
"<a href=\"/slides.html\">Slides</a>"
"<a href=\"/about-me.html\">About</a>
<span class=\"details\">
(<a href=\"https://gitea.esy.fun/yogsototh\">code</a>
<a href=\"https://espial.esy.fun/u:yogsototh\">bookmarks</a>
<a href=\"https://espial.esy.fun/u:yogsototh/notes\">notes</a>)</span>")
lst)
" | ")
"</nav>"))
(defun get-from-info (info k)
(let ((i (car (plist-get info k))))
(when (and i (stringp i))
i)))
(defun logo ()
(concat
"<div id=\"logo\">"
"<a href=\"/\">"
"<svg width=\"5em\" viewBox=\"0 0 64 64\">"
"<circle cx=\"32\" cy=\"32\" r=\"30\" stroke=\"var(--b2)\" stroke-width=\"2\" fill=\"var(--b03)\"/>"
"<circle cx=\"32\" cy=\"32\" r=\"12\" stroke=\"var(--r)\" stroke-width=\"2\" fill=\"var(--o)\"/>"
"<circle cx=\"32\" cy=\"32\" r=\"6\" stroke-width=\"0\" fill=\"var(--y)\"/>"
"<ellipse cx=\"32\" cy=\"14\" rx=\"14\" ry=\"8\" stroke-width=\"0\" fill=\"var(--b3)\"/>"
"</svg>"
"</a>"
"</div>"))
(defun relative-link (output-file)
"Given an output-file generate a link relative to the URL origin."
(replace-regexp-in-string ".*/_site" "" output-file))
(defun gen-permalink (output-file)
"Given the output-file generate a permalink"
(format "%s%s"
websiteorigin
(relative-link output-file)))
(defun gen-org-src (permalink)
"Given a permalink generate the path to the asssociated .org source file"
(replace-regexp-in-string "\.html$" ".org" permalink))
(defun org-blog-preamble (info)
"Pre-amble for whole blog."
(concat
(logo)
"<div class=\"content\">"
"<h1>"
(format "%s" (car (plist-get info :title)))
"</h1>"
(when-let ((subtitle (car (plist-get info :subtitle))))
(format "<h2>%s</h2>" subtitle))
(when-let ((date (plist-get info :date)))
(concat
"<div class=\"author\">"
"Yann Esposito"
"<br/>"
(format "<span class=\"article-date\">%s</span>"
(format-time-string "%Y-%m-%d"
(org-timestamp-to-time
(car date))))
"<br/>on "
(format " <a href=\"%s\">Yann Esposito's blog</a>" websiteorigin)
(let ((permalink (gen-permalink (plist-get info :output-file))))
(concat
" - "
(let ((orgfile (gen-org-src permalink)))
(format " <a href=\"%s\">source</a>" orgfile))
" - "
(format " <a class=\"permalink\" href=\"%s\">§permalink</a>" permalink)))
"</div>"))
(when-let ((description (plist-get info :description)))
(format "<div class=\"abstract\">%s</div>" description))
"</div>"))
(defun rand-obfs (c)
(let ((r (% (random) 20)))
(cond ;; ((eq 0 r) (format "%c" c))
((<= 0 r 10) (format "&#%d;" c))
(t (format "&#x%X;" c)))))
(defun obfuscate-html (txt)
(apply 'concat
(mapcar 'rand-obfs txt)))
(defun keywords-to-html (keywords)
(let ((keywords (split-string keywords ",\s*")))
(format " <span class=\"keywords\">%s</span>"
(mapconcat (lambda (k)
(format "<code>#%s</code>" k))
(cl-sort keywords 'string-lessp :key 'downcase)
" "))))
(defun org-blog-postamble (info)
"Post-amble for whole blog."
(concat
"<div class=\"content\">"
;; TODO install a comment system
;; (let ((url (format "%s%s" websiteorigin (replace-regexp-in-string base-dir "" (plist-get info :input-file)))))
;; (format "<a href=\"https://comments.esy.fun/slug/%s\">comment</a>"
;; (url-hexify-string url)))
"<footer>"
(let* ((author (when-let ((author (get-from-info info :author)))
(if-let ((email (plist-get info :email)))
(let* ((obfs-email (obfuscate-html email))
(obfs-author (obfuscate-html author))
(obfs-title (obfuscate-html (get-from-info info :title)))
(full-email (format "%s &lt;%s&gt;" obfs-author obfs-email)))
(format "<span class=\"author\"><a href=\"%s%s%s%s\">%s</a></span>"
(obfuscate-html "mailto:")
full-email
(obfuscate-html "?subject=yblog: ")
obfs-title
full-email))
(format "<span class=\"author\">%s</span>" author))))
(date (when-let ((date (get-from-info info :date)))
(format "<div class=\"date\">Created: %s (%s)</div>" date (y-date date))))
(keywords (when-let ((keywords (plist-get info :keywords)))
(keywords-to-html keywords)))
(rss
(concat
"<div class=\"rss\">"
"<a rel=\"alternate\""
" type=\"application/rss+xml\""
" href=\"/rss.xml\">"
"RSS"
"</a>"
" (<a href=\"https://validator.w3.org/feed/check.cgi?url=https%3A%2F%2Fher.esy.fun%2Frss.xml\">"
"validate</a>)"
"</div>"))
(generated-date
(format "<div class=\"date\">%s</div>"
(format-time-string "%Y-%m-%d %H:%M:%S")))
(size
"<div class=\"web-file-size\">XXK (html XXK, css XXK, img XXK)</div>")
(gzsize
"<div class=\"gzweb-file-size\">XXK (html XXK, css XXK, img XXK)</div>")
(generated-with
(format (concat "<div class=\"creator\">"
"<a href=\"https://www.gnu.org/software/emacs/\" target=\"_blank\" rel=\"noopener noreferrer\">Emacs %s</a>, "
"<a href=\"http://spacemacs.org\" target=\"_blank\" rel=\"noopener noreferrer\">Spacemacs %s</a>, "
"<a href=\"http://orgmode.org\" target=\"_blank\" rel=\"noopener noreferrer\">Org Mode %s</a>"
"</div>")
emacs-version spacemacs-version org-version))
(website-code
"<a href=\"https://gitea.esy.fun/yogsototh/her.esy.fun\" target=\"_blank\" rel=\"noopener noreferrer\">Website source code</a>")
(org-src (gen-org-src (relative-link (plist-get info :output-file))))
(org-src-link (format "<a href=\"%s\">%s</a>" org-src org-src)))
(concat
"<i>Any comment? Click on my email below and I'll add it.</i>"
"<table>"
(mapconcat (lambda (entry)
(when (cdr entry)
(format "<tr><td>%s</td><td>%s</td></tr>"
(car entry) (cdr entry))))
`(("author" . ,author)
("date" . ,date)
("tags" . ,keywords)
("rss" . ,rss)
("size" . ,size)
("gz" . ,gzsize)
("generated" . ,generated-date)
("gen-with" . ,generated-with)
("src" . ,website-code)
("org-file" . ,org-src-link))
" ")
"</table>"))
"</footer>"
(menu '("<a href=\"#preamble\">↑ Top ↑</a>"))
"</div>"))
(defun date-format-entry (entry _style project)
"Return string for each ENTRY in PROJECT."
(when (string-match "posts/.*" entry)
(let* ((file (org-publish--expand-file-name entry project))
(title (org-publish-find-title entry project))
(artdate (format-time-string "%Y-%m-%d" (org-publish-find-date entry project)))
(description (org-publish-find-property entry :description project 'html)))
(concat
(format " @@html:<span class=\"metas\">%s</span>@@: " artdate)
(format " *[[file:%s][%s]]*" file title)
(format " @@html:<div class=\"description\">%s</div>@@" description)
(format " @@html:<div class=\"metas\">@@ ")
" @@html:</div>@@\n"))))
(defun org-blog-sitemap-fn-descr (_descr title list)
"Return sitemap using TITLE and LIST returned by `org-blog-sitemap-format-entry'."
(concat "#+TITLE: " title "\n"
"#+AUTHOR: " author-name "\n"
"#+EMAIL: " author-email "\n"
(concat "@@html:" (menu '()) "@@")
"\n\n"
(mapconcat (lambda (li) (format "%s" (car li)))
(seq-filter #'car (cdr list))
"\n")))
(defun org-blog-prepare (project-plist)
"With help from `https://github.com/howardabrams/dot-files'.
Touch `archive.org' to rebuilt it.
Argument `PROJECT-PLIST' contains information about the current project."
(let* ((base-directory (plist-get project-plist :base-directory))
(buffer (find-file-noselect (expand-file-name "archive.org" base-directory) t)))
(with-current-buffer buffer
(set-buffer-modified-p t)
(save-buffer 0))
(kill-buffer buffer)))
(defun org-blog-publish-to-html (plist filename pub-dir)
"Same as `org-html-publish-to-html' but modifies html before finishing."
(let* ((file-path (org-html-publish-to-html plist filename pub-dir))
(mk-path (format "./%s.html"
(replace-regexp-in-string ".*/\\([^/]*\\)\\.org$"
"\\1"
filename))))
(with-current-buffer (find-file-noselect file-path)
(goto-char (point-min))
(search-forward "<body>")
(insert (mapconcat 'identity
`("<input name=\"t\" type=\"radio\" id=\"l\">"
"<input name=\"t\" type=\"radio\" id=\"d\">"
"<div id=\"labels\">"
"<div class=\"content\">"
"<label for=\"l\">light</label>"
"|"
"<label for=\"d\">dark</label>"
"</div>"
"</div>"
"<div class=\"main\">")
"\n"))
(goto-char (point-max))
(search-backward "</body>")
(insert "\n</div>\n")
(save-buffer)
(kill-buffer))
file-path))
(defun compress-image (filename dst-file)
"Compress images using imagemagick"
(shell-command
(format
(concat
"~/.nix-profile/bin/convert"
" %s" ;; source
" -sampling-factor 4:2:0"
" -strip"
" -resize 320x320\\>"
" -interlace Plane"
" -quality 85"
" -define filter:blur=0.75"
" -filter Gaussian"
" -ordered-dither o4x4,4"
" %s" ;; dest
)
filename
dst-file)))
(defun compress-css (root-dir filename dst-file)
"Compress CSS usin compresscss.sh script"
(shell-command
(format "%s/engine/compresscss.sh %s %s" root-dir filename dst-file)))
(defun org-blog-publish-attachment (plist filename pub-dir)
"Publish a file with no transformation of any kind.
FILENAME is the filename of the Org file to be published. PLIST
is the property list for the given project. PUB-DIR is the
publishing directory.
Take care of minimizing the pictures using imagemagick.
Return output file name."
(unless (file-directory-p pub-dir)
(make-directory pub-dir t))
(or (equal (expand-file-name (file-name-directory filename))
(file-name-as-directory (expand-file-name pub-dir)))
(let ((dst-file (expand-file-name (file-name-nondirectory filename) pub-dir)))
(cond ((string-match-p ".*\\.\\(png\\|jpg\\|jpeg\\|gif\\)$" filename)
(compress-image filename dst-file))
((string-match-p ".*\\.css$" filename)
(compress-css root-dir filename dst-file))
(t (copy-file filename dst-file t))))))
(defalias 'org-blog-posts-sitemap-fn
(apply-partially 'org-blog-sitemap-fn-descr ""))
(setq org-html-htmlize-output-type 'css)
(setq org-html-htmlize-font-prefix "org-")
(setq org-publish-project-alist
`(("orgfiles"
:base-directory ,base-dir
:exclude ".*drafts/.*"
:base-extension "org"
:publishing-directory ,publish-dir
:recursive t
:preparation-function org-blog-prepare
:publishing-function org-blog-publish-to-html
:with-toc nil
:with-title nil
:with-date t
:section-numbers nil
:html-doctype "html5"
:html-html5-fancy t
:html-head-include-default-style nil
:html-head-include-scripts nil
:htmlized-source t
:html-head-extra ,org-blog-head
:html-preamble org-blog-preamble
:html-postamble org-blog-postamble
:auto-sitemap t
:sitemap-filename "archive.org"
:sitemap-title "Articles"
:sitemap-style list
:sitemap-sort-files anti-chronologically
:sitemap-format-entry date-format-entry
:sitemap-function org-blog-posts-sitemap-fn)
("css"
:base-directory ,assets-dir
:base-extension "css"
:publishing-directory ,publish-assets-dir
:publishing-function org-blog-publish-attachment
:recursive t)
("img"
:base-directory ,assets-dir
:base-extension "(jpg|png|gif|jpeg)"
:publishing-directory ,publish-assets-dir
:publishing-function org-blog-publish-attachment
:recursive t)
("files"
:base-directory ,assets-dir
:base-extension ".*"
:exclude ".*\.(org|css|jpg|png|gif|jpeg)$"
:publishing-directory ,publish-assets-dir
:publishing-function org-blog-publish-attachment
:recursive t)
("draft-org-files"
:base-directory ,base-dir
:base-extension "org"
:publishing-directory ,draft-publish-dir
:recursive t
:preparation-function org-blog-prepare
:publishing-function org-blog-publish-to-html
:with-toc nil
:with-title nil
:with-date t
:section-numbers nil
:html-doctype "html5"
:html-html5-fancy t
:html-head-include-default-style nil
:html-head-include-scripts nil
:htmlized-source t
:html-head-extra ,org-blog-head
:html-preamble org-blog-preamble
:html-postamble org-blog-postamble)
("draft-css"
:base-directory ,assets-dir
:base-extension "css"
:publishing-directory ,draft-publish-assets-dir
:publishing-function org-blog-publish-attachment
:recursive t)
("draft-img"
:base-directory ,assets-dir
:base-extension "(jpg|png|gif|jpeg)"
:publishing-directory ,draft-publish-assets-dir
:publishing-function org-blog-publish-attachment
:recursive t)
("draft-files"
:base-directory ,assets-dir
:base-extension ".*"
:include ".*\.(org|css|jpg|png|gif|jpeg)$"
:publishing-directory ,draft-publish-assets-dir
:publishing-function org-blog-publish-attachment
:recursive t)
("assets" :components ("css" "img" "files"))
("blog" :components ("orgfiles" "assets"))
("draft-assets" :components ("draft-css" "draft-img" "draft-files"))
("draft" :components ("draft-org-files" "draft-assets"))))
;; add target=_blank and rel="noopener noreferrer" to all links by default
(defun my-org-export-add-target-blank-to-http-links (text backend info)
"Add target=\"_blank\" to external links."
(when (and
(org-export-derived-backend-p backend 'html)
(string-match "href=\"http[^\"]+" text)
(not (string-match "target=\"" text))
(not (string-match (concat "href=\"" websiteorigin "[^\"]*") text)))
(string-match "<a " text)
(replace-match "<a target=\"_blank\" rel=\"noopener noreferrer\" " nil nil text)))
(add-to-list 'org-export-filter-link-functions
'my-org-export-add-target-blank-to-http-links)
(defun my-add-link-to-tangled-files (backend)
"Add a link just before source code block with tangled files.
BACKEND is the export backend. Used as symbol."
(while ;; (re-search-forward )
(re-search-forward "^\\( *\\)#\\+begin_src .*:tangle \\([^\s\n]*\\)" nil t)
(replace-match "\\1#+CAPTION: [[./\\2][=\\2=]]\n\\&")))
(setq org-export-before-processing-hook nil)
(add-hook 'org-export-before-processing-hook
'my-add-link-to-tangled-files)
(provide 'her-esy-fun-publish)

Binary file not shown.

View file

@ -1,15 +1,32 @@
# { pkgs ? import <nixpkgs> {} }:
{ pkgs ? import (fetchTarball https://github.com/NixOS/nixpkgs/archive/19.09.tar.gz) {} }:
let my_aspell = pkgs.aspellWithDicts(p: with p; [en fr]);
in
pkgs.mkShell {
buildInputs = [ pkgs.coreutils
pkgs.html-xml-utils
pkgs.zsh
pkgs.perl
pkgs.perlPackages.URI
pkgs.minify
pkgs.haskellPackages.sws
pkgs.cacert
];
let
sources = import ./nix/sources.nix;
pkgs = import sources.nixpkgs {};
pkgs1909 = import (fetchTarball https://github.com/NixOS/nixpkgs/archive/19.09.tar.gz) {};
haskellDeps = ps : with ps; [
shake
pandoc
data-default
protolude
pkgs1909.haskellPackages.sws
stache
];
ghc = pkgs.haskellPackages.ghcWithPackages haskellDeps;
in
pkgs.mkShell {
buildInputs = with pkgs;
[ cacert
coreutils
html-xml-utils
zsh
perl
perlPackages.URI
minify
niv
ghc
git
direnv
haskellPackages.shake
# for emacs dev
ripgrep
];
}

View file

@ -309,9 +309,6 @@ dl dd {
font-size: 85%;
margin-bottom: 0.4rem;
}
.footnotes {
border-top: 1px solid hsl(0, 0%, 39%);
}
/* Center title and paragraph */
.abstract,
@ -319,7 +316,9 @@ dl dd {
text-align: center;
}
.abstract {
margin: 2.25rem 0;
margin: 2.25rem;
font-size: 0.85rem;
font-style: italic;
}
/* Format the LaTeX symbol correctly (a higher up, e lower) */
@ -430,6 +429,7 @@ footer { margin: 3em 0;
border-bottom: solid 1px;
line-height: 1em;
font-size: 0.85em;
text-align: center;
}
td { border-bottom: none; padding: .2rem; }
table { margin-top: 1rem; }
@ -554,17 +554,20 @@ body, body > div {
}
a,a:visited { color: var(--hl); }
figcaption { color: var(--fg0); }
/* ---- SYNTAX HIGHLIGHTING ---- */
#table-of-contents { text-align: left; }
.org-rainbow-delimiters-depth-1, .org-rainbow-delimiters-depth-9,
.org-css-selector, .org-builtin,
.IN_REVIEW {
.IN_REVIEW, .ex {
color:var(--c);
}
.org-rainbow-delimiters-depth-2, .org-nix-builtin, .org-variable-name,
.org-haskell-definition, .org-haskell-operator, .org-function-name, .org-diff-changed,
.org-nix-attribute, .org-nxml-element-local-name {
.org-nix-attribute, .org-nxml-element-local-name, .op, .fu, .ot {
color:var(--b);
}
@ -573,21 +576,21 @@ a,a:visited { color: var(--hl); }
}
.org-rainbow-delimiters-depth-4, .org-diff-hunk-header, .org-sh-quoted-exec,
.CANCELED {
.CANCELED, .bu {
color:var(--m);
}
.org-rainbow-delimiters-depth-5, .org-diff-removed, .TODO {
color:var(--r);
}
.org-rainbow-delimiters-depth-6, .org-haskell-constructor {
.org-rainbow-delimiters-depth-6, .org-haskell-constructor, .dt {
color:var(--o);
}
.org-rainbow-delimiters-depth-7, .org-type, .org-constant, .org-diff-header,
.org-haskell-keyword, .org-haskell-type, .IN_PROGRESS {
.org-haskell-keyword, .org-haskell-type, .IN_PROGRESS, .kw {
color:var(--y);
}
.org-rainbow-delimiters-depth-8, .org-sh-heredoc, .org-diff-added, .org-string,
.org-doc, .org-keyword, .DONE {
.org-doc, .org-keyword, .DONE, .st {
color:var(--g);
}
@ -595,6 +598,6 @@ a,a:visited { color: var(--hl); }
.org-diff-none, .org-preprocessor, .org-comment-delimiter, .org-comment,
.org-outshine-level-1, .org-outshine-level-2, .org-outshine-level-3,
.org-outshine-level-4, .org-outshine-level-5, .org-outshine-level-6,
.org-outshine-level-7, .org-outshine-level-8, .org-outshine-level-9 {
.org-outshine-level-7, .org-outshine-level-8, .org-outshine-level-9, .co {
color:var(--fg0);
}

View file

@ -93,7 +93,8 @@ k l m n o p q r s t u v w x y z
:PROPERTIES:
:CUSTOM_ID: math
:END:
Let also try to write some math inside the text $\pi_1(X,x_0)$
Let also try to write some math inside the text $\pi_1(X,x_0)$.
In the middle of the text again $x$ and $x_i\times 0$.
\(x^y / \log(x)\)
@ -344,9 +345,9 @@ After the rule.
an image:
#+ATTR_HTML: The Experiment
#+CAPTION: Testing include an image
#+NAME: fig:test-image
#+ATTR_HTML: The Experiment
[[../img/a.png]]

View file

@ -3,9 +3,7 @@
#+Email: yann@esposito.host
#+Date: [2020-06-14 Sun]
#+KEYWORDS: nix, programming
#+DESCRIPTION: In this article I explain how I use nix.
#+DESCRIPTION: As a brew replacement, as home environment manager,
#+DESCRIPTION: to have reproductible dev environment.
#+DESCRIPTION: In this article I explain how I use nix. As a brew replacement, as home environment manager, to have reproductible dev environment.
#+LANGUAGE: en
#+LANG: en
#+OPTIONS: H:5 auto-id:t toc:nil
@ -295,7 +293,6 @@ Typically for Haskell projects.
[fn:direnv] https://direnv.net
[fn:lorri] https://github.com/target/lorri
** Install
:PROPERTIES:
:CUSTOM_ID: install

View file

@ -48,8 +48,7 @@ priority:
referrer for all external links, etc...)
{{{br}}}
{{{br}}}
2. *Almost javascript free*; no js at all except for a single exception,
pages containing Math formulæ are displayed using mathjax.
2. *javascript free*; no js at all (math is rendered with MathML).
{{{br}}}
{{{br}}}
3. *Accessibility*; should be easy to read on a text browser so people with
@ -62,6 +61,3 @@ priority:
5. *Frugal*; try to minimize the resources needed to visit my website; no
javascript, no web-font, not too much CSS magic, not much images or really
compressed one.
If you are interested about technical details behind this website, take a
look [[file:./posts/new-blog.org][here]].

View file

@ -44,9 +44,9 @@ goblins.
Those costume looks very bad and cheap.
So much you can only find them not terrorizing but funny and ridiculous.
#+ATTR_HTML: A goblin
#+CAPTION: One goblin during the introduction scene of Troll 2
#+NAME: fig:troll-2-intro
#+ATTR_HTML: A goblin
[[./Troll-2-intro.jpg]]
Soon after that, you realize the acting of all actors is extremely bad.
@ -55,9 +55,9 @@ To give you an idea, the only equal bad acting I ever witnessed was while
looking at amateurs first Youtube movies trying to follow a scenario.
Apparently most actors were amateurs, it was their first and last movie.
#+ATTR_HTML: A bad acting demonstration
#+CAPTION: One particularly terrible acting scene
#+NAME: fig:bad-acting
#+ATTR_HTML: A bad acting demonstration
[[file:bad-acting.png]]
The dialog are, really something...
@ -83,9 +83,9 @@ They win against the monsters with, what I believe was a failed attempt at
humor.
It misses the point so bad, that the irony still make it funny.
#+ATTR_HTML: Eliott prevents his family to eat the food by urinating on the table
#+CAPTION: Our hero save the day by urinating on the table. His family is frozen for 30s said grandpa, they were for 70s.
#+NAME: fig:prevent-eating
#+ATTR_HTML: Eliott prevents his family to eat the food by urinating on the table
[[./prevent-eating-scene.jpg]]
Of course, the very last scene is a classical so terrible cliché.

View file

@ -4,13 +4,7 @@
#+author: Yann Esposito
#+EMAIL: yann@esposito.host
#+keywords: Haskell, programming, functional, tutorial
#+DESCRIPTION: A short and intense introduction to Haskell.
#+DESCRIPTION: This is an update of my old (2012) article.
#+DESCRIPTION: A lot of things have changed since then.
#+DESCRIPTION: Mostly I changed my approach about the easiest way to install
#+DESCRIPTION: a Haskell playground.
#+DESCRIPTION: I removed the not as important part, and added a short
#+DESCRIPTION: introduction about starting a new project.
#+DESCRIPTION: A short and intense introduction to Haskell. This is an update of my old (2012) article. A lot of things have changed since then. Mostly I changed my approach about the easiest way to install a Haskell playground. I removed the not as important part, and added a short introduction about starting a new project.
#+OPTIONS: auto-id:t toc:t
#+STARTUP: overview
@ -178,32 +172,32 @@ Otherwise, you can follow my advice to use nix:
4. Put the following =shell.nix= file inside it
#+begin_src nix :tangle shell.nix
{ nixpkgs ? import (fetchTarball https://github.com/NixOS/nixpkgs/archive/19.09.tar.gz) {} }:
let
inherit (nixpkgs) pkgs;
inherit (pkgs) haskellPackages;
haskellDeps = ps: with ps; [
base
protolude
containers
];
ghc = haskellPackages.ghcWithPackages haskellDeps;
nixPackages = [
ghc
pkgs.gdb
haskellPackages.cabal-install
];
in
pkgs.stdenv.mkDerivation {
name = "env";
buildInputs = nixPackages;
shellHook = ''
export PS1="\n\[[hs:\033[1;32m\]\W\[\033[0m\]]> "
'';
}
{ nixpkgs ? import (fetchTarball https://github.com/NixOS/nixpkgs/archive/19.09.tar.gz) {} }:
let
inherit (nixpkgs) pkgs;
inherit (pkgs) haskellPackages;
haskellDeps = ps: with ps; [
base
protolude
containers
];
ghc = haskellPackages.ghcWithPackages haskellDeps;
nixPackages = [
ghc
pkgs.gdb
haskellPackages.cabal-install
];
in
pkgs.stdenv.mkDerivation {
name = "env";
buildInputs = nixPackages;
shellHook = ''
export PS1="\n\[[hs:\033[1;32m\]\W\[\033[0m\]]> "
'';
}
#+end_src
5. In the =hsenv= directory, in a terminal, run =nix-shell --pure=.
@ -219,11 +213,11 @@ pkgs.stdenv.mkDerivation {
something like this:
#+begin_src
~/hsenv> nix-shell
[nix-shell:~/hsenv]$ ghci
GHCi, version 8.6.5: http://www.haskell.org/ghc/ :? for help
Prelude> import Protolude
Prelude Protolude>
~/hsenv> nix-shell
[nix-shell:~/hsenv]$ ghci
GHCi, version 8.6.5: http://www.haskell.org/ghc/ :? for help
Prelude> import Protolude
Prelude Protolude>
#+end_src
Congratulations you should be ready to start now.
@ -1492,7 +1486,7 @@ The only way to work around this problem is to use some meta-programming
trick, for example using the pre-processor.
In C++ there is a better way, C++ templates:
#+BEGIN_SRC c++
#+BEGIN_SRC cpp
#include <iostream>
#include <complex>
using namespace std;
@ -3880,9 +3874,7 @@ I will not argue much, but mainly, semantic versionning and Haskell
versionning are just a "right to break things to your users".
I don't want to talk a lot more about this, but, it would be nice if more
people would watch this talk[fn:9] related to versionning.
[fn:9]: [[https://www.youtube.com/watch?v=oyLBGkS5ICk][Spec-ulation Keynote - Rich Hickey]]
people would watch this talk[fn:8] related to versionning.
If you want to know more about Haskell versionning convention:
https://pvp.haskell.org
@ -4082,30 +4074,32 @@ Thank you man.
As of today, the definition of =IO= is no more visible into =base=.
We have the following explanation in [[http://hackage.haskell.org/package/base-4.12.0.0/docs/src/GHC.IO.html][=GHC.IO.hs=]]:
#+begin_quote
#+begin_src
The IO Monad is just an instance of the ST monad, where the state is
the real world. We use the exception mechanism (in GHC.Exception) to
implement IO exceptions.
NOTE: The IO representation is deeply wired in to various parts of the
system. The following list may or may not be exhaustive:
Compiler - types of various primitives in PrimOp.hs
RTS - forceIO (StgStartup.cmm)
- catchzh_fast, (un)?blockAsyncExceptionszh_fast, raisezh_fast
(Exception.cmm)
- raiseAsync (RaiseAsync.c)
Prelude - GHC.IO.hs, and several other places including
GHC.Exception.hs.
Libraries - parts of hslibs/lang.
--SDM
#+end_src
#+begin_src
The IO Monad is just an instance of the ST monad, where the state is
the real world. We use the exception mechanism (in GHC.Exception) to
implement IO exceptions.
NOTE: The IO representation is deeply wired in to various parts of the
system. The following list may or may not be exhaustive:
Compiler - types of various primitives in PrimOp.hs
RTS - forceIO (StgStartup.cmm)
- catchzh_fast, (un)?blockAsyncExceptionszh_fast, raisezh_fast
(Exception.cmm)
- raiseAsync (RaiseAsync.c)
Prelude - GHC.IO.hs, and several other places including
GHC.Exception.hs.
Libraries - parts of hslibs/lang.
--SDM
#+end_src
#+end_quote
[fn:7] Well, you'll certainly need to practice a bit to get used to them
and to understand when you can use them and create your own. But
you already made a big step in this direction.
[fn:8] [[https://www.youtube.com/watch?v=oyLBGkS5ICk][Spec-ulation Keynote - Rich Hickey]]

View file

@ -58,6 +58,7 @@ Here is the CSS you could use:
{{{colorbox(b1,black,#a7abb5)}}}
{{{colorbox(b2,black,#e5e8f0)}}}
{{{colorbox(b3,black,#f3f6fe)}}}
@@html:<br/>@@
{{{colorbox(y,white,#ad8c51)}}}
{{{colorbox(o,white,#a9664b)}}}
{{{colorbox(r,white,#af6256)}}}

View file

@ -3,10 +3,7 @@
#+Email: yann@esposito.host
#+Date: [2020-05-09 Sat]
#+KEYWORDS: emacs, softwares
#+DESCRIPTION: Modern tools tend to disapears.
#+DESCRIPTION: An app on the web will change, and could break for the worst.
#+DESCRIPTION: Quite often investing in long living tools which are harder start
#+DESCRIPTION: with will be worth the investment.
#+DESCRIPTION: Modern tools tend to disapears. An app on the web will change, and could break for the worst. Quite often investing in long living tools which are harder start with will be worth the investment.
#+LANGUAGE: en
#+LANG: en
#+OPTIONS: H:5 auto-id:t
@ -19,8 +16,10 @@ And this week-end, in the morning I read those:
- [[https://news.ycombinator.com/item?id=23107123][Making Emacs popular again]]
- [[https://news.ycombinator.com/item?id=23092904][Github Codespace]]
#+DOWNLOADED: https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Ftse1.mm.bing.net%2Fth%3Fid%3DOIP.g7OSuCGH0u7OIUA9vdxlTAEsCo%26pid%3DApi&f=1 @ 2020-05-09 12:49:34
#+ATTR_HTML: :alt Midsommar Welcome
#+DOWNLOADED: https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Ftse1.mm.bing.net%2Fth%3Fid%3DOIP.g7OSuCGH0u7OIUA9vdxlTAEsCo%26pid%3DApi&f=1 @ 2020-05-09 12:49:34
#+NAME: Welcome
#+CAPTION: Midsommar Welcome
[[file:2020-05-09_12-49-34_.jpeg]]
@ -93,8 +92,9 @@ For the single developers and open source developers this offer:
But the price to pay is hidden.
#+ATTR_HTML: :alt Midsommar Sorrow
#+DOWNLOADED: https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Ftse1.mm.bing.net%2Fth%3Fid%3DOIP.FrCRrhENMjdfD4pUcAwKEgHaEK%26pid%3DApi&f=1 @ 2020-05-09 12:48:31
#+ATTR_HTML: :alt Midsommar Cry
#+CAPTION: Midsommar Sorrow
[[file:2020-05-09_12-48-31_.jpeg]]
@ -178,6 +178,7 @@ future.
:CUSTOM_ID: post-conclusion
:END:
#+ATTR_HTML: :alt Midsommar Joy
#+CAPTION: Midsommar Joy
[[./midsommar-joy.jpeg]]

55
templates/main.mustache Normal file
View file

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{title}}</title>
<meta name="generator" content="ystgen">
<meta name="author" content="{{author}}">
<meta name="keywords" content="{{#tags}}{{.}} {{/tags}}">
<link rel="stylesheet" href="/css/y.css"/>
<link rel="alternate" type="application/rss+xml" href="/rss.xml" />
<link rel="icon" href="/favicon.ico">
</head>
<body>
<input name="t" type="radio" id="l">
<input name="t" type="radio" id="d">
<div id="labels">
<div class="content">
<label for="l">light</label> | <label for="d">dark</label>
</div>
</div>
<div class="main">
<div id="preamble" class="status">
<div id="logo">
<a href="/">
<svg width="5em" viewBox="0 0 64 64">
<circle cx="32" cy="32" r="30" stroke="var(--b2)" stroke-width="2" fill="var(--b03)"/>
<circle cx="32" cy="32" r="12" stroke="var(--r)" stroke-width="2" fill="var(--o)"/>
<circle cx="32" cy="32" r="6" stroke-width="0" fill="var(--y)"/>
<ellipse cx="32" cy="14" rx="14" ry="8" stroke-width="0" fill="var(--b3)"/>
</svg>
</a>
</div>
<div class="content"><h1>{{title}}</h1></div>
</div>
<div id="content">
{{{ body }}}
</div>
<div id="postamble" class="status">
<div class="content">
<nav>
<a href="/index.html">Home</a> |
<a href="/archive.html">Posts</a> |
<a href="/slides.html">Slides</a> |
<a href="/about-me.html">About</a>
<span class="details"> (<a href="https://gitea.esy.fun/yogsototh">code</a>
<a href="https://espial.esy.fun/u:yogsototh">bookmarks</a>
<a href="https://espial.esy.fun/u:yogsototh/notes">notes</a>)</span> |
<a href="#preamble">↑ Top ↑</a>
</nav>
</div>
</div>
</div>
</body>
</html>

64
templates/post.mustache Normal file
View file

@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{title}}</title>
<meta name="author" content="{{author}}">
<meta name="description" content="{{description}}">
<meta name="keywords" content="{{#tags}}{{.}}{{^last}} {{/last}}{{/tags}}">
<link rel="stylesheet" href="/css/y.css"/><link rel="alternate" type="application/rss+xml" href="/rss.xml" /><link rel="icon" href="/favicon.ico">
</head>
<body><input name="t" type="radio" id="l">
<input name="t" type="radio" id="d">
<div id="labels">
<div class="content">
<label for="l">light</label> | <label for="d">dark</label>
</div>
</div>
<div class="main">
<div id="preamble" class="status">
<div id="logo">
<a href="/">
<svg width="5em" viewBox="0 0 64 64">
<circle cx="32" cy="32" r="30" stroke="var(--b2)" stroke-width="2" fill="var(--b03)"/>
<circle cx="32" cy="32" r="12" stroke="var(--r)" stroke-width="2" fill="var(--o)"/>
<circle cx="32" cy="32" r="6" stroke-width="0" fill="var(--y)"/>
<ellipse cx="32" cy="14" rx="14" ry="8" stroke-width="0" fill="var(--b3)"/>
</svg>
</a>
</div>
<div class="content">
<h1>{{title}}</h1>
<div class="author">{{author}}<br/>
<span class="article-date">{{date}}</span><br/>on
<a href="https://her.esy.fun">Yann Esposito's blog</a> -
<a href="{{orgsource}}">source</a> -
<a href="{{txtsource}}">txt</a> -
<a class="permalink" href="{{permalink}}">§permalink</a>
</div>
<div class="abstract">
{{description}}
</div>
</div>
</div>
<div id="content">
{{{body}}}
</div>
<div id="postamble" class="status">
<div class="content">
<nav>
<a href="/index.html">Home</a> |
<a href="/archive.html">Posts</a> |
<a href="/slides.html">Slides</a> |
<a href="/about-me.html">About</a>
<span class="details"> (<a href="https://gitea.esy.fun/yogsototh">code</a>
<a href="https://espial.esy.fun/u:yogsototh">bookmarks</a>
<a href="https://espial.esy.fun/u:yogsototh/notes">notes</a>)</span> |
<a href="#preamble">↑ Top ↑</a>
</nav>
</div>
</div>
</div>
</body>
</html>