001: /*
002: * DiffMode.java
003: *
004: * Copyright (C) 1998-2004 Peter Graves
005: * $Id: DiffMode.java,v 1.12 2004/08/08 00:54:04 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 java.awt.AWTEvent;
025: import java.awt.event.KeyEvent;
026: import java.awt.event.MouseEvent;
027: import java.util.List;
028:
029: public final class DiffMode extends AbstractMode implements Constants,
030: Mode {
031: private static final DiffMode mode = new DiffMode();
032:
033: private DiffMode() {
034: super (DIFF_MODE, DIFF_MODE_NAME);
035: }
036:
037: public static final DiffMode getMode() {
038: return mode;
039: }
040:
041: public Formatter getFormatter(Buffer buffer) {
042: return new DiffFormatter(buffer);
043: }
044:
045: protected void setKeyMapDefaults(KeyMap km) {
046: km.mapKey(KeyEvent.VK_ENTER, 0, "diffGotoFile");
047: km
048: .mapKey(KeyEvent.VK_G, CTRL_MASK | SHIFT_MASK,
049: "diffGotoFile");
050: km.mapKey(VK_DOUBLE_MOUSE_1, 0, "diffGotoFile");
051: km.mapKey(VK_MOUSE_2, 0, "diffGotoFile");
052: }
053:
054: public static void diff() {
055: final Editor editor = Editor.currentEditor();
056: final Buffer buffer = editor.getBuffer();
057: File file = buffer.getFile();
058: if (file.isLocal() && file.isFile()) {
059: File patchFile = buffer.getPatchFile();
060: if (patchFile != null && patchFile.isFile()) {
061: boolean save = false;
062: if (buffer.isModified()) {
063: int response = ConfirmDialog
064: .showConfirmDialogWithCancelButton(editor,
065: CHECK_SAVE_PROMPT, "diff");
066: switch (response) {
067: case RESPONSE_YES:
068: save = true;
069: break;
070: case RESPONSE_NO:
071: break;
072: case RESPONSE_CANCEL:
073: return;
074: }
075: editor.repaintNow();
076: }
077: editor.setWaitCursor();
078: if (!save || buffer.save()) {
079: FastStringBuffer sb = new FastStringBuffer("-u \"");
080: sb.append(patchFile.canonicalPath());
081: sb.append("\" \"");
082: sb.append(file.canonicalPath());
083: sb.append('"');
084: diff(sb.toString());
085: }
086: return;
087: }
088: }
089: diff("--help");
090: }
091:
092: public static void diff(String args) {
093: final Editor editor = Editor.currentEditor();
094: final Buffer parentBuffer = editor.getBuffer();
095: String defaultOptions = "-u ";
096: List argList = Utilities.tokenize(args);
097: for (int i = 0; i < argList.size(); i++) {
098: String arg = (String) argList.get(i);
099: if (arg.equals("%")) {
100: File file = parentBuffer.getFile();
101: if (file == null) {
102: MessageDialog
103: .showMessageDialog(
104: "There is no file associated with the current buffer.",
105: "Error");
106: return;
107: }
108: if (file.isRemote()) {
109: MessageDialog.showMessageDialog(file.netPath()
110: + " is a remote file.", "Error");
111: return;
112: }
113: if (file.isDirectory()) {
114: MessageDialog.showMessageDialog(file
115: .canonicalPath()
116: + " is a directory.", "Error");
117: return;
118: }
119: // OK.
120: argList.set(i, file.canonicalPath());
121: } else if (arg.startsWith("-")) {
122: defaultOptions = null;
123: } else {
124: File file = File.getInstance(editor
125: .getCurrentDirectory(), arg);
126: if (file.exists())
127: argList.set(i, file.canonicalPath());
128: }
129: }
130: editor.setWaitCursor();
131: FastStringBuffer sb = new FastStringBuffer("diff ");
132: if (defaultOptions != null)
133: sb.append(defaultOptions);
134: for (int i = 0; i < argList.size(); i++) {
135: String s = (String) argList.get(i);
136: if (s.indexOf(' ') >= 0) {
137: sb.append('"');
138: sb.append(s);
139: sb.append('"');
140: } else
141: sb.append(s);
142: sb.append(' ');
143: }
144: String cmdline = sb.toString().trim();
145: ShellCommand shellCommand = new ShellCommand(cmdline);
146: shellCommand.run();
147: String output = shellCommand.getOutput();
148: if (output.length() == 0)
149: MessageDialog.showMessageDialog(editor, "No changes",
150: "diff");
151: else {
152: DiffOutputBuffer buf = new DiffOutputBuffer(parentBuffer,
153: output, 0);
154: buf.setTitle(cmdline);
155: editor.makeNext(buf);
156: editor.activateInOtherWindow(buf);
157: editor.setDefaultCursor();
158: }
159: }
160:
161: public static void gotoFile() {
162: final Editor editor = Editor.currentEditor();
163: if (editor.getDot() == null)
164: return;
165: final Buffer buffer = editor.getBuffer();
166: if (!(buffer instanceof DiffOutputBuffer))
167: return;
168:
169: // If this method is invoked via a mouse event mapping, move dot to
170: // location of mouse click first.
171: AWTEvent e = editor.getDispatcher().getLastEvent();
172: if (e instanceof MouseEvent)
173: editor.mouseMoveDotToPoint((MouseEvent) e);
174:
175: DiffOutputBuffer diffOutputBuffer = (DiffOutputBuffer) buffer;
176: int vcType = diffOutputBuffer.getVCType();
177: switch (vcType) {
178: case VC_P4:
179: p4GotoFile(editor, diffOutputBuffer);
180: break;
181: case VC_CVS:
182: cvsGotoFile(editor, diffOutputBuffer);
183: break;
184: default:
185: localGotoFile(editor, diffOutputBuffer);
186: break;
187: }
188: }
189:
190: private static void cvsGotoFile(Editor editor,
191: DiffOutputBuffer diffOutputBuffer) {
192: final Line dotLine = editor.getDotLine();
193: final int dotOffset = editor.getDotOffset();
194: final String text = dotLine.getText();
195: if (text.startsWith("? ") || text.startsWith("Index: ")) {
196: String filename = text.substring(text.indexOf(' ') + 1);
197: File file = File.getInstance(diffOutputBuffer
198: .getDirectory(), filename);
199: Buffer buf = editor.getBuffer(file);
200: if (buf != null) {
201: if (editor.getOtherEditor() != null) {
202: editor.activateInOtherWindow(buf);
203: } else {
204: editor.makeNext(buf);
205: editor.activate(buf);
206: }
207: }
208: return;
209: }
210: int lineNumber = 0;
211: int count = 0;
212: Line line = dotLine;
213: if (line.getText().startsWith("@@")) {
214: lineNumber = parseLineNumber(line);
215: } else {
216: line = line.previous();
217: while (line != null && !line.getText().startsWith("@@")) {
218: if (!line.getText().startsWith("-"))
219: ++count;
220: line = line.previous();
221: }
222: if (line == null)
223: return;
224: Debug.assertTrue(line.getText().startsWith("@@"));
225: lineNumber = parseLineNumber(line);
226: }
227: // Our line numbers are zero-based.
228: if (--lineNumber < 0)
229: return;
230: lineNumber += count;
231: Buffer parentBuffer = diffOutputBuffer.getParentBuffer();
232: File dir;
233: if (parentBuffer != null)
234: dir = parentBuffer.getCurrentDirectory();
235: else
236: dir = diffOutputBuffer.getDirectory();
237:
238: line = line.previous();
239: while (line != null && !line.getText().startsWith("Index: "))
240: line = line.previous();
241: if (line == null)
242: return;
243: if (line.getText().startsWith("Index: ")) {
244: String filename = line.getText().substring(7);
245: File file = File.getInstance(dir, filename);
246: if (file != null && file.isFile()) {
247: Buffer buf = editor.getBuffer(file);
248: if (buf != null)
249: gotoLocation(editor, buf, lineNumber,
250: dotOffset > 0 ? dotOffset - 1 : 0);
251: }
252: } else
253: Debug.bug();
254: }
255:
256: private static void p4GotoFile(Editor editor,
257: DiffOutputBuffer diffOutputBuffer) {
258: final Line dotLine = editor.getDotLine();
259: final int dotOffset = editor.getDotOffset();
260: final String text = dotLine.getText();
261: int lineNumber = 0;
262: int count = 0;
263: Line line = dotLine;
264: if (line.getText().startsWith("@@")) {
265: lineNumber = parseLineNumber(line);
266: } else {
267: line = line.previous();
268: while (line != null && !line.getText().startsWith("@@")) {
269: if (!line.getText().startsWith("-"))
270: ++count;
271: line = line.previous();
272: }
273: if (line == null)
274: return;
275: Debug.assertTrue(line.getText().startsWith("@@"));
276: lineNumber = parseLineNumber(line);
277: }
278: // Our line numbers are zero-based.
279: if (--lineNumber < 0)
280: return;
281: lineNumber += count;
282: Buffer parentBuffer = diffOutputBuffer.getParentBuffer();
283: File dir;
284: if (parentBuffer != null)
285: dir = parentBuffer.getCurrentDirectory();
286: else
287: dir = diffOutputBuffer.getDirectory();
288: line = line.previous();
289: while (line != null && !line.getText().endsWith(" ===="))
290: line = line.previous();
291: if (line == null)
292: return;
293: int index = line.getText().lastIndexOf(" - ");
294: if (index >= 0) {
295: String filename = line.getText().substring(index + 3);
296: if (filename.endsWith(" ===="))
297: filename = filename.substring(0, filename.length() - 5);
298: File file = File.getInstance(dir, filename);
299: if (file != null && file.isFile()) {
300: Buffer buf = editor.getBuffer(file);
301: if (buf != null)
302: gotoLocation(editor, buf, lineNumber,
303: dotOffset > 0 ? dotOffset - 1 : 0);
304: }
305: }
306: }
307:
308: private static void localGotoFile(Editor editor,
309: DiffOutputBuffer diffOutputBuffer) {
310: final Line dotLine = editor.getDotLine();
311: String filename1 = null;
312: String filename2 = null;
313: ;
314: for (Line line = dotLine; line != null; line = line.previous()) {
315: String text = line.getText();
316: if (text.startsWith("+++ ")) {
317: filename2 = extractFilename(text);
318: } else if (text.startsWith("--- ")) {
319: filename1 = extractFilename(text);
320: if (filename2 == null) {
321: line = line.next();
322: if (line != null)
323: filename2 = extractFilename(line.getText());
324: }
325: break;
326: }
327: }
328: final String text = dotLine.getText();
329: if (text.startsWith("---")) {
330: Buffer buf = editor.getBuffer(File.getInstance(filename1));
331: if (buf != null) {
332: editor.makeNext(buf);
333: editor.activateInOtherWindow(buf);
334: }
335: return;
336: }
337: if (text.startsWith("+++")) {
338: Buffer buf = editor.getBuffer(File.getInstance(filename2));
339: if (buf != null) {
340: editor.makeNext(buf);
341: editor.activateInOtherWindow(buf);
342: }
343: return;
344: }
345: int oldLineNumber = -1;
346: int newLineNumber = -1;
347: int oldLines = 0;
348: int newLines = 0;
349: int unchangedLines = 0;
350: Line line = dotLine;
351: if (line.getText().startsWith("@@")) {
352: oldLineNumber = parseLineNumber(line, '-');
353: newLineNumber = parseLineNumber(line, '+');
354: } else {
355: line = line.previous();
356: while (line != null && !line.getText().startsWith("@@")) {
357: if (line.getText().startsWith("-"))
358: ++oldLines;
359: else if (line.getText().startsWith("+"))
360: ++newLines;
361: else
362: ++unchangedLines;
363: line = line.previous();
364: }
365: if (line == null)
366: return;
367: Debug.assertTrue(line.getText().startsWith("@@"));
368: oldLineNumber = parseLineNumber(line, '-');
369: newLineNumber = parseLineNumber(line, '+');
370: }
371: // Our line numbers are zero-based.
372: --oldLineNumber;
373: --newLineNumber;
374: String filename = filename2;
375: if (text.startsWith("-")) {
376: oldLineNumber += unchangedLines + oldLines;
377: newLineNumber += unchangedLines;
378: filename = filename1;
379: } else if (text.startsWith("+")) {
380: oldLineNumber += unchangedLines;
381: newLineNumber += unchangedLines + newLines;
382: filename = filename2;
383: } else {
384: // Context line.
385: oldLineNumber = oldLineNumber + unchangedLines + oldLines;
386: newLineNumber = newLineNumber + unchangedLines + newLines;
387: File parentFile = diffOutputBuffer.getParentBuffer()
388: .getFile();
389: if (parentFile != null) {
390: String cp = parentFile.canonicalPath();
391: if (cp != null) {
392: if (cp.equals(filename1))
393: filename = filename1;
394: }
395: }
396: }
397: File dir = null;
398: Buffer parentBuffer = diffOutputBuffer.getParentBuffer();
399: if (parentBuffer != null)
400: dir = parentBuffer.getCurrentDirectory();
401: final File file;
402: if (dir != null)
403: file = File.getInstance(dir, filename);
404: else
405: file = File.getInstance(filename);
406: if (file != null && file.isFile()) {
407: Buffer buf = editor.getBuffer(file);
408: if (buf != null) {
409: int lineNumber = (filename == filename1) ? oldLineNumber
410: : newLineNumber;
411: final int offset = editor.getDotOffset();
412: gotoLocation(editor, buf, lineNumber,
413: offset > 0 ? offset - 1 : 0);
414: }
415: }
416: }
417:
418: private static String extractFilename(String s) {
419: if (s.startsWith("+++ ") || s.startsWith("--- "))
420: s = s.substring(4);
421: int index = s.indexOf('\t');
422: return index >= 0 ? s.substring(0, index) : s;
423: }
424:
425: private static void gotoLocation(Editor editor, Buffer buf,
426: int lineNumber, int offset) {
427: if (buf != null) {
428: editor.makeNext(buf);
429: Editor ed = editor.activateInOtherWindow(buf);
430: Position pos = buf.findOriginal(lineNumber, offset);
431: ed.moveDotTo(pos);
432: ed.setUpdateFlag(REFRAME);
433: ed.updateDisplay();
434: }
435: }
436:
437: private static int parseLineNumber(Line line) {
438: return parseLineNumber(line, '+');
439: }
440:
441: private static int parseLineNumber(Line line, char c) {
442: String s = line.getText();
443: int index = s.indexOf(c);
444: if (index < 0)
445: return 0;
446: try {
447: return Utilities.parseInt(s.substring(index + 1));
448: } catch (NumberFormatException e) {
449: Log.error(e);
450: return 0;
451: }
452: }
453: }
|