justinpombrio / partial-pretty-printer

A pretty printing library for formatting source code in any language, which can efficiently print just part of a document.
Apache License 2.0
3 stars 0 forks source link

Comments #11

Closed justinpombrio closed 8 months ago

justinpombrio commented 11 months ago

We need to handle comments. There are a few tricky issues.

Problems

Comments vs. Doc comments

Doc comments apply to a node, such as a function definition or an enum variant. Regular comments typically do not. For example, a comment in the middle of a function body might be meant to apply to all following lines; commented-out code does not apply to whatever happens to come next; and regular comments can appear at the end of a file.

Therefore, doc comments should be an optional child of the node they apply to. In Rust, they're placed above a function, or sometimes at the top of a module; in Python they're in doc strings before the function body; in other languages they might be allowed to be at the end of a line.

Regular comments, by contrast, exist between nodes. Usually they're between listy nodes, but we may want to support them appearing between fixed arity nodes as well. (The only real reason to support them between fixed arity nodes is to accurately represent code written in a text editor that has comments in strange places.)

Commented-out code

You should be able to

End of line comments

What should happen if there's a comment like:

foobar(bizzazzle, boozazzle) // foobar the bezazzles

Is that equivalent to a comment on the previous line?

// foobar the bezazzles
foobar(bizzazzle, boozazzle)

Inline block comments

What should we do with inline block comments like these?

let x = /* one */ 1 /* plus */ + /* two */ 2;

Comments and commas

How is this JSON list displayed?

[
    one,
    // comment1
    two
    // comment2
    // comment3
]

Assuming that we're using "sibling comments" (see "Comments vs. Doc Comments"), this list has five elements, three of which are whitespace elements. Commas must be placed only after the element one, not after comments or two (because JSON). So the rule is that you put a comment after every non-last, non-whitespace element.

Proposed Solutions

Commented-out code

When you comment out code, it's placed in a special "code block" node in the comment. Or alternatively, it's placed in a "commented code" node (as distinguished from "comment" nodes). Either way, it marks what sort of code was commented. For example, commented-out code when saved to a text file might appear as:

// ``` rust statement
//     let x = 1;
// ```

Commented-out code from a text editor appears as regular comments, and cannot be un-commented. (Unless you manually add the "commented code" node syntax.)

End of line comments

End of line comments can be parsed, but are always converted to before-line comments. This is due to an interaction of rules we really want to hold:

  1. Navigation order equals visual order. A before-line comment would have to be the first child, while and end of line comment would have to be the last child, so that when you navigate to the next sibling you don't jump around.
  2. Fixed navigation order: if you edit a comment, it absolutely cannot move to a different location in the tree. However, an end of line comment can only be so long while fitting on the line and needing to be moved. (And in screen reader mode, line width isn't even defined).

Inline block comments

At least for now, turn inline block comments into before-line comments. Thus this code:

let x = /* one */ 1 /* plus */ + /* two */ 2;

gets converted into:

// one
// plus
// two
let x = 1 + 2;

Comments vs. Doc comments

Doc comments are optional children of the node they annotate.

Regular comments can appear only in listy nodes, where they can be interspersed with regular children.

Comments and commas

The notation language can handle this with two new predicates:

There's a new kind of notation called If that takes a Predicate, which is made of the base predicates above joined by Not, And, Or. These predicates are implemented by PrettyDoc, just like IsEmptyText is currently.

e-matteson commented 8 months ago

We also need a way to change the style of code when it's commented out. Some possible solutions are:

e-matteson commented 8 months ago

We also need a way to change the style of code when it's commented out

This is now supported, after the style/mark unification. Synless's style struct can have a comment: Option<bool> field or something.

justinpombrio commented 8 months ago

Done with the PPP parts. The rest has been migrated to a Synless issue.