001: /*
002: * Replacement.java
003: *
004: * Copyright (C) 1998-2002 Peter Graves
005: * $Id: Replacement.java,v 1.1.1.1 2002/09/24 16:09:21 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j;
023:
024: import gnu.regexp.REMatch;
025:
026: public class Replacement extends Search {
027: private Editor editor;
028:
029: // This is the replacement string entered by the user. If we're working
030: // with regular expressions, this string may contain one or more
031: // occurrences of "\\", "\&", or "\D", where D is a digit from 1 to 9
032: // (inclusive).
033: private String replaceWith;
034:
035: private boolean confirmChanges = true;
036: private int replacementCount;
037:
038: public Replacement(Editor editor) {
039: super ();
040: this .editor = editor;
041: }
042:
043: public final Editor getEditor() {
044: return editor;
045: }
046:
047: public final String getReplaceWith() {
048: return replaceWith;
049: }
050:
051: public final void setReplaceWith(String s) {
052: replaceWith = s;
053: }
054:
055: public final boolean confirmChanges() {
056: return confirmChanges;
057: }
058:
059: public final void setConfirmChanges(boolean b) {
060: confirmChanges = b;
061: }
062:
063: public final int getReplacementCount() {
064: return replacementCount;
065: }
066:
067: public void replaceOccurrence() {
068: final Buffer buffer = editor.getBuffer();
069: try {
070: buffer.lockWrite();
071: } catch (InterruptedException e) {
072: Log.error(e);
073: return;
074: }
075: try {
076: final Line dotLine = editor.getDotLine();
077: final int dotOffset = editor.getDotOffset();
078: if (isMultilinePattern()) {
079: Debug.assertTrue(isRegularExpression());
080: Debug.assertTrue(editor.getMark() != null);
081: Debug.assertTrue(editor.getDot().isBefore(
082: editor.getMark()));
083: Debug.assertTrue(getMatch() != null);
084: final Region region = getRegion();
085: int end = -1;
086: if (region != null) {
087: // Restrict to selection.
088: end = buffer.getAbsoluteOffset(region.getEnd());
089: }
090: Region r = new Region(editor);
091: editor.addUndoDeleteRegion(r);
092: // Sets buffer modified flag.
093: r.delete();
094: final String toBeReplaced = getMatch().toString();
095: final String toBeInserted = getReplacementText(toBeReplaced);
096: editor.addUndo(SimpleEdit.INSERT_STRING);
097: buffer.insertString(editor.getDot(), toBeInserted);
098: if (region != null) {
099: Debug.assertTrue(end >= 0);
100: end -= toBeReplaced.length();
101: end += toBeInserted.length();
102: Debug.assertTrue(end > buffer
103: .getAbsoluteOffset(region.getBegin()));
104: Position endPos = buffer.getPosition(end);
105: Debug.assertTrue(endPos != null);
106: region.setEnd(endPos);
107: }
108: editor.getBuffer().repaint();
109: } else {
110: editor.addUndo(SimpleEdit.LINE_EDIT);
111: editor.setMark(null);
112: String head = dotLine.substring(0, dotOffset);
113: String toBeReplaced;
114: if (isRegularExpression()) {
115: Debug.assertTrue(getMatch() != null);
116: toBeReplaced = getMatch().toString();
117: } else {
118: toBeReplaced = dotLine.substring(dotOffset,
119: dotOffset + getPatternLength());
120: }
121: String tail = dotLine.substring(dotOffset
122: + toBeReplaced.length());
123: String toBeInserted = getReplacementText(toBeReplaced);
124: FastStringBuffer sb = new FastStringBuffer(head);
125: sb.append(toBeInserted);
126: sb.append(tail);
127: dotLine.setText(sb.toString());
128: Region region = getRegion();
129: if (region != null && dotLine == region.getEndLine())
130: if (dotOffset + toBeReplaced.length() <= region
131: .getEndOffset())
132: region.setEndOffset(region.getEndOffset()
133: + toBeInserted.length()
134: - toBeReplaced.length());
135: editor.getDot().skip(toBeInserted.length());
136: Editor.updateInAllEditors(dotLine);
137: buffer.modified();
138: }
139: ++replacementCount;
140: } finally {
141: buffer.unlockWrite();
142: }
143: }
144:
145: // No editor, no region, no undo, does not set buffer's modified flag.
146: // Used by replace in files when not confirming changes or keeping
147: // modified buffers.
148: public void replaceOccurrence(Position pos) {
149: final Line line = pos.getLine();
150: final int offset = pos.getOffset();
151: final String head = line.substring(0, offset);
152: String toBeReplaced;
153: if (isRegularExpression()) {
154: Debug.assertTrue(getMatch() != null);
155: toBeReplaced = getMatch().toString();
156: } else
157: toBeReplaced = line.substring(offset, offset
158: + getPatternLength());
159: final String tail = line.substring(offset
160: + toBeReplaced.length());
161: final String toBeInserted = getReplacementText(toBeReplaced);
162: FastStringBuffer sb = new FastStringBuffer(head);
163: sb.append(toBeInserted);
164: sb.append(tail);
165: line.setText(sb.toString());
166: pos.skip(toBeInserted.length());
167: ++replacementCount;
168: }
169:
170: private String getReplacementText(String toBeReplaced) {
171: String replacementText;
172: if (isRegularExpression()) {
173: // Perform regular expression variable substitution as necessary.
174: replacementText = substituteInto(getMatch(), replaceWith);
175: } else {
176: // We're not doing regular expressions. Use the string entered by
177: // the user, verbatim.
178: replacementText = replaceWith;
179: }
180: // Handle case conversion if appropriate.
181: if (ignoreCase() && toBeReplaced.length() > 0
182: && replacementText.length() > 0) {
183: if (Utilities.isUpperCase(toBeReplaced)) {
184: // The string to be replaced is all upper case. Make the
185: // replacement all upper case too.
186: replacementText = replacementText.toUpperCase();
187: } else {
188: char c = toBeReplaced.charAt(0);
189: if (Character.isUpperCase(c)) {
190: // The string to be replaced begins with an upper case
191: // letter. Make the replacement begin with an upper case
192: // letter too.
193: c = replacementText.charAt(0);
194: if (Character.isLowerCase(c)) {
195: FastStringBuffer sb = new FastStringBuffer(
196: replacementText);
197: sb.setCharAt(0, Character.toUpperCase(c));
198: replacementText = sb.toString();
199: }
200: }
201: }
202: }
203: return replacementText;
204: }
205:
206: private String substituteInto(REMatch match, String input) {
207: FastStringBuffer sb = new FastStringBuffer();
208: int i;
209: for (i = 0; i < input.length() - 1; i++) {
210: char c = input.charAt(i);
211: if (c == '\\') {
212: c = input.charAt(++i);
213: if (c == '&') {
214: sb.append(match.toString());
215: } else if (c >= '1' && c <= '9') {
216: int val = Character.digit(c, 10);
217: sb.append(match.toString(val));
218: } else if (isMultilinePattern() && c == 'n') {
219: sb.append('\n');
220: } else {
221: // Escape everything else.
222: sb.append(c);
223: }
224: } else
225: sb.append(c);
226: }
227:
228: if (i < input.length())
229: sb.append(input.charAt(i));
230:
231: return sb.toString();
232: }
233: }
|