Skip to main content
summaryrefslogtreecommitdiffstats
blob: 578cee27034b003c1ecc116f0c19680f8cd692b5 (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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/*******************************************************************************
 * Copyright (c) 2000, 2009 IBM Corporation 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jface.text.rules;


import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;

import org.eclipse.core.runtime.Assert;

import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.TextAttribute;
import org.eclipse.jface.text.TextPresentation;
import org.eclipse.jface.text.presentation.IPresentationDamager;
import org.eclipse.jface.text.presentation.IPresentationRepairer;


/**
 * A standard implementation of a syntax driven presentation damager
 * and presentation repairer. It uses a token scanner to scan
 * the document and to determine its damage and new text presentation.
 * The tokens returned by the scanner are supposed to return text attributes
 * as their data.
 *
 * @see ITokenScanner
 * @since 2.0
 */
public class DefaultDamagerRepairer implements IPresentationDamager, IPresentationRepairer {


	/** The document this object works on */
	protected IDocument fDocument;
	/** The scanner it uses */
	protected ITokenScanner fScanner;
	/** The default text attribute if non is returned as data by the current token */
	protected TextAttribute fDefaultTextAttribute;

	/**
	 * Creates a damager/repairer that uses the given scanner and returns the given default
	 * text attribute if the current token does not carry a text attribute.
	 *
	 * @param scanner the token scanner to be used
	 * @param defaultTextAttribute the text attribute to be returned if non is specified by the current token,
	 * 			may not be <code>null</code>
	 *
	 * @deprecated use DefaultDamagerRepairer(ITokenScanner) instead
	 */
	@Deprecated
	public DefaultDamagerRepairer(ITokenScanner scanner, TextAttribute defaultTextAttribute) {

		Assert.isNotNull(defaultTextAttribute);

		fScanner= scanner;
		fDefaultTextAttribute= defaultTextAttribute;
	}

	/**
	 * Creates a damager/repairer that uses the given scanner. The scanner may not be <code>null</code>
	 * and is assumed to return only token that carry text attributes.
	 *
	 * @param scanner the token scanner to be used, may not be <code>null</code>
	 */
	public DefaultDamagerRepairer(ITokenScanner scanner) {

		Assert.isNotNull(scanner);

		fScanner= scanner;
		fDefaultTextAttribute= new TextAttribute(null);
	}

	/*
	 * @see IPresentationDamager#setDocument(IDocument)
	 * @see IPresentationRepairer#setDocument(IDocument)
	 */
	@Override
	public void setDocument(IDocument document) {
		fDocument= document;
	}


	//---- IPresentationDamager

	/**
	 * Returns the end offset of the line that contains the specified offset or
	 * if the offset is inside a line delimiter, the end offset of the next line.
	 *
	 * @param offset the offset whose line end offset must be computed
	 * @return the line end offset for the given offset
	 * @exception BadLocationException if offset is invalid in the current document
	 */
	protected int endOfLineOf(int offset) throws BadLocationException {

		IRegion info= fDocument.getLineInformationOfOffset(offset);
		if (offset <= info.getOffset() + info.getLength())
			return info.getOffset() + info.getLength();

		int line= fDocument.getLineOfOffset(offset);
		try {
			info= fDocument.getLineInformation(line + 1);
			return info.getOffset() + info.getLength();
		} catch (BadLocationException x) {
			return fDocument.getLength();
		}
	}

	/**
	 * {@inheritDoc}
	 * <p>
	 * This implementation damages entire lines unless clipped by the given partition.
	 * </p>
	 * 
	 * @return the full lines containing the document changes described by the document event,
	 *         clipped by the given partition. If there was a partitioning change then the whole
	 *         partition is returned.
	 */
	@Override
	public IRegion getDamageRegion(ITypedRegion partition, DocumentEvent e, boolean documentPartitioningChanged) {

		if (!documentPartitioningChanged) {
			try {

				IRegion info= fDocument.getLineInformationOfOffset(e.getOffset());
				int start= Math.max(partition.getOffset(), info.getOffset());

				int end= e.getOffset() + (e.getText() == null ? e.getLength() : e.getText().length());

				if (info.getOffset() <= end && end <= info.getOffset() + info.getLength()) {
					// optimize the case of the same line
					end= info.getOffset() + info.getLength();
				} else
					end= endOfLineOf(end);

				end= Math.min(partition.getOffset() + partition.getLength(), end);
				return new Region(start, end - start);

			} catch (BadLocationException x) {
			}
		}

		return partition;
	}

	//---- IPresentationRepairer

	@Override
	public void createPresentation(TextPresentation presentation, ITypedRegion region) {

		if (fScanner == null) {
			// will be removed if deprecated constructor will be removed
			addRange(presentation, region.getOffset(), region.getLength(), fDefaultTextAttribute);
			return;
		}

		int lastStart= region.getOffset();
		int length= 0;
		boolean firstToken= true;
		IToken lastToken= Token.UNDEFINED;
		TextAttribute lastAttribute= getTokenTextAttribute(lastToken);

		fScanner.setRange(fDocument, lastStart, region.getLength());

		while (true) {
			IToken token= fScanner.nextToken();
			if (token.isEOF())
				break;

			TextAttribute attribute= getTokenTextAttribute(token);
			if (lastAttribute != null && lastAttribute.equals(attribute)) {
				length += fScanner.getTokenLength();
				firstToken= false;
			} else {
				if (!firstToken)
					addRange(presentation, lastStart, length, lastAttribute);
				firstToken= false;
				lastToken= token;
				lastAttribute= attribute;
				lastStart= fScanner.getTokenOffset();
				length= fScanner.getTokenLength();
			}
		}

		addRange(presentation, lastStart, length, lastAttribute);
	}

	/**
	 * Returns a text attribute encoded in the given token. If the token's
	 * data is not <code>null</code> and a text attribute it is assumed that
	 * it is the encoded text attribute. It returns the default text attribute
	 * if there is no encoded text attribute found.
	 *
	 * @param token the token whose text attribute is to be determined
	 * @return the token's text attribute
	 */
	protected TextAttribute getTokenTextAttribute(IToken token) {
		Object data= token.getData();
		if (data instanceof TextAttribute)
			return (TextAttribute) data;
		return fDefaultTextAttribute;
	}

	/**
	 * Adds style information to the given text presentation.
	 *
	 * @param presentation the text presentation to be extended
	 * @param offset the offset of the range to be styled
	 * @param length the length of the range to be styled
	 * @param attr the attribute describing the style of the range to be styled
	 */
	protected void addRange(TextPresentation presentation, int offset, int length, TextAttribute attr) {
		if (attr != null) {
			int style= attr.getStyle();
			int fontStyle= style & (SWT.ITALIC | SWT.BOLD | SWT.NORMAL);
			StyleRange styleRange= new StyleRange(offset, length, attr.getForeground(), attr.getBackground(), fontStyle);
			styleRange.strikeout= (style & TextAttribute.STRIKETHROUGH) != 0;
			styleRange.underline= (style & TextAttribute.UNDERLINE) != 0;
			styleRange.font= attr.getFont();
			presentation.addStyleRange(styleRange);
		}
	}
}


Back to the top