We need to decide what we want to do with end-of-line-whitespace

Code view:

A painting is a person's account of this edit as text, recorded independently of the node mapping - a rendering often has several equally defensible answers where the mapping has one. Deletions and insertions carry no position on the opposite side in a painting, so that panel draws no caret for them.

Before

1package org.jsoup.nodes;
2
3import org.jsoup.helper.Validate;
4import org.jsoup.parser.Tag;
5
6import java.nio.charset.Charset;
7import java.nio.charset.CharsetEncoder;
8import java.util.ArrayList;
9import java.util.List;
10
11/**
…lines 12–105 unchanged (94 lines)
106
107 // pull text nodes out of root, html, and head els, and push into body. non-text nodes are already taken care
108 // of. do in inverse order to maintain text order.
109 normaliseTextNodes(head());
110 normaliseTextNodes(htmlEl);
111 normaliseTextNodes(this);
112
113
114 return this;
115 }
116
117 // does not recurse.
118 private void normaliseTextNodes(Element element) {
…lines 119–130 unchanged (12 lines)
131 body().prependChild(new TextNode(" ", ""));
132 body().prependChild(node);
133 }
134 }
135
136 // merge multiple <head> or <body> contents into one, delete the remainder, and ensure they are owned by <html>
137 // ensure parented by <html>
138
139 // fast method to get first by tag name, used for html, head, body finders
140 private Element findFirstElementByTagName(String tag, Node node) {
141 if (node.nodeName().equals(tag))
142 return (Element) node;
143 else {
144 for (Node child: node.childNodes) {
…lines 145–294 unchanged (150 lines)

After

1package org.jsoup.nodes;
2
3import org.jsoup.helper.Validate;
4import org.jsoup.parser.Tag;
5import org.jsoup.select.Elements;
6
7import java.nio.charset.Charset;
8import java.nio.charset.CharsetEncoder;
9import java.util.ArrayList;
10import java.util.List;
11
…lines 12–107 unchanged (96 lines)
108 // pull text nodes out of root, html, and head els, and push into body. non-text nodes are already taken care
109 // of. do in inverse order to maintain text order.
110 normaliseTextNodes(head());
111 normaliseTextNodes(htmlEl);
112 normaliseTextNodes(this);
113
114 normaliseStructure("head", htmlEl);
115 normaliseStructure("body", htmlEl);
116
117 return this;
118 }
119
120 // does not recurse.
121 private void normaliseTextNodes(Element element) {
…lines 122–133 unchanged (12 lines)
134 body().prependChild(new TextNode(" ", ""));
135 body().prependChild(node);
136 }
137 }
138
139 // merge multiple <head> or <body> contents into one, delete the remainder, and ensure they are owned by <html>
140 private void normaliseStructure(String tag, Element htmlEl) {
141 Elements elements = this.getElementsByTag(tag);
142 Element master = elements.first(); // will always be available as created above if not existent
143 if (elements.size() > 1) { // dupes, move contents to master
144 List<Node> toMove = new ArrayList<Node>();
145 for (int i = 1; i < elements.size(); i++) {
146 Node dupe = elements.get(i);
147 for (Node node : dupe.childNodes)
148 toMove.add(node);
149 dupe.remove();
150 }
151
152 for (Node dupe : toMove)
153 master.appendChild(dupe);
154 }
155 // ensure parented by <html>
156 if (!master.parent().equals(htmlEl)) {
157 htmlEl.appendChild(master); // includes remove()
158 }
159 }
160
161 // fast method to get first by tag name, used for html, head, body finders
162 private Element findFirstElementByTagName(String tag, Node node) {
163 if (node.nodeName().equals(tag))
164 return (Element) node;
165 else {
…lines 166–316 unchanged (151 lines)

Before

program
package_declaration
package "package"
scoped_identifier
scoped_identifier
identifier "org"
. "."
identifier "jsoup"
. "."
identifier "nodes"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "org"
. "."
identifier "jsoup"
. "."
identifier "helper"
. "."
identifier "Validate"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "org"
. "."
identifier "jsoup"
. "."
identifier "parser"
. "."
identifier "Tag"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "java"
. "."
identifier "nio"
. "."
identifier "charset"
. "."
identifier "Charset"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "java"
. "."
identifier "nio"
. "."
identifier "charset"
. "."
identifier "CharsetEncoder"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
identifier "java"
. "."
identifier "util"
. "."
identifier "ArrayList"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
identifier "java"
. "."
identifier "util"
. "."
identifier "List"
; ";"
block_comment "/**\n A HTML Document.\n\n @author Jonathan Hedley, jonathan@he"...
class_declaration
modifiers
public "public"
class "class"
identifier "Document"
superclass
extends "extends"
type_identifier "Element"
class_body
{ "{"
field_declaration
modifiers
private "private"
type_identifier "OutputSettings"
variable_declarator
identifier "outputSettings"
= "="
object_creation_expression
new "new"
type_identifier "OutputSettings"
argument_list
( "("
) ")"
; ";"
block_comment "/**\n Create a new, empty Document.\n @param baseUri b"...
constructor_declaration (+32 nodes collapsed)
block_comment "/**\n Create a valid, empty shell of a document, suitable"...
method_declaration (+85 nodes collapsed)
block_comment "/**\n Accessor to the document's {@code head} element.\n "...
method_declaration (+25 nodes collapsed)
block_comment "/**\n Accessor to the document's {@code body} element.\n "...
method_declaration (+25 nodes collapsed)
block_comment "/**\n Get the string contents of the document's {@code ti"...
method_declaration (+58 nodes collapsed)
block_comment "/**\n Set the document's {@code title} element. Updates t"...
method_declaration (+96 nodes collapsed)
block_comment "/**\n Create a new Element, with this document's base uri"...
method_declaration (+39 nodes collapsed)
block_comment "/**\n Normalise the document. This happens after the pars"...
method_declaration
modifiers
public "public"
type_identifier "Document"
identifier "normalise"
formal_parameters
( "("
) ")"
block
{ "{"
local_variable_declaration
type_identifier "Element"
variable_declarator
identifier "htmlEl"
= "="
method_invocation
identifier "findFirstElementByTagName"
argument_list
( "("
string_literal
" "\""
string_fragment "html"
" "\""
, ","
this "this"
) ")"
; ";"
if_statement (+23 nodes collapsed)
if_statement (+26 nodes collapsed)
if_statement (+26 nodes collapsed)
line_comment "// pull text nodes out of root, html, and head els, and push"...
line_comment "// of. do in inverse order to maintain text order."
expression_statement
method_invocation
identifier "normaliseTextNodes"
argument_list
( "("
method_invocation
identifier "head"
argument_list
( "("
) ")"
) ")"
; ";"
expression_statement
method_invocation
identifier "normaliseTextNodes"
argument_list
( "("
identifier "htmlEl"
) ")"
; ";"
expression_statement
method_invocation
identifier "normaliseTextNodes"
argument_list
( "("
this "this"
) ")"
; ";"
return_statement
return "return"
this "this"
; ";"
} "}"
line_comment "// does not recurse."
method_declaration (+194 nodes collapsed)
line_comment "// merge multiple <head> or <body> contents into one, delete"...
line_comment "// ensure parented by <html>"
line_comment "// fast method to get first by tag name, used for html, head"...
method_declaration (+94 nodes collapsed)
method_declaration (+25 nodes collapsed)
block_comment "/**\n Set the text of the {@code body} of this document. "...
method_declaration (+36 nodes collapsed)
method_declaration (+21 nodes collapsed)
block_comment "/**\n * A Document's output settings control the form of "...
class_declaration (+343 nodes collapsed)
block_comment "/**\n * Get the document's current output settings.\n "...
method_declaration
modifiers
public "public"
type_identifier "OutputSettings"
identifier "outputSettings"
formal_parameters
( "("
) ")"
block
{ "{"
return_statement
return "return"
identifier "outputSettings"
; ";"
} "}"
} "}"

After

program
package_declaration
package "package"
scoped_identifier
scoped_identifier
identifier "org"
. "."
identifier "jsoup"
. "."
identifier "nodes"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "org"
. "."
identifier "jsoup"
. "."
identifier "helper"
. "."
identifier "Validate"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "org"
. "."
identifier "jsoup"
. "."
identifier "parser"
. "."
identifier "Tag"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "org"
. "."
identifier "jsoup"
. "."
identifier "select"
. "."
identifier "Elements"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "java"
. "."
identifier "nio"
. "."
identifier "charset"
. "."
identifier "Charset"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "java"
. "."
identifier "nio"
. "."
identifier "charset"
. "."
identifier "CharsetEncoder"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
identifier "java"
. "."
identifier "util"
. "."
identifier "ArrayList"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
identifier "java"
. "."
identifier "util"
. "."
identifier "List"
; ";"
block_comment "/**\n A HTML Document.\n\n @author Jonathan Hedley, jonathan@he"...
class_declaration
modifiers
public "public"
class "class"
identifier "Document"
superclass
extends "extends"
type_identifier "Element"
class_body
{ "{"
field_declaration
modifiers
private "private"
type_identifier "OutputSettings"
variable_declarator
identifier "outputSettings"
= "="
object_creation_expression
new "new"
type_identifier "OutputSettings"
argument_list
( "("
) ")"
; ";"
block_comment "/**\n Create a new, empty Document.\n @param baseUri b"...
constructor_declaration (+32 nodes collapsed)
block_comment "/**\n Create a valid, empty shell of a document, suitable"...
method_declaration (+85 nodes collapsed)
block_comment "/**\n Accessor to the document's {@code head} element.\n "...
method_declaration (+25 nodes collapsed)
block_comment "/**\n Accessor to the document's {@code body} element.\n "...
method_declaration (+25 nodes collapsed)
block_comment "/**\n Get the string contents of the document's {@code ti"...
method_declaration (+58 nodes collapsed)
block_comment "/**\n Set the document's {@code title} element. Updates t"...
method_declaration (+96 nodes collapsed)
block_comment "/**\n Create a new Element, with this document's base uri"...
method_declaration (+39 nodes collapsed)
block_comment "/**\n Normalise the document. This happens after the pars"...
method_declaration
modifiers
public "public"
type_identifier "Document"
identifier "normalise"
formal_parameters
( "("
) ")"
block
{ "{"
local_variable_declaration
type_identifier "Element"
variable_declarator
identifier "htmlEl"
= "="
method_invocation
identifier "findFirstElementByTagName"
argument_list
( "("
string_literal
" "\""
string_fragment "html"
" "\""
, ","
this "this"
) ")"
; ";"
if_statement (+23 nodes collapsed)
if_statement (+26 nodes collapsed)
if_statement (+26 nodes collapsed)
line_comment "// pull text nodes out of root, html, and head els, and push"...
line_comment "// of. do in inverse order to maintain text order."
expression_statement
method_invocation
identifier "normaliseTextNodes"
argument_list
( "("
method_invocation
identifier "head"
argument_list
( "("
) ")"
) ")"
; ";"
expression_statement
method_invocation
identifier "normaliseTextNodes"
argument_list
( "("
identifier "htmlEl"
) ")"
; ";"
expression_statement
method_invocation
identifier "normaliseTextNodes"
argument_list
( "("
this "this"
) ")"
; ";"
expression_statement
method_invocation
identifier "normaliseStructure"
argument_list
( "("
string_literal
" "\""
string_fragment "head"
" "\""
, ","
identifier "htmlEl"
) ")"
; ";"
expression_statement
method_invocation
identifier "normaliseStructure"
argument_list
( "("
string_literal
" "\""
string_fragment "body"
" "\""
, ","
identifier "htmlEl"
) ")"
; ";"
return_statement
return "return"
this "this"
; ";"
} "}"
line_comment "// does not recurse."
method_declaration (+194 nodes collapsed)
line_comment "// merge multiple <head> or <body> contents into one, delete"...
method_declaration
modifiers
private "private"
void_type "void"
identifier "normaliseStructure"
formal_parameters
( "("
formal_parameter
type_identifier "String"
identifier "tag"
, ","
formal_parameter
type_identifier "Element"
identifier "htmlEl"
) ")"
block
{ "{"
local_variable_declaration
type_identifier "Elements"
variable_declarator
identifier "elements"
= "="
method_invocation
this "this"
. "."
identifier "getElementsByTag"
argument_list
( "("
identifier "tag"
) ")"
; ";"
local_variable_declaration
type_identifier "Element"
variable_declarator
identifier "master"
= "="
method_invocation
identifier "elements"
. "."
identifier "first"
argument_list
( "("
) ")"
; ";"
line_comment "// will always be available as created above if not existent"
if_statement
if "if"
parenthesized_expression
( "("
binary_expression
method_invocation
identifier "elements"
. "."
identifier "size"
argument_list
( "("
) ")"
> ">"
decimal_integer_literal "1"
) ")"
block
{ "{"
line_comment "// dupes, move contents to master"
local_variable_declaration
generic_type
type_identifier "List"
type_arguments
< "<"
type_identifier "Node"
> ">"
variable_declarator
identifier "toMove"
= "="
object_creation_expression
new "new"
generic_type
type_identifier "ArrayList"
type_arguments
< "<"
type_identifier "Node"
> ">"
argument_list
( "("
) ")"
; ";"
for_statement
for "for"
( "("
local_variable_declaration
integral_type
int "int"
variable_declarator
identifier "i"
= "="
decimal_integer_literal "1"
; ";"
binary_expression
identifier "i"
< "<"
method_invocation
identifier "elements"
. "."
identifier "size"
argument_list
( "("
) ")"
; ";"
update_expression
identifier "i"
++ "++"
) ")"
block
{ "{"
local_variable_declaration
type_identifier "Node"
variable_declarator
identifier "dupe"
= "="
method_invocation
identifier "elements"
. "."
identifier "get"
argument_list
( "("
identifier "i"
) ")"
; ";"
enhanced_for_statement
for "for"
( "("
type_identifier "Node"
identifier "node"
: ":"
field_access
identifier "dupe"
. "."
identifier "childNodes"
) ")"
expression_statement
method_invocation
identifier "toMove"
. "."
identifier "add"
argument_list
( "("
identifier "node"
) ")"
; ";"
expression_statement
method_invocation
identifier "dupe"
. "."
identifier "remove"
argument_list
( "("
) ")"
; ";"
} "}"
enhanced_for_statement
for "for"
( "("
type_identifier "Node"
identifier "dupe"
: ":"
identifier "toMove"
) ")"
expression_statement
method_invocation
identifier "master"
. "."
identifier "appendChild"
argument_list
( "("
identifier "dupe"
) ")"
; ";"
} "}"
line_comment "// ensure parented by <html>"
if_statement
if "if"
parenthesized_expression
( "("
unary_expression
! "!"
method_invocation
method_invocation
identifier "master"
. "."
identifier "parent"
argument_list
( "("
) ")"
. "."
identifier "equals"
argument_list
( "("
identifier "htmlEl"
) ")"
) ")"
block
{ "{"
expression_statement
method_invocation
identifier "htmlEl"
. "."
identifier "appendChild"
argument_list
( "("
identifier "master"
) ")"
; ";"
line_comment "// includes remove() "
} "}"
} "}"
line_comment "// fast method to get first by tag name, used for html, head"...
method_declaration (+94 nodes collapsed)
method_declaration (+25 nodes collapsed)
block_comment "/**\n Set the text of the {@code body} of this document. "...
method_declaration (+36 nodes collapsed)
method_declaration (+21 nodes collapsed)
block_comment "/**\n * A Document's output settings control the form of "...
class_declaration (+343 nodes collapsed)
block_comment "/**\n * Get the document's current output settings.\n "...
method_declaration
modifiers
public "public"
type_identifier "OutputSettings"
identifier "outputSettings"
formal_parameters
( "("
) ")"
block
{ "{"
return_statement
return "return"
identifier "outputSettings"
; ";"
} "}"
} "}"