/* * Copyright (c) 2003-2004 Christopher Lenz 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: * Christopher Lenz - initial API and implementation * * $Id: CssAutoEditStrategy.java,v 1.1 2004-09-02 18:11:48 jsurfer Exp $ */ package net.sourceforge.phpeclipse.css.ui.internal.text; import net.sourceforge.phpeclipse.css.core.internal.text.CssTextUtils; import net.sourceforge.phpeclipse.css.ui.CssUI; import net.sourceforge.phpeclipse.css.ui.internal.CssUIPreferences; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.DefaultAutoIndentStrategy; import org.eclipse.jface.text.DefaultLineTracker; import org.eclipse.jface.text.DocumentCommand; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ILineTracker; import org.eclipse.jface.text.IRegion; 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.ITextEditorExtension3; import org.eclipse.ui.texteditor.ITextEditorExtension3.InsertMode; /** * Implements various auto-editing aspects for editing CSS: * * All these only operate when 'Smart Insert' mode is enabled, and the closing * of braces, brackets, parenthesis and strings can be disabled in the editor * preferences. */ public class CssAutoEditStrategy extends DefaultAutoIndentStrategy { // Constants --------------------------------------------------------------- /** * Alias for the preference constant EDITOR_SPACES_FOR_TABS. */ public static final String SPACES_FOR_TABS = CssUIPreferences.EDITOR_SPACES_FOR_TABS; /** * Alias for the preference constant EDITOR_TAB_WIDTH. */ public static final String TAB_WIDTH = CssUIPreferences.EDITOR_TAB_WIDTH; // Instance Variables ------------------------------------------------------ /** * The line tracker. */ private ILineTracker lineTracker; /** * The preference store. */ private IPreferenceStore store; // Constructors ------------------------------------------------------------ /** * Default constructor. */ public CssAutoEditStrategy() { lineTracker = new DefaultLineTracker(); store = CssUI.getDefault().getPreferenceStore(); } // DefaultAutoIndentStrategy Implementation -------------------------------- /** * @see org.eclipse.jface.text.IAutoEditStrategy#customizeDocumentCommand(IDocument, DocumentCommand) */ public void customizeDocumentCommand(IDocument d, DocumentCommand c) { if (isSmartInsertMode()) { if (isNewLine(d, c)) { smartIndentAfterNewLine(d, c); } else if (c.text != null) { if (c.text.length() == 1) { switch (c.text.charAt(0)) { case '}': { smartInsertClosingBrace(d, c); break; } default: { // do nothing } } } if (store.getBoolean(SPACES_FOR_TABS)) { convertTabs(d, c); } } } } // Private Methods --------------------------------------------------------- private void convertTabs(IDocument d, DocumentCommand c) { int index = c.text.indexOf('\t'); if (index > -1) { StringBuffer buffer = new StringBuffer(); lineTracker.set(c.text); int lines = lineTracker.getNumberOfLines(); try { for (int i = 0; i < lines; i++) { int offset = lineTracker.getLineOffset(i); int endOffset = offset + lineTracker.getLineLength(i); String line = c.text.substring(offset, endOffset); int position = 0; if (i == 0) { IRegion firstLine = d.getLineInformationOfOffset(c.offset); position = c.offset - firstLine.getOffset(); } int length = line.length(); for (int j = 0; j < length; j++) { char ch = line.charAt(j); if (ch == '\t') { int tabWidth = getTabWidth(); int remainder = position % tabWidth; remainder = tabWidth - remainder; for (int k = 0; k < remainder; k++) { buffer.append(' '); } position += remainder; } else { buffer.append(ch); position++; } } } c.text = buffer.toString(); } catch (BadLocationException e) { // ignore } } } private String getIndentOfLine(IDocument d, int line) throws BadLocationException { if (line > -1) { int start = d.getLineOffset(line); int end = start + d.getLineLength(line) - 1; int whiteEnd = findEndOfWhiteSpace(d, start, end); return d.get(start, whiteEnd - start); } else { return ""; //$NON-NLS-1$ } } private int getTabWidth() { return store.getInt(TAB_WIDTH); } private boolean isNewLine(IDocument d, DocumentCommand c) { if ((c.length == 0) && (c.text != null)) { String[] delimiters = d.getLegalLineDelimiters(); for (int i = 0; i < delimiters.length; i++) { if (c.text.equals(delimiters[i])) { return true; } } } return false; } private boolean isSmartInsertMode() { IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (window != null) { IWorkbenchPage page = window.getActivePage(); if (page != null) { IEditorPart part = page.getActiveEditor(); if (part instanceof ITextEditorExtension3) { InsertMode insertMode = ((ITextEditorExtension3) part).getInsertMode(); return (insertMode == ITextEditorExtension3.SMART_INSERT); } } } return false; } private String createIndentation(int level) { StringBuffer buf = new StringBuffer(); if (store.getBoolean(SPACES_FOR_TABS)) { int tabWidth = getTabWidth(); for (int i = 0; i < level * tabWidth; i++) { buf.append(' '); } } else { for (int i = 0; i < level; i++) { buf.append('\t'); } } return buf.toString(); } private void smartInsertClosingBrace(IDocument d, DocumentCommand c) { int docLength = d.getLength(); if ((c.offset == -1) || (docLength == 0)) { return; } try { int lineOffset = d.getLineInformationOfOffset(c.offset).getOffset(); if (c.offset == findEndOfWhiteSpace(d, lineOffset, c.offset)) { int openingBraceOffset = CssTextUtils.findMatchingOpeningPeer(d, c.offset - 1, '}'); if (openingBraceOffset >= 0) { int openingBraceLine = d.getLineOfOffset(openingBraceOffset); StringBuffer buf = new StringBuffer(getIndentOfLine(d, openingBraceLine)); buf.append(c.text); c.length += c.offset - lineOffset; c.offset = lineOffset; c.text = buf.toString(); } } } catch (BadLocationException e) { CssUI.log( "Failed to smart indent after closing brace", e); //$NON-NLS-1$ } } private void smartIndentAfterNewLine(IDocument d, DocumentCommand c) { try { int docLength = d.getLength(); if ((c.offset == -1) || (docLength == 0)) { return; } StringBuffer buf = new StringBuffer(c.text); if ((c.offset < docLength) && (d.getChar(c.offset - 1) == '}')) { // indent with the same amount used before the block was opened int openingBraceOffset = CssTextUtils.findMatchingOpeningPeer(d, c.offset - 2, '}'); if (openingBraceOffset >= 0) { int openingBraceLine = d.getLineOfOffset(openingBraceOffset); buf.append(getIndentOfLine(d, openingBraceLine)); } } else if ((c.offset < docLength) && (d.getChar(c.offset - 1) == '{')) { int previousLine = d.getLineOfOffset(c.offset); buf.append(getIndentOfLine(d, previousLine)); buf.append(createIndentation(1)); } else { int previousLine = d.getLineOfOffset(c.offset); buf.append(getIndentOfLine(d, previousLine)); } c.text = buf.toString(); } catch (BadLocationException e) { CssUI.log( "Failed to smart indent after new line", e); //$NON-NLS-1$ } } }