Format and Indent Toggle

Are you missing a feature? Request it's implementation here.
dnedrow
Posts: 60
Joined: Wed Jan 28, 2004 10:51 pm

Format and Indent Toggle

Post by dnedrow » Wed Dec 28, 2011 2:05 am

(Jump in if there's a feature in oxygen that I've missed which does what I'm asking below)

I tried the xml:space attribute declaration thinking I would be able to basically use it as a toggle for pretty print. Eg., for an ant build file,

Code: Select all

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE
project [
<!ATTLIST project xml:space (default|preserve) 'preserve'>
<!ATTLIST target xml:space (default|preserve) 'preserve'>
]>
<project name="OIM" default="startDomain" basedir=".">
<target name="preserveExistingFormatting">
<something/><something/>
</target>
<target name="reformat" xml:space="default">
<something/><something/>
</target>
</project>
Such that the result of a "Format and Indent" would be...

Code: Select all

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE
project [
<!ATTLIST project xml:space (default|preserve) 'preserve'>
<!ATTLIST target xml:space (default|preserve) 'preserve'>
]>
<project name="OIM" default="startDomain" basedir=".">
<target name="preserveExistingFormatting">
<something/><something/>
</target>
<target name="reformat" xml:space="default">
<something/>
<something/>
</target>
</project>
Note that the "preserveExistingFormatting" target has not been mucked with, but the "reformat" target has. But, when I actually run a Format and Indent using the xml:space attribute, everything is reflowed. Am I not understanding what function xml:space is supposed to provide within oXygen?

It's also awkward that it appears as though xml:space must be declared for each element. Is that correct?

I use a couple of code formatters and each has an inline marker that allows one to enable or disable the formatter throughout a document. For example, Jindent uses "//j+" and "//j-" to toggle reformatting. Eclipse uses "// @formatter:on" and "// @formatter:off".

If xml:space isn't meant to provide what I'm looking for, could I suggest an inline comment to toggle formatting?

Eg., something similar to...

Code: Select all


<!-- oXygenFormat=on -->
<!-- oXygenFormat=off -->
Justification:

I work on a lot of files that were originally written by others, and for whom any type of logical indenting was foreign.

I like my additions to be neat and tidy, but I can't touch the rest of the file as it is SCMd and the diff would freak people out. ;)

I know I can individually format elements, but I would like a much coarser control, as I may be adding dozens of complex elements.

It would be great if I could just insert <!-- oXygenFormat=off --> after the <?xml> declaration, turn it on for my block, and then back off for the rest of the file. This ensures that I don't accidentally format the entire thing without noticing. Can you tell I've caused a diff freak-out before? ;)

-David

ionela
Posts: 342
Joined: Mon Dec 05, 2011 6:08 pm

Re: Format and Indent Toggle

Post by ionela » Wed Dec 28, 2011 12:41 pm

Hi David,

For the example you gave us, if you are using xml:space attribute set to "default" then the element should be formated.
I have run this example in oXygen and the result is the one expected:

Code: Select all


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE
project [
<!ATTLIST project xml:space (default|preserve) 'preserve'>
<!ATTLIST target xml:space (default|preserve) 'preserve'>
]>
<project name="OIM" default="startDomain" basedir=".">
<target name="preserveExistingFormatting">
<something/><something/>
</target>
<target
name="reformat" xml:space="default">
<something/>
<something/>
</target>
</project>
Unfortunately, I haven't understood what do you mean by:
dnedrow wrote:But, when I actually run a Format and Indent using the xml:space attribute, everything is reflowed.
Have you set xml:space="default" to all elements and run Format and Indent?
Or have you set it only to "reformat" target element and everything is formatted?
If you are using this attribute on a parent element and its value is not overwritten into the child element(including the default attribute value), then the value is inherited.

Another way to preserve whitespace is to set in Option->Preferences->Editor / Format / XML -> Preserve space tab the elements or a XPath expression for the elements. More about this you can find in our user manual.

Or in you case, a better way is to insert into Preserve space tab * (that means all the elements from the document would have whitespace preserved) and set the attribute xml:space="default" only for the elements you add and you would like to Format and Indent.

Regards,
Ionela
Ionela Istodor
oXygen XML Editor and Author Support

dnedrow
Posts: 60
Joined: Wed Jan 28, 2004 10:51 pm

