From f1cb583d0f077ccffd320ace7c92d30287c41872 Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Fri, 26 Sep 2025 22:46:59 +0200 Subject: [PATCH 01/18] Runner base config --- .forgejo/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .forgejo/workflows/ci.yml diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml new file mode 100644 index 0000000..3f7362e --- /dev/null +++ b/.forgejo/workflows/ci.yml @@ -0,0 +1,2 @@ +runs-on: self-hosted + From 20c78cf01545383da3717f4ba26cf843ff5fb874 Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Fri, 26 Sep 2025 22:49:48 +0200 Subject: [PATCH 02/18] Updated ci.yml --- .forgejo/workflows/ci.yml | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 3f7362e..427b75b 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -1,2 +1,34 @@ -runs-on: self-hosted +name: Haskell CI + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + build: + runs-on: self-hosted + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up GHC (Haskell) + run: | + sudo apt update + sudo apt install -y haskell-platform cabal-install + + - name: Install dependencies + run: | + cabal update + cabal build --only-dependencies + + - name: Build project + run: cabal build + + - name: Run tests + run: cabal test From 0f03f9eb7a46074beb40a3482149c3a5e2934f43 Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Fri, 26 Sep 2025 22:50:54 +0200 Subject: [PATCH 03/18] New rules --- .forgejo/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 427b75b..16e8ca9 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -3,6 +3,7 @@ name: Haskell CI on: pull_request: branches: + - dev - main push: branches: @@ -16,7 +17,7 @@ jobs: - name: Checkout code uses: actions/checkout@v3 - - name: Set up GHC (Haskell) + - name: Install Haskell run: | sudo apt update sudo apt install -y haskell-platform cabal-install From d012a8e3964b453fceb104c45521029fb75fafc3 Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Fri, 26 Sep 2025 23:21:19 +0200 Subject: [PATCH 04/18] Renamed file --- .forgejo/workflows/{ci.yml => test.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .forgejo/workflows/{ci.yml => test.yaml} (100%) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/test.yaml similarity index 100% rename from .forgejo/workflows/ci.yml rename to .forgejo/workflows/test.yaml From 9d4e278b9189d13e6bd65775b7f4dd078802dd75 Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Fri, 26 Sep 2025 23:22:08 +0200 Subject: [PATCH 05/18] Run on docker --- .forgejo/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/test.yaml b/.forgejo/workflows/test.yaml index 16e8ca9..dfbcabb 100644 --- a/.forgejo/workflows/test.yaml +++ b/.forgejo/workflows/test.yaml @@ -11,7 +11,7 @@ on: jobs: build: - runs-on: self-hosted + runs-on: docker steps: - name: Checkout code From f452197fca33eb03b3d4c6a2dd7024c463e7b01c Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Fri, 26 Sep 2025 23:22:36 +0200 Subject: [PATCH 06/18] update ci action --- .forgejo/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/test.yaml b/.forgejo/workflows/test.yaml index dfbcabb..0747c56 100644 --- a/.forgejo/workflows/test.yaml +++ b/.forgejo/workflows/test.yaml @@ -15,7 +15,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Haskell run: | From 1b360e3592e83bf8bdea9da5c5567c1c851e6cd5 Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Fri, 26 Sep 2025 23:25:05 +0200 Subject: [PATCH 07/18] Updated ci --- .forgejo/workflows/test.yaml | 62 +++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/.forgejo/workflows/test.yaml b/.forgejo/workflows/test.yaml index 0747c56..22f314d 100644 --- a/.forgejo/workflows/test.yaml +++ b/.forgejo/workflows/test.yaml @@ -1,5 +1,4 @@ name: Haskell CI - on: pull_request: branches: @@ -12,24 +11,65 @@ on: jobs: build: runs-on: docker - + container: + image: ubuntu:22.04 # Use Ubuntu base and install via ghcup like your local setup steps: - name: Checkout code - uses: actions/checkout@v4 - - - name: Install Haskell - run: | - sudo apt update - sudo apt install -y haskell-platform cabal-install + uses: https://github.com/actions/checkout@v4 - name: Install dependencies run: | + apt-get update + apt-get install -y curl build-essential libffi-dev libgmp-dev zlib1g-dev + + - name: Install GHCup + run: | + curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh + echo "source ~/.ghcup/env" >> ~/.bashrc + + - name: Install GHC and Cabal (matching local versions) + run: | + source ~/.ghcup/env + ghcup install ghc 9.10.2 --set + ghcup install cabal 3.14.2.0 --set + + - name: Cache Cabal packages + uses: https://github.com/actions/cache@v4 + with: + path: | + ~/.cabal/packages + ~/.cabal/store + dist-newstyle + key: ${{ runner.os }}-ghc-9.10.2-cabal-${{ hashFiles('**/*.cabal', '**/cabal.project') }} + restore-keys: | + ${{ runner.os }}-ghc-9.10.2-cabal- + + - name: Update Cabal package index + run: | + source ~/.ghcup/env cabal update - cabal build --only-dependencies + + - name: Configure project + run: | + source ~/.ghcup/env + cabal configure --enable-tests --enable-benchmarks + + - name: Build dependencies + run: | + source ~/.ghcup/env + cabal build --only-dependencies --enable-tests --enable-benchmarks - name: Build project - run: cabal build + run: | + source ~/.ghcup/env + cabal build --enable-tests --enable-benchmarks - name: Run tests - run: cabal test + run: | + source ~/.ghcup/env + cabal test --test-show-details=direct + - name: Run documentation build + run: | + source ~/.ghcup/env + cabal haddock From 10469b367726a17e72fe779a79328a93e30698c0 Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Fri, 26 Sep 2025 23:39:34 +0200 Subject: [PATCH 08/18] Fixed ci.yml --- .forgejo/workflows/test.yaml | 60 ++++++++++-------------------------- 1 file changed, 16 insertions(+), 44 deletions(-) diff --git a/.forgejo/workflows/test.yaml b/.forgejo/workflows/test.yaml index 22f314d..b1b3a9d 100644 --- a/.forgejo/workflows/test.yaml +++ b/.forgejo/workflows/test.yaml @@ -12,64 +12,36 @@ jobs: build: runs-on: docker container: - image: ubuntu:22.04 # Use Ubuntu base and install via ghcup like your local setup + image: haskell:9.10 # Official Haskell image with GHC 9.10 + Cabal preinstalled steps: - name: Checkout code - uses: https://github.com/actions/checkout@v4 + uses: actions/checkout@v4 - - name: Install dependencies + - name: Check versions run: | - apt-get update - apt-get install -y curl build-essential libffi-dev libgmp-dev zlib1g-dev + ghc --version + cabal --version - - name: Install GHCup + # Manual caching with volumes (act-friendly) + - name: Cache Cabal store run: | - curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh - echo "source ~/.ghcup/env" >> ~/.bashrc - - - name: Install GHC and Cabal (matching local versions) - run: | - source ~/.ghcup/env - ghcup install ghc 9.10.2 --set - ghcup install cabal 3.14.2.0 --set - - - name: Cache Cabal packages - uses: https://github.com/actions/cache@v4 - with: - path: | - ~/.cabal/packages - ~/.cabal/store - dist-newstyle - key: ${{ runner.os }}-ghc-9.10.2-cabal-${{ hashFiles('**/*.cabal', '**/cabal.project') }} - restore-keys: | - ${{ runner.os }}-ghc-9.10.2-cabal- - - - name: Update Cabal package index - run: | - source ~/.ghcup/env + mkdir -p ~/.cabal/packages ~/.cabal/store cabal update + - name: Update Cabal package index + run: cabal update + - name: Configure project - run: | - source ~/.ghcup/env - cabal configure --enable-tests --enable-benchmarks + run: cabal configure --enable-tests --enable-benchmarks - name: Build dependencies - run: | - source ~/.ghcup/env - cabal build --only-dependencies --enable-tests --enable-benchmarks + run: cabal build --only-dependencies --enable-tests --enable-benchmarks - name: Build project - run: | - source ~/.ghcup/env - cabal build --enable-tests --enable-benchmarks + run: cabal build --enable-tests --enable-benchmarks - name: Run tests - run: | - source ~/.ghcup/env - cabal test --test-show-details=direct + run: cabal test --test-show-details=direct - name: Run documentation build - run: | - source ~/.ghcup/env - cabal haddock + run: cabal haddock From 2fc79481128bba9c2e54054fe784c076e1b438ea Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Fri, 26 Sep 2025 23:45:32 +0200 Subject: [PATCH 09/18] try again --- .forgejo/workflows/test.yaml | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/.forgejo/workflows/test.yaml b/.forgejo/workflows/test.yaml index b1b3a9d..959167f 100644 --- a/.forgejo/workflows/test.yaml +++ b/.forgejo/workflows/test.yaml @@ -12,21 +12,33 @@ jobs: build: runs-on: docker container: - image: haskell:9.10 # Official Haskell image with GHC 9.10 + Cabal preinstalled + image: fpco/stack-build:lts-24.11 steps: + - name: Install Node.js (for actions) + run: | + curl -fsSL https://deb.nodesource.com/setup_18.x | bash - + apt-get install -y nodejs + - name: Checkout code - uses: actions/checkout@v4 + uses: https://github.com/actions/checkout@v4 - name: Check versions run: | ghc --version cabal --version + stack --version + node --version - # Manual caching with volumes (act-friendly) - - name: Cache Cabal store - run: | - mkdir -p ~/.cabal/packages ~/.cabal/store - cabal update + - name: Cache Cabal packages + uses: https://github.com/actions/cache@v4 + with: + path: | + ~/.cabal/packages + ~/.cabal/store + dist-newstyle + key: ${{ runner.os }}-stackage-lts22-cabal-${{ hashFiles('**/*.cabal', '**/cabal.project') }} + restore-keys: | + ${{ runner.os }}-stackage-lts22-cabal- - name: Update Cabal package index run: cabal update From 9edd5cb4365d39fad864791dd0198f5af1d19c1c Mon Sep 17 00:00:00 2001 From: elland Date: Fri, 26 Sep 2025 21:55:59 +0000 Subject: [PATCH 10/18] Update .forgejo/workflows/test.yaml --- .forgejo/workflows/test.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.forgejo/workflows/test.yaml b/.forgejo/workflows/test.yaml index 959167f..a8b8bda 100644 --- a/.forgejo/workflows/test.yaml +++ b/.forgejo/workflows/test.yaml @@ -12,7 +12,7 @@ jobs: build: runs-on: docker container: - image: fpco/stack-build:lts-24.11 + image: haskell:9.10 steps: - name: Install Node.js (for actions) run: | @@ -20,14 +20,12 @@ jobs: apt-get install -y nodejs - name: Checkout code - uses: https://github.com/actions/checkout@v4 + uses: actions/checkout@v4 - name: Check versions run: | ghc --version cabal --version - stack --version - node --version - name: Cache Cabal packages uses: https://github.com/actions/cache@v4 From afc9a3b2114fec21e81744d2fdf92796d6c8b089 Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Fri, 26 Sep 2025 22:31:28 +0200 Subject: [PATCH 11/18] Added Makefile --- Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..068aa35 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +.PHONY: help +help: ## Show this help. + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: format +format: + find . -type f -name "*.hs" ! -path "./dist-newstyle/*" -exec fourmolu -i {} + + From b8eac2856cc2e73f58ca653ad9759c1246c6d68c Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Fri, 26 Sep 2025 22:32:19 +0200 Subject: [PATCH 12/18] Formatting --- src/Lexer.hs | 310 ++++++++++++++++++++++++++------------------------- test/Spec.hs | 238 +++++++++++++++++++-------------------- 2 files changed, 275 insertions(+), 273 deletions(-) diff --git a/src/Lexer.hs b/src/Lexer.hs index 426a7ff..4a85fb5 100644 --- a/src/Lexer.hs +++ b/src/Lexer.hs @@ -1,10 +1,11 @@ {-# LANGUAGE OverloadedStrings #-} module Lexer ( - Token (..), - lexer, - emphasis, -) where + Token (..), + lexer, + emphasis, +) +where import Control.Monad (mfilter, void) import Data.Functor (($>)) @@ -17,51 +18,52 @@ import Text.Parsec qualified as Parsec import Text.Parsec.Pos (updatePosChar) type Located a = (SourcePos, a) + type LocatedToken = (SourcePos, Token) type Lexer = Parser [LocatedToken] data Level - = One - | Two - | Three - | Four - | Five - | Six - deriving (Eq, Show) + = One + | Two + | Three + | Four + | Five + | Six + deriving (Eq, Show) data Token - = Token Text - | Anchor Text - | BirdTrack - | BoldOpen - | BoldClose - | Escape - | EmphasisOpen - | EmphasisClose - | Header Level - | MonospaceOpen - | MonospaceClose - | Newline - | LinkOpen - | LinkClose - | LabeledLinkOpen - | LabeledLinkClose - | ParenOpen - | ParenClose - | BracketOpen - | BracketClose - | MathInlineOpen - | MathInlineClose - | MathMultilineOpen - | MathMultilineClose - | NumericEntity Int - | Module Text - | QuoteOpen - | QuoteClose - | Space - | EOF - deriving (Eq, Show) + = Token Text + | Anchor Text + | BirdTrack + | BoldOpen + | BoldClose + | Escape + | EmphasisOpen + | EmphasisClose + | Header Level + | MonospaceOpen + | MonospaceClose + | Newline + | LinkOpen + | LinkClose + | LabeledLinkOpen + | LabeledLinkClose + | ParenOpen + | ParenClose + | BracketOpen + | BracketClose + | MathInlineOpen + | MathInlineClose + | MathMultilineOpen + | MathMultilineClose + | NumericEntity Int + | Module Text + | QuoteOpen + | QuoteClose + | Space + | EOF + deriving (Eq, Show) located :: Parser a -> Parser (SourcePos, a) located p = (,) <$> getPosition <*> p @@ -74,74 +76,74 @@ lexer = Parsec.runParser lexText initialParserState "input" . Text.pack lexText :: Parser [LocatedToken] lexText = go - where - go = do - Parsec.optionMaybe Parsec.eof >>= \case - Just _ -> pure [] - Nothing -> do - toks <- - choice $ - Parsec.try - <$> [ mathMultiline - , mathInline - , escape -- maths go before escape to avoid mismatch - , headers - , newlineToken - , spaceToken - , link - , labeledLink - , module_ - , anchor - , textElement - , quotes - , birdTrack - , other - ] - rest <- go - pure (toks <> rest) + where + go = do + Parsec.optionMaybe Parsec.eof >>= \case + Just _ -> pure [] + Nothing -> do + toks <- + choice $ + Parsec.try + <$> [ mathMultiline + , mathInline + , escape -- maths go before escape to avoid mismatch + , headers + , newlineToken + , spaceToken + , link + , labeledLink + , module_ + , anchor + , textElement + , quotes + , birdTrack + , other + ] + rest <- go + pure (toks <> rest) -- Tokens textElement :: Parser [LocatedToken] textElement = - choice $ - Parsec.try - <$> [ emphasis - , bold - , monospace - ] + choice $ + Parsec.try + <$> [ emphasis + , bold + , monospace + ] headers :: Parser [LocatedToken] headers = - choice $ - Parsec.try - <$> [ header1 - , header2 - , header3 - , header4 - , header5 - , header6 - ] + choice $ + Parsec.try + <$> [ header1 + , header2 + , header3 + , header4 + , header5 + , header6 + ] anyUntil :: Parser a -> Parser Text anyUntil p = Text.pack <$> manyTill anyChar (lookAhead p) delimitedAsTuple :: Parser open -> Parser close -> Parser (Located open, LocatedToken, Located close) delimitedAsTuple openP closeP = - (,,) - <$> located openP - <*> located (Token <$> anyUntil closeP) - <*> located closeP + (,,) + <$> located openP + <*> located (Token <$> anyUntil closeP) + <*> located closeP delimited :: Parser open -> Parser close -> Token -> Token -> Parser [LocatedToken] delimited openP closeP openTok closeTok = asList <$> delimitedAsTuple (openTok <$ openP) (closeTok <$ closeP) - where - asList (a, tok, b) = [a, tok, b] + where + asList (a, tok, b) = [a, tok, b] delimitedNoTrailing :: Parser open -> Parser close -> Token -> Parser [LocatedToken] delimitedNoTrailing openP closeP openTok = asList <$> delimitedAsTuple (openTok <$ openP) (void closeP) - where - asList (a, tok, _) = [a, tok] + where + asList (a, tok, _) = [a, tok] delimitedSymmetric :: Parser a -> Token -> Token -> Parser [LocatedToken] delimitedSymmetric s t1 t2 = delimited s s t1 t2 @@ -170,9 +172,8 @@ header6 = delimitedNoTrailing "====== " eol (Header Six) -- #anchors# anchor :: Lexer anchor = do - x <- located $ between "#" "#" (Anchor <$> anyUntil "#") - pure [x] - + x <- located $ between "#" "#" (Anchor <$> anyUntil "#") + pure [x] moduleNames :: Parser Text moduleNames = intercalate "." . fmap Text.pack <$> upperId `sepBy1` char '.' @@ -188,47 +189,47 @@ identifierChar = satisfy (\c -> isAlphaNum c || c == '_') -- "Module.Name\#anchor" -- known as "old anchor". this has been deprecated for 9 years, thanks Ben module_ :: Lexer module_ = between (char '"') (char '"') inner - where - inner = do - m <- located $ Module <$> moduleNames - mAnchor <- optionMaybe (located $ anchorHash *> (Anchor <$> anchorText)) - pure $ case mAnchor of - Just anc -> [m, anc] - Nothing -> [m] + where + inner = do + m <- located $ Module <$> moduleNames + mAnchor <- optionMaybe (located $ anchorHash *> (Anchor <$> anchorText)) + pure $ case mAnchor of + Just anc -> [m, anc] + Nothing -> [m] - anchorHash :: Parser Text - anchorHash = "#" <|> try "\\#" + anchorHash :: Parser Text + anchorHash = "#" <|> try "\\#" - anchorText :: Parser Text - anchorText = Text.pack <$> many (satisfy (\c -> c /= '"' && not (isSpace c))) + anchorText :: Parser Text + anchorText = Text.pack <$> many (satisfy (\c -> c /= '"' && not (isSpace c))) linkRaw :: Lexer linkRaw = - tokenise - [ BracketOpen <$ "[" - , Token <$> anyUntil "]" - , BracketClose <$ "]" - , ParenOpen <$ "(" - , Token <$> anyUntil ")" - , ParenClose <$ ")" - ] + tokenise + [ BracketOpen <$ "[" + , Token <$> anyUntil "]" + , BracketClose <$ "]" + , ParenOpen <$ "(" + , Token <$> anyUntil ")" + , ParenClose <$ ")" + ] link :: Lexer link = do - pos <- getPosition - l <- linkRaw - -- register the position of the last token - pos' <- flip incSourceColumn (-1) <$> getPosition - pure $ (pos, LinkOpen) : l <> [(pos', LinkClose)] + pos <- getPosition + l <- linkRaw + -- register the position of the last token + pos' <- flip incSourceColumn (-1) <$> getPosition + pure $ (pos, LinkOpen) : l <> [(pos', LinkClose)] labeledLink :: Lexer labeledLink = do - open <- located $ LabeledLinkOpen <$ "<" - linkRes <- linkRaw - labelRes <- located $ Token <$> anyUntil ">" - close <- located $ LabeledLinkClose <$ ">" - pure $ - open : linkRes <> [ labelRes , close ] + open <- located $ LabeledLinkOpen <$ "<" + linkRes <- linkRaw + labelRes <- located $ Token <$> anyUntil ">" + close <- located $ LabeledLinkClose <$ ">" + pure $ + open : linkRes <> [labelRes, close] mathMultiline :: Lexer mathMultiline = delimited "\\[" "\\]" MathMultilineOpen MathMultilineClose @@ -256,23 +257,23 @@ monospace = delimitedSymmetric "@" MonospaceOpen MonospaceClose other :: Lexer other = do - pos <- getPosition - c <- takeWhile1_ isUnicodeAlphaNum - pure . pure $ (pos, Token c) - where - isUnicodeAlphaNum c = isPrint c && not (isControl c) && not (isSpace c) + pos <- getPosition + c <- takeWhile1_ isUnicodeAlphaNum + pure . pure $ (pos, Token c) + where + isUnicodeAlphaNum c = isPrint c && not (isControl c) && not (isSpace c) spaceToken :: Lexer spaceToken = do - pos <- getPosition - _ <- many1 (char ' ') - pure . pure $ (pos, Space) + pos <- getPosition + _ <- many1 (char ' ') + pure . pure $ (pos, Space) newlineToken :: Lexer newlineToken = do - pos <- getPosition - _ <- newline - pure . pure $ (pos, Newline) + pos <- getPosition + _ <- newline + pure . pure $ (pos, Newline) ------- -- Helpers @@ -281,11 +282,11 @@ newlineToken = do -- | Like `takeWhile`, but unconditionally take escaped characters. takeWhile_ :: (Char -> Bool) -> Parser Text takeWhile_ p = scan p_ False - where - p_ escaped c - | escaped = Just False - | not $ p c = Nothing - | otherwise = Just (c == '\\') + where + p_ escaped c + | escaped = Just False + | not $ p c = Nothing + | otherwise = Just (c == '\\') -- | Like 'takeWhile1', but unconditionally take escaped characters. takeWhile1_ :: (Char -> Bool) -> Parser Text @@ -295,19 +296,20 @@ takeWhile1_ = mfilter (not . Text.null) . takeWhile_ function returns true. -} scan :: - -- | scan function - (state -> Char -> Maybe state) -> - -- | initial state - state -> - Parser Text + -- | scan function + (state -> Char -> Maybe state) -> + -- | initial state + state -> + Parser Text scan f initState = do - parserState@State{stateInput = input, statePos = pos} <- Parsec.getParserState - (remaining, finalPos, ct) <- go input initState pos 0 - let newState = parserState{stateInput = remaining, statePos = finalPos} - Parsec.setParserState newState $> Text.take ct input - where - go !input' !st !posAccum !count' = case Text.uncons input' of - Nothing -> pure (input', posAccum, count') - Just (char', input'') -> case f st char' of - Nothing -> pure (input', posAccum, count') - Just st' -> go input'' st' (updatePosChar posAccum char') (count' + 1) + parserState@State{stateInput = input, statePos = pos} <- Parsec.getParserState + + (remaining, finalPos, ct) <- go input initState pos 0 + let newState = parserState{stateInput = remaining, statePos = finalPos} + Parsec.setParserState newState $> Text.take ct input + where + go !input' !st !posAccum !count' = case Text.uncons input' of + Nothing -> pure (input', posAccum, count') + Just (char', input'') -> case f st char' of + Nothing -> pure (input', posAccum, count') + Just st' -> go input'' st' (updatePosChar posAccum char') (count' + 1) diff --git a/test/Spec.hs b/test/Spec.hs index 745aefa..7258a2d 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -10,33 +10,33 @@ import Types import Data.String (IsString (..)) import Data.Text (Text) -import Text.Parsec.Pos import GHC.Stack +import Text.Parsec.Pos main :: IO () main = hspec $ do - describe "Lexer" do - describe "minimal" do - it "handles unicode" unicode - it "escapes" escaping - it "maths" math - it "anchors" anchor - it "space chars" space - it "bare string" someString - it "emphasis" emphatic - it "monospace" monospace - it "labeled link" labeledLink - it "markdown link" link - it "bird tracks" birdTracks - it "module names" modules - it "quotes" quotes - it "ignores nesting" ignoreNesting + describe "Lexer" do + describe "minimal" do + it "handles unicode" unicode + it "escapes" escaping + it "maths" math + it "anchors" anchor + it "space chars" space + it "bare string" someString + it "emphasis" emphatic + it "monospace" monospace + it "labeled link" labeledLink + it "markdown link" link + it "bird tracks" birdTracks + it "module names" modules + it "quotes" quotes + it "ignores nesting" ignoreNesting - describe "Parser" do - it "Bold" do - "__bold__" `shouldParseTo` (DocBold (DocString "bold")) - it "Emphasis" do - "/emphasis/" `shouldParseTo` (DocEmphasis (DocString "emphasis")) + describe "Parser" do + it "Bold" do + "__bold__" `shouldParseTo` (DocBold (DocString "bold")) + it "Emphasis" do + "/emphasis/" `shouldParseTo` (DocEmphasis (DocString "emphasis")) ------------ -- Tests @@ -44,137 +44,137 @@ main = hspec $ do modules :: Expectation modules = do - "\"MyModule.Name\"" - `shouldLexTo` [ (1, 2, Module "MyModule.Name") - ] + "\"MyModule.Name\"" + `shouldLexTo` [ (1, 2, Module "MyModule.Name") + ] - "\"OtherModule.Name#myAnchor\"" - `shouldLexTo` [ (1, 2, Module "OtherModule.Name") - , (1, 18, Anchor "myAnchor") - ] + "\"OtherModule.Name#myAnchor\"" + `shouldLexTo` [ (1, 2, Module "OtherModule.Name") + , (1, 18, Anchor "myAnchor") + ] - "\"OtherModule.Name\\#myAnchor\"" - `shouldLexTo` [ (1, 2, Module "OtherModule.Name") - , (1, 18, Anchor "myAnchor") - ] + "\"OtherModule.Name\\#myAnchor\"" + `shouldLexTo` [ (1, 2, Module "OtherModule.Name") + , (1, 18, Anchor "myAnchor") + ] link :: Expectation link = - "[link to](http://some.website)" - `shouldLexTo` [ (1, 1, LinkOpen) - , (1, 1, BracketOpen) - , (1, 2, Token "link to") - , (1, 9, BracketClose) - , (1, 10, ParenOpen) - , (1, 11, Token "http://some.website") - , (1, 30, ParenClose) - , (1, 30, LinkClose) - ] + "[link to](http://some.website)" + `shouldLexTo` [ (1, 1, LinkOpen) + , (1, 1, BracketOpen) + , (1, 2, Token "link to") + , (1, 9, BracketClose) + , (1, 10, ParenOpen) + , (1, 11, Token "http://some.website") + , (1, 30, ParenClose) + , (1, 30, LinkClose) + ] labeledLink :: Expectation labeledLink = - "<[link here](http://to.here) label>" - `shouldLexTo` [ (1, 1, LabeledLinkOpen) - , (1, 2, BracketOpen) - , (1, 3, Token "link here") - , (1, 12, BracketClose) - , (1, 13, ParenOpen) - , (1, 14, Token "http://to.here") - , (1, 28, ParenClose) - , (1, 29, Token " label") - , (1, 35, LabeledLinkClose) - ] + "<[link here](http://to.here) label>" + `shouldLexTo` [ (1, 1, LabeledLinkOpen) + , (1, 2, BracketOpen) + , (1, 3, Token "link here") + , (1, 12, BracketClose) + , (1, 13, ParenOpen) + , (1, 14, Token "http://to.here") + , (1, 28, ParenClose) + , (1, 29, Token " label") + , (1, 35, LabeledLinkClose) + ] anchor :: Expectation anchor = - "#myAnchor#" - `shouldLexTo` [ (1, 1, Anchor "myAnchor") - ] + "#myAnchor#" + `shouldLexTo` [ (1, 1, Anchor "myAnchor") + ] math :: IO () math = do - "\\[some math\\]" - `shouldLexTo` [ (1, 1, MathMultilineOpen) - , (1, 3, Token "some math") - , (1, 12, MathMultilineClose) - ] - "\\(other maths\\)" - `shouldLexTo` [ (1, 1, MathInlineOpen) - , (1, 3, Token "other maths") - , (1, 14, MathInlineClose) - ] + "\\[some math\\]" + `shouldLexTo` [ (1, 1, MathMultilineOpen) + , (1, 3, Token "some math") + , (1, 12, MathMultilineClose) + ] + "\\(other maths\\)" + `shouldLexTo` [ (1, 1, MathInlineOpen) + , (1, 3, Token "other maths") + , (1, 14, MathInlineClose) + ] escaping :: Expectation escaping = do - "\\(" - `shouldLexTo` [ (1, 1, Escape) - , (1, 2, Token "(") - ] - "\\(\r\n" - `shouldLexTo` [ (1, 1, Escape) - , (1, 2, Token "(") - ] + "\\(" + `shouldLexTo` [ (1, 1, Escape) + , (1, 2, Token "(") + ] + "\\(\r\n" + `shouldLexTo` [ (1, 1, Escape) + , (1, 2, Token "(") + ] unicode :: Expectation unicode = - "ドラゴンクエストの冒険者🐉" - `shouldLexTo` [ (1, 1, Token "ドラゴンクエストの冒険者🐉") - ] + "ドラゴンクエストの冒険者🐉" + `shouldLexTo` [ (1, 1, Token "ドラゴンクエストの冒険者🐉") + ] ignoreNesting :: Expectation ignoreNesting = - ">/foo/" - `shouldLexTo` [ (1, 1, Token ">/foo/") - ] + ">/foo/" + `shouldLexTo` [ (1, 1, Token ">/foo/") + ] birdTracks :: Expectation birdTracks = - ">> code" - `shouldLexTo` [ (1, 1, BirdTrack) - , (1, 4, Token "code") - ] + ">> code" + `shouldLexTo` [ (1, 1, BirdTrack) + , (1, 4, Token "code") + ] quotes :: Expectation quotes = - "\"quoted\"" - `shouldLexTo` [ (1, 1, QuoteOpen) - , (1, 2, Token "quoted") - , (1, 8, QuoteClose) - ] + "\"quoted\"" + `shouldLexTo` [ (1, 1, QuoteOpen) + , (1, 2, Token "quoted") + , (1, 8, QuoteClose) + ] space :: Expectation space = do - "\n " - `shouldLexTo` [ (1, 1, Newline) - , (2, 1, Space) - ] - " \n" - `shouldLexTo` [ (1, 1, Space) - , (1, 2, Newline) - ] + "\n " + `shouldLexTo` [ (1, 1, Newline) + , (2, 1, Space) + ] + " \n" + `shouldLexTo` [ (1, 1, Space) + , (1, 2, Newline) + ] monospace :: Expectation monospace = - "@mono@" - `shouldLexTo` [ (1, 1, MonospaceOpen) - , (1, 2, Token "mono") - , (1, 6, MonospaceClose) - ] + "@mono@" + `shouldLexTo` [ (1, 1, MonospaceOpen) + , (1, 2, Token "mono") + , (1, 6, MonospaceClose) + ] emphatic :: Expectation emphatic = - "/emphatic/" - `shouldLexTo` [ (1, 1, EmphasisOpen) - , (1, 2, Token "emphatic") - , (1, 10, EmphasisClose) - ] + "/emphatic/" + `shouldLexTo` [ (1, 1, EmphasisOpen) + , (1, 2, Token "emphatic") + , (1, 10, EmphasisClose) + ] someString :: Expectation someString = - "some string" - `shouldLexTo` [ (1, 1, Token "some") - , (1, 5, Space) - , (1, 6, Token "string") - ] + "some string" + `shouldLexTo` [ (1, 1, Token "some") + , (1, 5, Space) + , (1, 6, Token "string") + ] -------------- -- Helpers @@ -183,16 +183,16 @@ someString = type Doc id = DocMarkup () id instance IsString (Doc String) where - fromString = DocString + fromString = DocString shouldLexTo :: String -> [(Int, Int, Token)] -> Expectation shouldLexTo input expected = - withFrozenCallStack $ + withFrozenCallStack $ case lexer input of - Right tokens -> do - let actual = map (\(pos, tok) -> (sourceLine pos, sourceColumn pos, tok)) tokens - actual `shouldBe` expected - Left err -> expectationFailure $ "Parse error: " <> show err + Right tokens -> do + let actual = map (\(pos, tok) -> (sourceLine pos, sourceColumn pos, tok)) tokens + actual `shouldBe` expected + Left err -> expectationFailure $ "Parse error: " <> show err shouldParseTo :: Text -> DocMarkup mod Identifier -> Expectation shouldParseTo input ast = parseText input `shouldBe` ast From 3e829d126ca23f4fff35e8d61ad4482b8663d593 Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Fri, 26 Sep 2025 22:33:06 +0200 Subject: [PATCH 13/18] Added cabal-gild to format cmd --- Makefile | 1 + haddock2.cabal | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 068aa35..62cad36 100644 --- a/Makefile +++ b/Makefile @@ -5,4 +5,5 @@ help: ## Show this help. .PHONY: format format: find . -type f -name "*.hs" ! -path "./dist-newstyle/*" -exec fourmolu -i {} + + cabal-gild --io=haddock2.cabal diff --git a/haddock2.cabal b/haddock2.cabal index 7fe124c..9ae122d 100644 --- a/haddock2.cabal +++ b/haddock2.cabal @@ -46,10 +46,10 @@ test-suite haddock2-test type: exitcode-stdio-1.0 main-is: Spec.hs build-depends: - parsec ^>=3.1.18.0, base >=4.20.1.0, haddock2:{haddock2-lib}, hspec ^>=2.11.0, + parsec ^>=3.1.18.0, text ^>=2.1.2, hs-source-dirs: test From c9f6358254ac99556b0d6cbb1c8d2a0d16c0bb6c Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Sat, 27 Sep 2025 09:00:43 +0200 Subject: [PATCH 14/18] Split jobs --- .forgejo/workflows/test.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.forgejo/workflows/test.yaml b/.forgejo/workflows/test.yaml index a8b8bda..603a9be 100644 --- a/.forgejo/workflows/test.yaml +++ b/.forgejo/workflows/test.yaml @@ -50,8 +50,12 @@ jobs: - name: Build project run: cabal build --enable-tests --enable-benchmarks - - name: Run tests - run: cabal test --test-show-details=direct - - name: Run documentation build run: cabal haddock + + + test: + runs-on: docker + steps: + - name: Run tests + run: cabal test --test-show-details=direct From ad0dafa84152ec2b64f9217891323f39fe3c70b8 Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Sat, 27 Sep 2025 09:14:30 +0200 Subject: [PATCH 15/18] Try more steps --- .forgejo/workflows/test.yaml | 82 ++++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 13 deletions(-) diff --git a/.forgejo/workflows/test.yaml b/.forgejo/workflows/test.yaml index 603a9be..c7e70a7 100644 --- a/.forgejo/workflows/test.yaml +++ b/.forgejo/workflows/test.yaml @@ -16,46 +16,102 @@ jobs: steps: - name: Install Node.js (for actions) run: | - curl -fsSL https://deb.nodesource.com/setup_18.x | bash - + curl -fsSL https://deb.nodesource.com/setup_22.x | bash - apt-get install -y nodejs - - name: Checkout code uses: actions/checkout@v4 - - name: Check versions run: | ghc --version cabal --version - + node --version - name: Cache Cabal packages - uses: https://github.com/actions/cache@v4 + uses: actions/cache@v4 with: path: | ~/.cabal/packages ~/.cabal/store dist-newstyle - key: ${{ runner.os }}-stackage-lts22-cabal-${{ hashFiles('**/*.cabal', '**/cabal.project') }} + key: ${{ runner.os }}-haskell-9.10-cabal-${{ hashFiles('**/*.cabal', '**/cabal.project') }} restore-keys: | - ${{ runner.os }}-stackage-lts22-cabal- - + ${{ runner.os }}-haskell-9.10-cabal- - name: Update Cabal package index run: cabal update - - name: Configure project run: cabal configure --enable-tests --enable-benchmarks - - name: Build dependencies run: cabal build --only-dependencies --enable-tests --enable-benchmarks - - name: Build project run: cabal build --enable-tests --enable-benchmarks - - name: Run documentation build run: cabal haddock - test: runs-on: docker + container: + image: haskell:9.10 + needs: build steps: + - name: Install Node.js (for actions) + run: | + curl -fsSL https://deb.nodesource.com/setup_22.x | bash - + apt-get install -y nodejs + - name: Checkout code + uses: actions/checkout@v4 + - name: Cache Cabal packages + uses: actions/cache@v4 + with: + path: | + ~/.cabal/packages + ~/.cabal/store + dist-newstyle + key: ${{ runner.os }}-haskell-9.10-cabal-${{ hashFiles('**/*.cabal', '**/cabal.project') }} + restore-keys: | + ${{ runner.os }}-haskell-9.10-cabal- + - name: Update Cabal package index + run: cabal update + - name: Configure project + run: cabal configure --enable-tests --enable-benchmarks + - name: Build dependencies + run: cabal build --only-dependencies --enable-tests --enable-benchmarks + - name: Build project + run: cabal build --enable-tests --enable-benchmarks - name: Run tests run: cabal test --test-show-details=direct + + fourmolu: + runs-on: docker + container: + image: haskell:9.10 + steps: + - name: Install Node.js (for actions) + run: | + curl -fsSL https://deb.nodesource.com/setup_22.x | bash - + apt-get install -y nodejs + - name: Checkout code + uses: actions/checkout@v4 + - name: Install fourmolu + run: cabal install fourmolu-0.18.0.0 + - name: Run fourmolu + run: | + find src test app -name "*.hs" -exec fourmolu --check-idempotence {} \; 2>/dev/null || true + find src test app -name "*.hs" -exec fourmolu --mode check {} \; + + hlint: + runs-on: docker + container: + image: haskell:9.10 + steps: + - name: Install Node.js (for actions) + run: | + curl -fsSL https://deb.nodesource.com/setup_22.x | bash - + apt-get install -y nodejs + - name: Checkout code + uses: actions/checkout@v4 + - name: Install hlint + run: cabal install hlint-3.8 + - name: Run hlint + run: | + if [ -d src ]; then hlint src/; fi + if [ -d test ]; then hlint test/; fi + if [ -d app ]; then hlint app/; fi From 9db8fd395737338fd6ff4ce925b7e554bfff5e4d Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Sat, 27 Sep 2025 09:27:30 +0200 Subject: [PATCH 16/18] Improved makefile, formatting --- Makefile | 41 +++++++++++++++++++++-- src/Lexer.hs | 4 +-- src/Parser/Util.hs | 4 ++- src/Types.hs | 83 ++++++++++++++++++++++++---------------------- test/Spec.hs | 17 +++++----- 5 files changed, 94 insertions(+), 55 deletions(-) diff --git a/Makefile b/Makefile index 62cad36..6bc9ca2 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,44 @@ .PHONY: help -help: ## Show this help. +help: ## Show this help @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' -.PHONY: format -format: +.PHONY: build +build: ## Build the project + cabal build + +.PHONY: test +test: ## Run tests + cabal test --test-show-details=direct + +.PHONY: clean +clean: ## Clean build artifacts + cabal clean + +.PHONY: fourmolu +fourmolu: ## Format Haskell code find . -type f -name "*.hs" ! -path "./dist-newstyle/*" -exec fourmolu -i {} + + +.PHONY: fourmolu-check +fourmolu-check: ## Check if code is formatted + find . -type f -name "*.hs" ! -path "./dist-newstyle/*" -exec fourmolu --mode check {} \; + +.PHONY: lint +lint: ## Run hlint + hlint src test app + +.PHONY: cabal-gild +cabal-gild: ## Format cabal file cabal-gild --io=haddock2.cabal +.PHONY: format +format: fourmolu cabal-gild ## Run all formatters + +.PHONY: check +check: fourmolu-check lint ## Run all checks (CI-style) + +.PHONY: ci +ci: build test check ## Run full CI pipeline locally + +.PHONY: docs +docs: ## Generate documentation + cabal haddock --haddock-hyperlink-source diff --git a/src/Lexer.hs b/src/Lexer.hs index 4a85fb5..84a8373 100644 --- a/src/Lexer.hs +++ b/src/Lexer.hs @@ -69,7 +69,7 @@ located :: Parser a -> Parser (SourcePos, a) located p = (,) <$> getPosition <*> p tokenise :: [Parser a] -> Parser [(SourcePos, a)] -tokenise = sequence . map located +tokenise = mapM located lexer :: String -> Either ParseError [LocatedToken] lexer = Parsec.runParser lexText initialParserState "input" . Text.pack @@ -146,7 +146,7 @@ delimitedNoTrailing openP closeP openTok = asList <$> delimitedAsTuple (openTok asList (a, tok, _) = [a, tok] delimitedSymmetric :: Parser a -> Token -> Token -> Parser [LocatedToken] -delimitedSymmetric s t1 t2 = delimited s s t1 t2 +delimitedSymmetric s = delimited s s eol :: Parser () eol = void "\n" <|> void "\r\n" <|> Parsec.eof diff --git a/src/Parser/Util.hs b/src/Parser/Util.hs index 4cf96cb..a75fcef 100644 --- a/src/Parser/Util.hs +++ b/src/Parser/Util.hs @@ -13,7 +13,9 @@ import Text.Parsec.Pos (updatePosChar) Return everything consumed except for the end pattern itself. -} takeUntil :: Text -> Parser Text -takeUntil end_ = Text.dropEnd (Text.length end_) <$> requireEnd (scan p (False, end)) >>= gotSome +takeUntil end_ = + requireEnd (scan p (False, end)) + >>= gotSome . Text.dropEnd (Text.length end_) where end = Text.unpack end_ diff --git a/src/Types.hs b/src/Types.hs index a41e38b..ec7a4e4 100644 --- a/src/Types.hs +++ b/src/Types.hs @@ -9,6 +9,8 @@ module Types ( ) where +import Data.Foldable (fold) + newtype Document = Document { meta :: Meta } @@ -28,6 +30,7 @@ data Since = Since -- Could have a better type? type Version = [Int] + type Package = String data DocMarkup mod id @@ -51,78 +54,78 @@ data DocMarkup mod id | -- | Bold __bold text__ DocBold (DocMarkup mod id) | {- | Unordered lists - * this - or - - this + * this + or + - this -} DocUnorderedList [DocMarkup mod id] | {- | Ordered lists - 1. this - or - (1) this + 1. this + or + (1) this -} DocOrderedList [(Int, DocMarkup mod id)] | {- | Definition lists - [term] a term - [another term] another definition + [term] a term + [another term] another definition -} DocDefinitionList [(DocMarkup mod id, DocMarkup mod id)] | {- | Code blocks - @ - a code block in here - with multiple lines - @ + @ + a code block in here + with multiple lines + @ - Or with bird tracks: - > some code - > goes here + Or with bird tracks: + > some code + > goes here -} DocCodeBlock (DocMarkup mod id) | {- | Hyperlinks - __marked__: - - - __Auto-detected URLs__: - http://example.com - https://example.com - ftp://example.com - __Markdown style__ - [link text](http://example.com) - [link text]("Module.Name") + __marked__: + + + __Auto-detected URLs__: + http://example.com + https://example.com + ftp://example.com + __Markdown style__ + [link text](http://example.com) + [link text]("Module.Name") -} DocHyperlink (Hyperlink (DocMarkup mod id)) | {- | Pictures - <> - <> + <> + <> - __Markdown Images__ + __Markdown Images__ - ![alt text](image.png) + ![alt text](image.png) -} DocPicture Picture | {- | Inline math expressions - \(mathematical expression\) + \(mathematical expression\) -} DocMathInline String | {- | Math multiline display - \[ - mathematical expression - in multiple lines - \] + \[ + mathematical expression + in multiple lines + \] -} DocMathDisplay String | {- | Anchors, no spaces allowed - #anchor-name# + #anchor-name# -} DocAnchor String | {- | Property descriptions - prop> property description + prop> property description -} DocProperty String | {- | Examples - >>> expression - result line 1 - result line 2 + >>> expression + result line 1 + result line 2 -} DocExamples [Example] | -- | Header @@ -136,7 +139,7 @@ instance Semigroup (DocMarkup mod id) where instance Monoid (DocMarkup mod id) where mempty = DocEmpty - mconcat = foldr (<>) mempty + mconcat = fold data ModuleLink id = ModuleLink { name :: String diff --git a/test/Spec.hs b/test/Spec.hs index 7258a2d..7040f87 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -1,17 +1,15 @@ {-# LANGUAGE OverloadedStrings #-} {-# OPTIONS_GHC -Wno-orphans #-} -import Test.Hspec - -import Identifier (Identifier) -import Lexer -import Parser -import Types - import Data.String (IsString (..)) import Data.Text (Text) import GHC.Stack +import Identifier (Identifier) +import Lexer +import Parser +import Test.Hspec import Text.Parsec.Pos +import Types main :: IO () main = hspec $ do @@ -34,9 +32,9 @@ main = hspec $ do describe "Parser" do it "Bold" do - "__bold__" `shouldParseTo` (DocBold (DocString "bold")) + "__bold__" `shouldParseTo` DocBold (DocString "bold") it "Emphasis" do - "/emphasis/" `shouldParseTo` (DocEmphasis (DocString "emphasis")) + "/emphasis/" `shouldParseTo` DocEmphasis (DocString "emphasis") ------------ -- Tests @@ -57,6 +55,7 @@ modules = do `shouldLexTo` [ (1, 2, Module "OtherModule.Name") , (1, 18, Anchor "myAnchor") ] + link :: Expectation link = "[link to](http://some.website)" From 0d35907d533a144edadbc577a7b74cd6a2bde8be Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Sat, 27 Sep 2025 09:35:46 +0200 Subject: [PATCH 17/18] Remove hlint hard-coded version --- .forgejo/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/test.yaml b/.forgejo/workflows/test.yaml index c7e70a7..fd470bc 100644 --- a/.forgejo/workflows/test.yaml +++ b/.forgejo/workflows/test.yaml @@ -109,7 +109,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - name: Install hlint - run: cabal install hlint-3.8 + run: cabal install hlint - name: Run hlint run: | if [ -d src ]; then hlint src/; fi From 29f6eac7cbbe25720a99ad51958bee54feb56b64 Mon Sep 17 00:00:00 2001 From: Igor Ranieri Date: Sat, 27 Sep 2025 09:37:36 +0200 Subject: [PATCH 18/18] Added missing cabal-update steps --- .forgejo/workflows/test.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.forgejo/workflows/test.yaml b/.forgejo/workflows/test.yaml index fd470bc..d780c83 100644 --- a/.forgejo/workflows/test.yaml +++ b/.forgejo/workflows/test.yaml @@ -90,6 +90,8 @@ jobs: apt-get install -y nodejs - name: Checkout code uses: actions/checkout@v4 + - name: Update Cabal package index + run: cabal update - name: Install fourmolu run: cabal install fourmolu-0.18.0.0 - name: Run fourmolu @@ -108,6 +110,8 @@ jobs: apt-get install -y nodejs - name: Checkout code uses: actions/checkout@v4 + - name: Update Cabal package index + run: cabal update - name: Install hlint run: cabal install hlint - name: Run hlint