Package de.innovationgate.eclipse.editors.tml

Source Code of de.innovationgate.eclipse.editors.tml.TMLRegion

/*******************************************************************************
* Copyright (c) 2009, 2010 Innovation Gate GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Innovation Gate GmbH - initial API and implementation
******************************************************************************/
package de.innovationgate.eclipse.editors.tml;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.FindReplaceDocumentAdapter;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.contentassist.CompletionProposal;
import org.eclipse.jface.text.contentassist.ICompletionProposal;

import de.innovationgate.eclipse.editors.Plugin;
import de.innovationgate.eclipse.editors.config.TMLTag;
import de.innovationgate.eclipse.editors.config.TMLTagAttribute;
import de.innovationgate.eclipse.editors.config.TMLTagDefinitions;
import de.innovationgate.eclipse.editors.helpers.CompletionProposalComparator;
import de.innovationgate.eclipse.editors.helpers.ContextInformation;
import de.innovationgate.eclipse.editors.helpers.TMLReferenceLookup;
import de.innovationgate.eclipse.editors.tmlscript.parsing.TMLScriptRegion;
import de.innovationgate.eclipse.utils.wga.WGADesignStructureHelper;
import de.innovationgate.utils.WGUtils;
import de.innovationgate.wga.common.beans.csconfig.v1.Version;
import de.innovationgate.wga.model.VersionCompliance;
import de.innovationgate.wga.model.WGADesignConfigurationModel;

/**
* represent a tml start tag region
* and offers CompletionProposals
*
*
*/
public class TMLRegion {


  private static final String TML_REGION_PREFIX = "<tml:";
   
  private IRegion _documentRegion;
  private IDocument _document;
 
  private int _cursorAbsolute;
  private int _cursorRelative;
 
  private String _tagName;

  private Map<String, String> _attributes = new HashMap<String, String>();
 
  /**
   * contains attributes with no values (without trailing <code>=""</code>)
   * useful for tag validation
   */
  private Set<String> _valuelessAttributes = new HashSet<String>();

  private String _content = "";


  private TMLRegion(IRegion region, IDocument document, int cursorPositionInDocument) {
    _documentRegion = region;
    _document = document;
    _cursorAbsolute = cursorPositionInDocument;   
  }

  public static final TMLRegion parse(IRegion region, IDocument document, int cursorPositionInDocument) throws ParseException {
    TMLRegion tmlRegion = new TMLRegion(region, document, cursorPositionInDocument);
    tmlRegion.parse();
    return tmlRegion;
  }
 
  public static final TMLRegion parse(IRegion region, IDocument document) throws ParseException {
    return parse(region, document, region.getOffset());
  }
 
