/** Result computed show it... Takes AnnotateLines and shows them. */ public void annotationLines(File file, List<AnnotateLine> annotateLines) { // set repository root for popup menu, now should be the right time repositoryRoot = Mercurial.getInstance().getRepositoryRoot(getCurrentFile()); final List<AnnotateLine> lines = new LinkedList<AnnotateLine>(annotateLines); int lineCount = lines.size(); /** 0 based line numbers => 1 based line numbers */ final int ann2editorPermutation[] = new int[lineCount]; for (int i = 0; i < lineCount; i++) { ann2editorPermutation[i] = i + 1; } DiffProvider diff = (DiffProvider) Lookup.getDefault().lookup(DiffProvider.class); if (diff != null) { Reader r = new LinesReader(lines); Reader docReader = Utils.getDocumentReader(doc); try { Difference[] differences = diff.computeDiff(r, docReader); // customize annotation line numbers to match different reality // compule line permutation for (Difference d : differences) { int offset, editorStart; if (d.getType() == Difference.ADD) { offset = d.getSecondEnd() - d.getSecondStart() + 1; editorStart = d.getFirstStart(); } else if (d.getType() == Difference.DELETE) { offset = d.getFirstEnd() - d.getFirstStart() + 1; editorStart = d.getFirstEnd(); for (int c = editorStart - offset; c < editorStart; c++) { ann2editorPermutation[c] = -1; } offset = -offset; } else { // change int firstLen = d.getFirstEnd() - d.getFirstStart(); int secondLen = d.getSecondEnd() - d.getSecondStart(); offset = secondLen - firstLen; if (offset == 0) continue; editorStart = d.getFirstEnd(); for (int c = d.getFirstStart(); c < editorStart; c++) { ann2editorPermutation[c] += -1; } } for (int c = editorStart; c < lineCount; c++) { ann2editorPermutation[c] += offset; } } } catch (IOException e) { Mercurial.LOG.log( Level.INFO, "Cannot compute local diff required for annotations, ignoring..."); // NOI18N } } doc.render( new Runnable() { @Override public void run() { StyledDocument sd = (StyledDocument) doc; Iterator<AnnotateLine> it = lines.iterator(); previousRevisions = Collections.synchronizedMap(new HashMap<String, HgRevision>()); originalFiles = Collections.synchronizedMap(new HashMap<String, File>()); elementAnnotations = Collections.synchronizedMap(new HashMap<Element, AnnotateLine>(lines.size())); while (it.hasNext()) { AnnotateLine line = it.next(); int lineNum = ann2editorPermutation[line.getLineNum() - 1]; if (lineNum == -1) { continue; } try { int lineOffset = NbDocument.findLineOffset(sd, lineNum - 1); Element element = sd.getParagraphElement(lineOffset); elementAnnotations.put(element, line); } catch (IndexOutOfBoundsException ex) { // TODO how could I get line behind document end? // furtunately user does not spot it Mercurial.LOG.log(Level.INFO, null, ex); } } } }); final String url = HgUtils.getRemoteRepository(repositoryRoot); final boolean isKenaiRepository = url != null && HgKenaiAccessor.getInstance().isKenai(url); if (isKenaiRepository) { kenaiUsersMap = new HashMap<String, KenaiUser>(); Iterator<AnnotateLine> it = lines.iterator(); while (it.hasNext()) { AnnotateLine line = it.next(); String author = line.getAuthor(); if (author != null && !author.equals("") && !kenaiUsersMap.keySet().contains(author)) { KenaiUser ku = HgKenaiAccessor.getInstance().forName(author, url); if (ku != null) { kenaiUsersMap.put(author, ku); } } } } // lazy listener registration caret.addChangeListener(this); this.caretTimer = new Timer(500, this); caretTimer.setRepeats(false); elementAnnotationsSubstitute = ""; onCurrentLine(); revalidate(); repaint(); }
@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; }