private void addFolds(
      BaseDocument doc,
      List<? extends ASTElement> elements,
      Map<String, List<OffsetRange>> folds,
      List<OffsetRange> codeblocks)
      throws BadLocationException {
    for (ASTElement element : elements) {
      ElementKind kind = element.getKind();
      switch (kind) {
        case FIELD:
        case METHOD:
        case CONSTRUCTOR:
        case CLASS:
        case MODULE:
          ASTNode node = element.getNode();
          OffsetRange range = ASTUtils.getRangeFull(node, doc);

          // beware of synthetic elements
          if ((kind == ElementKind.METHOD && !((MethodNode) node).isSynthetic())
              || (kind == ElementKind.CONSTRUCTOR && !((ConstructorNode) node).isSynthetic())
              || (kind == ElementKind.FIELD
                  && ((FieldNode) node).getInitialExpression() instanceof ClosureExpression)
              // Only make nested classes/modules foldable, similar to what the java editor is doing
              || (range.getStart() > Utilities.getRowStart(doc, range.getStart()))
                  && kind != ElementKind.FIELD) {

            int start = range.getStart();
            // Start the fold at the END of the line behind last non-whitespace, remove curly brace,
            // if any
            start = Utilities.getRowLastNonWhite(doc, start);
            if (start >= 0 && doc.getChars(start, 1)[0] != '{') {
              start++;
            }
            int end = range.getEnd();
            if (start != (-1) && end != (-1) && start < end && end <= doc.getLength()) {
              range = new OffsetRange(start, end);
              codeblocks.add(range);
            }
          }
          break;
      }

      List<? extends ASTElement> children = element.getChildren();

      if (children != null && children.size() > 0) {
        addFolds(doc, children, folds, codeblocks);
      }
    }
  }
Example #2
0
 @Override
 protected int getPreservedLineInitialIndentation(JoinedTokenSequence<JspTokenId> ts)
     throws BadLocationException {
   int[] index = ts.index();
   boolean found = false;
   do {
     if (ts.token().id() == JspTokenId.COMMENT) {
       String comment = ts.token().text().toString().trim();
       if (comment.startsWith("<%--")) {
         found = true;
         break;
       }
     } else {
       break;
     }
   } while (ts.movePrevious());
   int indent = 0;
   if (found) {
     int lineStart = Utilities.getRowStart(getDocument(), ts.offset());
     // TODO: can comment token start with spaces?? if yes then adjust
     // column to point to first non-whitespace
     int column = ts.offset();
     indent = column - lineStart;
   }
   ts.moveIndex(index);
   ts.moveNext();
   return indent;
 }
 /** Creates new instance initializing final fields. */
 public AnnotationBar(JTextComponent target) {
   this.textComponent = target;
   this.editorUI = Utilities.getEditorUI(target);
   this.foldHierarchy = FoldHierarchy.get(editorUI.getComponent());
   this.doc = editorUI.getDocument();
   this.caret = textComponent.getCaret();
   setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
   elementAnnotationsSubstitute = ""; // NOI18N
 }
  protected synchronized void disposeGotoDialog() {
    if (gotoDialog != null) {
      EditorState.put(BOUNDS_KEY, gotoDialog.getBounds());
      gotoDialog.dispose();
      Utilities.returnFocus();
    }

    gotoDialog = null;
  }
