📄 searchandreplace.java
字号:
/* * SearchAndReplace.java - Search and replace * :tabSize=8:indentSize=8:noTabs=false: * :folding=explicit:collapseFolds=1: * * Copyright (C) 1999, 2000, 2001, 2002 Slava Pestov * Portions copyright (C) 2001 Tom Locke * * 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.search;//{{{ Importsimport bsh.BshMethod;import java.awt.Component;import javax.swing.JOptionPane;import javax.swing.text.Segment;import org.gjt.sp.jedit.*;import org.gjt.sp.jedit.io.VFSManager;import org.gjt.sp.jedit.msg.SearchSettingsChanged;import org.gjt.sp.jedit.textarea.*;import org.gjt.sp.util.Log;//}}}/** * Class that implements regular expression and literal search within * jEdit buffers.<p> * * There are two main groups of methods in this class: * <ul> * <li>Property accessors - for changing search and replace settings.</li> * <li>Actions - for performing search and replace.</li> * </ul> * * The "HyperSearch" and "Keep dialog" features, as reflected in * checkbox options in the search dialog, are not handled from within * this class. If you wish to have these options set before the search dialog * appears, make a prior call to either or both of the following: * * <pre> jEdit.setBooleanProperty("search.hypersearch.toggle",true); * jEdit.setBooleanProperty("search.keepDialog.toggle",true);</pre> * * If you are not using the dialog to undertake a search or replace, you may * call any of the search and replace methods (including * {@link #hyperSearch(View)}) without concern for the value of these properties. * * @author Slava Pestov * @author John Gellene (API documentation) * @version $Id: SearchAndReplace.java,v 1.43 2003/02/09 05:16:57 spestov Exp $ */public class SearchAndReplace{ //{{{ Getters and setters //{{{ setSearchString() method /** * Sets the current search string. * @param search The new search string */ public static void setSearchString(String search) { if(search.equals(SearchAndReplace.search)) return; SearchAndReplace.search = search; matcher = null; EditBus.send(new SearchSettingsChanged(null)); } //}}} //{{{ getSearchString() method /** * Returns the current search string. */ public static String getSearchString() { return search; } //}}} //{{{ setReplaceString() method /** * Sets the current replacement string. * @param search The new replacement string */ public static void setReplaceString(String replace) { if(replace.equals(SearchAndReplace.replace)) return; SearchAndReplace.replace = replace; matcher = null; EditBus.send(new SearchSettingsChanged(null)); } //}}} //{{{ getReplaceString() method /** * Returns the current replacement string. */ public static String getReplaceString() { return replace; } //}}} //{{{ setIgnoreCase() method /** * Sets the ignore case flag. * @param ignoreCase True if searches should be case insensitive, * false otherwise */ public static void setIgnoreCase(boolean ignoreCase) { if(ignoreCase == SearchAndReplace.ignoreCase) return; SearchAndReplace.ignoreCase = ignoreCase; matcher = null; EditBus.send(new SearchSettingsChanged(null)); } //}}} //{{{ getIgnoreCase() method /** * Returns the state of the ignore case flag. * @return True if searches should be case insensitive, * false otherwise */ public static boolean getIgnoreCase() { return ignoreCase; } //}}} //{{{ setRegexp() method /** * Sets the state of the regular expression flag. * @param regexp True if regular expression searches should be * performed */ public static void setRegexp(boolean regexp) { if(regexp == SearchAndReplace.regexp) return; SearchAndReplace.regexp = regexp; if(regexp && reverse) reverse = false; matcher = null; EditBus.send(new SearchSettingsChanged(null)); } //}}} //{{{ getRegexp() method /** * Returns the state of the regular expression flag. * @return True if regular expression searches should be performed */ public static boolean getRegexp() { return regexp; } //}}} //{{{ setReverseSearch() method /** * Determines whether a reverse search will conducted from the current * position to the beginning of a buffer. Note that reverse search and * regular expression search is mutually exclusive; enabling one will * disable the other. * @param reverse True if searches should go backwards, * false otherwise */ public static void setReverseSearch(boolean reverse) { if(reverse == SearchAndReplace.reverse) return; SearchAndReplace.reverse = (regexp ? false : reverse); matcher = null; EditBus.send(new SearchSettingsChanged(null)); } //}}} //{{{ getReverseSearch() method /** * Returns the state of the reverse search flag. * @return True if searches should go backwards, * false otherwise */ public static boolean getReverseSearch() { return reverse; } //}}} //{{{ setBeanShellReplace() method /** * Sets the state of the BeanShell replace flag. * @param regexp True if the replace string is a BeanShell expression * @since jEdit 3.2pre2 */ public static void setBeanShellReplace(boolean beanshell) { if(beanshell == SearchAndReplace.beanshell) return; SearchAndReplace.beanshell = beanshell; matcher = null; EditBus.send(new SearchSettingsChanged(null)); } //}}} //{{{ getBeanShellReplace() method /** * Returns the state of the BeanShell replace flag. * @return True if the replace string is a BeanShell expression * @since jEdit 3.2pre2 */ public static boolean getBeanShellReplace() { return beanshell; } //}}} //{{{ setAutoWrap() method /** * Sets the state of the auto wrap around flag. * @param wrap If true, the 'continue search from start' dialog * will not be displayed * @since jEdit 3.2pre2 */ public static void setAutoWrapAround(boolean wrap) { if(wrap == SearchAndReplace.wrap) return; SearchAndReplace.wrap = wrap; EditBus.send(new SearchSettingsChanged(null)); } //}}} //{{{ getAutoWrap() method /** * Returns the state of the auto wrap around flag. * @param wrap If true, the 'continue search from start' dialog * will not be displayed * @since jEdit 3.2pre2 */ public static boolean getAutoWrapAround() { return wrap; } //}}} //{{{ setSearchMatcher() method /** * Sets a custom search string matcher. Note that calling * {@link #setSearchString(String)}, {@link #setReplaceString(String)}, * {@link #setIgnoreCase(boolean)}, {@link #setRegexp(boolean)}, * {@link #setReverseSearch(boolean)} or * {@link #setBeanShellReplace(boolean)} will reset the matcher to the * default. */ public static void setSearchMatcher(SearchMatcher matcher) { SearchAndReplace.matcher = matcher; EditBus.send(new SearchSettingsChanged(null)); } //}}} //{{{ getSearchMatcher() method /** * Returns the current search string matcher. * @param reverseOK Replacement commands need a non-reversed matcher, * so they set this to false * @exception IllegalArgumentException if regular expression search * is enabled, the search string or replacement string is invalid * @since jEdit 4.1pre7 */ public static SearchMatcher getSearchMatcher() throws Exception { if(matcher != null) return matcher; if(search == null || "".equals(search)) return null; // replace must not be null String replace = (SearchAndReplace.replace == null ? "" : SearchAndReplace.replace); BshMethod replaceMethod; if(beanshell && replace.length() != 0) { replaceMethod = BeanShell.cacheBlock("replace","return (" + replace + ");",true); } else replaceMethod = null; if(regexp) matcher = new RESearchMatcher(search,replace,ignoreCase, beanshell,replaceMethod); else { matcher = new BoyerMooreSearchMatcher(search,replace, ignoreCase,beanshell,replaceMethod); } return matcher; } //}}} //{{{ setSearchFileSet() method /** * Sets the current search file set. * @param fileset The file set to perform searches in * @see AllBufferSet * @see CurrentBufferSet * @see DirectoryListSet */ public static void setSearchFileSet(SearchFileSet fileset) { SearchAndReplace.fileset = fileset; EditBus.send(new SearchSettingsChanged(null)); } //}}} //{{{ getSearchFileSet() method /** * Returns the current search file set. */ public static SearchFileSet getSearchFileSet() { return fileset; } //}}} //}}} //{{{ Actions //{{{ hyperSearch() method /** * Performs a HyperSearch. * @param view The view * @since jEdit 2.7pre3 */ public static boolean hyperSearch(View view) { return hyperSearch(view,false); } //}}} //{{{ hyperSearch() method /** * Performs a HyperSearch. * @param view The view * @param selection If true, will only search in the current selection. * Note that the file set must be the current buffer file set for this * to work. * @since jEdit 4.0pre1 */ public static boolean hyperSearch(View view, boolean selection) { // component that will parent any dialog boxes Component comp = SearchDialog.getSearchDialog(view); if(comp == null) comp = view; record(view,"hyperSearch(view," + selection + ")",false, !selection); view.getDockableWindowManager().addDockableWindow( HyperSearchResults.NAME); final HyperSearchResults results = (HyperSearchResults) view.getDockableWindowManager() .getDockable(HyperSearchResults.NAME); results.searchStarted(); try { SearchMatcher matcher = getSearchMatcher(); if(matcher == null) { view.getToolkit().beep(); results.searchFailed(); return false; } Selection[] s; if(selection) { s = view.getTextArea().getSelection(); if(s == null) { results.searchFailed(); return false; } } else s = null; VFSManager.runInWorkThread(new HyperSearchRequest(view, matcher,results,s)); return true; } catch(Exception e) { results.searchFailed(); Log.log(Log.ERROR,SearchAndReplace.class,e); Object[] args = { e.getMessage() }; if(args[0] == null) args[0] = e.toString(); GUIUtilities.error(comp,"searcherror",args); return false; } } //}}} //{{{ find() method /** * Finds the next occurance of the search string. * @param view The view * @return True if the operation was successful, false otherwise */ public static boolean find(View view) { // component that will parent any dialog boxes Component comp = SearchDialog.getSearchDialog(view); if(comp == null) comp = view; boolean repeat = false; String path = fileset.getNextFile(view,null); if(path == null) { GUIUtilities.error(comp,"empty-fileset",null); return false; } try { SearchMatcher matcher = getSearchMatcher(); if(matcher == null) { view.getToolkit().beep(); return false; } record(view,"find(view)",false,true); view.showWaitCursor(); boolean _reverse = reverse && fileset instanceof CurrentBufferSet;loop: for(;;) { while(path != null) { Buffer buffer = jEdit.openTemporary( view,null,path,false); /* this is stupid and misleading. * but 'path' is not used anywhere except * the above line, and if this is done * after the 'continue', then we will * either hang, or be forced to duplicate * it inside the buffer == null, or add * a 'finally' clause. you decide which one's * worse. */ path = fileset.getNextFile(view,path); if(buffer == null) continue loop; // Wait for the buffer to load if(!buffer.isLoaded()) VFSManager.waitForRequests(); int start; if(view.getBuffer() == buffer && !repeat) { JEditTextArea textArea = view.getTextArea(); Selection s = textArea.getSelectionAtOffset( textArea.getCaretPosition()); if(s == null) start = textArea.getCaretPosition(); else if(_reverse) start = s.getStart(); else start = s.getEnd(); } else if(_reverse) start = buffer.getLength(); else start = 0; if(find(view,buffer,start,repeat,_reverse)) return true; } if(repeat) { if(!BeanShell.isScriptRunning()) { view.getStatus().setMessageAndClear( jEdit.getProperty("view.status.search-not-found")); view.getToolkit().beep(); } return false; } boolean restart; if(BeanShell.isScriptRunning()) { restart = true; } else if(wrap) { view.getStatus().setMessageAndClear( jEdit.getProperty("view.status.auto-wrap")); // beep if beep property set if(jEdit.getBooleanProperty("search.beepOnSearchAutoWrap")) { view.getToolkit().beep(); } restart = true; } else { Integer[] args = { new Integer(_reverse ? 1 : 0) }; int result = GUIUtilities.confirm(comp, "keepsearching",args, JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); restart = (result == JOptionPane.YES_OPTION); } if(restart) { // start search from beginning path = fileset.getFirstFile(view);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -