PageRenderTime 66ms CodeModel.GetById 42ms app.highlight 19ms RepoModel.GetById 0ms app.codeStats 1ms

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