You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2016/08/03 09:23:54 UTC

syncope git commit: Auto-Format menu item for HTMLEditor - This closes #31

Repository: syncope
Updated Branches:
  refs/heads/master 33fd24368 -> de3ab177f


Auto-Format menu item for HTMLEditor - This closes #31


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/de3ab177
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/de3ab177
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/de3ab177

Branch: refs/heads/master
Commit: de3ab177f9efe093f84447a42851b1e07a69dc40
Parents: 33fd243
Author: Tushar <tu...@gmail.com>
Authored: Thu Jul 28 15:40:50 2016 +0530
Committer: Francesco Chicchiricc� <il...@apache.org>
Committed: Wed Aug 3 11:24:45 2016 +0200

----------------------------------------------------------------------
 ide/eclipse/LICENSE                             |   5 +
 ide/eclipse/NOTICE                              |   5 +
 .../META-INF/MANIFEST.MF                        |   1 +
 .../build.properties                            |   3 +-
 .../plugin.xml                                  |   6 +-
 .../pom.xml                                     |   5 +
 .../ide/eclipse/plugin/editors/HTMLEditor.java  |  25 ++
 .../eclipse/plugin/editors/TemplateEditor.java  |  14 +-
 .../editors/htmlhelpers/AutoIndentAction.java   |  75 +++++
 .../htmlhelpers/HTMLAutoEditStrategy.java       | 301 +++++++++++++++++--
 .../htmlhelpers/HTMLCompletionProcessor.java    |  13 +-
 .../src/main/resources/HTMLEditor.properties    |  21 ++
 12 files changed, 439 insertions(+), 35 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/de3ab177/ide/eclipse/LICENSE
----------------------------------------------------------------------
diff --git a/ide/eclipse/LICENSE b/ide/eclipse/LICENSE
index 2219062..87a5b13 100644
--- a/ide/eclipse/LICENSE
+++ b/ide/eclipse/LICENSE
@@ -673,6 +673,11 @@ This is licensed under the MIT license:
 
 ==
 
