Project

General

Profile

Revision 218

View differences:

trunk/scripts/archive.js.php
1
<?php
2
// ensure this file is being included by a parent file
3
if( !defined( '_JEXEC' ) && !defined( '_VALID_MOS' ) ) die( 'Restricted access' );
4
/**
5
 * @version $Id$
6
 * @package eXtplorer
7
 * @copyright soeren 2007-2012
8
 * This file is dynamically loaded when something is to be archived
9
 * It handles the callback to control + show the archive progress
10
 */
11
 ?>
12
 function submitArchiveForm( startfrom, msg ) {
13
	var form = Ext.getCmp("simpleform").getForm();
14
	if( startfrom == 0 ) {
15
		Ext.Msg.show({
16
			title: 'Please wait',
17
			msg: msg ? msg : '<?php echo ext_Lang::msg( 'creating_archive', true ) ?>',
18
			progressText: 'Initializing...',
19
			width:300,
20
			progress:true,
21
			closable:false,
22
		});
23
	}
24
	params = getRequestParams();
25
	params.action = 'archive',
26
	params.startfrom = startfrom,
27
	params.confirm = 'true'
28
	
29
	form.submit({
30
		reset: false,
31
		success: function(form, action) {
32
			if( !action.result ) return;
33

  
34
			if( action.result.startfrom > 0 ) {
35
				submitArchiveForm( action.result.startfrom, action.result.message );
36

  
37
				i = action.result.startfrom/action.result.totalitems;
38
				Ext.Msg.updateProgress(i, action.result.startfrom + " of "+action.result.totalitems + " (" + Math.round(100*i)+'% completed)');
39

  
40
				return
41
			} else {
42

  
43
				if( form.findField('download').getValue() ) {
44
					datastore.reload();
45
					Ext.getCmp("dialog").destroy();
46
					Ext.Msg.hide();
47
					location.href = action.result.newlocation;
48
					
49
				} else {
50
					Ext.Msg.alert('<?php echo ext_Lang::msg('success', true) ?>!', action.result.message);
51
					datastore.reload();
52
					Ext.Msg.hide();
53
					Ext.getCmp("dialog").destroy();
54
				}
55
				return;
56
			}
57
		},
58
		failure: function(form, action) {
59
			Ext.Msg.hide();
60
			if( action.result ) {
61
				Ext.Msg.alert('<?php echo ext_Lang::err('error', true) ?>', action.result.error);
62
			} else {
63
				Ext.Msg.alert('<?php echo ext_Lang::err('error', true) ?>', "An unknown Error occured" );
64
			}
65
		},
66
		scope: form,
67
		
68
		params: params
69
	});
70
}
71 0

  
trunk/scripts/app/controller/Forms.js.php
212 212
				reset: false,
213 213
				success: function(frm, action) {
214 214
					statusBarMessage( action.result.message, false, true );
215
					frm.findField('thecode').setValue( action.result.content );
216
					//editAreaLoader.setValue("ext_codefield" + this.id, action.result.content);
215
					frm.findField('code').setValue( action.result.content );
217 216
				},
