PageRenderTime 298ms CodeModel.GetById 257ms app.highlight 35ms RepoModel.GetById 1ms app.codeStats 1ms

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

#
Java | 560 lines | 371 code | 65 blank | 124 comment | 70 complexity | a784ace79ebfc9e2fd24ed52009a8196 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 3852 2001-10-24 08:18:09Z 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		return globalAbbrevs;
206	} //}}}
207
208	//{{{ setGlobalAbbrevs() method
209	/**
210	 * Sets the global abbreviation set.
211	 * @param globalAbbrevs The new global abbrev set
212	 * @since jEdit 2.3pre1
213	 */
214	public static void setGlobalAbbrevs(Hashtable globalAbbrevs)
215	{
216		abbrevsChanged = true;
217		Abbrevs.globalAbbrevs = globalAbbrevs;
218	} //}}}
219
220	//{{{ getModeAbbrevs() method
221	/**
222	 * Returns the mode-specific abbreviation set.
223	 * @since jEdit 2.3pre1
224	 */
225	public static Hashtable getModeAbbrevs()
226	{
227		return modes;
228	} //}}}
229
230	//{{{ setModeAbbrevs() method
231	/**
232	 * Sets the mode-specific abbreviation set.
233	 * @param globalAbbrevs The new global abbrev set
234	 * @since jEdit 2.3pre1
235	 */
236	public static void setModeAbbrevs(Hashtable modes)
237	{
238		abbrevsChanged = true;
239		Abbrevs.modes = modes;
240	} //}}}
241
242	//{{{ addGlobalAbbrev() method
243	/**
244	 * Adds an abbreviation to the global abbreviation list.
245	 * @param abbrev The abbreviation
246	 * @param expansion The expansion
247	 * @since jEdit 3.1pre1
248	 */
249	public static void addGlobalAbbrev(String abbrev, String expansion)
250	{
251		globalAbbrevs.put(abbrev,expansion);
252		abbrevsChanged = true;
253	} //}}}
254
255	//{{{ addModeAbbrev() method
256	/**
257	 * Adds a mode-specific abbrev.
258	 * @param mode The edit mode
259	 * @param abbrev The abbrev
260	 * @param expansion The expansion
261	 * @since jEdit 3.1pre1
262	 */
263	public static void addModeAbbrev(String mode, String abbrev, String expansion)
264	{
265		Hashtable modeAbbrevs = (Hashtable)modes.get(mode);
266		if(modeAbbrevs == null)
267		{
268			modeAbbrevs = new Hashtable();
269			modes.put(mode,modeAbbrevs);
270		}
271		modeAbbrevs.put(abbrev,expansion);
272		abbrevsChanged = true;
273	} //}}}
274
275	//{{{ Package-private members
276
277	//{{{ load() method
278	static void load()
279	{
280		expandOnInput = jEdit.getBooleanProperty("view.expandOnInput");
281
282		globalAbbrevs = new Hashtable();
283		modes = new Hashtable();
284
285		boolean loaded = false;
286
287		String settings = jEdit.getSettingsDirectory();
288		if(settings != null)
289		{
290			File file = new File(MiscUtilities.constructPath(settings,"abbrevs"));
291			abbrevsModTime = file.lastModified();
292
293			try
294			{
295				loadAbbrevs(new FileReader(file));
296				loaded = true;
297			}
298			catch(FileNotFoundException fnf)
299			{
300			}
301			catch(Exception e)
302			{
303				Log.log(Log.ERROR,Abbrevs.class,"Error while loading " + file);
304				Log.log(Log.ERROR,Abbrevs.class,e);
305			}
306		}
307
308		// only load global abbrevs if user abbrevs file could not be loaded
309		if(!loaded)
310		{
311			try
312			{
313				loadAbbrevs(new InputStreamReader(Abbrevs.class
314					.getResourceAsStream("default.abbrevs")));
315			}
316			catch(Exception e)
317			{
318				Log.log(Log.ERROR,Abbrevs.class,"Error while loading default.abbrevs");
319				Log.log(Log.ERROR,Abbrevs.class,e);
320			}
321		}
322	} //}}}
323
324	//{{{ save() method
325	static void save()
326	{
327		jEdit.setBooleanProperty("view.expandOnInput",expandOnInput);
328
329		String settings = jEdit.getSettingsDirectory();
330		if(abbrevsChanged && settings != null)
331		{
332			File file1 = new File(MiscUtilities.constructPath(settings,"#abbrevs#save#"));
333			File file2 = new File(MiscUtilities.constructPath(settings,"abbrevs"));
334			if(file2.exists() && file2.lastModified() != abbrevsModTime)
335			{
336				Log.log(Log.WARNING,Abbrevs.class,file2 + " changed on disk;"
337					+ " will not save abbrevs");
338			}
339			else
340			{
341				jEdit.backupSettingsFile(file2);
342
343				try
344				{
345					saveAbbrevs(new FileWriter(file1));
346				}
347				catch(Exception e)
348				{
349					Log.log(Log.ERROR,Abbrevs.class,"Error while saving " + file1);
350					Log.log(Log.ERROR,Abbrevs.class,e);
351				}
352				file2.delete();
353				file1.renameTo(file2);
354				abbrevsModTime = file2.lastModified();
355			}
356		}
357	} //}}}
358
359	//}}}
360
361	//{{{ Private members
362
363	//{{{ Instance variables
364	private static boolean abbrevsChanged;
365	private static long abbrevsModTime;
366	private static boolean expandOnInput;
367	private static Hashtable globalAbbrevs;
368	private static Hashtable modes;
369	private static Vector pp = new Vector();
370	//}}}
371
372	private Abbrevs() {}
373
374	//{{{ expandAbbrev() method
375	private static Expansion expandAbbrev(String mode, String abbrev,
376		int softTabSize, Vector pp)
377	{
378		// try mode-specific abbrevs first
379		String expand = null;
380		Hashtable modeAbbrevs = (Hashtable)modes.get(mode);
381		if(modeAbbrevs != null)
382			expand = (String)modeAbbrevs.get(abbrev);
383
384		if(expand == null)
385			expand = (String)globalAbbrevs.get(abbrev);
386
387		if(expand == null)
388			return null;
389		else
390			return new Expansion(expand,softTabSize,pp);
391	} //}}}
392
393	//{{{ loadAbbrevs() method
394	private static void loadAbbrevs(Reader _in) throws Exception
395	{
396		BufferedReader in = new BufferedReader(_in);
397
398		Hashtable currentAbbrevs = null;
399
400		String line;
401		while((line = in.readLine()) != null)
402		{
403			if(line.length() == 0)
404				continue;
405			else if(line.startsWith("[") && line.indexOf('|') == -1)
406			{
407				if(line.equals("[global]"))
408					currentAbbrevs = globalAbbrevs;
409				else
410				{
411					String mode = line.substring(1,
412						line.length() - 1);
413					currentAbbrevs = (Hashtable)modes.get(mode);
414					if(currentAbbrevs == null)
415					{
416						currentAbbrevs = new Hashtable();
417						modes.put(mode,currentAbbrevs);
418					}
419				}
420			}
421			else
422			{
423				int index = line.indexOf('|');
424				currentAbbrevs.put(line.substring(0,index),
425					line.substring(index + 1));
426			}
427		}
428
429		in.close();
430	} //}}}
431
432	//{{{ saveAbbrevs() method
433	private static void saveAbbrevs(Writer _out) throws Exception
434	{
435		BufferedWriter out = new BufferedWriter(_out);
436		String lineSep = System.getProperty("line.separator");
437
438		// write global abbrevs
439		out.write("[global]");
440		out.write(lineSep);
441
442		saveAbbrevs(out,globalAbbrevs);
443
444		// write mode abbrevs
445		Enumeration keys = modes.keys();
446		Enumeration values = modes.elements();
447		while(keys.hasMoreElements())
448		{
449			out.write('[');
450			out.write((String)keys.nextElement());
451			out.write(']');
452			out.write(lineSep);
453			saveAbbrevs(out,(Hashtable)values.nextElement());
454		}
455
456		out.close();
457	} //}}}
458
459	//{{{ saveAbbrevs() method
460	private static void saveAbbrevs(Writer out, Hashtable abbrevs)
461		throws Exception
462	{
463		String lineSep = System.getProperty("line.separator");
464
465		Enumeration keys = abbrevs.keys();
466		Enumeration values = abbrevs.elements();
467		while(keys.hasMoreElements())
468		{
469			String abbrev = (String)keys.nextElement();
470			out.write(abbrev);
471			out.write('|');
472			out.write(values.nextElement().toString());
473			out.write(lineSep);
474		}
475	} //}}}
476
477	//}}}
478
479	//{{{ Expansion class
480	static class Expansion
481	{
482		String text;
483		int caretPosition = -1;
484		int lineCount;
485
486		//{{{ Expansion constructor
487		Expansion(String text, int softTabSize, Vector pp)
488		{
489			StringBuffer buf = new StringBuffer();
490			boolean backslash = false;
491
492			for(int i = 0; i < text.length(); i++)
493			{
494				char ch = text.charAt(i);
495				//{{{ Handle backslash
496				if(backslash)
497				{
498					backslash = false;
499
500					if(ch == '|')
501						caretPosition = buf.length();
502					else if(ch == 'n')
503					{
504						buf.append('\n');
505						lineCount++;
506					}
507					else if(ch == 't')
508					{
509						if(softTabSize == 0)
510							buf.append('\t');
511						else
512						{
513							for(int j = 0; j < softTabSize; j++)
514								buf.append(' ');
515						}
516					}
517					else
518						buf.append(ch);
519				}
520				else if(ch == '\\')
521					backslash = true;
522				//}}}
523				//{{{ Handle $
524				else if(ch == '$')
525				{
526					if(i != text.length() - 1)
527					{
528						ch = text.charAt(i + 1);
529						if(Character.isDigit(ch) && ch != '0')
530						{
531							i++;
532
533							int pos = ch - '0';
534							if(pos < pp.size())
535								buf.append(pp.elementAt(pos));
536							else
537							{
538								// so the user knows
539								// a positional is
540								// expected
541								buf.append('$');
542								buf.append(ch);
543							}
544						}
545						else
546						{
547							// $key will be $key, for
548							// example
549							buf.append('$');
550						}
551					}
552				} //}}}
553				else
554					buf.append(ch);
555			}
556
557			this.text = buf.toString();
558		} //}}}
559	} //}}}
560}