org.gjt.sp.jedit.jEdit Maven / Gradle / Ivy
/*
* jEdit.java - Main class of the jEdit editor
* :tabSize=8:indentSize=8:noTabs=false:
* :folding=explicit:collapseFolds=1:
*
* Copyright (C) 1998, 2005 Slava Pestov
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.gjt.sp.jedit;
//{{{ Imports
import java.awt.Color;
import java.awt.Component;
import java.awt.DefaultKeyboardFocusManager;
import java.awt.Font;
import java.awt.Frame;
import java.awt.KeyboardFocusManager;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.net.Authenticator;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.Socket;
import java.net.URL;
import java.net.URLDecoder;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.EventObject;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Vector;
import javax.swing.Box;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.LayoutFocusTraversalPolicy;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import org.gjt.sp.jedit.bsh.UtilEvalError;
import org.gjt.sp.jedit.buffer.FoldHandler;
import org.gjt.sp.jedit.buffer.JEditBuffer;
import org.gjt.sp.jedit.buffer.KillRing;
import org.gjt.sp.jedit.bufferio.BufferIORequest;
import org.gjt.sp.jedit.gui.DefaultInputHandler;
import org.gjt.sp.jedit.gui.InputHandler;
import org.gjt.sp.jedit.io.VFS;
import org.gjt.sp.jedit.io.VFSManager;
import org.gjt.sp.jedit.msg.BufferUpdate;
import org.gjt.sp.jedit.msg.DynamicMenuChanged;
import org.gjt.sp.jedit.msg.EditorExitRequested;
import org.gjt.sp.jedit.msg.EditorExiting;
import org.gjt.sp.jedit.msg.PropertiesChanged;
import org.gjt.sp.jedit.msg.ViewUpdate;
import org.gjt.sp.jedit.syntax.ModeProvider;
import org.gjt.sp.jedit.syntax.TokenMarker;
import org.gjt.sp.jedit.syntax.XModeHandler;
import org.gjt.sp.jedit.textarea.JEditTextArea;
import org.gjt.sp.jedit.textarea.Selection;
import org.gjt.sp.jedit.textarea.TextArea;
import org.gjt.sp.jedit.visitors.JEditVisitor;
import org.gjt.sp.util.IOUtilities;
import org.gjt.sp.util.Log;
import org.gjt.sp.util.StandardUtilities;
import org.gjt.sp.util.SyntaxUtilities;
import org.gjt.sp.util.XMLUtilities;
import org.xml.sax.SAXParseException;
/**
* The main class of the jEdit text editor.
* @author Slava Pestov
* @version $Id: jEdit.java 13207 2008-08-06 12:19:50Z kpouer $
*/
public class jEdit
{
//{{{ getVersion() method
/**
* Returns the jEdit version as a human-readable string.
*/
public static String getVersion()
{
return MiscUtilities.buildToVersion(getBuild());
} //}}}
//{{{ getBuild() method
/**
* Returns the internal version. MiscUtilities.compareStrings() can be used
* to compare different internal versions.
*/
public static String getBuild()
{
// (major).(minor).(<99 = preX, 99 = final).(bug fix)
return "04.03.15.00";
} //}}}
//{{{ main() method
/**
* The main method of the jEdit application.
* This should never be invoked directly.
* @param args The command line arguments
*/
public static void main(String[] args)
{
//{{{ Check for Java 1.5 or later
String javaVersion = System.getProperty("java.version");
if(javaVersion.compareTo("1.5") < 0)
{
System.err.println("You are running Java version "
+ javaVersion + '.');
System.err.println("jEdit requires Java 1.5 or later.");
System.exit(1);
} //}}}
// later on we need to know if certain code is called from
// the main thread
mainThread = Thread.currentThread();
settingsDirectory = ".jedit";
// MacOS users expect the app to keep running after all windows
// are closed
background = OperatingSystem.isMacOS();
//{{{ Parse command line
boolean endOpts = false;
int level = Log.WARNING;
String portFile = "server";
boolean restore = true;
boolean newView = true;
boolean newPlainView = false;
boolean gui = true; // open initial view?
boolean loadPlugins = true;
boolean runStartupScripts = true;
boolean quit = false;
boolean wait = false;
String userDir = System.getProperty("user.dir");
// script to run
String scriptFile = null;
for(int i = 0; i < args.length; i++)
{
String arg = args[i];
if(arg == null)
continue;
else if(arg.length() == 0)
args[i] = null;
else if(arg.startsWith("-") && !endOpts)
{
if(arg.equals("--"))
endOpts = true;
else if(arg.equals("-usage"))
{
version();
System.err.println();
usage();
System.exit(1);
}
else if(arg.equals("-version"))
{
version();
System.exit(1);
}
else if(arg.startsWith("-log="))
{
try
{
level = Integer.parseInt(arg.substring("-log=".length()));
}
catch(NumberFormatException nf)
{
System.err.println("Malformed option: " + arg);
}
}
else if(arg.equals("-nosettings"))
settingsDirectory = null;
else if(arg.startsWith("-settings="))
settingsDirectory = arg.substring(10);
else if(arg.startsWith("-noserver"))
portFile = null;
else if(arg.equals("-server"))
portFile = "server";
else if(arg.startsWith("-server="))
portFile = arg.substring(8);
else if(arg.startsWith("-background"))
background = true;
else if(arg.startsWith("-nobackground"))
background = false;
else if(arg.equals("-gui"))
gui = true;
else if(arg.equals("-nogui"))
gui = false;
else if(arg.equals("-newview"))
newView = true;
else if(arg.equals("-newplainview"))
newPlainView = true;
else if(arg.equals("-reuseview"))
newPlainView = newView = false;
else if(arg.equals("-restore"))
restore = true;
else if(arg.equals("-norestore"))
restore = false;
else if(arg.equals("-plugins"))
loadPlugins = true;
else if(arg.equals("-noplugins"))
loadPlugins = false;
else if(arg.equals("-startupscripts"))
runStartupScripts = true;
else if(arg.equals("-nostartupscripts"))
runStartupScripts = false;
else if(arg.startsWith("-run="))
scriptFile = arg.substring(5);
else if(arg.equals("-wait"))
wait = true;
else if(arg.equals("-quit"))
quit = true;
else
{
System.err.println("Unknown option: "
+ arg);
usage();
System.exit(1);
}
args[i] = null;
}
} //}}}
//{{{ We need these initializations very early on
if(settingsDirectory != null)
{
settingsDirectory = MiscUtilities.constructPath(
System.getProperty("user.home"),
settingsDirectory);
settingsDirectory = MiscUtilities.resolveSymlinks(
settingsDirectory);
}
if(settingsDirectory != null && portFile != null)
portFile = MiscUtilities.constructPath(settingsDirectory,portFile);
else
portFile = null;
Log.init(true,level);
//}}}
//{{{ Try connecting to another running jEdit instance
if(portFile != null && new File(portFile).exists())
{
try
{
BufferedReader in = new BufferedReader(new FileReader(portFile));
String check = in.readLine();
if(!check.equals("b"))
throw new Exception("Wrong port file format");
int port = Integer.parseInt(in.readLine());
int key = Integer.parseInt(in.readLine());
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),port);
DataOutputStream out = new DataOutputStream(
socket.getOutputStream());
out.writeInt(key);
String script;
if(quit)
{
script = "socket.close();\n"
+ "jEdit.exit(null,true);\n";
}
else
{
script = makeServerScript(wait,restore,
newView,newPlainView,args,
scriptFile);
}
out.writeUTF(script);
Log.log(Log.DEBUG,jEdit.class,"Waiting for server");
// block until its closed
try
{
socket.getInputStream().read();
}
catch(Exception e)
{
}
in.close();
out.close();
System.exit(0);
}
catch(Exception e)
{
// ok, this one seems to confuse newbies
// endlessly, so log it as NOTICE, not
// ERROR
Log.log(Log.NOTICE,jEdit.class,"An error occurred"
+ " while connecting to the jEdit server instance.");
Log.log(Log.NOTICE,jEdit.class,"This probably means that"
+ " jEdit crashed and/or exited abnormally");
Log.log(Log.NOTICE,jEdit.class,"the last time it was run.");
Log.log(Log.NOTICE,jEdit.class,"If you don't"
+ " know what this means, don't worry.");
Log.log(Log.NOTICE,jEdit.class,e);
}
}
if(quit)
{
// if no server running and user runs jedit -quit,
// just exit
System.exit(0);
} //}}}
//{{{ Initialize settings directory
Writer stream;
if(settingsDirectory != null)
{
File _settingsDirectory = new File(settingsDirectory);
if(!_settingsDirectory.exists())
_settingsDirectory.mkdirs();
File _macrosDirectory = new File(settingsDirectory,"macros");
if(!_macrosDirectory.exists())
_macrosDirectory.mkdir();
String logPath = MiscUtilities.constructPath(
settingsDirectory,"activity.log");
backupSettingsFile(new File(logPath));
try
{
stream = new BufferedWriter(new FileWriter(logPath));
// Write a warning message:
String lineSep = System.getProperty("line.separator");
stream.write("Log file created on " + new Date());
stream.write(lineSep);
stream.write("IMPORTANT:");
stream.write(lineSep);
stream.write("Because updating this file after "
+ "every log message would kill");
stream.write(lineSep);
stream.write("performance, it will be *incomplete* "
+ "unless you invoke the");
stream.write(lineSep);
stream.write("Utilities->Troubleshooting->Update "
+ "Activity Log on Disk command!");
stream.write(lineSep);
}
catch(Exception e)
{
e.printStackTrace();
stream = null;
}
}
else
{
stream = null;
} //}}}
Log.setLogWriter(stream);
Log.log(Log.NOTICE,jEdit.class,"jEdit version " + getVersion());
Log.log(Log.MESSAGE,jEdit.class,"Settings directory is "
+ settingsDirectory);
//{{{ Get things rolling
initMisc();
initSystemProperties();
if(jEditHome != null)
initSiteProperties();
initUserProperties();
///Options.SIMPLIFIED_KEY_HANDLING = jEdit.getBooleanProperty("newkeyhandling");
//}}}
//{{{ Initialize server
if(portFile != null)
{
}
else
{
if(background)
{
background = false;
Log.log(Log.WARNING,jEdit.class,"You cannot specify both the"
+ " -background and -noserver switches");
}
} //}}}
//{{{ Do more stuff
VFSManager.init();
initResources();
if(loadPlugins)
{
initPlugins();
}
BufferHistory.load();
KillRing.setInstance(new JEditKillRing());
KillRing.getInstance().load();
propertiesChanged();
// Buffer sort
sortBuffers = getBooleanProperty("sortBuffers");
sortByName = getBooleanProperty("sortByName");
reloadModes();
//}}}
if(runStartupScripts && jEditHome != null)
{
String path = MiscUtilities.constructPath(jEditHome,"startup");
File file = new File(path);
if(file.exists())
{
runStartupScripts(file);
}
}
if(runStartupScripts && settingsDirectory != null)
{
String path = MiscUtilities.constructPath(settingsDirectory,"startup");
File file = new File(path);
if (file.exists())
{
runStartupScripts(file);
}
else
{
file.mkdirs();
}
}
// Open files, create the view and hide the splash screen.
SyntaxUtilities.propertyManager = jEdit.propertyManager;
finishStartup(gui,restore,userDir,args);
} //}}}
//{{{ Property methods
//{{{ getProperties() method
/**
* Returns the properties object which contains all known
* jEdit properties. Note that as of jEdit 4.2pre10, this returns a
* new collection, not the existing properties instance.
* @since jEdit 3.1pre4
*/
public static Properties getProperties()
{
return propMgr.getProperties();
} //}}}
//{{{ getProperty() method
/**
* Fetches a property, returning null if it's not defined.
* @param name The property
*/
public static String getProperty(String name)
{
return propMgr.getProperty(name);
} //}}}
//{{{ getProperty() method
/**
* Fetches a property, returning the default value if it's not
* defined.
* @param name The property
* @param def The default value
*/
public static String getProperty(String name, String def)
{
String value = propMgr.getProperty(name);
if(value == null)
return def;
else
return value;
} //}}}
//{{{ getProperty() method
/**
* Returns the property with the specified name.
*
* The elements of the args
array are substituted
* into the value of the property in place of strings of the
* form {n}
, where n
is an index
* in the array.
*
* You can find out more about this feature by reading the
* documentation for the format
method of the
* java.text.MessageFormat
class.
*
* @param name The property
* @param args The positional parameters
*/
public static String getProperty(String name, Object[] args)
{
if(name == null)
return null;
if(args == null)
return getProperty(name);
else
{
String value = getProperty(name);
if(value == null)
return null;
else
return MessageFormat.format(value,args);
}
} //}}}
//{{{ getBooleanProperty() method
/**
* Returns the value of a boolean property.
* @param name The property
*/
public static boolean getBooleanProperty(String name)
{
return getBooleanProperty(name,false);
} //}}}
//{{{ getBooleanProperty() method
/**
* Returns the value of a boolean property.
* @param name The property
* @param def The default value
*/
public static boolean getBooleanProperty(String name, boolean def)
{
String value = getProperty(name);
if(value == null)
return def;
else if(value.equals("true") || value.equals("yes")
|| value.equals("on"))
return true;
else if(value.equals("false") || value.equals("no")
|| value.equals("off"))
return false;
else
return def;
} //}}}
//{{{ getIntegerProperty() method
/**
* Returns the value of an integer property.
* @param name The property
*/
public static int getIntegerProperty(String name)
{
return getIntegerProperty(name,0);
} //}}}
//{{{ getIntegerProperty() method
/**
* Returns the value of an integer property.
* @param name The property
* @param def The default value
* @since jEdit 4.0pre1
*/
public static int getIntegerProperty(String name, int def)
{
String value = getProperty(name);
if(value == null)
return def;
else
{
try
{
return Integer.parseInt(value.trim());
}
catch(NumberFormatException nf)
{
return def;
}
}
} //}}}
//{{{ getDoubleProperty() method
public static double getDoubleProperty(String name, double def)
{
String value = getProperty(name);
if(value == null)
return def;
else
{
try
{
return Double.parseDouble(value.trim());
}
catch(NumberFormatException nf)
{
return def;
}
}
}
//}}}
//{{{ getFontProperty() method
/**
* Returns the value of a font property. The family is stored
* in the name
property, the font size is stored
* in the namesize
property, and the font style is
* stored in namestyle
. For example, if
* name
is view.gutter.font
, the
* properties will be named view.gutter.font
,
* view.gutter.fontsize
, and
* view.gutter.fontstyle
.
*
* @param name The property
* @since jEdit 4.0pre1
*/
public static Font getFontProperty(String name)
{
return getFontProperty(name,null);
} //}}}
//{{{ getFontProperty() method
/**
* Returns the value of a font property. The family is stored
* in the name
property, the font size is stored
* in the namesize
property, and the font style is
* stored in namestyle
. For example, if
* name
is view.gutter.font
, the
* properties will be named view.gutter.font
,
* view.gutter.fontsize
, and
* view.gutter.fontstyle
.
*
* @param name The property
* @param def The default value
* @since jEdit 4.0pre1
*/
public static Font getFontProperty(String name, Font def)
{
String family = getProperty(name);
String sizeString = getProperty(name + "size");
String styleString = getProperty(name + "style");
if(family == null || sizeString == null || styleString == null)
return def;
else
{
int size, style;
try
{
size = Integer.parseInt(sizeString);
}
catch(NumberFormatException nf)
{
return def;
}
try
{
style = Integer.parseInt(styleString);
}
catch(NumberFormatException nf)
{
return def;
}
return new Font(family,style,size);
}
} //}}}
//{{{ getColorProperty() method
/**
* Returns the value of a color property.
* @param name The property name
* @since jEdit 4.0pre1
*/
public static Color getColorProperty(String name)
{
return getColorProperty(name,Color.black);
} //}}}
//{{{ getColorProperty() method
/**
* Returns the value of a color property.
* @param name The property name
* @param def The default value
* @since jEdit 4.0pre1
*/
public static Color getColorProperty(String name, Color def)
{
String value = getProperty(name);
if(value == null)
return def;
else
return SyntaxUtilities.parseColor(value, def);
} //}}}
//{{{ setColorProperty() method
/**
* Sets the value of a color property.
* @param name The property name
* @param value The value
* @since jEdit 4.0pre1
*/
public static void setColorProperty(String name, Color value)
{
setProperty(name, SyntaxUtilities.getColorHexString(value));
} //}}}
//{{{ setProperty() method
/**
* Sets a property to a new value.
* @param name The property
* @param value The new value
*/
public static void setProperty(String name, String value)
{
propMgr.setProperty(name,value);
} //}}}
//{{{ setTemporaryProperty() method
/**
* Sets a property to a new value. Properties set using this
* method are not saved to the user properties list.
* @param name The property
* @param value The new value
* @since jEdit 2.3final
*/
public static void setTemporaryProperty(String name, String value)
{
propMgr.setTemporaryProperty(name,value);
} //}}}
//{{{ setBooleanProperty() method
/**
* Sets a boolean property.
* @param name The property
* @param value The value
*/
public static void setBooleanProperty(String name, boolean value)
{
setProperty(name,value ? "true" : "false");
} //}}}
//{{{ setIntegerProperty() method
/**
* Sets the value of an integer property.
* @param name The property
* @param value The value
* @since jEdit 4.0pre1
*/
public static void setIntegerProperty(String name, int value)
{
setProperty(name,String.valueOf(value));
} //}}}
//{{{ setDoubleProperty() method
public static void setDoubleProperty(String name, double value)
{
setProperty(name,String.valueOf(value));
}
//}}}
//{{{ setFontProperty() method
/**
* Sets the value of a font property. The family is stored
* in the name
property, the font size is stored
* in the namesize
property, and the font style is
* stored in namestyle
. For example, if
* name
is view.gutter.font
, the
* properties will be named view.gutter.font
,
* view.gutter.fontsize
, and
* view.gutter.fontstyle
.
*
* @param name The property
* @param value The value
* @since jEdit 4.0pre1
*/
public static void setFontProperty(String name, Font value)
{
setProperty(name,value.getFamily());
setIntegerProperty(name + "size",value.getSize());
setIntegerProperty(name + "style",value.getStyle());
} //}}}
//{{{ unsetProperty() method
/**
* Unsets (clears) a property.
* @param name The property
*/
public static void unsetProperty(String name)
{
propMgr.unsetProperty(name);
} //}}}
//{{{ resetProperty() method
/**
* Resets a property to its default value.
* @param name The property
*
* @since jEdit 2.5pre3
*/
public static void resetProperty(String name)
{
propMgr.resetProperty(name);
} //}}}
//{{{ propertiesChanged() method
/**
* Reloads various settings from the properties.
*/
public static void propertiesChanged()
{
initKeyBindings();
saveCaret = getBooleanProperty("saveCaret");
UIDefaults defaults = UIManager.getDefaults();
// give all text areas the same font
Font font = getFontProperty("view.font");
//defaults.put("TextField.font",font);
defaults.put("TextArea.font",font);
defaults.put("TextPane.font",font);
// Enable/Disable tooltips
ToolTipManager.sharedInstance().setEnabled(
jEdit.getBooleanProperty("showTooltips"));
initProxy();
// we do this here instead of adding buffers to the bus.
Buffer buffer = buffersFirst;
while(buffer != null)
{
buffer.resetCachedProperties();
buffer.propertiesChanged();
buffer = buffer.next;
}
KillRing.getInstance().propertiesChanged(getIntegerProperty("history",25));
EditBus.send(new PropertiesChanged(null));
} //}}}
//}}}
//{{{ Plugin management methods
//{{{ getNotLoadedPluginJARs() method
/**
* Returns a list of plugin JARs pathnames that are not currently loaded
* by examining the user and system plugin directories.
* @since jEdit 3.2pre1
*/
public static String[] getNotLoadedPluginJARs()
{
List returnValue = new ArrayList();
if(jEditHome != null)
{
String systemPluginDir = MiscUtilities
.constructPath(jEditHome,"jars");
String[] list = new File(systemPluginDir).list();
if(list != null)
getNotLoadedPluginJARs(returnValue,systemPluginDir,list);
}
if(settingsDirectory != null)
{
String userPluginDir = MiscUtilities
.constructPath(settingsDirectory,"jars");
String[] list = new File(userPluginDir).list();
if(list != null)
{
getNotLoadedPluginJARs(returnValue,
userPluginDir,list);
}
}
String[] _returnValue = new String[returnValue.size()];
returnValue.toArray(_returnValue);
return _returnValue;
} //}}}
//{{{ addPluginJARsFromDirectory() method
/**
* Loads all plugins in a directory.
* @param directory The directory
* @since jEdit 4.2pre1
*/
private static void addPluginJARsFromDirectory(String directory)
{
Log.log(Log.NOTICE,jEdit.class,"Loading plugins from "
+ directory);
File file = new File(directory);
if(!(file.exists() && file.isDirectory()))
return;
String[] plugins = file.list();
if(plugins == null)
return;
for(int i = 0; i < plugins.length; i++)
{
String plugin = plugins[i];
if(!plugin.toLowerCase().endsWith(".jar"))
continue;
String path = MiscUtilities.constructPath(directory,plugin);
if (jEdit.getBooleanProperty("plugin-blacklist."+plugin))
continue;
// remove this when 4.1 plugin API is deprecated
if(plugin.equals("EditBuddy.jar")
|| plugin.equals("PluginManager.jar")
|| plugin.equals("Firewall.jar")
|| plugin.equals("Tidy.jar")
|| plugin.equals("DragAndDrop.jar"))
{
pluginError(path,"plugin-error.obsolete",null);
continue;
}
}
} //}}}
//}}}
//{{{ Action methods
//{{{ getActionContext() method
/**
* Returns the action context used to store editor actions.
* @since jEdit 4.2pre1
*/
public static ActionContext getActionContext()
{
return actionContext;
} //}}}
//{{{ getActionNames() method
/**
* Returns all registered action names.
*/
public static String[] getActionNames()
{
return actionContext.getActionNames();
} //}}}
//}}}
//{{{ Edit mode methods
//{{{ reloadModes() method
/**
* Reloads all edit modes.
* @since jEdit 3.2pre2
*/
public static void reloadModes()
{
/* Try to guess the eventual size to avoid unnecessary
* copying */
ModeProvider.instance.removeAll();
//{{{ Load the global catalog
if(jEditHome == null)
loadModeCatalog("/modes/catalog",true);
else
{
loadModeCatalog(MiscUtilities.constructPath(jEditHome,
"modes","catalog"),false);
} //}}}
//{{{ Load user catalog
if(settingsDirectory != null)
{
File userModeDir = new File(MiscUtilities.constructPath(
settingsDirectory,"modes"));
if(!userModeDir.exists())
userModeDir.mkdirs();
File userCatalog = new File(MiscUtilities.constructPath(
settingsDirectory,"modes","catalog"));
if(!userCatalog.exists())
{
// create dummy catalog
FileWriter out = null;
try
{
out = new FileWriter(userCatalog);
out.write(jEdit.getProperty("defaultCatalog"));
}
catch(IOException io)
{
Log.log(Log.ERROR,jEdit.class,io);
}
finally
{
IOUtilities.closeQuietly(out);
}
}
loadModeCatalog(userCatalog.getPath(),false);
} //}}}
Buffer buffer = buffersFirst;
while(buffer != null)
{
// This reloads the token marker and sends a message
// which causes edit panes to repaint their text areas
buffer.setMode();
buffer = buffer.next;
}
} //}}}
//{{{ getMode() method
/**
* Returns the edit mode with the specified name.
* @param name The edit mode
*/
public static Mode getMode(String name)
{
return ModeProvider.instance.getMode(name);
} //}}}
//{{{ getModes() method
/**
* Returns an array of installed edit modes.
*/
public static Mode[] getModes()
{
return ModeProvider.instance.getModes();
} //}}}
//}}}
//{{{ Buffer creation methods
//{{{ openFiles() method
/**
* Opens the file names specified in the argument array. This
* handles +line and +marker arguments just like the command
* line parser.
* @param parent The parent directory
* @param args The file names to open
* @since jEdit 3.2pre4
*/
public static Buffer openFiles(View view, String parent, String[] args)
{
Buffer retVal = null;
Buffer lastBuffer = null;
for(int i = 0; i < args.length; i++)
{
String arg = args[i];
if(arg == null)
continue;
else if(arg.startsWith("+line:") || arg.startsWith("+marker:"))
{
if(lastBuffer != null)
gotoMarker(view,lastBuffer,arg);
continue;
}
lastBuffer = openFile(null,parent,arg,false,null);
if(retVal == null && lastBuffer != null)
retVal = lastBuffer;
}
if(view != null && retVal != null)
view.setBuffer(retVal,true);
return retVal;
} //}}}
//{{{ openFile() methods
/**
* Opens a file. Note that as of jEdit 2.5pre1, this may return
* null if the buffer could not be opened.
* @param view The view to open the file in
* @param path The file path
*
* @return the buffer, or null if jEdit was unable to load it
*
* @since jEdit 2.4pre1
*/
public static Buffer openFile(View view, String path)
{
return openFile(view,null,path,false,new Hashtable());
}
/**
* @deprecated The openFile() forms with the readOnly parameter
* should not be used. The readOnly prameter is no longer supported.
*/
@Deprecated
public static Buffer openFile(View view, String parent,
String path, boolean readOnly, boolean newFile)
{
return openFile(view,parent,path,newFile,new Hashtable());
}
/**
* @deprecated The openFile() forms with the readOnly parameter
* should not be used. The readOnly prameter is no longer supported.
*/
@Deprecated
public static Buffer openFile(View view, String parent,
String path, boolean readOnly, boolean newFile,
Hashtable props)
{
return openFile(view,parent,path,newFile,props);
}
/**
* Opens a file. This may return null if the buffer could not be
* opened for some reason.
* @param view The view to open the file in. If it is null, the file
* will be opened and added to the bufferSet of the current edit pane,
* but not selected
* @param parent The parent directory of the file
* @param path The path name of the file
* @param newFile True if the file should not be loaded from disk
* be prompted if it should be reloaded
* @param props Buffer-local properties to set in the buffer
*
* @return the buffer, or null if jEdit was unable to load it
*
* @since jEdit 3.2pre10
*/
public static Buffer openFile(View view, String parent,
String path, boolean newFile, Hashtable props)
{
if(view != null && parent == null)
parent = view.getBuffer().getDirectory();
try
{
URL u = new URL(path);
if (u.getProtocol().equals("file"))
path = URLDecoder.decode(u.getPath());
}
catch (MalformedURLException mue)
{
path = MiscUtilities.constructPath(parent,path);
}
if(props == null)
props = new Hashtable();
composeBufferPropsFromHistory(props, path);
Buffer newBuffer;
synchronized (editBusOrderingLock)
{
synchronized(bufferListLock)
{
Buffer buffer = getBuffer(path);
if(buffer != null)
{
if(view != null)
view.setBuffer(buffer,true);
return buffer;
}
newBuffer = new Buffer(path,newFile,false,props);
if(!newBuffer.load(view,false))
return null;
addBufferToList(newBuffer);
}
EditBus.send(new BufferUpdate(newBuffer,view,BufferUpdate.CREATED));
}
if(view != null)
view.setBuffer(newBuffer,true);
return newBuffer;
} //}}}
//{{{ openTemporary() methods
/**
* Opens a temporary buffer. A temporary buffer is like a normal
* buffer, except that an event is not fired, the the buffer is
* not added to the buffers list.
*
* @param view The view to open the file in
* @param parent The parent directory of the file
* @param path The path name of the file
* @param newFile True if the file should not be loaded from disk
*
* @return the buffer, or null if jEdit was unable to load it
*
* @since jEdit 3.2pre10
*/
public static Buffer openTemporary(View view, String parent,
String path, boolean newFile)
{
return openTemporary(view, parent, path, newFile, null);
}
/**
* Opens a temporary buffer. A temporary buffer is like a normal
* buffer, except that an event is not fired, the the buffer is
* not added to the buffers list.
*
* @param view The view to open the file in
* @param parent The parent directory of the file
* @param path The path name of the file
* @param newFile True if the file should not be loaded from disk
* @param props Buffer-local properties to set in the buffer
*
* @return the buffer, or null if jEdit was unable to load it
*
* @since jEdit 4.3pre10
*/
public static Buffer openTemporary(View view, String parent,
String path, boolean newFile, Hashtable props)
{
if(view != null && parent == null)
parent = view.getBuffer().getDirectory();
if(MiscUtilities.isURL(path))
{
if(MiscUtilities.getProtocolOfURL(path).equals("file"))
path = path.substring(5);
}
path = MiscUtilities.constructPath(parent,path);
if(props == null)
props = new Hashtable();
composeBufferPropsFromHistory(props, path);
synchronized(bufferListLock)
{
Buffer buffer = getBuffer(path);
if(buffer != null)
return buffer;
buffer = new Buffer(path,newFile,true,props);
buffer.setBooleanProperty(Buffer.ENCODING_AUTODETECT, true);
if(!buffer.load(view,false))
return null;
else
return buffer;
}
} //}}}
//{{{ commitTemporary() method
/**
* Adds a temporary buffer to the buffer list. This must be done
* before allowing the user to interact with the buffer in any
* way.
* @param buffer The buffer
*/
public static void commitTemporary(Buffer buffer)
{
if(!buffer.isTemporary())
return;
addBufferToList(buffer);
buffer.commitTemporary();
// send full range of events to avoid breaking plugins
EditBus.send(new BufferUpdate(buffer,null,BufferUpdate.CREATED));
EditBus.send(new BufferUpdate(buffer,null,BufferUpdate.LOAD_STARTED));
EditBus.send(new BufferUpdate(buffer,null,BufferUpdate.LOADED));
} //}}}
//{{{ newFile() method
/**
* Creates a new `untitled' file.
*
* @param view The view to create the file in
*
* @return the new buffer
*/
public static Buffer newFile(View view)
{
String path;
if(view != null && view.getBuffer() != null)
{
path = view.getBuffer().getDirectory();
VFS vfs = VFSManager.getVFSForPath(path);
// don't want 'New File' to create a read only buffer
// if current file is on SQL VFS or something
if((vfs.getCapabilities() & VFS.WRITE_CAP) == 0)
path = System.getProperty("user.home");
}
else
path = null;
return newFile(view,path);
} //}}}
//{{{ newFile() method
/**
* Creates a new `untitled' file.
* @param view The view to create the file in
* @param dir The directory to create the file in
*
* @return the new buffer
*
* @since jEdit 3.1pre2
*/
public static Buffer newFile(View view, String dir)
{
// Find the highest Untitled-n file
int untitledCount = getNextUntitledBufferId();
return openFile(view,dir,"Untitled-" + untitledCount,true,null);
} //}}}
//}}}
//{{{ Buffer management methods
//{{{ closeBuffer() method
/**
* Closes a buffer. If there are unsaved changes, the user is
* prompted if they should be saved first.
* @param view The view
* @param buffer The buffer
* @return True if the buffer was really closed, false otherwise
*/
public static boolean closeBuffer(View view, Buffer buffer)
{
if(buffer.isDirty())
{
Object[] args = { buffer.getName() };
}
_closeBuffer(view,buffer);
return true;
} //}}}
//{{{ _closeBuffer() method
/**
* Closes the buffer, even if it has unsaved changes.
* @param view The view, may be null
* @param buffer The buffer
*
* @exception NullPointerException if the buffer is null
*
* @since jEdit 2.2pre1
*/
public static void _closeBuffer(View view, Buffer buffer)
{
if(buffer.isClosed())
{
// can happen if the user presses C+w twice real
// quick and the buffer has unsaved changes
return;
}
if(!buffer.isNewFile())
{
Integer _caret = (Integer)buffer.getProperty(Buffer.CARET);
int caret = _caret == null ? 0 : _caret.intValue();
BufferHistory.setEntry(buffer.getPath(),caret,
(Selection[])buffer.getProperty(Buffer.SELECTION),
buffer.getStringProperty(JEditBuffer.ENCODING),
buffer.getMode().getName());
}
String path = buffer.getSymlinkPath();
if((VFSManager.getVFSForPath(path).getCapabilities()
& VFS.CASE_INSENSITIVE_CAP) != 0)
{
path = path.toLowerCase();
}
EditBus.send(new BufferUpdate(buffer,view,BufferUpdate.CLOSING));
bufferHash.remove(path);
removeBufferFromList(buffer);
buffer.close();
EditBus.send(new BufferUpdate(buffer,view,BufferUpdate.CLOSED));
if(jEdit.getBooleanProperty("persistentMarkers"))
buffer.updateMarkersFile(view);
} //}}}
//{{{ closeAllBuffers() methods
/**
* Closes all open buffers.
* @param view The view
*
* @return true if all buffers were closed, false otherwise
*/
public static boolean closeAllBuffers(View view)
{
return closeAllBuffers(view,false);
}
/**
* Closes all open buffers.
* @param view The view
* @param isExiting This must be false unless this method is
* being called by the exit() method
*
* @return true if all buffers were closed, false otherwise
*/
public static boolean closeAllBuffers(View view, boolean isExiting)
{
boolean dirty = false;
boolean saveRecent = !(isExiting && jEdit.getBooleanProperty("restore"));
Buffer buffer = buffersFirst;
while(buffer != null)
{
if(buffer.isDirty())
{
dirty = true;
break;
}
buffer = buffer.next;
}
// Wait for pending I/O requests
if(VFSManager.errorOccurred())
return false;
// close remaining buffers (the close dialog only deals with
// dirty ones)
buffer = buffersFirst;
// zero it here so that BufferTabs doesn't have any problems
buffersFirst = buffersLast = null;
bufferHash.clear();
bufferCount = 0;
while(buffer != null)
{
if(!buffer.isNewFile() && saveRecent)
{
Integer _caret = (Integer)buffer.getProperty(Buffer.CARET);
int caret = _caret == null ? 0 : _caret.intValue();
BufferHistory.setEntry(buffer.getPath(),caret,
(Selection[])buffer.getProperty(Buffer.SELECTION),
buffer.getStringProperty(JEditBuffer.ENCODING),
buffer.getMode().getName());
}
buffer.close();
if(jEdit.getBooleanProperty("persistentMarkers"))
buffer.updateMarkersFile(view);
buffer = buffer.next;
}
return true;
} //}}}
//{{{ saveAllBuffers() method
/**
* Saves all open buffers.
* @param view The view
* @since jEdit 4.2pre1
*/
public static void saveAllBuffers(View view)
{
saveAllBuffers(view,jEdit.getBooleanProperty("confirmSaveAll"));
} //}}}
//{{{ saveAllBuffers() method
/**
* Saves all open buffers.
* @param view The view
* @param confirm If true, a confirmation dialog will be shown first
* @since jEdit 2.7pre2
*/
public static void saveAllBuffers(View view, boolean confirm)
{
Buffer current = view.getBuffer();
Buffer buffer = buffersFirst;
while(buffer != null)
{
if(buffer.isDirty())
{
if(buffer.isNewFile())
view.setBuffer(buffer,true);
buffer.save(view,null,true,true);
}
buffer = buffer.next;
}
view.setBuffer(current,true);
} //}}}
//{{{ reloadAllBuffers() method
/**
* Reloads all open buffers.
* @param view The view
* @param confirm If true, a confirmation dialog will be shown first
* if any buffers are dirty
* @since jEdit 2.7pre2
*/
public static void reloadAllBuffers(View view, boolean confirm)
{
boolean hasDirty = false;
Buffer[] buffers = jEdit.getBuffers();
for(int i = 0; i < buffers.length && !hasDirty; i++)
hasDirty = !buffers[i].isUntitled() && buffers[i].isDirty();
for(int i = 0; i < buffers.length; i++)
{
Buffer buffer = buffers[i];
if (buffer.isUntitled())
continue;
buffer.load(view,true);
}
} //}}}
//{{{ _getBuffer() method
/**
* Returns the buffer with the specified path name. The path name
* must be an absolute, canonical, path.
*
* @param path The path name
*
* @return the searched buffer, or null if it is not already open
*
* @see MiscUtilities#constructPath(String,String)
* @see MiscUtilities#resolveSymlinks(String)
* @see #getBuffer(String)
*
* @since jEdit 4.2pre7
*/
public static Buffer _getBuffer(String path)
{
// paths on case-insensitive filesystems are stored as lower
// case in the hash.
if((VFSManager.getVFSForPath(path).getCapabilities()
& VFS.CASE_INSENSITIVE_CAP) != 0)
{
path = path.toLowerCase();
}
synchronized(bufferListLock)
{
return bufferHash.get(path);
}
} //}}}
//{{{ getBuffer() method
/**
* Returns the buffer with the specified path name. The path name
* must be an absolute path. This method automatically resolves
* symbolic links. If performance is critical, cache the canonical
* path and call {@link #_getBuffer(String)} instead.
*
* @param path The path name
*
* @return the searched buffer, or null if it is not already open
*
* @see MiscUtilities#constructPath(String,String)
* @see MiscUtilities#resolveSymlinks(String)
*/
public static Buffer getBuffer(String path)
{
return _getBuffer(MiscUtilities.resolveSymlinks(path));
} //}}}
//{{{ getBuffers() method
/**
* Returns an array of open buffers.
* @return an array of all open buffers
*/
public static Buffer[] getBuffers()
{
synchronized(bufferListLock)
{
Buffer[] buffers = new Buffer[bufferCount];
Buffer buffer = buffersFirst;
for(int i = 0; i < bufferCount; i++)
{
buffers[i] = buffer;
buffer = buffer.next;
}
return buffers;
}
} //}}}
//{{{ getBufferCount() method
/**
* Returns the number of open buffers.
*/
public static int getBufferCount()
{
return bufferCount;
} //}}}
//{{{ getFirstBuffer() method
/**
* Returns the first buffer.
*/
public static Buffer getFirstBuffer()
{
return buffersFirst;
} //}}}
//{{{ getLastBuffer() method
/**
* Returns the last buffer.
* @return the last buffer
*/
public static Buffer getLastBuffer()
{
return buffersLast;
} //}}}
//{{{ getPropertyManager() method
/**
* @return the propertyManager
* @since jEdit 4.3pre15
*/
public static JEditPropertyManager getPropertyManager()
{
return propertyManager;
} //}}}
//{{{ checkBufferStatus() methods
/**
* Checks each buffer's status on disk and shows the dialog box
* informing the user that buffers changed on disk, if necessary.
* @param view The view
* @since jEdit 4.2pre1
*/
public static void checkBufferStatus(View view)
{
checkBufferStatus(view,false);
}
/**
* Checks buffer status on disk and shows the dialog box
* informing the user that buffers changed on disk, if necessary.
* @param view The view
* @param currentBuffer indicates whether to check only the current buffer
* @since jEdit 4.2pre1
*/
public static void checkBufferStatus(View view, boolean currentBuffer)
{
// still need to call the status check even if the option is
// off, so that the write protection is updated if it changes
// on disk
// auto reload changed buffers?
boolean autoReload = getBooleanProperty("autoReload");
// the problem with this is that if we have two edit panes
// looking at the same buffer and the file is reloaded both
// will jump to the same location
Buffer buffer;
buffer = buffersFirst;
int[] states = new int[bufferCount];
int i = 0;
boolean notifyFileChanged = false;
while(buffer != null)
{
if(currentBuffer && buffer != view.getBuffer())
{
buffer = buffer.next;
i++;
continue;
}
states[i] = buffer.checkFileStatus(view);
switch(states[i])
{
case Buffer.FILE_CHANGED:
if(buffer.getAutoReload())
{
if(buffer.isDirty())
notifyFileChanged = true;
else
buffer.load(view,true);
}
else // no automatic reload even if general setting is true
autoReload = false;
// don't notify user if "do nothing" was chosen
if(buffer.getAutoReloadDialog())
notifyFileChanged = true;
break;
case Buffer.FILE_DELETED:
notifyFileChanged = true;
break;
}
buffer = buffer.next;
i++;
}
} //}}}
//}}}
//{{{ View methods
//{{{ getInputHandler() method
/**
* Returns the current input handler (key binding to action mapping)
* @see org.gjt.sp.jedit.gui.InputHandler
*/
public static InputHandler getInputHandler()
{
return inputHandler;
} //}}}
/* public static void newViewTest()
{
long time = System.currentTimeMillis();
for(int i = 0; i < 30; i++)
{
Buffer b = newFile(null);
b.insert(0,"x");
new View(b,null,false);
}
System.err.println(System.currentTimeMillis() - time);
} */
//{{{ newView() methods
/**
* Creates a new view.
* @param view An existing view
* @since jEdit 3.2pre2
*/
public static View newView(View view)
{
return newView(view,null,false);
}
/**
* Creates a new view of a buffer.
* @param view An existing view
* @param buffer The buffer
*/
public static View newView(View view, Buffer buffer)
{
return newView(view,buffer,false);
}
/**
* Creates a new view of a buffer.
* @param view An existing view
* @param buffer The buffer
* @param plainView If true, the view will not have dockable windows or
* tool bars.
*
* @since 4.1pre2
*/
public static View newView(View view, Buffer buffer, boolean plainView)
{
View.ViewConfig config;
if(view != null && (plainView == view.isPlainView()))
{
config = view.getViewConfig();
config.x -= 20;
config.y += 20;
}
else
{
config = new View.ViewConfig(plainView);
}
return newView(view,buffer,config);
}
/**
* Creates a new view.
* @param view An existing view
* @param buffer A buffer to display, or null
* @param config Encapsulates the view geometry, split configuration
* and if the view is a plain view
* @since jEdit 4.2pre1
*/
public static View newView(View view, Buffer buffer, View.ViewConfig config)
{
return null;
} //}}}
//{{{ closeView() method
/**
* Closes a view.
*
* jEdit will exit if this was the last open view.
*/
public static void closeView(View view)
{
closeView(view,true);
} //}}}
//{{{ getViews() method
/**
* Returns an array of all open views.
*/
public static View[] getViews()
{
return new View[0];
} //}}}
//{{{ getViewCount() method
/**
* Returns the number of open views.
*/
public static int getViewCount()
{
return 0;
} //}}}
//{{{ getFirstView() method
/**
* Returns the first view.
*/
public static View getFirstView()
{
return viewsFirst;
} //}}}
//{{{ getLastView() method
/**
* Returns the last view.
*/
public static View getLastView()
{
return viewsLast;
} //}}}
//{{{ getActiveView() method
/**
* Returns the currently focused view.
* @since jEdit 4.1pre1
*/
public static View getActiveView()
{
if(activeView == null)
{
// eg user just closed a view and didn't focus another
return viewsFirst;
}
else
return activeView;
} //}}}
//}}}
//{{{ Miscellaneous methods
//{{{ isMainThread() method
/**
* Returns true if the currently running thread is the main thread.
* @since jEdit 4.2pre1
*/
public static boolean isMainThread()
{
return Thread.currentThread() == mainThread;
} //}}}
//{{{ isBackgroundMode() method
/**
* Returns true if jEdit was started with the -background
* command-line switch.
* @since jEdit 4.0pre4
*/
public static boolean isBackgroundModeEnabled()
{
return background;
} //}}}
//{{{ showMemoryStatusDialog() method
/**
* Performs garbage collection and displays a dialog box showing
* memory status.
* @param view The view
* @since jEdit 4.0pre1
*/
public static void showMemoryDialog(View view)
{
Runtime rt = Runtime.getRuntime();
int before = (int) (rt.freeMemory() / 1024);
System.gc();
int after = (int) (rt.freeMemory() / 1024);
int total = (int) (rt.totalMemory() / 1024);
JProgressBar progress = new JProgressBar(0,total);
progress.setValue(total - after);
progress.setStringPainted(true);
progress.setString(jEdit.getProperty("memory-status.use",
new Object[] { total - after, total }));
Object[] message = new Object[4];
message[0] = getProperty("memory-status.gc",
new Object[] { after - before });
message[1] = Box.createVerticalStrut(12);
message[2] = progress;
message[3] = Box.createVerticalStrut(6);
JOptionPane.showMessageDialog(view,message,
jEdit.getProperty("memory-status.title"),
JOptionPane.INFORMATION_MESSAGE);
} //}}}
//{{{ getJEditHome() method
/**
* Returns the jEdit install directory.
*/
public static String getJEditHome()
{
return jEditHome;
} //}}}
//{{{ getSettingsDirectory() method
/**
* Returns the path of the directory where user-specific settings
* are stored. This will be null
if jEdit was
* started with the -nosettings
command-line switch; do not
* blindly use this method without checking for a null
* return value first.
*/
public static String getSettingsDirectory()
{
return settingsDirectory;
} //}}}
//{{{ getJARCacheDirectory() method
/**
* Returns the directory where plugin cache files are stored.
* @since jEdit 4.2pre1
*/
public static String getJARCacheDirectory()
{
return jarCacheDirectory;
} //}}}
//{{{ backupSettingsFile() method
/**
* Backs up the specified file in the settings directory.
* You should call this on any settings files your plugin
* writes.
* @param file The file
* @since jEdit 4.0pre1
*/
public static void backupSettingsFile(File file)
{
if(settingsDirectory == null)
return;
String backupDir = MiscUtilities.constructPath(
settingsDirectory,"settings-backup");
File dir = new File(backupDir);
if(!dir.exists())
dir.mkdirs();
// ... sweet. saveBackup() will create backupDir if it
// doesn't exist.
MiscUtilities.saveBackup(file,5,null,"~",backupDir);
} //}}}
//{{{ saveSettings() method
/**
* Saves all user preferences to disk.
*/
public static void saveSettings()
{
if(settingsDirectory == null)
return;
BufferHistory.save();
KillRing.getInstance().save();
File file1 = new File(MiscUtilities.constructPath(
settingsDirectory,"#properties#save#"));
File file2 = new File(MiscUtilities.constructPath(
settingsDirectory,"properties"));
if(file2.exists() && file2.lastModified() != propsModTime)
{
Log.log(Log.WARNING,jEdit.class,file2 + " changed"
+ " on disk; will not save user properties");
}
else
{
backupSettingsFile(file2);
try
{
OutputStream out = new FileOutputStream(file1);
propMgr.saveUserProps(out);
file2.delete();
file1.renameTo(file2);
}
catch(IOException io)
{
Log.log(Log.ERROR,jEdit.class,io);
}
propsModTime = file2.lastModified();
}
} //}}}
// {{{ createTextArea() method
/**
* Create a standalone TextArea.
*
* @return a textarea
* @since 4.3pre13
*/
public static TextArea createTextArea()
{
final TextArea textArea = TextArea._createTextArea(true, propertyManager);
return textArea;
} // }}}
//{{{ exit() method
/**
* Exits cleanly from jEdit, prompting the user if any unsaved files
* should be saved first.
* @param view The view from which this exit was called
* @param reallyExit If background mode is enabled and this parameter
* is true, then jEdit will close all open views instead of exiting
* entirely.
*/
public static void exit(View view, boolean reallyExit)
{
// Close dialog, view.close() call need a view...
if(view == null)
view = activeView;
// Create a new EditorExitRequested
EditorExitRequested eer = new EditorExitRequested(view);
// Send EditorExitRequested
EditBus.send(eer);
// Check if the ExitRequest has been cancelled
// if so, do not proceed anymore in the exiting
if (eer.hasBeenExitCancelled())
{
Log.log(Log.MESSAGE, jEdit.class, "Exit has been cancelled");
return;
}
// Even if reallyExit is false, we still exit properly
// if background mode is off
reallyExit |= !background;
// Close all buffers
if(!closeAllBuffers(view,reallyExit))
return;
// If we are running in background mode and
// reallyExit was not specified, then return here.
if(!reallyExit)
{
// in this case, we can't directly call
// view.close(); we have to call closeView()
// for all open views
view = viewsFirst;
while(view != null)
{
closeView(view,false);
}
// Save settings in case user kills the backgrounded
// jEdit process
saveSettings();
}
else
{
// Save view properties here
if(view != null)
{
view.close();
removeViewFromList(view);
}
// Send EditorExiting
EditBus.send(new EditorExiting(null));
// Save settings
saveSettings();
// Close activity log stream
Log.closeStream();
// Byebye...
System.exit(0);
}
} //}}}
//{{{ visit() method
/**
* Visit the views, editpanes and textareas
* @param visitor the visitor
* @since jEdit 4.3pre13
*/
public static void visit(JEditVisitor visitor)
{
View view = jEdit.getFirstView();
while (view != null)
{
visitor.visit(view);
view.visit(visitor);
view = view.getNext();
}
} //}}}
//}}}
//{{{ Package-private members
//{{{ updatePosition() method
/**
* If buffer sorting is enabled, this repositions the buffer.
*/
static void updatePosition(String oldPath, Buffer buffer)
{
if((VFSManager.getVFSForPath(oldPath).getCapabilities()
& VFS.CASE_INSENSITIVE_CAP) != 0)
{
oldPath = oldPath.toLowerCase();
}
bufferHash.remove(oldPath);
String path = buffer.getSymlinkPath();
if((VFSManager.getVFSForPath(path).getCapabilities()
& VFS.CASE_INSENSITIVE_CAP) != 0)
{
path = path.toLowerCase();
}
bufferHash.put(path,buffer);
if(sortBuffers)
{
removeBufferFromList(buffer);
addBufferToList(buffer);
}
} //}}}
//{{{ loadMode() method
/**
* Loads an XML-defined edit mode from the specified reader.
* @param mode The edit mode
*/
/* package-private */ static void loadMode(Mode mode)
{
Object o = mode.getProperty("file");
if (o instanceof URL)
{
mode.setProperty("file",((URL)o).toExternalForm().substring(5));
}
final String fileName = (String)mode.getProperty("file");
XModeHandler xmh = new XModeHandler(mode.getName())
{
@Override
public void error(String what, Object subst)
{
String msg;
Object line = "";
if(subst == null)
msg = jEdit.getProperty("xmode-error." + what);
else
{
msg = jEdit.getProperty("xmode-error." + what,
new String[] { subst.toString() });
if(subst instanceof Throwable)
Log.log(Log.ERROR,this,subst);
if (subst instanceof SAXParseException)
{
line = ((SAXParseException)subst).getLineNumber();
}
}
Object[] args = { fileName, line, null, msg };
}
@Override
public TokenMarker getTokenMarker(String modeName)
{
Mode mode = getMode(modeName);
if(mode == null)
return null;
else
return mode.getTokenMarker();
}
};
ModeProvider.instance.loadMode(mode, xmh);
} //}}}
//{{{ addPluginProps() method
static void addPluginProps(Properties map)
{
propMgr.addPluginProps(map);
} //}}}
//{{{ removePluginProps() method
static void removePluginProps(Properties map)
{
propMgr.removePluginProps(map);
} //}}}
//{{{ pluginError() method
/**
*
* @param messageProp - a property of a message to print
* @param args a list of arguments whch correspond to {0} and {1} in the string to print.
*/
static void pluginError(String path, String messageProp,
Object[] args)
{
synchronized(pluginErrorLock)
{
if(startupDone)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
showPluginErrorDialog();
}
});
}
}
} //}}}
//{{{ setActiveView() method
static void setActiveView(View view)
{
jEdit.activeView = view;
} //}}}
//{{{ getActiveViewInternal() method
/**
* Returns the internal active view, which might be null.
*
* @since 4.3pre10
*/
public static View getActiveViewInternal()
{
return activeView;
} //}}}
//}}}
//{{{ Private members
//{{{ Static variables
private static String jEditHome;
private static String settingsDirectory;
private static String jarCacheDirectory;
private static long propsModTime;
private static PropertyManager propMgr;
private static boolean background;
private static ActionContext actionContext;
private static final Object pluginErrorLock = new Object();
private static boolean saveCaret;
private static InputHandler inputHandler;
// buffer link list
private static boolean sortBuffers;
private static boolean sortByName;
private static int bufferCount;
private static Buffer buffersFirst;
private static Buffer buffersLast;
private static Map bufferHash = new HashMap();
// makes openTemporary() thread-safe
private static final Object bufferListLock = new Object();
private static final Object editBusOrderingLock = new Object();
// view link list
private static int viewCount;
private static View viewsFirst;
private static View viewsLast;
private static View activeView;
private static boolean startupDone;
private static Thread mainThread;
//}}}
private jEdit() {}
//{{{ usage() method
private static void usage()
{
System.out.println("Usage: jedit [] []");
System.out.println(" +marker:: Positions caret"
+ " at marker ");
System.out.println(" +line:: Positions caret"
+ " at line number ");
System.out.println(" +line:,: Positions caret"
+ " at line number and column number ");
System.out.println(" --: End of options");
System.out.println(" -background: Run in background mode");
System.out.println(" -nobackground: Disable background mode (default)");
System.out.println(" -gui: Only if running in background mode; open initial view (default)");
System.out.println(" -nogui: Only if running in background mode; don't open initial view");
System.out.println(" -log=: Log messages with level equal to or higher than this to");
System.out.println(" standard error. must be between 1 and 9. Default is 7.");
System.out.println(" -newplainview: Client instance opens a new plain view");
System.out.println(" -newview: Client instance opens a new view (default)");
System.out.println(" -plugins: Load plugins (default)");
System.out.println(" -noplugins: Don't load any plugins");
System.out.println(" -restore: Restore previously open files (default)");
System.out.println(" -norestore: Don't restore previously open files");
System.out.println(" -reuseview: Client instance reuses existing view");
System.out.println(" -quit: Quit a running instance");
System.out.println(" -run=