  private void parse() throws ParseException {
    try {     
      // extract region content
      try {
        _content = _document.get(_documentRegion.getOffset(), _documentRegion.getLength());
//        int cursorRelative = _cursorAbsolute - _region.getOffset();
//       
//        String beforeCursor = _content.substring(0, cursorRelative);
//        int beforeContentLength = beforeCursor.length();
//        beforeCursor = beforeCursor.replaceAll("\\n", "");
//        beforeCursor = beforeCursor.replaceAll("\\t", "");
//        // count whitespaces in prefix
//        int i = 0;
//        while (i < beforeCursor.length() && beforeCursor.charAt(i) == ' ') {
//          i++;
//        }           
//        int filteredCharsBeforeCursor = beforeContentLength - beforeCursor.length() + i;
       
        _content = _content.replaceAll("\\n", " ");
        _content = _content.replaceAll("\\t", " ");
        //_content = _content.trim();     
        _cursorRelative = _cursorAbsolute - _documentRegion.getOffset(); //- filteredCharsBeforeCursor;       
      } catch (BadLocationException e) {
        throw new ParseException("Unable to extract content of region.", _documentRegion.getOffset());
      }
     
      if (_content.startsWith("</tml:")) {
        // stop tag - parse tagname only
        _tagName = _content.substring(_content.indexOf("</tml:") + "</tml:".length(), _content.indexOf(">"));
        _tagName = _tagName.trim();
      } else if (_content.startsWith(TML_REGION_PREFIX)){
        // perform start tag parsing
       
       
        // parse tagname
        String tagContent = _content.substring(_content.indexOf(":") + 1);
        Set<String> tagNameStopWords = new HashSet<String>();
        tagNameStopWords.add(" ");
        tagNameStopWords.add("/>");
        tagNameStopWords.add(">");
        tagNameStopWords.add("\"");
        tagNameStopWords.add("<");
        //tagNameStopWords.add("\n");
        int tagnameEndPos = searchForward(tagNameStopWords, tagContent);
        if (tagnameEndPos == -1) {
          tagnameEndPos = _cursorRelative - TML_REGION_PREFIX.length();
        }
        _tagName = tagContent.substring(0, tagnameEndPos).trim();
       
        // parse attributes
        int attributesStart = TML_REGION_PREFIX.length() + _tagName.length();
        int attributesEnd = _content.length();
        if (_content.endsWith("/>")) {
          attributesEnd = attributesEnd - 2;
        } else if (_content.endsWith(">")) {
          attributesEnd = attributesEnd - 1;
        }
       
        String attributes = _content.substring(attributesStart, attributesEnd);
        attributes = attributes.replaceAll("\n", "");
        attributes = attributes.replaceAll("\r", "");
        if (attributes.contains("<tml:")) {
          // attribute section might contain <tml: start sequence if current tag partion is not closed yet and current tag is followed by another tml tag
          // remove this
          attributes = attributes.substring(0, attributes.indexOf("<tml:"));
        }
        attributes = attributes.trim();
        if (attributes.length() > 0) {
          attributes = WGUtils.strReplace(attributes, "\\\"", "$IG_APO$", true);
          attributes = WGUtils.strReplace(attributes, "\"\"", "\"$IG_EMPTY$\"", true);
          String[] attributeTokens = attributes.split("\"*\"");
          for (int i=0; i < attributeTokens.length; i += 2) {
            String key = attributeTokens[i];
            boolean valueless = false;
            if (!key.contains("=")) {
              valueless = true;
            }
            key = key.replaceAll("=", "");
            String value = null;
            if (key.contains(" ")) {           
              String[] keys = key.split(" ");
              key = keys[keys.length -1];         
              key = key.trim();
              // all other strings in key array are attributes without = and value - add to attribute list
              for (int j=0; j < keys.length - 1; j++) {
                String sValueless = keys[j].trim();
                if (sValueless.length() > 0) {               
                  _valuelessAttributes.add(sValueless.toLowerCase());
                }
              }
            }
            if ((i + 1) < attributeTokens.length) {
              value = attributeTokens[i + 1];
            }
            if (!valueless) {
              value = WGUtils.strReplace(value, "$IG_APO$", "\\\"", true);
              value = WGUtils.strReplace(value, "$IG_EMPTY$","", true);
              _attributes.put(key.toLowerCase(), value);
            } else {
              _valuelessAttributes.add(key.toLowerCase());
            }
          }
        }
      }
    } catch (ParseException e) {
      throw e;
    } catch (Exception e) {
      throw new ParseException("Unknown parsing error '" + e.getMessage() + "'", -1);
    }
  }
 
  public boolean hasAttribute(String name) {
    return _attributes.containsKey(name.toLowerCase());
  }
 
  public boolean hasAttribute(String name, String value) {
    if (isDynamicAttributeValue(name)) {
      return false;
    } else {
      String attValue = getAttributeValue(name);
      if (attValue != null) {
        return attValue.equals(value);
      }
    }
    return false;
  }
 
  public String getAttributeValue(String name) {
    return _attributes.get(name.toLowerCase());
  }
 
  public Set<String> getAttributeNames() {
    return _attributes.keySet();
  }
 
  private static int searchForward(Set<String> stopwords, String input) {
    int lowestIndex = Integer.MAX_VALUE;
    Iterator<String> stopIt = stopwords.iterator();
    while (stopIt.hasNext()) {
      String stopWord = stopIt.next();
      int stop = input.indexOf(stopWord);
      if (stop != -1) {
        if (stop < lowestIndex) {
          lowestIndex = stop;
        }
      } 
     
    }
    if (lowestIndex == Integer.MAX_VALUE) {
      return -1;
    } else {
      return lowestIndex;
    }
  }
 
