Compare commits

..

1 Commits

Author SHA1 Message Date
James Eversole
3172ca2f59 Add markdown response support 2026-04-23 10:53:56 -05:00
7 changed files with 159 additions and 53 deletions

35
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": {
"haskell-flake": {
"locked": {
"lastModified": 1728845985,
"narHash": "sha256-0KkAWCRBNpno3f+E1rvV9TOr0iuweqncWGn1KtbrGmo=",
"lastModified": 1776783293,
"narHash": "sha256-Na95Y2awqZsLhFNfBNbLj0hk4zyE3eKUROB2o9Qdqi8=",
"owner": "srid",
"repo": "haskell-flake",
"rev": "2393b55948866f39afcfa7d8a53893a096bcd284",
"rev": "f52ac89b2232dd50e5d1110416ebc5bbb09265bd",
"type": "github"
},
"original": {
@@ -17,30 +17,33 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1701282334,
"narHash": "sha256-MxCVrXY6v4QmfTwIysjjaX0XUhqBbxTWWB4HXtDYsdk=",
"lastModified": 1764521362,
"narHash": "sha256-M101xMtWdF1eSD0xhiR8nG8CXRlHmv6V+VoY65Smwf4=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "057f9aecfb71c4437d2b27d3323df7f93c010b7e",
"rev": "871b9fd269ff6246794583ce4ee1031e1da71895",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "23.11",
"ref": "25.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1727825735,
"narHash": "sha256-0xHYkMkeLVQAMa7gvkddbPqpxph+hDzdu1XdGPJR+Os=",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/fb192fec7cc7a4c26d51779e9bab07ce6fa5597a.tar.gz"
"lastModified": 1774748309,
"narHash": "sha256-+U7gF3qxzwD5TZuANzZPeJTZRHS29OFQgkQ2kiTJBIQ=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "333c4e0545a6da976206c74db8773a1645b5870a",
"type": "github"
},
"original": {
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/fb192fec7cc7a4c26d51779e9bab07ce6fa5597a.tar.gz"
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"parts": {
@@ -48,11 +51,11 @@
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1727826117,
"narHash": "sha256-K5ZLCyfO/Zj9mPFldf3iwS6oZStJcU4tSpiXTMYaaL0=",
"lastModified": 1775087534,
"narHash": "sha256-91qqW8lhL7TLwgQWijoGBbiD4t7/q75KTi8NxjVmSmA=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "3d04084d54bedc3d6b8b736c70ef449225c361b1",
"rev": "3107b77cd68437b9a76194f0f7f9c55f2329ca5b",
"type": "github"
},
"original": {

View File

@@ -1,6 +1,6 @@
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/23.11";
nixpkgs.url = "github:nixos/nixpkgs/25.11";
haskell-flake.url = "github:srid/haskell-flake";
parts.url = "github:hercules-ci/flake-parts";
};
@@ -17,7 +17,7 @@
haskellProjects.default = {
basePackages = pkgs.haskellPackages;
packages = {
http2.source = "3.0.3";
http2.source = "5.3.10";
};
devShell = {
enable = true;

View File

@@ -15,23 +15,23 @@ executable sampu
default-extensions: OverloadedStrings
ghc-options: -threaded -rtsopts -with-rtsopts=-N -optl-pthread -fPIC
build-depends: base
, bytestring >= 0.11.5.0
, clay >= 0.14.0
, commonmark >= 0.2.4
, directory >= 1.3.7.0
, dotenv >= 0.11.0.0
, feed >= 1.3.2.0
, filemanip >= 0.3.6.1
, filepath >= 1.4.2.2
, bytestring
, clay
, commonmark
, directory
, dotenv
, feed
, filemanip
, filepath
, http-types
, lucid >= 2.11.0
, text >= 2.0
, time >= 1.12.0
, twain >= 2.1.0.0
, wai-extra >= 3.0 && < 3.2
, wai-middleware-static >= 0.9.0
, warp == 3.3.25
, xml-conduit >= 1.9.1.0
, lucid
, text
, time
, twain
, wai-extra
, wai-middleware-static
, warp
, xml-conduit
hs-source-dirs: src
other-modules: Core.Configuration
Core.Feed

75
scratch/tricu.cabal Normal file
View File

@@ -0,0 +1,75 @@
cabal-version: 1.12
name: tricu
version: 0.19.0
description: A micro-language for exploring Tree Calculus
author: James Eversole
maintainer: james@eversole.co
copyright: James Eversole
license: ISC
license-file: LICENSE
build-type: Simple
extra-source-files:
README.md
executable tricu
main-is: Main.hs
hs-source-dirs:
src
default-extensions:
DeriveDataTypeable
LambdaCase
MultiWayIf
OverloadedStrings
ghc-options: -threaded -rtsopts -with-rtsopts=-N -optl-pthread -fPIC
build-depends:
base >=4.7
, cmdargs
, containers
, exceptions
, filepath
, haskeline
, megaparsec
, mtl
, text
, transformers
other-modules:
Eval
FileEval
Lexer
Parser
REPL
Research
default-language: Haskell2010
test-suite tricu-tests
type: exitcode-stdio-1.0
main-is: Spec.hs
hs-source-dirs: test, src
default-extensions:
DeriveDataTypeable
LambdaCase
MultiWayIf
OverloadedStrings
build-depends:
base
, cmdargs
, containers
, exceptions
, filepath
, haskeline
, megaparsec
, mtl
, tasty
, tasty-hunit
, tasty-quickcheck
, text
, transformers
default-language: Haskell2010
other-modules:
Eval
FileEval
Lexer
Parser
REPL
Research

View File

@@ -5,9 +5,8 @@ import Data.Text
import qualified Data.Text.Lazy as LT
import qualified Text.Atom.Feed as Atom
import qualified Text.Feed.Export as Export (textFeedWith)
import qualified Text.Feed.Export as Export (textFeed)
import Text.Feed.Types
import Text.XML (def, rsPretty)
data Post = Post { _date :: Text
, _url :: Text
@@ -21,7 +20,7 @@ autoFeed baseFeed feedData = baseFeed { Atom.feedEntries = fmap toEntry feedData
-- Render the Atom Feed to Lazy Text
renderFeed :: Atom.Feed -> LT.Text
renderFeed = fromJust . Export.textFeedWith def{rsPretty = True} . AtomFeed
renderFeed = fromJust . Export.textFeed . AtomFeed
-- Convert a Post to an Atom Entry
toEntry :: Post -> Atom.Entry

View File

@@ -10,6 +10,7 @@ import qualified Text.Atom.Feed as Atom
import Control.Monad.IO.Class (liftIO)
import Data.ByteString.Lazy (ByteString)
import qualified Data.Text as T
import qualified Data.Text.Lazy as LT
import qualified Data.Text.Lazy.Encoding as TLE
import Data.Time.Clock (UTCTime(..), getCurrentTime)
import Data.Time.Format (formatTime, defaultTimeLocale)
@@ -24,6 +25,10 @@ import Web.Twain hiding (fileName)
-- A ResponoderM capable of lifting to IO monad; constructs response to clients
index :: ResponderM a
index = do
markdownRequested <- acceptsMarkdown
if markdownRequested
then sendMarkdownFile "./data/posts/home.md"
else do
(title, homeMd, footerMd) <- liftIO $ (,,)
<$> Conf.title
<*> mdFileToLucid "./data/posts/home.md"
@@ -39,6 +44,10 @@ posts = do
case postValid of
False -> missing
True -> do
markdownRequested <- acceptsMarkdown
if markdownRequested
then sendMarkdownFile $ postPath postName
else do
(title, footerMd, postMd) <- liftIO $ (,,)
<$> Conf.title
<*> mdFileToLucid "./data/posts/footer.md"
@@ -104,6 +113,10 @@ feed = do
-- Refer to index comments
contact :: ResponderM a
contact = do
markdownRequested <- acceptsMarkdown
if markdownRequested
then sendMarkdownFile "./data/posts/contact.md"
else do
(title, contactMd, footerMd) <- liftIO $ (,,)
<$> Conf.title
<*> mdFileToLucid "./data/posts/contact.md"
@@ -114,6 +127,19 @@ contact = do
theme :: ResponderM a
theme = send $ css $ TLE.encodeUtf8 $ S.cssRender S.composedStyles
acceptsMarkdown :: ResponderM Bool
acceptsMarkdown = do
acceptHeader <- header "Accept"
return $ maybe False (T.isInfixOf "text/markdown" . T.toLower) acceptHeader
sendMarkdownFile :: FilePath -> ResponderM a
sendMarkdownFile path = do
markdown <- liftIO $ mdFileToMarkdown path
send $ withHeader (hContentType, "text/markdown; charset=utf-8")
$ raw status200 []
$ TLE.encodeUtf8
$ LT.fromStrict markdown
-- Helper function for responding in ResponderM from Html
sendLucidFragment :: Html () -> ResponderM a
sendLucidFragment x = send $ html $ lucidToTwain x

View File

@@ -20,6 +20,9 @@ mdToLucid cmtextinput = case (commonmark "" cmtextinput) of
mdFileToLucid :: FilePath -> IO (LU.Html ())
mdFileToLucid path = fmap (mdToLucid . decodeUtf8) (B.readFile path)
mdFileToMarkdown :: FilePath -> IO Text
mdFileToMarkdown path = fmap decodeUtf8 (B.readFile path)
mdFileToText :: FilePath -> IO (Text)
mdFileToText path = do
htmlContent <- mdFileToLucid path