+For Jsoup (https://jsoup.org/):
+This is licensed under the MIT license, see above.
+
+==
+
 For Web Services Description Language for Java (http://wsdl4j.sourceforge.net/):
 This is licensed under the CPL:
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/de3ab177/ide/eclipse/NOTICE
----------------------------------------------------------------------
diff --git a/ide/eclipse/NOTICE b/ide/eclipse/NOTICE
index f0545a2..2e18d85 100644
--- a/ide/eclipse/NOTICE
+++ b/ide/eclipse/NOTICE
@@ -79,3 +79,8 @@ All Rights Reserved
 This product includes software developed by the Eclipse SWT project.
 Copyright (c) 2016 The Eclipse Foundation.
 All Rights Reserved.
+
+==
+
+This product includes software developed by the Jsoup project.
+Copyright (c) 2009 - 2016 Jonathan Hedley (jonathan@hedley.net)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/de3ab177/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/META-INF/MANIFEST.MF b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/META-INF/MANIFEST.MF
index 8bce572..64d6159 100644
--- a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/META-INF/MANIFEST.MF
+++ b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/META-INF/MANIFEST.MF
@@ -45,4 +45,5 @@ Bundle-ClassPath: lib/asm.jar,
       lib/woodstox-core-asl.jar,
       lib/wsdl4j.jar,
       lib/xmlschema-core.jar,
+      lib/jsoup.jar,
       .

http://git-wip-us.apache.org/repos/asf/syncope/blob/de3ab177/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/build.properties
----------------------------------------------------------------------
diff --git a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/build.properties b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/build.properties
index 759669b..13ef6f0 100644
--- a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/build.properties
+++ b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/build.properties
@@ -54,4 +54,5 @@ bin.includes = plugin.xml,\
       lib/validation-api.jar,\
       lib/woodstox-core-asl.jar,\
       lib/wsdl4j.jar,\
-      lib/xmlschema-core.jar
+      lib/xmlschema-core.jar,\
+      lib/jsoup.jar

http://git-wip-us.apache.org/repos/asf/syncope/blob/de3ab177/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/plugin.xml
----------------------------------------------------------------------
diff --git a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/plugin.xml b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/plugin.xml
index 2737d91..cd0bcf1 100644
--- a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/plugin.xml
+++ b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/plugin.xml
@@ -58,6 +58,10 @@ under the License.
          icon="src/main/resources/icons/syncope.png"
          class="org.apache.syncope.ide.eclipse.plugin.editors.TemplateEditor"
       />
+    <editor id="org.apache.syncope.ide.eclipse.plugin.editors.HTMLEditor"
+         name="HTML Editor"
+         icon="src/main/resources/icons/syncope.png"
+         class="org.apache.syncope.ide.eclipse.plugin.editors.HTMLEditor"
+      />
    </extension>
-
 </plugin>

http://git-wip-us.apache.org/repos/asf/syncope/blob/de3ab177/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/pom.xml
----------------------------------------------------------------------
diff --git a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/pom.xml b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/pom.xml
index 4b67c79..732c242 100644
--- a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/pom.xml
+++ b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/pom.xml
@@ -40,6 +40,11 @@ under the License.
       <artifactId>syncope-client-lib</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.jsoup</groupId>
+      <artifactId>jsoup</artifactId>
+      <version>1.9.2</version>
+    </dependency>
   </dependencies>
   
   <properties>

http://git-wip-us.apache.org/repos/asf/syncope/blob/de3ab177/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/HTMLEditor.java
----------------------------------------------------------------------
diff --git a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/HTMLEditor.java b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/HTMLEditor.java
index 89f2a2e..95768cd 100644
--- a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/HTMLEditor.java
+++ b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/HTMLEditor.java
@@ -18,19 +18,44 @@
  */
 package org.apache.syncope.ide.eclipse.plugin.editors;
 
+import java.util.ResourceBundle;
+
+import org.apache.syncope.ide.eclipse.plugin.editors.htmlhelpers.AutoIndentAction;
 import org.apache.syncope.ide.eclipse.plugin.editors.htmlhelpers.HTMLFileDocumentProvider;
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuManager;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.editors.text.TextEditor;
+import org.eclipse.ui.texteditor.ITextEditorActionConstants;
+import org.eclipse.ui.texteditor.TextEditorAction;
 
 public class HTMLEditor extends TextEditor {
+    
+    private static final String RESOURCE_BUNDLE = "/src/main/resources/HTMLEditor";
+            
     public HTMLEditor() {
         super();
         setSourceViewerConfiguration(new HTMLSourceConfiguration());
     }
 
+    @Override
     protected final void doSetInput(final IEditorInput input) throws CoreException {
         setDocumentProvider(new HTMLFileDocumentProvider());
         super.doSetInput(input);
     }
+
+    @Override
+    protected void editorContextMenuAboutToShow(final IMenuManager menu) {
+        super.editorContextMenuAboutToShow(menu);
+        addAction(menu, ITextEditorActionConstants.GROUP_EDIT, "AutoIndent");
+    }
+
+    @Override
+    protected void createActions() {
+        super.createActions();
+        IAction a = (TextEditorAction) new AutoIndentAction(
+                ResourceBundle.getBundle(RESOURCE_BUNDLE), "AutoIndent", null);
+        setAction("AutoIndent", a);
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/de3ab177/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/TemplateEditor.java
----------------------------------------------------------------------
diff --git a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/TemplateEditor.java b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/TemplateEditor.java
index 7a1468f..5b0ba38 100644
--- a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/TemplateEditor.java
+++ b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/TemplateEditor.java
@@ -68,10 +68,7 @@ public class TemplateEditor extends MultiPageEditorPart implements IResourceChan
             setPageText(index, editor.getTitle());
         } catch (final PartInitException e) {
             ErrorDialog.openError(
-                getSite().getShell(),
-                ERROR_NESTED_EDITOR,
-                null,
-                e.getStatus());
+                getSite().getShell(), ERROR_NESTED_EDITOR, null, e.getStatus());
         }
     }
 
@@ -179,6 +176,15 @@ public class TemplateEditor extends MultiPageEditorPart implements IResourceChan
     protected void pageChange(final int newPageIndex) {
         super.pageChange(newPageIndex);
     }
+    
+    public ITextEditor getActiveHTMLEditor() {
+        final ITextEditor ite = (ITextEditor) getActiveEditor();
+        if (ite.getTitle().equals(SyncopeView.TEMPLATE_FORMAT_HTML)) {
+            return (ITextEditor) getActiveEditor();
+        } else {
+            return null;
+        }
+    }
 
     public void resourceChanged(final IResourceChangeEvent event) {
         if (event.getType() == IResourceChangeEvent.PRE_CLOSE) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/de3ab177/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/htmlhelpers/AutoIndentAction.java
----------------------------------------------------------------------
diff --git a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/htmlhelpers/AutoIndentAction.java b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/htmlhelpers/AutoIndentAction.java
new file mode 100644
index 0000000..b5e7d11
--- /dev/null
+++ b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/htmlhelpers/AutoIndentAction.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.ide.eclipse.plugin.editors.htmlhelpers;
+
+import java.util.ResourceBundle;
+
+import org.apache.syncope.ide.eclipse.plugin.editors.TemplateEditor;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.ui.texteditor.TextEditorAction;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+
+public class AutoIndentAction extends TextEditorAction {
+
+    public AutoIndentAction(final ResourceBundle bundle, final String prefix, final ITextEditor editor) {
+        super(bundle, prefix, editor);
+        update();
+    }
+
+    @Override
+    public void run() {
+        String content = getCurrentEditorContent();
+        content = formatContent(content);
+        ITextEditor ite = getHTMLEditor();
+        IDocument doc = ite.getDocumentProvider().getDocument(ite.getEditorInput());
+        doc.set(content);
+    }
+
+    private String formatContent(final String contentarg) {
+        String content =  contentarg;
+        Document htmlDoc = Jsoup.parse(content);
+        content = htmlDoc.html();
+        return content;
+    }
+
+    public String getCurrentEditorContent() {
+        ITextEditor ite = getHTMLEditor();
+        IDocument doc = ite.getDocumentProvider().getDocument(ite.getEditorInput());
+        return doc.get();
+    }
+
+    protected ITextEditor getHTMLEditor() {
+        final IEditorPart editor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
+                .getActiveEditor();
+        if (!(editor instanceof TemplateEditor)) {
+            return null;
+        }
+        TemplateEditor te = (TemplateEditor) editor;
+        return (ITextEditor) (te.getActiveHTMLEditor());
+    }
+
+    @Override
+    public void update() {
+        setEnabled(true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/de3ab177/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/htmlhelpers/HTMLAutoEditStrategy.java
----------------------------------------------------------------------
diff --git a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/htmlhelpers/HTMLAutoEditStrategy.java b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/htmlhelpers/HTMLAutoEditStrategy.java
index 3c7842b..8761e88 100644
--- a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/htmlhelpers/HTMLAutoEditStrategy.java
+++ b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/htmlhelpers/HTMLAutoEditStrategy.java
@@ -24,18 +24,13 @@ import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.DefaultIndentLineAutoEditStrategy;
 import org.eclipse.jface.text.DocumentCommand;
 import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.TextUtilities;
 
 public class HTMLAutoEditStrategy extends DefaultIndentLineAutoEditStrategy {
 
     private String charset = System.getProperty("file.encoding");
-    protected boolean enable;
 
     public HTMLAutoEditStrategy() {
-        this.enable = true;
-    }
-
-    public void setEnabled(final boolean enable) {
-        this.enable = enable;
     }
 
     public void setFile(final IFile file) {
@@ -47,31 +42,285 @@ public class HTMLAutoEditStrategy extends DefaultIndentLineAutoEditStrategy {
     }
 
     public void customizeDocumentCommand(final IDocument d, final DocumentCommand c) {
-        if (enable) {
-            try {
-                if ("-".equals(c.text) && c.offset >= 3 && d.get(c.offset - 3, 3).equals("<!-")) {
-                    c.text = "-  -->";
-                    c.shiftsCaret = false;
-                    c.caretOffset = c.offset + 2;
-                    c.doit = false;
-                    return;
+        try {
+            if ("-".equals(c.text) && c.offset >= 3 && d.get(c.offset - 3, 3).equals("<!-")) {
+                c.text = "-  -->";
+                c.shiftsCaret = false;
+                c.caretOffset = c.offset + 2;
+                c.doit = false;
+                return;
+            } else if ("[".equals(c.text) && c.offset >= 2 && d.get(c.offset - 2, 2).equals("<!")) {
+                c.text = "[CDATA[]]>";
+                c.shiftsCaret = false;
+                c.caretOffset = c.offset + 7;
+                c.doit = false;
+                return;
+            } else if ("l".equals(c.text) && c.offset >= 4 && d.get(c.offset - 4, 4).equals("<?xm")) {
+                c.text = "l version = \"1.0\" encoding = \"" + charset + "\"?>";
+                return;
+            } else if (c.length == 0 && c.text != null && endsWithDelimiter(d, c.text)) {
+                smartIndentAfterNewLine(d, c);
+            } else if ("<".equals(c.text)) { //$NON-NLS-1$
+                smartInsertAfterBracket(d, c);
+            }
+        } catch (final BadLocationException e) {
+            e.printStackTrace();
+        }
+        super.customizeDocumentCommand(d, c);
+    }
+
+
+    /**
+     * Returns whether or not the given text ends with one of the documents legal line delimiters.
+     *
+     * @param d the document
+     * @param txt the text
+     * @return <code>true</code> if <code>txt</code> ends with one of the document's line delimiters,
+     * <code>false</code> otherwise
+     */
+    private boolean endsWithDelimiter(final IDocument d, final String txt) {
+        String[] delimiters = d.getLegalLineDelimiters();
+        if (delimiters != null) {
+            return TextUtilities.endsWith(delimiters, txt) > -1;
+        }
+        return false;
+    }
+
+    /**
+     * Returns the line number of the next bracket after end.
+     *
+     * @param document - the document being parsed
+     * @param line - the line to start searching back from
+     * @param end - the end position to search back from
+     * @param closingBracketIncrease - the number of brackets to skip
+     * @return the line number of the next matching bracket after end
+     * @throws BadLocationException in case the line numbers are invalid in the document
+     */
+     protected int findMatchingOpenBracket(final IDocument document, final int linearg,
+         final int endarg, final int closingBracketIncrease) throws BadLocationException {
+
+         int line = linearg;
+         int end = endarg;
+        int start = document.getLineOffset(line);
+        int brackcount = getBracketCount(document, start, end, false) - closingBracketIncrease;
+
+        // sum up the brackets counts of each line (closing brackets count negative,
+        // opening positive) until we find a line the brings the count to zero
+        while (brackcount < 0) {
+            line--;
+            if (line < 0) {
+                return -1;
+            }
+            start = document.getLineOffset(line);
+            end = start + document.getLineLength(line) - 1;
+            brackcount += getBracketCount(document, start, end, false);
+        }
+        return line;
+    }
+
+    /**
+     * Returns the bracket value of a section of text. Closing brackets have a value of -1 and
+     * open brackets have a value of 1.
+     *
+     * @param document - the document being parsed
+     * @param start - the start position for the search
+     * @param end - the end position for the search
+     * @param ignoreCloseBrackets - whether or not to ignore closing brackets in the count
+     * @return the bracket value of a section of text
+     * @throws BadLocationException in case the positions are invalid in the document
+     */
+     private int getBracketCount(final IDocument document, final int start, final int end,
+         final boolean ignoreCloseBracketsarg) throws BadLocationException {
+
+         boolean ignoreCloseBrackets = ignoreCloseBracketsarg;
+        int begin = start;
+        int bracketcount = 0;
+        while (begin < end) {
+            char curr = document.getChar(begin);
+            begin++;
+            switch (curr) {
+                case '/' :
+                    if (begin < end) {
+                        char next = document.getChar(begin);
+                        if (next == '*') {
+                            // a comment starts, advance to the comment end
+                            begin = getCommentEnd(document, begin + 1, end);
+                        } else if (next == '/') {
+                            // '//'-comment: nothing to do anymore on this line
+                            begin = end;
+                        }
+                    }
+                    break;
+                case '*' :
+                    if (begin < end) {
+                        char next = document.getChar(begin);
+                        if (next == '/') {
+                            // we have been in a comment: forget what we read before
+                            bracketcount = 0;
+                            begin++;
+                        }
+                    }
+                    break;
+                case '>' :
+                    bracketcount++;
+                    ignoreCloseBrackets = false;
+                    break;
+                case '<' :
+                    if (!ignoreCloseBrackets) {
+                        bracketcount--;
+                    }
+                    break;
+                case '"' :
+                case '\'' :
+                    begin = getStringEnd(document, begin, end, curr);
+                    break;
+                default :
+                    }
+        }
+        return bracketcount;
+    }
+
+    /**
+     * Returns the end position of a comment starting at the given <code>position</code>.
+     *
+     * @param document - the document being parsed
+     * @param position - the start position for the search
+     * @param end - the end position for the search
+     * @return the end position of a comment starting at the given <code>position</code>
+     * @throws BadLocationException in case <code>position</code> and <code>end</code> are invalid in the document
+     */
+     private int getCommentEnd(final IDocument document, final int position, final int end)
+            throws BadLocationException {
+        int currentPosition = position;
+        while (currentPosition < end) {
+            char curr = document.getChar(currentPosition);
+            currentPosition++;
+            if (curr == '*') {
+                if (currentPosition < end && document.getChar(currentPosition) == '/') {
+                    return currentPosition + 1;
                 }
-                if ("[".equals(c.text) && c.offset >= 2 && d.get(c.offset - 2, 2).equals("<!")) {
-                    c.text = "[CDATA[]]>";
-                    c.shiftsCaret = false;
-                    c.caretOffset = c.offset + 7;
-                    c.doit = false;
-                    return;
+            }
+        }
+        return end;
+    }
+
+    /**
+     * Returns the content of the given line without the leading whitespace.
+     *
+     * @param document - the document being parsed
+     * @param line - the line being searched
+     * @return the content of the given line without the leading whitespace
+     * @throws BadLocationException in case <code>line</code> is invalid in the document
+     */
+     protected String getIndentOfLine(final IDocument document, final int line)
+            throws BadLocationException {
+        if (line > -1) {
+            int start = document.getLineOffset(line);
+            int end = start + document.getLineLength(line) - 1;
+            int whiteend = findEndOfWhiteSpace(document, start, end);
+            return document.get(start, whiteend - start);
+        }
+        return ""; //$NON-NLS-1$
+    }
+
+    /**
+     * Returns the position of the <code>character</code> in the <code>document</code> after <code>position</code>.
+     *
+     * @param document - the document being parsed
+     * @param position - the position to start searching from
+     * @param end - the end of the document
+     * @param character - the character you are trying to match
+     * @return the next location of <code>character</code>
+     * @throws BadLocationException in case <code>position</code> is invalid in the document
+     */
+     private int getStringEnd(final IDocument document, final int position, final int end,
+         final char character) throws BadLocationException {
+        int currentPosition = position;
+        while (currentPosition < end) {
+            char currentCharacter = document.getChar(currentPosition);
+            currentPosition++;
+            if (currentCharacter == '\\') {
+                // ignore escaped characters
+                currentPosition++;
+            } else if (currentCharacter == character) {
+                return currentPosition;
+            }
+        }
+        return end;
+    }
+
+    /**
+     * Set the indent of a new line based on the command provided in the supplied document.
+     * @param document - the document being parsed
+     * @param command - the command being performed
+     */
+     protected void smartIndentAfterNewLine(final IDocument document, final DocumentCommand command) {
+
+        int docLength = document.getLength();
+        if (command.offset == -1 || docLength == 0) {
+            return;
+        }
+
+        try {
+            int p = (command.offset == docLength ? command.offset - 1 : command.offset);
+            int line = document.getLineOfOffset(p);
+
+            StringBuilder buf = new StringBuilder(command.text);
+            if (command.offset < docLength && document.getChar(command.offset) == '<') {
+                int indLine = findMatchingOpenBracket(document, line, command.offset, 0);
+                if (indLine == -1) {
+                    indLine = line;
                 }
-                if ("l".equals(c.text) && c.offset >= 4 && d.get(c.offset - 4, 4).equals("<?xm")) {
-                    c.text = "l version = \"1.0\" encoding = \"" + charset + "\"?>";
-                    return;
+                buf.append(getIndentOfLine(document, indLine));
+            } else {
+                int start = document.getLineOffset(line);
+                int whiteend = findEndOfWhiteSpace(document, start, command.offset);
+                buf.append(document.get(start, whiteend - start));
+                if (getBracketCount(document, start, command.offset, true) > 0) {
+                    buf.append('\t');
                 }
-            } catch (final BadLocationException e) {
-                e.printStackTrace();
             }
+            command.text = buf.toString();
+
+        } catch (BadLocationException excp) {
+            System.out.println("AutoIndent.error.bad_location_1"); //$NON-NLS-1$
         }
-        super.customizeDocumentCommand(d, c);
     }
 
+    /**
+     * Set the indent of a bracket based on the command provided in the supplied document.
+     * @param document - the document being parsed
+     * @param command - the command being performed
+     */
+     protected void smartInsertAfterBracket(final IDocument document, final DocumentCommand command) {
+        if (command.offset == -1 || document.getLength() == 0) {
+            return;
+        }
+
+        try {
+            int p = (command.offset == document.getLength() ? command.offset - 1 : command.offset);
+            int line = document.getLineOfOffset(p);
+            int start = document.getLineOffset(line);
+            int whiteend = findEndOfWhiteSpace(document, start, command.offset);
+
+            // shift only when line does not contain any text up to the closing bracket
+            if (whiteend == command.offset) {
+                // evaluate the line with the opening bracket that matches out closing bracket
+                int indLine = findMatchingOpenBracket(document, line, command.offset, 1);
+                if (indLine != -1 && indLine != line) {
+                    // take the indent of the found line
+                    StringBuilder replaceText = new StringBuilder(getIndentOfLine(document, indLine));
+                    // add the rest of the current line including the just added close bracket
+                    replaceText.append(document.get(whiteend, command.offset - whiteend));
+                    replaceText.append(command.text);
+                    // modify document command
+                    command.length = command.offset - start;
+                    command.offset = start;
+                    command.text = replaceText.toString();
+                }
+            }
+        } catch (final BadLocationException excp) {
+            System.out.println("AutoIndent.error.bad_location_2"); //$NON-NLS-1$
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/de3ab177/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/htmlhelpers/HTMLCompletionProcessor.java
----------------------------------------------------------------------
diff --git a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/htmlhelpers/HTMLCompletionProcessor.java b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/htmlhelpers/HTMLCompletionProcessor.java
index 1eefd68..44d2efc 100644
--- a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/htmlhelpers/HTMLCompletionProcessor.java
+++ b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/java/org/apache/syncope/ide/eclipse/plugin/editors/htmlhelpers/HTMLCompletionProcessor.java
@@ -272,9 +272,16 @@ public class HTMLCompletionProcessor extends HTMLTemplateAssistProcessor {
                 if (word.equals("</")) {
                     length = 2;
                 }
-                list.add(new CompletionProposal(
-                        assistKeyword, documentOffset - length, length,
-                        assistKeyword.length()));
+                String contentBefore = viewer.getDocument().get().substring(0, documentOffset - length);
+                if (contentBefore.endsWith("\t")) {
+                    list.add(new CompletionProposal(
+                            assistKeyword, documentOffset - (length + 1), length + 1,
+                            assistKeyword.length()));
+                } else {
+                    list.add(new CompletionProposal(
+                            assistKeyword, documentOffset - length, length,
+                            assistKeyword.length()));
+                }
             }
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/de3ab177/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/resources/HTMLEditor.properties
----------------------------------------------------------------------
diff --git a/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/resources/HTMLEditor.properties b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/resources/HTMLEditor.properties
new file mode 100644
index 0000000..d73d046
--- /dev/null
+++ b/ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/src/main/resources/HTMLEditor.properties
@@ -0,0 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+AutoIndentlabel=Auto Indent
+AutoIndenttooltip=Auto Format HTML content
+AutoIndentdescription=Indentation and formatting of HTML content