⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 buffer.java

📁 用java 编写的源码开放的文本编辑器。有很多有用的特性
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
/* * Buffer.java - jEdit buffer * :tabSize=8:indentSize=8:noTabs=false: * :folding=explicit:collapseFolds=1: * * Copyright (C) 1998, 2003 Slava Pestov * Portions copyright (C) 1999, 2000 mike dillon * * 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;//{{{ Importsimport gnu.regexp.*;import javax.swing.*;import javax.swing.text.*;import java.awt.Toolkit;import java.io.File;import java.util.*;import org.gjt.sp.jedit.browser.VFSBrowser;import org.gjt.sp.jedit.buffer.*;import org.gjt.sp.jedit.io.*;import org.gjt.sp.jedit.msg.*;import org.gjt.sp.jedit.search.RESearchMatcher;import org.gjt.sp.jedit.syntax.*;import org.gjt.sp.jedit.textarea.*;import org.gjt.sp.util.*;//}}}/** * A <code>Buffer</code> represents the contents of an open text * file as it is maintained in the computer's memory (as opposed to * how it may be stored on a disk).<p> * * In a BeanShell script, you can obtain the current buffer instance from the * <code>buffer</code> variable.<p> * * This class does not have a public constructor. * Buffers can be opened and closed using methods in the <code>jEdit</code> * class.<p> * * This class is partially thread-safe, however you must pay attention to two * very important guidelines: * <ul> * <li>Changes to a buffer can only be made from the AWT thread. * <li>When accessing the buffer from another thread, you must * grab a read lock if you plan on performing more than one call, to ensure that * the buffer contents are not changed by the AWT thread for the duration of the * lock. Only methods whose descriptions specify thread safety can be invoked * from other threads. * </ul> * * @author Slava Pestov * @version $Id: Buffer.java,v 1.126 2003/02/23 04:05:21 spestov Exp $ */public class Buffer implements EBComponent{	//{{{ Some constants	/**	 * Line separator property.	 */	public static final String LINESEP = "lineSeparator";	/**	 * Backed up property.	 * @since jEdit 3.2pre2	 */	public static final String BACKED_UP = "Buffer__backedUp";	/**	 * Caret info properties.	 * @since jEdit 3.2pre1	 */	public static final String CARET = "Buffer__caret";	public static final String SELECTION = "Buffer__selection";	/**	 * This should be a physical line number, so that the scroll	 * position is preserved correctly across reloads (which will	 * affect virtual line numbers, due to fold being reset)	 */	public static final String SCROLL_VERT = "Buffer__scrollVert";	public static final String SCROLL_HORIZ = "Buffer__scrollHoriz";	/**	 * Character encoding used when loading and saving.	 * @since jEdit 3.2pre4	 */	public static final String ENCODING = "encoding";	/**	 * This property is set to 'true' if the file has a trailing newline.	 * @since jEdit 4.0pre1	 */	public static final String TRAILING_EOL = "trailingEOL";	/**	 * This property is set to 'true' if the file should be GZipped.	 * @since jEdit 4.0pre4	 */	public static final String GZIPPED = "gzipped";	//}}}	//{{{ Input/output methods	//{{{ showInsertFileDialog() method	/**	 * Displays the 'insert file' dialog box and inserts the selected file	 * into the buffer.	 * @param view The view	 * @since jEdit 2.7pre2	 */	public void showInsertFileDialog(View view)	{		String[] files = GUIUtilities.showVFSFileDialog(view,null,			VFSBrowser.OPEN_DIALOG,false);		if(files != null)			insertFile(view,files[0]);	} //}}}	//{{{ reload() method	/**	 * Reloads the buffer from disk, asking for confirmation if the buffer	 * has unsaved changes.	 * @param view The view	 * @since jEdit 2.7pre2	 */	public void reload(View view)	{		if(getFlag(DIRTY))		{			String[] args = { name };			int result = GUIUtilities.confirm(view,"changedreload",				args,JOptionPane.YES_NO_OPTION,				JOptionPane.WARNING_MESSAGE);			if(result != JOptionPane.YES_OPTION)				return;		}		view.getEditPane().saveCaretInfo();		load(view,true);	} //}}}	//{{{ load() method	/**	 * Loads the buffer from disk, even if it is loaded already.	 * @param view The view	 * @param reload If true, user will not be asked to recover autosave	 * file, if any	 *	 * @since 2.5pre1	 */	public boolean load(final View view, final boolean reload)	{		if(isPerformingIO())		{			GUIUtilities.error(view,"buffer-multiple-io",null);			return false;		}		setBooleanProperty(BufferIORequest.ERROR_OCCURRED,false);		setFlag(LOADING,true);		// view text areas temporarily blank out while a buffer is		// being loaded, to indicate to the user that there is no		// data available yet.		if(!getFlag(TEMPORARY))			EditBus.send(new BufferUpdate(this,view,BufferUpdate.LOAD_STARTED));		final boolean loadAutosave;		if(reload || !getFlag(NEW_FILE))		{			if(file != null)				modTime = file.lastModified();			// Only on initial load			if(!reload && autosaveFile != null && autosaveFile.exists())				loadAutosave = recoverAutosave(view);			else			{				if(autosaveFile != null)					autosaveFile.delete();				loadAutosave = false;			}			if(!loadAutosave)			{				// this returns false if initial sanity				// checks (if the file is a directory, etc)				// fail				if(!vfs.load(view,this,path))				{					setFlag(LOADING,false);					return false;				}			}		}		else			loadAutosave = false;		//{{{ Do some stuff once loading is finished		Runnable runnable = new Runnable()		{			public void run()			{				String newPath = getStringProperty(					BufferIORequest.NEW_PATH);				Segment seg = (Segment)getProperty(					BufferIORequest.LOAD_DATA);				IntegerArray endOffsets = (IntegerArray)					getProperty(BufferIORequest.END_OFFSETS);				// below remove() call only works if read only				// is false. this is a slightly silly workaround.				boolean readOnly = isReadOnly();				setFlag(READ_ONLY,false);				// For `reload' command				remove(0,getLength());				if(seg != null && endOffsets != null)				{					// This is faster than Buffer.insert()					try					{						writeLock();						// theoretically a segment could						// have seg.offset != 0 but						// SegmentBuffer never does that						contentMgr._setContent(seg.array,seg.count);						contentInserted(0,seg.count,endOffsets);					}					catch(OutOfMemoryError oom)					{						Log.log(Log.ERROR,this,oom);						VFSManager.error(view,path,"out-of-memory-error",null);					}					finally					{						writeUnlock();					}				}				setFlag(READ_ONLY,readOnly);				unsetProperty(BufferIORequest.LOAD_DATA);				unsetProperty(BufferIORequest.END_OFFSETS);				unsetProperty(BufferIORequest.NEW_PATH);				undoMgr.clear();				undoMgr.setLimit(jEdit.getIntegerProperty(					"buffer.undoCount",100));				if(!getFlag(TEMPORARY))					finishLoading();				/* Ultra-obscure: we have to fire this event				 * after the buffer might have been collapsed				 * by finishLoading(), since finishLoading(),				 * unlike "official" fold APIs, does not notify				 * the text area to invalidate its cached				 * virtual to physical information. Note that				 * the text area's contentInserted() handler				 * updates 'lastPhysLine' even if the LOADING				 * flag is set. */				fireContentInserted(0,0,getLineCount(),getLength() - 1);				setFlag(LOADING,false);				// if reloading a file, clear dirty flag				if(reload)					setDirty(false);				if(!loadAutosave && newPath != null && !path.equals(newPath))					setPath(newPath);				// if loadAutosave is false, we loaded an				// autosave file, so we set 'dirty' to true				// note that we don't use setDirty(),				// because a) that would send an unnecessary				// message, b) it would also set the				// AUTOSAVE_DIRTY flag, which will make				// the autosave thread write out a				// redundant autosave file				if(loadAutosave)					setFlag(DIRTY,true);				// send some EditBus messages				if(!getFlag(TEMPORARY))				{					EditBus.send(new BufferUpdate(Buffer.this,						view,BufferUpdate.LOADED));					//EditBus.send(new BufferUpdate(Buffer.this,					//	view,BufferUpdate.MARKERS_CHANGED));				}			}		}; //}}}		if(getFlag(TEMPORARY))			runnable.run();		else			VFSManager.runInAWTThread(runnable);		return true;	} //}}}	//{{{ insertFile() method	/**	 * Loads a file from disk, and inserts it into this buffer.	 * @param view The view	 *	 * @since 4.0pre1	 */	public boolean insertFile(final View view, String path)	{		if(isPerformingIO())		{			GUIUtilities.error(view,"buffer-multiple-io",null);			return false;		}		setBooleanProperty(BufferIORequest.ERROR_OCCURRED,false);		path = MiscUtilities.constructPath(this.path,path);		Buffer buffer = jEdit.getBuffer(path);		if(buffer != null)		{			view.getTextArea().setSelectedText(				buffer.getText(0,buffer.getLength()));			return true;		}		VFS vfs = VFSManager.getVFSForPath(path);		setFlag(IO,true);		// this returns false if initial sanity		// checks (if the file is a directory, etc)		// fail		if(!vfs.insert(view,this,path))		{			setFlag(IO,false);			return false;		}		// Do some stuff once loading is finished		VFSManager.runInAWTThread(new Runnable()		{			public void run()			{				setFlag(IO,false);				SegmentBuffer sbuf = (SegmentBuffer)getProperty(					BufferIORequest.LOAD_DATA);				if(sbuf != null)				{					unsetProperty(BufferIORequest.LOAD_DATA);					view.getTextArea().setSelectedText(sbuf.toString());				}			}		});		return true;	} //}}}	//{{{ autosave() method	/**	 * Autosaves this buffer.	 */	public void autosave()	{		if(autosaveFile == null || !getFlag(AUTOSAVE_DIRTY)			|| !getFlag(DIRTY)			|| getFlag(LOADING)			|| getFlag(IO))			return;		setFlag(AUTOSAVE_DIRTY,false);		VFSManager.runInWorkThread(new BufferIORequest(			BufferIORequest.AUTOSAVE,null,this,null,			VFSManager.getFileVFS(),autosaveFile.getPath()));	} //}}}	//{{{ saveAs() method	/**	 * Prompts the user for a file to save this buffer to.	 * @param view The view	 * @param rename True if the buffer's path should be changed, false	 * if only a copy should be saved to the specified filename	 * @since jEdit 2.6pre5	 */	public boolean saveAs(View view, boolean rename)	{		String[] files = GUIUtilities.showVFSFileDialog(view,path,			VFSBrowser.SAVE_DIALOG,false);		// files[] should have length 1, since the dialog type is		// SAVE_DIALOG		if(files == null)			return false;		return save(view,files[0],rename);	} //}}}	//{{{ save() method	/**	 * Saves this buffer to the specified path name, or the current path	 * name if it's null.	 * @param view The view	 * @param path The path name to save the buffer to, or null to use	 * the existing path	 */	public boolean save(View view, String path)	{		return save(view,path,true);	} //}}}	//{{{ save() method	/**	 * Saves this buffer to the specified path name, or the current path	 * name if it's null.	 * @param view The view	 * @param path The path name to save the buffer to, or null to use	 * the existing path	 * @param rename True if the buffer's path should be changed, false	 * if only a copy should be saved to the specified filename	 * @since jEdit 2.6pre5	 */	public boolean save(final View view, String path, final boolean rename)	{		if(isPerformingIO())		{			GUIUtilities.error(view,"buffer-multiple-io",null);			return false;		}		setBooleanProperty(BufferIORequest.ERROR_OCCURRED,false);		if(path == null && getFlag(NEW_FILE))			return saveAs(view,rename);		if(path == null && file != null)		{			long newModTime = file.lastModified();			if(newModTime != modTime				&& jEdit.getBooleanProperty("view.checkModStatus"))			{				Object[] args = { this.path };				int result = GUIUtilities.confirm(view,					"filechanged-save",args,					JOptionPane.YES_NO_OPTION,					JOptionPane.WARNING_MESSAGE);				if(result != JOptionPane.YES_OPTION)					return false;			}		}		setFlag(IO,true);		EditBus.send(new BufferUpdate(this,view,BufferUpdate.SAVING));		final String oldPath = this.path;		final String newPath = (path == null ? this.path : path);		VFS vfs = VFSManager.getVFSForPath(newPath);		if(!vfs.save(view,this,newPath))		{			setFlag(IO,false);			return false;		}		// Once save is complete, do a few other things		VFSManager.runInAWTThread(new Runnable()		{			public void run()			{				setFlag(IO,false);				finishSaving(view,oldPath,newPath,rename,					getBooleanProperty(BufferIORequest					.ERROR_OCCURRED));			}		});		return true;	} //}}}	//{{{ checkFileStatus() method	public static final int FILE_NOT_CHANGED = 0;	public static final int FILE_CHANGED = 1;	public static final int FILE_DELETED = 2;	/**	 * Check if the buffer has changed on disk.	 * @return One of <code>NOT_CHANGED</code>, <code>CHANGED</code>, or	 * <code>DELETED</code>.	 *	 * @since jEdit 4.1pre3	 */	public int checkFileStatus()	{		// - don't do these checks while a save is in progress,		// because for a moment newModTime will be greater than		// oldModTime, due to the multithreading		// - only supported on local file system		if(!getFlag(IO) && !getFlag(LOADING) && file != null			&& !getFlag(NEW_FILE))		{			boolean newReadOnly = (file.exists() && !file.canWrite());			if(newReadOnly != getFlag(READ_ONLY))			{				setFlag(READ_ONLY,newReadOnly);				EditBus.send(new BufferUpdate(this,null,					BufferUpdate.DIRTY_CHANGED));			}			long oldModTime = modTime;			long newModTime = file.lastModified();			if(newModTime != oldModTime)			{				modTime = newModTime;				if(!file.exists())				{					setFlag(NEW_FILE,true);					EditBus.send(new BufferUpdate(this,null,						BufferUpdate.DIRTY_CHANGED));					return FILE_DELETED;				}				else					return FILE_CHANGED;			}		}		return FILE_NOT_CHANGED;	} //}}}	//{{{ checkModTime() method	/**	 * Check if the buffer has changed on disk.	 * @since jEdit 4.1pre8	 */	public void checkModTime(EditPane editPane)	{		View view = editPane.getView();		int status = checkFileStatus();		// still need to call the status check even if this option is off,		// so that the write protection is updated if it changes on disk		if(!jEdit.getBooleanProperty("view.checkModStatus"))			return;		if(status == FILE_DELETED)		{			Object[] args = { path };			GUIUtilities.message(view,"filedeleted",args);		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -