package net.sourceforge.phpeclipse.phpeditor; /********************************************************************** Copyright (c) 2000, 2002 IBM Corp. and others. All rights reserved. This program and the accompanying materials are made available under the terms of the Common Public License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/cpl-v10.html Contributors: IBM Corporation - Initial implementation Klaus Hartlage - www.eclipseproject.de **********************************************************************/ import java.util.ArrayList; import java.util.List; import net.sourceforge.phpdt.internal.ui.actions.CompositeActionGroup; import net.sourceforge.phpdt.internal.ui.text.HTMLTextPresenter; import net.sourceforge.phpdt.internal.ui.text.JavaColorManager; import net.sourceforge.phpdt.internal.ui.text.PHPPairMatcher; import net.sourceforge.phpdt.internal.ui.viewsupport.IViewPartInputProvider; import net.sourceforge.phpdt.ui.actions.GenerateActionGroup; import net.sourceforge.phpdt.ui.actions.GotoMatchingBracketAction; import net.sourceforge.phpdt.ui.text.JavaTextTools; import net.sourceforge.phpeclipse.IPreferenceConstants; import net.sourceforge.phpeclipse.PHPeclipsePlugin; import net.sourceforge.phpeclipse.phpeditor.php.IPHPPartitionScannerConstants; import net.sourceforge.phpeclipse.phpeditor.php.PHPCodeScanner; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceConverter; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.DefaultInformationControl; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IInformationControl; import org.eclipse.jface.text.IInformationControlCreator; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextOperationTarget; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.ITextViewerExtension3; import org.eclipse.jface.text.ITypedRegion; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.information.InformationPresenter; import org.eclipse.jface.text.source.AnnotationRulerColumn; import org.eclipse.jface.text.source.CompositeRuler; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.IVerticalRuler; import org.eclipse.jface.text.source.IVerticalRulerColumn; import org.eclipse.jface.text.source.LineNumberRulerColumn; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BidiSegmentEvent; import org.eclipse.swt.custom.BidiSegmentListener; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.actions.ActionContext; import org.eclipse.ui.actions.ActionGroup; import org.eclipse.ui.texteditor.ContentAssistAction; import org.eclipse.ui.texteditor.DefaultRangeIndicator; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.IEditorStatusLine; import org.eclipse.ui.texteditor.ITextEditorActionConstants; import org.eclipse.ui.texteditor.StatusTextEditor; import org.eclipse.ui.texteditor.TextOperationAction; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; /** * PHP specific text editor. */ public class PHPEditor extends StatusTextEditor implements IViewPartInputProvider { // extends TextEditor { // protected PHPActionGroup fActionGroups; /** The outline page */ private PHPContentOutlinePage fOutlinePage; // protected PHPSyntaxParserThread fValidationThread = null; // private IPreferenceStore fPHPPrefStore; /** The editor's bracket matcher */ private PHPPairMatcher fBracketMatcher; /** The line number ruler column */ private LineNumberRulerColumn fLineNumberRulerColumn; protected CompositeActionGroup fActionGroups; /** The standard action groups added to the menu */ private GenerateActionGroup fGenerateActionGroup; private CompositeActionGroup fContextMenuGroup; /** The information presenter. */ private InformationPresenter fInformationPresenter; /** * Default constructor. */ public PHPEditor() { super(); JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools(); setSourceViewerConfiguration( new PHPSourceViewerConfiguration(textTools, this)); setRangeIndicator(new DefaultRangeIndicator()); setPreferenceStore(PHPeclipsePlugin.getDefault().getPreferenceStore()); // if (PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE)) // fUpdater= new OutlinePageSelectionUpdater(); initializeEditor(); } // // /** // * @see IMember#getCompilationUnit() // */ // public ICompilationUnit getCompilationUnit() { // return this; // } // /** // * @see org.phpeclipse.phpdt.internal.compiler.env.ICompilationUnit#getContents() // */ // public char[] getContents() { // IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput()); // // return doc.get().toCharArray(); // } /* * @see net.sourceforge.phpdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput() */ public Object getViewPartInput() { return getEditorInput().getAdapter(IResource.class); } /* * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt. * widgets.Composite) */ public void createPartControl(Composite parent) { super.createPartControl(parent); IInformationControlCreator informationControlCreator = new IInformationControlCreator() { public IInformationControl createInformationControl(Shell parent) { boolean cutDown = false; int style = cutDown ? SWT.NONE : (SWT.V_SCROLL | SWT.H_SCROLL); return new DefaultInformationControl( parent, SWT.RESIZE, style, new HTMLTextPresenter(cutDown)); } }; fInformationPresenter = new InformationPresenter(informationControlCreator); fInformationPresenter.setSizeConstraints(60, 10, true, true); fInformationPresenter.install(getSourceViewer()); } /** * Returns this document's complete text. * * @return the document's complete text */ public String get() { IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput()); return doc.get(); } /** * Returns the standard action group of this editor. */ protected ActionGroup getActionGroup() { return fActionGroups; } public PHPContentOutlinePage getfOutlinePage() { return fOutlinePage; } /** The PHPEditor implementation of this * AbstractTextEditor method extend the * actions to add those specific to the receiver */ protected void createActions() { super.createActions(); Action action; // setAction( // "ContentAssistProposal", // new TextOperationAction( // PHPEditorMessages.getResourceBundle(), // "ContentAssistProposal.", // this, // ISourceViewer.CONTENTASSIST_PROPOSALS)); action = new ContentAssistAction(PHPEditorMessages.getResourceBundle(), "ContentAssistProposal.", this); //$NON-NLS-1$ action.setActionDefinitionId( PHPEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); setAction("ContentAssistProposal", action); //$NON-NLS-1$ setAction( "ContentAssistTip", new TextOperationAction( PHPEditorMessages.getResourceBundle(), "ContentAssistTip.", this, ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION)); action = new TextOperationAction( PHPEditorMessages.getResourceBundle(), "Comment.", this, ITextOperationTarget.PREFIX); action.setActionDefinitionId(PHPEditorActionDefinitionIds.COMMENT); setAction("Comment", action); action = new TextOperationAction( PHPEditorMessages.getResourceBundle(), "Uncomment.", this, ITextOperationTarget.STRIP_PREFIX); action.setActionDefinitionId(PHPEditorActionDefinitionIds.UNCOMMENT); setAction("Uncomment", action); action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Format.", this, ISourceViewer.FORMAT); //$NON-NLS-1$ action.setActionDefinitionId(PHPEditorActionDefinitionIds.FORMAT); setAction("Format", action); //$NON-NLS-1$ markAsStateDependentAction("ContentAssistProposal", true); //$NON-NLS-1$ markAsStateDependentAction("Comment", true); //$NON-NLS-1$ markAsStateDependentAction("Uncomment", true); //$NON-NLS-1$ markAsStateDependentAction("Format", true); //$NON-NLS-1$ action = new GotoMatchingBracketAction(this); action.setActionDefinitionId( PHPEditorActionDefinitionIds.GOTO_MATCHING_BRACKET); setAction(GotoMatchingBracketAction.GOTO_MATCHING_BRACKET, action); fGenerateActionGroup = new GenerateActionGroup(this, ITextEditorActionConstants.GROUP_EDIT); fActionGroups = new CompositeActionGroup(new ActionGroup[] { fGenerateActionGroup }); // We have to keep the context menu group separate to have better control over positioning fContextMenuGroup = new CompositeActionGroup(new ActionGroup[] { fGenerateActionGroup }); // rg, // new LocalHistoryActionGroup(this, ITextEditorActionConstants.GROUP_EDIT)}); // if (fValidationThread == null) { // fValidationThread = // new PHPSyntaxParserThread(this, getSourceViewer()); // //Thread defaults // // fValidationThread.start(); // } // // fValidationThread.setText(getSourceViewer().getTextWidget().getText()); } /** The PHPEditor implementation of this * AbstractTextEditor method performs any extra * disposal actions required by the php editor. */ public void dispose() { PHPEditorEnvironment.disconnect(this); if (fOutlinePage != null) fOutlinePage.setInput(null); if (fActionGroups != null) fActionGroups.dispose(); super.dispose(); } /** The PHPEditor implementation of this * AbstractTextEditor method performs any extra * revert behavior required by the php editor. */ public void doRevertToSaved() { super.doRevertToSaved(); if (fOutlinePage != null) fOutlinePage.update(); } /** The PHPEditor implementation of this * AbstractTextEditor method performs any extra * save behavior required by the php editor. */ public void doSave(IProgressMonitor monitor) { super.doSave(monitor); // compile or not, according to the user preferences IPreferenceStore store = getPreferenceStore(); // fPHPPrefStore; if (store.getBoolean(PHPeclipsePlugin.PHP_PARSE_ON_SAVE)) { IAction a = PHPParserAction.getInstance(); if (a != null) a.run(); } if (fOutlinePage != null) fOutlinePage.update(); } /** The PHPEditor implementation of this * AbstractTextEditor method performs any extra * save as behavior required by the php editor. */ public void doSaveAs() { super.doSaveAs(); if (fOutlinePage != null) fOutlinePage.update(); } /** The PHPEditor implementation of this * AbstractTextEditor method performs sets the * input of the outline page after AbstractTextEditor has set input. */ protected void doSetInput(IEditorInput input) throws CoreException { super.doSetInput(input); if (fOutlinePage != null) fOutlinePage.setInput(input); } /* * @see org.phpeclipse.phpdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput() */ // public Object getViewPartInput() { // return getEditorInput().getAdapter(IFile.class); // } /** The PHPEditor implementation of this * AbstractTextEditor method adds any * PHPEditor specific entries. */ public void editorContextMenuAboutToShow(MenuManager menu) { super.editorContextMenuAboutToShow(menu); addAction(menu, ITextEditorActionConstants.GROUP_EDIT, "Format"); //$NON-NLS-1$ ActionContext context = new ActionContext(getSelectionProvider().getSelection()); fContextMenuGroup.setContext(context); fContextMenuGroup.fillContextMenu(menu); fContextMenuGroup.setContext(null); } protected void updateStateDependentActions() { super.updateStateDependentActions(); fGenerateActionGroup.editorStateChanged(); } /** The PHPEditor implementation of this * AbstractTextEditor method performs gets * the java content outline page if request is for a an * outline page. */ public Object getAdapter(Class required) { if (IContentOutlinePage.class.equals(required)) { if (fOutlinePage == null) { fOutlinePage = new PHPContentOutlinePage(getDocumentProvider(), this); if (getEditorInput() != null) fOutlinePage.setInput(getEditorInput()); } return fOutlinePage; } return super.getAdapter(required); } // public void openContextHelp() { // IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput()); // ITextSelection selection = (ITextSelection) this.getSelectionProvider().getSelection(); // int pos = selection.getOffset(); // String word = getFunctionName(doc, pos); // openContextHelp(word); // } // // private void openContextHelp(String word) { // open(word); // } // // public static void open(String word) { // IHelp help = WorkbenchHelp.getHelpSupport(); // if (help != null) { // IHelpResource helpResource = new PHPFunctionHelpResource(word); // WorkbenchHelp.getHelpSupport().displayHelpResource(helpResource); // } else { // // showMessage(shell, dialogTitle, ActionMessages.getString("Open help not available"), false); //$NON-NLS-1$ // } // } // private String getFunctionName(IDocument doc, int pos) { // Point word = PHPWordExtractor.findWord(doc, pos); // if (word != null) { // try { // return doc.get(word.x, word.y).replace('_', '-'); // } catch (BadLocationException e) { // } // } // return ""; // } /* * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent) */ protected void handlePreferenceStoreChanged(PropertyChangeEvent event) { try { ISourceViewer sourceViewer = getSourceViewer(); if (sourceViewer == null) return; String property = event.getProperty(); // if (JavaSourceViewerConfiguration.PREFERENCE_TAB_WIDTH.equals(property)) { // Object value= event.getNewValue(); // if (value instanceof Integer) { // sourceViewer.getTextWidget().setTabs(((Integer) value).intValue()); // } else if (value instanceof String) { // sourceViewer.getTextWidget().setTabs(Integer.parseInt((String) value)); // } // return; // } if (IPreferenceConstants.LINE_NUMBER_RULER.equals(property)) { if (isLineNumberRulerVisible()) showLineNumberRuler(); else hideLineNumberRuler(); return; } if (fLineNumberRulerColumn != null && (IPreferenceConstants.LINE_NUMBER_COLOR.equals(property) || PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property) || PREFERENCE_COLOR_BACKGROUND.equals(property))) { initializeLineNumberRulerColumn(fLineNumberRulerColumn); } } finally { super.handlePreferenceStoreChanged(event); } } /** * Shows the line number ruler column. */ private void showLineNumberRuler() { IVerticalRuler v = getVerticalRuler(); if (v instanceof CompositeRuler) { CompositeRuler c = (CompositeRuler) v; c.addDecorator(1, createLineNumberRulerColumn()); } } /** * Return whether the line number ruler column should be * visible according to the preference store settings. * @return true if the line numbers should be visible */ private boolean isLineNumberRulerVisible() { // IPreferenceStore store= getPreferenceStore(); return getPreferenceStore().getBoolean( IPreferenceConstants.LINE_NUMBER_RULER); } /** * Hides the line number ruler column. */ private void hideLineNumberRuler() { IVerticalRuler v = getVerticalRuler(); if (v instanceof CompositeRuler) { CompositeRuler c = (CompositeRuler) v; try { c.removeDecorator(1); } catch (Throwable e) { } } } /** * Initializes the given line number ruler column from the preference store. * @param rulerColumn the ruler column to be initialized */ protected void initializeLineNumberRulerColumn(LineNumberRulerColumn rulerColumn) { JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools(); // PHPColorProvider manager = PHPEditorEnvironment.getPHPColorProvider(); JavaColorManager manager = textTools.getColorManager(); IPreferenceStore store = getPreferenceStore(); if (store != null) { RGB rgb = null; // foreground color if (store.contains(IPreferenceConstants.LINE_NUMBER_COLOR)) { if (store.isDefault(IPreferenceConstants.LINE_NUMBER_COLOR)) rgb = PreferenceConverter.getDefaultColor( store, IPreferenceConstants.LINE_NUMBER_COLOR); else rgb = PreferenceConverter.getColor( store, IPreferenceConstants.LINE_NUMBER_COLOR); } rulerColumn.setForeground(manager.getColor(rgb)); rgb = null; // background color if (!store .getBoolean( IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT)) { if (store.contains(IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND)) { if (store .isDefault(IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND)) rgb = PreferenceConverter.getDefaultColor( store, IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND); else rgb = PreferenceConverter.getColor( store, IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND); } rulerColumn.setBackground(manager.getColor(rgb)); } } } /** * Creates a new line number ruler column that is appropriately initialized. */ protected IVerticalRulerColumn createLineNumberRulerColumn() { fLineNumberRulerColumn = new LineNumberRulerColumn(); initializeLineNumberRulerColumn(fLineNumberRulerColumn); return fLineNumberRulerColumn; } /* * @see AbstractTextEditor#createVerticalRuler() */ protected IVerticalRuler createVerticalRuler() { CompositeRuler ruler = new CompositeRuler(); ruler.addDecorator(0, new AnnotationRulerColumn(VERTICAL_RULER_WIDTH)); if (isLineNumberRulerVisible()) ruler.addDecorator(1, createLineNumberRulerColumn()); return ruler; } /* (non-Javadoc) * Method declared on TextEditor */ protected void initializeEditor() { IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore(); PHPEditorEnvironment.connect(this); setEditorContextMenuId("#PHPEditorContext"); //$NON-NLS-1$ setRulerContextMenuId("#PHPRulerContext"); //$NON-NLS-1$ // setDocumentProvider(PHPeclipsePlugin.getCompilationUnitDocumentProvider()); store.addPropertyChangeListener(new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { PHPCodeScanner scanner = PHPEditorEnvironment.getPHPCodeScanner(); if (scanner != null) { scanner.updateToken(PHPEditorEnvironment.getPHPColorProvider()); } if (getSourceViewer() != null) { getSourceViewer().invalidateTextPresentation(); } String property = event.getProperty(); if (IPreferenceConstants.LINE_NUMBER_RULER.equals(property)) { if (isLineNumberRulerVisible()) showLineNumberRuler(); else hideLineNumberRuler(); return; } } }); } private static IRegion getSignedSelection(ITextViewer viewer) { StyledText text = viewer.getTextWidget(); int caretOffset = text.getCaretOffset(); Point selection = text.getSelection(); // caret left int offset, length; if (caretOffset == selection.x) { offset = selection.y; length = selection.x - selection.y; // caret right } else { offset = selection.x; length = selection.y - selection.x; } return new Region(offset, length); } private final static char[] BRACKETS = { '{', '}', '(', ')', '[', ']' }; private static boolean isBracket(char character) { for (int i = 0; i != BRACKETS.length; ++i) if (character == BRACKETS[i]) return true; return false; } private static boolean isSurroundedByBrackets( IDocument document, int offset) { if (offset == 0 || offset == document.getLength()) return false; try { return isBracket(document.getChar(offset - 1)) && isBracket(document.getChar(offset)); } catch (BadLocationException e) { return false; } } /** * Jumps to the matching bracket. */ public void gotoMatchingBracket() { if (fBracketMatcher == null) fBracketMatcher = new PHPPairMatcher(BRACKETS); ISourceViewer sourceViewer = getSourceViewer(); IDocument document = sourceViewer.getDocument(); if (document == null) return; IRegion selection = getSignedSelection(sourceViewer); int selectionLength = Math.abs(selection.getLength()); if (selectionLength > 1) { setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.invalidSelection")); //$NON-NLS-1$ sourceViewer.getTextWidget().getDisplay().beep(); return; } // #26314 int sourceCaretOffset = selection.getOffset() + selection.getLength(); if (isSurroundedByBrackets(document, sourceCaretOffset)) sourceCaretOffset -= selection.getLength(); IRegion region = fBracketMatcher.match(document, sourceCaretOffset); if (region == null) { setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.noMatchingBracket")); //$NON-NLS-1$ sourceViewer.getTextWidget().getDisplay().beep(); return; } int offset = region.getOffset(); int length = region.getLength(); if (length < 1) return; int anchor = fBracketMatcher.getAnchor(); int targetOffset = (PHPPairMatcher.RIGHT == anchor) ? offset : offset + length - 1; boolean visible = false; if (sourceViewer instanceof ITextViewerExtension3) { ITextViewerExtension3 extension = (ITextViewerExtension3) sourceViewer; visible = (extension.modelOffset2WidgetOffset(targetOffset) > -1); } else { IRegion visibleRegion = sourceViewer.getVisibleRegion(); visible = (targetOffset >= visibleRegion.getOffset() && targetOffset < visibleRegion.getOffset() + visibleRegion.getLength()); } if (!visible) { setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.bracketOutsideSelectedElement")); //$NON-NLS-1$ sourceViewer.getTextWidget().getDisplay().beep(); return; } if (selection.getLength() < 0) targetOffset -= selection.getLength(); sourceViewer.setSelectedRange(targetOffset, selection.getLength()); sourceViewer.revealRange(targetOffset, selection.getLength()); } /** * Ses the given message as error message to this editor's status line. * @param msg message to be set */ protected void setStatusLineErrorMessage(String msg) { IEditorStatusLine statusLine = (IEditorStatusLine) getAdapter(IEditorStatusLine.class); if (statusLine != null) statusLine.setMessage(true, msg, null); } /** * Returns a segmentation of the line of the given document appropriate for bidi rendering. * The default implementation returns only the string literals of a php code line as segments. * * @param document the document * @param lineOffset the offset of the line * @return the line's bidi segmentation * @throws BadLocationException in case lineOffset is not valid in document */ public static int[] getBidiLineSegments(IDocument document, int lineOffset) throws BadLocationException { IRegion line= document.getLineInformationOfOffset(lineOffset); ITypedRegion[] linePartitioning= document.computePartitioning(lineOffset, line.getLength()); List segmentation= new ArrayList(); for (int i= 0; i < linePartitioning.length; i++) { if (IPHPPartitionScannerConstants.PHP_STRING.equals(linePartitioning[i].getType())) segmentation.add(linePartitioning[i]); } if (segmentation.size() == 0) return null; int size= segmentation.size(); int[] segments= new int[size * 2 + 1]; int j= 0; for (int i= 0; i < size; i++) { ITypedRegion segment= (ITypedRegion) segmentation.get(i); if (i == 0) segments[j++]= 0; int offset= segment.getOffset() - lineOffset; if (offset > segments[j - 1]) segments[j++]= offset; if (offset + segment.getLength() >= line.getLength()) break; segments[j++]= offset + segment.getLength(); } if (j < segments.length) { int[] result= new int[j]; System.arraycopy(segments, 0, result, 0, j); segments= result; } return segments; } /** * Returns a segmentation of the given line appropriate for bidi rendering. The default * implementation returns only the string literals of a php code line as segments. * * @param lineOffset the offset of the line * @param line the content of the line * @return the line's bidi segmentation */ protected int[] getBidiLineSegments(int lineOffset, String line) { IDocumentProvider provider = getDocumentProvider(); if (provider != null && line != null && line.length() > 0) { IDocument document = provider.getDocument(getEditorInput()); if (document != null) try { return getBidiLineSegments(document, lineOffset); } catch (BadLocationException x) { // ignore } } return null; } /* * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int) */ protected final ISourceViewer createSourceViewer( Composite parent, IVerticalRuler ruler, int styles) { ISourceViewer viewer = createJavaSourceViewer(parent, ruler, styles); StyledText text = viewer.getTextWidget(); text.addBidiSegmentListener(new BidiSegmentListener() { public void lineGetSegments(BidiSegmentEvent event) { event.segments = getBidiLineSegments(event.lineOffset, event.lineText); } }); // JavaUIHelp.setHelp(this, text, IJavaHelpContextIds.JAVA_EDITOR); return viewer; } /* * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int) */ protected ISourceViewer createJavaSourceViewer( Composite parent, IVerticalRuler ruler, int styles) { return super.createSourceViewer(parent, ruler, styles); } }