/*=============================================================================#
# Copyright (c) 2014-2016 Stephan Wahlbrink (WalWare.de) and others.
# 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:
# Stephan Wahlbrink - initial API and implementation
#=============================================================================*/
package de.walware.docmlet.wikitext.internal.core;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
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.filebuffers.LocationKind;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jface.text.AbstractDocument;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentPartitioner;
import org.eclipse.osgi.util.NLS;
import de.walware.jcommons.collections.ImCollections;
import de.walware.jcommons.collections.ImIdentityList;
import de.walware.ecommons.ltk.IModelManager;
import de.walware.ecommons.ltk.ISourceUnitManager;
import de.walware.ecommons.ltk.LTK;
import de.walware.ecommons.ltk.core.model.ISourceUnit;
import de.walware.ecommons.ltk.core.model.IWorkspaceSourceUnit;
import de.walware.docmlet.wikitext.core.WikitextCore;
import de.walware.docmlet.wikitext.core.markup.IMarkupLanguage;
import de.walware.docmlet.wikitext.core.markup.IMarkupLanguageManager1;
import de.walware.docmlet.wikitext.core.markup.IMarkupLanguageManager1.IMarkupConfigChangedListener;
import de.walware.docmlet.wikitext.core.model.WikitextModel;
import de.walware.docmlet.wikitext.core.source.IMarkupLanguagePartitioner;
import de.walware.docmlet.wikitext.core.source.MarkupLanguageDocumentSetupParticipant;
public class MarkupConfigTextFileBufferUpdater implements IMarkupConfigChangedListener {
private class UpdateRunnable implements Runnable {
private final IFile file;
private final AbstractDocument document;
private final List<String> partitionings;
private final Map<String, List<IProject>> languages;
public UpdateRunnable(final IFile file, final AbstractDocument document,
final List<String> partitionings, final Map<String, List<IProject>> languages) {
this.file= file;
this.document= document;
this.partitionings= partitionings;
this.languages= languages;
}
@Override
public void run() {
// runs in UI
for (final String partitioning : this.partitionings) {
final IDocumentPartitioner partitioner= this.document.getDocumentPartitioner(partitioning);
if (partitioner instanceof IMarkupLanguagePartitioner) {
try {
final IMarkupLanguagePartitioner markupPartitioner= (IMarkupLanguagePartitioner) partitioner;
final IMarkupLanguage currentMarkupLanguage= markupPartitioner.getMarkupLanguage();
if (this.languages != null && !this.languages.containsKey(currentMarkupLanguage.getName())) {
continue;
}
IMarkupLanguage newMarkupLanguage= null;
if (this.file != null) {
newMarkupLanguage= MarkupConfigTextFileBufferUpdater.this.markupLanguageManager.getLanguage(this.file,
currentMarkupLanguage.getName(), true );
}
else {
newMarkupLanguage= MarkupConfigTextFileBufferUpdater.this.markupLanguageManager.getLanguage(
currentMarkupLanguage.getName() );
}
if (newMarkupLanguage != null) {
markupPartitioner.setMarkupLanguage(newMarkupLanguage);
this.document.setDocumentPartitioner(partitioning, partitioner);
}
}
catch (final Exception e) {
WikitextCorePlugin.log(new Status(IStatus.ERROR, WikitextCore.PLUGIN_ID,
NLS.bind("An error occurred when trying to update the markup configuration of the open document (partitioning= {0}).", partitioning),
e ));
}
}
}
}
}
private final IMarkupLanguageManager1 markupLanguageManager;
private final ITextFileBufferManager textFileBufferManager;
// TODO lookup at runtime
private final ImIdentityList<String> markupModelTypeIds= ImCollections.newIdentityList(
WikitextModel.WIKIDOC_TYPE_ID,
"WikidocRweave" );
private final List<String> checkPartitionings= new ArrayList<>();
public MarkupConfigTextFileBufferUpdater(final IMarkupLanguageManager1 markupLanguageManager) {
this.markupLanguageManager= markupLanguageManager;
this.textFileBufferManager= FileBuffers.getTextFileBufferManager();
}
@Override
public void configChanged(final Map<String, List<IProject>> languages,
final IProgressMonitor monitor) throws CoreException {
final SubMonitor m= SubMonitor.convert(monitor, 100 + 100);
{ final SubMonitor mBuffers= m.newChild(100, 10 + 80 + 10 + 20);
IFileBuffer[] fileBuffers;
fileBuffers= this.textFileBufferManager.getFileBuffers();
m.worked(10);
checkFileBuffers(fileBuffers, languages, mBuffers.newChild(80));
fileBuffers= this.textFileBufferManager.getFileStoreFileBuffers();
m.worked(10);
checkFileBuffers(fileBuffers, languages, mBuffers.newChild(20));
}
{ // Reconcile source units
final SubMonitor mSus= m.newChild(100);
final ISourceUnitManager suManager= LTK.getSourceUnitManager();
final List<ISourceUnit> sus= suManager.getOpenSourceUnits(this.markupModelTypeIds,
LTK.EDITOR_CONTEXT);
mSus.setWorkRemaining(sus.size());
for (final ISourceUnit su : sus) {
checkEditSourceUnit(su, languages, mSus.newChild(1));
}
}
}
@Override
public void configChanged(final IFile file,
final IProgressMonitor monitor) throws CoreException {
final SubMonitor m= SubMonitor.convert(monitor, 100 + 100);
{ // Update document
final SubMonitor mFileBuffers= m.newChild(100);
final ITextFileBuffer fileBuffer= this.textFileBufferManager.getTextFileBuffer(
file.getFullPath(), LocationKind.IFILE );
if (fileBuffer != null) {
checkFileBuffer(fileBuffer, file, null);
}
}
{ // Reconcile source units
final SubMonitor mSus= m.newChild(100);
final ISourceUnitManager suManager= LTK.getSourceUnitManager();
final List<ISourceUnit> sus= suManager.getOpenSourceUnits(this.markupModelTypeIds,
LTK.EDITOR_CONTEXT, file );
mSus.setWorkRemaining(sus.size());
for (final ISourceUnit su : sus) {
checkEditSourceUnit(su, null, mSus.newChild(1));
}
}
}
private AbstractDocument getDocument(final ITextFileBuffer fileBuffer) {
final IDocument document= fileBuffer.getDocument();
if (document instanceof AbstractDocument) {
return (AbstractDocument) document;
}
else {
return null;
}
}
private void checkFileBuffers(final IFileBuffer[] fileBuffers,
final Map<String, List<IProject>> languages, final SubMonitor m) {
// Update documents
final SubMonitor mFileBuffers= m.newChild(100);
for (int i= 0; i < fileBuffers.length; i++) {
mFileBuffers.setWorkRemaining(fileBuffers.length - i);
if (fileBuffers[i] instanceof ITextFileBuffer) {
checkFileBuffer((ITextFileBuffer) fileBuffers[i], null, languages);
}
}
}
private void checkFileBuffer(final ITextFileBuffer fileBuffer, IFile file,
final Map<String, List<IProject>> languages) {
final AbstractDocument document= getDocument(fileBuffer);
if (document == null) {
return;
}
this.checkPartitionings.clear();
final String[] partitionings= document.getPartitionings();
for (int i= 0; i < partitionings.length; i++) {
if (document.getDocumentPartitioner(partitionings[i]) instanceof IMarkupLanguagePartitioner) {
this.checkPartitionings.add(partitionings[i]);
}
}
if (this.checkPartitionings.isEmpty()) {
return;
}
if (file == null && fileBuffer.getLocation() != null) {
file= FileBuffers.getWorkspaceFileAtLocation(fileBuffer.getLocation(), true);
}
final UpdateRunnable runnable= new UpdateRunnable(file, document,
ImCollections.toList(this.checkPartitionings), languages );
this.textFileBufferManager.execute(runnable); // async
}
private void checkEditSourceUnit(final ISourceUnit su,
final Map<String, List<IProject>> languages,
final SubMonitor m) {
if (su.isConnected()) {
su.connect(m);
try {
if (su.getModelInfo(null, 0, m) == null) {
return;
}
final AbstractDocument document= su.getDocument(m);
final IMarkupLanguage currentMarkupLanguage= MarkupLanguageDocumentSetupParticipant
.getMarkupLanguage(document, su.getDocumentContentInfo().getPartitioning());
if (currentMarkupLanguage != null && languages != null) {
final List<IProject> projects= languages.get(currentMarkupLanguage.getName());
if (projects == null) {
return;
}
if (!projects.isEmpty() && su instanceof IWorkspaceSourceUnit
&& !projects.contains(((IWorkspaceSourceUnit) su).getResource().getProject())) {
return;
}
}
su.getModelInfo(null, IModelManager.REFRESH | IModelManager.RECONCILE, m);
}
finally {
su.disconnect(m);
}
}
}
}