/* * 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: *
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$
}
}
}