//---------------------------------------------------------------------------- // COMPONENT NAME: LPEX Editor // // © Copyright IBM Corporation 2004, 2007 // All Rights Reserved. // // DESCRIPTION: // EntabCommand - sample user-defined command (entab) //---------------------------------------------------------------------------- package com.ibm.lpex.samples; import com.ibm.lpex.core.LpexCommand; import com.ibm.lpex.core.LpexView; /** * Sample command <b>entab</b> - compress leading spaces to tabs. * It compresses leading blanks in the document to tab characters. By default, it * uses the value of the <b>tabs</b> editor parameter in the current view. * Alternatively, the tab settings may be specified via the command parameters. * * <p>Here is the EntabCommand * <a href="doc-files/EntabCommand.java.html">source code</a>. * This class shares several methods with {@link DetabCommand}.</p> * * <p>To run this sample: * <ul> * <li>Define this user command via an editor preference page, where available, * or from the editor command line: * <pre>set commandClass.entab com.ibm.lpex.samples.EntabCommand</pre></li> * <li>Run it from the editor command line: * <pre>entab [<i>stop1 stop2 ..</i> [every <i>increment</i>]]</pre></li> * </ul></p> * * @see com.ibm.lpex.samples.DetabCommand * @see com.ibm.lpex.samples All the samples */ public class EntabCommand implements LpexCommand { /** * Runs this command. * Compresses leading spaces in the document to tabs. * * @param lpexView the document view in which the command was issued * @param parameters optional tab stops */ public boolean doCommand(LpexView lpexView, String parameters) { parameters = parameters.trim(); if ("?".equals(parameters)) // command help { if (lpexView != null) { lpexView.doCommand("set messageText Syntax: entab [<tab stop> .. [every <increment>]]"); } return true; } // if no view, just validate the parameters (if any) if (lpexView == null) { return DetabCommand.validSettings(parameters); } // determine and validate the tab settings to use DetabCommand.Settings currentSettings = new DetabCommand.Settings(); if (!DetabCommand.initSettings(lpexView, parameters, currentSettings, TestCommand.commandName(this, lpexView))) { return false; } // compress spaces in the document boolean changes = compressBlanks(lpexView, currentSettings); // indicate successful completion lpexView.doCommand("set messageText " + (changes? "Spaces in document compressed." : "No spaces in document compressed.")); return true; } /** * Compresses leading spaces in the document, according to the given settings. * * @return indication whether spaces were compressed in the document */ boolean compressBlanks(LpexView lpexView, DetabCommand.Settings currentSettings) { // remember original cursor location on the screen int originalElement = lpexView.currentElement(); int originalPosition = lpexView.queryInt("displayPosition"); // process all non-show elements boolean changes = false; int elements = lpexView.elements(); for (int element = 1; element <= elements; element++) { if (!lpexView.show(element)) { if (compressBlanks(element, currentSettings)) { changes = true; } } } // restore the cursor if (changes && (lpexView.currentElement() != originalElement || lpexView.queryInt("displayPosition") != originalPosition)) { lpexView.jump(originalElement, 1); lpexView.doCommand("set displayPosition " + originalPosition); } return changes; } /** * Compresses leading spaces in a non-show element, according to the given settings. * Tabs are interpreted in terms of display columns. * * <p>Currently, we change the entire element text - could be subtler and * replace one blank with '\t' and then delete any additional blanks up to the * tab stop, in order to maintain marks better.</p> * * @return indication whether spaces were compressed in the element */ boolean compressBlanks(int element, DetabCommand.Settings currentSettings) { LpexView lpexView = currentSettings._lpexView; String text = lpexView.elementText(element); if (text.indexOf(' ') < 0) { return false; // empty line / no spaces. } StringBuilder buffer = new StringBuilder(text.length()); int tc = 0; // last-used tab stop in currentSettings._tabStops[] int lastTabVal = 0; // last-used tab stop position int i = 0; // current index into text int pos = 1; // current display column position int iRest = 0; // rest-of-line index in text boolean changes = false; // meaningful changes to the text? boolean leadingSpaces = false; // coalesce " \t" into "\t" for (; i < text.length(); i++) { // establish relevant tab stop while (tc < currentSettings._tabStops.length && lastTabVal <= pos) { lastTabVal = currentSettings._tabStops[tc++]; } while (lastTabVal <= pos) { lastTabVal += currentSettings._tabIncrement; // NB it's non-zero } char c = text.charAt(i); if (c == ' ') { if (pos == lastTabVal - 1) { buffer.append('\t'); iRest = i + 1; changes = true; } else { leadingSpaces = true; } pos++; } else if (c == '\t') { buffer.append('\t'); iRest = i + 1; if (leadingSpaces) { changes = true; } pos = lastTabVal; // we'll be at lastTabVal display column position } else { break; } } if (changes) { if (iRest < text.length()) { buffer.append(text.substring(iRest)); } lpexView.setElementText(element, buffer.toString()); } return changes; } }