Skip to content

Exactprinter & modification framework, take 2 - #12316

Draft
leana8959 wants to merge 15 commits into
haskell:masterfrom
leana8959:transform-fields-poc
Draft

leana8959 wants to merge 15 commits into
haskell:masterfrom
leana8959:transform-fields-poc

Conversation

@leana8959

@leana8959 leana8959 commented Sep 4, 2026 •

Copy link
Copy Markdown
Collaborator

I made substantial progress in the exactprinter & modification framework describe in the proposal haskell/cabal-proposals#7. This branch/PR shows how it works.

The diff is roughly 2.5k (it's stacked on the #11252).

TL;DR: The exactprinter allows programmers to parse a fields file, and printed it back exactly the same (with the exception that we decided that trailing spaces will be discarded for now for a simple first implementation).
The modification framework allows users to modify values in the cabal fields tree in a typed manner.

In Cabal-tests/tests/ParserTests.hs you can find examples of how the API would look like.

I am planning to rewrite the modification framework with a Relative monad, so that the modification will only have to handle offsets, and changes become more composable. Absolute position will only need to be resolved in the end of the modification. This is not yet implemented.


Please read Github PR Conventions and then fill in one of these two templates.


Template Α: This PR modifies behaviour or interface

Include the following checklist in your PR:


Template B: This PR does not modify behaviour or interface

E.g. the PR only touches documentation or tests, does refactorings, etc.

Include the following checklist in your PR:

  • Patches conform to the coding conventions.
  • Is this a PR that fixes CI? If so, it will need to be backported to older cabal release branches (ask maintainers for directions).

leana8959 and others added 11 commits September 19, 2026 15:26
This lays the foundation for Cabal-exactprint to consume user comments.

The parser of the envelope format ("field parser") now annotates each of
the parsed fields with its preceding and succeeding comments, along with
the existing source location annotation 'Position'.

This change is orthogonal to the final chosen exactprint implementation,
or the algebra we use to modify existing fields and/or generate new
fields. Instead, it merely makes the user comments available to any
consumer that reads cabal fields, the envelope format.

readFields* functions now have their counterparts that parses with
comments, named readFieldsWithComments*.
@leana8959
leana8959 force-pushed the transform-fields-poc branch 2 times, most recently from f09cbf5 to 3e1d2f1 Compare September 22, 2026 17:14
use transform example

refactor modifying, take 1

refactor modifying, take 2

rename functions

preverse correct starting position

extract and restore comments

edit target build depend example

HasPos class

print to stderr to avoid interleaving

test editing

make edit better

implement relativization

clean up relativization

compute line position

add new joining function

rewrite transformation algebra

use relative spacing in modification

clean up, move Fields.Spacing to its own module

clean up test suite

include comment in relative spacing conversion

checkpoint

implement a simple renderer for Field ann

initialize test for field exact rendering

debug exact printer

roundtrip is possible

roundtrip poc

Run cabal test Cabal-tests:hackage-tests --test-option="field-roundtrip"

dump everything that don't match in exact print hackage test

restore joining, ditch spacing experiments for now

add naive tabs to space substitution, remove tracing

demonstrate cabal project file roundtrip

ignore stupid errors and focus on the real ones

patch tabs -> space, empty lines, and lineendings

drop empty lines at end of file

retain position of colon

This needs to be refined but it's the basic idea.

make colon closest to field name and not separated by comments

print failed filenames for further processing and investigation

add a few examples for quotes

apply hints

rewrite exact printer with RWS

remove irrelevant todo

fix tests

restore final trailing newline

prevent memory leak

print quotes

add unit test for simple transformation

implement modifyValueList

remove useless instance

add few new tests and CRLF support

comment out traces

implement splitBSAtPosition, add tests

implement substituteSubBSAt

fix off by one

The way parsec combinators save position makes it save on the first and last char.
We need to increment the position to make the end position exclusive.

clean up joinFieldLine implementation, add tests

test modifyValueList

Located combinator will report the placement when the parser is done.
If a parser consumes trailing spaces, it will report a ending position that is too far below.
This is the case for dependency.

fix off by one

fix in list modification trailing list

remove tracing

split bytestring transformation from fieldlines

implement tests for modifyValueAtomAlaBS

rename functions

test modification of strings at any position within a dependency list

parameterize edit functions with lineending configuration

run formatter

add examples for stringy lists

implement prepend item in list

clean up modification framework to better match the proposal

add simple modification framework tests

field removal

fix removal, add tested test

add a line ending guessing function

add todos

fine grain adding/removing/modifying

fix mapping functions

doesn't really matter, we can just tell the user

but maybe the open approach can allow user to do this. hmm.

implement cascading to chain fallback edits

rewrite in individual simple functions

simplify function naming

add todos

rename configuration types

edit distributivity

add product operator

add hasChanged assertion operator

clean up todos

create a concrete edit error type

remove applicative instance

remove temporary call to error

implement fieldline splitting

remove duplicated functions and newline handling

We always split the lines to a field line, so we don't care

use split fieldlines

start implementing position fixing in addField

fixes, complete add's position shifting

fix one-indexed position, accept test result

test AddStart as well

implement position shifting in modifyField and modifySection

remove ModifyAll mode

add a modify test

update substitute sub bytestring at tests

Previously the ending was not inclusing, I must have changed how it
works.

add an integration test

replace Newtype class with Coerce class

fix newtype class in parser tests

add a pass to turn name to lower case

accept casing in concrete parsing

document the reason of orFallback

add comment handling in modification functions

update comment handling in test suite

add comment in example

add export list to transform module

make modifyValueList partial

make modifyValueAtomAla partial

allow using partial modification function in modify focuses

add instances to fix test

update todos

remove project files

add todos

add export list for ExactPretty

add proper position shifting logic in new field

fix colonPos calculation

remove todo

add a basic add section function

make prependValueListBS partial

add a function to prepend function list

move code around

clean up imports

implement example formatter to test out the idea

add a function to run the formatter

run the build-depends formatter as an example

add shared context to edit functions

move code around, remove dead code

implement sectionArgBS

refactor using monad instance

run formatter

liftA2 is cool

move parsec orphan instance to its module

update todo on labels

reuse transform functions to format

proper formatting example with multiple sections

add modifyConfitionConfVar

document position handling

run formatter

fix test suite

add fields to example

demonstrate printing

rip out formatter poc

This will be put into a separate PR for demonstration

clean up warnings

fix import

run formatter

fix lints

fix conditional import

fix compilation

run formatter

fix compilation warning

fix whitespaces

fix typos

guard field concrete syntax annotation behind pattern synonyms

fix doctests

Revert "fix whitespaces"

This reverts commit c53ef37.

exclude golden test files from whitespace check

restore poc version of transform.hs

fix test compilation

update test expectations

fix validate

fix linting

remove use of foldl1'

It uses Data.Foldable1 and is too recent, I don't want to do cpp

guard pattern export behind CPP
@philderbeast

philderbeast commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

To avoid the GHC parser failure, the whole export list can be disabled:

fourmolu-export-cpp.patch

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants