spoon icon indicating copy to clipboard operation
spoon copied to clipboard

Feature request: provide API to add blank lines

Open schakko opened this issue 7 years ago • 13 comments

This is a simple feature request with no real business value but makes it a lot more easier to read through the source code.

Usage

block.addStatement(getFactory().createCodeSnippetStatement("int i = 1"));
block.addStatement(getFactory().createBlankLine());
// or block.addBlankLine()
block.addStatement(getFactory().createCodeSnippetStatement("for (; i < 0; i++) {}));

Current result

int i = 1;
for (; i < 0; i++) {}

Expected result

int i = 1;

for (; i < 0; i++) {}

schakko avatar Apr 20 '17 11:04 schakko

Actually I don't agree with that kind of API: block.addStatement(getFactory().createBlankLine());

because it would mean that the blank line will be contained in the model, whereas it's only a pretty-print consideration. However, maybe you could have a look on the DefaultJavaPrettyPrinter to improve or customize it to render the code for your specific needs.

surli avatar Apr 20 '17 12:04 surli

block.addStatement(getFactory().createBlankLine());

This simple API looks good to me. Would you propose a tentative implementation in a pull request?

monperrus avatar Apr 24 '17 13:04 monperrus

I suggest to have formatting information OPTIONALLY configurable on level of each CtElement.

If the formatting information is not null then DJPP would use it instead of standard formatting.

The formatting information might consist of this information:

  • number of EOL before the element
  • number of extra TABs and SPACES before the element
  • number of EOL after the element

To have it memory efficient, we can share this complex structure between all elements, which has same formatting request.

pvojtechovsky avatar Oct 15 '17 13:10 pvojtechovsky

CtElement#getMetaData is an option for this.

monperrus avatar Oct 16 '17 09:10 monperrus

For me the best way to handle it is to support standart Code Formatter Settings (xml file). like this one: https://github.com/mantono/CodeFormatterSettings/blob/master/intellij/Java.xml

tdurieux avatar Oct 16 '17 09:10 tdurieux

@schakko What would you preffer? A) to be able to add extra line break on selected model element B) to be able to define formatting rule, which adds that extra line before each for cycle C) ???

I guess it depends on the use case UC1) to keep formatting of source unchanged to minimize differences in history of source file. UC2) to format printed sources following customizable rules to pass the clients checkstyle rules. UC3) to apply special formatting to specific place to higlight that code.

It would be nice to support all these usecases

pvojtechovsky avatar Oct 16 '17 15:10 pvojtechovsky

Personally I'd prefer option A as I like to have control when to add a line break. For example, after initialization of local variables I always add a line break to visualize that business logic follows. A formatter setting can't handle this use case.

schakko avatar Oct 16 '17 19:10 schakko

Automated source code formatting cannot determine when to apply newlines for grouping blocks of code that are logically related. For example:

String[] tokens = key.split(XML_DELIM);
List<String> tokenList = new ArrayList(Arrays.asList(tokens));
tokenList.remove(tokenList.size() - 1);
LOG.fine( "..." );

String parentKey = buildString(tokenList);
LOG.fine( "..." );

Element parentElement = getElementMap().get(parentKey);
if (parentElement == null) {
    parentElement = createElementHierarchy(parentKey);
}
LOG.fine( "..." );

Usually I'd want a blank line before and after the if statement. In this case, I can understand why the author kept those lines together: those lines form a related, coherent snippet.

After processing with Spoon, the code becomes:

String[] tokens = key.split(XML_DELIM);
List<String> tokenList = new ArrayList(Arrays.asList(tokens));
tokenList.remove(tokenList.size() - 1);
LOG.fine( "..." );
String parentKey = buildString(tokenList);
LOG.fine( "..." );
Element parentElement = getElementMap().get(parentKey);
if (parentElement == null) {
    parentElement = createElementHierarchy(parentKey);
}
LOG.fine( "..." );

This "wall of text" loses information.

it would mean that the blank line will be contained in the model, whereas it's only a pretty-print consideration.

Depends on how one views the model as it pertains to the problem domain. For an interpreter or compiler, whitespace and comments are superfluous. For a source code manipulation tool, whitespace is reasonably important to track. Although an AST doesn't generally include whitespace, line terminators, and comments, such lexical preservation is not unheard of. See also:

  • https://tomassetti.me/lexical-preservation-javaparser/
  • http://www.docjar.com/html/api/org/eclipse/jdt/core/JavaCore.java.html (line 1904)
  • http://swerl.tudelft.nl/twiki/pub/Main/TechnicalReports/TUD-SERG-2011-027.pdf

Having a CtBlankLine in the AST would help preserve layout in those cases where blank lines convey meaning that cannot be determined by an automated source beautifier.

ghost avatar Oct 20 '17 18:10 ghost

I do agree that vertical spacing has a semantic.

The current solution to this is the somewhat experimental "--lines" option.

The next solution is the so-called sniper mode (#1358) where any help would be appreciated to finish the implementation and testing.

monperrus avatar Oct 20 '17 21:10 monperrus

i am a beginner can i work on this can i write this issue for my coding period in GSoC spoon project proposal?

KishkinJ10 avatar Apr 06 '21 13:04 KishkinJ10

Talking about this feature with @MartinWitt today.

This feature would definitely be useful. In addition, it may be a solution to workaround some limitations of the sniper printer.

cc/ @bbaudry @deee92

monperrus avatar Apr 25 '22 11:04 monperrus

per our meeting, is what you're looking for @I-Al-Istannen?

monperrus avatar Jan 31 '23 17:01 monperrus

Yes, it would be helpful sometimes to create some visual separation. I think @MartinWitt did some stuff with custom AST elements which just cause a whitespace to be printed. I haven't really thought about a nice API for this.

I-Al-Istannen avatar Jan 31 '23 21:01 I-Al-Istannen