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