Mercurial > projects > dwt-addons
annotate dwtx/jface/text/templates/TemplateProposal.d @ 133:7d818bd32d63
Fix ctors to this with gvim regexp
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 24 Aug 2008 01:29:22 +0200 |
parents | c4fb132a086c |
children | 51e6e63f930e |
rev | line source |
---|---|
129 | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2007 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module dwtx.jface.text.templates.TemplateProposal; | |
14 | |
131 | 15 import dwtx.jface.text.templates.SimpleTemplateVariableResolver; // packageimport |
16 import dwtx.jface.text.templates.TemplateBuffer; // packageimport | |
17 import dwtx.jface.text.templates.TemplateContext; // packageimport | |
18 import dwtx.jface.text.templates.TemplateContextType; // packageimport | |
19 import dwtx.jface.text.templates.Template; // packageimport | |
20 import dwtx.jface.text.templates.TemplateVariable; // packageimport | |
21 import dwtx.jface.text.templates.PositionBasedCompletionProposal; // packageimport | |
22 import dwtx.jface.text.templates.TemplateException; // packageimport | |
23 import dwtx.jface.text.templates.TemplateTranslator; // packageimport | |
24 import dwtx.jface.text.templates.DocumentTemplateContext; // packageimport | |
25 import dwtx.jface.text.templates.GlobalTemplateVariables; // packageimport | |
26 import dwtx.jface.text.templates.InclusivePositionUpdater; // packageimport | |
27 import dwtx.jface.text.templates.ContextTypeRegistry; // packageimport | |
28 import dwtx.jface.text.templates.JFaceTextTemplateMessages; // packageimport | |
29 import dwtx.jface.text.templates.TemplateCompletionProcessor; // packageimport | |
30 import dwtx.jface.text.templates.TextTemplateMessages; // packageimport | |
31 import dwtx.jface.text.templates.TemplateVariableType; // packageimport | |
32 import dwtx.jface.text.templates.TemplateVariableResolver; // packageimport | |
33 | |
34 | |
129 | 35 import dwt.dwthelper.utils; |
36 | |
37 | |
38 import dwt.graphics.Image; | |
39 import dwt.graphics.Point; | |
40 import dwt.widgets.Shell; | |
41 import dwtx.core.runtime.Assert; | |
42 import dwtx.jface.dialogs.MessageDialog; | |
43 import dwtx.jface.text.BadLocationException; | |
44 import dwtx.jface.text.BadPositionCategoryException; | |
45 import dwtx.jface.text.DocumentEvent; | |
46 import dwtx.jface.text.IDocument; | |
47 import dwtx.jface.text.IInformationControlCreator; | |
48 import dwtx.jface.text.IRegion; | |
49 import dwtx.jface.text.ITextViewer; | |
50 import dwtx.jface.text.Position; | |
51 import dwtx.jface.text.Region; | |
52 import dwtx.jface.text.contentassist.ICompletionProposal; | |
53 import dwtx.jface.text.contentassist.ICompletionProposalExtension; | |
54 import dwtx.jface.text.contentassist.ICompletionProposalExtension2; | |
55 import dwtx.jface.text.contentassist.ICompletionProposalExtension3; | |
56 import dwtx.jface.text.contentassist.IContextInformation; | |
57 import dwtx.jface.text.link.ILinkedModeListener; | |
58 import dwtx.jface.text.link.LinkedModeModel; | |
59 import dwtx.jface.text.link.LinkedModeUI; | |
60 import dwtx.jface.text.link.LinkedPosition; | |
61 import dwtx.jface.text.link.LinkedPositionGroup; | |
62 import dwtx.jface.text.link.ProposalPosition; | |
63 | |
64 | |
65 /** | |
66 * A template completion proposal. | |
67 * <p> | |
68 * Clients may subclass.</p> | |
69 * | |
70 * @since 3.0 | |
71 */ | |
72 public class TemplateProposal : ICompletionProposal, ICompletionProposalExtension, ICompletionProposalExtension2, ICompletionProposalExtension3 { | |
73 | |
74 private final Template fTemplate; | |
75 private final TemplateContext fContext; | |
76 private final Image fImage; | |
77 private final IRegion fRegion; | |
78 private int fRelevance; | |
79 | |
80 private IRegion fSelectedRegion; // initialized by apply() | |
81 private String fDisplayString; | |
82 private InclusivePositionUpdater fUpdater; | |
83 private IInformationControlCreator fInformationControlCreator; | |
84 | |
85 /** | |
86 * Creates a template proposal with a template and its context. | |
87 * | |
88 * @param template the template | |
89 * @param context the context in which the template was requested. | |
90 * @param region the region this proposal is applied to | |
91 * @param image the icon of the proposal. | |
92 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
93 public this(Template template, TemplateContext context, IRegion region, Image image) { |
129 | 94 this(template, context, region, image, 0); |
95 } | |
96 | |
97 /** | |
98 * Creates a template proposal with a template and its context. | |
99 * | |
100 * @param template the template | |
101 * @param context the context in which the template was requested. | |
102 * @param image the icon of the proposal. | |
103 * @param region the region this proposal is applied to | |
104 * @param relevance the relevance of the proposal | |
105 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
106 public this(Template template, TemplateContext context, IRegion region, Image image, int relevance) { |
129 | 107 Assert.isNotNull(template); |
108 Assert.isNotNull(context); | |
109 Assert.isNotNull(region); | |
110 | |
111 fTemplate= template; | |
112 fContext= context; | |
113 fImage= image; | |
114 fRegion= region; | |
115 | |
116 fDisplayString= null; | |
117 | |
118 fRelevance= relevance; | |
119 } | |
120 | |
121 /** | |
122 * Sets the information control creator for this completion proposal. | |
123 * | |
124 * @param informationControlCreator the information control creator | |
125 * @since 3.1 | |
126 */ | |
127 public final void setInformationControlCreator(IInformationControlCreator informationControlCreator) { | |
128 fInformationControlCreator= informationControlCreator; | |
129 } | |
130 | |
131 /** | |
132 * Returns the template of this proposal. | |
133 * | |
134 * @return the template of this proposal | |
135 * @since 3.1 | |
136 */ | |
137 protected final Template getTemplate() { | |
138 return fTemplate; | |
139 } | |
140 | |
141 /** | |
142 * Returns the context in which the template was requested. | |
143 * | |
144 * @return the context in which the template was requested | |
145 * @since 3.1 | |
146 */ | |
147 protected final TemplateContext getContext() { | |
148 return fContext; | |
149 } | |
150 | |
151 /* | |
152 * @see ICompletionProposal#apply(IDocument) | |
153 */ | |
154 public final void apply(IDocument document) { | |
155 // not called anymore | |
156 } | |
157 | |
158 /** | |
159 * Inserts the template offered by this proposal into the viewer's document | |
160 * and sets up a <code>LinkedModeUI</code> on the viewer to edit any of | |
161 * the template's unresolved variables. | |
162 * | |
163 * @param viewer {@inheritDoc} | |
164 * @param trigger {@inheritDoc} | |
165 * @param stateMask {@inheritDoc} | |
166 * @param offset {@inheritDoc} | |
167 */ | |
168 public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) { | |
169 | |
170 IDocument document= viewer.getDocument(); | |
171 try { | |
172 fContext.setReadOnly(false); | |
173 int start; | |
174 TemplateBuffer templateBuffer; | |
175 { | |
176 int oldReplaceOffset= getReplaceOffset(); | |
177 try { | |
178 // this may already modify the document (e.g. add imports) | |
179 templateBuffer= fContext.evaluate(fTemplate); | |
180 } catch (TemplateException e1) { | |
181 fSelectedRegion= fRegion; | |
182 return; | |
183 } | |
184 | |
185 start= getReplaceOffset(); | |
186 int shift= start - oldReplaceOffset; | |
187 int end= Math.max(getReplaceEndOffset(), offset + shift); | |
188 | |
189 // insert template string | |
190 String templateString= templateBuffer.getString(); | |
191 document.replace(start, end - start, templateString); | |
192 } | |
193 | |
194 // translate positions | |
195 LinkedModeModel model= new LinkedModeModel(); | |
196 TemplateVariable[] variables= templateBuffer.getVariables(); | |
197 bool hasPositions= false; | |
198 for (int i= 0; i !is variables.length; i++) { | |
199 TemplateVariable variable= variables[i]; | |
200 | |
201 if (variable.isUnambiguous()) | |
202 continue; | |
203 | |
204 LinkedPositionGroup group= new LinkedPositionGroup(); | |
205 | |
206 int[] offsets= variable.getOffsets(); | |
207 int length= variable.getLength(); | |
208 | |
209 LinkedPosition first; | |
210 { | |
211 String[] values= variable.getValues(); | |
212 ICompletionProposal[] proposals= new ICompletionProposal[values.length]; | |
213 for (int j= 0; j < values.length; j++) { | |
214 ensurePositionCategoryInstalled(document, model); | |
215 Position pos= new Position(offsets[0] + start, length); | |
216 document.addPosition(getCategory(), pos); | |
217 proposals[j]= new PositionBasedCompletionProposal(values[j], pos, length); | |
218 } | |
219 | |
220 if (proposals.length > 1) | |
221 first= new ProposalPosition(document, offsets[0] + start, length, proposals); | |
222 else | |
223 first= new LinkedPosition(document, offsets[0] + start, length); | |
224 } | |
225 | |
226 for (int j= 0; j !is offsets.length; j++) | |
227 if (j is 0) | |
228 group.addPosition(first); | |
229 else | |
230 group.addPosition(new LinkedPosition(document, offsets[j] + start, length)); | |
231 | |
232 model.addGroup(group); | |
233 hasPositions= true; | |
234 } | |
235 | |
236 if (hasPositions) { | |
237 model.forceInstall(); | |
238 LinkedModeUI ui= new LinkedModeUI(model, viewer); | |
239 ui.setExitPosition(viewer, getCaretOffset(templateBuffer) + start, 0, Integer.MAX_VALUE); | |
240 ui.enter(); | |
241 | |
242 fSelectedRegion= ui.getSelectedRegion(); | |
243 } else { | |
244 ensurePositionCategoryRemoved(document); | |
245 fSelectedRegion= new Region(getCaretOffset(templateBuffer) + start, 0); | |
246 } | |
247 | |
248 } catch (BadLocationException e) { | |
249 openErrorDialog(viewer.getTextWidget().getShell(), e); | |
250 ensurePositionCategoryRemoved(document); | |
251 fSelectedRegion= fRegion; | |
252 } catch (BadPositionCategoryException e) { | |
253 openErrorDialog(viewer.getTextWidget().getShell(), e); | |
254 fSelectedRegion= fRegion; | |
255 } | |
256 | |
257 } | |
258 | |
259 private void ensurePositionCategoryInstalled(final IDocument document, LinkedModeModel model) { | |
260 if (!document.containsPositionCategory(getCategory())) { | |
261 document.addPositionCategory(getCategory()); | |
262 fUpdater= new InclusivePositionUpdater(getCategory()); | |
263 document.addPositionUpdater(fUpdater); | |
264 | |
265 model.addLinkingListener(new ILinkedModeListener() { | |
266 | |
267 /* | |
268 * @see dwtx.jface.text.link.ILinkedModeListener#left(dwtx.jface.text.link.LinkedModeModel, int) | |
269 */ | |
270 public void left(LinkedModeModel environment, int flags) { | |
271 ensurePositionCategoryRemoved(document); | |
272 } | |
273 | |
274 public void suspend(LinkedModeModel environment) {} | |
275 public void resume(LinkedModeModel environment, int flags) {} | |
276 }); | |
277 } | |
278 } | |
279 | |
280 private void ensurePositionCategoryRemoved(IDocument document) { | |
281 if (document.containsPositionCategory(getCategory())) { | |
282 try { | |
283 document.removePositionCategory(getCategory()); | |
284 } catch (BadPositionCategoryException e) { | |
285 // ignore | |
286 } | |
287 document.removePositionUpdater(fUpdater); | |
288 } | |
289 } | |
290 | |
291 private String getCategory() { | |
292 return "TemplateProposalCategory_" + toString(); //$NON-NLS-1$ | |
293 } | |
294 | |
295 private int getCaretOffset(TemplateBuffer buffer) { | |
296 | |
297 TemplateVariable[] variables= buffer.getVariables(); | |
298 for (int i= 0; i !is variables.length; i++) { | |
299 TemplateVariable variable= variables[i]; | |
300 if (variable.getType().equals(GlobalTemplateVariables.Cursor.NAME)) | |
301 return variable.getOffsets()[0]; | |
302 } | |
303 | |
304 return buffer.getString().length(); | |
305 } | |
306 | |
307 /** | |
308 * Returns the offset of the range in the document that will be replaced by | |
309 * applying this template. | |
310 * | |
311 * @return the offset of the range in the document that will be replaced by | |
312 * applying this template | |
313 * @since 3.1 | |
314 */ | |
315 protected final int getReplaceOffset() { | |
316 int start; | |
317 if (fContext instanceof DocumentTemplateContext) { | |
318 DocumentTemplateContext docContext = (DocumentTemplateContext)fContext; | |
319 start= docContext.getStart(); | |
320 } else { | |
321 start= fRegion.getOffset(); | |
322 } | |
323 return start; | |
324 } | |
325 | |
326 /** | |
327 * Returns the end offset of the range in the document that will be replaced | |
328 * by applying this template. | |
329 * | |
330 * @return the end offset of the range in the document that will be replaced | |
331 * by applying this template | |
332 * @since 3.1 | |
333 */ | |
334 protected final int getReplaceEndOffset() { | |
335 int end; | |
336 if (fContext instanceof DocumentTemplateContext) { | |
337 DocumentTemplateContext docContext = (DocumentTemplateContext)fContext; | |
338 end= docContext.getEnd(); | |
339 } else { | |
340 end= fRegion.getOffset() + fRegion.getLength(); | |
341 } | |
342 return end; | |
343 } | |
344 | |
345 /* | |
346 * @see ICompletionProposal#getSelection(IDocument) | |
347 */ | |
348 public Point getSelection(IDocument document) { | |
349 return new Point(fSelectedRegion.getOffset(), fSelectedRegion.getLength()); | |
350 } | |
351 | |
352 /* | |
353 * @see ICompletionProposal#getAdditionalProposalInfo() | |
354 */ | |
355 public String getAdditionalProposalInfo() { | |
356 try { | |
357 fContext.setReadOnly(true); | |
358 TemplateBuffer templateBuffer; | |
359 try { | |
360 templateBuffer= fContext.evaluate(fTemplate); | |
361 } catch (TemplateException e) { | |
362 return null; | |
363 } | |
364 | |
365 return templateBuffer.getString(); | |
366 | |
367 } catch (BadLocationException e) { | |
368 return null; | |
369 } | |
370 } | |
371 | |
372 /* | |
373 * @see ICompletionProposal#getDisplayString() | |
374 */ | |
375 public String getDisplayString() { | |
376 if (fDisplayString is null) { | |
377 String[] arguments= new String[] { fTemplate.getName(), fTemplate.getDescription() }; | |
378 fDisplayString= JFaceTextTemplateMessages.getFormattedString("TemplateProposal.displayString", arguments); //$NON-NLS-1$ | |
379 } | |
380 return fDisplayString; | |
381 } | |
382 | |
383 /* | |
384 * @see ICompletionProposal#getImage() | |
385 */ | |
386 public Image getImage() { | |
387 return fImage; | |
388 } | |
389 | |
390 /* | |
391 * @see ICompletionProposal#getContextInformation() | |
392 */ | |
393 public IContextInformation getContextInformation() { | |
394 return null; | |
395 } | |
396 | |
397 private void openErrorDialog(Shell shell, Exception e) { | |
398 MessageDialog.openError(shell, JFaceTextTemplateMessages.getString("TemplateProposal.errorDialog.title"), e.getMessage()); //$NON-NLS-1$ | |
399 } | |
400 | |
401 /** | |
402 * Returns the relevance. | |
403 * | |
404 * @return the relevance | |
405 */ | |
406 public int getRelevance() { | |
407 return fRelevance; | |
408 } | |
409 | |
410 /* | |
411 * @see dwtx.jface.text.contentassist.ICompletionProposalExtension3#getInformationControlCreator() | |
412 */ | |
413 public IInformationControlCreator getInformationControlCreator() { | |
414 return fInformationControlCreator; | |
415 } | |
416 | |
417 /* | |
418 * @see dwtx.jface.text.contentassist.ICompletionProposalExtension2#selected(dwtx.jface.text.ITextViewer, bool) | |
419 */ | |
420 public void selected(ITextViewer viewer, bool smartToggle) { | |
421 } | |
422 | |
423 /* | |
424 * @see dwtx.jface.text.contentassist.ICompletionProposalExtension2#unselected(dwtx.jface.text.ITextViewer) | |
425 */ | |
426 public void unselected(ITextViewer viewer) { | |
427 } | |
428 | |
429 /* | |
430 * @see dwtx.jface.text.contentassist.ICompletionProposalExtension2#validate(dwtx.jface.text.IDocument, int, dwtx.jface.text.DocumentEvent) | |
431 */ | |
432 public bool validate(IDocument document, int offset, DocumentEvent event) { | |
433 try { | |
434 int replaceOffset= getReplaceOffset(); | |
435 if (offset >= replaceOffset) { | |
436 String content= document.get(replaceOffset, offset - replaceOffset); | |
437 return fTemplate.getName().toLowerCase().startsWith(content.toLowerCase()); | |
438 } | |
439 } catch (BadLocationException e) { | |
440 // concurrent modification - ignore | |
441 } | |
442 return false; | |
443 } | |
444 | |
445 /* | |
446 * @see dwtx.jface.text.contentassist.ICompletionProposalExtension3#getPrefixCompletionText(dwtx.jface.text.IDocument, int) | |
447 */ | |
448 public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) { | |
449 return fTemplate.getName(); | |
450 } | |
451 | |
452 /* | |
453 * @see dwtx.jface.text.contentassist.ICompletionProposalExtension3#getPrefixCompletionStart(dwtx.jface.text.IDocument, int) | |
454 */ | |
455 public int getPrefixCompletionStart(IDocument document, int completionOffset) { | |
456 return getReplaceOffset(); | |
457 } | |
458 | |
459 /* | |
460 * @see dwtx.jface.text.contentassist.ICompletionProposalExtension#apply(dwtx.jface.text.IDocument, char, int) | |
461 */ | |
462 public void apply(IDocument document, char trigger, int offset) { | |
463 // not called any longer | |
464 } | |
465 | |
466 /* | |
467 * @see dwtx.jface.text.contentassist.ICompletionProposalExtension#isValidFor(dwtx.jface.text.IDocument, int) | |
468 */ | |
469 public bool isValidFor(IDocument document, int offset) { | |
470 // not called any longer | |
471 return false; | |
472 } | |
473 | |
474 /* | |
475 * @see dwtx.jface.text.contentassist.ICompletionProposalExtension#getTriggerCharacters() | |
476 */ | |
477 public char[] getTriggerCharacters() { | |
478 // no triggers | |
479 return new char[0]; | |
480 } | |
481 | |
482 /* | |
483 * @see dwtx.jface.text.contentassist.ICompletionProposalExtension#getContextInformationPosition() | |
484 */ | |
485 public int getContextInformationPosition() { | |
486 return fRegion.getOffset(); | |
487 } | |
488 } |