  public ICompletionProposal[] createProposals(ITextViewer viewer, IFile activeFile) {
    List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();   
    if (isCursorInTagName()) {
      // create tag name proposals
      String alreadyTyped = getTagName();
      if (alreadyTyped != null) {
        if (!alreadyTyped.startsWith("[")) {
          Iterator<TMLTag> it = TMLTagDefinitions.getInstance(WGADesignStructureHelper.getWGAVersionCompliance(activeFile)).getTagsByPrefix(alreadyTyped).iterator();
          while (it.hasNext()) {
            TMLTag tag = it.next();
            proposals.addAll(createTagProposals(alreadyTyped, tag, _document, _cursorAbsolute,activeFile));
          }
        } else {
          Version wgaVersion = (Version) WGADesignConfigurationModel.VERSIONCOMPLIANCE_TO_WGA_VERSION.get(WGADesignStructureHelper.getWGAVersionCompliance(activeFile).getKey())
          if (wgaVersion.isAtLeast(4, 1)) {
            proposals.addAll(createIncludeModuleProposals(alreadyTyped, _document, _cursorAbsolute, activeFile));
          }
        }
      }     
    } else if (!isCursorInAttributeValue()) {
      // create attribute name proposals
      String search = _content.substring(0, _cursorRelative);
      int attributePrefixStartPos = searchBackwards(" ", search, "<");
      if (attributePrefixStartPos != -1) {
        attributePrefixStartPos += 1;
        String typed = search.substring(attributePrefixStartPos, _cursorRelative);
        TMLTag tag = TMLTagDefinitions.getInstance(WGADesignStructureHelper.getWGAVersionCompliance(activeFile)).getTagByName(getTagName());
        if (tag != null) {
          Iterator<TMLTagAttribute> it = tag.getAttributesByPrefix(typed).iterator();
          while (it.hasNext()) {
            TMLTagAttribute attrib = it.next();
            if (!_attributes.containsKey(attrib.getName()) && !attrib.isDeprecated()) {
              String attName  = attrib.getName();
              String display = attName;
              StringBuffer replacement = new StringBuffer();
              replacement.append(attName);
              replacement.append("=\"\"");
              int cursorPosAfterReplace = replacement.toString().length() - 1;
              ContextInformation contextInfo = Plugin.getDefault().getContextInformationProvider().getAttributeInformation(tag.getName(), attrib.getName(), activeFile);
              proposals.add(new TMLCompletionProposal(replacement.toString(), _cursorAbsolute - typed.length(), typed.length(), cursorPosAfterReplace, null, display, contextInfo));
            }
          }
        }
      }
    } else if (getAttributeNameOfValueCursorPosition() != null) {
      // create attribute value proposals
      String attribute = getAttributeNameOfValueCursorPosition();
      String search = _content.substring(0, _cursorRelative);
      int attributeValueStartPos = searchBackwards("\"", search, "=");
      String typed = "";
      if (attributeValueStartPos != -1) {
        typed = _content.substring(attributeValueStartPos + 1, _cursorRelative)
      } else {
        typed = "";
      }     
      TMLTag tag = TMLTagDefinitions.getInstance(WGADesignStructureHelper.getWGAVersionCompliance(activeFile)).getTagByName(getTagName());
      if (tag != null) {
          TMLTagAttribute tagAttribute = tag.getAttribute(attribute);
          if (tagAttribute != null) {
              if (tagAttribute.isTmlscriptExpression()) {
                  // perform tmlscript code completion
                  try {
                            IRegion region = getAttributeValueRegion(attribute);
                            TMLScriptRegion tmlScriptRegion = TMLScriptRegion.parse(region, _document, _cursorAbsolute, WGADesignStructureHelper.getWGAVersionCompliance(activeFile));
                            proposals.addAll(tmlScriptRegion.createProposals());
                        }
                        catch (BadLocationException e) {
                        }
              } else {
                  // lookup attribute values
                    Iterator<String> values = tag.getAttributeValuesByPrefix(attribute, typed, _document, this, viewer, activeFile).iterator();
                    while (values.hasNext()) {
                        String value = values.next();
                        String display = value;
                        StringBuffer replacement = new StringBuffer();
                        replacement.append(value);
                        int cursorPosAfterReplace = replacement.toString().length() + 1;
                        ContextInformation info = Plugin.getDefault().getContextInformationProvider().getAttributeInformation(tag.getName(), attribute, value,activeFile);
          proposals.add(new TMLCompletionProposal(replacement.toString(), _cursorAbsolute - typed.length(), typed.length(), cursorPosAfterReplace, null, display, info));
                    }                 
              }
          }         
      }
    }       
    try {
        if (!isCursorInAttributeValue()) {
            proposals.addAll(computeCloseTagProposals(_document, _cursorAbsolute));
        }
    } catch (BadLocationException e) {
    }
    Collections.sort(proposals, new CompletionProposalComparator());
    return proposals.toArray(new ICompletionProposal[0]);
  }