Re: Format and Indent Toggle

Post by dnedrow » Thu Dec 29, 2011 7:21 pm

The problem is that even when I have preserve set, portions of a "preserved" element are still modified by pretty print.

The original ...

Code: Select all


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE
project [
<!ATTLIST project xml:space (default|preserve) 'preserve'>
<!ATTLIST target xml:space (default|preserve) 'preserve'>
]>
<project name="OIM" default="startDomain" basedir=".">
<target name="preserveExistingFormatting">
<something /><something />

<however this="that"></however>
</target>
<target
name="reformat" xml:space="default">
<something /><something />

<however this="that"></however>
</target>
</project>
... turns into ...

Code: Select all


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE
project [
<!ATTLIST project xml:space (default|preserve) 'preserve'>
<!ATTLIST target xml:space (default|preserve) 'preserve'>
]>
<project name="OIM" default="startDomain" basedir=".">
<target name="preserveExistingFormatting">
<something/><something/>

<however this="that"/>
</target>
<target
name="reformat" xml:space="default">
<something/>
<something/>

<however this="that"/>
</target>
</project>
... rather than the following, which is what I would expect ...

Code: Select all


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE
project [
<!ATTLIST project xml:space (default|preserve) 'preserve'>
<!ATTLIST target xml:space (default|preserve) 'preserve'>
]>
<project name="OIM" default="startDomain" basedir=".">
<target name="preserveExistingFormatting">
<something /><something />

<however this="that"></however>
</target>
<target
name="reformat" xml:space="default">
<something/>
<something/>

<however this="that"/>
</target>
Note that in "what I would expect", nothing in the preserveExistingFormatting target has been touched.

The more I think about it, I'm not sure I'm clearly asking for what I would like to see in oXygen.

I would like some type of inline marker that enables/disables pretty print from that point on, outside of the context of attribute manipulation. Maybe this is beyond the capability of oXygen's formatting routines/external parsers.

I think it would make sense that it would be something embedded in a <!-- --> block, as then it is ignored by other tools. Perhaps when oXygen were to see <!-- O- -->, it would stop formatting, then re-enable formatting when it comes across <!-- O- -->.

I think this type of implementation would be best, as then I wouldn't have diddle with project/app prefs, which become global to the project/app.

Basically, here's what I am requesting ...

<!-- O- --> : Do not make any changes to text following this comment tag.

<!-- O+ --> : Apply configured formatting to text following this comment tag.

Keep in mind that I (and probably others) need this when working with source control systems, as any change to text (including space folding, etc.) will cause most SCM systems to flag those lines as changed, regardless of whether the functional integrity of the code/markup remains unchanged.

In the examples above, the initial pretty printed output changes <something /> to <something/>, which will be marked by the SCM as a change. Other developers must then examine their code to see if these changes should be merged into their working code. It creates a pretty big mess and a waste of time.

The stuff below is just a demo of how Jindent toggling works. Ignore it if you've already "got" what I'm asking for. ;)

-David

For example, here's a Jindent Java example...

Code: Select all


//J-
package net.gtheatre;

import java.util.ArrayList;

public class Minimal {

public static void main(String[] args) {

}

private void theirCode() {
if(stateCityMap.containsKey(state)){
ArrayList <String> cityList = (ArrayList <String>) stateCityMap.get(state);
if(!cityList.contains(city)){ cityList.add(city);
}
} else { ArrayList <String> cityList = new ArrayList <String>();
cityList.add(city);
stateCityMap.put(state, cityList);
}


}
//J+
private void myCode() {
if(cityMembersMap.containsKey(city)){
ArrayList <String> membersList = (ArrayList <String>) cityMembersMap.get(city);
if(!membersList.contains(member)){
membersList.add(member);
}
} else {
ArrayList <String> membersList = new ArrayList <String>();
membersList.add(member);
cityMembersMap.put(city, membersList);
}

}
//J-

// Why do we need all this white space?





private void moreOfTheirCode() {
if(true) { /* Blah, blah */ }



return;



}
}
When run through Jindent, this becomes ...

Code: Select all


//J-
package net.gtheatre;

import java.util.ArrayList;

