PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

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

#
Java | 574 lines | 385 code | 67 blank | 122 comment | 75 complexity | 93c15aac96f0ce263523ebfb650ac02e 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 3970 2002-01-16 09:21:51Z 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. } //}}}
  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.beginCompoundEdit();
  142. try
  143. {
  144. // obtain the leading indent for later use
  145. lineText = buffer.getText(lineStart,wordStart);
  146. int leadingIndent = MiscUtilities.getLeadingWhiteSpaceWidth(
  147. lineText,buffer.getTabSize());
  148. buffer.remove(lineStart + wordStart,pos - wordStart);
  149. buffer.insert(lineStart + wordStart,expand.text);
  150. if(expand.caretPosition != -1)
  151. {
  152. textArea.setCaretPosition(lineStart + wordStart
  153. + expand.caretPosition);
  154. }
  155. String whiteSpace = MiscUtilities.createWhiteSpace(
  156. leadingIndent,buffer.getBooleanProperty("noTabs")
  157. ? 0 : buffer.getTabSize());
  158. // note that if expand.lineCount is 0, we
  159. // don't do any indentation at all
  160. for(int i = line + 1; i <= line + expand.lineCount; i++)
  161. {
  162. buffer.insert(buffer.getLineStartOffset(i),
  163. whiteSpace);
  164. }
  165. }
  166. finally
  167. {
  168. buffer.endCompoundEdit();
  169. }
  170. return true;
  171. } //}}}
  172. } //}}}
  173. //{{{ getGlobalAbbrevs() method
  174. /**
  175. * Returns the global abbreviation set.
  176. * @since jEdit 2.3pre1
  177. */
  178. public static Hashtable getGlobalAbbrevs()
  179. {
  180. if(!loaded)
  181. load();
  182. return globalAbbrevs;
  183. } //}}}
  184. //{{{ setGlobalAbbrevs() method
  185. /**
  186. * Sets the global abbreviation set.
  187. * @param globalAbbrevs The new global abbrev set
  188. * @since jEdit 2.3pre1
  189. */
  190. public static void setGlobalAbbrevs(Hashtable globalAbbrevs)
  191. {
  192. abbrevsChanged = true;
  193. Abbrevs.globalAbbrevs = globalAbbrevs;
  194. } //}}}
  195. //{{{ getModeAbbrevs() method
  196. /**
  197. * Returns the mode-specific abbreviation set.
  198. * @since jEdit 2.3pre1
  199. */
  200. public static Hashtable getModeAbbrevs()
  201. {
  202. if(!loaded)
  203. load();
  204. return modes;
  205. } //}}}
  206. //{{{ setModeAbbrevs() method
  207. /**
  208. * Sets the mode-specific abbreviation set.
  209. * @param globalAbbrevs The new global abbrev set
  210. * @since jEdit 2.3pre1
  211. */
  212. public static void setModeAbbrevs(Hashtable modes)
  213. {
  214. abbrevsChanged = true;
  215. Abbrevs.modes = modes;
  216. } //}}}
  217. //{{{ addGlobalAbbrev() method
  218. /**
  219. * Adds an abbreviation to the global abbreviation list.
  220. * @param abbrev The abbreviation
  221. * @param expansion The expansion
  222. * @since jEdit 3.1pre1
  223. */
  224. public static void addGlobalAbbrev(String abbrev, String expansion)
  225. {
  226. if(!loaded)
  227. load();
  228. globalAbbrevs.put(abbrev,expansion);
  229. abbrevsChanged = true;
  230. } //}}}
  231. //{{{ addModeAbbrev() method
  232. /**
  233. * Adds a mode-specific abbrev.
  234. * @param mode The edit mode
  235. * @param abbrev The abbrev
  236. * @param expansion The expansion
  237. * @since jEdit 3.1pre1
  238. */
  239. public static void addModeAbbrev(String mode, String abbrev, String expansion)
  240. {
  241. if(!loaded)
  242. load();
  243. Hashtable modeAbbrevs = (Hashtable)modes.get(mode);
  244. if(modeAbbrevs == null)
  245. {
  246. modeAbbrevs = new Hashtable();
  247. modes.put(mode,modeAbbrevs);
  248. }
  249. modeAbbrevs.put(abbrev,expansion);
  250. abbrevsChanged = true;
  251. } //}}}
  252. //{{{ save() method
  253. static void save()
  254. {
  255. jEdit.setBooleanProperty("view.expandOnInput",expandOnInput);
  256. String settings = jEdit.getSettingsDirectory();
  257. if(abbrevsChanged && settings != null)
  258. {
  259. File file1 = new File(MiscUtilities.constructPath(settings,"#abbrevs#save#"));
  260. File file2 = new File(MiscUtilities.constructPath(settings,"abbrevs"));
  261. if(file2.exists() && file2.lastModified() != abbrevsModTime)
  262. {
  263. Log.log(Log.WARNING,Abbrevs.class,file2 + " changed on disk;"
  264. + " will not save abbrevs");
  265. }
  266. else
  267. {
  268. jEdit.backupSettingsFile(file2);
  269. try
  270. {
  271. saveAbbrevs(new FileWriter(file1));
  272. }
  273. catch(Exception e)
  274. {
  275. Log.log(Log.ERROR,Abbrevs.class,"Error while saving " + file1);
  276. Log.log(Log.ERROR,Abbrevs.class,e);
  277. }
  278. file2.delete();
  279. file1.renameTo(file2);
  280. abbrevsModTime = file2.lastModified();
  281. }
  282. }
  283. } //}}}
  284. //{{{ Private members
  285. //{{{ Instance variables
  286. private static boolean loaded;
  287. private static boolean abbrevsChanged;
  288. private static long abbrevsModTime;
  289. private static boolean expandOnInput;
  290. private static Hashtable globalAbbrevs;
  291. private static Hashtable modes;
  292. private static Vector pp = new Vector();
  293. //}}}
  294. private Abbrevs() {}
  295. static
  296. {
  297. expandOnInput = jEdit.getBooleanProperty("view.expandOnInput");
  298. }
  299. //{{{ load() method
  300. private static void load()
  301. {
  302. globalAbbrevs = new Hashtable();
  303. modes = new Hashtable();
  304. String settings = jEdit.getSettingsDirectory();
  305. if(settings != null)
  306. {
  307. File file = new File(MiscUtilities.constructPath(settings,"abbrevs"));
  308. abbrevsModTime = file.lastModified();
  309. try
  310. {
  311. loadAbbrevs(new FileReader(file));
  312. loaded = true;
  313. }
  314. catch(FileNotFoundException fnf)
  315. {
  316. }
  317. catch(Exception e)
  318. {
  319. Log.log(Log.ERROR,Abbrevs.class,"Error while loading " + file);
  320. Log.log(Log.ERROR,Abbrevs.class,e);
  321. }
  322. }
  323. // only load global abbrevs if user abbrevs file could not be loaded
  324. if(!loaded)
  325. {
  326. try
  327. {
  328. loadAbbrevs(new InputStreamReader(Abbrevs.class
  329. .getResourceAsStream("default.abbrevs")));
  330. }
  331. catch(Exception e)
  332. {
  333. Log.log(Log.ERROR,Abbrevs.class,"Error while loading default.abbrevs");
  334. Log.log(Log.ERROR,Abbrevs.class,e);
  335. }
  336. loaded = true;
  337. }
  338. } //}}}
  339. //{{{ expandAbbrev() method
  340. private static Expansion expandAbbrev(String mode, String abbrev,
  341. int softTabSize, Vector pp)
  342. {
  343. if(!loaded)
  344. load();
  345. // try mode-specific abbrevs first
  346. String expand = null;
  347. Hashtable modeAbbrevs = (Hashtable)modes.get(mode);
  348. if(modeAbbrevs != null)
  349. expand = (String)modeAbbrevs.get(abbrev);
  350. if(expand == null)
  351. expand = (String)globalAbbrevs.get(abbrev);
  352. if(expand == null)
  353. return null;
  354. else
  355. return new Expansion(expand,softTabSize,pp);
  356. } //}}}
  357. //{{{ loadAbbrevs() method
  358. private static void loadAbbrevs(Reader _in) throws Exception
  359. {
  360. BufferedReader in = new BufferedReader(_in);
  361. Hashtable currentAbbrevs = null;
  362. String line;
  363. while((line = in.readLine()) != null)
  364. {
  365. if(line.length() == 0)
  366. continue;
  367. else if(line.startsWith("[") && line.indexOf('|') == -1)
  368. {
  369. if(line.equals("[global]"))
  370. currentAbbrevs = globalAbbrevs;
  371. else
  372. {
  373. String mode = line.substring(1,
  374. line.length() - 1);
  375. currentAbbrevs = (Hashtable)modes.get(mode);
  376. if(currentAbbrevs == null)
  377. {
  378. currentAbbrevs = new Hashtable();
  379. modes.put(mode,currentAbbrevs);
  380. }
  381. }
  382. }
  383. else
  384. {
  385. int index = line.indexOf('|');
  386. currentAbbrevs.put(line.substring(0,index),
  387. line.substring(index + 1));
  388. }
  389. }
  390. in.close();
  391. } //}}}
  392. //{{{ saveAbbrevs() method
  393. private static void saveAbbrevs(Writer _out) throws Exception
  394. {
  395. BufferedWriter out = new BufferedWriter(_out);
  396. String lineSep = System.getProperty("line.separator");
  397. // write global abbrevs
  398. out.write("[global]");
  399. out.write(lineSep);
  400. saveAbbrevs(out,globalAbbrevs);
  401. // write mode abbrevs
  402. Enumeration keys = modes.keys();
  403. Enumeration values = modes.elements();
  404. while(keys.hasMoreElements())
  405. {
  406. out.write('[');
  407. out.write((String)keys.nextElement());
  408. out.write(']');
  409. out.write(lineSep);
  410. saveAbbrevs(out,(Hashtable)values.nextElement());
  411. }
  412. out.close();
  413. } //}}}
  414. //{{{ saveAbbrevs() method
  415. private static void saveAbbrevs(Writer out, Hashtable abbrevs)
  416. throws Exception
  417. {
  418. String lineSep = System.getProperty("line.separator");
  419. Enumeration keys = abbrevs.keys();
  420. Enumeration values = abbrevs.elements();
  421. while(keys.hasMoreElements())
  422. {
  423. String abbrev = (String)keys.nextElement();
  424. out.write(abbrev);
  425. out.write('|');
  426. out.write(values.nextElement().toString());
  427. out.write(lineSep);
  428. }
  429. } //}}}
  430. //}}}
  431. //{{{ Expansion class
  432. static class Expansion
  433. {
  434. String text;
  435. int caretPosition = -1;
  436. int lineCount;
  437. //{{{ Expansion constructor
  438. Expansion(String text, int softTabSize, Vector pp)
  439. {
  440. StringBuffer buf = new StringBuffer();
  441. boolean backslash = false;
  442. for(int i = 0; i < text.length(); i++)
  443. {
  444. char ch = text.charAt(i);
  445. //{{{ Handle backslash
  446. if(backslash)
  447. {
  448. backslash = false;
  449. if(ch == '|')
  450. caretPosition = buf.length();
  451. else if(ch == 'n')
  452. {
  453. buf.append('\n');
  454. lineCount++;
  455. }
  456. else if(ch == 't')
  457. {
  458. if(softTabSize == 0)
  459. buf.append('\t');
  460. else
  461. {
  462. for(int j = 0; j < softTabSize; j++)
  463. buf.append(' ');
  464. }
  465. }
  466. else
  467. buf.append(ch);
  468. }
  469. else if(ch == '\\')
  470. backslash = true;
  471. //}}}
  472. //{{{ Handle $
  473. else if(ch == '$')
  474. {
  475. if(i != text.length() - 1)
  476. {
  477. ch = text.charAt(i + 1);
  478. if(Character.isDigit(ch) && ch != '0')
  479. {
  480. i++;
  481. int pos = ch - '0';
  482. if(pos < pp.size())
  483. buf.append(pp.elementAt(pos));
  484. else
  485. {
  486. // so the user knows
  487. // a positional is
  488. // expected
  489. buf.append('$');
  490. buf.append(ch);
  491. }
  492. }
  493. else
  494. {
  495. // $key will be $key, for
  496. // example
  497. buf.append('$');
  498. }
  499. }
  500. } //}}}
  501. else
  502. buf.append(ch);
  503. }
  504. this.text = buf.toString();
  505. } //}}}
  506. } //}}}
  507. }