/** * Copyright (c) 2009, 2010 Mark Feber, MulgaSoft * * 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 * */ package com.mulgasoft.emacsplus.commands; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.TextSelection; import org.eclipse.ui.texteditor.ITextEditor; /** * Implement indent-rigidly * * Indent all lines <b>starting</b> in the region sideways by ARG columns. * You can remove all indentation from a region by giving a large negative ARG. * * @author Mark Feber - initial API and implementation */ public class IndentRigidlyHandler extends RectangleHandler { /** * @see com.mulgasoft.emacsplus.commands.RectangleHandler#doTransform(org.eclipse.ui.texteditor.ITextEditor, org.eclipse.jface.text.IDocument, org.eclipse.jface.text.ITextSelection) */ @Override protected int doTransform(ITextEditor editor, IDocument document, ITextSelection currentSelection) throws BadLocationException { int result = NO_OFFSET; int count = this.getUniversalCount(); // get full explicit or point/mark selection if explicit.length == 0 ITextSelection selection = getImpliedSelection(editor, document, currentSelection); if (selection != null && count != 0) { Pattern nonSpace = Pattern.compile("\\S"); //$NON-NLS-1$ IRegion[] regions = getRegions(document,selection); // iterate over lines from bottom up, so offsets remain consistent for (int i = regions.length; i > 0; i--) { IRegion reg = regions[i-1]; String text = document.get(reg.getOffset(),reg.getLength()); Matcher matcher = nonSpace.matcher(text); // get offset on the line where spaces end int endOffset = reg.getOffset() + ((matcher.find()) ? matcher.end() - 1 : reg.getLength()); // get the column number where spaces end IRegion endCol = rs.getColumn(document, reg.getOffset(), endOffset - reg.getOffset(), Integer.MAX_VALUE); // get the length of the replacement on the line int length = endOffset-reg.getOffset(); // get then new length (in columns) of the replacement int columns = ((count > 0) ? endCol.getLength()+count : Math.max(endCol.getLength()+count,0)); document.replace(reg.getOffset(), length, rs.getSpaces(0, columns)); } } return result; } /** * Limit the selection to lines that have their beginning included in the original (implied) selection * * @param editor * @param document * @param currentSelection * @return selection starting on first line begin, or null if none * * @throws BadLocationException */ private ITextSelection getImpliedSelection(ITextEditor editor, IDocument document, ITextSelection currentSelection) throws BadLocationException{ ITextSelection result = getImpliedSelection(editor, currentSelection); if (result != null) { IRegion reg = document.getLineInformationOfOffset(result.getOffset()); // line must include beginning of line if (reg.getOffset() != result.getOffset()) { // goto next line reg = document.getLineInformationOfOffset(document.getLineOfOffset(reg.getOffset())+1); int offset = reg.getOffset(); if (offset > result.getOffset() + result.getLength()) { // if we don't even include a single begin line result = null; } else { // last line information reg = document.getLineInformationOfOffset(offset + (result.getLength() - (offset - result.getOffset()))); // get full rectangle (including end of last line) result = new TextSelection(document,offset,(reg.getOffset() + reg.getLength()) - offset); } } } return result; } /** * Get the line information for each line in the region * * @param document * @param selection * @return the array of line regions * * @throws BadLocationException */ private IRegion[] getRegions(IDocument document, ITextSelection selection) throws BadLocationException { int bline = document.getLineOfOffset(selection.getOffset()); int eline = document.getLineOfOffset(selection.getOffset()+selection.getLength()); IRegion[] lines = new IRegion[eline+1-bline]; for (int i = 0; i < lines.length; i++) { lines[i] = document.getLineInformation(bline + i); } return lines; } /** * @see com.mulgasoft.emacsplus.commands.EmacsPlusCmdHandler#isLooping() */ protected boolean isLooping() { return false; } }