Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 6f23d995388bf68dd0296859e2a61852d056e4b1 (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
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
/*******************************************************************************
 * Copyright (c) 2010, 2011 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.equinox.bidi.custom;

import org.eclipse.equinox.bidi.advanced.IStructuredTextExpert;
import org.eclipse.equinox.bidi.advanced.StructuredTextEnvironment;
import org.eclipse.equinox.bidi.internal.StructuredTextImpl;

/**
 *  Generic handler to be used as superclass (base class)
 *  for specific structured text handlers.
 *  <p>
 *  Here are some guidelines about how to write structured text
 *  handlers.
 *  <ul>
 *    <li>Handler instances may be accessed simultaneously by
 *        several threads. They should have no instance variables.</li>
 *    <li>This class provides common logic in code which can be invoked
 *        by any {@link StructuredTextTypeHandler structured text handler}. 
 *        This common logic uses handler methods to query the
 *        characteristics of the specific handler:
 *        <ul>
 *          <li>the separators which separate the structured text into
 *              tokens. See {@link #getSeparators}.</li>
 *          <li>the direction which governs the display of tokens
 *              one after the other. See {@link #getDirection}.</li>
 *          <li>the number of special cases which need to be handled by
 *              code specific to that handler.
 *              See {@link #getSpecialsCount}.</li>
 *        </ul></li>
 *    <li>Before starting deeper analysis of the submitted text, the common
 *        logic gives to the handler a chance to shorten the process by
 *        invoking its {@link #skipProcessing} method.</li>
 *    <li>The common logic then analyzes the text to segment it into tokens
 *        according to the appearance of separators (as retrieved using
 *        {@link #getSeparators}).</li>
 *    <li>If the handler indicated a positive number of special cases as
 *        return value from its {@link #getSpecialsCount}
 *        method, the common logic will repeatedly invoke the handler's
 *        {@link #indexOfSpecial} method to let it signal the
 *        presence of special strings which may further delimit the source text.</li>
 *    <li>When such a special case is signaled by the handler, the common
 *        logic will call the handler's {@link #processSpecial}
 *        method to give it the opportunity to handle it as needed. Typical
 *        actions that the handler may perform are to add directional marks
 *        unconditionally (by calling {@link #insertMark} or
 *        conditionally (by calling {@link #processSeparator}).</li>
 *  </ul>
 */
public class StructuredTextTypeHandler {

	final private String separators;

	/**
	 * Creates a new instance of the StructuredTextTypeHandler class.
	 */
	public StructuredTextTypeHandler() {
		separators = ""; //$NON-NLS-1$
	}

	/**
	 * Creates a new instance of the StructuredTextTypeHandler class.
	 * @param separators string consisting of characters that split the text into fragments.
	 */
	public StructuredTextTypeHandler(String separators) {
		this.separators = separators;
	}

	/**
	 * Locates occurrences of special strings within a structured text
	 * and returns their indexes one after the other in successive calls.
	 * <p>
	 * This method is called repeatedly if the number of special cases 
	 * returned by {@link #getSpecialsCount} is greater than zero.
	 * </p><p>
	 * A handler handling special cases must override this method.
	 * </p>
	 * @param  expert IStructuredTextExpert instance through which this handler
	 *         is invoked. The handler can use IStructuredTextExpert methods to
	 *         query items stored in the expert instance, like the current
	 *         {@link StructuredTextEnvironment environment}.      
	 * @param  text the structured text string before
	 *         addition of any directional formatting characters.
	 * @param  charTypes an object whose methods can be useful to the 
	 *         handler.
	 * @param  offsets an object whose methods can be useful to the 
	 *         handler.
	 * @param  caseNumber number of the special case to locate.
	 *         This number varies from 1 to the number of special cases
	 *         returned by {@link #getSpecialsCount}
	 *         for this handler.
	 *         The meaning of this number is internal to the class
	 *         implementing <code>indexOfSpecial</code>.
	 * @param  fromIndex the index within <code>text</code> to start
	 *         the search from.
	 *         
	 * @return the position where the start of the special case
	 *         corresponding to <code>caseNumber</code> was located.
	 *         The method must return the first occurrence of whatever
	 *         identifies the start of the special case starting from
	 *         <code>fromIndex</code>. The method does not have to check if
	 *         this occurrence appears within the scope of another special
	 *         case (e.g. a comment starting delimiter within the scope of
	 *         a literal or vice-versa).
	 *         <br>If no occurrence is found, the method must return -1.
	 *
	 * @throws IllegalStateException If not overridden, this method throws an
	 * <code>IllegalStateException</code>. This is appropriate behavior
	 * (and does not need to be overridden) for handlers whose
	 * number of special cases is zero, which means that
	 * <code>indexOfSpecial</code> should never be called for them.
	 */
	public int indexOfSpecial(IStructuredTextExpert expert, String text, StructuredTextCharTypes charTypes, StructuredTextOffsets offsets, int caseNumber, int fromIndex) {
		// This method must be overridden by all subclasses with special cases.
		throw new IllegalStateException("A handler with specialsCount > 0 must have an indexOfSpecial() method."); //$NON-NLS-1$
	}

	/**
	 * Handles special cases specific to this handler.
	 * It is called when a special case occurrence 
	 * is located by {@link #indexOfSpecial}.
	 * <p>
	 * If a special processing cannot be completed within a current call to
	 * <code>processSpecial</code> (for instance, a comment has been started
	 * in the current line but its end appears in a following line),
	 * <code>processSpecial</code> should specify a final state by calling
	 * {@link IStructuredTextExpert#setState(Object)}.
	 * The meaning of this state is internal to the handler.
	 * <p>
	 * On a later call, <code>processSpecial</code> will be called with
	 * <code>-1</code> for parameter <code>separLocation</code>. It should then
	 * retrieve the last state by calling {@link IStructuredTextExpert#getState()} and
	 * clear the state by calling {@link IStructuredTextExpert#clearState()}. After that, 
	 * it should perform whatever initializations are required
	 * depending on the last state.
	 * </p><p>
	 * A handler handling special cases (with a number of
	 * special cases greater than zero) must override this method.
	 * </p>
	 * @param  expert IStructuredTextExpert instance through which this handler
	 *         is invoked. The handler can use IStructuredTextExpert methods to
	 *         query items stored in the expert instance, like the current
	 *         {@link StructuredTextEnvironment environment}.      
	 * @param  text the structured text string before
	 *         addition of any directional formatting characters.
	 * @param  charTypes an object whose methods can be useful to the 
	 *         handler.
	 * @param  offsets an object whose methods can be useful to the 
	 *         handler.
	 * @param  caseNumber number of the special case to handle.
	 * @param  separLocation the position returned by
	 *         {@link #indexOfSpecial}. After calls to
	 *         {@link IStructuredTextExpert#leanToFullText} and other
	 *         methods of {@link IStructuredTextExpert} which set a non-null
	 *         final state, <code>processSpecial</code> is
	 *         called when initializing the processing with value of
	 *         <code>separLocation</code> equal to <code>-1</code>.
	 *
	 * @return the position after the scope of the special case ends.
	 *         For instance, the position after the end of a comment,
	 *         the position after the end of a literal.
	 *         <br>A value greater or equal to the length of <code>text</code>
	 *         means that there is no further occurrence of this case in the
	 *         current structured text.
	 *
	 * @throws IllegalStateException If not overridden, this method throws an
	 * <code>IllegalStateException</code>. This is appropriate behavior
	 * (and does not need to be overridden) for handlers whose
	 * number of special cases is zero, which means that
	 * <code>processSpecial</code> should never be called for them.
	 */
	public int processSpecial(IStructuredTextExpert expert, String text, StructuredTextCharTypes charTypes, StructuredTextOffsets offsets, int caseNumber, int separLocation) {
		// This method must be overridden by all subclasses with any special case.
		throw new IllegalStateException("A handler with specialsCount > 0 must have a processSpecial() method."); //$NON-NLS-1$
	}

	/**
	 * Specifies that a mark character must be added before the character
	 * at the specified position of the <i>lean</i> text when generating the
	 * <i>full</i> text. This method can be called from within 
	 * {@link #indexOfSpecial} or
	 * {@link #processSpecial} in extensions of 
	 * <code>StructuredTextTypeHandler</code>.
	 * The mark character will be LRM for structured text
	 * with a LTR base direction, and RLM for structured text with RTL
	 * base direction. The mark character is not added physically by this
	 * method, but its position is noted and will be used when generating
	 * the <i>full</i> text.
	 *
	 * @param  text is the structured text string received as
	 *         parameter to <code>indexOfSpecial</code> or
	 *         <code>processSpecial</code>.
	 * @param  charTypes is a parameter received by <code>indexOfSpecial</code>
	 *         or <code>processSpecial</code>.
	 * @param  offsets is a parameter received by <code>indexOfSpecial</code>
	 *         or <code>processSpecial</code>.
	 * @param  offset position of the character in the <i>lean</i> text.
	 *         It must be a non-negative number smaller than the length
	 *         of the <i>lean</i> text.
	 *         For the benefit of efficiency, it is better to insert
	 *         multiple marks in ascending order of the offsets.
	 */
	public static final void insertMark(String text, StructuredTextCharTypes charTypes, StructuredTextOffsets offsets, int offset) {
		offsets.insertOffset(charTypes, offset);
	}

	/**
	 * Adds a directional mark before a separator if needed for correct
	 * display, depending on the base direction of the text and on the
	 * class of the characters in the <i>lean</i> text preceding and 
	 * following the separator itself. This method
	 * can be called from within {@link #indexOfSpecial} or
	 * {@link #processSpecial} in extensions of 
	 * <code>StructuredTextTypeHandler</code>. 
	 * <p>
	 * The logic implemented in this method considers the text before
	 * <code>separLocation</code> and the text following it. If, and only if,
	 * a directional mark is needed to insure that the two parts of text
	 * will be laid out according to the base direction, a mark will be
	 * added when generating the <i>full</i> text.
	 * </p>
	 * @param  text is the structured text string received as
	 *         parameter to <code>indexOfSpecial</code> or
	 *         <code>processSpecial</code>.
	 * @param  charTypes is a parameter received by <code>indexOfSpecial</code>
	 *         or <code>processSpecial</code>.
	 * @param  offsets is a parameter received by <code>indexOfSpecial</code>
	 *         or <code>processSpecial</code>.
	 * @param  separLocation offset of the separator in the <i>lean</i> text.
	 *         It must be a non-negative number smaller than the length
	 *         of the <i>lean</i> text.
	 */
	public static final void processSeparator(String text, StructuredTextCharTypes charTypes, StructuredTextOffsets offsets, int separLocation) {
		StructuredTextImpl.processSeparator(text, charTypes, offsets, separLocation);
	}

	/**
	 * Indicates the separators to use for the current handler.
	 * This method is invoked before starting the processing.
	 * <p>
	 * If no separators are specified, this method returns an empty string.
	 * </p>
	 * @param  expert IStructuredTextExpert instance through which this handler
	 *         is invoked. The handler can use IStructuredTextExpert methods to
	 *         query items stored in the expert instance, like the current
	 *         {@link StructuredTextEnvironment environment}.      
	 *
	 * @return a string grouping one-character separators which separate
	 *         the structured text into tokens.
	 */
	public String getSeparators(IStructuredTextExpert expert) {
		return separators;
	}

	/**
	 * Indicates the base text direction appropriate for an instance of
	 * structured text. This method is invoked before starting the processing.
	 * <p>
	 * If not overridden, this method returns {@link IStructuredTextExpert#DIR_LTR DIR_LTR}.
	 * </p>
	 * @param  expert IStructuredTextExpert instance through which this handler
	 *         is invoked. The handler can use IStructuredTextExpert methods to
	 *         query items stored in the expert instance, like the current
	 *         {@link StructuredTextEnvironment environment}.      
	 * @param  text the structured text string to process.
	 *
	 * @return the base direction of the structured text. This direction
	 *         may not be the same depending on the environment and on
	 *         whether the structured text contains Arabic or Hebrew
	 *         letters.<br>
	 *         The value returned is either
	 *         {@link IStructuredTextExpert#DIR_LTR DIR_LTR} or 
	 *         {@link IStructuredTextExpert#DIR_RTL DIR_RTL}.
	 */
	public int getDirection(IStructuredTextExpert expert, String text) {
		return IStructuredTextExpert.DIR_LTR;
	}

	/**
	 * Indicates the base text direction appropriate for an instance of
	 * structured text. This method is invoked before starting the processing.
	 * <p>
	 * If not overridden, this method returns {@link IStructuredTextExpert#DIR_LTR DIR_LTR}.
	 * </p>
	 * @param  expert IStructuredTextExpert instance through which this handler
	 *         is invoked. The handler can use IStructuredTextExpert methods to
	 *         query items stored in the expert instance, like the current
	 *         {@link StructuredTextEnvironment environment}.      
	 * @param  text is the structured text string to process.
	 * @param  charTypes is a parameter received by <code>indexOfSpecial</code>
	 *         or <code>processSpecial</code>.
	 *
	 * @return the base direction of the structured text. This direction
	 *         may not be the same depending on the environment and on
	 *         whether the structured text contains Arabic or Hebrew
	 *         letters.<br>
	 *         The value returned is either
	 *         {@link IStructuredTextExpert#DIR_LTR DIR_LTR} or {@link IStructuredTextExpert#DIR_RTL DIR_RTL}.
	 */
	public int getDirection(IStructuredTextExpert expert, String text, StructuredTextCharTypes charTypes) {
		return IStructuredTextExpert.DIR_LTR;
	}

	/**
	 * Indicates the number of special cases handled by the current handler.
	 * This method is invoked before starting the processing.
	 * If the number returned is zero, {@link #indexOfSpecial}
	 * and {@link #processSpecial} will not be invoked.
	 * <p>
	 * If not overridden, this method returns <code>zero</code>.
	 * </p>
	 * @param  expert IStructuredTextExpert instance through which this handler
	 *         is invoked. The handler can use IStructuredTextExpert methods to
	 *         query items stored in the expert instance, like the current
	 *         {@link StructuredTextEnvironment environment}.      
	 *
	 * @return the number of special cases for the associated handler.
	 *         Special cases exist for some types of structured text
	 *         handlers. They are implemented by overriding methods
	 *         {@link StructuredTextTypeHandler#indexOfSpecial} and
	 *         {@link StructuredTextTypeHandler#processSpecial}.
	 *         Examples of special cases are comments, literals, or
	 *         anything which is not identified by a one-character separator.
	 *
	 */
	public int getSpecialsCount(IStructuredTextExpert expert) {
		return 0;
	}

	/**
	 * Checks if there is a need for processing structured text.
	 * This method is invoked before starting the processing. If the
	 * handler returns <code>true</code>, no directional formatting
	 * characters are added to the <i>lean</i> text and the processing
	 * is shortened.
	 * <p>
	 * If not overridden, this method returns <code>false</code>.
	 * </p>
	 * @param  expert IStructuredTextExpert instance through which this handler
	 *         is invoked. The handler can use IStructuredTextExpert methods to
	 *         query items stored in the expert instance, like the current
	 *         {@link StructuredTextEnvironment environment}.      
	 * @param  text is the structured text string to process.
	 * @param  charTypes is a parameter received by <code>indexOfSpecial</code>
	 *         or <code>processSpecial</code>.
	 *
	 * @return a flag indicating if there is no need to process the structured
	 *         text to add directional formatting characters.
	 *
	 */
	public boolean skipProcessing(IStructuredTextExpert expert, String text, StructuredTextCharTypes charTypes) {
		return false;
	}

	public String toString() {
		return super.toString() + " [" + separators + "]"; //$NON-NLS-1$ //$NON-NLS-2$
	}
}

Back to the top