//----------------------------------------------------------------------------
// 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;
}
}