PageRenderTime 42ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/Abbrevs.java

#
Java | 591 lines | 399 code | 72 blank | 120 comment | 82 complexity | 8cfe278ab1b9224b2ac8a3dccaebed55 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * Abbrevs.java - Abbreviation manager
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999, 2004 Slava Pestov
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.jedit;
  23. //{{{ Imports
  24. import java.io.*;
  25. import java.util.*;
  26. import org.gjt.sp.jedit.gui.AddAbbrevDialog;
  27. import org.gjt.sp.jedit.textarea.*;
  28. import org.gjt.sp.util.Log;
  29. //}}}
  30. /**
  31. * Abbreviation manager.
  32. * @author Slava Pestov
  33. * @version $Id: Abbrevs.java 5053 2004-05-29 01:55:26Z spestov $
  34. */
  35. public class Abbrevs
  36. {
  37. public static final String ENCODING = "UTF8";
  38. //{{{ getExpandOnInput() method
  39. /**
  40. * Returns if abbreviations should be expanded after the
  41. * user finishes typing a word.
  42. */
  43. public static boolean getExpandOnInput()
  44. {
  45. return expandOnInput;
  46. } //}}}
  47. //{{{ setExpandOnInput() method
  48. /**
  49. * Sets if abbreviations should be expanded after the
  50. * user finishes typing a word.
  51. * @param expandOnInput If true, typing a non-alphanumeric character
  52. * will automatically attempt to expand the current abbrev
  53. */
  54. public static void setExpandOnInput(boolean expandOnInput)
  55. {
  56. Abbrevs.expandOnInput = expandOnInput;
  57. } //}}}
  58. //{{{ expandAbbrev() method
  59. /**
  60. * Expands the abbrev at the caret position in the specified
  61. * view.
  62. * @param view The view
  63. * @param add If true and abbrev not found, will ask user if
  64. * it should be added
  65. * @since jEdit 2.6pre4
  66. */
  67. public static boolean expandAbbrev(View view, boolean add)
  68. {
  69. //{{{ Figure out some minor things
  70. Buffer buffer = view.getBuffer();
  71. JEditTextArea textArea = view.getTextArea();
  72. if(!buffer.isEditable())
  73. {
  74. view.getToolkit().beep();
  75. return false;
  76. }
  77. int line = textArea.getCaretLine();
  78. int lineStart = buffer.getLineStartOffset(line);
  79. int caret = textArea.getCaretPosition();
  80. String lineText = buffer.getLineText(line);
  81. if(lineText.length() == 0)
  82. {
  83. if(add)
  84. view.getToolkit().beep();
  85. return false;
  86. }
  87. int pos = caret - lineStart;
  88. if(pos == 0)
  89. {
  90. if(add)
  91. view.getToolkit().beep();
  92. return false;
  93. } //}}}
  94. // we reuse the 'pp' vector to save time
  95. pp.removeAllElements();
  96. int wordStart;
  97. String abbrev;
  98. //{{{ Handle abbrevs of the form abbrev#pos1#pos2#pos3#...
  99. if(lineText.charAt(pos-1) == '#')
  100. {
  101. wordStart = lineText.indexOf('#');
  102. wordStart = TextUtilities.findWordStart(lineText,wordStart,
  103. buffer.getStringProperty("noWordSep") + '#');
  104. abbrev = lineText.substring(wordStart,pos - 1);
  105. // positional parameters will be inserted where $1, $2, $3, ...
  106. // occurs in the expansion
  107. int lastIndex = 0;
  108. for(int i = 0; i < abbrev.length(); i++)
  109. {
  110. if(abbrev.charAt(i) == '#')
  111. {
  112. pp.addElement(abbrev.substring(lastIndex,i));
  113. lastIndex = i + 1;
  114. }
  115. }
  116. pp.addElement(abbrev.substring(lastIndex));
  117. // the first element of pp is the abbrev itself
  118. abbrev = (String)pp.elementAt(0);
  119. pp.removeElementAt(0);
  120. } //}}}
  121. //{{{ Handle ordinary abbrevs
  122. else
  123. {
  124. wordStart = TextUtilities.findWordStart(lineText,pos - 1,
  125. buffer.getStringProperty("noWordSep"));
  126. abbrev = lineText.substring(wordStart,pos);
  127. } //}}}
  128. Expansion expand = expandAbbrev(buffer.getMode().getName(),
  129. abbrev,(buffer.getBooleanProperty("noTabs") ?
  130. buffer.getTabSize() : 0),pp);
  131. //{{{ Maybe show add abbrev dialog
  132. if(expand == null)
  133. {
  134. if(add)
  135. new AddAbbrevDialog(view,abbrev);
  136. return false;
  137. } //}}}
  138. //{{{ Insert the expansion
  139. else
  140. {
  141. buffer.remove(lineStart + wordStart,
  142. pos - wordStart);
  143. int whitespace = buffer.insertIndented(
  144. lineStart + wordStart,
  145. expand.text);
  146. int newlines = countNewlines(expand.text,
  147. expand.caretPosition);
  148. if(expand.caretPosition != -1)
  149. {
  150. textArea.setCaretPosition(lineStart + wordStart
  151. + expand.caretPosition
  152. + newlines * whitespace);
  153. }
  154. if(expand.posParamCount != pp.size())
  155. {
  156. view.getStatus().setMessageAndClear(
  157. jEdit.getProperty(
  158. "view.status.incomplete-abbrev",
  159. new Integer[] { new Integer(pp.size()),
  160. new Integer(expand.posParamCount) }));
  161. }
  162. return true;
  163. } //}}}
  164. } //}}}
  165. //{{{ getGlobalAbbrevs() method
  166. /**
  167. * Returns the global abbreviation set.
  168. * @since jEdit 2.3pre1
  169. */
  170. public static Hashtable getGlobalAbbrevs()
  171. {
  172. if(!loaded)
  173. load();
  174. return globalAbbrevs;
  175. } //}}}
  176. //{{{ setGlobalAbbrevs() method
  177. /**
  178. * Sets the global abbreviation set.
  179. * @param globalAbbrevs The new global abbrev set
  180. * @since jEdit 2.3pre1
  181. */
  182. public static void setGlobalAbbrevs(Hashtable globalAbbrevs)
  183. {
  184. abbrevsChanged = true;
  185. Abbrevs.globalAbbrevs = globalAbbrevs;
  186. } //}}}
  187. //{{{ getModeAbbrevs() method
  188. /**
  189. * Returns the mode-specific abbreviation set.
  190. * @since jEdit 2.3pre1
  191. */
  192. public static Hashtable getModeAbbrevs()
  193. {
  194. if(!loaded)
  195. load();
  196. return modes;
  197. } //}}}
  198. //{{{ setModeAbbrevs() method
  199. /**
  200. * Sets the mode-specific abbreviation set.
  201. * @param modes The new mode abbrev set
  202. * @since jEdit 2.3pre1
  203. */
  204. public static void setModeAbbrevs(Hashtable modes)
  205. {
  206. abbrevsChanged = true;
  207. Abbrevs.modes = modes;
  208. } //}}}
  209. //{{{ addGlobalAbbrev() method
  210. /**
  211. * Adds an abbreviation to the global abbreviation list.
  212. * @param abbrev The abbreviation
  213. * @param expansion The expansion
  214. * @since jEdit 3.1pre1
  215. */
  216. public static void addGlobalAbbrev(String abbrev, String expansion)
  217. {
  218. if(!loaded)
  219. load();
  220. globalAbbrevs.put(abbrev,expansion);
  221. abbrevsChanged = true;
  222. } //}}}
  223. //{{{ addModeAbbrev() method
  224. /**
  225. * Adds a mode-specific abbrev.
  226. * @param mode The edit mode
  227. * @param abbrev The abbrev
  228. * @param expansion The expansion
  229. * @since jEdit 3.1pre1
  230. */
  231. public static void addModeAbbrev(String mode, String abbrev, String expansion)
  232. {
  233. if(!loaded)
  234. load();
  235. Hashtable modeAbbrevs = (Hashtable)modes.get(mode);
  236. if(modeAbbrevs == null)
  237. {
  238. modeAbbrevs = new Hashtable();
  239. modes.put(mode,modeAbbrevs);
  240. }
  241. modeAbbrevs.put(abbrev,expansion);
  242. abbrevsChanged = true;
  243. } //}}}
  244. //{{{ save() method
  245. static void save()
  246. {
  247. jEdit.setBooleanProperty("view.expandOnInput",expandOnInput);
  248. String settings = jEdit.getSettingsDirectory();
  249. if(abbrevsChanged && settings != null)
  250. {
  251. File file1 = new File(MiscUtilities.constructPath(settings,"#abbrevs#save#"));
  252. File file2 = new File(MiscUtilities.constructPath(settings,"abbrevs"));
  253. if(file2.exists() && file2.lastModified() != abbrevsModTime)
  254. {
  255. Log.log(Log.WARNING,Abbrevs.class,file2 + " changed on disk;"
  256. + " will not save abbrevs");
  257. }
  258. else
  259. {
  260. jEdit.backupSettingsFile(file2);
  261. try
  262. {
  263. saveAbbrevs(new OutputStreamWriter(
  264. new FileOutputStream(file1),
  265. ENCODING));
  266. file2.delete();
  267. file1.renameTo(file2);
  268. }
  269. catch(Exception e)
  270. {
  271. Log.log(Log.ERROR,Abbrevs.class,"Error while saving " + file1);
  272. Log.log(Log.ERROR,Abbrevs.class,e);
  273. }
  274. abbrevsModTime = file2.lastModified();
  275. }
  276. }
  277. } //}}}
  278. //{{{ Private members
  279. //{{{ Instance variables
  280. private static boolean loaded;
  281. private static boolean abbrevsChanged;
  282. private static long abbrevsModTime;
  283. private static boolean expandOnInput;
  284. private static Hashtable globalAbbrevs;
  285. private static Hashtable modes;
  286. private static Vector pp = new Vector();
  287. //}}}
  288. private Abbrevs() {}
  289. static
  290. {
  291. expandOnInput = jEdit.getBooleanProperty("view.expandOnInput");
  292. }
  293. //{{{ load() method
  294. private static void load()
  295. {
  296. globalAbbrevs = new Hashtable();
  297. modes = new Hashtable();
  298. String settings = jEdit.getSettingsDirectory();
  299. if(settings != null)
  300. {
  301. File file = new File(MiscUtilities.constructPath(settings,"abbrevs"));
  302. abbrevsModTime = file.lastModified();
  303. try
  304. {
  305. loadAbbrevs(new InputStreamReader(
  306. new FileInputStream(file),ENCODING));
  307. loaded = true;
  308. }
  309. catch(FileNotFoundException fnf)
  310. {
  311. }
  312. catch(Exception e)
  313. {
  314. Log.log(Log.ERROR,Abbrevs.class,"Error while loading " + file);
  315. Log.log(Log.ERROR,Abbrevs.class,e);
  316. }
  317. }
  318. // only load global abbrevs if user abbrevs file could not be loaded
  319. if(!loaded)
  320. {
  321. try
  322. {
  323. loadAbbrevs(new InputStreamReader(Abbrevs.class
  324. .getResourceAsStream("default.abbrevs"),
  325. ENCODING));
  326. }
  327. catch(Exception e)
  328. {
  329. Log.log(Log.ERROR,Abbrevs.class,"Error while loading default.abbrevs");
  330. Log.log(Log.ERROR,Abbrevs.class,e);
  331. }
  332. loaded = true;
  333. }
  334. } //}}}
  335. //{{{ countNewlines() method
  336. private static int countNewlines(String s, int end)
  337. {
  338. int counter = 0;
  339. for(int i = 0; i < end; i++)
  340. {
  341. if(s.charAt(i) == '\n')
  342. counter++;
  343. }
  344. return counter;
  345. } //}}}
  346. //{{{ expandAbbrev() method
  347. private static Expansion expandAbbrev(String mode, String abbrev,
  348. int softTabSize, Vector pp)
  349. {
  350. if(!loaded)
  351. load();
  352. // try mode-specific abbrevs first
  353. String expand = null;
  354. Hashtable modeAbbrevs = (Hashtable)modes.get(mode);
  355. if(modeAbbrevs != null)
  356. expand = (String)modeAbbrevs.get(abbrev);
  357. if(expand == null)
  358. expand = (String)globalAbbrevs.get(abbrev);
  359. if(expand == null)
  360. return null;
  361. else
  362. return new Expansion(expand,softTabSize,pp);
  363. } //}}}
  364. //{{{ loadAbbrevs() method
  365. private static void loadAbbrevs(Reader _in) throws Exception
  366. {
  367. BufferedReader in = new BufferedReader(_in);
  368. try
  369. {
  370. Hashtable currentAbbrevs = null;
  371. String line;
  372. while((line = in.readLine()) != null)
  373. {
  374. int index = line.indexOf('|');
  375. if(line.length() == 0)
  376. continue;
  377. else if(line.startsWith("[") && index == -1)
  378. {
  379. if(line.equals("[global]"))
  380. currentAbbrevs = globalAbbrevs;
  381. else
  382. {
  383. String mode = line.substring(1,
  384. line.length() - 1);
  385. currentAbbrevs = (Hashtable)modes.get(mode);
  386. if(currentAbbrevs == null)
  387. {
  388. currentAbbrevs = new Hashtable();
  389. modes.put(mode,currentAbbrevs);
  390. }
  391. }
  392. }
  393. else if(index != -1)
  394. {
  395. currentAbbrevs.put(line.substring(0,index),
  396. line.substring(index + 1));
  397. }
  398. }
  399. }
  400. finally
  401. {
  402. in.close();
  403. }
  404. } //}}}
  405. //{{{ saveAbbrevs() method
  406. private static void saveAbbrevs(Writer _out) throws Exception
  407. {
  408. BufferedWriter out = new BufferedWriter(_out);
  409. String lineSep = System.getProperty("line.separator");
  410. // write global abbrevs
  411. out.write("[global]");
  412. out.write(lineSep);
  413. saveAbbrevs(out,globalAbbrevs);
  414. // write mode abbrevs
  415. Enumeration keys = modes.keys();
  416. Enumeration values = modes.elements();
  417. while(keys.hasMoreElements())
  418. {
  419. out.write('[');
  420. out.write((String)keys.nextElement());
  421. out.write(']');
  422. out.write(lineSep);
  423. saveAbbrevs(out,(Hashtable)values.nextElement());
  424. }
  425. out.close();
  426. } //}}}
  427. //{{{ saveAbbrevs() method
  428. private static void saveAbbrevs(Writer out, Hashtable abbrevs)
  429. throws Exception
  430. {
  431. String lineSep = System.getProperty("line.separator");
  432. Enumeration keys = abbrevs.keys();
  433. Enumeration values = abbrevs.elements();
  434. while(keys.hasMoreElements())
  435. {
  436. String abbrev = (String)keys.nextElement();
  437. out.write(abbrev);
  438. out.write('|');
  439. out.write(values.nextElement().toString());
  440. out.write(lineSep);
  441. }
  442. } //}}}
  443. //}}}
  444. //{{{ Expansion class
  445. static class Expansion
  446. {
  447. String text;
  448. int caretPosition = -1;
  449. int lineCount;
  450. // number of positional parameters in abbreviation expansion
  451. int posParamCount;
  452. //{{{ Expansion constructor
  453. Expansion(String text, int softTabSize, Vector pp)
  454. {
  455. StringBuffer buf = new StringBuffer();
  456. boolean backslash = false;
  457. for(int i = 0; i < text.length(); i++)
  458. {
  459. char ch = text.charAt(i);
  460. //{{{ Handle backslash
  461. if(backslash)
  462. {
  463. backslash = false;
  464. if(ch == '|')
  465. caretPosition = buf.length();
  466. else if(ch == 'n')
  467. {
  468. buf.append('\n');
  469. lineCount++;
  470. }
  471. else if(ch == 't')
  472. {
  473. if(softTabSize == 0)
  474. buf.append('\t');
  475. else
  476. {
  477. for(int j = 0; j < softTabSize; j++)
  478. buf.append(' ');
  479. }
  480. }
  481. else
  482. buf.append(ch);
  483. }
  484. else if(ch == '\\')
  485. backslash = true;
  486. //}}}
  487. //{{{ Handle $
  488. else if(ch == '$')
  489. {
  490. if(i != text.length() - 1)
  491. {
  492. ch = text.charAt(i + 1);
  493. if(Character.isDigit(ch) && ch != '0')
  494. {
  495. i++;
  496. int pos = ch - '0';
  497. posParamCount = Math.max(pos,posParamCount);
  498. // $n is 1-indexed, but vector
  499. // contents is zero indexed
  500. if(pos <= pp.size())
  501. buf.append(pp.elementAt(pos - 1));
  502. }
  503. else
  504. {
  505. // $key will be $key, for
  506. // example
  507. buf.append('$');
  508. }
  509. }
  510. else
  511. buf.append('$'); // $ at end is literal
  512. } //}}}
  513. else
  514. buf.append(ch);
  515. }
  516. this.text = buf.toString();
  517. } //}}}
  518. } //}}}
  519. }