public OffsetRange getReferenceSpan(Document doc, int lexOffset) {
    TokenHierarchy<Document> th = TokenHierarchy.get(doc);

    // BaseDocument doc = (BaseDocument)document;

    TokenSequence<? extends PythonTokenId> ts = PythonLexerUtils.getPythonSequence(th, lexOffset);

    if (ts == null) {
      return OffsetRange.NONE;
    }

    ts.move(lexOffset);

    if (!ts.moveNext() && !ts.movePrevious()) {
      return OffsetRange.NONE;
    }

    // Determine whether the caret position is right between two tokens
    boolean isBetween = (lexOffset == ts.offset());

    OffsetRange range = getReferenceSpan(ts, th, lexOffset);

    if ((range == OffsetRange.NONE) && isBetween) {
      // The caret is between two tokens, and the token on the right
      // wasn't linkable. Try on the left instead.
      if (ts.movePrevious()) {
        range = getReferenceSpan(ts, th, lexOffset);
      }
    }

    return range;
  }
  @SuppressWarnings("empty-statement")
  private DeclarationLocation findUrl(PythonParserResult info, Document doc, int lexOffset) {
    TokenSequence<?> ts = PythonLexerUtils.getPythonSequence((BaseDocument) doc, lexOffset);

    if (ts == null) {
      return DeclarationLocation.NONE;
    }

    ts.move(lexOffset);

    if (!ts.moveNext() && !ts.movePrevious()) {
      return DeclarationLocation.NONE;
    }

    Token<?> token = ts.token();

    TokenSequence<?> embedded = ts.embedded();

    if (embedded != null) {
      ts = embedded;

      embedded.move(lexOffset);

      if (!embedded.moveNext() && !embedded.movePrevious()) {
        return DeclarationLocation.NONE;
      }

      token = embedded.token();
    }

    // Is this a comment? If so, possibly do rdoc-method reference jump
    if ((token != null) && (token.id() == PythonStringTokenId.URL)) {
      // TODO - use findLinkedMethod
      String method = token.text().toString();
      if (method.startsWith("www.")) { // NOI18N
        method = "http://" + method; // NOI18N
      }

      // A URL such as http://netbeans.org - try to open it in a browser!
      try {
        URL url = new URL(method);

        return new DeclarationLocation(url);
      } catch (MalformedURLException mue) {
        // URL is from user source... don't complain with exception dialogs etc.
        ;
      }
    }

    return DeclarationLocation.NONE;
  }
  private DeclarationLocation findImport(PythonParserResult info, int lexOffset, BaseDocument doc) {
    TokenSequence<? extends PythonTokenId> ts =
        PythonLexerUtils.getPositionedSequence(doc, lexOffset);
    if (ts == null) {
      return DeclarationLocation.NONE;
    }
    if (ts.offset() == lexOffset) {
      // We're looking at the offset to the RIGHT of the caret
      // and here I care about what's on the left
      if (!ts.movePrevious()) {
        return DeclarationLocation.NONE;
      }
    }

    Token<? extends PythonTokenId> token = ts.token();
    if (token == null) {
      return DeclarationLocation.NONE;
    }

    TokenId id = token.id();

    String moduleName = null;
    while (true) {
      if (id == PythonTokenId.IDENTIFIER || id.primaryCategory().equals(PythonLexer.KEYWORD_CAT)) {
        // Possibly inside the import string
        String tokenText = token.text().toString();
        if (moduleName == null) {
          moduleName = tokenText;
        } else {
          moduleName = tokenText + "." + moduleName;
        }
      } else if (id != PythonTokenId.DOT) {
        break;
      }
      if (!ts.movePrevious()) {
        return DeclarationLocation.NONE;
      }
      token = ts.token();
      id = token.id();
    }

    if (id != PythonTokenId.ERROR
        && id != PythonTokenId.NEWLINE
        && id != PythonTokenId.WHITESPACE) {
      return DeclarationLocation.NONE;
    }

    if (!ts.movePrevious()) {
      return DeclarationLocation.NONE;
    }
    token = ts.token();
    id = token.id();
    if (id != PythonTokenId.IMPORT) {
      return DeclarationLocation.NONE;
    }
    if (moduleName == null) {
      return DeclarationLocation.NONE;
    }

    if (id == PythonTokenId.IMPORT || id == PythonTokenId.FROM) {
      if (id == PythonTokenId.IMPORT
          && ts.movePrevious()
          && ts.token().id() == PythonTokenId.WHITESPACE
          && ts.movePrevious()) {
        // See if this was "from foo import bar" such that we really should
        // be listing symbols inside the foo library
        token = ts.token();
        id = token.id();
        String library = null;
        while (true) {
          if (id == PythonTokenId.IDENTIFIER
              || id.primaryCategory().equals(PythonLexer.KEYWORD_CAT)) {
            // Possibly inside the import string
            String tokenText = token.text().toString();
            if (library == null) {
              library = tokenText;
            } else {
              library = tokenText + "." + library;
            }
          } else if (id != PythonTokenId.DOT) {
            break;
          }
          if (!ts.movePrevious()) {
            return DeclarationLocation.NONE;
          }
          token = ts.token();
          id = token.id();
        }
        if (library != null) {
          if (id == PythonTokenId.WHITESPACE
              && ts.movePrevious()
              && ts.token().id() == PythonTokenId.FROM) {
            return findImport(info, library, moduleName);
          }
        }
      }

      return findImport(info, moduleName, null);
    }

    return DeclarationLocation.NONE;
  }
