--- a/csl.api/nbproject/project.properties +++ a/csl.api/nbproject/project.properties @@ -40,9 +40,9 @@ # Version 2 license, then the option applies only if the new code is # made subject to such option by the copyright holder. -spec.version.base=2.49.0 +spec.version.base=2.50.0 is.autoload=true -javac.source=1.6 +javac.source=1.7 javadoc.overview=${basedir}/doc/overview.html javadoc.arch=${basedir}/arch.xml --- a/csl.api/src/org/netbeans/modules/csl/core/SpiSupportAccessor.java +++ a/csl.api/src/org/netbeans/modules/csl/core/SpiSupportAccessor.java @@ -0,0 +1,74 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2015 Sun Microsystems, Inc. + */ +package org.netbeans.modules.csl.core; + +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.modules.parsing.spi.support.CancelSupport; +import org.openide.util.Parameters; + +/** + * + * @author Tomas Zezula + */ +public abstract class SpiSupportAccessor { + private static volatile SpiSupportAccessor instance; + + @NonNull + public static synchronized SpiSupportAccessor getInstance() { + if (instance == null) { + try { + Class.forName(org.netbeans.modules.csl.spi.support.CancelSupport.class.getName(), true, SpiSupportAccessor.class.getClassLoader()); + assert instance != null; + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + return instance; + } + + public static void setInstance(@NonNull final SpiSupportAccessor inst) { + Parameters.notNull("inst", inst); //NOI18N + instance = inst; + } + public abstract void setCancelSupport(@NonNull CancelSupport cancelSupport); + public abstract void removeCancelSupport(@NonNull CancelSupport cancelSupport); +} --- a/csl.api/src/org/netbeans/modules/csl/editor/overridden/ComputeAnnotations.java +++ a/csl.api/src/org/netbeans/modules/csl/editor/overridden/ComputeAnnotations.java @@ -50,7 +50,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.text.BadLocationException; @@ -68,6 +67,7 @@ import org.netbeans.modules.csl.core.GsfHtmlFormatter; import org.netbeans.modules.csl.core.Language; import org.netbeans.modules.csl.core.LanguageRegistry; +import org.netbeans.modules.csl.core.SpiSupportAccessor; import org.netbeans.modules.csl.navigation.ElementScanningTask; import org.netbeans.modules.csl.spi.ParserResult; import org.netbeans.modules.parsing.api.Embedding; @@ -82,7 +82,7 @@ import org.netbeans.modules.parsing.spi.Scheduler; import org.netbeans.modules.parsing.spi.SchedulerEvent; import org.netbeans.modules.parsing.spi.SchedulerTask; -import org.netbeans.modules.parsing.spi.TaskFactory; +import org.netbeans.modules.parsing.spi.support.CancelSupport; import org.openide.filesystems.FileObject; import org.openide.text.NbDocument; import org.openide.util.NbBundle; @@ -91,110 +91,113 @@ * * @author lahvac */ -public class ComputeAnnotations extends ParserResultTask { +public final class ComputeAnnotations extends ParserResultTask { private static final Logger LOG = Logger.getLogger(ComputeAnnotations.class.getName()); - private final AtomicBoolean cancel = new AtomicBoolean(); + private final CancelSupport cancel = CancelSupport.create(this); @Override public void run(Result result, SchedulerEvent event) { if (!(result instanceof ParserResult)) { return; } + SpiSupportAccessor.getInstance().setCancelSupport(cancel); + try { + final FileObject file = result.getSnapshot().getSource().getFileObject(); - cancel.set(false); - - final FileObject file = result.getSnapshot().getSource().getFileObject(); + if (file == null) { + return; + } - if (file == null) { - return; - } + final StyledDocument doc = (StyledDocument) result.getSnapshot().getSource().getDocument(false); - final StyledDocument doc = (StyledDocument) result.getSnapshot().getSource().getDocument(false); + if (doc == null) { + return; + } - if (doc == null) { - return; - } + final List annotations = new LinkedList(); + try { + ParserManager.parse(Collections.singleton(result.getSnapshot().getSource()), new UserTask() { + public @Override void run(ResultIterator resultIterator) throws Exception { + Language language = LanguageRegistry.getInstance().getLanguageByMimeType(resultIterator.getSnapshot().getMimeType()); + if(language != null) { //check for non csl results + StructureScanner scanner = language.getStructure(); + OverridingMethods om = language.getOverridingMethods(); + if (scanner != null && om != null) { + Parser.Result r = resultIterator.getParserResult(); + if (r instanceof ParserResult) { + Map> overriding = new HashMap>(); + Map> overridden = new HashMap>(); + Set seen = new HashSet(); + Map node2Parent = new HashMap(); - final List annotations = new LinkedList(); - try { - ParserManager.parse(Collections.singleton(result.getSnapshot().getSource()), new UserTask() { - public @Override void run(ResultIterator resultIterator) throws Exception { - Language language = LanguageRegistry.getInstance().getLanguageByMimeType(resultIterator.getSnapshot().getMimeType()); - if(language != null) { //check for non csl results - StructureScanner scanner = language.getStructure(); - OverridingMethods om = language.getOverridingMethods(); - if (scanner != null && om != null) { - Parser.Result r = resultIterator.getParserResult(); - if (r instanceof ParserResult) { - Map> overriding = new HashMap>(); - Map> overridden = new HashMap>(); - Set seen = new HashSet(); - Map node2Parent = new HashMap(); - - List children = ElementScanningTask.findCachedStructure(resultIterator.getSnapshot(), r); - if (children == null) { - long startTime = System.currentTimeMillis(); - children = scanner.scan((ParserResult) r); + List children = ElementScanningTask.findCachedStructure(resultIterator.getSnapshot(), r); + if (children == null) { + long startTime = System.currentTimeMillis(); + children = scanner.scan((ParserResult) r); - long endTime = System.currentTimeMillis(); - Logger.getLogger("TIMER").log(Level.FINE, "Structure (" + language.getMimeType() + ")", - new Object[]{file, endTime - startTime}); - ElementScanningTask.markProcessed(r, children); - } - List todo = new LinkedList(children); - - while (!todo.isEmpty()) { - StructureItem i = todo.remove(0); + long endTime = System.currentTimeMillis(); + Logger.getLogger("TIMER").log(Level.FINE, "Structure (" + language.getMimeType() + ")", + new Object[]{file, endTime - startTime}); + ElementScanningTask.markProcessed(r, children); + } + List todo = new LinkedList(children); - todo.addAll(i.getNestedItems()); + while (!todo.isEmpty()) { + StructureItem i = todo.remove(0); - for (StructureItem nested : i.getNestedItems()) { - if (!node2Parent.containsKey(nested.getElementHandle())) { - node2Parent.put(nested.getElementHandle(), i.getElementHandle()); + todo.addAll(i.getNestedItems()); + + for (StructureItem nested : i.getNestedItems()) { + if (!node2Parent.containsKey(nested.getElementHandle())) { + node2Parent.put(nested.getElementHandle(), i.getElementHandle()); + } + } + + if (seen.add(i.getElementHandle())) { + if (i.getElementHandle().getKind() != ElementKind.CLASS && i.getElementHandle().getKind() != ElementKind.INTERFACE) { + Collection ov = om.overrides((ParserResult) r, i.getElementHandle()); + + if (ov != null && !ov.isEmpty()) { + overriding.put(i.getElementHandle(), ov); + } + } + + if (om.isOverriddenBySupported((ParserResult) r, i.getElementHandle())) { + Collection on = om.overriddenBy((ParserResult) r, i.getElementHandle()); + + if (on != null && !on.isEmpty()) { + overridden.put(i.getElementHandle(), on); + } + } } } - if (seen.add(i.getElementHandle())) { - if (i.getElementHandle().getKind() != ElementKind.CLASS && i.getElementHandle().getKind() != ElementKind.INTERFACE) { - Collection ov = om.overrides((ParserResult) r, i.getElementHandle()); - - if (ov != null && !ov.isEmpty()) { - overriding.put(i.getElementHandle(), ov); - } - } - - if (om.isOverriddenBySupported((ParserResult) r, i.getElementHandle())) { - Collection on = om.overriddenBy((ParserResult) r, i.getElementHandle()); - - if (on != null && !on.isEmpty()) { - overridden.put(i.getElementHandle(), on); - } - } - } + createAnnotations((ParserResult) r, doc, overriding, node2Parent, false, annotations); + createAnnotations((ParserResult) r, doc, overridden, node2Parent, true, annotations); } - - createAnnotations((ParserResult) r, doc, overriding, node2Parent, false, annotations); - createAnnotations((ParserResult) r, doc, overridden, node2Parent, true, annotations); } } + + for(Embedding e : resultIterator.getEmbeddings()) { + run(resultIterator.getResultIterator(e)); + } } + }); + } catch (ParseException e) { + LOG.log(Level.WARNING, null, e); + } - for(Embedding e : resultIterator.getEmbeddings()) { - run(resultIterator.getResultIterator(e)); - } - } - }); - } catch (ParseException e) { - LOG.log(Level.WARNING, null, e); + AnnotationsHolder holder = AnnotationsHolder.get(file); + + if (holder != null) { + holder.setNewAnnotations(annotations); + } +// Logger.getLogger("TIMER").log(Level.FINE, "Is Overridden Annotations", new Object[] {info.getFileObject(), end - start}); + } finally { + SpiSupportAccessor.getInstance().removeCancelSupport(cancel); } - AnnotationsHolder holder = AnnotationsHolder.get(file); - - if (holder != null) { - holder.setNewAnnotations(annotations); - } -// Logger.getLogger("TIMER").log(Level.FINE, "Is Overridden Annotations", new Object[] {info.getFileObject(), end - start}); } private void createAnnotations(ParserResult r, StyledDocument doc, Map> descriptions, Map node2Parent, boolean overridden, List annotations) { @@ -279,9 +282,8 @@ @Override public void cancel() { - cancel.set(true); } - + private static Position getPosition(final StyledDocument doc, final int offset) { class Impl implements Runnable { private Position pos; --- a/csl.api/src/org/netbeans/modules/csl/editor/semantic/MarkOccurrencesHighlighter.java +++ a/csl.api/src/org/netbeans/modules/csl/editor/semantic/MarkOccurrencesHighlighter.java @@ -45,7 +45,6 @@ import java.awt.Color; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.SortedSet; @@ -60,11 +59,13 @@ import org.netbeans.modules.csl.spi.ParserResult; import org.netbeans.modules.csl.core.Language; import org.netbeans.modules.csl.api.ColoringAttributes.Coloring; +import org.netbeans.modules.csl.core.SpiSupportAccessor; import org.netbeans.modules.parsing.api.Snapshot; import org.netbeans.modules.parsing.spi.CursorMovedSchedulerEvent; import org.netbeans.modules.parsing.spi.ParserResultTask; import org.netbeans.modules.parsing.spi.Scheduler; import org.netbeans.modules.parsing.spi.SchedulerEvent; +import org.netbeans.modules.parsing.spi.support.CancelSupport; import org.netbeans.spi.editor.highlighting.support.AbstractHighlightsContainer; import org.openide.ErrorManager; import org.openide.util.NbBundle; @@ -78,11 +79,12 @@ * * @author Jan Lahoda */ -public class MarkOccurrencesHighlighter extends ParserResultTask { +public final class MarkOccurrencesHighlighter extends ParserResultTask { private static final Logger LOG = Logger.getLogger(MarkOccurrencesHighlighter.class.getName()); //private FileObject file; + private final CancelSupport cancel = CancelSupport.create(this); private final Language language; private final Snapshot snapshot; private int version; @@ -101,59 +103,62 @@ // } // public void run(ParserResult info, SchedulerEvent event) { - resume(); - - Document doc = snapshot.getSource().getDocument(false); - - if (doc == null) { - LOG.log(Level.INFO, "MarkOccurencesHighlighter: Cannot get document!"); //NOI18N - return ; - } - - if (!(event instanceof CursorMovedSchedulerEvent)) { - return; - } + SpiSupportAccessor.getInstance().setCancelSupport(cancel); + try { + Document doc = snapshot.getSource().getDocument(false); - int caretPosition = ((CursorMovedSchedulerEvent) event).getCaretOffset(); - - if (isCancelled()) { - return; - } - - int snapshotOffset = info.getSnapshot().getEmbeddedOffset(caretPosition); + if (doc == null) { + LOG.log(Level.INFO, "MarkOccurencesHighlighter: Cannot get document!"); //NOI18N + return ; + } - if (snapshotOffset == -1) { - // caret offset not part of this lang embedding, ignore, since - // we cannot assume identifiers in different languages match. - return; - } + if (!(event instanceof CursorMovedSchedulerEvent)) { + return; + } - List bag = processImpl(info, doc, caretPosition); - if(bag == null) { - //the occurrences finder haven't found anything, just ignore the result - //and keep the previous occurrences - return ; - } + int caretPosition = ((CursorMovedSchedulerEvent) event).getCaretOffset(); - if (isCancelled()) { - return; - } - - GsfSemanticLayer layer = GsfSemanticLayer.getLayer(MarkOccurrencesHighlighter.class, doc); - SortedSet seqs = new TreeSet(); + if (cancel.isCancelled()) { + return; + } - if (bag.size() > 0) { - for (OffsetRange range : bag) { - if (range != OffsetRange.NONE) { - SequenceElement s = new SequenceElement(language, range, MO); - seqs.add(s); + int snapshotOffset = info.getSnapshot().getEmbeddedOffset(caretPosition); + + if (snapshotOffset == -1) { + // caret offset not part of this lang embedding, ignore, since + // we cannot assume identifiers in different languages match. + return; + } + + List bag = processImpl(info, doc, caretPosition); + if(bag == null) { + //the occurrences finder haven't found anything, just ignore the result + //and keep the previous occurrences + return ; + } + + if (cancel.isCancelled()) { + return; + } + + GsfSemanticLayer layer = GsfSemanticLayer.getLayer(MarkOccurrencesHighlighter.class, doc); + SortedSet seqs = new TreeSet(); + + if (bag.size() > 0) { + for (OffsetRange range : bag) { + if (range != OffsetRange.NONE) { + SequenceElement s = new SequenceElement(language, range, MO); + seqs.add(s); + } } } + + layer.setColorings(seqs, version++); + + OccurrencesMarkProvider.get(doc).setOccurrences(OccurrencesMarkProvider.createMarks(doc, bag, ES_COLOR, NbBundle.getMessage(MarkOccurrencesHighlighter.class, "LBL_ES_TOOLTIP"))); + } finally { + SpiSupportAccessor.getInstance().removeCancelSupport(cancel); } - - layer.setColorings(seqs, version++); - - OccurrencesMarkProvider.get(doc).setOccurrences(OccurrencesMarkProvider.createMarks(doc, bag, ES_COLOR, NbBundle.getMessage(MarkOccurrencesHighlighter.class, "LBL_ES_TOOLTIP"))); } @NonNull @@ -168,7 +173,7 @@ ErrorManager.getDefault().notify(ex); } - if (isCancelled()) { + if (cancel.isCancelled()) { finder.cancel(); } @@ -186,21 +191,11 @@ public Class getSchedulerClass () { return Scheduler.CURSOR_SENSITIVE_TASK_SCHEDULER; } - - private boolean canceled; - - public final synchronized void cancel() { - canceled = true; + + @Override + public final void cancel() { } - - protected final synchronized boolean isCancelled() { - return canceled; - } - - protected final synchronized void resume() { - canceled = false; - } - + public static AbstractHighlightsContainer getHighlightsBag(Document doc) { GsfSemanticLayer highlight = GsfSemanticLayer.getLayer(MarkOccurrencesHighlighter.class, doc); return highlight; --- a/csl.api/src/org/netbeans/modules/csl/editor/semantic/SemanticHighlighter.java +++ a/csl.api/src/org/netbeans/modules/csl/editor/semantic/SemanticHighlighter.java @@ -58,6 +58,7 @@ import org.netbeans.modules.csl.api.SemanticAnalyzer; import org.netbeans.modules.csl.core.Language; import org.netbeans.modules.csl.core.LanguageRegistry; +import org.netbeans.modules.csl.core.SpiSupportAccessor; import org.netbeans.modules.csl.spi.ParserResult; import org.netbeans.modules.parsing.api.Embedding; import org.netbeans.modules.parsing.api.ParserManager; @@ -65,6 +66,7 @@ import org.netbeans.modules.parsing.api.Source; import org.netbeans.modules.parsing.api.UserTask; import org.netbeans.modules.parsing.spi.*; +import org.netbeans.modules.parsing.spi.support.CancelSupport; /** @@ -76,9 +78,11 @@ * * @author Jan Lahoda */ -public class SemanticHighlighter extends IndexingAwareParserResultTask { +public final class SemanticHighlighter extends IndexingAwareParserResultTask { private static final Logger LOG = Logger.getLogger(SemanticHighlighter.class.getName()); + + private final CancelSupport cancel = CancelSupport.create(this); /** Creates a new instance of SemanticHighlighter */ SemanticHighlighter() { @@ -99,77 +103,69 @@ return Scheduler.EDITOR_SENSITIVE_TASK_SCHEDULER; } - private boolean cancelled; - public final synchronized void cancel() { - cancelled = true; - } - - protected final synchronized boolean isCancelled() { - return cancelled; - } - - protected final synchronized void resume() { - cancelled = false; + public final void cancel() { } public @Override void run(ParserResult info, SchedulerEvent event) { - resume(); - Document doc = info.getSnapshot().getSource().getDocument(false); if (doc == null) { return; } + SpiSupportAccessor.getInstance().setCancelSupport(cancel); + try { + long startTime = System.currentTimeMillis(); - long startTime = System.currentTimeMillis(); + Source source = info.getSnapshot().getSource(); + final SortedSet newColoring = new TreeSet(); + try { + ParserManager.parse(Collections.singleton(source), new UserTask() { + public @Override void run(ResultIterator resultIterator) throws Exception { + String mimeType = resultIterator.getSnapshot().getMimeType(); + Language language = LanguageRegistry.getInstance().getLanguageByMimeType(mimeType); + if (language != null) { + ColoringManager manager = language.getColoringManager(); + SemanticAnalyzer task = language.getSemanticAnalyzer(); + if (manager != null && task != null) { + Parser.Result r = resultIterator.getParserResult(); + if (r instanceof ParserResult) { + process(language, (ParserResult) r, newColoring); + } + } + } - Source source = info.getSnapshot().getSource(); - final SortedSet newColoring = new TreeSet(); - try { - ParserManager.parse(Collections.singleton(source), new UserTask() { - public @Override void run(ResultIterator resultIterator) throws Exception { - String mimeType = resultIterator.getSnapshot().getMimeType(); - Language language = LanguageRegistry.getInstance().getLanguageByMimeType(mimeType); - if (language != null) { - ColoringManager manager = language.getColoringManager(); - SemanticAnalyzer task = language.getSemanticAnalyzer(); - if (manager != null && task != null) { - Parser.Result r = resultIterator.getParserResult(); - if (r instanceof ParserResult) { - process(language, (ParserResult) r, newColoring); + for(Embedding e : resultIterator.getEmbeddings()) { + if (cancel.isCancelled()) { + return; + } else { + run(resultIterator.getResultIterator(e)); } } } + }); + } catch (ParseException e) { + LOG.log(Level.WARNING, null, e); + return; + } - for(Embedding e : resultIterator.getEmbeddings()) { - if (isCancelled()) { - return; - } else { - run(resultIterator.getResultIterator(e)); - } - } + long endTime = System.currentTimeMillis(); + Logger.getLogger("TIMER").log(Level.FINE, "Semantic (" + source.getMimeType() + ")", //NOI18N + new Object[] { source.getFileObject(), endTime - startTime}); + + if (cancel.isCancelled()) { + return; + } + + final GsfSemanticLayer layer = GsfSemanticLayer.getLayer(SemanticHighlighter.class, doc); + SwingUtilities.invokeLater(new Runnable () { + public void run() { + // XXX: parsingapi + layer.setColorings(newColoring, -1); //version } }); - } catch (ParseException e) { - LOG.log(Level.WARNING, null, e); - return; + } finally { + SpiSupportAccessor.getInstance().removeCancelSupport(cancel); } - - long endTime = System.currentTimeMillis(); - Logger.getLogger("TIMER").log(Level.FINE, "Semantic (" + source.getMimeType() + ")", //NOI18N - new Object[] { source.getFileObject(), endTime - startTime}); - - if (isCancelled()) { - return; - } - - final GsfSemanticLayer layer = GsfSemanticLayer.getLayer(SemanticHighlighter.class, doc); - SwingUtilities.invokeLater(new Runnable () { - public void run() { -// XXX: parsingapi - layer.setColorings(newColoring, -1); //version - } - }); } @@ -294,7 +290,7 @@ // } - if (isCancelled()) { + if (cancel.isCancelled()) { return; } @@ -312,7 +308,7 @@ "(mimepath = " + result.getSnapshot().getMimePath() + ")", ex); } - if (isCancelled()) { + if (cancel.isCancelled()) { task.cancel(); return; } @@ -330,7 +326,7 @@ newColoring.add(new SequenceElement(language, range, c)); - if (isCancelled()) { + if (cancel.isCancelled()) { return; } } --- a/csl.api/src/org/netbeans/modules/csl/hints/GsfHintsProvider.java +++ a/csl.api/src/org/netbeans/modules/csl/hints/GsfHintsProvider.java @@ -69,6 +69,7 @@ import org.netbeans.modules.csl.api.Hint; import org.netbeans.modules.csl.api.OffsetRange; import org.netbeans.modules.csl.api.RuleContext; +import org.netbeans.modules.csl.core.SpiSupportAccessor; import org.netbeans.modules.csl.hints.infrastructure.GsfHintsManager; import org.netbeans.modules.csl.spi.ParserResult; import org.netbeans.modules.parsing.api.Embedding; @@ -79,6 +80,7 @@ import org.netbeans.modules.parsing.spi.ParseException; import org.netbeans.modules.parsing.spi.ParserResultTask; import org.netbeans.modules.parsing.spi.SchedulerEvent; +import org.netbeans.modules.parsing.spi.support.CancelSupport; import org.netbeans.spi.editor.hints.ErrorDescription; import org.netbeans.spi.editor.hints.ErrorDescriptionFactory; import org.netbeans.spi.editor.hints.HintsController; @@ -101,7 +103,8 @@ public final class GsfHintsProvider extends ParserResultTask { public static final Logger LOG = Logger.getLogger(GsfHintsProvider.class.getName()); // NOI18N - + + private final CancelSupport cancel = CancelSupport.create(this); private FileObject file; /** @@ -133,7 +136,7 @@ } for (Error d : errors) { - if (isCanceled()) { + if (cancel.isCancelled()) { return null; } @@ -178,7 +181,7 @@ final String desc = d.getDisplayName(); final Position[] range = getLine(d, doc, position, endPosition); - if (isCanceled()) { + if (cancel.isCancelled()) { return null; } @@ -189,7 +192,7 @@ descs.add(ErrorDescriptionFactory.createErrorDescription(errorKind2Severity.get(d.getSeverity()), desc, ehm, doc, range[0], range[1])); } - if (isCanceled()) { + if (cancel.isCancelled()) { return null; } @@ -209,7 +212,7 @@ // under the document read-lock. doc.render(new Runnable() { public void run() { - if (isCanceled()) { + if (cancel.isCancelled()) { return; } ret[0] = getLine0(d, doc, startOffset, endOffset); @@ -259,7 +262,7 @@ int len = doc.getLength(); if (startOffsetFinal > len || endOffsetFinal > len) { - if (!isCanceled() && LOG.isLoggable(Level.WARNING)) { + if (!cancel.isCancelled() && LOG.isLoggable(Level.WARNING)) { LOG.log(Level.WARNING, "document changed, but not canceled?" ); LOG.log(Level.WARNING, "len = " + len ); LOG.log(Level.WARNING, "startOffset = " + startOffsetFinal ); @@ -279,29 +282,16 @@ return result; } - - private boolean cancel; - - synchronized boolean isCanceled() { - return cancel; - } - + + @Override public void cancel() { - HintsProvider curProvider; - synchronized (this) { - curProvider = this.pendingProvider; - cancel = true; - } + final HintsProvider curProvider = this.pendingProvider; if (curProvider != null) { curProvider.cancel(); } } - - synchronized void resume() { - cancel = false; - } - + private List processProviderErrors( final List descriptions, Snapshot topLevelSnapshot, final ParserResult r, final Language language) throws ParseException { @@ -324,7 +314,7 @@ try { synchronized (this) { pendingProvider = provider; - if (isCanceled()) { + if (cancel.isCancelled()) { return errors; } } @@ -377,7 +367,7 @@ for(Embedding e : resultIterator.getEmbeddings()) { try { - if (isCanceled()) { + if (cancel.isCancelled()) { return; } } catch (Exception ex) { @@ -429,15 +419,12 @@ } public @Override void run(ParserResult result, SchedulerEvent event) { - resume(); - final Document doc = getDocument(); - if (doc == null) { LOG.log(Level.INFO, "SemanticHighlighter: Cannot get document!"); return ; } - + SpiSupportAccessor.getInstance().setCancelSupport(cancel); try { ParserManager.parse(Collections.singleton(result.getSnapshot().getSource()), new UserTask() { public @Override void run(ResultIterator resultIterator) throws ParseException { @@ -447,6 +434,8 @@ }); } catch (ParseException e) { LOG.log(Level.WARNING, null, e); + } finally { + SpiSupportAccessor.getInstance().removeCancelSupport(cancel); } } --- a/csl.api/src/org/netbeans/modules/csl/hints/infrastructure/HintsTask.java +++ a/csl.api/src/org/netbeans/modules/csl/hints/infrastructure/HintsTask.java @@ -53,6 +53,7 @@ import org.netbeans.modules.csl.core.LanguageRegistry; import org.netbeans.modules.csl.api.Hint; import org.netbeans.modules.csl.api.RuleContext; +import org.netbeans.modules.csl.core.SpiSupportAccessor; import org.netbeans.modules.csl.spi.ParserResult; import org.netbeans.modules.parsing.api.Embedding; import org.netbeans.modules.parsing.api.ParserManager; @@ -63,6 +64,7 @@ import org.netbeans.modules.parsing.spi.ParserResultTask; import org.netbeans.modules.parsing.spi.Scheduler; import org.netbeans.modules.parsing.spi.SchedulerEvent; +import org.netbeans.modules.parsing.spi.support.CancelSupport; import org.netbeans.spi.editor.hints.ErrorDescription; import org.netbeans.spi.editor.hints.HintsController; @@ -71,11 +73,11 @@ * * @author Tor Norbye */ -public class HintsTask extends ParserResultTask { +public final class HintsTask extends ParserResultTask { private static final Logger LOG = Logger.getLogger(HintsTask.class.getName()); - private volatile boolean cancelled = false; - + private final CancelSupport cancel = CancelSupport.create(this); + /** * Tracks the HintsProvider being executed, so it can be cancelled. */ @@ -85,10 +87,8 @@ } public @Override void run(ParserResult result, SchedulerEvent event) { - resume(); - - final List descriptions = new ArrayList(); - + final List descriptions = new ArrayList<>(); + SpiSupportAccessor.getInstance().setCancelSupport(cancel); try { ParserManager.parse(Collections.singleton(result.getSnapshot().getSource()), new UserTask() { public @Override void run(ResultIterator resultIterator) throws ParseException { @@ -131,7 +131,7 @@ try { synchronized (HintsTask.this) { pendingProvider = provider; - if (isCancelled()) { + if (cancel.isCancelled()) { return; } } @@ -140,7 +140,7 @@ pendingProvider = null; } - if (isCancelled()) { + if (cancel.isCancelled()) { return; } @@ -153,8 +153,9 @@ }); } catch (ParseException e) { LOG.log(Level.WARNING, null, e); + } finally { + SpiSupportAccessor.getInstance().removeCancelSupport(cancel); } - HintsController.setErrors(result.getSnapshot().getSource().getFileObject(), HintsTask.class.getName(), descriptions); } @@ -167,21 +168,9 @@ } public @Override void cancel() { - HintsProvider proc; - synchronized (this) { - proc = pendingProvider; - cancelled = true; - } + final HintsProvider proc = pendingProvider; if (proc != null) { proc.cancel(); } } - - private synchronized void resume() { - cancelled = false; - } - - private synchronized boolean isCancelled() { - return cancelled; - } } --- a/csl.api/src/org/netbeans/modules/csl/hints/infrastructure/SelectionHintsTask.java +++ a/csl.api/src/org/netbeans/modules/csl/hints/infrastructure/SelectionHintsTask.java @@ -52,6 +52,7 @@ import org.netbeans.modules.csl.api.HintsProvider; import org.netbeans.modules.csl.api.RuleContext; import org.netbeans.modules.csl.core.LanguageRegistry; +import org.netbeans.modules.csl.core.SpiSupportAccessor; import org.netbeans.modules.parsing.api.ResultIterator; import org.netbeans.modules.parsing.spi.Parser; import org.netbeans.modules.parsing.spi.Scheduler; @@ -62,6 +63,7 @@ import org.netbeans.modules.parsing.spi.ParseException; import org.netbeans.modules.parsing.spi.ParserResultTask; import org.netbeans.modules.parsing.spi.SchedulerEvent; +import org.netbeans.modules.parsing.spi.support.CancelSupport; import org.netbeans.spi.editor.hints.ErrorDescription; import org.netbeans.spi.editor.hints.HintsController; import org.openide.filesystems.FileObject; @@ -70,10 +72,10 @@ * * @author Tor Norbye */ -public class SelectionHintsTask extends ParserResultTask { +public final class SelectionHintsTask extends ParserResultTask { private static final Logger LOG = Logger.getLogger(SelectionHintsTask.class.getName()); - private volatile boolean cancelled = false; + private final CancelSupport cancel = CancelSupport.create(this); /** * Tracks the HintsProvider being executed, so it can be cancelled. @@ -84,88 +86,92 @@ } public @Override void run(ParserResult result, SchedulerEvent event) { - resume(); final FileObject fileObject = result.getSnapshot().getSource().getFileObject(); - if (fileObject == null || isCancelled()) { + if (fileObject == null || cancel.isCancelled()) { return; } - if (!(event instanceof CursorMovedSchedulerEvent) || isCancelled()) { + if (!(event instanceof CursorMovedSchedulerEvent) || cancel.isCancelled()) { return; } - // Do we have a selection? If so, don't do suggestions - CursorMovedSchedulerEvent evt = (CursorMovedSchedulerEvent) event; - final int[] range = new int [] { - Math.min(evt.getMarkOffset(), evt.getCaretOffset()), - Math.max(evt.getMarkOffset(), evt.getCaretOffset()) - }; - if (range == null || range.length != 2 || range[0] == -1 || range[1] == -1 || range[0] == range[1]) { - HintsController.setErrors(fileObject, SelectionHintsTask.class.getName(), Collections.emptyList()); - return; - } + SpiSupportAccessor.getInstance().setCancelSupport(cancel); + try { + // Do we have a selection? If so, don't do suggestions + CursorMovedSchedulerEvent evt = (CursorMovedSchedulerEvent) event; + final int[] range = new int [] { + Math.min(evt.getMarkOffset(), evt.getCaretOffset()), + Math.max(evt.getMarkOffset(), evt.getCaretOffset()) + }; + if (range == null || range.length != 2 || range[0] == -1 || range[1] == -1 || range[0] == range[1]) { + HintsController.setErrors(fileObject, SelectionHintsTask.class.getName(), Collections.emptyList()); + return; + } - try { - ParserManager.parse(Collections.singleton(result.getSnapshot().getSource()), new UserTask() { - public @Override void run(ResultIterator resultIterator) throws Exception { - Parser.Result r = resultIterator.getParserResult(range[0]); - if(!(r instanceof ParserResult)) { - return ; - } - Language language = LanguageRegistry.getInstance().getLanguageByMimeType(r.getSnapshot().getMimeType()); - if (language == null || isCancelled()) { - return; - } + try { + ParserManager.parse(Collections.singleton(result.getSnapshot().getSource()), new UserTask() { + public @Override void run(ResultIterator resultIterator) throws Exception { + Parser.Result r = resultIterator.getParserResult(range[0]); + if(!(r instanceof ParserResult)) { + return ; + } + Language language = LanguageRegistry.getInstance().getLanguageByMimeType(r.getSnapshot().getMimeType()); + if (language == null || cancel.isCancelled()) { + return; + } - HintsProvider provider = language.getHintsProvider(); - if (provider == null || isCancelled()) { - return; - } + HintsProvider provider = language.getHintsProvider(); + if (provider == null || cancel.isCancelled()) { + return; + } - GsfHintsManager manager = language.getHintsManager(); - if (manager == null || isCancelled()) { - return; - } + GsfHintsManager manager = language.getHintsManager(); + if (manager == null || cancel.isCancelled()) { + return; + } - List description = new ArrayList(); - List hints = new ArrayList(); + List description = new ArrayList(); + List hints = new ArrayList(); - RuleContext ruleContext = manager.createRuleContext((ParserResult) r, language, -1, range[0], range[1]); - if (ruleContext != null) { - try { - synchronized (this) { - pendingProvider = provider; - if (isCancelled()) { + RuleContext ruleContext = manager.createRuleContext((ParserResult) r, language, -1, range[0], range[1]); + if (ruleContext != null) { + try { + synchronized (this) { + pendingProvider = provider; + if (cancel.isCancelled()) { + return; + } + } + provider.computeSelectionHints(manager, ruleContext, hints, range[0], range[1]); + } finally { + pendingProvider = null; + } + + for (int i = 0; i < hints.size(); i++) { + Hint hint= hints.get(i); + + if (cancel.isCancelled()) { return; } + + ErrorDescription desc = manager.createDescription(hint, ruleContext, false, i == hints.size()-1); + description.add(desc); } - provider.computeSelectionHints(manager, ruleContext, hints, range[0], range[1]); - } finally { - pendingProvider = null; } - for (int i = 0; i < hints.size(); i++) { - Hint hint= hints.get(i); + if (cancel.isCancelled()) { + return; + } - if (isCancelled()) { - return; - } - - ErrorDescription desc = manager.createDescription(hint, ruleContext, false, i == hints.size()-1); - description.add(desc); - } + HintsController.setErrors(fileObject, SelectionHintsTask.class.getName(), description); } - - if (isCancelled()) { - return; - } - - HintsController.setErrors(fileObject, SelectionHintsTask.class.getName(), description); - } - }); - } catch (ParseException e) { - LOG.log(Level.WARNING, null, e); + }); + } catch (ParseException e) { + LOG.log(Level.WARNING, null, e); + } + } finally { + SpiSupportAccessor.getInstance().removeCancelSupport(cancel); } } @@ -180,20 +186,9 @@ } public @Override void cancel() { - synchronized (this) { - cancelled = true; - } - HintsProvider p = pendingProvider; + final HintsProvider p = pendingProvider; if (p != null) { p.cancel(); } } - - private synchronized void resume() { - cancelled = false; - } - - private synchronized boolean isCancelled() { - return cancelled; - } } --- a/csl.api/src/org/netbeans/modules/csl/hints/infrastructure/SuggestionsTask.java +++ a/csl.api/src/org/netbeans/modules/csl/hints/infrastructure/SuggestionsTask.java @@ -56,6 +56,7 @@ import org.netbeans.modules.csl.api.Hint; import org.netbeans.modules.csl.api.OffsetRange; import org.netbeans.modules.csl.api.RuleContext; +import org.netbeans.modules.csl.core.SpiSupportAccessor; import org.netbeans.modules.csl.spi.ParserResult; import org.netbeans.modules.parsing.api.ParserManager; import org.netbeans.modules.parsing.api.ResultIterator; @@ -66,6 +67,7 @@ import org.netbeans.modules.parsing.spi.ParserResultTask; import org.netbeans.modules.parsing.spi.Scheduler; import org.netbeans.modules.parsing.spi.SchedulerEvent; +import org.netbeans.modules.parsing.spi.support.CancelSupport; import org.netbeans.spi.editor.hints.ErrorDescription; import org.netbeans.spi.editor.hints.HintsController; import org.openide.filesystems.FileObject; @@ -75,10 +77,10 @@ * * @author Tor Norbye */ -public class SuggestionsTask extends ParserResultTask { +public final class SuggestionsTask extends ParserResultTask { private static final Logger LOG = Logger.getLogger(SuggestionsTask.class.getName()); - private volatile boolean cancelled = false; + private final CancelSupport cancel = CancelSupport.create(this); /** * Tracks the HintsProvider being executed, so it can be cancelled. @@ -89,95 +91,99 @@ } public @Override void run(ParserResult result, SchedulerEvent event) { - resume(); - + final FileObject fileObject = result.getSnapshot().getSource().getFileObject(); - if (fileObject == null || isCancelled()) { + if (fileObject == null || cancel.isCancelled()) { return; } - if (!(event instanceof CursorMovedSchedulerEvent) || isCancelled()) { + if (!(event instanceof CursorMovedSchedulerEvent) || cancel.isCancelled()) { return; } - // Do we have a selection? If so, don't do suggestions - CursorMovedSchedulerEvent evt = (CursorMovedSchedulerEvent) event; - int[] range = new int [] { - Math.min(evt.getMarkOffset(), evt.getCaretOffset()), - Math.max(evt.getMarkOffset(), evt.getCaretOffset()) - }; - if (range != null && range.length == 2 && range[0] != -1 && range[1] != -1 && range[0] != range[1]) { - HintsController.setErrors(fileObject, SuggestionsTask.class.getName(), Collections.emptyList()); - return; - } + SpiSupportAccessor.getInstance().setCancelSupport(cancel); + try { + // Do we have a selection? If so, don't do suggestions + CursorMovedSchedulerEvent evt = (CursorMovedSchedulerEvent) event; + int[] range = new int [] { + Math.min(evt.getMarkOffset(), evt.getCaretOffset()), + Math.max(evt.getMarkOffset(), evt.getCaretOffset()) + }; + if (range != null && range.length == 2 && range[0] != -1 && range[1] != -1 && range[0] != range[1]) { + HintsController.setErrors(fileObject, SuggestionsTask.class.getName(), Collections.emptyList()); + return; + } - final int pos = evt.getCaretOffset(); - if (pos == -1 || isCancelled()) { - return; - } - - try { - ParserManager.parse(Collections.singleton(result.getSnapshot().getSource()), new UserTask() { - public @Override void run(ResultIterator resultIterator) throws Exception { - Parser.Result r = resultIterator.getParserResult(pos); - if(!(r instanceof ParserResult)) { - return ; - } - Language language = LanguageRegistry.getInstance().getLanguageByMimeType(r.getSnapshot().getMimeType()); - if (language == null || isCancelled()) { - return; - } + final int pos = evt.getCaretOffset(); + if (pos == -1 || cancel.isCancelled()) { + return; + } - HintsProvider provider = language.getHintsProvider(); - if (provider == null || isCancelled()) { - return; - } - GsfHintsManager manager = language.getHintsManager(); - if (manager == null || isCancelled()) { - return; - } - RuleContext ruleContext = manager.createRuleContext((ParserResult) r, language, pos, -1, -1); - if (ruleContext == null || isCancelled()) { - return; - } - List descriptions = new ArrayList(); - List hints = new ArrayList(); + try { + ParserManager.parse(Collections.singleton(result.getSnapshot().getSource()), new UserTask() { + public @Override void run(ResultIterator resultIterator) throws Exception { + Parser.Result r = resultIterator.getParserResult(pos); + if(!(r instanceof ParserResult)) { + return ; + } + Language language = LanguageRegistry.getInstance().getLanguageByMimeType(r.getSnapshot().getMimeType()); + if (language == null || cancel.isCancelled()) { + return; + } - OffsetRange linerange = findLineBoundaries(resultIterator.getSnapshot().getText(), pos); - try { - synchronized (this) { - pendingProvider = provider; - if (isCancelled()) { + HintsProvider provider = language.getHintsProvider(); + if (provider == null || cancel.isCancelled()) { + return; + } + GsfHintsManager manager = language.getHintsManager(); + if (manager == null || cancel.isCancelled()) { + return; + } + RuleContext ruleContext = manager.createRuleContext((ParserResult) r, language, pos, -1, -1); + if (ruleContext == null || cancel.isCancelled()) { + return; + } + List descriptions = new ArrayList(); + List hints = new ArrayList(); + + OffsetRange linerange = findLineBoundaries(resultIterator.getSnapshot().getText(), pos); + try { + synchronized (this) { + pendingProvider = provider; + if (cancel.isCancelled()) { + return; + } + } + provider.computeSuggestions(manager, ruleContext, hints, pos); + } finally { + pendingProvider = null; + } + + for (int i = 0; i < hints.size(); i++) { + Hint hint = hints.get(i); + if (cancel.isCancelled()) { return; } + // #224654 - suggestions may be returned for text unrelated to caret position + if (linerange != OffsetRange.NONE && !overlaps(linerange, hint.getRange())) { + continue; + } + ErrorDescription desc = manager.createDescription(hint, ruleContext, false, i == hints.size()-1); + descriptions.add(desc); } - provider.computeSuggestions(manager, ruleContext, hints, pos); - } finally { - pendingProvider = null; - } - for (int i = 0; i < hints.size(); i++) { - Hint hint = hints.get(i); - if (isCancelled()) { + if (cancel.isCancelled()) { return; } - // #224654 - suggestions may be returned for text unrelated to caret position - if (linerange != OffsetRange.NONE && !overlaps(linerange, hint.getRange())) { - continue; - } - ErrorDescription desc = manager.createDescription(hint, ruleContext, false, i == hints.size()-1); - descriptions.add(desc); + + HintsController.setErrors(r.getSnapshot().getSource().getFileObject(), SuggestionsTask.class.getName(), descriptions); } - - if (isCancelled()) { - return; - } - - HintsController.setErrors(r.getSnapshot().getSource().getFileObject(), SuggestionsTask.class.getName(), descriptions); - } - }); - } catch (ParseException e) { - LOG.log(Level.WARNING, null, e); + }); + } catch (ParseException e) { + LOG.log(Level.WARNING, null, e); + } + } finally { + SpiSupportAccessor.getInstance().removeCancelSupport(cancel); } } @@ -215,20 +221,9 @@ } public @Override void cancel() { - synchronized (this) { - cancelled = true; - } - HintsProvider p = pendingProvider; + final HintsProvider p = pendingProvider; if (p != null) { p.cancel(); } } - - private synchronized void resume() { - cancelled = false; - } - - private synchronized boolean isCancelled() { - return cancelled; - } } --- a/csl.api/src/org/netbeans/modules/csl/navigation/BreadCrumbsTask.java +++ a/csl.api/src/org/netbeans/modules/csl/navigation/BreadCrumbsTask.java @@ -80,6 +80,9 @@ */ public class BreadCrumbsTask extends ElementScanningTask { + public BreadCrumbsTask() { + } + private static final RequestProcessor WORKER = new RequestProcessor(BreadCrumbsTask.class.getName(), 1, false, false); @Override @@ -95,36 +98,42 @@ private final AtomicLong requestId = new AtomicLong(); @Override - public void run(ParserResult result, SchedulerEvent event) { - final long id = requestId.incrementAndGet(); - - final Document doc = result.getSnapshot().getSource().getDocument(false); - - if (doc == null || !BreadcrumbsController.areBreadCrumsEnabled(doc)) return ; - - final int caret; - - if (event instanceof CursorMovedSchedulerEvent) { - caret = ((CursorMovedSchedulerEvent) event).getCaretOffset(); - } else { - //XXX: outside AWT! - JTextComponent c = EditorRegistry.focusedComponent(); - - if (c != null && c.getDocument() == doc) - caret = c.getCaretPosition(); - else - caret = (-1); - } - - if (caret == (-1)) return ; - - final StructureItem structureRoot = computeStructureRoot(result.getSnapshot().getSource()); - - if (structureRoot == null) return ; - - WORKER.post(new Runnable() { - @Override public void run() { - selectNode(doc, structureRoot, id, caret); + public void run(final ParserResult result, final SchedulerEvent event) { + runWithCancelService(new Runnable() { + @Override + public void run() { + resume(); + final long id = requestId.incrementAndGet(); + + final Document doc = result.getSnapshot().getSource().getDocument(false); + + if (doc == null || !BreadcrumbsController.areBreadCrumsEnabled(doc)) return ; + + final int caret; + + if (event instanceof CursorMovedSchedulerEvent) { + caret = ((CursorMovedSchedulerEvent) event).getCaretOffset(); + } else { + //XXX: outside AWT! + JTextComponent c = EditorRegistry.focusedComponent(); + + if (c != null && c.getDocument() == doc) + caret = c.getCaretPosition(); + else + caret = (-1); + } + + if (caret == (-1)) return ; + + final StructureItem structureRoot = computeStructureRoot(result.getSnapshot().getSource()); + + if (structureRoot == null) return ; + + WORKER.post(new Runnable() { + @Override public void run() { + selectNode(doc, structureRoot, id, caret); + } + }); } }); } --- a/csl.api/src/org/netbeans/modules/csl/navigation/CaretListeningTask.java +++ a/csl.api/src/org/netbeans/modules/csl/navigation/CaretListeningTask.java @@ -44,8 +44,10 @@ package org.netbeans.modules.csl.navigation; +import org.netbeans.modules.csl.core.SpiSupportAccessor; import org.netbeans.modules.csl.spi.ParserResult; import org.netbeans.modules.parsing.spi.*; +import org.netbeans.modules.parsing.spi.support.CancelSupport; /** * This file is originally from Retouche, the Java Support @@ -56,43 +58,35 @@ * This task is called every time the caret position changes in a GSF editor. * It delegates to the navigator to show the current selection. */ -public class CaretListeningTask extends IndexingAwareParserResultTask { +public final class CaretListeningTask extends IndexingAwareParserResultTask { - private boolean canceled; + private final CancelSupport cancel = CancelSupport.create(this); CaretListeningTask() { super(TaskIndexingMode.ALLOWED_DURING_SCAN); } public @Override void run(ParserResult result, SchedulerEvent event) { - resume(); - + boolean navigatorShouldUpdate = ClassMemberPanel.getInstance() != null; // XXX set by navigator visible - - if (isCancelled() || (!navigatorShouldUpdate) || !(event instanceof CursorMovedSchedulerEvent)) { + if (cancel.isCancelled() || (!navigatorShouldUpdate) || !(event instanceof CursorMovedSchedulerEvent)) { return; } - - int offset = ((CursorMovedSchedulerEvent) event).getCaretOffset(); - if (offset != -1) { - ClassMemberPanel.getInstance().selectElement(result, offset); + + SpiSupportAccessor.getInstance().setCancelSupport(cancel); + try { + int offset = ((CursorMovedSchedulerEvent) event).getCaretOffset(); + if (offset != -1) { + ClassMemberPanel.getInstance().selectElement(result, offset); + } + } finally { + SpiSupportAccessor.getInstance().removeCancelSupport(cancel); } } - /** - * After this method is called the task if running should exit the run - * method immediately. - */ + + @Override public final synchronized void cancel() { - canceled = true; - } - - protected final synchronized boolean isCancelled() { - return canceled; - } - - protected final synchronized void resume() { - canceled = false; } public @Override int getPriority() { --- a/csl.api/src/org/netbeans/modules/csl/navigation/ClassMemberNavigatorSourceFactory.java +++ a/csl.api/src/org/netbeans/modules/csl/navigation/ClassMemberNavigatorSourceFactory.java @@ -48,12 +48,14 @@ import java.util.Collections; import org.netbeans.modules.csl.core.AbstractTaskFactory; import org.netbeans.modules.csl.core.Language; +import org.netbeans.modules.csl.core.SpiSupportAccessor; import org.netbeans.modules.parsing.api.Snapshot; import org.netbeans.modules.parsing.spi.Scheduler; import org.netbeans.modules.parsing.spi.SchedulerTask; import org.openide.util.Lookup; import org.netbeans.modules.csl.spi.ParserResult; import org.netbeans.modules.parsing.spi.*; +import org.netbeans.modules.parsing.spi.support.CancelSupport; /** * This file is originally from Retouche, the Java Support @@ -108,6 +110,7 @@ } private final class ProxyElementScanningTask extends IndexingAwareParserResultTask { + private final CancelSupport cancel = CancelSupport.create(this); private ElementScanningTask task = null; private Class clazz; @@ -126,16 +129,22 @@ } public @Override void cancel() { - ElementScanningTask t = getTask(); + final ElementScanningTask t = getTask(); if (t != null) { t.cancel(); } } - public @Override void run(ParserResult result, SchedulerEvent event) { - ElementScanningTask t = getTask(); - if (t != null) { - t.run(result, event); + @Override + public void run(ParserResult result, SchedulerEvent event) { + SpiSupportAccessor.getInstance().setCancelSupport(cancel); + try { + final ElementScanningTask t = getTask(); + if (t != null) { + t.run(result, event); + } + } finally { + SpiSupportAccessor.getInstance().removeCancelSupport(cancel); } } --- a/csl.api/src/org/netbeans/modules/csl/navigation/ClassMemberPanelUI.java +++ a/csl.api/src/org/netbeans/modules/csl/navigation/ClassMemberPanelUI.java @@ -220,17 +220,21 @@ public @Override Class getSchedulerClass() { return CSLNavigatorScheduler.class; } - @Override public void run(ParserResult result, SchedulerEvent event) { - resume(); - - StructureItem root = computeStructureRoot(result.getSnapshot().getSource()); - FileObject file = result.getSnapshot().getSource().getFileObject(); + @Override public void run(final ParserResult result, final SchedulerEvent event) { + runWithCancelService(new Runnable() { + @Override + public void run() { + resume(); + StructureItem root = computeStructureRoot(result.getSnapshot().getSource()); + FileObject file = result.getSnapshot().getSource().getFileObject(); - if (root != null && file != null) { - Document doc = result.getSnapshot().getSource().getDocument(false); - BaseDocument bd = doc instanceof BaseDocument ? (BaseDocument)doc : null; - refresh(root, file, bd); - } + if (root != null && file != null) { + Document doc = result.getSnapshot().getSource().getDocument(false); + BaseDocument bd = doc instanceof BaseDocument ? (BaseDocument)doc : null; + refresh(root, file, bd); + } + } + }); } }; --- a/csl.api/src/org/netbeans/modules/csl/navigation/ElementScanningTask.java +++ a/csl.api/src/org/netbeans/modules/csl/navigation/ElementScanningTask.java @@ -56,6 +56,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.ImageIcon; +import org.netbeans.api.annotations.common.NonNull; import org.netbeans.api.editor.mimelookup.MimePath; import org.netbeans.modules.csl.api.StructureScanner; import org.netbeans.modules.csl.api.ElementHandle; @@ -65,6 +66,7 @@ import org.netbeans.modules.csl.core.Language; import org.netbeans.modules.csl.core.LanguageRegistry; import org.netbeans.modules.csl.api.HtmlFormatter; +import org.netbeans.modules.csl.core.SpiSupportAccessor; import org.netbeans.modules.csl.navigation.ElementNode.Description; import org.netbeans.modules.csl.spi.ParserResult; import org.netbeans.modules.parsing.api.Embedding; @@ -75,6 +77,7 @@ import org.netbeans.modules.parsing.api.UserTask; import org.netbeans.modules.parsing.spi.*; import org.netbeans.modules.parsing.spi.Parser.Result; +import org.netbeans.modules.parsing.spi.support.CancelSupport; import org.openide.filesystems.FileObject; import org.openide.util.ImageUtilities; import org.openide.util.RequestProcessor; @@ -94,14 +97,14 @@ public abstract class ElementScanningTask extends IndexingAwareParserResultTask { private static final Logger LOG = Logger.getLogger(ElementScanningTask.class.getName()); - - private boolean canceled; + + private final CancelSupport cs = CancelSupport.create(this); + private volatile boolean canceled; /** * Reference to the last result of parsing processed into structure. */ - private static final Map> lastResults = - new WeakHashMap>(); + private static final Map> lastResults = new WeakHashMap<>(); /** * Cache the parser result and the resulting structure. @@ -249,18 +252,27 @@ return new RootStructureItem(items); } - public @Override synchronized void cancel() { + @Override + public void cancel() { canceled = true; } - public synchronized void resume() { + protected final void resume() { canceled = false; } - public synchronized boolean isCancelled() { + protected final boolean isCancelled() { return canceled; } - + + protected final void runWithCancelService(@NonNull final Runnable r) { + SpiSupportAccessor.getInstance().setCancelSupport(cs); + try { + + } finally { + SpiSupportAccessor.getInstance().removeCancelSupport(cs); + } + } private static final class RootStructureItem implements StructureItem { private final List items; --- a/csl.api/src/org/netbeans/modules/csl/spi/support/CancelSupport.java +++ a/csl.api/src/org/netbeans/modules/csl/spi/support/CancelSupport.java @@ -0,0 +1,111 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2015 Sun Microsystems, Inc. + */ +package org.netbeans.modules.csl.spi.support; + +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.modules.csl.core.SpiSupportAccessor; +import org.netbeans.modules.parsing.spi.SchedulerTask; +import org.openide.util.Parameters; + +/** + * Provides a thread safe testing of the {@link SchedulerTask} canceling. + * Provides a thread safe testing of the {@link SchedulerTask} canceling for CSL + * services which are not implemented using {@link SchedulerTask}. For {@link SchedulerTask} + * subclasses use parsing api {@link org.netbeans.modules.parsing.spi.support.CancelSupport} + * @author Tomas Zezula + * @since 2.50 + */ +public final class CancelSupport { + + private static final CancelSupport INSTANCE = new CancelSupport(); + + static { + SpiSupportAccessor.setInstance(new SpiSupportAccessorImpl()); + } + + private final ThreadLocal selfSpi; + + private CancelSupport() { + this.selfSpi = new ThreadLocal<>(); + } + + /** + * Returns true if the task is canceled. + * @return true when task is canceled + */ + public boolean isCancelled() { + final org.netbeans.modules.parsing.spi.support.CancelSupport spi = selfSpi.get(); + return spi == null ? + false : + spi.isCancelled(); + } + + /** + * Returns the {@link CancelSupport} instance. + * @return the {@link CancelSupport} instance. + */ + @NonNull + public static CancelSupport getDefault() { + return INSTANCE; + } + + private static final class SpiSupportAccessorImpl extends SpiSupportAccessor { + + @Override + public void setCancelSupport(@NonNull final org.netbeans.modules.parsing.spi.support.CancelSupport cancelSupport) { + Parameters.notNull("cancelSupport", cancelSupport); //NOI18N + final CancelSupport cs = getDefault(); + if (cs.selfSpi.get() == null) { + cs.selfSpi.set(cancelSupport); + } + } + + @Override + public void removeCancelSupport(@NonNull final org.netbeans.modules.parsing.spi.support.CancelSupport cancelSupport) { + Parameters.notNull("cancelSupport", cancelSupport); //NOI18N + final CancelSupport cs = getDefault(); + if (cs.selfSpi.get() == cancelSupport) { + cs.selfSpi.remove(); + } + } + } +}