Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
3e9d08c
Revert "Remove hls-retrie-plugin (#4839)"
simonhorlick Sep 10, 2026
71d3b96
retrie: Update package bounds and supported ghc versions
simonhorlick Aug 7, 2026
5df3c31
retrie: Add support for GHC 9.14
simonhorlick Aug 7, 2026
fc53d49
retrie: Convert code actions to the codeAction/resolve flow
simonhorlick Aug 7, 2026
1db6ba1
Clean up tests
simonhorlick Sep 10, 2026
cd0e129
retrie: Add test for correctly re-associated ast
simonhorlick Sep 10, 2026
5c96005
retrie: Add test expression has lower precedence
simonhorlick Aug 8, 2026
4b26427
retrie: Add test partially applied function
simonhorlick Sep 10, 2026
6c37dbf
retrie: Add test infix with extra arguments
simonhorlick Sep 10, 2026
6b491a8
retrie: Add test list use
simonhorlick Sep 10, 2026
53ede24
retrie: Add test right-associative expression needs parens
simonhorlick Sep 10, 2026
8121611
retrie: Add test where to let
simonhorlick Sep 10, 2026
2b1f6d3
retrie: Add test where to let arg substitution
simonhorlick Sep 10, 2026
ca111c0
retrie: Add test qualified
simonhorlick Sep 10, 2026
8ccb447
Add dispatch tests
simonhorlick Aug 8, 2026
2edf679
Add tests:
simonhorlick Aug 8, 2026
6262c26
retrie: Add test single clause pattern
simonhorlick Aug 28, 2026
57121e3
retrie: Add test rename let binding
simonhorlick Aug 28, 2026
ba367f9
retrie: Add test rule
simonhorlick Aug 10, 2026
1ff2507
retrie: Add test type synonym
simonhorlick Aug 10, 2026
72f1c8c
retrie: Move import handling to Ide.Plugin.Retrie.Imports
simonhorlick Sep 11, 2026
14b2f36
retrie: Add the imports to the resulting edits
simonhorlick Sep 11, 2026
fbbd325
Move IE item builders into hls-exactprint-utils
simonhorlick Sep 4, 2026
c711e06
Add withCommas to hls-exactprint-utils
simonhorlick Sep 4, 2026
ffcc26e
retrie: Restrict each resolve to a single rewrite spec
simonhorlick Sep 16, 2026
9f9fc8e
retrie: Fix imports
simonhorlick Sep 16, 2026
ccdf39c
retrie: Add testUnfold helper
simonhorlick Sep 16, 2026
01d8f21
retrie: Remove restrictToOriginatingFile
simonhorlick Sep 16, 2026
1d9a6a0
retrie: Add test for unfolds
simonhorlick Sep 16, 2026
b3283d1
retrie: Add Fold test
simonhorlick Sep 18, 2026
f0a51c6
retrie: detect CPP via extension flags
simonhorlick Sep 18, 2026
3ad3960
retrie: Add test unfold cpp branches
simonhorlick Sep 18, 2026
842ef57
retrie: Don't import synthesized names
simonhorlick Sep 19, 2026
ab45d80
retrie: Delta-ify inline source AST
simonhorlick Sep 27, 2026
c6f421d
Move the GetFixity rule into ghcide
simonhorlick Sep 28, 2026
5bdbfd2
retrie: Take fixities from the GetFixity rule
simonhorlick Sep 28, 2026
b7b5016
retrie: Add test definition uses imported fixities
simonhorlick Sep 28, 2026
d03f461
retrie: Inline local definitions with a scoped rewriter
simonhorlick Sep 28, 2026
49d23d8
retrie: Mark qualified as expectFail
simonhorlick Sep 30, 2026
d3ea423
retrie: Offer inline only for equation-bound names
simonhorlick Sep 30, 2026
ca0c74c
retrie: Pin record field offer the equation filter lets through
simonhorlick Sep 30, 2026
c7370ea
retrie: Pin where binder offer the equation filter lets through
simonhorlick Sep 30, 2026
795698d
retrie: Show a warning instead of an internal error
simonhorlick Sep 30, 2026
7f520de
retrie: Raise CannotImport error if extractImports fails
simonhorlick Sep 30, 2026
a80db5e
retrie: Warn and don't make any edits
simonhorlick Sep 30, 2026
e10e726
retrie: Don't treat a refused site as an error
simonhorlick Sep 30, 2026
dd01b98
retrie: Move span filtering to the context updater
simonhorlick Oct 3, 2026
d4c6616
retrie: Parse the target module with comments
simonhorlick Oct 3, 2026
b43a44c
retrie: Compute TextEdits using makeDiffTextEdit
simonhorlick Oct 3, 2026
feb19b2
docs: Fix docs for retrie suggestions
simonhorlick Oct 3, 2026
6f0797b
retrie: Add README.md
simonhorlick Oct 3, 2026
4482235
retrie: Build Imports on GHC 9.12
simonhorlick Oct 3, 2026
be5c44d
retrie: Build Imports on GHC 9.8
simonhorlick Oct 3, 2026
fd1ec5b
retrie: Build Imports on GHC 9.6
simonhorlick Oct 3, 2026
713dd7e
retrie: Use ConIsPatSyn on 9.14 branch
simonhorlick Oct 4, 2026
22109e3
retrie: Fix where binder test expectation
simonhorlick Oct 4, 2026
3b13181
retrie: Inline every use from a local binder
simonhorlick Oct 4, 2026
dc34954
retrie: Inline nested uses from a binder
simonhorlick Oct 4, 2026
89b1703
retrie: Inline only the use at the site
simonhorlick Oct 4, 2026
df3aeb6
retrie: Pass back retrie imports
simonhorlick Oct 5, 2026
da0ce1f
retrie: Refuse inlines that cannot select a clause
simonhorlick Oct 5, 2026
93db181
retrie: Offer Unfold and Fold only for selectable clauses
simonhorlick Oct 5, 2026
fe5d5ae
retrie: Parse rewrite targets at their current version
simonhorlick Oct 5, 2026
096480a
retrie: Add ChildExportUse test
simonhorlick Oct 8, 2026
da47cf0
retrie: Import methods and fields by their own name
simonhorlick Oct 8, 2026
6b55156
retrie: Fix test matrix
simonhorlick Oct 12, 2026
0d630f2
retrie: Cleanup
simonhorlick Oct 13, 2026
77f72fc
retrie: Cleanup
simonhorlick Oct 13, 2026
ee0eb32
retrie: Cosmetics
simonhorlick Oct 15, 2026
1a7bbe5
retrie: Cosmetics
simonhorlick Oct 15, 2026
3ab260a
retrie: Cosmetics
simonhorlick Oct 15, 2026
5f3f5cd
cosmetics
simonhorlick Oct 15, 2026
8c6a24b
retrie: Cosmetics
simonhorlick Oct 15, 2026
dff5330
retrie: Cosmetics
simonhorlick Oct 15, 2026
e3477ff
retrie: Cosmetics
simonhorlick Oct 15, 2026
a1739f4
retrie: Cosmetics
simonhorlick Oct 15, 2026
989f9b1
retrie: Cosmetics
simonhorlick Oct 15, 2026
d725249
retrie: Cosmetics
simonhorlick Oct 15, 2026
8edb9cd
retrie: Import GHC names unqualified
simonhorlick Oct 15, 2026
61e365c
retrie: Cosmetics
simonhorlick Oct 15, 2026
841fe68
retrie: Cosmetics
simonhorlick Oct 15, 2026
076f8fe
retrie: Cosmetics
simonhorlick Oct 15, 2026
b2c1890
retrie: Temporarily remove failing test
simonhorlick Oct 16, 2026
b0e400b
retrie: Use addImportsCPP instead of newImportInsertRange
simonhorlick Oct 16, 2026
0df4ce8
retrie: Don't offer for generated record field selectors
simonhorlick Oct 16, 2026
0d41808
retrie: Cleanup
simonhorlick Oct 16, 2026
8b36fba
retrie: Look spellings up across field and variable namespaces
simonhorlick Sep 4, 2026
e3f6899
retrie: Capture FieldOccs in occurrences check
simonhorlick Oct 16, 2026
5808925
Update vscode-extension-schema golden
simonhorlick Oct 16, 2026
4727fc0
Bump retrie versions in stack.yaml
simonhorlick Oct 16, 2026
f7fdda1
Fix precommit by moving fixityText body into the cpp branches
simonhorlick Oct 18, 2026
1946548
retrie: Update example usage gif
simonhorlick Oct 18, 2026
1e433cb
retrie: Print progress
simonhorlick Oct 18, 2026
efdb147
retrie: Mark all 9.10 releases as unsupported
simonhorlick Oct 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ jobs:
name: Test hls-cabal-plugin test suite
run: cabal test ${CABAL_ARGS} hls-cabal-plugin-tests || cabal test ${CABAL_ARGS} hls-cabal-plugin-tests