예제 #4
0
  public void run(RubyRuleContext context, List<Hint> result) {
    Node node = context.node;
    ParserResult info = context.parserResult;

    IfNode ifNode = (IfNode) node;
    if (ifNode.getCondition() == null) {
      // Can happen for this code:
      //   if ()
      //   end
      // (typically while editing)
      return;
    }
    Node body = ifNode.getThenBody();
    Node elseNode = ifNode.getElseBody();

    if (body != null && elseNode != null) {
      // Can't convert if-then-else conditionals
      return;
    }

    if (body == null && elseNode == null) {
      // Can't convert empty conditions
      return;
    }

    // Can't convert if !x/elseif blocks
    if (ifNode.getElseBody() != null && ifNode.getElseBody().getNodeType() == NodeType.IFNODE) {
      return;
    }

    int start = ifNode.getPosition().getStartOffset();
    if (!RubyHints.isNullOrInvisible(body)
        && (
        // Can't convert blocks with multiple statements
        body.getNodeType() == NodeType.BLOCKNODE
            ||
            // Already a statement modifier?
            body.getPosition().getStartOffset() <= start)) {
      return;
    } else if (!RubyHints.isNullOrInvisible(elseNode)
        && (elseNode.getNodeType() == NodeType.BLOCKNODE
            || elseNode.getPosition().getStartOffset() <= start)) {
      return;
    }

    BaseDocument doc = context.doc;
    try {
      int keywordOffset = ConvertIfToUnless.findKeywordOffset(context, ifNode);
      if (keywordOffset == -1 || keywordOffset > doc.getLength() - 1) {
        return;
      }

      char k = doc.getText(keywordOffset, 1).charAt(0);
      if (!(k == 'i' || k == 'u')) {
        return; // Probably ternary operator, ?:
      }
    } catch (BadLocationException ble) {
      Exceptions.printStackTrace(ble);
    }

    // If statement that is not already a statement modifier
    OffsetRange range = AstUtilities.getRange(node);

    if (RubyUtils.isRhtmlDocument(doc) || RubyUtils.isYamlDocument(doc)) {
      // Make sure that we're in a single contiguous Ruby section; if not, this won't work
      range = LexUtilities.getLexerOffsets(info, range);
      if (range == OffsetRange.NONE) {
        return;
      }

      try {
        doc.readLock();
        TokenHierarchy th = TokenHierarchy.get(doc);
        TokenSequence ts = th.tokenSequence();
        ts.move(range.getStart());
        if (!ts.moveNext() && !ts.movePrevious()) {
          return;
        }

        if (ts.offset() + ts.token().length() < range.getEnd()) {
          return;
        }
      } finally {
        doc.readUnlock();
      }
    }

    ConvertToModifier fix = new ConvertToModifier(context, ifNode);

    if (fix.getEditList() == null) {
      return;
    }

    List<HintFix> fixes = Collections.<HintFix>singletonList(fix);

    String displayName = NbBundle.getMessage(ConvertConditionals.class, "ConvertConditionals");
    Hint desc = new Hint(this, displayName, RubyUtils.getFileObject(info), range, fixes, 500);
    result.add(desc);
  }