218 217
				failure: function(form, action) {
219 218
					statusBarMessage( action.result.error, false, false );
trunk/scripts/app/view/forms/Admin.js.php
1
<?php
2
if( !defined( '_JEXEC' )) {
3
	$_REQUEST['action'] = 'include_javascript';
4
	$_GET['subdir'][] = 'app/view/forms';
5
	$_GET['file'][] = str_replace('.php', '', basename(__FILE__) );
6
	include('../../../../index.php');
7
}
8
$permvalues = array(0,1,2,3,7);
9
$permcount = count($GLOBALS["messages"]["miscpermnames"]);
10
?>	
11
  Ext.define('eXtplorer.model.User', {
12
        extend: 'Ext.data.Model',
13
        fields: [
14
            'nuser',
15
            'home_url',
16
            'home_dir',
17
            'permissions',
18
            'home_url',
19
            'no_access',
20
            { name: 'show_hidden', type: 'bool' },
21
            { name: 'active', type: 'bool' },
22
            { name: 'isNew', type: 'bool' }
23
        ],
24
		 proxy: {
25
            type: 'ajax',
26
			url: 'index.php',
27
			extraParams: { option: "com_extplorer", action: "admin" },
28
			reader: {
29
				type: 'json',
30
				root: "users",
31
				totalProperty: "totalCount"
32
			}
33
		}
34
    });
35
var store = Ext.create('Ext.data.Store', {
36
	// destroy the store if the grid is destroyed
37
	autoDestroy: true,
38
	model: 'eXtplorer.model.User',
39
	autoLoad: true,
40
	sorters: [{
41
		property: 'nuser',
42
		direction: 'ASC'
43
	}]
44
});
45

  
46
store.on("update", function( store, record, operation, modifiedFieldNames, eOpts ) {
47
	var action2 = record.get("isNew") == true ? "adduser" : "edituser";
48
	store.sync({
49
		params: {
50
			action2: action2,
51
			user: record
52
		}
53
	});
54
});
55
store.on("remove", function( store, record, operation, modifiedFieldNames, eOpts ) {
56
	alert( operation );
57
});
58
var rowEditing = Ext.create('Ext.grid.plugin.RowEditing', {
59
	clicksToMoveEditor: 1,
60
	autoCancel: true
61
});
62
Ext.define( 'eXtplorer.view.forms.Admin', {
63
	extend: 'Ext.grid.Panel',
64
	store: store,
65
	width: 700,
66
	height: 500,
67
	title: "<?php echo ext_Lang::msg('actusers', true) ?>",
68
    columns: [{
69
        header: '<?php echo ext_Lang::msg( 'miscusername', true ) ?>',
70
        dataIndex: 'nuser',
71
        flex: 1,
72
        editor: {
73
            // defaults to textfield if no xtype is supplied
74
            allowBlank: false
75
        }
76
    },{
77
        header: 'Pass',
78
        dataIndex: 'pass1',
79
        flex: 1,
80
        editor: {
81
            allowBlank: true,
82
            inputType: 'password'
83
        }
84
    },{
85
        header: '<?php echo ext_Lang::msg( 'mischomeurl', true ) ?>',
86
        dataIndex: 'home_url',
87
        flex: 1,
88
        editor: {
89
            allowBlank: true
90
        }
91
    },{
92
        header: '<?php echo ext_Lang::msg( 'mischomedir', true ) ?>',
93
        dataIndex: 'home_dir',
94
        flex: 1,
95
        editor: {
96
            allowBlank: true
97
        }
98
    }, {
99
        header: '<?php echo ext_Lang::msg( 'miscshowhidden', true ) ?>',
100
        dataIndex: 'show_hidden',
101
        renderer: function( value ) {
102
        	return value.toString() == "true" ? "<?php echo $GLOBALS["messages"]["miscyesno"][0] ?>" : "<?php echo $GLOBALS["messages"]["miscyesno"][1] ?>";
103
        },
104
        width: 55,
105
        editor: {
106
            xtype: 'checkbox',
107
            cls: 'x-grid-checkheader-editor'
108
        }
109
    },{
110
        header: '<?php echo ext_Lang::msg( 'mischidepattern', true ) ?>',
111
        dataIndex: 'no_access',
112
        flex: 1,
113
        editor: {
114
            allowBlank: true
115
        }
116
    }, {
117
            header: '<?php echo ext_Lang::msg( 'miscperms', true ) ?>',
118
            dataIndex: 'permissions',
119
            width: 130,
120
            renderer: function(value) {
121
            	switch( value ) {
122
            	<?php 
123
            		for($i=0;$i<$permcount;++$i) {
124
						if( $permvalues[$i]==7) $index = 4;
125
						else $index = $i;
126
						echo 'case "'.$permvalues[$i].'": return "'.ext_lang::msg( array('miscpermnames' => $index)).'";'."\n";
127
					}
128
					?>
129
				}
130
            }, 
131
            editor: new Ext.form.field.ComboBox({
132
                typeAhead: true,
133
                triggerAction: 'all',
134
                selectOnTab: true,
135
                store:[<?php
136
						
137
						for($i=0;$i<$permcount;++$i) {
138
							if( $permvalues[$i]==7) $index = 4;
139
							else $index = $i;
140
							echo '["'.$permvalues[$i].'", "'.ext_lang::msg( array('miscpermnames' => $index)).'" ]'."\n";
141
							if( $i+1<$permcount) echo ',';
142
						}
143
						?>
144
					],
145
                lazyRender: true,
146
                listClass: 'x-combo-list-small'
147
            })
148
        }, {
149
            header: '<?php echo ext_Lang::msg( 'miscactive', true ) ?>',
150
            dataIndex: 'active',
151
        renderer: function( value ) {
152
        	return value.toString() == "true" ? "<?php echo $GLOBALS["messages"]["miscyesno"][0] ?>" : "<?php echo $GLOBALS["messages"]["miscyesno"][1] ?>";
153
        },
154
            width: 55,
155
            editor: {
156
                xtype: 'checkbox',
157
                cls: 'x-grid-checkheader-editor'
158
            }
159
        }
160
    ],
161
     tbar: [{
162
		text: '<?php echo ext_Lang::msg( 'miscadduser', true ) ?>',
163
		iconCls: 'user-add',
164
		handler : function() {
165
			rowEditing.cancelEdit();
166

  
167
			// Create a model instance
168
			var r = Ext.create('eXtplorer.model.User', {
169
				nuser: 'NewUser',
170
                show_hidden: true,
171
                active: true,
172
                isNew: true
173
            });
174

  
175
            store.insert(0, r);
176
            rowEditing.startEdit(0, 0);
177
        }
178
    }, {
179
        itemId: 'removeUser',
180
        text: 'Remove User',
181
        iconCls: 'user-remove',
182
        handler: function() {
183
            var sm = this.up("gridpanel").getSelectionModel();
184
            rowEditing.cancelEdit();
185
            store.remove(sm.getSelection());
186
            if (store.getCount() > 0) {
187
                sm.select(0);
188
            }
189
        },
190
        disabled: true
191
    }],
192
    plugins: [rowEditing],
193
    listeners: {
194
        'selectionchange': function(view, records) {
195
            this.down('#removeUser').setDisabled(!records.length);
196
        }
197
    }
198
});
199 0

  
trunk/scripts/app/view/forms/Edit.js.php
5 5
	$_GET['file'][] = str_replace('.php', '', basename(__FILE__) );
6 6
	include('../../../../index.php');
7 7
}
8
include( '../../../codemirror/lib/codemirror.js' );
9

  
10
include( '../../../extjs-ux/codemirror/Ext.ux.form.field.CodeMirror.js');
11
include( '../../../codemirror/lib/util/dialog.js' );
12
include( '../../../codemirror/lib/util/foldcode.js' );
13
include( '../../../codemirror/lib/util/search.js' );
14
include( '../../../codemirror/lib/util/searchcursor.js' );
8 15
?>
9 16
Ext.define( 'eXtplorer.view.forms.Edit', {
10 17
	extend: 'Ext.form.Panel',
11 18
	labelWidth: 300,
12 19
	autoScroll: true,
13 20
	
14
	url:"<?php echo basename( $GLOBALS['script_name']) ?>",
15
	
16 21
	initComponent: function() {
17 22
		this.callParent();
18 23
		this.getForm().findField('fname').setValue( this.filename );
trunk/include/init.php
75 75
define ("_EXT_PATH",		realpath(dirname( __FILE__ ) . '/..'));
76 76
define ("_EXT_FTPTMP_PATH", realpath(dirname( __FILE__ ) . '/../ftp_tmp'));
77 77

  
78
set_include_path(get_include_path() . PATH_SEPARATOR .  _EXT_PATH .DIRECTORY_SEPARATOR.'libraries');
79

  
78 80
if (function_exists( 'mosGetParam') || class_exists( 'jconfig')) {
79 81
	define ("_EXT_URL", $GLOBALS['home_url']."/administrator/components/com_extplorer");
80 82
} else {
trunk/include/diff.php
122 122
	{
123 123
	    $hlines1 = explode("\n", $text1);
124 124
        $hlines2 = explode("\n", $text2);
125

  
126
        include_once dirname(dirname(__FILE__)).'/libraries/Text/Diff.php';
125
        include_once dirname(dirname(__FILE__)).'/libraries/Horde/Autoloader.php';
126
        include_once dirname(dirname(__FILE__)).'/libraries/Horde/Autoloader/Default.php';
127
        
128
        include_once dirname(dirname(__FILE__)).'/libraries/Horde/Text/Diff.php';
127 129
		// create the diff object
128
        $diff = new Text_Diff($hlines1, $hlines2);
130
        $diff = new Horde_Text_Diff('auto', array( $hlines1, $hlines2 ));
129 131

  
130 132
        // get the diff in unified format
131 133
        // you can add 4 other parameters, which will be the ins/del prefix/suffix tags
132
		include_once dirname(dirname(__FILE__)).'/libraries/Text/Diff/Renderer/unified.php';
133
        $renderer = new Text_Diff_Renderer_unified();
134
		include_once dirname(dirname(__FILE__)).'/libraries/Horde/Text/Diff/Renderer/unified.php';
135
        $renderer = new Horde_Text_Diff_Renderer_unified();
134 136
		//include_once dirname(dirname(__FILE__)).'/libraries/Text/Diff/Renderer/inline.php';
135 137
        //$renderer = new Text_Diff_Renderer_Inline(50000);
136 138

  
trunk/include/functions.php
883 883
*/
884 884
class extHTML {
885 885
	function loadExtJS() {
886
		$scripts[] = array('dir' => 'scripts/codemirror/lib/', 'file' => 'codemirror.js');
887 886
		$scripts[] = array('dir' => 'scripts/extjs/', 'file' => 'ext-all-debug-w-comments.js');
888 887
		
889
		$scripts[] = array('dir' => 'scripts/extjs-ux/codemirror/', 'file' => 'Ext.ux.form.field.CodeMirror.js');
890 888
		$scripts[] = array('dir' => 'scripts/extjs-ux/statusbar/', 'file' => 'StatusBar.js');
891 889
		$scripts[] = array('dir' => 'scripts/extjs-ux/statusbar/', 'file' => 'ValidationStatus.js');
892 890
		$scripts[] = array('dir' => 'scripts/extjs-ux/swfupload/', 'file' => 'SwfUpload.js');
893 891
		$scripts[] = array('dir' => 'scripts/extjs-ux/swfupload/', 'file' => 'SwfUploadPanel.js');
894 892
		
895 893
		$styles[] = array('dir' => 'scripts/codemirror/lib/', 'file' => 'codemirror.css');
894
		$styles[] = array('dir' => 'scripts/codemirror/lib/util/', 'file' => 'dialog.css');
896 895
		$styles[] = array('dir' => 'scripts/resources/css/', 'file' => 'ext-all-gray.css');
897 896
		$styles[] = array('dir' => 'scripts/extjs-ux/swfupload/', 'file' => 'SwfUploadPanel.css');
898 897
		$styles[] = array('dir' => 'scripts/extjs-ux/statusbar/css/', 'file' => 'statusbar.css');
trunk/admin.extplorer.php
101 101

  
102 102
// Empty the output buffer if this is a XMLHttpRequest
103 103
if( ext_isXHR() ) {
104
	error_reporting(0);
105
	while( @ob_end_clean() );
104
	//error_reporting(0);
105
	//while( @ob_end_clean() );
106 106
}
107 107

  
108 108
if( file_exists( _EXT_PATH . '/include/'. strtolower(basename( $action )) .'.php') ) {
trunk/libraries/Text/Diff/Renderer.php
1
<?php
2
/**
3
 * A class to render Diffs in different formats.
4
 *
5
 * This class renders the diff in classic diff format. It is intended that
6
 * this class be customized via inheritance, to obtain fancier outputs.
7
 *
8
 * $Horde: framework/Text_Diff/Diff/Renderer.php,v 1.5.10.12 2009/07/24 13:26:40 jan Exp $
9
 *
10
 * Copyright 2004-2009 The Horde Project (http://www.horde.org/)
11
 *
12
 * See the enclosed file COPYING for license information (LGPL). If you did
13
 * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
14
 *
15
 * @package Text_Diff
16
 */
17
class Text_Diff_Renderer {
18

  
19
    /**
20
     * Number of leading context "lines" to preserve.
21
     *
22
     * This should be left at zero for this class, but subclasses may want to
23
     * set this to other values.
24
     */
25
    var $_leading_context_lines = 0;
26

  
27
    /**
28
     * Number of trailing context "lines" to preserve.
29
     *
30
     * This should be left at zero for this class, but subclasses may want to
31
     * set this to other values.
32
     */
33
    var $_trailing_context_lines = 0;
34

  
35
    /**
36
     * Constructor.
37
     */
38
    function Text_Diff_Renderer($params = array())
39
    {
40
        foreach ($params as $param => $value) {
41
            $v = '_' . $param;
42
            if (isset($this->$v)) {
43
                $this->$v = $value;
44
            }
45
        }
46
    }
47

  
48
    /**
49
     * Get any renderer parameters.
50
     *
51
     * @return array  All parameters of this renderer object.
52
     */
53
    function getParams()
54
    {
55
        $params = array();
56
        foreach (get_object_vars($this) as $k => $v) {
57
            if ($k[0] == '_') {
58
                $params[substr($k, 1)] = $v;
59
            }
60
        }
61

  
62
        return $params;
63
    }
64

  
65
    /**
66
     * Renders a diff.
67
     *
68
     * @param Text_Diff $diff  A Text_Diff object.
69
     *
70
     * @return string  The formatted output.
71
     */
72
    function render($diff)
73
    {
74
        $xi = $yi = 1;
75
        $block = false;
76
        $context = array();
77

  
78
        $nlead = $this->_leading_context_lines;
79
        $ntrail = $this->_trailing_context_lines;
80

  
81
        $output = $this->_startDiff();
82

  
83
        $diffs = $diff->getDiff();
84
        foreach ($diffs as $i => $edit) {
85
            /* If these are unchanged (copied) lines, and we want to keep
86
             * leading or trailing context lines, extract them from the copy
87
             * block. */
88
            if (is_a($edit, 'Text_Diff_Op_copy')) {
89
                /* Do we have any diff blocks yet? */
90
                if (is_array($block)) {
91
                    /* How many lines to keep as context from the copy
92
                     * block. */
93
                    $keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail;
94
                    if (count($edit->orig) <= $keep) {
95
                        /* We have less lines in the block than we want for
96
                         * context => keep the whole block. */
97
                        $block[] = $edit;
98
                    } else {
99
                        if ($ntrail) {
100
                            /* Create a new block with as many lines as we need
101
                             * for the trailing context. */
102
                            $context = array_slice($edit->orig, 0, $ntrail);
103
                            $block[] = new Text_Diff_Op_copy($context);
104
                        }
105
                        /* @todo */
106
                        $output .= $this->_block($x0, $ntrail + $xi - $x0,
107
                                                 $y0, $ntrail + $yi - $y0,
108
                                                 $block);
109
                        $block = false;
110
                    }
111
                }
112
                /* Keep the copy block as the context for the next block. */
113
                $context = $edit->orig;
114
            } else {
115
                /* Don't we have any diff blocks yet? */
116
                if (!is_array($block)) {
117
                    /* Extract context lines from the preceding copy block. */
118
                    $context = array_slice($context, count($context) - $nlead);
119
                    $x0 = $xi - count($context);
120
                    $y0 = $yi - count($context);
121
                    $block = array();
122
                    if ($context) {
123
                        $block[] = new Text_Diff_Op_copy($context);
124
                    }
125
                }
126
                $block[] = $edit;
127
            }
128

  
129
            if ($edit->orig) {
130
                $xi += count($edit->orig);
131
            }
132
            if ($edit->final) {
133
                $yi += count($edit->final);
134
            }
135
        }
136

  
137
        if (is_array($block)) {
138
            $output .= $this->_block($x0, $xi - $x0,
139
                                     $y0, $yi - $y0,
140
                                     $block);
141
        }
142

  
143
        return $output . $this->_endDiff();
144
    }
145

  
146
    function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
147
    {
148
        $output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
149

  
150
        foreach ($edits as $edit) {
151
            switch (strtolower(get_class($edit))) {
152
            case 'text_diff_op_copy':
153
                $output .= $this->_context($edit->orig);
154
                break;
155

  
156
            case 'text_diff_op_add':
157
                $output .= $this->_added($edit->final);
158
                break;
159

  
160
            case 'text_diff_op_delete':
161
                $output .= $this->_deleted($edit->orig);
162
                break;
163

  
164
            case 'text_diff_op_change':
165
                $output .= $this->_changed($edit->orig, $edit->final);
166
                break;
167
            }
168
        }
169

  
170
        return $output . $this->_endBlock();
171
    }
172

  
173
    function _startDiff()
174
    {
175
        return '';
176
    }
177

  
178
    function _endDiff()
179
    {
180
        return '';
181
    }
182

  
183
    function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
184
    {
185
        if ($xlen > 1) {
186
            $xbeg .= ',' . ($xbeg + $xlen - 1);
187
        }
188
        if ($ylen > 1) {
189
            $ybeg .= ',' . ($ybeg + $ylen - 1);
190
        }
191

  
192
        // this matches the GNU Diff behaviour
193
        if ($xlen && !$ylen) {
194
            $ybeg--;
195
        } elseif (!$xlen) {
196
            $xbeg--;
197
        }
198

  
199
        return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
200
    }
201

  
202
    function _startBlock($header)
203
    {
204
        return $header . "\n";
205
    }
206

  
207
    function _endBlock()
208
    {
209
        return '';
210
    }
211

  
212
    function _lines($lines, $prefix = ' ')
213
    {
214
        return $prefix . implode("\n$prefix", $lines) . "\n";
215
    }
216

  
217
    function _context($lines)
218
    {
219
        return $this->_lines($lines, '  ');
220
    }
221

  
222
    function _added($lines)
223
    {
224
        return $this->_lines($lines, '> ');
225
    }
226

  
227
    function _deleted($lines)
228
    {
229
        return $this->_lines($lines, '< ');
230
    }
231

  
232
    function _changed($orig, $final)
233
    {
234
        return $this->_deleted($orig) . "---\n" . $this->_added($final);
235
    }
236

  
237
}
238 0

  
trunk/libraries/Text/Diff/Mapped.php
1
<?php
2
/**
3
 * $Horde: framework/Text_Diff/Diff/Mapped.php,v 1.3.2.4 2009/01/06 15:23:41 jan Exp $
4
 *
5
 * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
6
 *
7
 * See the enclosed file COPYING for license information (LGPL). If you did
8
 * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
9
 *
10
 * @package Text_Diff
11
 * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
12
 */
13
class Text_Diff_Mapped extends Text_Diff {
14

  
15
    /**
16
     * Computes a diff between sequences of strings.
17
     *
18
     * This can be used to compute things like case-insensitve diffs, or diffs
19
     * which ignore changes in white-space.
20
     *
21
     * @param array $from_lines         An array of strings.
22
     * @param array $to_lines           An array of strings.
23
     * @param array $mapped_from_lines  This array should have the same size
24
     *                                  number of elements as $from_lines.  The
25
     *                                  elements in $mapped_from_lines and
26
     *                                  $mapped_to_lines are what is actually
27
     *                                  compared when computing the diff.
28
     * @param array $mapped_to_lines    This array should have the same number
29
     *                                  of elements as $to_lines.
30
     */
31
    function Text_Diff_Mapped($from_lines, $to_lines,
32
                              $mapped_from_lines, $mapped_to_lines)
33
    {
34
        assert(count($from_lines) == count($mapped_from_lines));
35
        assert(count($to_lines) == count($mapped_to_lines));
36

  
37
        parent::Text_Diff($mapped_from_lines, $mapped_to_lines);
38

  
39
        $xi = $yi = 0;
40
        for ($i = 0; $i < count($this->_edits); $i++) {
41
            $orig = &$this->_edits[$i]->orig;
42
            if (is_array($orig)) {
43
                $orig = array_slice($from_lines, $xi, count($orig));
44
                $xi += count($orig);
45
            }
46

  
47
            $final = &$this->_edits[$i]->final;
48
            if (is_array($final)) {
49
                $final = array_slice($to_lines, $yi, count($final));
50
                $yi += count($final);
51
            }
52
        }
53
    }
54

  
55
}
56 0

  
trunk/libraries/Text/Diff/ThreeWay.php
1
<?php
2
/**
3
 * A class for computing three way diffs.
4
 *
5
 * $Horde: framework/Text_Diff/Diff/ThreeWay.php,v 1.3.2.4 2009/01/06 15:23:41 jan Exp $
6
 *
7
 * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
8
 *
9
 * See the enclosed file COPYING for license information (LGPL). If you did
10
 * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
11
 *
12
 * @package Text_Diff
13
 * @since   0.3.0
14
 */
15

  
16
/** Text_Diff */
17
require_once 'Text/Diff.php';
18

  
19
/**
20
 * A class for computing three way diffs.
21
 *
22
 * @package Text_Diff
23
 * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
24
 */
25
class Text_Diff_ThreeWay extends Text_Diff {
26

  
27
    /**
28
     * Conflict counter.
29
     *
30
     * @var integer
31
     */
32
    var $_conflictingBlocks = 0;
33

  
34
    /**
35
     * Computes diff between 3 sequences of strings.
36
     *
37
     * @param array $orig    The original lines to use.
38
     * @param array $final1  The first version to compare to.
39
     * @param array $final2  The second version to compare to.
40
     */
41
    function Text_Diff_ThreeWay($orig, $final1, $final2)
42
    {
43
        if (extension_loaded('xdiff')) {
44
            $engine = new Text_Diff_Engine_xdiff();
45
        } else {
46
            $engine = new Text_Diff_Engine_native();
47
        }
48

  
49
        $this->_edits = $this->_diff3($engine->diff($orig, $final1),
50
                                      $engine->diff($orig, $final2));
51
    }
52

  
53
    /**
54
     */
55
    function mergedOutput($label1 = false, $label2 = false)
56
    {
57
        $lines = array();
58
        foreach ($this->_edits as $edit) {
59
            if ($edit->isConflict()) {
60
                /* FIXME: this should probably be moved somewhere else. */
61
                $lines = array_merge($lines,
62
                                     array('<<<<<<<' . ($label1 ? ' ' . $label1 : '')),
63
                                     $edit->final1,
64
                                     array("======="),
65
                                     $edit->final2,
66
                                     array('>>>>>>>' . ($label2 ? ' ' . $label2 : '')));
67
                $this->_conflictingBlocks++;
68
            } else {
69
                $lines = array_merge($lines, $edit->merged());
70
            }
71
        }
72

  
73
        return $lines;
74
    }
75

  
76
    /**
77
     * @access private
78
     */
79
    function _diff3($edits1, $edits2)
80
    {
81
        $edits = array();
82
        $bb = new Text_Diff_ThreeWay_BlockBuilder();
83

  
84
        $e1 = current($edits1);
85
        $e2 = current($edits2);
86
        while ($e1 || $e2) {
87
            if ($e1 && $e2 && is_a($e1, 'Text_Diff_Op_copy') && is_a($e2, 'Text_Diff_Op_copy')) {
88
                /* We have copy blocks from both diffs. This is the (only)
89
                 * time we want to emit a diff3 copy block.  Flush current
90
                 * diff3 diff block, if any. */
91
                if ($edit = $bb->finish()) {
92
                    $edits[] = $edit;
93
                }
94

  
95
                $ncopy = min($e1->norig(), $e2->norig());
96
                assert($ncopy > 0);
97
                $edits[] = new Text_Diff_ThreeWay_Op_copy(array_slice($e1->orig, 0, $ncopy));
98

  
99
                if ($e1->norig() > $ncopy) {
100
                    array_splice($e1->orig, 0, $ncopy);
101
                    array_splice($e1->final, 0, $ncopy);
102
                } else {
103
                    $e1 = next($edits1);
104
                }
105

  
106
                if ($e2->norig() > $ncopy) {
107
                    array_splice($e2->orig, 0, $ncopy);
108
                    array_splice($e2->final, 0, $ncopy);
109
                } else {
110
                    $e2 = next($edits2);
111
                }
112
            } else {
113
                if ($e1 && $e2) {
114
                    if ($e1->orig && $e2->orig) {
115
                        $norig = min($e1->norig(), $e2->norig());
116
                        $orig = array_splice($e1->orig, 0, $norig);
117
                        array_splice($e2->orig, 0, $norig);
118
                        $bb->input($orig);
119
                    }
120

  
121
                    if (is_a($e1, 'Text_Diff_Op_copy')) {
122
                        $bb->out1(array_splice($e1->final, 0, $norig));
123
                    }
124

  
125
                    if (is_a($e2, 'Text_Diff_Op_copy')) {
126
                        $bb->out2(array_splice($e2->final, 0, $norig));
127
                    }
128
                }
129

  
130
                if ($e1 && ! $e1->orig) {
131
                    $bb->out1($e1->final);
132
                    $e1 = next($edits1);
133
                }
134
                if ($e2 && ! $e2->orig) {
135
                    $bb->out2($e2->final);
136
                    $e2 = next($edits2);
137
                }
138
            }
139
        }
140

  
141
        if ($edit = $bb->finish()) {
142
            $edits[] = $edit;
143
        }
144

  
145
        return $edits;
146
    }
147

  
148
}
149

  
150
/**
151
 * @package Text_Diff
152
 * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
153
 *
154
 * @access private
155
 */
156
class Text_Diff_ThreeWay_Op {
157

  
158
    function Text_Diff_ThreeWay_Op($orig = false, $final1 = false, $final2 = false)
159
    {
160
        $this->orig = $orig ? $orig : array();
161
        $this->final1 = $final1 ? $final1 : array();
162
        $this->final2 = $final2 ? $final2 : array();
163
    }
164

  
165
    function merged()
166
    {
167
        if (!isset($this->_merged)) {
168
            if ($this->final1 === $this->final2) {
169
                $this->_merged = &$this->final1;
170
            } elseif ($this->final1 === $this->orig) {
171
                $this->_merged = &$this->final2;
172
            } elseif ($this->final2 === $this->orig) {
173
                $this->_merged = &$this->final1;
174
            } else {
175
                $this->_merged = false;
176
            }
177
        }
178

  
179
        return $this->_merged;
180
    }
181

  
182
    function isConflict()
183
    {
184
        return $this->merged() === false;
185
    }
186

  
187
}
188

  
189
/**
190
 * @package Text_Diff
191
 * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
192
 *
193
 * @access private
194
 */
195
class Text_Diff_ThreeWay_Op_copy extends Text_Diff_ThreeWay_Op {
196

  
197
    function Text_Diff_ThreeWay_Op_Copy($lines = false)
198
    {
199
        $this->orig = $lines ? $lines : array();
200
        $this->final1 = &$this->orig;
201
        $this->final2 = &$this->orig;
202
    }
203

  
204
    function merged()
205
    {
206
        return $this->orig;
207
    }
208

  
209
    function isConflict()
210
    {
211
        return false;
212
    }
213

  
214
}
215

  
216
/**
217
 * @package Text_Diff
218
 * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
219
 *
220
 * @access private
221
 */
222
class Text_Diff_ThreeWay_BlockBuilder {
223

  
224
    function Text_Diff_ThreeWay_BlockBuilder()
225
    {
226
        $this->_init();
227
    }
228

  
229
    function input($lines)
230
    {
231
        if ($lines) {
232
            $this->_append($this->orig, $lines);
233
        }
234
    }
235

  
236
    function out1($lines)
237
    {
238
        if ($lines) {
239
            $this->_append($this->final1, $lines);
240
        }
241
    }
242

  
243
    function out2($lines)
244
    {
245
        if ($lines) {
246
            $this->_append($this->final2, $lines);
247
        }
248
    }
249

  
250
    function isEmpty()
251
    {
252
        return !$this->orig && !$this->final1 && !$this->final2;
253
    }
254

  
255
    function finish()
256
    {
257
        if ($this->isEmpty()) {
258
            return false;
259
        } else {
260
            $edit = new Text_Diff_ThreeWay_Op($this->orig, $this->final1, $this->final2);
261
            $this->_init();
262
            return $edit;
263
        }
264
    }
265

  
266
    function _init()
267
    {
268
        $this->orig = $this->final1 = $this->final2 = array();
269
    }
270

  
271
    function _append(&$array, $lines)
272
    {
273
        array_splice($array, sizeof($array), 0, $lines);
274
    }
275

  
276
}
277 0

  
trunk/libraries/Text/Diff/Engine/xdiff.php
1
<?php
2
/**
3
 * Class used internally by Diff to actually compute the diffs.
4
 *
5
 * This class uses the xdiff PECL package (http://pecl.php.net/package/xdiff)
6
 * to compute the differences between the two input arrays.
7
 *
8
 * $Horde: framework/Text_Diff/Diff/Engine/xdiff.php,v 1.4.2.5 2009/07/24 13:06:24 jan Exp $
9
 *
10
 * Copyright 2004-2009 The Horde Project (http://www.horde.org/)
11
 *
12
 * See the enclosed file COPYING for license information (LGPL). If you did
13
 * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
14
 *
15
 * @author  Jon Parise <jon@horde.org>
16
 * @package Text_Diff
17
 */
18
class Text_Diff_Engine_xdiff {
19

  
20
    /**
21
     */
22
    function diff($from_lines, $to_lines)
23
    {
24
        array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
25
        array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
26

  
27
        /* Convert the two input arrays into strings for xdiff processing. */
28
        $from_string = implode("\n", $from_lines);
29
        $to_string = implode("\n", $to_lines);
30

  
31
        /* Diff the two strings and convert the result to an array. */
32
        $diff = xdiff_string_diff($from_string, $to_string, count($to_lines));
33
        $diff = explode("\n", $diff);
34

  
35
        /* Walk through the diff one line at a time.  We build the $edits
36
         * array of diff operations by reading the first character of the
37
         * xdiff output (which is in the "unified diff" format).
38
         *
39
         * Note that we don't have enough information to detect "changed"
40
         * lines using this approach, so we can't add Text_Diff_Op_changed
41
         * instances to the $edits array.  The result is still perfectly
42
         * valid, albeit a little less descriptive and efficient. */
43
        $edits = array();
44
        foreach ($diff as $line) {
45
            if (!strlen($line)) {
46
                continue;
47
            }
48
            switch ($line[0]) {
49
            case ' ':
50
                $edits[] = &new Text_Diff_Op_copy(array(substr($line, 1)));
51
                break;
52

  
53
            case '+':
54
                $edits[] = &new Text_Diff_Op_add(array(substr($line, 1)));
55
                break;
56

  
57
            case '-':
58
                $edits[] = &new Text_Diff_Op_delete(array(substr($line, 1)));
59
                break;
60
            }
61
        }
62

  
63
        return $edits;
64
    }
65

  
66
}
67 0

  
trunk/libraries/Text/Diff/Engine/string.php
1
<?php
2
/**
3
 * Parses unified or context diffs output from eg. the diff utility.
4
 *
5
 * Example:
6
 * <code>
7
 * $patch = file_get_contents('example.patch');
8
 * $diff = new Text_Diff('string', array($patch));
9
 * $renderer = new Text_Diff_Renderer_inline();
10
 * echo $renderer->render($diff);
11
 * </code>
12
 *
13
 * $Horde: framework/Text_Diff/Diff/Engine/string.php,v 1.5.2.7 2009/07/24 13:04:43 jan Exp $
14
 *
15
 * Copyright 2005 ?rjan Persson <o@42mm.org>
16
 * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
17
 *
18
 * See the enclosed file COPYING for license information (LGPL). If you did
19
 * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
20
 *
21
 * @author  ?rjan Persson <o@42mm.org>
22
 * @package Text_Diff
23
 * @since   0.2.0
24
 */
25
class Text_Diff_Engine_string {
26

  
27
    /**
28
     * Parses a unified or context diff.
29
     *
30
     * First param contains the whole diff and the second can be used to force
31
     * a specific diff type. If the second parameter is 'autodetect', the
32
     * diff will be examined to find out which type of diff this is.
33
     *
34
     * @param string $diff  The diff content.
35
     * @param string $mode  The diff mode of the content in $diff. One of
36
     *                      'context', 'unified', or 'autodetect'.
37
     *
38
     * @return array  List of all diff operations.
39
     */
40
    function diff($diff, $mode = 'autodetect')
41
    {
42
        // Detect line breaks.
43
        $lnbr = "\n";
44
        if (strpos($diff, "\r\n") !== false) {
45
            $lnbr = "\r\n";
46
        } elseif (strpos($diff, "\r") !== false) {
47
            $lnbr = "\r";
48
        }
49

  
50
        // Make sure we have a line break at the EOF.
51
        if (substr($diff, -strlen($lnbr)) != $lnbr) {
52
            $diff .= $lnbr;
53
        }
54

  
55
        if ($mode != 'autodetect' && $mode != 'context' && $mode != 'unified') {
56
            return PEAR::raiseError('Type of diff is unsupported');
57
        }
58

  
59
        if ($mode == 'autodetect') {
60
            $context = strpos($diff, '***');
61
            $unified = strpos($diff, '---');
62
            if ($context === $unified) {
63
                return PEAR::raiseError('Type of diff could not be detected');
64
            } elseif ($context === false || $unified === false) {
65
                $mode = $context !== false ? 'context' : 'unified';
66
            } else {
67
                $mode = $context < $unified ? 'context' : 'unified';
68
            }
69
        }
70

  
71
        // Split by new line and remove the diff header, if there is one.
72
        $diff = explode($lnbr, $diff);
73
        if (($mode == 'context' && strpos($diff[0], '***') === 0) ||
74
            ($mode == 'unified' && strpos($diff[0], '---') === 0)) {
75
            array_shift($diff);
76
            array_shift($diff);
77
        }
78

  
79
        if ($mode == 'context') {
80
            return $this->parseContextDiff($diff);
81
        } else {
82
            return $this->parseUnifiedDiff($diff);
83
        }
84
    }
85

  
86
    /**
87
     * Parses an array containing the unified diff.
88
     *
89
     * @param array $diff  Array of lines.
90
     *
91
     * @return array  List of all diff operations.
92
     */
93
    function parseUnifiedDiff($diff)
94
    {
95
        $edits = array();
96
        $end = count($diff) - 1;
97
        for ($i = 0; $i < $end;) {
98
            $diff1 = array();
99
            switch (substr($diff[$i], 0, 1)) {
100
            case ' ':
101
                do {
102
                    $diff1[] = substr($diff[$i], 1);
103
                } while (++$i < $end && substr($diff[$i], 0, 1) == ' ');
104
                $edits[] = new Text_Diff_Op_copy($diff1);
105
                break;
106

  
107
            case '+':
108
                // get all new lines
109
                do {
110
                    $diff1[] = substr($diff[$i], 1);
111
                } while (++$i < $end && substr($diff[$i], 0, 1) == '+');
112
                $edits[] = new Text_Diff_Op_add($diff1);
113
                break;
114

  
115
            case '-':
116
                // get changed or removed lines
117
                $diff2 = array();
118
                do {
119
                    $diff1[] = substr($diff[$i], 1);
120
                } while (++$i < $end && substr($diff[$i], 0, 1) == '-');
121

  
122
                while ($i < $end && substr($diff[$i], 0, 1) == '+') {
123
                    $diff2[] = substr($diff[$i++], 1);
124
                }
125
                if (count($diff2) == 0) {
126
                    $edits[] = new Text_Diff_Op_delete($diff1);
127
                } else {
128
                    $edits[] = new Text_Diff_Op_change($diff1, $diff2);
129
                }
130
                break;
131

  
132
            default:
133
                $i++;
134
                break;
135
            }
136
        }
137

  
138
        return $edits;
139
    }
140

  
141
    /**
142
     * Parses an array containing the context diff.
143
     *
144
     * @param array $diff  Array of lines.
145
     *
146
     * @return array  List of all diff operations.
147
     */
148
    function parseContextDiff(&$diff)
149
    {
150
        $edits = array();
151
        $i = $max_i = $j = $max_j = 0;
152
        $end = count($diff) - 1;
153
        while ($i < $end && $j < $end) {
154
            while ($i >= $max_i && $j >= $max_j) {
155
                // Find the boundaries of the diff output of the two files
156
                for ($i = $j;
157
                     $i < $end && substr($diff[$i], 0, 3) == '***';
158
                     $i++);
159
                for ($max_i = $i;
160
                     $max_i < $end && substr($diff[$max_i], 0, 3) != '---';
161
                     $max_i++);
162
                for ($j = $max_i;
163
                     $j < $end && substr($diff[$j], 0, 3) == '---';
164
                     $j++);
165
                for ($max_j = $j;
166
                     $max_j < $end && substr($diff[$max_j], 0, 3) != '***';
167
                     $max_j++);
168
            }
169

  
170
            // find what hasn't been changed
171
            $array = array();
172
            while ($i < $max_i &&
173
                   $j < $max_j &&
174
                   strcmp($diff[$i], $diff[$j]) == 0) {
175
                $array[] = substr($diff[$i], 2);
176
                $i++;
177
                $j++;
178
            }
179

  
180
            while ($i < $max_i && ($max_j-$j) <= 1) {
181
                if ($diff[$i] != '' && substr($diff[$i], 0, 1) != ' ') {
182
                    break;
183
                }
184
                $array[] = substr($diff[$i++], 2);
185
            }
186

  
187
            while ($j < $max_j && ($max_i-$i) <= 1) {
188
                if ($diff[$j] != '' && substr($diff[$j], 0, 1) != ' ') {
189
                    break;
190
                }
191
                $array[] = substr($diff[$j++], 2);
192
            }
193
            if (count($array) > 0) {
194
                $edits[] = new Text_Diff_Op_copy($array);
195
            }
196

  
197
            if ($i < $max_i) {
198
                $diff1 = array();
199
                switch (substr($diff[$i], 0, 1)) {
200
                case '!':
201
                    $diff2 = array();
202
                    do {
203
                        $diff1[] = substr($diff[$i], 2);
204
                        if ($j < $max_j && substr($diff[$j], 0, 1) == '!') {
205
                            $diff2[] = substr($diff[$j++], 2);
206
                        }
207
                    } while (++$i < $max_i && substr($diff[$i], 0, 1) == '!');
208
                    $edits[] = new Text_Diff_Op_change($diff1, $diff2);
209
                    break;
210

  
211
                case '+':
212
                    do {
213
                        $diff1[] = substr($diff[$i], 2);
214
                    } while (++$i < $max_i && substr($diff[$i], 0, 1) == '+');
215
                    $edits[] = new Text_Diff_Op_add($diff1);
216
                    break;
217

  
218
                case '-':
219
                    do {
220
                        $diff1[] = substr($diff[$i], 2);
221
                    } while (++$i < $max_i && substr($diff[$i], 0, 1) == '-');
222
                    $edits[] = new Text_Diff_Op_delete($diff1);
223
                    break;
224
                }
225
            }
226

  
227
            if ($j < $max_j) {
228
                $diff2 = array();
229
                switch (substr($diff[$j], 0, 1)) {
230
                case '+':
231
                    do {
232
                        $diff2[] = substr($diff[$j++], 2);
233
                    } while ($j < $max_j && substr($diff[$j], 0, 1) == '+');
234
                    $edits[] = new Text_Diff_Op_add($diff2);
235
                    break;
236

  
237
                case '-':
238
                    do {
239
                        $diff2[] = substr($diff[$j++], 2);
240
                    } while ($j < $max_j && substr($diff[$j], 0, 1) == '-');
241
                    $edits[] = new Text_Diff_Op_delete($diff2);
242
                    break;
243
                }
244
            }
245
        }
246

  
247
        return $edits;
248
    }
249

  
250
}
251 0

  
trunk/libraries/Text/Diff/Engine/native.php
1
<?php
2
/**
3
 * Class used internally by Text_Diff to actually compute the diffs.
4
 *
5
 * This class is implemented using native PHP code.
6
 *
7
 * The algorithm used here is mostly lifted from the perl module
8
 * Algorithm::Diff (version 1.06) by Ned Konz, which is available at:
9
 * http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip
10
 *
11
 * More ideas are taken from: http://www.ics.uci.edu/~eppstein/161/960229.html
12
 *
13
 * Some ideas (and a bit of code) are taken from analyze.c, of GNU
14
 * diffutils-2.7, which can be found at:
15
 * ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz
16
 *
17
 * Some ideas (subdivision by NCHUNKS > 2, and some optimizations) are from
18
 * Geoffrey T. Dairiki <dairiki@dairiki.org>. The original PHP version of this
19
 * code was written by him, and is used/adapted with his permission.
20
 *
21
 * $Horde: framework/Text_Diff/Diff/Engine/native.php,v 1.7.2.5 2009/01/06 15:23:41 jan Exp $
22
 *
23
 * Copyright 2004-2009 The Horde Project (http://www.horde.org/)
24
 *
25
 * See the enclosed file COPYING for license information (LGPL). If you did
26
 * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
27
 *
28
 * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
29
 * @package Text_Diff
30
 */
31
class Text_Diff_Engine_native {
32

  
33
    function diff($from_lines, $to_lines)
34
    {
35
        array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
36
        array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
37

  
38
        $n_from = count($from_lines);
39
        $n_to = count($to_lines);
40

  
41
        $this->xchanged = $this->ychanged = array();
42
        $this->xv = $this->yv = array();
43
        $this->xind = $this->yind = array();
44
        unset($this->seq);
45
        unset($this->in_seq);
46
        unset($this->lcs);
47

  
48
        // Skip leading common lines.
49
        for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) {
50
            if ($from_lines[$skip] !== $to_lines[$skip]) {
51
                break;
52
            }
53
            $this->xchanged[$skip] = $this->ychanged[$skip] = false;
54
        }
55

  
56
        // Skip trailing common lines.
57
        $xi = $n_from; $yi = $n_to;
58
        for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) {
59
            if ($from_lines[$xi] !== $to_lines[$yi]) {
60
                break;
61
            }
62
            $this->xchanged[$xi] = $this->ychanged[$yi] = false;
63
        }
64

  
65
        // Ignore lines which do not exist in both files.
66
        for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
67
            $xhash[$from_lines[$xi]] = 1;
68
        }
69
        for ($yi = $skip; $yi < $n_to - $endskip; $yi++) {
70
            $line = $to_lines[$yi];
71
            if (($this->ychanged[$yi] = empty($xhash[$line]))) {
72
                continue;
73
            }
74
            $yhash[$line] = 1;
75
            $this->yv[] = $line;
76
            $this->yind[] = $yi;
77
        }
78
        for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
79
            $line = $from_lines[$xi];
80
            if (($this->xchanged[$xi] = empty($yhash[$line]))) {
81
                continue;
82
            }
83
            $this->xv[] = $line;
84
            $this->xind[] = $xi;
85
        }
86

  
87
        // Find the LCS.
88
        $this->_compareseq(0, count($this->xv), 0, count($this->yv));
89

  
90
        // Merge edits when possible.
91
        $this->_shiftBoundaries($from_lines, $this->xchanged, $this->ychanged);
92
        $this->_shiftBoundaries($to_lines, $this->ychanged, $this->xchanged);
93

  
94
        // Compute the edit operations.
95
        $edits = array();
96
        $xi = $yi = 0;
97
        while ($xi < $n_from || $yi < $n_to) {
98
            assert($yi < $n_to || $this->xchanged[$xi]);
99
            assert($xi < $n_from || $this->ychanged[$yi]);
100

  
101
            // Skip matching "snake".
102
            $copy = array();
103
            while ($xi < $n_from && $yi < $n_to
104
                   && !$this->xchanged[$xi] && !$this->ychanged[$yi]) {
105
                $copy[] = $from_lines[$xi++];
106
                ++$yi;
107
            }
108
            if ($copy) {
109
                $edits[] = &new Text_Diff_Op_copy($copy);
110
            }
111

  
112
            // Find deletes & adds.
113
            $delete = array();
114
            while ($xi < $n_from && $this->xchanged[$xi]) {
115
                $delete[] = $from_lines[$xi++];
116
            }
117

  
118
            $add = array();
119
            while ($yi < $n_to && $this->ychanged[$yi]) {
120
                $add[] = $to_lines[$yi++];
121
            }
122

  
123
            if ($delete && $add) {
124
                $edits[] = &new Text_Diff_Op_change($delete, $add);
125
            } elseif ($delete) {
126
                $edits[] = &new Text_Diff_Op_delete($delete);
127
            } elseif ($add) {
128
                $edits[] = &new Text_Diff_Op_add($add);
129
            }
130
        }
131

  
132
        return $edits;
133
    }
134

  
135
    /**
136
     * Divides the Largest Common Subsequence (LCS) of the sequences (XOFF,
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff