Package com.johnlindquist.xml

Source Code of com.johnlindquist.xml.XmlElementSelectionNavigation

package com.johnlindquist.xml;

import com.intellij.codeInsight.completion.CodeCompletionHandlerBase;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.SelectionModel;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.source.xml.XmlAttributeImpl;
import com.intellij.psi.impl.source.xml.XmlTokenImpl;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.xml.XmlElementType;
import com.intellij.psi.xml.XmlTokenType;

/**
* User: John Lindquist
* Date: 7/22/11
* Time: 1:56 PM
*/
public class XmlElementSelectionNavigation{
    public static final String RIGHT = "right";
    public static final String LEFT = "left";
    private TextRange nextRange;

    public XmlElementSelectionNavigation(Editor editor, String direction){
        PsiElement element = PsiUtil.getElementAtCaret(editor);
        CaretModel caretModel = editor.getCaretModel();

        XmlTokenImpl token = (XmlTokenImpl) element;
        nextRange = getRangeFromToken(token, caretModel, direction);
        int startOffset = nextRange.getStartOffset();
        caretModel.moveToOffset(startOffset);
        SelectionModel selectionModel = editor.getSelectionModel();
        selectionModel.setSelection(startOffset, nextRange.getEndOffset());

        new CodeCompletionHandlerBase(CompletionType.BASIC).invokeCompletion(editor.getProject(), editor);
    }

    private TextRange getRangeFromToken(XmlTokenImpl token, CaretModel caretModel, String direction){
        XmlAttributeImpl attribute = getAttributeFromToken(token);

        if (RIGHT.equals(direction)){
            //account for namespace
            if (token.getTokenType() == XmlTokenType.XML_NAME){
                //special case for namespace
                if (attribute.isNamespaceDeclaration()){

                    String namespacePrefix = attribute.getNamespacePrefix();
                    String localName = attribute.getLocalName();
                    int textOffset = attribute.getFirstChild().getTextOffset();
                    int localNameOffset = textOffset + namespacePrefix.length() + 1;

                    //the caret is on the prefix, so go to the local name
                    if (caretModel.getOffset() < localNameOffset){
                        return new TextRange(localNameOffset, localNameOffset + localName.length());
                    }

                    PsiElement attributeValue = attribute.getLastChild().getChildren()[1];
                    return attributeValue.getTextRange();
                }
                //just a plain attribute (not a namespace)
                else{
                    //the caret is either on the namespace or it's not a namespace, so go to the value
                    PsiElement attributeValue = attribute.getLastChild();
                    PsiElement valueToken = attributeValue.getChildren()[1];
                    return valueToken.getTextRange();
                }
            }
            //the caret is on the attribute value
            else if (token.getTokenType() == XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN){
                //Don't forget the whitespace!
                PsiElement whiteSpace = attribute.getNextSibling();
                attribute = (XmlAttributeImpl) whiteSpace.getNextSibling();
                //you've moved to the attribute name of the next attribute
                if (attribute.isNamespaceDeclaration()){
                    String namespacePrefix = attribute.getNamespacePrefix();
                    int textOffset = attribute.getFirstChild().getTextOffset();
                    int localNameOffset = textOffset + namespacePrefix.length() + 1;

                    //time to select the prefix
                    if (caretModel.getOffset() < localNameOffset){
                        return new TextRange(textOffset, textOffset + namespacePrefix.length());
                    }
                }

                //just return the attribute name
                return attribute.getFirstChild().getTextRange();
            }

        }
        else if (LEFT.equals(direction)){
            //special case for namespace
            if (attribute.isNamespaceDeclaration()){
                String namespacePrefix = attribute.getNamespacePrefix();
                String localName = attribute.getLocalName();
                int textOffset = attribute.getFirstChild().getTextOffset();
                int localNameOffset = textOffset + namespacePrefix.length() + 1;

                //the caret is on the prefix, so go to the local name
                if (caretModel.getOffset() < localNameOffset){
                    return new TextRange(localNameOffset, localNameOffset + localName.length());
                }
            }
        }


        return token.getTextRange();
    }

    private XmlAttributeImpl getAttributeFromToken(XmlTokenImpl token){
        PsiElement context = token.getContext();
        IElementType contextElementType = context.getNode().getElementType();

        if (contextElementType == XmlElementType.XML_ATTRIBUTE_VALUE){
            context = context.getContext(); //move up from the value to the attribute
        }

        return (XmlAttributeImpl) context;
    }

    public TextRange getNextRange(){
        return nextRange;
    }

}
TOP

Related Classes of com.johnlindquist.xml.XmlElementSelectionNavigation

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.