Skip to content
This repository has been archived by the owner on Apr 3, 2018. It is now read-only.

Commit

Permalink
!API Added DocumentReconcileManager
Browse files Browse the repository at this point in the history
Refactor new ICommonOperation. Renamed AbstractToolManager.
  • Loading branch information
bruno-medeiros committed Apr 11, 2016
1 parent a0767c4 commit 0ac43a3
Show file tree
Hide file tree
Showing 31 changed files with 728 additions and 308 deletions.
Expand Up @@ -124,7 +124,7 @@ public CommonBuildTargetOperation getBuildOperation(BuildTarget bt, IOperationCo
return new CommonBuildTargetOperation(buildMgr, bt, opHandler, buildToolPath, buildArguments) {
@Override
protected void processBuildOutput(ExternalProcessResult processResult, IProgressMonitor pm)
throws CoreException, CommonException, OperationCancellation {
throws CommonException, OperationCancellation {
}
};
}
Expand Down
Expand Up @@ -18,16 +18,16 @@
import melnorme.utilbox.misc.SimpleLogger;
import melnorme.utilbox.ownership.LifecycleObject;

public class AbstractModelUpdateManager<KEY> extends LifecycleObject {
public class AbstractAgentManager extends LifecycleObject {

public static SimpleLogger log = init_log();
public final SimpleLogger log = init_log();

protected final ICommonExecutor executor = init_executor();

public AbstractModelUpdateManager() {
public AbstractAgentManager() {
}

protected static SimpleLogger init_log() {
protected SimpleLogger init_log() {
return new SimpleLogger(Platform.inDebugMode());
}
protected ICommonExecutor init_executor() {
Expand Down
@@ -0,0 +1,196 @@
/*******************************************************************************
* Copyright (c) 2016 Bruno Medeiros and other Contributors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package melnorme.lang.ide.core.engine;

import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;

import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.IFileBuffer;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.ISynchronizable;

import melnorme.lang.ide.core.engine.SourceModelManager.StructureInfo;
import melnorme.lang.ide.core.engine.SourceModelManager.StructureUpdateTask;
import melnorme.lang.ide.core.utils.CoreExecutors;
import melnorme.lang.ide.core.utils.DefaultBufferListener;
import melnorme.lang.ide.core.utils.ResourceUtils;
import melnorme.utilbox.concurrency.ICommonExecutor;
import melnorme.utilbox.concurrency.ResultFuture.LatchFuture;
import melnorme.utilbox.core.fntypes.CallableX;

/**
* Manager for all model reconciliations after text file buffer changes,
* whether is document modifications, or file saves.
*/
public class DocumentReconcileManager extends AbstractAgentManager {

protected final ITextFileBufferManager fbm;

public DocumentReconcileManager() {
this(FileBuffers.getTextFileBufferManager());
}

public DocumentReconcileManager(ITextFileBufferManager fbm) {
this.fbm = assertNotNull(fbm);
}

@Override
protected ICommonExecutor init_executor() {
return CoreExecutors.newExecutorTaskAgent(DocumentReconcileManager.class);
}

/* ----------------- ----------------- */

public DocumentReconcileConnection connectDocument(IDocument document, StructureInfo structureInfo) {
ITextFileBuffer textFileBuffer = ResourceUtils.getTextFileBuffer(fbm, structureInfo.getLocation());

if(textFileBuffer != null) {
return new TextReconcileConnection(document, structureInfo, textFileBuffer);
}
return new DocumentReconcileConnection(document, structureInfo);
}

public class DocumentReconcileConnection {

protected final IDocument document;
protected final StructureInfo structureInfo;

public DocumentReconcileConnection(IDocument document, StructureInfo structureInfo) {
this.document = assertNotNull(document);
this.structureInfo = assertNotNull(structureInfo);

document.addDocumentListener(docListener);
}

public void disconnect() {
document.removeDocumentListener(docListener);
}

protected final IDocumentListener docListener = new IDocumentListener() {
@Override
public void documentAboutToBeChanged(DocumentEvent event) {
}
@Override
public void documentChanged(DocumentEvent event) {
assertTrue(document == event.fDocument);
doDocumentChanged();
}
};

protected StructureUpdateTask doDocumentChanged() {
return structureInfo.queueSourceUpdateTask(document.get());
}

}

public static IProject getProject(IFileBuffer fileBuffer) {
/* TODO : improve the API to get a project, or ignore project altogheter */

IFile file= FileBuffers.getWorkspaceFileAtLocation(fileBuffer.getLocation(), true);
if (file == null) {
return null;
}

return file.getProject();
}

public class TextReconcileConnection extends DocumentReconcileConnection {

protected final IProject project; // Can be null

protected final ITextFileBuffer textFileBuffer;
protected final DirtyBufferListener fbListener;

protected LatchFuture fileSaveFuture = new LatchFuture();

public TextReconcileConnection(IDocument document, StructureInfo structureInfo, ITextFileBuffer textFileBuffer) {
super(document, structureInfo);

this.textFileBuffer = assertNotNull(textFileBuffer);

fbListener = new DirtyBufferListener();
fbm.addFileBufferListener(fbListener);

project = getProject(textFileBuffer);
}

@Override
public void disconnect() {
super.disconnect();
fbm.removeFileBufferListener(fbListener);
fileSaveFuture.cancel();
}

@Override
protected StructureUpdateTask doDocumentChanged() {
StructureUpdateTask structureUpdateTask = structureInfo.queueSourceUpdateTask(document.get());

fileSaveFuture.cancel();
fileSaveFuture = new LatchFuture();

if(project != null) {
projectReconciler.invalidateProjectModel(project, structureUpdateTask, fileSaveFuture);
}
return structureUpdateTask;
}

public class DirtyBufferListener extends DefaultBufferListener {

@Override
public void dirtyStateChanged(IFileBuffer buffer, boolean isDirty) {
if(buffer == textFileBuffer) {
if(!isDirty) {
// Mark the file save as completed
fileSaveFuture.setCompleted();
handleDocumentSaved();
}
}
}

protected void handleDocumentSaved() {
StructureUpdateTask structureUpdateTask = structureInfo.documentSaved(document);

if(structureUpdateTask != null && project != null) {
projectReconciler.invalidateProjectModel(project, structureUpdateTask, fileSaveFuture);
}
}

}

}

protected final ProjectReconcileManager projectReconciler = new ProjectReconcileManager(this.executor);

/* ----------------- ----------------- */

public static <R> R runUnderDocumentLock(IDocument doc, CallableX<R, RuntimeException> runnable) {
if(doc instanceof ISynchronizable) {
ISynchronizable synchronizable = (ISynchronizable) doc;

Object lockObject = synchronizable.getLockObject();
if(lockObject != null) {
synchronized(lockObject) {
return runnable.call();
}
}
}

return runnable.call();
}

}
Expand Up @@ -13,8 +13,6 @@
import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;

import java.util.concurrent.ExecutorService;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
Expand All @@ -32,28 +30,35 @@
import melnorme.lang.ide.core.utils.ResourceUtils;
import melnorme.lang.tooling.ast.ParserError;
import melnorme.lang.tooling.structure.SourceFileStructure;
import melnorme.utilbox.concurrency.ICommonExecutor;
import melnorme.utilbox.concurrency.OperationCancellation;
import melnorme.utilbox.misc.Location;
import melnorme.utilbox.ownership.IDisposable;

public class ProblemMarkerUpdater implements IDisposable {
public class ProblemMarkerUpdater extends AbstractAgentManager {

protected final ExecutorService problemsExecutor = CoreExecutors.newExecutorTaskAgent(getClass());
protected SourceModelManager sourceModelManager;

public ProblemMarkerUpdater() {
}

@Override
protected ICommonExecutor init_executor() {
return CoreExecutors.newExecutorTaskAgent(getClass());
}

public void install(SourceModelManager sourceModelManager) {
this.sourceModelManager = sourceModelManager;
sourceModelManager.addListener(problemUpdaterListener);
sourceModelManager.asOwner().bind(this);
IDisposable listenerRegistration = sourceModelManager.addListener(problemUpdaterListener);
asOwner().bind(listenerRegistration);

sourceModelManager.asOwner().bind(this); // Make ProblemMarkerUpdater be owned by the model manager
}

@Override
public void dispose() {
sourceModelManager.removeListener(problemUpdaterListener);
problemsExecutor.shutdownNow();
protected void dispose_post() {
super.dispose_post();
executor.shutdownNow();
}

protected final IStructureModelListener problemUpdaterListener = new IStructureModelListener() {
Expand All @@ -65,7 +70,7 @@ public void dataChanged(StructureInfo structureInfo) {

assertTrue(Job.getJobManager().currentRule() == null);

problemsExecutor.submit(new UpdateProblemMarkersTask(structureInfo));
executor.submit(new UpdateProblemMarkersTask(structureInfo));
}
};

Expand Down

0 comments on commit 0ac43a3

Please sign in to comment.