  private List<ICompletionProposal> createIncludeModuleProposals(String alreadyTyped, IDocument document, int cursorAbsolute, IFile activeFile) {
    List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
   
    Iterator<String> modules = TMLReferenceLookup.lookupValues(this, activeFile).iterator();
    while (modules.hasNext()) {
      String module = modules.next();
      if (module.startsWith(alreadyTyped.substring(1))) {
        String display = "<tml:[" + module +  "]>";

        StringBuffer replacement = new StringBuffer();
        replacement.append("[" + module + "]");
        int cursorPosAfterReplace = replacement.length();     
        replacement.append(">");
        proposals.add(new CompletionProposal(replacement.toString(), cursorAbsolute - alreadyTyped.length(), alreadyTyped.length(), cursorPosAfterReplace, null, display, null, null));
      }

    }       
    return proposals;
  }

  private List<ICompletionProposal> createTagProposals(String alreadyTyped, TMLTag tag, IDocument document, int documentOffset, IFile file) {
    List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
   
    if (tag != null && !tag.isDeprecated()) {
   
//        String tagDescription = null;
        ContextInformation info = Plugin.getDefault().getContextInformationProvider().getTagInformation(tag.getName(), file);
//        if (info != null) {
//          tagDescription = info.getInformation();
//        }
   
        //String display = "<tml:" + tagName + "/>";
           
        // generate attribute section
        StringBuffer attributeSection = new StringBuffer();
        int offsetFirstAttribute = generateAttributeSection(tag, attributeSection);
       
               
    //    if (tag.isBodyNeeded() || tag.isBodyRecommended()) {
    //      // create proposal with body
    //      String display = "<tml:" + tag.getName() + " " + attributeSection + "> ... </tml:" + tag.getName() + ">";
    //      StringBuffer replacement = new StringBuffer();
    //      replacement.append(tag.getName());
    //      if (tag.isAttributeNecessary()) {
    //        replacement.append(" ");
    //      }
    //      int cursorPosAfterReplace = replacement.length();
    //      if (offsetFirstAttribute != -1) {
    //        // append attribute section
    //        replacement.append(" ");
    //        replacement.append(attributeSection);
    //        cursorPosAfterReplace += offsetFirstAttribute + 1;
    //      }
    //      replacement.append(">");
    //      if (tag.isMultiLineBodyRecommended()) {
    //        replacement.append(computeIndent("\n\t", documentOffset, document));
    //      }
    //      if (offsetFirstAttribute == -1 && !tag.isAttributeNecessary()) {
    //        // no attributes - place cursor in body
    //        cursorPosAfterReplace = replacement.length();
    //      }
    //      if (tag.isMultiLineBodyRecommended()) {       
    //        replacement.append(computeIndent("\n", documentOffset, document));
    //      }
    //      replacement.append("</tml:" + tag.getName() + ">");
    //      proposals.add(new CompletionProposal(replacement.toString(), documentOffset - alreadyTyped.length(), alreadyTyped.length(), cursorPosAfterReplace, null, display, null, tagDescription)); 
    //    } else if (!tag.isBodyNeeded()) {
          String display = null;
          if (offsetFirstAttribute != -1) {
            display = "<tml:" + tag.getName() " " + attributeSection; // + ">";
          //} else if (tag.isAttributeNecessary()) {
            //display = "<tml:" + tag.getName() +  " >";       
          } else {
            display = "<tml:" + tag.getName(); // +  ">";
          }
          StringBuffer replacement = new StringBuffer();
          replacement.append(tag.getName());
          //if (tag.isAttributeNecessary()) {
          //  replacement.append(" ");
          //}
          int cursorPosAfterReplace = replacement.length();     
          if (offsetFirstAttribute != -1) {
            // append attribute section
            replacement.append(" ");
            replacement.append(attributeSection);
            cursorPosAfterReplace += offsetFirstAttribute + 1;
          }// else if (!tag.isAttributeNecessary()) {
            //cursorPosAfterReplace = replacement.length() + 1;
          //}
          //replacement.append(">");
          proposals.add(new TMLCompletionProposal(replacement.toString(), documentOffset - alreadyTyped.length(), alreadyTyped.length(), cursorPosAfterReplace, null, display, info));
    //    }       
    }
   
    return proposals;
  }

