/******************************************************************************* * Copyright (c) 2005, 2007 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 * Jens Lukowski/Innoopract - initial renaming/restructuring *******************************************************************************/ package org.eclipse.wst.jsdt.web.ui.internal.autoedit; import org.eclipse.core.runtime.Preferences; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.ConfigurableLineTracker; import org.eclipse.jface.text.DocumentCommand; import org.eclipse.jface.text.IAutoEditStrategy; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ILineTracker; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.TextUtilities; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.texteditor.ITextEditor; import org.eclipse.ui.texteditor.ITextEditorExtension3; import org.eclipse.wst.html.core.internal.HTMLCorePlugin; import org.eclipse.wst.html.core.internal.preferences.HTMLCorePreferenceNames; import org.eclipse.wst.jsdt.web.ui.internal.Logger; /** * * Provisional API: This class/interface is part of an interim API that is still under development and expected to * change significantly before reaching stability. It is being made available at this early stage to solicit feedback * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken * (repeatedly) as the API evolves. */ public class AutoEditStrategyForTabs implements IAutoEditStrategy { private final String TAB_CHARACTER = "\t"; //$NON-NLS-1$ public void customizeDocumentCommand(IDocument document, DocumentCommand command) { // if not in smart insert mode just ignore if (!isSmartInsertMode()) { return; } // spaces for tab character if (command.length == 0 && command.text != null && command.text.length() > 0 && command.text.indexOf(TAB_CHARACTER) != -1) { smartInsertForTab(command, document); } } /** * Returns indentation width if using spaces for indentation, -1 otherwise * * @return */ private int getIndentationWidth() { int width = -1; Preferences preferences = HTMLCorePlugin.getDefault().getPluginPreferences(); if (HTMLCorePreferenceNames.SPACE.equals(preferences.getString(HTMLCorePreferenceNames.INDENTATION_CHAR))) { width = preferences.getInt(HTMLCorePreferenceNames.INDENTATION_SIZE); } return width; } /** * Calculate number of spaces for next tab stop */ private String getIndentString(int indentationWidth, int lineOffset, ILineTracker lineTracker, int index) { int indentSize = indentationWidth; int offsetInLine = -1; if (lineTracker != null) { try { IRegion lineInfo = lineTracker.getLineInformationOfOffset(index); if (lineInfo.getOffset() == 0 && lineOffset > -1) { offsetInLine = lineOffset + index; } else { offsetInLine = index - lineInfo.getOffset(); } } catch (BadLocationException e) { Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e); } } else { if (lineOffset > -1) { offsetInLine = lineOffset + index; } } if (offsetInLine > -1 && indentationWidth > 0) { int remainder = offsetInLine % indentationWidth; indentSize = indentationWidth - remainder; } StringBuffer indent = new StringBuffer(); for (int i = 0; i < indentSize; i++) { indent.append(' '); } return indent.toString(); } /** * Set up a line tracker for text within command if text is multi-line */ private ILineTracker getLineTracker(IDocument document, String originalText) { ConfigurableLineTracker lineTracker = null; int[] delims = TextUtilities.indexOf(document.getLegalLineDelimiters(), originalText, 0); if (delims[0] != -1 || delims[1] != -1) { lineTracker = new ConfigurableLineTracker(document.getLegalLineDelimiters()); lineTracker.set(originalText); } return lineTracker; } /** * Return true if active editor is in smart insert mode, false otherwise * * @return */ private boolean isSmartInsertMode() { boolean isSmartInsertMode = false; ITextEditor textEditor = null; IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (window != null) { IWorkbenchPage page = window.getActivePage(); if (page != null) { IEditorPart editor = page.getActiveEditor(); if (editor != null) { if (editor instanceof ITextEditor) { textEditor = (ITextEditor) editor; } else { textEditor = (ITextEditor) editor.getAdapter(ITextEditor.class); } } } } // check if smart insert mode if (textEditor instanceof ITextEditorExtension3 && ((ITextEditorExtension3) textEditor).getInsertMode() == ITextEditorExtension3.SMART_INSERT) { isSmartInsertMode = true; } return isSmartInsertMode; } /** * Insert spaces for tabs * * @param command */ private void smartInsertForTab(DocumentCommand command, IDocument document) { // tab key was pressed. now check preferences to see if need to insert // spaces instead of tab int indentationWidth = getIndentationWidth(); if (indentationWidth > -1) { String originalText = command.text; StringBuffer newText = new StringBuffer(originalText); // determine where in line this command begins int lineOffset = -1; try { IRegion lineInfo = document.getLineInformationOfOffset(command.offset); lineOffset = command.offset - lineInfo.getOffset(); } catch (BadLocationException e) { Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e); } ILineTracker lineTracker = getLineTracker(document, originalText); int startIndex = 0; int index = newText.indexOf(TAB_CHARACTER); while (index != -1) { String indent = getIndentString(indentationWidth, lineOffset, lineTracker, index); // replace \t character with spaces newText.replace(index, index + 1, indent); if (lineTracker != null) { try { lineTracker.replace(index, 1, indent); } catch (BadLocationException e) { // if something goes wrong with replacing text, just // reset to current string lineTracker.set(newText.toString()); Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e); } } startIndex = index + indent.length(); index = newText.indexOf(TAB_CHARACTER, startIndex); } command.text = newText.toString(); } } }