Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: f79906ab62947ed7d33db68e0a700c733ab2596c (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
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
/*******************************************************************************
 * Copyright (c) 2010, 2011 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.equinox.bidi.custom;

import org.eclipse.equinox.bidi.STextDirection;
import org.eclipse.equinox.bidi.advanced.ISTextExpert;
import org.eclipse.equinox.bidi.advanced.STextEnvironment;
import org.eclipse.equinox.bidi.internal.STextImpl;

/**
 *  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>The 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 getSeparators}.</li>
 *          <li>the direction which governs the display of tokens
 *              one after the other. See {@link #getDirection getDirection}.</li>
 *          <li>the number of special cases which need to be handled by
 *              code specific to that handler.
 *              See {@link #getSpecialsCount 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 processus by
 *        invoking its {@link #skipProcessing 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 getSeparators}).</li>
 *    <li>If the handler indicated a positive number of special cases as
 *        return value from its {@link #getSpecialsCount getSpecialsCount}
 *        method, the common logic will repeatedly invoke the handler's
 *        {@link #indexOfSpecial 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 signalled by the handler, the common
 *        logic will call the handler's {@link #processSpecial processSpecial}
 *        method to give it the opportunity to handle it as needed. Typical
 *        actions that the handler may perform are to add directional marks
 *        inconditionally (by calling {@link #insertMark insertMark} or
 *        conditionally (by calling {@link #processSeparator processSeparator}).</li>
 *  </ul>
 *
 * @author Matitiahu Allouche
 */
public class STextTypeHandler {

	final private String separators;

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

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

	/**
	 * Locate occurrences of special strings within a structured text
	 * and return 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  environment the current environment, which may affect the behavior of
	 *         the handler. This parameter may be specified as
	 *         <code>null</code>, in which case the
	 *         {@link STextEnvironment#DEFAULT DEFAULT}
	 *         environment should be assumed.
	 *
	 * @param  text is the structured text string before
	 *         addition of any directional formatting characters.
	 *
	 * @param  charTypes is a parameter received by <code>indexOfSpecial</code>
	 *         uniquely to be used as argument for calls to methods which
	 *         need it.
	 *
	 * @param  offsets is a parameter received by <code>indexOfSpecial</code>
	 *         uniquely to be used as argument for calls to methods which
	 *         need it.
	 *
	 * @param  caseNumber number of the special case to locate.
	 *         This number varies from 1 to the number of special cases
	 *         returned by {@link #getSpecialsCount 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(STextEnvironment environment, String text, STextCharTypes charTypes, STextOffsets 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$
	}

	/**
	 * This method 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
	 * putting its value in the first element of the <code>state</code>
	 * parameter.
	 * The meaning of this state is internal to the handler.
	 * On a later call, <code>processSpecial</code> will be called with that value 
	 * for parameter <code>caseNumber</code> and <code>-1</code> for parameter 
	 * <code>separLocation</code> and should perform whatever initializations are required
	 * depending on the state.
	 * </p><p>
	 * A handler handling special cases (with a number of
	 * special cases greater than zero) must override this method.
	 * </p>
	 * @param  environment the current environment, which may affect the behavior of
	 *         the handler. This parameter may be specified as
	 *         <code>null</code>, in which case the
	 *         {@link STextEnvironment#DEFAULT DEFAULT}
	 *         environment should be assumed.
	 *
	 * @param  text is the structured text string before
	 *         addition of any directional formatting characters.
	 *
	 * @param  charTypes is a parameter received by <code>processSpecial</code>
	 *         uniquely to be used as argument for calls to methods which
	 *         need it.
	 *
	 * @param  offsets is a parameter received by <code>processSpecial</code>
	 *         uniquely to be used as argument for calls to methods which
	 *         need it.
	 *
	 * @param  state is an integer array with at least one element.
	 *         If the handler needs to signal the occurrence of a
	 *         special case which must be passed to the next call to
	 *         <code>leanToFullText</code> (for instance, a comment or a
	 *         literal started but not closed in the current
	 *         <code>text</code>), it must put a value in the first element
	 *         of the <code>state</code> parameter.
	 *         This number must be >= 1 and less or equal to the number of special
	 *         cases returned by {@link #getSpecialsCount getSpecialsCount}
	 *         by this handler.
	 *         This number is passed back to the caller
	 *         and should be specified as <code>state</code> argument
	 *         in the next call to <code>leanToFullText</code> together
	 *         with the continuation text.
	 *         The meaning of this number is internal to the handler.
	 *
	 * @param  caseNumber number of the special case to handle.
	 *
	 * @param  separLocation the position returned by
	 *         {@link #indexOfSpecial indexOfSpecial}. In calls to
	 *         {@link ISTextExpert#leanToFullText leanToFullText} and other
	 *         methods of {@link ISTextExpert} specifying a  non-null
	 *         <code>state</code> parameter, <code>processSpecial</code> is
	 *         called when initializing the processing with the value of
	 *         <code>caseNumber</code> equal to the value returned in the
	 *         first element of <code>state</code> and the 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(ISTextExpert expert, STextEnvironment environment, String text, STextCharTypes charTypes, STextOffsets 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$
	}

	/**
	 * This method can be called from within {@link #indexOfSpecial} or
	 * {@link #processSpecial} in extensions of <code>STextTypeHandler</code>
	 * to specify 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. 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>, uniquely to be used as argument
	 *         for calls to <code>insertMark</code> and other methods used
	 *         by handlers.
	 *
	 * @param  offsets is a parameter received by <code>indexOfSpecial</code>
	 *         or <code>processSpecial</code>, uniquely to be used as argument
	 *         for calls to <code>insertMark</code> and other methods used
	 *         by handlers.
	 *
	 * @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, STextCharTypes charTypes, STextOffsets offsets, int offset) {
		offsets.insertOffset(charTypes, offset);
	}

	/**
	 * This method can be called from within {@link #indexOfSpecial} or
	 * {@link #processSpecial} in extensions of <code>STextTypeHandler</code> to add 
	 * 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.
	 * <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>, uniquely to be used as argument
	 *         for calls to <code>processSeparator</code> and other methods used
	 *         by handlers.
	 *
	 * @param  offsets is a parameter received by <code>indexOfSpecial</code>
	 *         or <code>processSpecial</code>, uniquely to be used as argument
	 *         for calls to <code>processSeparator</code> and other methods used
	 *         by handlers.
	 *
	 * @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, STextCharTypes charTypes, STextOffsets offsets, int separLocation) {
		STextImpl.processSeparator(text, charTypes, offsets, separLocation);
	}

	/**
	 * Indicate 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  environment the current environment, which may affect the behavior of
	 *         the handler. This parameter may be specified as
	 *         <code>null</code>, in which case the
	 *         {@link STextEnvironment#DEFAULT DEFAULT}
	 *         environment should be assumed.
	 *
	 * @return a string grouping one-character separators which separate
	 *         the structured text into tokens.
	 */
	public String getSeparators(STextEnvironment environment) {
		return separators;
	}

	/**
	 * Indicate 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 <code>DIR_LTR</code>.
	 * </p>
	 * @param  environment the current environment, which may affect the behavior of
	 *         the handler. This parameter may be specified as
	 *         <code>null</code>, in which case the
	 *         {@link STextEnvironment#DEFAULT DEFAULT}
	 *         environment should be assumed.
	 *
	 * @param  text is 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 STextDirection#DIR_LTR DIR_LTR} or {@link STextDirection#DIR_RTL DIR_RTL}.
	 */
	public int getDirection(STextEnvironment environment, String text) {
		return STextDirection.DIR_LTR;
	}

	/**
	 * Indicate 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 <code>DIR_LTR</code>.
	 * </p>
	 * @param  environment the current environment, which may affect the behavior of
	 *         the handler. This parameter may be specified as
	 *         <code>null</code>, in which case the
	 *         {@link STextEnvironment#DEFAULT DEFAULT}
	 *         environment should be assumed.
	 *
	 * @param  text is the structured text string to process.
	 *
	 * @param  charTypes is a parameter received uniquely to be used as argument
	 *         for calls to <code>getCharType</code> and other methods used
	 *         by handlers.
	 *
	 * @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 STextDirection#DIR_LTR DIR_LTR} or {@link STextDirection#DIR_RTL DIR_RTL}.
	 */
	public int getDirection(STextEnvironment environment, String text, STextCharTypes charTypes) {
		return STextDirection.DIR_LTR;
	}

	/**
	 * Indicate 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  environment the current environment, which may affect the behavior of
	 *         the handler. This parameter may be specified as
	 *         <code>null</code>, in which case the
	 *         {@link STextEnvironment#DEFAULT DEFAULT}
	 *         environment should be assumed.
	 *
	 * @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 STextTypeHandler#indexOfSpecial} and {@link STextTypeHandler#processSpecial}.
	 *         Examples of special cases are comments, literals, or
	 *         anything which is not identified by a one-character separator.
	 *
	 */
	public int getSpecialsCount(STextEnvironment environment) {
		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  environment the current environment, which may affect the behavior of
	 *         the handler. This parameter may be specified as
	 *         <code>null</code>, in which case the
	 *         {@link STextEnvironment#DEFAULT DEFAULT}
	 *         environment should be assumed.
	 *
	 * @param  text is the structured text string to process.
	 *
	 * @param  charTypes is a parameter received uniquely to be used as argument
	 *         for calls to <code>getCharType</code> and other methods used
	 *         by handlers.
	 *
	 * @return a flag indicating if there is no need to process the structured
	 *         text to add directional formatting characters.
	 *
	 */
	public boolean skipProcessing(STextEnvironment environment, String text, STextCharTypes charTypes) {
		return false;
	}

}

Back to the top