Skip to content

Formatter poc - #12319

Draft
leana8959 wants to merge 61 commits into
haskell:masterfrom
leana8959:formatter-poc
Draft

Formatter poc#12319
leana8959 wants to merge 61 commits into
haskell:masterfrom
leana8959:formatter-poc

Conversation

@leana8959

@leana8959 leana8959 commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

This is a proof of concept of an alternative formatter in cabal by implementing a third instance of FieldGrammar, stacked on top of the exactprinting framework. By doing so we get for free, functions that format each FieldLine according to the type they should be parse/printed with.

This formatter has interesting properties: it doesn't fuse in common stanzas.
Comments are not handled at the moment but it can be done in the future. We just need to agree on a sensible way to interleave comments with rerendered data.

In Cabal-syntax/src/Distribution/PackageDescription/Format.hs you can see how to define a formatter using existing field grammar for each section. In Cabal-tests/tests/ParserTests/format-printed/simple_buildinfo.expr you will find the printed version (in golden file expression) of Cabal-tests/tests/ParserTests/format-printed/simple.cabal. No outer structure is changed, only the values.

In Cabal-syntax/src/Distribution/FieldGrammar/Format.hs you can find the new formatter instance. It is very simple and serves as a shim layer to recover type information associated with each field name in FieldGrammar definitions.

No new Parsec or Pretty instances need to be written, they are already there and their existence is enforced by the compiler.

What's left to do to make this good:

  • handle comments
  • align fieldlines (the exactprint idea preserves their original position, aligning them is more of a formatter's job)

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 30 commits July 24, 2026 11:16
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*.
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
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.

1 participant