/jEdit/tags/jedit-4-3-pre14/org/gjt/sp/util/StandardUtilities.java

# · Java · 491 lines · 306 code · 39 blank · 146 comment · 64 complexity · 34a78db1f89c24661f50b40713a0a972 MD5 · raw file

  1. /*
  2. * StandardUtilities.java - Various miscallaneous utility functions
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999, 2006 Matthieu Casanova, Slava Pestov
  7. * Portions copyright (C) 2000 Richard S. Hall
  8. * Portions copyright (C) 2001 Dirk Moebius
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version 2
  13. * of the License, or any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. */
  24. package org.gjt.sp.util;
  25. //{{{ Imports
  26. import javax.swing.text.Segment;
  27. import java.util.Comparator;
  28. import java.util.Stack;
  29. //}}}
  30. /**
  31. * Several tools that depends on JDK only.
  32. *
  33. * @author Matthieu Casanova
  34. * @version $Id: StandardUtilities.java 12504 2008-04-22 23:12:43Z ezust $
  35. * @since 4.3pre5
  36. */
  37. public class StandardUtilities
  38. {
  39. //{{{ Text methods
  40. //{{{ getPrevIndentStyle() method
  41. /**
  42. * @param str A java string
  43. * @return the leading whitespace of that string, for indenting subsequent lines.
  44. * @since jEdit 4.3pre10
  45. */
  46. public static String getIndentString(String str)
  47. {
  48. StringBuffer indentString = new StringBuffer();
  49. int idx = 0;
  50. char ch = str.charAt(idx);
  51. while (idx < str.length() && Character.isWhitespace(ch)) {
  52. indentString.append(ch);
  53. idx++;
  54. ch = str.charAt(idx);
  55. }
  56. return indentString.toString();
  57. } //}}}
  58. //{{{ getLeadingWhiteSpace() method
  59. /**
  60. * Returns the number of leading white space characters in the
  61. * specified string.
  62. *
  63. * @param str The string
  64. */
  65. public static int getLeadingWhiteSpace(String str)
  66. {
  67. int whitespace = 0;
  68. loop: for(;whitespace < str.length();)
  69. {
  70. switch(str.charAt(whitespace))
  71. {
  72. case ' ':
  73. case '\t':
  74. whitespace++;
  75. break;
  76. default:
  77. break loop;
  78. }
  79. }
  80. return whitespace;
  81. } //}}}
  82. //{{{ getTrailingWhiteSpace() method
  83. /**
  84. * Returns the number of trailing whitespace characters in the
  85. * specified string.
  86. * @param str The string
  87. */
  88. public static int getTrailingWhiteSpace(String str)
  89. {
  90. int whitespace = 0;
  91. loop: for(int i = str.length() - 1; i >= 0; i--)
  92. {
  93. switch(str.charAt(i))
  94. {
  95. case ' ':
  96. case '\t':
  97. whitespace++;
  98. break;
  99. default:
  100. break loop;
  101. }
  102. }
  103. return whitespace;
  104. } //}}}
  105. //{{{ getLeadingWhiteSpaceWidth() method
  106. /**
  107. * Returns the width of the leading white space in the specified
  108. * string.
  109. * @param str The string
  110. * @param tabSize The tab size
  111. */
  112. public static int getLeadingWhiteSpaceWidth(String str, int tabSize)
  113. {
  114. int whitespace = 0;
  115. loop: for(int i = 0; i < str.length(); i++)
  116. {
  117. switch(str.charAt(i))
  118. {
  119. case ' ':
  120. whitespace++;
  121. break;
  122. case '\t':
  123. whitespace += tabSize -
  124. whitespace % tabSize;
  125. break;
  126. default:
  127. break loop;
  128. }
  129. }
  130. return whitespace;
  131. } //}}}
  132. //{{{ createWhiteSpace() method
  133. /**
  134. * Creates a string of white space with the specified length.<p>
  135. *
  136. * To get a whitespace string tuned to the current buffer's
  137. * settings, call this method as follows:
  138. *
  139. * <pre>myWhitespace = MiscUtilities.createWhiteSpace(myLength,
  140. * (buffer.getBooleanProperty("noTabs") ? 0
  141. * : buffer.getTabSize()));</pre>
  142. *
  143. * @param len The length
  144. * @param tabSize The tab size, or 0 if tabs are not to be used
  145. */
  146. public static String createWhiteSpace(int len, int tabSize)
  147. {
  148. return createWhiteSpace(len,tabSize,0);
  149. } //}}}
  150. //{{{ createWhiteSpace() method
  151. /**
  152. * Creates a string of white space with the specified length.<p>
  153. *
  154. * To get a whitespace string tuned to the current buffer's
  155. * settings, call this method as follows:
  156. *
  157. * <pre>myWhitespace = MiscUtilities.createWhiteSpace(myLength,
  158. * (buffer.getBooleanProperty("noTabs") ? 0
  159. * : buffer.getTabSize()));</pre>
  160. *
  161. * @param len The length
  162. * @param tabSize The tab size, or 0 if tabs are not to be used
  163. * @param start The start offset, for tab alignment
  164. */
  165. public static String createWhiteSpace(int len, int tabSize, int start)
  166. {
  167. StringBuilder buf = new StringBuilder();
  168. if(tabSize == 0)
  169. {
  170. while(len-- > 0)
  171. buf.append(' ');
  172. }
  173. else if(len == 1)
  174. buf.append(' ');
  175. else
  176. {
  177. int count = (len + start % tabSize) / tabSize;
  178. if(count != 0)
  179. len += start;
  180. while(count-- > 0)
  181. buf.append('\t');
  182. count = len % tabSize;
  183. while(count-- > 0)
  184. buf.append(' ');
  185. }
  186. return buf.toString();
  187. } //}}}
  188. //{{{ getVirtualWidth() method
  189. /**
  190. * Returns the virtual column number (taking tabs into account) of the
  191. * specified offset in the segment.
  192. *
  193. * @param seg The segment
  194. * @param tabSize The tab size
  195. */
  196. public static int getVirtualWidth(Segment seg, int tabSize)
  197. {
  198. int virtualPosition = 0;
  199. for (int i = 0; i < seg.count; i++)
  200. {
  201. char ch = seg.array[seg.offset + i];
  202. if (ch == '\t')
  203. {
  204. virtualPosition += tabSize
  205. - virtualPosition % tabSize;
  206. }
  207. else
  208. {
  209. ++virtualPosition;
  210. }
  211. }
  212. return virtualPosition;
  213. } //}}}
  214. //{{{ getOffsetOfVirtualColumn() method
  215. /**
  216. * Returns the array offset of a virtual column number (taking tabs
  217. * into account) in the segment.
  218. *
  219. * @param seg The segment
  220. * @param tabSize The tab size
  221. * @param column The virtual column number
  222. * @param totalVirtualWidth If this array is non-null, the total
  223. * virtual width will be stored in its first location if this method
  224. * returns -1.
  225. *
  226. * @return -1 if the column is out of bounds
  227. */
  228. public static int getOffsetOfVirtualColumn(Segment seg, int tabSize,
  229. int column, int[] totalVirtualWidth)
  230. {
  231. int virtualPosition = 0;
  232. for (int i = 0; i < seg.count; i++)
  233. {
  234. char ch = seg.array[seg.offset + i];
  235. if (ch == '\t')
  236. {
  237. int tabWidth = tabSize
  238. - virtualPosition % tabSize;
  239. if(virtualPosition >= column)
  240. return i;
  241. else
  242. virtualPosition += tabWidth;
  243. }
  244. else
  245. {
  246. if(virtualPosition >= column)
  247. return i;
  248. else
  249. ++virtualPosition;
  250. }
  251. }
  252. if(totalVirtualWidth != null)
  253. totalVirtualWidth[0] = virtualPosition;
  254. return -1;
  255. } //}}}
  256. //{{{ compareStrings() method
  257. /**
  258. * Compares two strings.<p>
  259. *
  260. * Unlike <function>String.compareTo()</function>,
  261. * this method correctly recognizes and handles embedded numbers.
  262. * For example, it places "My file 2" before "My file 10".<p>
  263. *
  264. * @param str1 The first string
  265. * @param str2 The second string
  266. * @param ignoreCase If true, case will be ignored
  267. * @return negative If str1 &lt; str2, 0 if both are the same,
  268. * positive if str1 &gt; str2
  269. * @since jEdit 4.3pre5
  270. */
  271. public static int compareStrings(String str1, String str2, boolean ignoreCase)
  272. {
  273. char[] char1 = str1.toCharArray();
  274. char[] char2 = str2.toCharArray();
  275. int len = Math.min(char1.length,char2.length);
  276. for(int i = 0, j = 0; i < len && j < len; i++, j++)
  277. {
  278. char ch1 = char1[i];
  279. char ch2 = char2[j];
  280. if(Character.isDigit(ch1) && Character.isDigit(ch2)
  281. && ch1 != '0' && ch2 != '0')
  282. {
  283. int _i = i + 1;
  284. int _j = j + 1;
  285. for(; _i < char1.length; _i++)
  286. {
  287. if(!Character.isDigit(char1[_i]))
  288. {
  289. //_i--;
  290. break;
  291. }
  292. }
  293. for(; _j < char2.length; _j++)
  294. {
  295. if(!Character.isDigit(char2[_j]))
  296. {
  297. //_j--;
  298. break;
  299. }
  300. }
  301. int len1 = _i - i;
  302. int len2 = _j - j;
  303. if(len1 > len2)
  304. return 1;
  305. else if(len1 < len2)
  306. return -1;
  307. else
  308. {
  309. for(int k = 0; k < len1; k++)
  310. {
  311. ch1 = char1[i + k];
  312. ch2 = char2[j + k];
  313. if(ch1 != ch2)
  314. return ch1 - ch2;
  315. }
  316. }
  317. i = _i - 1;
  318. j = _j - 1;
  319. }
  320. else
  321. {
  322. if(ignoreCase)
  323. {
  324. ch1 = Character.toLowerCase(ch1);
  325. ch2 = Character.toLowerCase(ch2);
  326. }
  327. if(ch1 != ch2)
  328. return ch1 - ch2;
  329. }
  330. }
  331. return char1.length - char2.length;
  332. } //}}}
  333. //{{{ StringCompare class
  334. /**
  335. * Compares objects as strings.
  336. */
  337. public static class StringCompare implements Comparator
  338. {
  339. public int compare(Object obj1, Object obj2)
  340. {
  341. return compareStrings(obj1.toString(),
  342. obj2.toString(),false);
  343. }
  344. } //}}}
  345. //{{{ objectsEqual() method
  346. /**
  347. * Returns if two strings are equal. This correctly handles null pointers,
  348. * as opposed to calling <code>o1.equals(o2)</code>.
  349. * @since jEdit 4.3pre6
  350. */
  351. public static boolean objectsEqual(Object o1, Object o2)
  352. {
  353. if(o1 == null)
  354. {
  355. if(o2 == null)
  356. return true;
  357. else
  358. return false;
  359. }
  360. else if(o2 == null)
  361. return false;
  362. else
  363. return o1.equals(o2);
  364. } //}}}
  365. //{{{ globToRE() method
  366. /**
  367. * Converts a Unix-style glob to a regular expression.<p>
  368. *
  369. * ? becomes ., * becomes .*, {aa,bb} becomes (aa|bb).
  370. * @param glob The glob pattern
  371. * @since jEdit 4.3pre7
  372. */
  373. public static String globToRE(String glob)
  374. {
  375. if (glob.startsWith("(re)"))
  376. {
  377. return glob.substring(4);
  378. }
  379. final Object NEG = new Object();
  380. final Object GROUP = new Object();
  381. Stack state = new Stack();
  382. StringBuffer buf = new StringBuffer();
  383. boolean backslash = false;
  384. for(int i = 0; i < glob.length(); i++)
  385. {
  386. char c = glob.charAt(i);
  387. if(backslash)
  388. {
  389. buf.append('\\');
  390. buf.append(c);
  391. backslash = false;
  392. continue;
  393. }
  394. switch(c)
  395. {
  396. case '\\':
  397. backslash = true;
  398. break;
  399. case '?':
  400. buf.append('.');
  401. break;
  402. case '.':
  403. case '+':
  404. case '(':
  405. case ')':
  406. buf.append('\\');
  407. buf.append(c);
  408. break;
  409. case '*':
  410. buf.append(".*");
  411. break;
  412. case '|':
  413. if(backslash)
  414. buf.append("\\|");
  415. else
  416. buf.append('|');
  417. break;
  418. case '{':
  419. buf.append('(');
  420. if(i + 1 != glob.length() && glob.charAt(i + 1) == '!')
  421. {
  422. buf.append('?');
  423. state.push(NEG);
  424. }
  425. else
  426. state.push(GROUP);
  427. break;
  428. case ',':
  429. if(!state.isEmpty() && state.peek() == GROUP)
  430. buf.append('|');
  431. else
  432. buf.append(',');
  433. break;
  434. case '}':
  435. if(!state.isEmpty())
  436. {
  437. buf.append(")");
  438. if(state.pop() == NEG)
  439. buf.append(".*");
  440. }
  441. else
  442. buf.append('}');
  443. break;
  444. default:
  445. buf.append(c);
  446. }
  447. }
  448. return buf.toString();
  449. } //}}}
  450. //}}}
  451. private StandardUtilities(){}
  452. }