/*
* Copyright (c) 2012 Sam Harwell, Tunnel Vision Laboratories LLC
* All rights reserved.
*
* The source code of this document is proprietary work, and is not licensed for
* distribution. For information about licensing, contact Sam Harwell at:
* sam@tunnelvisionlabs.com
*/
package org.tvl.goworks.editor.go.parser;
import java.net.URL;
import java.util.ArrayDeque;
import java.util.Collections;
import java.util.Deque;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.antlr.netbeans.editor.parsing.SyntaxError;
import org.antlr.netbeans.editor.parsing.SyntaxErrorConvertor;
import org.antlr.netbeans.editor.text.VersionedDocument;
import org.antlr.netbeans.editor.text.VersionedDocumentUtilities;
import org.antlr.netbeans.parsing.spi.ParseContext;
import org.antlr.netbeans.parsing.spi.ParserData;
import org.antlr.netbeans.parsing.spi.ParserTaskManager;
import org.antlr.netbeans.parsing.spi.ParserTaskScheduler;
import org.antlr.v4.runtime.misc.Tuple;
import org.antlr.v4.runtime.misc.Tuple2;
import org.netbeans.api.editor.mimelookup.MimeRegistration;
import org.netbeans.modules.parsing.spi.indexing.Context;
import org.netbeans.modules.parsing.spi.indexing.CustomIndexer;
import org.netbeans.modules.parsing.spi.indexing.CustomIndexerFactory;
import org.netbeans.modules.parsing.spi.indexing.ErrorsCache;
import org.netbeans.modules.parsing.spi.indexing.Indexable;
import org.netbeans.modules.parsing.spi.indexing.PathRecognizerRegistration;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.URLMapper;
import org.openide.util.Lookup;
import org.tvl.goworks.editor.GoEditorKit;
import org.tvl.goworks.editor.go.GoParserDataDefinitions;
import org.tvl.goworks.editor.go.codemodel.FileModel;
import org.tvl.goworks.project.GoProject;
/**
*
* @author Sam Harwell
*/
public class GoCustomIndexer extends CustomIndexer {
private static final Logger LOGGER = Logger.getLogger(GoCustomIndexer.class.getName());
private static final String INDEX_NAME = "golang";
private static final int INDEX_VERSION = 1;
public GoCustomIndexer() {
}
@Override
protected void index(Iterable<? extends Indexable> files, Context context) {
ParserTaskManager taskManager = Lookup.getDefault().lookup(ParserTaskManager.class);
Deque<Tuple2<Indexable, Future<ParserData<FileModel>>>> futures = new ArrayDeque<>();
for (Indexable file : files) {
try {
if (!GoEditorKit.GO_MIME_TYPE.equals(file.getMimeType())) {
continue;
}
FileObject fileObject = URLMapper.findFileObject(file.getURL());
if (fileObject == null) {
continue;
}
VersionedDocument versionedDocument = VersionedDocumentUtilities.getVersionedDocument(fileObject);
ParseContext parseContext = new ParseContext(ParserTaskScheduler.MANUAL_TASK_SCHEDULER, versionedDocument);
Future<ParserData<FileModel>> future = taskManager.scheduleData(parseContext, GoParserDataDefinitions.FILE_MODEL);
futures.add(Tuple.create(file, future));
if (context.isCancelled()) {
break;
}
} catch (RuntimeException ex) {
LOGGER.log(Level.WARNING, "An error occurred while indexing a document.", ex);
}
}
while (!futures.isEmpty()) {
Tuple2<Indexable, Future<ParserData<FileModel>>> pair = futures.poll();
Future<ParserData<FileModel>> future = pair.getItem2();
if (future == null) {
ErrorsCache.setErrors(context.getRootURI(), pair.getItem1(), Collections.<SyntaxError>emptyList(), SyntaxErrorConvertor.INSTANCE);
continue;
}
if (context.isCancelled()) {
future.cancel(true);
continue;
}
ParserData<FileModel> parserData = null;
try {
parserData = future.get(0, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException ex) {
LOGGER.log(Level.WARNING, "An exception occurred while indexing a document.", ex);
} catch (TimeoutException ex) {
futures.add(pair);
continue;
}
Iterable<? extends SyntaxError> errors = null;
if (parserData != null) {
Future<ParserData<CompiledModel>> futureCompiledModelData = taskManager.getData(parserData.getSnapshot(), null, GoParserDataDefinitions.COMPILED_MODEL);
ParserData<CompiledModel> compiledModelData = null;
try {
compiledModelData = futureCompiledModelData != null ? futureCompiledModelData.get() : null;
} catch (InterruptedException | ExecutionException ex) {
LOGGER.log(Level.WARNING, "An exception occurred while indexing a document.", ex);
}
CompiledModel model = compiledModelData != null ? compiledModelData.getData() : null;
if (model != null) {
errors = model.getResult().getSyntaxErrors();
}
}
if (errors == null) {
errors = Collections.emptyList();
}
ErrorsCache.setErrors(context.getRootURI(), pair.getItem1(), errors, SyntaxErrorConvertor.INSTANCE);
}
}
@MimeRegistration(mimeType=GoEditorKit.GO_MIME_TYPE, service=CustomIndexerFactory.class)
@PathRecognizerRegistration(sourcePathIds={ GoProject.SOURCE }, binaryLibraryPathIds={}, libraryPathIds={ GoProject.PLATFORM }, mimeTypes={ GoEditorKit.GO_MIME_TYPE })
public static class Factory extends CustomIndexerFactory {
public Factory() {
}
@Override
public boolean scanStarted(Context context) {
return false;
}
@Override
public void scanFinished(Context context) {
}
@Override
public CustomIndexer createIndexer() {
return new GoCustomIndexer();
}
@Override
public boolean supportsEmbeddedIndexers() {
return true;
}
@Override
public void filesDeleted(Iterable<? extends Indexable> deleted, Context context) {
LOGGER.log(Level.FINE, "filesDeleted({0})", deleted);
}
@Override
public void rootsRemoved(Iterable<? extends URL> removedRoots) {
LOGGER.log(Level.FINE, "roots removed: {0}", removedRoots);
}
@Override
public void filesDirty(Iterable<? extends Indexable> dirty, Context context) {
LOGGER.log(Level.FINE, "filesDirty({0})", dirty);
}
@Override
public String getIndexerName() {
return INDEX_NAME;
}
@Override
public int getIndexVersion() {
return INDEX_VERSION;
}
}
}