  /**
   * attribute section will be appended to the given stringbuffer
   * @param tag
   * @param section
   * @return offset of first attribute value in section or -1 if no attributes generated
   */
  private int generateAttributeSection(TMLTag tag, StringBuffer section) {
    Iterator<TMLTagAttribute> attribs = tag.getRequiredAttributes().iterator();
    boolean firstAttribute = true;
    int cursorPosFirstAttribute = -1;
    while (attribs.hasNext()) {
      TMLTagAttribute attribute = attribs.next();
      section.append(attribute.getName());
      section.append("=\"\"");
      if (firstAttribute) {
        firstAttribute = false;
        cursorPosFirstAttribute = section.toString().length() - 1;
      }
      if (attribs.hasNext()) {
        section.append(" ");
      }
    }
    return cursorPosFirstAttribute;
  }
 
  /**
   * checks if the cursor is on tagname
   * cursor behind "<tml:", and next char is an ' ', ', ", EOF or LineDelimiter
   * @return
   */
  public boolean isCursorInTagName() {
    List<String> lineDelimiters = Arrays.asList(_document.getLegalLineDelimiters());
    String search = _content.substring(0, _cursorRelative);     
    if (search.startsWith("<tml:") && search.indexOf(" ") == -1) {
      if (_cursorRelative < _content.length()) {
        char nextChar = _content.charAt(_cursorRelative);
        if (nextChar == ' ' || lineDelimiters.contains(Character.toString(nextChar)) || nextChar == '\'' || nextChar == '"' || nextChar == '<') {
          return true;
        } else {
          return false;
        }
      } else {
        return true;
      }
    }
    return false;
  }
 
  /**
   * checks if the cursor is in an attribute value
   * @return
   */
  public boolean isCursorInAttributeValue() {
    char[] search = _content.substring(0, _cursorRelative).toCharArray();
    // count unescaped '"'
    int count = 0;
    for (int i=search.length - 1; i >= 0; i--) {
      if (search[i] == '"') {
        if (i-1 >= 0) {
          if (search[i-1] != '\\') {
            count++;
          }
        } else {
          count++;
        }
      }
    }
    return (count%2 != 0);
  }
 
  /**
   * returns the attribute name if the cursor is in the attribute value section
   * null otherwise
   * @return
   */
  private String getAttributeNameOfValueCursorPosition() {       
    String contentBeforeCursor = _content.substring(0, _cursorRelative).trim();
    String contentBehindCursor = _content.substring(_cursorRelative).trim();
    if (contentBehindCursor.startsWith("\"")) {
      int attribEnd = searchBackwards("=\"", contentBeforeCursor, " ");
      if (attribEnd != -1) {
        String attribute = contentBeforeCursor.substring(0, attribEnd);
        int attribStart = attribute.lastIndexOf(" ");
        if (attribStart != -1) {
          attribute = attribute.substring(attribStart).trim();
          return attribute;
        }
      }
    }
    return null;
  }
 
 
  /**
   * returns the attribute name on which the cursor is placed
   * null if cursor is not in an attribute section
   * @return
   */
  public String getAttributeAtCursor() {
      int cursorPos = _cursorRelative;
    if (isCursorInAttributeValue()) {
      String search = _content.substring(0, cursorPos);
     
      for (int i = search.length() - 1; i > 0; i--) {
          char c = search.charAt(i);
          if (c == '"') {
              break;
          } else {
              cursorPos--;
          }
      }
      if (cursorPos > 1) {
          cursorPos = cursorPos-2;
      }
    }
    String contentBeforeCursor = _content.substring(0, cursorPos);
    String contentBehindCursor = _content.substring(cursorPos);
    int attributeStartPos = searchBackwards(" ", contentBeforeCursor, "<");
    if (attributeStartPos != -1) {
      attributeStartPos += 1;
      int attributeEndPos = searchForward("=", contentBehindCursor, ">");
      if (attributeEndPos != -1) {
        String name = contentBeforeCursor.substring(attributeStartPos);
        name += contentBehindCursor.substring(0, attributeEndPos);
        if (name.trim().equals("")) {
          return null;
        } else {
          return name;
        }
      }
    }
    return null;
  }
 
