//----------------------------------------------------------------------------
// COMPONENT NAME: LPEX Editor
//
// All Rights Reserved.
//
// DESCRIPTION:
// DetabCommand - sample user-defined command (detab)
//----------------------------------------------------------------------------
package com.ibm.lpex.samples;
import com.ibm.lpex.core.LpexCommand;
import com.ibm.lpex.core.LpexView;
import com.ibm.lpex.core.LpexStringTokenizer;
/**
* Sample command <b>detab</b> - expand all tabs to spaces.
* It expands all the tab characters in the document to blanks. 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 DetabCommand
* <a href="doc-files/DetabCommand.java.html">source code</a>.</p>
*
* <p>To run this sample:
* <ul>
* <li>Define the command via an editor preference page, where available, or
* from the editor command line:
* <pre>set commandClass.detab com.ibm.lpex.samples.DetabCommand</pre></li>
* <li>Run it from the editor command line:
* <pre>detab [<i>stop1 stop2 ..</i> [every <i>increment</i>]]</pre></li>
* </ul></p>
*
* @see com.ibm.lpex.samples.TestUserProfile
* @see com.ibm.lpex.samples All the samples
*/
public class DetabCommand implements LpexCommand
{
/*
* Run the command.
*/
public boolean doCommand(LpexView lpexView, String parameters)
{
// determine the tab settings to use
Settings currentSettings = new Settings();
if (parameters.trim().length() == 0)
{
parameters = lpexView.query("current.tabs");
}
if (!initSettings(lpexView, parameters, currentSettings))
{
// something wrong with the tab parameters
return false;
}
// expand the tabs in the document
boolean changes = false;
int elements = lpexView.elements();
for (int element = 1; element <= elements; element++)
{
if (!lpexView.show(element))
{
if (expandTabs(element, currentSettings))
{
changes = true;
}
}
}
// indicate successful completion
message(lpexView, changes? "Tabs in document expanded." : "No tabs found in document.");
return true;
}
/**
* Expand the tabs 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 '\t' with a blank and then insert any additional blanks up to the
* tab stop, in order to maintain marks better.</p>
*
* @return indication whether any tabs were expanded in the element
*/
static boolean expandTabs(int element, Settings currentSettings)
{
LpexView lpexView = currentSettings._lpexView;
String text = lpexView.elementText(element);
if (text.indexOf('\t') < 0)
{
return false;
}
StringBuffer buffer = new StringBuffer(text.length() + 32);
boolean mbcs = lpexView.nls().isSourceMbcs();
int tc = 0; // last-used tab stop in currentSettings._tabStops[]
int lastTabVal = 0; // last-used tab stop position
int i = 0; // index into text
int pos = 1; // display column position
for (; i < text.length(); i++)
{
char c = text.charAt(i);
if (c == '\t')
{
while (tc < currentSettings._tabStops.length && lastTabVal <= pos)
{
lastTabVal = currentSettings._tabStops[tc++];
}
while (lastTabVal <= pos)
{
lastTabVal += currentSettings._tabIncrement; // it's non-zero
}
int tabLen = lastTabVal - pos;
for (int j = 0; j < tabLen; j++)
{
buffer.append(' ');
}
pos = lastTabVal; // we're at lastTabVal position now
}
else
{
buffer.append(c);
pos += mbcs? lpexView.nls().sourceWidth(c) : 1;
}
}
lpexView.setElementText(element, buffer.toString());
return true;
}
/**
* Set up the tab stops and the view to use for one run of the command.
*
* @param lpexView document view running the command
* @param tabsString non-null tabs setting, e.g., "1 4 8 every 8"
* @param settings Settings to store the result
*
* @return true = <code>tabsString</code> correct, <code>settings</code> was set
*/
static boolean initSettings(LpexView lpexView, String tabsString, Settings settings)
{
int tabStops[] = null;
int tabIncrement = 1; // if none, tab stop on every character
String token = null;
int lastTabStop = 0;
int count = 1;
// validate, and determine the count of, the tab stops
LpexStringTokenizer st = new LpexStringTokenizer(tabsString);
while (st.hasMoreTokens())
{
token = st.nextToken();
try
{
int tabStop = Integer.parseInt(token);
if (tabStop <= lastTabStop)
{
return incorrectParameter(lpexView, token);
}
if (tabStop != 1)
{
count++;
}
lastTabStop = tabStop;
token = null;
}
catch(NumberFormatException e)
{
break;
}
}
// determine the tab increment
if (token != null)
{
if (!token.equals("every"))
{
return incorrectParameter(lpexView, token);
}
if (!st.hasMoreTokens())
{
return missingParameter(lpexView);
}
token = st.nextToken();
try
{
tabIncrement = Integer.parseInt(token);
if (tabIncrement < 1)
{
return incorrectParameter(lpexView, token);
}
}
catch(NumberFormatException e)
{
return incorrectParameter(lpexView, token);
}
if (st.hasMoreTokens())
{
return incorrectParameter(lpexView, st.nextToken());
}
}
// set up the tab stops
tabStops = new int[count];
tabStops[0] = 1;
int i = 1;
st = new LpexStringTokenizer(tabsString);
while (st.hasMoreTokens() && i < count)
{
try
{
int tabStop = Integer.parseInt(st.nextToken());
if (tabStop != 1)
{
tabStops[i] = tabStop;
i++;
}
}
catch(NumberFormatException e) {}
}
settings._tabStops = tabStops;
settings._tabIncrement = tabIncrement;
settings._lpexView = lpexView;
return true;
}
/**
* Display an incorrect-parameter message on the message line.
*/
static boolean incorrectParameter(LpexView lpexView, String token)
{
message(lpexView, "\""+token+"\" is not a correct parameter for the \"detab\" command.");
return false;
}
/**
* Display a missing-parameter message on the message line.
*/
static boolean missingParameter(LpexView lpexView)
{
message(lpexView, "Additional parameters are required for the \"detab\" command.");
return false;
}
/**
* Display a message on the editor message line.
*/
static void message(LpexView lpexView, String message)
{
lpexView.doDefaultCommand("set messageText " + message);
}
/**
* Settings used during one run of the command.
*/
static class Settings
{
int _tabStops[];
int _tabIncrement;
LpexView _lpexView;
}
}