Example #5
0
 private synchronized Action getEditorAction() {
   if (editorAction == null) {
     BaseKit kit = Utilities.getKit(getComponent());
     if (kit != null) {
       editorAction = kit.getActionByName(editorActionName);
     }
   }
   return editorAction;
 }
  /**
   * Perform the goto operation.
   *
   * @return whether the dialog should be made invisible or not
   */
  protected boolean performGoto() {
    JTextComponent c = EditorRegistry.lastFocusedComponent();
    if (c != null) {
      try {
        int line = Integer.parseInt(getGotoValueText());

        // issue 188976
        if (line == 0) line = 1;
        // end of issue 188976

        BaseDocument doc = Utilities.getDocument(c);
        if (doc != null) {
          int rowCount = Utilities.getRowCount(doc);
          if (line > rowCount) line = rowCount;

          // Obtain the offset where to jump
          int pos = Utilities.getRowStartFromLineOffset(doc, line - 1);

          BaseKit kit = Utilities.getKit(c);
          if (kit != null) {
            Action a = kit.getActionByName(ExtKit.gotoAction);
            if (a instanceof ExtKit.GotoAction) {
              pos = ((ExtKit.GotoAction) a).getOffsetFromLine(doc, line - 1);
            }
          }

          if (pos != -1) {
            Caret caret = c.getCaret();
            caret.setDot(pos);
          } else {
            c.getToolkit().beep();
            return false;
          }
        }
      } catch (NumberFormatException e) {
        c.getToolkit().beep();
        return false;
      }
    }
    return true;
  }
  private void refreshToolbarButtons() {
    final JTextComponent c = getComponent();
    final boolean visible = isToolbarVisible();

    Runnable r =
        new Runnable() {
          public void run() {
            if (visible) {
              checkPresentersAdded();
              if (c != null) { // #62487
                installNoOpActionMappings();
                Map<String, MultiKeyBinding> keybsMap = getKeyBindingMap();

                Component comps[] = getComponents();
                for (int i = 0; i < comps.length; i++) {
                  Component comp = comps[i];
                  if (comp instanceof JButton) {
                    JButton button = (JButton) comp;
                    Action action = button.getAction();
                    if (action == null) {
                      continue;
                    }
                    String actionName = (String) action.getValue(Action.NAME);
                    if (actionName == null) {
                      continue;
                    }

                    String tooltipText = button.getToolTipText();
                    if (tooltipText != null) {
                      int index = tooltipText.indexOf("("); // NOI18N
                      if (index > 0) {
                        tooltipText = tooltipText.substring(0, index - 1);
                      }
                    }

                    MultiKeyBinding mkb = keybsMap.get(actionName);
                    if (mkb != null) {
                      button.setToolTipText(tooltipText + " (" + getMnemonic(mkb) + ")"); // NOI18N
                    } else {
                      button.setToolTipText(tooltipText);
                    }
                  }
                }
              }
            } else {
              checkPresentersRemoved();
            }
            setVisible(visible);
          }
        };

    Utilities.runInEventDispatchThread(r);
  }
 /** GlyphGutter copy pasted utility method. */
 private int getLineFromMouseEvent(MouseEvent e) {
   int line = -1;
   if (editorUI != null) {
     try {
       JTextComponent component = editorUI.getComponent();
       BaseTextUI textUI = (BaseTextUI) component.getUI();
       int clickOffset = textUI.viewToModel(component, new Point(0, e.getY()));
       line = Utilities.getLineOffset(doc, clickOffset);
     } catch (BadLocationException ble) {
     }
   }
   return line;
 }
 /** *** Annotation Stuff ******* */
 static void processAnnotations(
     NbEditorDocument doc,
     List<PPLine> lineList) { // XXX needs to be split for errors and warnings
   final ArrayList<ErrorDescription> errs = new ArrayList();
   DataObject dob = NbEditorUtilities.getDataObject(doc);
   FileObject fo = dob == null ? null : dob.getPrimaryFile();
   for (PPLine line : lineList) {
     for (PPLine.Error err : line.getErrors()) {
       PPToken tok = err.token;
       int shift =
           (tok.getType() == LineParserTokens.END_OF_FILE
                   || tok.getType() == LineParserTokens.END_OF_LINE
                   || tok.getType() == LineParserTokens.OTHER_TEXT)
               ? Math.max(1, tok.getPadding().length())
               : 0;
       int loff = NbDocument.findLineOffset(doc, line.getLineNumber() - 1);
       errs.add(
           ErrorDescriptionFactory.createErrorDescription(
               err.warning ? Severity.WARNING : Severity.ERROR,
               err.message,
               fo,
               loff + tok.getColumn() - shift,
               loff + tok.getColumn() + tok.getText().length()));
     }
     ArrayList<Fix> fixes = new ArrayList();
     int start = Utilities.getRowStartFromLineOffset(doc, line.getLineNumber() - 1);
     if (line.getTokens().size() > 1
         && "//#include".equals(line.getTokens().get(0).getText())) { // NOI18N
       fixes.add(
           new InlineIncludeHint(
               (NbEditorDocument) doc, start, line.getTokens().get(1).getText()));
     } else if (line.getType() == PPLine.OLDIF || line.getType() == PPLine.OLDENDIF) {
       PPBlockInfo b = line.getBlock();
       while (b != null && b.getType() != PPLine.OLDIF) {
         b = b.getParent();
       }
       if (b != null) fixes.add(new ReplaceOldSyntaxHint(doc, lineList, b));
     }
     if (line.getType() == PPLine.UNKNOWN)
       fixes.add(new DisableHint((NbEditorDocument) doc, start));
     if (fixes.size() > 0)
       errs.add(
           ErrorDescriptionFactory.createErrorDescription(
               Severity.HINT,
               NbBundle.getMessage(DocumentPreprocessor.class, "LBL_PreprocessorHint"),
               fixes,
               doc,
               line.getLineNumber())); // NOI18N
   }
   HintsController.setErrors(doc, "preprocessor-errors", errs); // NOI18N
 }
