PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/jEdit/tags/jedit-4-1-pre5/org/gjt/sp/jedit/Abbrevs.java

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