  private boolean isCursorBetween(String wordBefore, String wordBehind, String stopWordBefore, String stopWordBehind) {
    String contentBehindCursor = _content.substring(_cursorRelative);
    int posWordBehind = searchForward(wordBehind, contentBehindCursor, stopWordBehind);
   
    String contentBeforeCursor = _content.substring(0, _cursorRelative);
    int posWordBefore = searchBackwards(wordBefore, contentBeforeCursor, stopWordBefore);
   
    if (posWordBefore != -1 && posWordBehind != -1) {
      return true;
    } else {
      return false;
    }
  }
 
  private static int searchBackwards(String search, String input, String stopAt) {
    for (int i=input.length() - 1; i >= 0; i--) {
      if (input.startsWith(search, i)) {
        return i;
      } else {
        if (stopAt != null) {         
          if (input.startsWith(stopAt, i)) {
            return -1;
          }
        }
      }
    }
    return -1;
  }
 
  private static int searchForward(String search, String input, String stopAt) {
    int start = input.indexOf(search);
    if (start != -1 && stopAt != null) {
      int stop = input.indexOf(stopAt);
      if (stop != -1 && stop < start) {
        return -1;
      }
    }
    return start;
  }
 
 
  public String getTagName() {
    return _tagName;
  }
 
  public boolean isClosed() {
    return _content.trim().endsWith("/>");
  }
 
