Search code examples
emacsdot-emacs

Customize GNU/Emacs nxml-mode indentation


As some of you who use GNU/Emacs to develop for Android, you are surely aware that the latest Android Tools introduces a new xml formatter. I use the excellent nxml-mode to edit xml since… I edit xml files ;) and I'm pretty happy with it BUT… as I can customize the Nxml Attribute Indent variable, the documentation says:

Indentation for the attributes of an element relative to the start-tag. Hide   
This only applies when the first attribute of a tag starts a line.
In other cases, the first attribute on one line is indented the same
as the first attribute on the previous line.

What matters there is the fallback for which a standalone attribute is aligned on the first attribute when this one is on the same line that the element.

Is this possible to change that behavior, in order to obtain a Android Tools compatible indentation? I just found nothing in the documentation and googling failed…

Update:

The comment helps me to realize that I'm not clear. Thus, here is an example of what nxml-mode does by default:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="org.foo.bar"
          android:versionCode="1"
          android:versionName="1.0">

  <uses-sdk android:minSdkVersion="8" />
  <application
      android:label="@string/app_name"
      android:icon="@drawable/ic_launcher">

    <activity
        android:name="Foo"
        android:label="@string/foo" />

    <activity android:name="Bar"
              android:label="@string/bar" />

  </application>

</manifest>

What I would like to get:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.foo.bar"
    android:versionCode="1"
    android:versionName="1.0">

  <uses-sdk android:minSdkVersion="8" />
  <application
      android:label="@string/app_name"
      android:icon="@drawable/ic_launcher">

    <activity
        android:name="Foo"
        android:label="@string/foo" />

    <activity android:name="Bar"
        android:label="@string/bar" />

  </application>

</manifest>

First case (default nxml-mode indentation behavior):

  • the package attribute of the manifest element is aligned with the xmlns:android decl
  • the android:label attribute of the Bar activity element is aligned with the android:name element.

Second case (intended result):

  • the package attribute of the manifest element is aligned with the parent manifest element plus a configurable number of spaces
  • the android:label attribute of the Bar activity element is aligned with the parent element plus a configurable number of spaces

I have browsed the nxml-mode source code and the indentation behavior begins with nxml-indent-line but I failed to follow the many subcalls to see what defun should be customized… due to my lack of lisp knowledge.

You could see that the manifest second attribute is not aligned with the first

Cheers,

Renaud (hardly managing the massive headache to conform with the Android coding and formatting rules)


Solution

  • doesn't look like that behavior is easily modifiable, as it appears to be hard coded into the nxml-compute-indent-in-start-tag function. the relevant chunk of code appears to be this:

                  (let* ((att (car atts))
                         (start (xmltok-attribute-name-start att)))
                    (when (< start pos)
                      (goto-char start)
                      (setq off 0))))
    

    you could always copy that method into your own init file, comment those lines out, and load your function definition after nxml mode loads (which will override the original implementation).

    Note, you might also want to submit an enhancement request to the gnu emacs maintainers to make this behavior easily customizable in the future.