Example #10
0
  /**
   * GlyphGutter copy pasted bolerplate method. It invokes {@link #paintView} that contains actual
   * business logic.
   */
  @Override
  public void paintComponent(Graphics g) {
    super.paintComponent(g);

    Rectangle clip = g.getClipBounds();

    JTextComponent component = editorUI.getComponent();
    if (component == null) return;

    BaseTextUI textUI = (BaseTextUI) component.getUI();
    View rootView = Utilities.getDocumentView(component);
    if (rootView == null) return;

    g.setColor(backgroundColor());
    g.fillRect(clip.x, clip.y, clip.width, clip.height);

    AbstractDocument doc = (AbstractDocument) component.getDocument();
    doc.readLock();
    try {
      foldHierarchy.lock();
      try {
        int startPos = textUI.getPosFromY(clip.y);
        int startViewIndex = rootView.getViewIndex(startPos, Position.Bias.Forward);
        int rootViewCount = rootView.getViewCount();

        if (startViewIndex >= 0 && startViewIndex < rootViewCount) {
          int clipEndY = clip.y + clip.height;
          for (int i = startViewIndex; i < rootViewCount; i++) {
            View view = rootView.getView(i);
            Rectangle rec = component.modelToView(view.getStartOffset());
            if (rec == null) {
              break;
            }
            int y = rec.y;
            paintView(view, g, y);
            if (y >= clipEndY) {
              break;
            }
          }
        }

      } finally {
        foldHierarchy.unlock();
      }
    } catch (BadLocationException ble) {
      Mercurial.LOG.log(Level.WARNING, null, ble);
    } finally {
      doc.readUnlock();
    }
  }
  @Override
  public DeclarationLocation findDeclaration(ParserResult info, int lexOffset) {

    final Document document = info.getSnapshot().getSource().getDocument(false);
    if (document == null) {
      return DeclarationLocation.NONE;
    }

    final BaseDocument doc = (BaseDocument) document;

    PythonParserResult parseResult = PythonAstUtils.getParseResult(info);
    doc.readLock(); // Read-lock due to Token hierarchy use
    try {
      PythonTree root = PythonAstUtils.getRoot(parseResult);
      final int astOffset = PythonAstUtils.getAstOffset(info, lexOffset);
      if (astOffset == -1) {
        return DeclarationLocation.NONE;
      }

      AstPath path = null;
      PythonTree node = null;
      if (root != null) {
        path = AstPath.get(root, astOffset);
        node = path.leaf();
      }

      // See if it's an import
      DeclarationLocation imp = findImport(parseResult, lexOffset, doc);
      if (imp != DeclarationLocation.NONE) {
        return imp;
      }

      DeclarationLocation url = findUrl(parseResult, doc, lexOffset);
      if (url != DeclarationLocation.NONE) {
        return url;
      }

      final TokenHierarchy<Document> th = TokenHierarchy.get(document);
      org.netbeans.modules.python.editor.lexer.Call call =
          org.netbeans.modules.python.editor.lexer.Call.getCallType(doc, th, lexOffset);

      FileObject fileObject = info.getSnapshot().getSource().getFileObject();

      // Search for local variables
      if (root != null && call.getLhs() == null) {
        if ((path.leaf() instanceof Name)) {
          PythonTree scope = PythonAstUtils.getLocalScope(path);
          SymbolTable symbolTable = parseResult.getSymbolTable();

          String name = ((Name) path.leaf()).getInternalId();

          SymInfo sym = symbolTable.findDeclaration(scope, name, true);
          if (sym != null) {
            if (sym.isFree()) {
              PythonIndex index = PythonIndex.get(fileObject);

              List<Import> imports = symbolTable.getImports();
              List<ImportFrom> importsFrom = symbolTable.getImportsFrom();
              Set<IndexedElement> elements =
                  index.getImportedElements(
                      name, QuerySupport.Kind.EXACT, parseResult, imports, importsFrom);
              if (elements != null && elements.size() > 0) {
                return getDeclaration(
                    parseResult, null /*name*/, elements, path, node, index, astOffset, lexOffset);
              }
              // Must be defined by one of the imported symbols
            }
            if (sym.node != null) {
              PythonTree declNode = sym.node;
              if (sym
                  .isImported()) { // Rather than showing the import symbol go to the definition in
                                   // the library!
                // Determine if it's an "as" name (import foo as bar) and if so just show the "as",
                // if not,
                // follow through to the library
                if (declNode instanceof Import) {
                  Import impNode = (Import) declNode;
                  List<alias> names = impNode.getInternalNames();
                  if (names != null) {
                    for (alias at : names) {
                      if (at.getInternalAsname() != null && name.equals(at.getInternalAsname())) {
                        break;
                      } else if (at.getInternalName().equals(name)) {
                        // We found our library - just show it
                        return findImport(parseResult, name, null);
                      }
                    }
                  }
                } else {
                  assert declNode instanceof ImportFrom : declNode;
                  ImportFrom impNode = (ImportFrom) declNode;
                  List<alias> names = impNode.getInternalNames();
                  if (names != null) {
                    for (alias at : names) {
                      if (at.getInternalAsname() != null && name.equals(at.getInternalAsname())) {
                        break;
                      } else if (at.getInternalName().equals(name)) {
                        // We found our library - just show it
                        return findImport(parseResult, impNode.getInternalModule(), name);
                      }
                    }
                  }
                }
              }

              if (sym.isUnresolved()) {
                PythonIndex index = PythonIndex.get(fileObject);

                List<Import> imports = symbolTable.getImports();
                List<ImportFrom> importsFrom = symbolTable.getImportsFrom();
                Set<IndexedElement> elements =
                    index.getImportedElements(
                        name, QuerySupport.Kind.EXACT, parseResult, imports, importsFrom);
                if (elements != null && elements.size() > 0) {
                  return getDeclaration(
                      parseResult,
                      null /*name*/,
                      elements,
                      path,
                      node,
                      index,
                      astOffset,
                      lexOffset);
                }
              } else {
                OffsetRange astRange = PythonAstUtils.getNameRange(null, declNode);
                int lexerOffset = PythonLexerUtils.getLexerOffset(parseResult, astRange.getStart());
                if (lexerOffset == -1) {
                  lexerOffset = 0;
                }
                return new DeclarationLocation(fileObject, lexerOffset);
              }
            }
          }
          //
          //                    List<Name> localVars = PythonAstUtils.getLocalVarNodes(info, scope,
          // name);
          //                    if (localVars.size() > 0) {
          //                        return new DeclarationLocation(info.getFileObject(),
          // PythonAstUtils.getRange(localVars.get(0)).getStart());
          //                    }
        }
      }

      // I'm not doing any data flow analysis at this point, so
      // I can't do anything with a LHS like "foo.". Only actual types.
      String type = call.getType();
      if (type != null && "self".equals(type)) { // NOI18N
        type = PythonAstUtils.getFqnName(path);
      }
      if (type != null && type.length() > 0) {
        String name = null;
        PythonTree leaf = path.leaf();
        if (leaf instanceof Name) {
          name = ((Name) path.leaf()).getInternalId();
        } else if (leaf instanceof Attribute) {
          name = ((Attribute) leaf).getInternalAttr();
        }

        if (name != null) {
          PythonIndex index = PythonIndex.get(fileObject);
          // Add methods in the class (without an FQN)
          Set<IndexedElement> elements =
              index.getInheritedElements(type, name, QuerySupport.Kind.EXACT);
          if (elements != null && elements.size() > 0) {
            return getDeclaration(
                parseResult, null /*name*/, elements, path, node, index, astOffset, lexOffset);
          }
        }
      }

      // Fallback: Index search on all names
      String prefix = new PythonCodeCompleter().getPrefix(info, lexOffset, false);
      if (prefix == null) {
        try {
          prefix = Utilities.getIdentifier(doc, lexOffset);
        } catch (BadLocationException ex) {
          Exceptions.printStackTrace(ex);
        }
      }
      if (prefix != null) {
        PythonIndex index = PythonIndex.get(fileObject);

        Set<? extends IndexedElement> elements = null;
        if (prefix.length() > 0 && Character.isUpperCase(prefix.charAt(0))) {
          elements = index.getClasses(prefix, QuerySupport.Kind.EXACT, parseResult, true);
        }

        if (elements == null || elements.size() == 0) {
          elements = index.getAllElements(prefix, QuerySupport.Kind.EXACT, parseResult, true);
        }

        if (elements == null || elements.size() == 0) {
          elements = index.getAllMembers(prefix, QuerySupport.Kind.EXACT, parseResult, true);
        }

        if (elements != null && elements.size() > 0) {
          return getDeclaration(
              parseResult, null /*name*/, elements, path, node, index, astOffset, lexOffset);
        }

        // TODO - classes
        // WORKING HERE
        //                if (elements == null || elements.size() == 0) {
        //                    elements = index.getClasses(prefix, QuerySupport.Kind.EXACT,
        // PythonIndex.ALL_SCOPE, parseResult, true);
        //                }
        //                if (elements != null && elements.size() > 0) {
        //                    String name = null; // unused!
        //
        //                    return getMethodDeclaration(info, name, elements,
        //                         path, null, index, astOffset, lexOffset);
        //                }
      }
    } finally {
      doc.readUnlock();
    }
    return DeclarationLocation.NONE;
  }