  public static List<ICompletionProposal> computeCloseTagProposals(IDocument document, int offset) throws BadLocationException {
    List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
   
    IRegion region = document.getPartition(offset);
    // fallback to current edit line if partition has length 0 - for e.g. end of document
    if (region.getLength() == 0) {         
      region = document.getLineInformationOfOffset(offset);
    }
    // search backwards for a tmltag with body which might need to be closed
    int pos = offset - 1;
    while (pos >= 0) {           
      ITypedRegion previousRegion = document.getPartition(pos);
      if (previousRegion.getType().equals(TMLPartitionScanner.TML_TAG_START) && !isTMLPartitionClosed(previousRegion, document)) {
          String alreadyTyped = document.get(region.getOffset(), offset-region.getOffset());       
          if (alreadyTyped.contains("\n")) {
            alreadyTyped = alreadyTyped.substring(alreadyTyped.lastIndexOf("\n"));
          }
          int posEnd = alreadyTyped.lastIndexOf(">");
          if (posEnd != -1) {
            alreadyTyped = alreadyTyped.substring(posEnd + 1);
          }
          posEnd = alreadyTyped.lastIndexOf("<");
          if (posEnd != -1) {
            alreadyTyped = alreadyTyped.substring(posEnd);
          } else {
            alreadyTyped = "";
          }
          String tagName = TMLPartitionScanner.determineTMLTagName(previousRegion, document);
          if (document.getLineOfOffset(offset) == document.getLineOfOffset(region.getOffset())) {
            // completion in same line
            int start = previousRegion.getOffset() + previousRegion.getLength();
            int end = offset;
            String typedBody = document.get(start, end - start);
            if (typedBody.trim().equals("")) {
              // create multi line completion - bc. empty tagbody makes no sense
              String display = "... </tml:" + tagName + ">";
              StringBuffer replacement = new StringBuffer("\n");
              replacement.append(computeIndent("\t", offset, document));
              int cursorPosAfterReplace = replacement.length();
              replacement.append(computeIndent("\n", offset, document));             
              replacement.append("</tml:" + tagName + ">");
              if (replacement.toString().startsWith(alreadyTyped.trim())) {
                int completionStartPos = alreadyTyped.lastIndexOf("<");
                if (completionStartPos == -1) {
                  completionStartPos = offset;
                } else {
                  completionStartPos = offset - (alreadyTyped.length() - completionStartPos);
                }               
                proposals.add(new CompletionProposal(replacement.toString(), completionStartPos, offset - completionStartPos, cursorPosAfterReplace, null, display, null, null));
              }
              // create close current tag completionv
              display = "/>";
              replacement = new StringBuffer("/>");
              cursorPosAfterReplace = replacement.length();             
              if (replacement.toString().startsWith(alreadyTyped.trim())) {
                int completionStartPos = previousRegion.getOffset() + previousRegion.getLength() + 1 - replacement.length();                         
                proposals.add(new CompletionProposal(replacement.toString(), completionStartPos, offset - completionStartPos, cursorPosAfterReplace, null, display, null, null));
              }
             
              break;
            } else {
              String replacement = "</tml:" + tagName + ">";
              if (replacement.startsWith(alreadyTyped.trim())) {
                int completionStartPos = alreadyTyped.lastIndexOf("<");
                if (completionStartPos == -1) {
                  completionStartPos = offset;
                } else {
                  completionStartPos = offset - (alreadyTyped.length() - completionStartPos);
                }
               
                proposals.add(new CompletionProposal(replacement, completionStartPos, offset - completionStartPos, replacement.length()));
                break;
              } else {
                break;
              }
            }
          } else {
            // completion in following line           
            String replacement = "</tml:" + tagName + ">";
            if (replacement.startsWith(alreadyTyped.trim())) {
              int completionStartPos = alreadyTyped.lastIndexOf("<");
              if (completionStartPos == -1) {
                completionStartPos = offset;
              } else {
                completionStartPos = offset - (alreadyTyped.length() - completionStartPos);
              }
             
              proposals.add(new CompletionProposal(replacement, completionStartPos, offset - completionStartPos, replacement.length()));
              break;
            } else {
              break;
            }
          }
         
                           
      }
      pos = previousRegion.getOffset() - 1;
    }
   
    return proposals;
    //return null;     
  }
 

  public static boolean isTMLPartitionClosed(ITypedRegion region, IDocument document) throws BadLocationException {
    if (region.getType().equals(TMLPartitionScanner.TML_TAG_START)) {
      String content = document.get(region.getOffset(), region.getLength());
      if (content.trim().endsWith("/>")) {
        return true;
      }
      String tagName = TMLPartitionScanner.determineTMLTagName(region, document);
      if (tagName != null) {     
        // retrieve document partitions from region offset to document end
        ITypedRegion[] partitions = document.computePartitioning(region.getOffset() + region.getLength(), document.getLength() - region.getOffset() - region.getLength());
        int openTags = 1;
        // search until end of doc or opentags == 0
        for (int i = 0; i < partitions.length; i++) {
          ITypedRegion partition = partitions[i];
          if (partition.getType().equals(TMLPartitionScanner.TML_TAG_START)) {
            content = document.get(partition.getOffset(), partition.getLength());
            if (!content.trim().endsWith("/>")) {
              String partitionTagName = TMLPartitionScanner.determineTMLTagName(partition, document);
              if (tagName.equals(partitionTagName)) {
                openTags++;
              }
            }
          } else if (partition.getType().equals(TMLPartitionScanner.TML_TAG_STOP)) {
            String partitionTagName = TMLPartitionScanner.determineTMLTagName(partition, document);
            if (tagName.equals(partitionTagName)) {
              openTags--;
            }
          }
          if (openTags == 0) {
            return true;
          }
        }     
        return openTags == 0;
      } else {
        return false;
      }
    } else if (region.getType().equals(TMLPartitionScanner.TML_TAG_STOP)) {
      String tagName = TMLPartitionScanner.determineTMLTagName(region, document);
      if (tagName != null) {     
        // retrieve document partitions from document beginn to region offset
        ITypedRegion[] partitions = document.computePartitioning(0, region.getOffset());
        int openTags = 1;
        // search backwards until opentags == 0 or document start has been reached
        for (int i = partitions.length - 1; i >= 0; i--) {
          ITypedRegion partition = partitions[i];
          if (partition.getType().equals(TMLPartitionScanner.TML_TAG_START)) {
            String content = document.get(partition.getOffset(), partition.getLength());
            if (!content.trim().endsWith("/>")) {
              String partitionTagName = TMLPartitionScanner.determineTMLTagName(partition, document);
              if (tagName.equals(partitionTagName)) {
                openTags--;
              }
            }
          } else if (partition.getType().equals(TMLPartitionScanner.TML_TAG_STOP)) {
            String partitionTagName = TMLPartitionScanner.determineTMLTagName(partition, document);
            if (tagName.equals(partitionTagName)) {
              openTags++;
            }
          }
          if (openTags == 0) {
            return true;
          }
        }     
        return openTags == 0;
      } else {
        return false;
      }
    } else {
      throw new IllegalArgumentException("Illegal partition type '" + region.getType() + "'.");
    }
  }
 