- if: matrix.test && matrix.ghc != '9.10' && matrix.ghc != '9.10.2'
name: Test hls-retrie-plugin test suite
run: cabal test ${CABAL_ARGS} hls-retrie-plugin-tests || cabal test ${CABAL_ARGS} hls-retrie-plugin-tests

- if: matrix.test
name: Test hls-overloaded-record-dot-plugin test suite
run: cabal test ${CABAL_ARGS} hls-overloaded-record-dot-plugin-tests || cabal test ${CABAL_ARGS} hls-overloaded-record-dot-plugin-tests
Expand Down
1 change: 1 addition & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
/plugins/hls-qualify-imported-names-plugin @eddiemundo
/plugins/hls-refactor-plugin
/plugins/hls-rename-plugin
/plugins/hls-retrie-plugin @simonhorlick
/plugins/hls-semantic-tokens-plugin @soulomoon
/plugins/hls-signature-help-plugin @jian-lin
/plugins/hls-splice-plugin @konn
Expand Down
1 change: 1 addition & 0 deletions bench/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ configurations:
# - pragmas
# - qualifyImportedNames
# - rename
# - retrie
# - splice
# - stan
# # - stylish-haskell
2 changes: 1 addition & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Here is a list of the additional settings currently supported by `haskell-langua
Plugins have a generic config to control their behaviour. The schema of such config is:

- `haskell.plugin.${pluginName}.globalOn`: usually with default true. Whether the plugin is enabled at runtime or it is not. That is the option you might use if you want to disable completely a plugin.
- Actual plugin names are: `ghcide-code-actions-fill-holes`, `ghcide-completions`, `ghcide-hover-and-symbols`, `ghcide-type-lenses`, `ghcide-code-actions-type-signatures`, `ghcide-code-actions-bindings`, `ghcide-code-actions-imports-exports`, `eval`, `moduleName`, `pragmas`, `importLens`, `class`, `hlint`, `rename`, `semanticTokens`, `splice`, `stan`, `signatureHelp`.
- Actual plugin names are: `ghcide-code-actions-fill-holes`, `ghcide-completions`, `ghcide-hover-and-symbols`, `ghcide-type-lenses`, `ghcide-code-actions-type-signatures`, `ghcide-code-actions-bindings`, `ghcide-code-actions-imports-exports`, `eval`, `moduleName`, `pragmas`, `importLens`, `class`, `hlint`, `retrie`, `rename`, `semanticTokens`, `splice`, `stan`, `signatureHelp`.
- So to disable the import lens with an explicit list of module definitions you could set `haskell.plugin.importLens.globalOn: false`
- `haskell.plugin.${pluginName}.${lspCapability}On`: usually with default true. Whether a concrete plugin capability is enabled.
- Capabilities are the different ways a lsp server can interact with the editor. The current available capabilities of the server are: `callHierarchy`, `codeActions`, `codeLens`, `diagnostics`, `hover`, `symbols`, `completion`, `rename`.
Expand Down
3 changes: 3 additions & 0 deletions docs/contributing/plugin-tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ In the last couple of months, I have written various HLS plugins, including:
1. Suggest imports for variables not in scope,
2. Remove redundant imports,
3. Evaluate code in comments (à la [doctest](https://docs.python.org/3/library/doctest.html)),

These plugins are small but meaningful steps towards a more polished IDE experience.
While writing them, I didn't have to worry about performance, UI, or distribution; another tool (usually GHC) always did the heavy lifting.

Expand Down Expand Up @@ -75,6 +76,7 @@ The HLS codebase includes several plugins (found in `./plugins`). For example:

- The `ormolu`, `fourmolu`, and `stylish-haskell` plugins used to format code
- The `eval` plugin, a code lens provider to evaluate code in comments
- The `retrie` plugin, a code action provider to execute retrie commands

I recommend looking at the existing plugins for inspiration and reference. A few conventions shared by all plugins are:

Expand All @@ -95,6 +97,7 @@ I recommend looking at the existing plugins for inspiration and reference. A few
, Fourmolu.descriptor "fourmolu"
, Ormolu.descriptor "ormolu"
, StylishHaskell.descriptor "stylish-haskell"
, Retrie.descriptor "retrie"
, Eval.descriptor "eval"
, NewPlugin.descriptor "new-plugin" -- Add new plugins here.
]
Expand Down
16 changes: 16 additions & 0 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,22 @@ Code action kind: `quickfix`

Adds placeholders for missing class methods in a class instance definition.

### Fold definition

Provided by: `hls-retrie-plugin`

Code action kind: `refactor.extract`

Replaces any instance of a function's body with a call to that function.

### Unfold definition

Provided by: `hls-retrie-plugin`

Code action kind: `refactor.inline`

Replaces every usage of a function with it's body.

### Insert contents of Template Haskell splice

Provided by: `hls-splice-plugin`
Expand Down
1 change: 1 addition & 0 deletions docs/support/plugin-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,6 @@ For example, a plugin to provide a formatter which has itself been abandoned has
| `hls-semantic-tokens-plugin` | 2 | |
| `hls-stan-plugin` | 3 | 9.12.2, 9.14.1 |
| `hls-splice-plugin` | 3 | |
| `hls-retrie-plugin` | 3 | 9.10.* |

[1]: HLint is incompatible with GHC 9.10 series. See the issue [#4674](https://github.com/haskell/haskell-language-server/issues/4674) for discussion and explanation.
1 change: 1 addition & 0 deletions ghcide/ghcide.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ library
Development.IDE.Spans.AtPoint
Development.IDE.Spans.Common
Development.IDE.Spans.Documentation
Development.IDE.Spans.Fixity
Development.IDE.Spans.LocalBindings
Development.IDE.Spans.Pragmas
Development.IDE.Types.Diagnostics
Expand Down
15 changes: 15 additions & 0 deletions ghcide/src/Development/IDE/Core/RuleTypes.hs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,16 @@ instance Show DocAndTyThingMap where

type instance RuleResult GetDocMap = DocAndTyThingMap

newtype FixityMap = FixityMap (M.Map Name Fixity)

instance NFData FixityMap where
rnf (FixityMap xs) = rnf xs

instance Show FixityMap where
show = const "FixityMap"

type instance RuleResult GetFixity = FixityMap

-- | A GHC session that we reuse.
type instance RuleResult GhcSession = HscEnvEq

Expand Down Expand Up @@ -501,6 +511,11 @@ data GetDocMap = GetDocMap
instance Hashable GetDocMap
instance NFData GetDocMap

data GetFixity = GetFixity
deriving (Eq, Show, Generic)
instance Hashable GetFixity
instance NFData GetFixity

data GetHieAst = GetHieAst
deriving (Eq, Show, Generic)
instance Hashable GetHieAst
Expand Down
19 changes: 19 additions & 0 deletions ghcide/src/Development/IDE/Core/Rules.hs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ import Development.IDE.Import.DependencyInformation
import Development.IDE.Import.FindImports
import qualified Development.IDE.Spans.AtPoint as AtPoint
import Development.IDE.Spans.Documentation
import Development.IDE.Spans.Fixity
import Development.IDE.Spans.LocalBindings
import Development.IDE.Types.Diagnostics as Diag
import Development.IDE.Types.HscEnvEq
Expand Down Expand Up @@ -199,6 +200,8 @@ import System.FilePath (dropExtension,
splitDirectories,
takeExtension,
takeFileName)
import qualified Data.Set as S
import Data.Either (isRight)

data Log
= LogShake Shake.Log
Expand Down Expand Up @@ -600,6 +603,20 @@ getDocMapRule recorder =
persistentDocMapRule :: Rules ()
persistentDocMapRule = addPersistentRule GetDocMap $ \_ -> pure $ Just (DKMap mempty mempty mempty, idDelta, Nothing)

getFixityRule :: Recorder (WithPriority Log) -> Rules ()
getFixityRule recorder =
define (cmapWithPrio LogShake recorder) $ \GetFixity nfp -> do
HAR{refMap} <- use_ GetHieAst nfp
env <- hscEnv <$> use_ GhcSessionDeps nfp -- deps necessary so that we can consult already loaded in ifaces instead of loading in duplicates
tcGblEnv <- tmrTypechecked <$> use_ TypeCheck nfp
fs <- lookupFixities env tcGblEnv (S.mapMonotonic (\(Right n) -> n) $ S.filter isRight $ M.keysSet refMap)
pure ([], Just (FixityMap fs))


-- | Persistent rule to ensure that hover doesn't block on startup
persistentFixityRule :: Rules ()
persistentFixityRule = addPersistentRule GetFixity $ \_ -> pure $ Just (FixityMap M.empty, idDelta, Nothing)

readHieFileForSrcFromDisk :: Recorder (WithPriority Log) -> NormalizedFilePath -> MaybeT IdeAction Compat.HieFile
readHieFileForSrcFromDisk recorder file = do
ShakeExtras{withHieDb} <- ask
Expand Down Expand Up @@ -1441,6 +1458,7 @@ mainRule recorder RulesConfig{..} = do
reportImportCyclesRule recorder
typeCheckRule recorder
getDocMapRule recorder
getFixityRule recorder
loadGhcSession recorder def{fullModuleGraph}
getModIfaceFromDiskRule recorder
getModIfaceFromDiskAndIndexRule recorder
Expand All @@ -1467,6 +1485,7 @@ mainRule recorder RulesConfig{..} = do
getImportMapRule recorder
persistentHieFileRule recorder
persistentDocMapRule
persistentFixityRule
persistentImportMapRule
getLinkableRule recorder
defineEarlyCutoff (cmapWithPrio LogShake recorder) $ Rule $ \GetModuleGraphTransDepsFingerprints file -> do
Expand Down
1 change: 1 addition & 0 deletions ghcide/src/Development/IDE/GHC/Orphans.hs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ instance Show ModDetails where show = const "<moddetails>"
instance NFData ModDetails where rnf = rwhnf
#if !MIN_VERSION_ghc(9,13,0)
instance NFData SafeHaskellMode where rnf = rwhnf
instance NFData Fixity where rnf = rwhnf
#endif
instance Show Linkable where show = unpack . printOutputable
#if MIN_VERSION_ghc(9,11,0)
Expand Down
27 changes: 27 additions & 0 deletions ghcide/src/Development/IDE/Spans/Fixity.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{-# LANGUAGE OverloadedStrings #-}

module Development.IDE.Spans.Fixity (lookupFixities) where

import Control.Monad.IO.Class (MonadIO, liftIO)
import qualified Data.Map.Strict as M
import Data.Maybe (fromMaybe)
import qualified Data.Set as S
import Development.IDE.GHC.Compat
import qualified Development.IDE.GHC.Compat.Util as Util

-- | Convert a HieAST to FixityTree with fixity info gathered
lookupFixities :: MonadIO m => HscEnv -> TcGblEnv -> S.Set Name -> m (M.Map Name Fixity)
lookupFixities hscEnv tcGblEnv names
= liftIO
$ fmap (fromMaybe M.empty . snd)
$ initTcWithGbl hscEnv tcGblEnv (realSrcLocSpan $ mkRealSrcLoc "<dummy>" 1 1)
$ M.traverseMaybeWithKey (\_ v -> v)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, this line (which I see already existed) is absurdly dense 😆

I can't even word what ti does...

$ M.fromSet lookupFixity names
where
lookupFixity name = do
f <- Util.handleGhcException
(const $ pure Nothing)
(Just <$> lookupFixityRn name)
if f == Just defaultFixity
then pure Nothing
else pure f
72 changes: 69 additions & 3 deletions haskell-language-server.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,73 @@ test-suite hls-rename-plugin-tests
, lsp-types
, text

-----------------------------
-- retrie plugin
-----------------------------

flag retrie
description: Enable retrie plugin
default: True
manual: True

common retrie
if flag(retrie) && (!impl(ghc ==9.10.*) || flag(ignore-plugins-ghc-bounds))
build-depends: haskell-language-server:hls-retrie-plugin
cpp-options: -Dhls_retrie

library hls-retrie-plugin
import: defaults, pedantic, warnings
if !(flag(retrie) && (!impl(ghc ==9.10.*) || flag(ignore-plugins-ghc-bounds)))
buildable: False
exposed-modules: Ide.Plugin.Retrie
other-modules:
Ide.Plugin.Retrie.Imports
hs-source-dirs: plugins/hls-retrie-plugin/src
build-depends:
, filepath
, aeson
, bytestring
, containers
, extra
, ghc
, ghc-boot-th
, ghcide == 2.15.0.0
, hashable
, hls-plugin-api == 2.15.0.0
, haskell-language-server:hls-refactor-plugin
, haskell-language-server:hls-exactprint-utils
, lens
, lsp
, lsp-types
, mtl
, retrie >=2.0.0
, safe-exceptions
, stm
, syb
, text
, text-rope
, transformers
, unliftio-core
, unordered-containers

default-extensions:
DataKinds

test-suite hls-retrie-plugin-tests
import: defaults, pedantic, test-defaults, warnings
if !(flag(retrie) && (!impl(ghc ==9.10.*) || flag(ignore-plugins-ghc-bounds)))
buildable: False
type: exitcode-stdio-1.0
hs-source-dirs: plugins/hls-retrie-plugin/test
main-is: Main.hs
build-depends:
, containers
, filepath
, hls-plugin-api
, haskell-language-server:{hls-refactor-plugin, hls-retrie-plugin}
, hls-test-utils == 2.15.0.0
, text

-----------------------------
-- hlint plugin
-----------------------------
Expand Down Expand Up @@ -1299,10 +1366,7 @@ library hls-explicit-fixity-plugin
hs-source-dirs: plugins/hls-explicit-fixity-plugin/src
build-depends:
, containers
, deepseq
, extra
, ghcide == 2.15.0.0
, hashable
Comment thread
simonhorlick marked this conversation as resolved.
, hls-plugin-api == 2.15.0.0
, lsp >=2.8
, text
Expand Down Expand Up @@ -1821,6 +1885,7 @@ library hls-exactprint-utils
exposed-modules:
Development.IDE.GHC.ExactPrint.Annotation
Development.IDE.GHC.ExactPrint.CPP
Development.IDE.GHC.ExactPrint.IE
hs-source-dirs: hls-exactprint-utils/src
build-depends:
, ghc
Expand Down Expand Up @@ -1910,6 +1975,7 @@ library
, importLens
, caseSplit
, rename
, retrie
, hlint
, stan
, signatureHelp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module Development.IDE.GHC.ExactPrint.Annotation
, removeTrailingCommaAnn
, ensureTrailingComma
, withTrailingComma
, withCommas
, modifyAnns
, addParens
, parenthesizeName
Expand Down Expand Up @@ -85,6 +86,12 @@ ensureTrailingComma ann
| any isCommaAnn (trailingAnns ann) = ann
| otherwise = addComma ann

-- | Add a trailing comma to every element but the last.
withCommas :: [LocatedAn AnnListItem a] -> [LocatedAn AnnListItem a]
withCommas [] = []
withCommas [x] = [x]
withCommas (L l e : xs) = L (ensureTrailingComma l) e : withCommas xs
Comment on lines +91 to +93

@Aster89 Aster89 Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, you can do this with lenses:

Suggested change
withCommas [] = []
withCommas [x] = [x]
withCommas (L l e : xs) = L (ensureTrailingComma l) e : withCommas xs
withCommas = over _init $ map ensureTrailingComma'
where ensureTrailingComma' (L l e) = L (ensureTrailingComma l) e

I'm still new to them, so I'm just spotting opportunities to practice with it

λ> over _init (map (*10)) ([] :: [Int])
[]
λ> over _init (map (*10)) ([1] :: [Int])
[1]
λ> over _init (map (*10)) ([1..3] :: [Int])
[10,20,3]

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to spend some time to learn how to use lenses. It reads quite clearly.


-- | Replace an item's trailing comma with @c@, preserving its delta.
withTrailingComma :: TrailingAnn -> SrcSpanAnnA -> SrcSpanAnnA
withTrailingComma c = overTrailingAnns (\as -> filter (not . isCommaAnn) as ++ [c])
Expand Down
Loading
Loading