Example #12
0
  // latestAnnotationTask business logic
  @Override
  public void run() {
    // get resource bundle
    ResourceBundle loc = NbBundle.getBundle(AnnotationBar.class);
    // give status bar "wait" indication // NOI18N
    StatusBar statusBar = editorUI.getStatusBar();
    recentStatusMessage = loc.getString("CTL_StatusBar_WaitFetchAnnotation"); // NOI18N
    statusBar.setText(StatusBar.CELL_MAIN, recentStatusMessage);

    // determine current line
    int line = -1;
    int offset = caret.getDot();
    try {
      line = Utilities.getLineOffset(doc, offset);
    } catch (BadLocationException ex) {
      Mercurial.LOG.log(Level.SEVERE, "Can not get line for caret at offset ", offset); // NOI18N
      clearRecentFeedback();
      return;
    }

    // handle locally modified lines
    AnnotateLine al = getAnnotateLine(line);
    if (al == null) {
      AnnotationMarkProvider amp = AnnotationMarkInstaller.getMarkProvider(textComponent);
      if (amp != null) {
        amp.setMarks(Collections.<AnnotationMark>emptyList());
      }
      clearRecentFeedback();
      if (recentRevision != null) {
        recentRevision = null;
        repaint();
      }
      return;
    }

    // handle unchanged lines
    String revision = al.getRevision();
    if (revision.equals(recentRevision) == false) {
      recentRevision = revision;
      repositoryRoot = Mercurial.getInstance().getRepositoryRoot(getCurrentFile());
      repaint();

      AnnotationMarkProvider amp = AnnotationMarkInstaller.getMarkProvider(textComponent);
      if (amp != null) {

        List<AnnotationMark> marks = new ArrayList<AnnotationMark>(elementAnnotations.size());
        // I cannot affort to lock elementAnnotations for long time
        // it's accessed from editor thread too
        Iterator<Map.Entry<Element, AnnotateLine>> it2;
        synchronized (elementAnnotations) {
          it2 =
              new HashSet<Map.Entry<Element, AnnotateLine>>(elementAnnotations.entrySet())
                  .iterator();
        }
        while (it2.hasNext()) {
          Map.Entry<Element, AnnotateLine> next = it2.next();
          AnnotateLine annotateLine = next.getValue();
          if (revision.equals(annotateLine.getRevision())) {
            Element element = next.getKey();
            if (elementAnnotations.containsKey(element) == false) {
              continue;
            }
            int elementOffset = element.getStartOffset();
            int lineNumber = NbDocument.findLineNumber((StyledDocument) doc, elementOffset);
            AnnotationMark mark = new AnnotationMark(lineNumber, revision);
            marks.add(mark);
          }

          if (Thread.interrupted()) {
            clearRecentFeedback();
            return;
          }
        }
        amp.setMarks(marks);
      }
    }

    if (al.getCommitMessage() != null) {
      recentStatusMessage = al.getCommitMessage();
      statusBar.setText(
          StatusBar.CELL_MAIN,
          al.getRevision()
              + ":"
              + al.getId()
              + " - "
              + al.getAuthor()
              + ": "
              + recentStatusMessage); // NOI18N
    } else {
      clearRecentFeedback();
    }
  }