  private static int findEndOfWhiteSpace(IDocument document, int offset, int end) throws BadLocationException {
    while (offset < end) {
      char c= document.getChar(offset);
      if (c != ' ' && c != '\t') {
        return offset;
      }
      offset++;
    }
    return end;
  }
 
 
  public static String computeIndent(String text, int offset, IDocument document) {
      if (offset == -1 || document.getLength() == 0)
        return text;

      try {
        // find start of line
        int p= (offset == document.getLength() ? offset  - 1 : offset);
        IRegion info= document.getLineInformationOfOffset(p);
        int start= info.getOffset();

        // find white spaces
        int end= findEndOfWhiteSpace(document, start, offset);

        StringBuffer buf= new StringBuffer(text);
        if (end > start) {
          // append to input
          buf.append(document.get(start, end - start));
        }

        return buf.toString();
      } catch (BadLocationException excp) {
        // stop work
      }
     
      return text;
  }

  public IRegion getDocumentRegion() {
    return _documentRegion;
  }

  public void setDocumentRegion(IRegion documentRegion) {
    _documentRegion = documentRegion;
  }
 
  public boolean isTagKnown(VersionCompliance versionCompliance) {
    return TMLTagDefinitions.getInstance(versionCompliance).getTagByName(getTagName()) != null;
  }

  public Set<String> getValuelessAttributes() {
    return _valuelessAttributes;
  }

  public String getContent() {
    return _content;
  }

 
  public boolean isDynamicAttributeValue(String name) {
    String value = getAttributeValue(name);
    if (value == null) {
      return false;
    } else {
      return (value.trim().startsWith("{") && value.trim().endsWith("}")) || (value.trim().startsWith("[") && value.trim().endsWith("]"));
    }
  }
 
  public IRegion getAttributeValueRegion(String attributeName) throws BadLocationException {
    FindReplaceDocumentAdapter findReplaceAdapter = new FindReplaceDocumentAdapter(_document);
   
    IRegion region = findReplaceAdapter.find(_documentRegion.getOffset(), attributeName + "=\"" + getAttributeValue(attributeName) + "\"", true, true, false, false);
    if (region != null) {
      String tmp = attributeName + "=\"";
      return new Region(region.getOffset() + tmp.length(), region.getLength() - tmp.length() - 1);
    } else {
      return null;
    }
    /*
    IRegion end = findReplaceAdapter.find(start.getOffset() + start.getLength(), "\"", true, true, false, false);

    boolean startPosInPartition = start != null && start.getOffset() > _documentRegion.getOffset();
    boolean endPosInPartition = end != null && end.getOffset() < (_documentRegion.getOffset() + _documentRegion.getLength());
    if (startPosInPartition && endPosInPartition) {
      int startPos = start.getOffset() + attributeName.length() + "=\"".length();
      if (startPos < end.getOffset()) { 
        new Region(startPos, end.getOffset()-startPos);
      }
    }
    return null;*/
  }
TOP

Related Classes of de.innovationgate.eclipse.editors.tml.TMLRegion

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.