Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 04c16d8ea1425bb7ec735bacdb02676caaaa4efd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*******************************************************************************
 * Copyright (c) 2000, 2015 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.core.filebuffers.manipulation;

import java.util.Map;

import org.eclipse.core.internal.filebuffers.FileBuffersPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;

import org.eclipse.core.filebuffers.IFileBuffer;
import org.eclipse.core.filebuffers.IFileBufferStatusCodes;
import org.eclipse.core.filebuffers.ITextFileBuffer;

import org.eclipse.text.edits.TextEdit;

import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentRewriteSession;
import org.eclipse.jface.text.DocumentRewriteSessionType;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension4;
import org.eclipse.jface.text.IDocumentPartitioner;
import org.eclipse.jface.text.TextUtilities;

/**
 * Abstraction for a file buffer operation that works on text file buffers.
 * Subclasses have to override the <code>computeTextEdits</code> method in
 * order to provide a sequence of {@link org.eclipse.text.edits.TextEdit}
 * objects.
 *
 * @since 3.1
 */
public abstract class TextFileBufferOperation implements IFileBufferOperation {


	/**
	 * Computes and returns a text edit. Subclasses have to provide that method.
	 *
	 * @param textFileBuffer the text file buffer to manipulate
	 * @param progressMonitor the progress monitor
	 * @return the text edits describing the content manipulation
	 * @throws CoreException in case the computation failed
	 * @throws OperationCanceledException in case the progress monitor has been set to canceled
	 */
	protected abstract MultiTextEditWithProgress computeTextEdit(ITextFileBuffer textFileBuffer, IProgressMonitor progressMonitor) throws CoreException, OperationCanceledException;

	/**
	 * Returns the rewrite session type that corresponds to the text edit sequence.
	 *
	 * @return the rewrite session type
	 */
	protected abstract DocumentRewriteSessionType getDocumentRewriteSessionType();


	private String fOperationName;
	private DocumentRewriteSession fDocumentRewriteSession;

	/**
	 * Creates a new operation with the given name.
	 *
	 * @param operationName the name of the operation
	 */
	protected TextFileBufferOperation(String operationName) {
		fOperationName= operationName;
	}

	@Override
	public String getOperationName() {
		return fOperationName;
	}

	@Override
	public void run(IFileBuffer fileBuffer, IProgressMonitor progressMonitor) throws CoreException, OperationCanceledException {

		if (fileBuffer instanceof ITextFileBuffer) {
			ITextFileBuffer textFileBuffer= (ITextFileBuffer) fileBuffer;
			IPath path= textFileBuffer.getLocation();
			String taskName= path == null ? getOperationName() : path.lastSegment();
			SubMonitor subMonitor= SubMonitor.convert(progressMonitor, taskName, 100);
			MultiTextEditWithProgress edit= computeTextEdit(textFileBuffer, subMonitor.split(10));
			if (edit != null) {
				Map<String, IDocumentPartitioner> stateData= startRewriteSession(textFileBuffer);
				try {
					applyTextEdit(textFileBuffer, edit, subMonitor.split(90));
				} finally {
					stopRewriteSession(textFileBuffer, stateData);
				}
			}
		}
	}

	private Map<String, IDocumentPartitioner> startRewriteSession(ITextFileBuffer fileBuffer) {
		Map<String, IDocumentPartitioner> stateData= null;

		IDocument document= fileBuffer.getDocument();
		if (document instanceof IDocumentExtension4) {
			IDocumentExtension4 extension= (IDocumentExtension4) document;
			fDocumentRewriteSession= extension.startRewriteSession(getDocumentRewriteSessionType());
		} else
			stateData= TextUtilities.removeDocumentPartitioners(document);

		return stateData;
	}

	private void stopRewriteSession(ITextFileBuffer fileBuffer, Map<String, IDocumentPartitioner> stateData) {
		IDocument document= fileBuffer.getDocument();
		if (document instanceof IDocumentExtension4) {
			IDocumentExtension4 extension= (IDocumentExtension4) document;
			extension.stopRewriteSession(fDocumentRewriteSession);
			fDocumentRewriteSession= null;
		} else if (stateData != null)
			TextUtilities.addDocumentPartitioners(document, stateData);
	}

	private void applyTextEdit(ITextFileBuffer fileBuffer, MultiTextEditWithProgress textEdit, IProgressMonitor progressMonitor) throws CoreException, OperationCanceledException {
		try {
			textEdit.apply(fileBuffer.getDocument(), TextEdit.NONE, progressMonitor);
		} catch (BadLocationException x) {
			throw new CoreException(new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, IFileBufferStatusCodes.CONTENT_CHANGE_FAILED, "", x)); //$NON-NLS-1$
		}
	}
}

Back to the top