Example #13
0
  @Override
  protected List<IndentCommand> getLineIndent(
      IndenterContextData<TplTopTokenId> context, List<IndentCommand> preliminaryNextLineIndent)
      throws BadLocationException {
    Stack<TplStackItem> blockStack = getStack();
    List<IndentCommand> iis = new ArrayList<IndentCommand>();
    getIndentFromState(iis, true, context.getLineStartOffset());

    JoinedTokenSequence<TplTopTokenId> ts = context.getJoinedTokenSequences();
    ts.move(context.getLineStartOffset());

    boolean isSmartyBodyCommand = false;
    boolean isSmartyElseCommand = false;
    boolean afterDelimiter = false;
    int embeddingLevel = 0;
    String lastTplCommand = "";
    // iterate over tokens on the line and push to stack any changes
    while (!context.isBlankLine()
        && ts.moveNext()
        && ((ts.isCurrentTokenSequenceVirtual() && ts.offset() < context.getLineEndOffset())
            || ts.offset() <= context.getLineEndOffset())) {
      Token<TplTopTokenId> token = ts.token();
      if (token == null) {
        continue;
      } else if (ts.embedded() != null) {
        // indent for smarty command of the zero embedding level
        if (embeddingLevel == 1 && afterDelimiter) {
          if (token.id() == TplTopTokenId.T_SMARTY && context.isIndentThisLine()) {
            String tplToken = getFunctionalTplTokenId(token);
            isSmartyBodyCommand = isBodyCommand(tplToken, context);
            if (isSmartyBodyCommand) {
              lastTplCommand = tplToken;
              isSmartyElseCommand = isElseCommand(tplToken);
            }
          } else {
            isSmartyBodyCommand = false;
            isSmartyElseCommand = false;
          }
        }
        continue;
      }

      if (token.id() == TplTopTokenId.T_SMARTY_OPEN_DELIMITER) {
        afterDelimiter = true;
        embeddingLevel++;
        TplStackItem state = new TplStackItem(StackItemState.IN_RULE);
        blockStack.push(state);
      } else if (token.id() == TplTopTokenId.T_SMARTY_CLOSE_DELIMITER) {
        afterDelimiter = false;
        if (isInState(blockStack, StackItemState.IN_RULE)) {
          // check that IN_RULE is the last state
          TplStackItem item = blockStack.pop();
          embeddingLevel--;
          if (embeddingLevel == 0) {
            assert item.state == StackItemState.IN_RULE;
            if (isSmartyBodyCommand) {
              if (!blockStack.isEmpty()
                  && isInRelatedCommand(lastTplCommand, blockStack.peek().getCommand())) {
                if (isSmartyElseCommand) {
                  String command = blockStack.pop().command;
                  blockStack.push(new TplStackItem(StackItemState.IN_BODY, command));
                } else {
                  blockStack.pop();
                }
                iis.add(new IndentCommand(IndentCommand.Type.RETURN, preservedLineIndentation));
              } else {
                blockStack.push(new TplStackItem(StackItemState.IN_BODY, lastTplCommand));
              }
            }
          }
        }
      } else if (isCommentToken(token)) {
        int start = context.getLineStartOffset();
        if (start < ts.offset()) {
          start = ts.offset();
        }
        int commentEndOffset = ts.offset() + ts.token().text().toString().trim().length() - 1;
        int end = context.getLineEndOffset();
        if (end > commentEndOffset) {
          end = commentEndOffset;
        }
        if (start > end) {
          // do nothing
        } else if (start == ts.offset()) {
          if (end < commentEndOffset) {
            // if comment ends on next line put formatter to IN_COMMENT state
            int lineStart = Utilities.getRowStart(getDocument(), ts.offset());
            preservedLineIndentation = start - lineStart;
          }
        } else if (end == commentEndOffset) {
          String text = getDocument().getText(start, end - start + 1).trim();
          if (!text.startsWith("*/")) {
            // if line does not start with '*/' then treat it as unformattable
            IndentCommand ic =
                new IndentCommand(
                    IndentCommand.Type.PRESERVE_INDENTATION, context.getLineStartOffset());
            ic.setFixedIndentSize(preservedLineIndentation);
            iis.add(ic);
          }
          preservedLineIndentation = -1;
        } else {
          IndentCommand ic =
              new IndentCommand(
                  IndentCommand.Type.PRESERVE_INDENTATION, context.getLineStartOffset());
          ic.setFixedIndentSize(preservedLineIndentation);
          iis.add(ic);
        }
      }
    }
    if (context.isBlankLine() && iis.isEmpty()) {
      IndentCommand ic =
          new IndentCommand(IndentCommand.Type.PRESERVE_INDENTATION, context.getLineStartOffset());
      ic.setFixedIndentSize(preservedLineIndentation);
      iis.add(ic);
    }

    if (iis.isEmpty()) {
      iis.add(new IndentCommand(IndentCommand.Type.NO_CHANGE, context.getLineStartOffset()));
    }

    if (context.getNextLineStartOffset() != -1) {
      getIndentFromState(preliminaryNextLineIndent, false, context.getNextLineStartOffset());
      if (preliminaryNextLineIndent.isEmpty()) {
        preliminaryNextLineIndent.add(
            new IndentCommand(IndentCommand.Type.NO_CHANGE, context.getNextLineStartOffset()));
      }
    }

    return iis;
  }
  @Override
  public Map<String, List<OffsetRange>> folds(ParserResult info) {
    ASTNode root = ASTUtils.getRoot(info);

    if (root == null) {
      return Collections.emptyMap();
    }

    GroovyParserResult rpr = ASTUtils.getParseResult(info);
    AnalysisResult analysisResult = rpr.getStructure();

    Map<String, List<OffsetRange>> folds = new HashMap<String, List<OffsetRange>>();
    List<OffsetRange> codefolds = new ArrayList<OffsetRange>();
    folds.put("codeblocks", codefolds); // NOI18N

    final BaseDocument doc = LexUtilities.getDocument(rpr, false);
    if (doc == null) {
      return Collections.emptyMap();
    }

    final OffsetRange[] importsRange = new OffsetRange[1];
    final List<OffsetRange> commentsRanges = new ArrayList<OffsetRange>();

    doc.render(
        new Runnable() {
          @Override
          public void run() {
            TokenSequence<?> ts = LexUtilities.getGroovyTokenSequence(doc, 1);

            int importStart = 0;
            int importEnd = 0;

            boolean startSet = false;

            while (ts != null && ts.isValid() && ts.moveNext()) {
              Token t = ts.token();
              if (t.id() == GroovyTokenId.LITERAL_import) {
                int offset = ts.offset();
                if (!startSet) {
                  importStart = offset;
                  startSet = true;
                }
                importEnd = offset;
              } else if (t.id() == GroovyTokenId.BLOCK_COMMENT) {
                // does this Block comment (GSF_BLOCK_COMMENT) span
                // multiple lines? E.g. includes \n ?
                StringBuffer sb = new StringBuffer(t.text());

                if (sb.indexOf("\n") != -1) {
                  int offset = ts.offset();
                  commentsRanges.add(new OffsetRange(offset, offset + t.length()));
                }
              }
            }
            try {
              importEnd = Utilities.getRowEnd(doc, importEnd);
              importsRange[0] = new OffsetRange(importStart, importEnd);
            } catch (BadLocationException ble) {
              Exceptions.printStackTrace(ble);
            }
          }
        });

    if (!commentsRanges.isEmpty()) {
      folds.put("comments", commentsRanges); // NOI18N
    }

    try {
      if (importsRange[0] != null
          && Utilities.getRowCount(doc, importsRange[0].getStart(), importsRange[0].getEnd()) > 1) {
        folds.put("imports", Collections.singletonList(importsRange[0])); // NOI18N
      }
      addFolds(doc, analysisResult.getElements(), folds, codefolds);
    } catch (BadLocationException ex) {
      Exceptions.printStackTrace(ex);
    }

    return folds;
  }