public class Minimal {

public static void main(String[] args) {

}

private void theirCode() {
if(stateCityMap.containsKey(state)){
ArrayList <String> cityList = (ArrayList <String>) stateCityMap.get(state);
if(!cityList.contains(city)){ cityList.add(city);
}
} else { ArrayList <String> cityList = new ArrayList <String>();
cityList.add(city);
stateCityMap.put(state, cityList);
}


}
//J+

private void myCode() {
if (cityMembersMap.containsKey(city)) {
ArrayList<String> membersList = (ArrayList<String>) cityMembersMap.get(city);

if (!membersList.contains(member)) {
membersList.add(member);
}
} else {
ArrayList<String> membersList = new ArrayList<String>();

membersList.add(member);
cityMembersMap.put(city, membersList);
}
}
//J-

// Why do we need all this white space?





private void moreOfTheirCode() {
if(true) { /* Blah, blah */ }



return;



}
}

dnedrow
Posts: 60
Joined: Wed Jan 28, 2004 10:51 pm

Re: Format and Indent Toggle

Post by dnedrow » Thu Dec 29, 2011 7:24 pm

dnedrow wrote:Perhaps when oXygen were to see <!-- O- -->, it would stop formatting, then re-enable formatting when it comes across <!-- O- -->.
Oop, this should be ...
Perhaps when oXygen were to see <!-- O- -->, it would stop formatting, then re-enable formatting when it comes across <!-- O+ -->.

adrian
Posts: 2667
Joined: Tue May 17, 2005 4:01 pm

Re: Format and Indent Toggle

Post by adrian » Fri Dec 30, 2011 2:12 pm

Hi,

The simplest workaround:
If you only want to format parts of the document, move the caret on an element you want to format and use the action Format and Indent Element(Ctrl+Shift+I)(in the Source submenu from the popup menu, or the toolbar). This will only format that element and its children, instead of the entire document.

To clarify a few things:
1. Oxygen does not have support for completely turning off format and indent for parts of the document content. This is currently very difficult to implement since formatting builds an XML model of the entire document and writes it back in text form by using the specified formatting rules. It does not format the document line by line like some text editors do(e.g. Java).

For text(not for elements) this could be easily implemented but it's unnecessary because the xml:space="preserve" attribute does just that.
For elements this is very difficult to implement because the elements are only kept in the XML model by name and not the way they were represented in text mode(with spaces in tags, expanded/collapsed empty elements, etc).
There are some workarounds for this, like using the Author mode which only formats the region of the document where modifications have been made, but this is still at element level.

We will discuss this feature request internally, but I'm not sure if the architecture of the formatter can be changed.

2. The attribute xml:space = "preserve" refers to the whitespaces/formatting of the text from inside that element. This does not include the whitespaces in tags(e.g. <something />), or the preservation of expanded empty tags(<however this="that"></however>). This means elements still get formatted, just not their text.

3. In XML, an empty tag <something /> is equivalent with an expanded element <something></something>. The whitespace in the tag and the expansion of the empty tag have no significance for XML. Because of this, they are not preserved when formatted, but they are enforced one way or the other.

4. Oxygen's formatting can be configured to add that space in empty elements, or it can be configured to expand empty elements. But you can't have it both ways and you can't preserve their current form(in your example you have both an empty tag(something) and also an expanded empty element(however).
The options are in Options -> Preferences, Editor -> Format -> XML, Expand empty elements, Add slash in empty elements.

Regards,
Adrian
Adrian Buza
<oXygen/> XML Editor, Schema Editor and XSLT Editor/Debugger
http://www.oxygenxml.com

dnedrow
Posts: 60
Joined: Wed Jan 28, 2004 10:51 pm

Re: Format and Indent Toggle

Post by dnedrow » Tue Jan 03, 2012 7:20 pm

Thanks for the reply Adrian.

I was afraid that formatting was handled exactly the way you described, which would be the "correct" way. ;)

I can see where implementing what I would like would be problematic.

Just in case anyone is trying to accomplish the same thing, here's my plan...

I'll write a cvs wrapper that handles checking for reformatting. Basically, I'll just add <!-- f[ormat]<+|-> --> tags and have a script compare sections between <!-- f- --> and the next <!-- f+ --> tag, or EOF. If there are changes, the wrapper will prevent check-in and issue a warning that the file has had unintended changes made. In all other cases, e.g. text after an f+ until the next f- or EOF, the wrapper would allow those changes.

-David

Post Reply