Example #15
0
  public void run(JsRuleContext context, List<Hint> result) {
    JsParseResult info = AstUtilities.getParseResult(context.parserResult);
    Node node = context.node;

    AstElement element = (AstElement) node.element;
    if (element == null) {
      JsParseResult jps = AstUtilities.getParseResult(info);
      if (jps != null) {
        jps.getStructure();
        element = (AstElement) node.element;
        if (element == null) {
          return;
        }
      }
    }

    if (element.getKind() != ElementKind.METHOD && element.getKind() != ElementKind.CONSTRUCTOR) {
      return;
    }

    if (!(element instanceof FunctionAstElement)) {
      assert false : element;
      return;
    }

    FunctionAstElement func = (FunctionAstElement) element;

    Map<String, String> docProps = element.getDocProps();
    if (docProps == null || docProps.size() == 0) {
      return;
    }

    // Make sure we actually have some parameters in the doc props
    boolean found = false;
    for (String key : docProps.keySet()) {
      if (!key.startsWith("@")) {
        found = true;
        break;
      }
    }

    // Don't complain about functions that don't have any parameters
    if (!found) {
      return;
    }

    // Make sure every parameter is documented
    List<String> params = func.getParameters();
    List<String> missing = null;
    List<String> extra = null;
    for (String param : params) {
      if (!docProps.containsKey(param)) {
        if (missing == null) {
          missing = new ArrayList<String>();
        }
        missing.add(param);
      }
    }

    // TODO - make sure doc props exist even for items without types!!
    for (String key : docProps.keySet()) {
      if (key.startsWith("@")) {
        continue;
      }
      if (!params.contains(key)) {
        if (extra == null) {
          extra = new ArrayList<String>();
        }
        extra.add(key);
      }
    }

    if (missing != null || extra != null) {
      String label;
      if (missing != null && extra != null) {
        label = NbBundle.getMessage(WrongJsDoc.class, "WrongParamsBoth", missing, extra);
      } else if (missing != null) {
        label = NbBundle.getMessage(WrongJsDoc.class, "WrongParamsMissing", missing);
      } else {
        assert extra != null;
        label = NbBundle.getMessage(WrongJsDoc.class, "WrongParamsExtra", extra);
      }

      OffsetRange astRange = AstUtilities.getNameRange(node);
      OffsetRange lexRange = LexUtilities.getLexerOffsets(info, astRange);
      if (lexRange == OffsetRange.NONE) {
        return;
      }
      if (lexRange.getEnd() < context.doc.getLength()) {
        try {
          int startRowEnd = Utilities.getRowEnd(context.doc, lexRange.getStart());
          if (startRowEnd < lexRange.getEnd() && startRowEnd > lexRange.getStart()) {
            lexRange = new OffsetRange(lexRange.getStart(), startRowEnd);
          }
        } catch (BadLocationException ex) {
          Exceptions.printStackTrace(ex);
        }
      }

      List<HintFix> fixList =
          Collections.<HintFix>singletonList(new MoreInfoFix("wrongjsdoc")); // NOI18N
      Hint desc =
          new Hint(
              this, label, info.getSnapshot().getSource().getFileObject(), lexRange, fixList, 1450);
      result.add(desc);
    }
  }