The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .github
    └── workflows
    │   └── release.yml
├── .gitignore
├── .travis.yml
├── ChangeLog
├── LICENSE
├── MANIFEST.in
├── README.md
├── git-icdiff
├── icdiff
├── icdiff.py
├── requirements-dev.txt
├── setup.py
├── test.sh
└── tests
    ├── a
        ├── 1
        ├── c
        │   ├── e
        │   └── f
        └── j
    ├── b
        ├── 1
        ├── c
        │   ├── e
        │   ├── f
        │   ├── g
        │   └── h
        ├── d
        │   └── q
        └── i
    ├── gitdiff-only-newlines.txt
    ├── gold-12-subcolors.txt
    ├── gold-12-t.txt
    ├── gold-12.txt
    ├── gold-3.txt
    ├── gold-45-95.txt
    ├── gold-45-h-nb.txt
    ├── gold-45-h.txt
    ├── gold-45-h3.txt
    ├── gold-45-l.txt
    ├── gold-45-lbrb.txt
    ├── gold-45-ln-color.txt
    ├── gold-45-ln.txt
    ├── gold-45-lr.txt
    ├── gold-45-nb.txt
    ├── gold-45-nh.txt
    ├── gold-45-pipe.txt
    ├── gold-45-sas-h-nb.txt
    ├── gold-45-sas-h.txt
    ├── gold-45-sas.txt
    ├── gold-45.txt
    ├── gold-4dn.txt
    ├── gold-67-ln.txt
    ├── gold-67-u3.txt
    ├── gold-67-wf.txt
    ├── gold-67.txt
    ├── gold-bad-encoding.txt
    ├── gold-dir.txt
    ├── gold-dn5.txt
    ├── gold-exclude.txt
    ├── gold-exit-process-sub
    ├── gold-file-not-found.txt
    ├── gold-hide-cr-if-dos
    ├── gold-identical-on.txt
    ├── gold-no-cr-indent
    ├── gold-permissions-diff-binary.txt
    ├── gold-permissions-diff-text.txt
    ├── gold-permissions-diff.txt
    ├── gold-permissions-same.txt
    ├── gold-recursive-with-exclude.txt
    ├── gold-recursive-with-exclude2.txt
    ├── gold-recursive.txt
    ├── gold-sas.txt
    ├── gold-show-spaces.txt
    ├── gold-sns.txt
    ├── gold-strip-cr-off.txt
    ├── gold-strip-cr-on.txt
    ├── gold-subcolors-bad-cat
    ├── gold-subcolors-bad-color
    ├── gold-subcolors-bad-fmt
    ├── gold-tabs-4.txt
    ├── gold-tabs-default.txt
    ├── input-1.txt
    ├── input-10.txt
    ├── input-11.txt
    ├── input-2.txt
    ├── input-3.txt
    ├── input-4-cr.txt
    ├── input-4-partial-cr.txt
    ├── input-4.txt
    ├── input-5-cr.txt
    ├── input-5.txt
    ├── input-6.txt
    ├── input-7.txt
    ├── input-8.txt
    ├── input-9.txt
    └── test-with-exclude
        ├── a
            ├── 1
            ├── c
            │   ├── e
            │   └── f
            ├── exclude
            │   └── text.txt
            └── j
        └── b
            ├── 1
            ├── c
                ├── e
                ├── f
                ├── g
                └── h
            ├── d
                └── q
            ├── exclude
                └── text.txt
            └── i


/.github/workflows/release.yml:
--------------------------------------------------------------------------------
 1 | name: Release Package
 2 | 
 3 | on:
 4 |   push:
 5 |     tags: ["release-*"]
 6 | 
 7 | permissions:
 8 |   contents: read
 9 | 
10 | jobs:
11 |   build_package:
12 |     name: Build Package
13 |     runs-on: ubuntu-latest
14 |     steps:
15 |       - uses: actions/checkout@v3
16 |       - name: Build sdist and wheel
17 |         run: pipx run build --sdist --wheel
18 |       - uses: actions/upload-artifact@v3
19 |         with:
20 |           path: dist
21 | 
22 |   pypi-publish:
23 |     needs: [build_package]
24 |     name: Upload release to PyPI
25 |     runs-on: ubuntu-latest
26 |     environment:
27 |       name: pypi
28 |     permissions:
29 |       id-token: write
30 |     steps:
31 |       - uses: actions/download-artifact@v3
32 |         with:
33 |           name: artifact
34 |           path: dist
35 |       - name: Publish package distributions to PyPI
36 |         uses: pypa/gh-action-pypi-publish@release/v1
37 | 


--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /venv/
2 | 


--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
 1 | language: python
 2 | sudo: required
 3 | dist: xenial
 4 | python:
 5 |   - "3.4"
 6 |   - "3.5"
 7 |   - "3.6"
 8 |   - "3.7"
 9 |   - "3.8"
10 |   - "3.9"
11 |   - "nightly"
12 | script:
13 |   - pip install -r requirements-dev.txt
14 |   - ./test.sh python
15 | git:
16 |   depth: false


--------------------------------------------------------------------------------
/ChangeLog:
--------------------------------------------------------------------------------
  1 | 2.0.7
  2 | 	Add --show-no-spaces #173
  3 | 
  4 | 2.0.6
  5 | 	Fix process exit code for non-file inputs #205
  6 | 	Make fullwidth characters take two columns #202
  7 | 	Add -x/--exclude optin to to exclude files matching patterns #199
  8 | 
  9 | 2.0.5
 10 | 	Set process exit code to indicate differences #195
 11 | 	Support -P/--permissions option #197
 12 | 
 13 | 2.0.4
 14 | 	Include LICENSE in package
 15 | 
 16 | 2.0.3
 17 | 	Attempts to publisher 2.0.1 and 2.0.2 to pypi gave broken packages
 18 | 
 19 | 2.0.1
 20 | 	Add  -t/--truncate option #184
 21 | 
 22 | 2.0.0
 23 | 	Drop support for Python 2
 24 | 	Clearer error on unknown encodings #145
 25 | 	Stop printing an error on closed pipes #156
 26 | 	Fix displayed filed names with git #159
 27 | 	Fix testcase that assumed a git repo #166
 28 | 	Implement --report-identical-files #168
 29 | 	Improved handling of very long lines #180
 30 | 
 31 | 1.9.4
 32 | 	Allow {path} and {basename} in --label #139
 33 | 	Properly implement git difftool protocol #140
 34 | 
 35 | 1.9.3
 36 | 	Properly set the version number
 37 | 
 38 | 1.9.2
 39 | 	Add --exclude-lines (-E) which can exclude comments
 40 | 	Add --color-map so you can choose which colors to use for what #121 #117
 41 | 	Allow highlighted characters to be bold #122
 42 | 	Support configuring git-icdiff with gitconfig
 43 | 	Don't choke on bad terminal sizes #113
 44 | 	Print proper error messages instead of raising exceptions
 45 | 	Allow the line numbers to be colorized
 46 | 	Add a LICENSE file
 47 | 
 48 | 1.9.1
 49 | 	Handle files with CR characters better and add --strip-trailing-cr
 50 | 
 51 | 1.9.0
 52 | 	Fix setup.py by symlinking icdiff to icdiff.py
 53 | 
 54 | 1.8.2
 55 | 	Add short flags for --highlight (-H), --line-numbers (-N), and --whole-file (-W).
 56 | 	Fix use with bash process substitution and other special files
 57 | 
 58 | 1.8.1
 59 | 	Updated remaining copy of unicode test file (b/1)
 60 | 
 61 | 1.8.0
 62 | 	Updated unicode test file (input-3)
 63 | 	Allow testing installed version
 64 | 	Allow importing as a module
 65 | 	Minor deduplication tweak to git-icdiff
 66 | 	Add pip instructions to readme
 67 | 	Allow using --tabsize
 68 | 	Allow non-recursive directory diffing
 69 | 
 70 | 1.7.6
 71 | 	Fixed copyright.
 72 | 
 73 | 1.7.3
 74 | 	Fix git-icdiff to handle filenames with spaces as arguments.
 75 | 
 76 | 1.7.2
 77 | 	Don't stop diffing recursively when encountering a binary file.
 78 | 
 79 | 1.7.1
 80 | 	Don't treat files with identical (mode, size, mtime) as equal.
 81 | 
 82 | 1.7.0
 83 | 	Add tests
 84 | 
 85 | 1.6.4
 86 | 	Unbreak --recursive again
 87 | 
 88 | 1.6.3
 89 | 	Stop setting LESS_IS_MORE with git-icdiff, fixing #33.
 90 | 
 91 | 1.6.2
 92 | 	Add support for setting the output encoding and default to utf8
 93 | 
 94 | 1.6.1
 95 | 	Unbreak --recursive
 96 | 
 97 | 1.6.0
 98 | 	Add support for setting the encoding, and handle fullwidth chars
 99 | 	in python2
100 | 
101 | 1.5.3
102 | 	Support use as an svn difftool.
103 | 	Support -U and -L, and allow but ignore -u.
104 | 
105 | 1.5.2
106 | 	Various pager improvements in git-icdiff.
107 | 
108 | 1.5.1
109 | 	Make --highlight and --no-bold play nice.
110 | 
111 | 1.5.0
112 | 	Pass arguments through to icdiff when using git-icdiff.
113 | 
114 | 1.4.0
115 | 	Use less with "git icdiff" by default.
116 | 
117 | 1.3.2
118 | 	Fix linewrapping with unicode.
119 | 
120 | 1.3.1
121 | 	1.3.0 was completely borked.
122 | 
123 | 1.3.0
124 | 	Use setup.py to support standard python installation.
125 | 
126 | 1.2.2
127 | 	Start printing output as soon as its ready instead of waiting for
128 | 	the whole file to complete.
129 | 
130 | 1.2.1
131 | 	Space fullwidth characters properly when treating input as unicode.
132 | 
133 | 1.2.0
134 | 	Add --recursive to support diffing directory trees.
135 | 
136 | 1.1.2
137 | 	Flush stdout when done.
138 | 
139 | 1.1.1
140 | 	Don't print stack traces on Ctrl+C or when piping into something
141 | 	that quits.
142 | 
143 | 1.1.0
144 | 	Add --no-bold option useful with the solarized colorscheme and for
145 | 	people who just don't like bold.
146 | 
147 | 1.0.0
148 | 	First Release
149 | 


--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
  1 | A. HISTORY OF THE SOFTWARE
  2 | ==========================
  3 | 
  4 | Python was created in the early 1990s by Guido van Rossum at Stichting
  5 | Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
  6 | as a successor of a language called ABC.  Guido remains Python's
  7 | principal author, although it includes many contributions from others.
  8 | 
  9 | In 1995, Guido continued his work on Python at the Corporation for
 10 | National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
 11 | in Reston, Virginia where he released several versions of the
 12 | software.
 13 | 
 14 | In May 2000, Guido and the Python core development team moved to
 15 | BeOpen.com to form the BeOpen PythonLabs team.  In October of the same
 16 | year, the PythonLabs team moved to Digital Creations, which became
 17 | Zope Corporation.  In 2001, the Python Software Foundation (PSF, see
 18 | https://www.python.org/psf/) was formed, a non-profit organization
 19 | created specifically to own Python-related Intellectual Property.
 20 | Zope Corporation was a sponsoring member of the PSF.
 21 | 
 22 | All Python releases are Open Source (see http://www.opensource.org for
 23 | the Open Source Definition).  Historically, most, but not all, Python
 24 | releases have also been GPL-compatible; the table below summarizes
 25 | the various releases.
 26 | 
 27 |     Release         Derived     Year        Owner       GPL-
 28 |                     from                                compatible? (1)
 29 | 
 30 |     0.9.0 thru 1.2              1991-1995   CWI         yes
 31 |     1.3 thru 1.5.2  1.2         1995-1999   CNRI        yes
 32 |     1.6             1.5.2       2000        CNRI        no
 33 |     2.0             1.6         2000        BeOpen.com  no
 34 |     1.6.1           1.6         2001        CNRI        yes (2)
 35 |     2.1             2.0+1.6.1   2001        PSF         no
 36 |     2.0.1           2.0+1.6.1   2001        PSF         yes
 37 |     2.1.1           2.1+2.0.1   2001        PSF         yes
 38 |     2.1.2           2.1.1       2002        PSF         yes
 39 |     2.1.3           2.1.2       2002        PSF         yes
 40 |     2.2 and above   2.1.1       2001-now    PSF         yes
 41 | 
 42 | Footnotes:
 43 | 
 44 | (1) GPL-compatible doesn't mean that we're distributing Python under
 45 |     the GPL.  All Python licenses, unlike the GPL, let you distribute
 46 |     a modified version without making your changes open source.  The
 47 |     GPL-compatible licenses make it possible to combine Python with
 48 |     other software that is released under the GPL; the others don't.
 49 | 
 50 | (2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
 51 |     because its license has a choice of law clause.  According to
 52 |     CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
 53 |     is "not incompatible" with the GPL.
 54 | 
 55 | Thanks to the many outside volunteers who have worked under Guido's
 56 | direction to make these releases possible.
 57 | 
 58 | 
 59 | B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
 60 | ===============================================================
 61 | 
 62 | PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
 63 | --------------------------------------------
 64 | 
 65 | 1. This LICENSE AGREEMENT is between the Python Software Foundation
 66 | ("PSF"), and the Individual or Organization ("Licensee") accessing and
 67 | otherwise using this software ("Python") in source or binary form and
 68 | its associated documentation.
 69 | 
 70 | 2. Subject to the terms and conditions of this License Agreement, PSF hereby
 71 | grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
 72 | analyze, test, perform and/or display publicly, prepare derivative works,
 73 | distribute, and otherwise use Python alone or in any derivative version,
 74 | provided, however, that PSF's License Agreement and PSF's notice of copyright,
 75 | i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 76 | 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 Python Software Foundation; All
 77 | Rights Reserved" are retained in Python alone or in any derivative version
 78 | prepared by Licensee.
 79 | 
 80 | 3. In the event Licensee prepares a derivative work that is based on
 81 | or incorporates Python or any part thereof, and wants to make
 82 | the derivative work available to others as provided herein, then
 83 | Licensee hereby agrees to include in any such work a brief summary of
 84 | the changes made to Python.
 85 | 
 86 | 4. PSF is making Python available to Licensee on an "AS IS"
 87 | basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
 88 | IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
 89 | DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
 90 | FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
 91 | INFRINGE ANY THIRD PARTY RIGHTS.
 92 | 
 93 | 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
 94 | FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
 95 | A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
 96 | OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
 97 | 
 98 | 6. This License Agreement will automatically terminate upon a material
 99 | breach of its terms and conditions.
100 | 
101 | 7. Nothing in this License Agreement shall be deemed to create any
102 | relationship of agency, partnership, or joint venture between PSF and
103 | Licensee.  This License Agreement does not grant permission to use PSF
104 | trademarks or trade name in a trademark sense to endorse or promote
105 | products or services of Licensee, or any third party.
106 | 
107 | 8. By copying, installing or otherwise using Python, Licensee
108 | agrees to be bound by the terms and conditions of this License
109 | Agreement.
110 | 
111 | 
112 | BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
113 | -------------------------------------------
114 | 
115 | BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
116 | 
117 | 1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
118 | office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
119 | Individual or Organization ("Licensee") accessing and otherwise using
120 | this software in source or binary form and its associated
121 | documentation ("the Software").
122 | 
123 | 2. Subject to the terms and conditions of this BeOpen Python License
124 | Agreement, BeOpen hereby grants Licensee a non-exclusive,
125 | royalty-free, world-wide license to reproduce, analyze, test, perform
126 | and/or display publicly, prepare derivative works, distribute, and
127 | otherwise use the Software alone or in any derivative version,
128 | provided, however, that the BeOpen Python License is retained in the
129 | Software, alone or in any derivative version prepared by Licensee.
130 | 
131 | 3. BeOpen is making the Software available to Licensee on an "AS IS"
132 | basis.  BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
133 | IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
134 | DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
135 | FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
136 | INFRINGE ANY THIRD PARTY RIGHTS.
137 | 
138 | 4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
139 | SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
140 | AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
141 | DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
142 | 
143 | 5. This License Agreement will automatically terminate upon a material
144 | breach of its terms and conditions.
145 | 
146 | 6. This License Agreement shall be governed by and interpreted in all
147 | respects by the law of the State of California, excluding conflict of
148 | law provisions.  Nothing in this License Agreement shall be deemed to
149 | create any relationship of agency, partnership, or joint venture
150 | between BeOpen and Licensee.  This License Agreement does not grant
151 | permission to use BeOpen trademarks or trade names in a trademark
152 | sense to endorse or promote products or services of Licensee, or any
153 | third party.  As an exception, the "BeOpen Python" logos available at
154 | http://www.pythonlabs.com/logos.html may be used according to the
155 | permissions granted on that web page.
156 | 
157 | 7. By copying, installing or otherwise using the software, Licensee
158 | agrees to be bound by the terms and conditions of this License
159 | Agreement.
160 | 
161 | 
162 | CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
163 | ---------------------------------------
164 | 
165 | 1. This LICENSE AGREEMENT is between the Corporation for National
166 | Research Initiatives, having an office at 1895 Preston White Drive,
167 | Reston, VA 20191 ("CNRI"), and the Individual or Organization
168 | ("Licensee") accessing and otherwise using Python 1.6.1 software in
169 | source or binary form and its associated documentation.
170 | 
171 | 2. Subject to the terms and conditions of this License Agreement, CNRI
172 | hereby grants Licensee a nonexclusive, royalty-free, world-wide
173 | license to reproduce, analyze, test, perform and/or display publicly,
174 | prepare derivative works, distribute, and otherwise use Python 1.6.1
175 | alone or in any derivative version, provided, however, that CNRI's
176 | License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
177 | 1995-2001 Corporation for National Research Initiatives; All Rights
178 | Reserved" are retained in Python 1.6.1 alone or in any derivative
179 | version prepared by Licensee.  Alternately, in lieu of CNRI's License
180 | Agreement, Licensee may substitute the following text (omitting the
181 | quotes): "Python 1.6.1 is made available subject to the terms and
182 | conditions in CNRI's License Agreement.  This Agreement together with
183 | Python 1.6.1 may be located on the Internet using the following
184 | unique, persistent identifier (known as a handle): 1895.22/1013.  This
185 | Agreement may also be obtained from a proxy server on the Internet
186 | using the following URL: http://hdl.handle.net/1895.22/1013".
187 | 
188 | 3. In the event Licensee prepares a derivative work that is based on
189 | or incorporates Python 1.6.1 or any part thereof, and wants to make
190 | the derivative work available to others as provided herein, then
191 | Licensee hereby agrees to include in any such work a brief summary of
192 | the changes made to Python 1.6.1.
193 | 
194 | 4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
195 | basis.  CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
196 | IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
197 | DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
198 | FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
199 | INFRINGE ANY THIRD PARTY RIGHTS.
200 | 
201 | 5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
202 | 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
203 | A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
204 | OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
205 | 
206 | 6. This License Agreement will automatically terminate upon a material
207 | breach of its terms and conditions.
208 | 
209 | 7. This License Agreement shall be governed by the federal
210 | intellectual property law of the United States, including without
211 | limitation the federal copyright law, and, to the extent such
212 | U.S. federal law does not apply, by the law of the Commonwealth of
213 | Virginia, excluding Virginia's conflict of law provisions.
214 | Notwithstanding the foregoing, with regard to derivative works based
215 | on Python 1.6.1 that incorporate non-separable material that was
216 | previously distributed under the GNU General Public License (GPL), the
217 | law of the Commonwealth of Virginia shall govern this License
218 | Agreement only as to issues arising under or with respect to
219 | Paragraphs 4, 5, and 7 of this License Agreement.  Nothing in this
220 | License Agreement shall be deemed to create any relationship of
221 | agency, partnership, or joint venture between CNRI and Licensee.  This
222 | License Agreement does not grant permission to use CNRI trademarks or
223 | trade name in a trademark sense to endorse or promote products or
224 | services of Licensee, or any third party.
225 | 
226 | 8. By clicking on the "ACCEPT" button where indicated, or by copying,
227 | installing or otherwise using Python 1.6.1, Licensee agrees to be
228 | bound by the terms and conditions of this License Agreement.
229 | 
230 |         ACCEPT
231 | 
232 | 
233 | CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
234 | --------------------------------------------------
235 | 
236 | Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
237 | The Netherlands.  All rights reserved.
238 | 
239 | Permission to use, copy, modify, and distribute this software and its
240 | documentation for any purpose and without fee is hereby granted,
241 | provided that the above copyright notice appear in all copies and that
242 | both that copyright notice and this permission notice appear in
243 | supporting documentation, and that the name of Stichting Mathematisch
244 | Centrum or CWI not be used in advertising or publicity pertaining to
245 | distribution of the software without specific, written prior
246 | permission.
247 | 
248 | STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
249 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
250 | FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
251 | FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
252 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
253 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
254 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
255 | 


--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.md
2 | include LICENSE
3 | 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
  1 | # Icdiff
  2 | 
  3 | Improved colored diff
  4 | 
  5 | ![screenshot](https://www.jefftk.com/icdiff-css-demo.png)
  6 | 
  7 | ## Installation
  8 | 
  9 | Download the [latest](https://github.com/jeffkaufman/icdiff/tags) `icdiff` and put it on your PATH.
 10 | 
 11 | Alternatively, install with packaging tools:
 12 | 
 13 | ```
 14 | # pip
 15 | pip install icdiff
 16 | 
 17 | # apt
 18 | sudo apt install icdiff
 19 | 
 20 | # homebrew
 21 | brew install icdiff
 22 | 
 23 | # aur
 24 | yay -S icdiff
 25 | 
 26 | # nix
 27 | nix-env -i icdiff
 28 | ```
 29 | 
 30 | ## Usage
 31 | 
 32 | ```sh
 33 | icdiff [options] left_file right_file
 34 | ```
 35 | 
 36 | Show differences between files in a two column view.
 37 | 
 38 | ### Options
 39 | 
 40 | ```
 41 |   --version             show program's version number and exit
 42 |   -h, --help            show this help message and exit
 43 |   --cols=COLS           specify the width of the screen. Autodetection is Unix
 44 |                         only
 45 |   --encoding=ENCODING   specify the file encoding; defaults to utf8
 46 |   -E MATCHER, --exclude-lines=MATCHER
 47 |                         Do not diff lines that match this regex. Not
 48 |                         compatible with the 'line-numbers' option
 49 |   --head=HEAD           consider only the first N lines of each file
 50 |   -H, --highlight       color by changing the background color instead of the
 51 |                         foreground color.  Very fast, ugly, displays all
 52 |                         changes
 53 |   -L LABELS, --label=LABELS
 54 |                         override file labels with arbitrary tags. Use twice,
 55 |                         one for each file
 56 |   -N, --line-numbers    generate output with line numbers. Not compatible with
 57 |                         the 'exclude-lines' option.
 58 |   --no-bold             use non-bold colors; recommended for solarized
 59 |   --no-headers          don't label the left and right sides with their file
 60 |                         names
 61 |   --output-encoding=OUTPUT_ENCODING
 62 |                         specify the output encoding; defaults to utf8
 63 |   -r, --recursive       recursively compare subdirectories
 64 |   -s, --report-identical-files
 65 |                         report when two files are the same
 66 |   --show-all-spaces     color all non-matching whitespace including that which
 67 |                         is not needed for drawing the eye to changes.  Slow,
 68 |                         ugly, displays all changes
 69 |   --tabsize=TABSIZE     tab stop spacing
 70 |   -t, --truncate        truncate long lines instead of wrapping them
 71 |   -u, --patch           generate patch. This is always true, and only exists
 72 |                         for compatibility
 73 |   -U NUM, --unified=NUM, --numlines=NUM
 74 |                         how many lines of context to print; can't be combined
 75 |                         with --whole-file
 76 |   -W, --whole-file      show the whole file instead of just changed lines and
 77 |                         context
 78 |   --strip-trailing-cr   strip any trailing carriage return at the end of an
 79 |                         input line
 80 |   --color-map=COLOR_MAP
 81 |                         choose which colors are used for which items. Default
 82 |                         is --color-map='add:green_bold,change:yellow_bold,desc
 83 |                         ription:blue,meta:magenta,separator:blue,subtract:red_
 84 |                         bold'.  You don't have to override all of them:
 85 |                         '--color-map=separator:white,description:cyan
 86 | ```
 87 | 
 88 | ## Using with Git
 89 | 
 90 | To see what it looks like, try:
 91 | 
 92 | ```sh
 93 | git difftool --extcmd icdiff
 94 | ```
 95 | 
 96 | To install this as a tool you can use with Git, copy
 97 | `git-icdiff` into your PATH and run:
 98 | 
 99 | ```sh
100 | git icdiff
101 | ```
102 | 
103 | You can configure `git-icdiff` in Git's config:
104 | 
105 | ```
106 | git config --global icdiff.options '--highlight --line-numbers'
107 | ```
108 | 
109 | ## Using with subversion
110 | 
111 | To try it out, run:
112 | 
113 | ```sh
114 | svn diff --diff-cmd icdiff
115 | ```
116 | 
117 | ## Using with Mercurial
118 | 
119 | Add the following to your `~/.hgrc`:
120 | 
121 | ```sh
122 | [extensions]
123 | extdiff=
124 | 
125 | [extdiff]
126 | cmd.icdiff=icdiff
127 | opts.icdiff=--recursive --line-numbers
128 | ```
129 | 
130 | Or check more [in-depth setup instructions](https://ianobermiller.com/blog/2016/07/14/side-by-side-diffs-for-mercurial-hg-icdiff-revisited/).
131 | 
132 | ## Setting up a dev environment
133 | 
134 | Create a virtualenv and install the dev dependencies.
135 | This is not needed for normal usage.
136 | 
137 | ```sh
138 | virtualenv venv
139 | source venv/bin/activate
140 | pip install -r requirements-dev.txt
141 | ```
142 | 
143 | ## Running tests
144 | 
145 | ```sh
146 | ./test.sh python3
147 | ```
148 | 
149 | ## Making a release
150 | 
151 | - Update ChangeLog with all the changes since the last release
152 | - Update `__version__` in `icdiff`
153 | - Run tests, make sure they pass
154 | - `git commit -a -m "release ${version}"`
155 | - `git push`
156 | - `git tag release-${version}`
157 | - `git push origin release-${version}`
158 | - A GitHub Action should be triggered due to the release tag being pushed, and will upload to PyPI.
159 | 
160 | ## License
161 | 
162 | This file is derived from `difflib.HtmlDiff` which is under [license](https://www.python.org/download/releases/2.6.2/license/).
163 | I release my changes here under the same license. This is GPL compatible.
164 | 


--------------------------------------------------------------------------------
/git-icdiff:
--------------------------------------------------------------------------------
 1 | #!/bin/sh
 2 | ICDIFF_OPTIONS=$(git config --get icdiff.options)
 3 | ICDIFF_OPTIONS="${ICDIFF_OPTIONS} --is-git-diff"
 4 | GITPAGER=$(git config --get icdiff.pager)
 5 | 
 6 | if [ -z "$GITPAGER" ]; then
 7 |   GITPAGER=$(git config --get core.pager)
 8 | fi
 9 | 
10 | if [ -z "$GITPAGER" ]; then
11 |   GITPAGER="${PAGER:-less}"
12 | fi
13 | 
14 | if [ "${GITPAGER%% *}" = "more" ] || [ "${GITPAGER%% *}" = "less" ]; then
15 |   GITPAGER="$GITPAGER -R"
16 | fi
17 | 
18 | git difftool --no-prompt --extcmd="icdiff $ICDIFF_OPTIONS" "$@" | $GITPAGER
19 | 


--------------------------------------------------------------------------------
/icdiff:
--------------------------------------------------------------------------------
   1 | #!/usr/bin/env python3
   2 | 
   3 | """ icdiff.py
   4 | 
   5 | Author: Jeff Kaufman, derived from difflib.HtmlDiff
   6 | 
   7 | License: This code is usable under the same open terms as the rest of
   8 |          python.  See: http://www.python.org/psf/license/
   9 | 
  10 | Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Python Software Foundation;
  11 | All Rights Reserved
  12 | 
  13 | Based on Python's difflib.HtmlDiff,
  14 | with changes to provide console output instead of html output.  """
  15 | 
  16 | import os
  17 | import stat
  18 | import sys
  19 | import errno
  20 | import difflib
  21 | from optparse import Option, OptionParser
  22 | import re
  23 | import filecmp
  24 | import unicodedata
  25 | import codecs
  26 | import fnmatch
  27 | 
  28 | __version__ = "2.0.7"
  29 | 
  30 | # Exit code constants
  31 | EXIT_CODE_SUCCESS = 0
  32 | EXIT_CODE_DIFF = 1
  33 | EXIT_CODE_ERROR = 2
  34 | 
  35 | color_codes = {
  36 |     "black": "\033[0;30m",
  37 |     "red": "\033[0;31m",
  38 |     "green": "\033[0;32m",
  39 |     "yellow": "\033[0;33m",
  40 |     "blue": "\033[0;34m",
  41 |     "magenta": "\033[0;35m",
  42 |     "cyan": "\033[0;36m",
  43 |     "white": "\033[0;37m",
  44 |     "none": "\033[m",
  45 |     "black_bold": "\033[1;30m",
  46 |     "red_bold": "\033[1;31m",
  47 |     "green_bold": "\033[1;32m",
  48 |     "yellow_bold": "\033[1;33m",
  49 |     "blue_bold": "\033[1;34m",
  50 |     "magenta_bold": "\033[1;35m",
  51 |     "cyan_bold": "\033[1;36m",
  52 |     "white_bold": "\033[1;37m",
  53 | }
  54 | 
  55 | 
  56 | color_mapping = {
  57 |     "add": "green_bold",
  58 |     "subtract": "red_bold",
  59 |     "change": "yellow_bold",
  60 |     "separator": "blue",
  61 |     "description": "blue",
  62 |     "permissions": "yellow",
  63 |     "meta": "magenta",
  64 |     "line-numbers": "white",
  65 | }
  66 | 
  67 | 
  68 | class ConsoleDiff(object):
  69 |     """Console colored side by side comparison with change highlights.
  70 | 
  71 |     Based on difflib.HtmlDiff
  72 | 
  73 |     This class can be used to create a text-mode table showing a side
  74 | 
  75 |     by side, line by line comparison of text with inter-line and
  76 |     intra-line change highlights in ansi color escape sequences as
  77 |     intra-line change highlights in ansi color escape sequences as
  78 |     read by xterm.  The table can be generated in either full or
  79 |     contextual difference mode.
  80 | 
  81 |     To generate the table, call make_table.
  82 | 
  83 |     Usage is the almost the same as HtmlDiff except only make_table is
  84 |     implemented and the file can be invoked on the command line.
  85 |     Run::
  86 | 
  87 |       python icdiff.py --help
  88 | 
  89 |     for command line usage information.
  90 | 
  91 |     """
  92 | 
  93 |     def __init__(
  94 |         self,
  95 |         tabsize=8,
  96 |         wrapcolumn=None,
  97 |         linejunk=None,
  98 |         charjunk=difflib.IS_CHARACTER_JUNK,
  99 |         cols=80,
 100 |         line_numbers=False,
 101 |         show_all_spaces=False,
 102 |         show_no_spaces=False,
 103 |         highlight=False,
 104 |         truncate=False,
 105 |         strip_trailing_cr=False,
 106 |     ):
 107 |         """ConsoleDiff instance initializer
 108 | 
 109 |         Arguments:
 110 |         tabsize -- tab stop spacing, defaults to 8.
 111 |         wrapcolumn -- column number where lines are broken and wrapped,
 112 |             defaults to None where lines are not wrapped.
 113 |         linejunk, charjunk -- keyword arguments passed into ndiff() (used by
 114 |             ConsoleDiff() to generate the side by side differences).  See
 115 |             ndiff() documentation for argument default values and descriptions.
 116 |         """
 117 | 
 118 |         self._tabsize = tabsize
 119 |         self.line_numbers = line_numbers
 120 |         self.cols = cols
 121 |         self.show_all_spaces = show_all_spaces
 122 |         self.show_no_spaces = show_no_spaces
 123 |         self.highlight = highlight
 124 |         self.strip_trailing_cr = strip_trailing_cr
 125 |         self.truncate = truncate
 126 | 
 127 |         if wrapcolumn is None:
 128 |             if not line_numbers:
 129 |                 wrapcolumn = self.cols // 2 - 2
 130 |             else:
 131 |                 wrapcolumn = self.cols // 2 - 10
 132 | 
 133 |         self._wrapcolumn = wrapcolumn
 134 |         self._linejunk = linejunk
 135 |         self._charjunk = charjunk
 136 | 
 137 |     def _tab_newline_replace(self, fromlines, tolines):
 138 |         """Returns from/to line lists with tabs expanded and newlines removed.
 139 | 
 140 |         Instead of tab characters being replaced by the number of spaces
 141 |         needed to fill in to the next tab stop, this function will fill
 142 |         the space with tab characters.  This is done so that the difference
 143 |         algorithms can identify changes in a file when tabs are replaced by
 144 |         spaces and vice versa.  At the end of the table generation, the tab
 145 |         characters will be replaced with a space.
 146 |         """
 147 | 
 148 |         def expand_tabs(line):
 149 |             # hide real spaces
 150 |             line = line.replace(" ", "\0")
 151 |             # expand tabs into spaces
 152 |             line = line.expandtabs(self._tabsize)
 153 |             # replace spaces from expanded tabs back into tab characters
 154 |             # (we'll replace them with markup after we do differencing)
 155 |             line = line.replace(" ", "\t")
 156 |             return line.replace("\0", " ").rstrip("\n")
 157 | 
 158 |         fromlines = [expand_tabs(line) for line in fromlines]
 159 |         tolines = [expand_tabs(line) for line in tolines]
 160 |         return fromlines, tolines
 161 | 
 162 |     def _strip_trailing_cr(self, lines):
 163 |         """Remove windows return carriage"""
 164 |         lines = [line.rstrip("\r") for line in lines]
 165 |         return lines
 166 | 
 167 |     def _all_cr_nl(self, lines):
 168 |         """Whether a file is entirely \r\n line endings"""
 169 |         return all(line.endswith("\r") for line in lines)
 170 | 
 171 |     def _display_len(self, s):
 172 |         # Handle wide characters like Chinese.
 173 |         def width(c):
 174 |             if isinstance(c, type("")) and unicodedata.east_asian_width(c) in [
 175 |                 "F",
 176 |                 "W",
 177 |             ]:
 178 |                 return 2
 179 |             elif c == "\r":
 180 |                 return 2
 181 |             return 1
 182 | 
 183 |         return sum(width(c) for c in s)
 184 | 
 185 |     def _split_line(self, data_list, line_num, text):
 186 |         """Builds list of text lines by splitting text lines at wrap point
 187 | 
 188 |         This function will determine if the input text line needs to be
 189 |         wrapped (split) into separate lines.  If so, the first wrap point
 190 |         will be determined and the first line appended to the output
 191 |         text line list.  This function is used recursively to handle
 192 |         the second part of the split line to further split it.
 193 |         """
 194 | 
 195 |         while True:
 196 |             # if blank line or context separator, just add it to the output
 197 |             # list
 198 |             if not line_num:
 199 |                 data_list.append((line_num, text))
 200 |                 return
 201 | 
 202 |             # if line text doesn't need wrapping, just add it to the output
 203 |             # list
 204 |             if (
 205 |                 self._display_len(text) - (text.count("\0") * 3)
 206 |                 <= self._wrapcolumn
 207 |             ):
 208 |                 data_list.append((line_num, text))
 209 |                 return
 210 | 
 211 |             # scan text looking for the wrap point, keeping track if the wrap
 212 |             # point is inside markers
 213 |             i = 0
 214 |             n = 0
 215 |             mark = ""
 216 |             while n < self._wrapcolumn and i < len(text):
 217 |                 if text[i] == "\0":
 218 |                     i += 1
 219 |                     mark = text[i]
 220 |                     i += 1
 221 |                 elif text[i] == "\1":
 222 |                     i += 1
 223 |                     mark = ""
 224 |                 else:
 225 |                     n += self._display_len(text[i])
 226 |                     i += 1
 227 | 
 228 |             # wrap point is inside text, break it up into separate lines
 229 |             line1 = text[:i]
 230 |             line2 = text[i:]
 231 | 
 232 |             # if wrap point is inside markers, place end marker at end of first
 233 |             # line and start marker at beginning of second line because each
 234 |             # line will have its own table tag markup around it.
 235 |             if mark:
 236 |                 line1 = line1 + "\1"
 237 |                 line2 = "\0" + mark + line2
 238 | 
 239 |             # tack on first line onto the output list
 240 |             data_list.append((line_num, line1))
 241 | 
 242 |             # use this routine again to wrap the remaining text
 243 |             # unless truncate is set
 244 |             if self.truncate:
 245 |                 return
 246 |             line_num = ">"
 247 |             text = line2
 248 | 
 249 |     def _line_wrapper(self, diffs):
 250 |         """Returns iterator that splits (wraps) mdiff text lines"""
 251 | 
 252 |         # pull from/to data and flags from mdiff iterator
 253 |         for fromdata, todata, flag in diffs:
 254 |             # check for context separators and pass them through
 255 |             if flag is None:
 256 |                 yield fromdata, todata, flag
 257 |                 continue
 258 |             (fromline, fromtext), (toline, totext) = fromdata, todata
 259 |             # for each from/to line split it at the wrap column to form
 260 |             # list of text lines.
 261 |             fromlist, tolist = [], []
 262 |             self._split_line(fromlist, fromline, fromtext)
 263 |             self._split_line(tolist, toline, totext)
 264 |             # yield from/to line in pairs inserting blank lines as
 265 |             # necessary when one side has more wrapped lines
 266 |             while fromlist or tolist:
 267 |                 if fromlist:
 268 |                     fromdata = fromlist.pop(0)
 269 |                 else:
 270 |                     fromdata = ("", " ")
 271 |                 if tolist:
 272 |                     todata = tolist.pop(0)
 273 |                 else:
 274 |                     todata = ("", " ")
 275 |                 yield fromdata, todata, flag
 276 | 
 277 |     def _collect_lines(self, diffs):
 278 |         """Collects mdiff output into separate lists
 279 | 
 280 |         Before storing the mdiff from/to data into a list, it is converted
 281 |         into a single line of text with console markup.
 282 |         """
 283 | 
 284 |         # pull from/to data and flags from mdiff style iterator
 285 |         for fromdata, todata, flag in diffs:
 286 |             if (fromdata, todata, flag) == (None, None, None):
 287 |                 yield None
 288 |             else:
 289 |                 yield (
 290 |                     self._format_line(*fromdata),
 291 |                     self._format_line(*todata),
 292 |                 )
 293 | 
 294 |     def _format_line(self, linenum, text):
 295 |         text = text.rstrip()
 296 |         if not self.line_numbers:
 297 |             return text
 298 |         return self._add_line_numbers(linenum, text)
 299 | 
 300 |     def _add_line_numbers(self, linenum, text):
 301 |         try:
 302 |             lid = "%d" % linenum
 303 |         except TypeError:
 304 |             # handle blank lines where linenum is '>' or ''
 305 |             lid = ""
 306 |             return text
 307 |         return "%s %s" % (
 308 |             self._rpad(simple_colorize(str(lid), "line-numbers"), 8),
 309 |             text,
 310 |         )
 311 | 
 312 |     def _real_len(self, s):
 313 |         s_len = 0
 314 |         in_esc = False
 315 |         prev = " "
 316 |         for c in replace_all(
 317 |             {"\0+": "", "\0-": "", "\0^": "", "\1": "", "\t": " "}, s
 318 |         ):
 319 |             if in_esc:
 320 |                 if c == "m":
 321 |                     in_esc = False
 322 |             else:
 323 |                 if c == "[" and prev == "\033":
 324 |                     in_esc = True
 325 |                     s_len -= 1  # we counted prev when we shouldn't have
 326 |                 else:
 327 |                     s_len += self._display_len(c)
 328 |             prev = c
 329 | 
 330 |         return s_len
 331 | 
 332 |     def _rpad(self, s, field_width):
 333 |         return self._pad(s, field_width) + s
 334 | 
 335 |     def _pad(self, s, field_width):
 336 |         return " " * (field_width - self._real_len(s))
 337 | 
 338 |     def _lpad(self, s, field_width):
 339 |         return s + self._pad(s, field_width)
 340 | 
 341 |     def make_table(
 342 |         self,
 343 |         fromlines,
 344 |         tolines,
 345 |         fromdesc="",
 346 |         todesc="",
 347 |         fromperms=None,
 348 |         toperms=None,
 349 |         context=False,
 350 |         numlines=5,
 351 |     ):
 352 |         """Generates table of side by side comparison with change highlights
 353 | 
 354 |         Arguments:
 355 |         fromlines -- list of "from" lines
 356 |         tolines -- list of "to" lines
 357 |         fromdesc -- "from" file column header string
 358 |         todesc -- "to" file column header string
 359 |         fromperms -- "from" file permissions
 360 |         toperms -- "to" file permissions
 361 |         context -- set to True for contextual differences (defaults to False
 362 |             which shows full differences).
 363 |         numlines -- number of context lines.  When context is set True,
 364 |             controls number of lines displayed before and after the change.
 365 |             When context is False, controls the number of lines to place
 366 |             the "next" link anchors before the next change (so click of
 367 |             "next" link jumps to just before the change).
 368 |         """
 369 |         if context:
 370 |             context_lines = numlines
 371 |         else:
 372 |             context_lines = None
 373 | 
 374 |         # change tabs to spaces before it gets more difficult after we insert
 375 |         # markup
 376 |         fromlines, tolines = self._tab_newline_replace(fromlines, tolines)
 377 | 
 378 |         if self.strip_trailing_cr or (
 379 |             self._all_cr_nl(fromlines) and self._all_cr_nl(tolines)
 380 |         ):
 381 |             fromlines = self._strip_trailing_cr(fromlines)
 382 |             tolines = self._strip_trailing_cr(tolines)
 383 | 
 384 |         # create diffs iterator which generates side by side from/to data
 385 |         diffs = difflib._mdiff(
 386 |             fromlines,
 387 |             tolines,
 388 |             context_lines,
 389 |             linejunk=self._linejunk,
 390 |             charjunk=self._charjunk,
 391 |         )
 392 | 
 393 |         # set up iterator to wrap lines that exceed desired width
 394 |         if self._wrapcolumn:
 395 |             diffs = self._line_wrapper(diffs)
 396 |         diffs = self._collect_lines(diffs)
 397 | 
 398 |         for left, right in self._generate_table(
 399 |             fromdesc, todesc, fromperms, toperms, diffs
 400 |         ):
 401 |             yield self.colorize(
 402 |                 "%s %s"
 403 |                 % (
 404 |                     self._lpad(left, self.cols // 2 - 1),
 405 |                     self._lpad(right, self.cols // 2 - 1),
 406 |                 )
 407 |             )
 408 | 
 409 |     def _generate_table(self, fromdesc, todesc, fromperms, toperms, diffs):
 410 |         if fromdesc or todesc:
 411 |             yield (
 412 |                 simple_colorize(fromdesc, "description"),
 413 |                 simple_colorize(todesc, "description"),
 414 |             )
 415 | 
 416 |         if fromperms != toperms:
 417 |             yield (
 418 |                 simple_colorize(
 419 |                     f"{stat.filemode(fromperms)} ({fromperms:o})",
 420 |                     "permissions",
 421 |                 ),
 422 |                 simple_colorize(
 423 |                     f"{stat.filemode(toperms)} ({toperms:o})", "permissions"
 424 |                 ),
 425 |             )
 426 | 
 427 |         for i, line in enumerate(diffs):
 428 |             if line is None:
 429 |                 # mdiff yields None on separator lines; skip the bogus ones
 430 |                 # generated for the first line
 431 |                 if i > 0:
 432 |                     yield (
 433 |                         simple_colorize("---", "separator"),
 434 |                         simple_colorize("---", "separator"),
 435 |                     )
 436 |             else:
 437 |                 yield line
 438 | 
 439 |     def colorize(self, s):
 440 |         def background(color):
 441 |             return replace_all(
 442 |                 {"\033[1;": "\033[7;1;", "\033[0;": "\033[7;"}, color
 443 |             )
 444 | 
 445 |         C_ADD = color_codes[color_mapping["add"]]
 446 |         C_SUB = color_codes[color_mapping["subtract"]]
 447 |         C_CHG = color_codes[color_mapping["change"]]
 448 | 
 449 |         if self.highlight:
 450 |             C_ADD, C_SUB, C_CHG = (
 451 |                 background(C_ADD),
 452 |                 background(C_SUB),
 453 |                 background(C_CHG),
 454 |             )
 455 | 
 456 |         C_NONE = color_codes["none"]
 457 |         colors = (C_ADD, C_SUB, C_CHG, C_NONE)
 458 | 
 459 |         s = replace_all(
 460 |             {
 461 |                 "\0+": C_ADD,
 462 |                 "\0-": C_SUB,
 463 |                 "\0^": C_CHG,
 464 |                 "\1": C_NONE,
 465 |                 "\t": " ",
 466 |                 "\r": "\\r",
 467 |             },
 468 |             s,
 469 |         )
 470 | 
 471 |         if self.highlight:
 472 |             return s
 473 | 
 474 |         if self.show_no_spaces:
 475 |             # Don't show whitespace even if it's a whitespace-only line.
 476 |             return re.sub(
 477 |                 "\033\\[[01];3([01234567])m(\\s+)(\033\\[)",
 478 |                 "\033[0;3\\1m\\2\\3",
 479 |                 s,
 480 |             )
 481 | 
 482 |         elif not self.show_all_spaces:
 483 |             # If there's a change consisting entirely of whitespace,
 484 |             # don't color it.
 485 |             return re.sub(
 486 |                 "\033\\[[01];3([01234567])m(\\s+)(\033\\[)",
 487 |                 "\033[7;3\\1m\\2\\3",
 488 |                 s,
 489 |             )
 490 | 
 491 |         def will_see_coloredspace(i, s):
 492 |             while i < len(s) and s[i].isspace():
 493 |                 i += 1
 494 |             if i < len(s) and s[i] == "\033":
 495 |                 return False
 496 |             return True
 497 | 
 498 |         n_s = []
 499 |         in_color = False
 500 |         seen_coloredspace = False
 501 |         for i, c in enumerate(s):
 502 |             if len(n_s) > 6 and n_s[-1] == "m":
 503 |                 ns_end = "".join(n_s[-7:])
 504 |                 for color in colors:
 505 |                     if ns_end.endswith(color):
 506 |                         if color != in_color:
 507 |                             seen_coloredspace = False
 508 |                         in_color = color
 509 |                 if ns_end.endswith(C_NONE):
 510 |                     in_color = False
 511 | 
 512 |             if (
 513 |                 c.isspace()
 514 |                 and in_color
 515 |                 and (
 516 |                     self.show_all_spaces
 517 |                     or not (seen_coloredspace or will_see_coloredspace(i, s))
 518 |                 )
 519 |             ):
 520 |                 n_s.extend([C_NONE, background(in_color), c, C_NONE, in_color])
 521 |             else:
 522 |                 if in_color:
 523 |                     seen_coloredspace = True
 524 |                 n_s.append(c)
 525 | 
 526 |         joined = "".join(n_s)
 527 | 
 528 |         return joined
 529 | 
 530 | 
 531 | def raw_colorize(s, color):
 532 |     return "%s%s%s" % (color_codes[color], s, color_codes["none"])
 533 | 
 534 | 
 535 | def simple_colorize(s, category):
 536 |     return raw_colorize(s, color_mapping[category])
 537 | 
 538 | 
 539 | def replace_all(replacements, string):
 540 |     for search, replace in replacements.items():
 541 |         string = string.replace(search, replace)
 542 |     return string
 543 | 
 544 | 
 545 | class MultipleOption(Option):
 546 |     ACTIONS = Option.ACTIONS + ("extend",)
 547 |     STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
 548 |     TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
 549 |     ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",)
 550 | 
 551 |     def take_action(self, action, dest, opt, value, values, parser):
 552 |         if action == "extend":
 553 |             values.ensure_value(dest, []).append(value)
 554 |         else:
 555 |             Option.take_action(self, action, dest, opt, value, values, parser)
 556 | 
 557 | 
 558 | def create_option_parser():
 559 |     # If you change any of these, also update README.
 560 |     parser = OptionParser(
 561 |         usage="usage: %prog [options] left_file right_file",
 562 |         version="icdiff version %s" % __version__,
 563 |         description="Show differences between files in a " "two column view.",
 564 |         option_class=MultipleOption,
 565 |     )
 566 |     parser.add_option(
 567 |         "--cols",
 568 |         default=None,
 569 |         help="specify the width of the screen. Autodetection is " "Unix only",
 570 |     )
 571 |     parser.add_option(
 572 |         "--encoding",
 573 |         default="utf-8",
 574 |         help="specify the file encoding; defaults to utf8",
 575 |     )
 576 |     parser.add_option(
 577 |         "-E",
 578 |         "--exclude-lines",
 579 |         action="store",
 580 |         type="string",
 581 |         dest="matcher",
 582 |         help="Do not diff lines that match this regex. Not "
 583 |         "compatible with the 'line-numbers' option",
 584 |     )
 585 |     parser.add_option(
 586 |         "--head",
 587 |         default=0,
 588 |         help="consider only the first N lines of each file",
 589 |     )
 590 |     parser.add_option(
 591 |         "-H",
 592 |         "--highlight",
 593 |         default=False,
 594 |         action="store_true",
 595 |         help="color by changing the background color instead of "
 596 |         "the foreground color.  Very fast, ugly, displays all "
 597 |         "changes",
 598 |     )
 599 |     parser.add_option(
 600 |         "-L",
 601 |         "--label",
 602 |         action="extend",
 603 |         type="string",
 604 |         dest="labels",
 605 |         help="override file labels with arbitrary tags. "
 606 |         "Use twice, one for each file. You may include the "
 607 |         "formatting strings '{path}' and '{basename}'",
 608 |     )
 609 |     parser.add_option(
 610 |         "-N",
 611 |         "--line-numbers",
 612 |         default=False,
 613 |         action="store_true",
 614 |         help="generate output with line numbers. Not compatible "
 615 |         "with the 'exclude-lines' option.",
 616 |     )
 617 |     parser.add_option(
 618 |         "--no-bold",
 619 |         default=False,
 620 |         action="store_true",
 621 |         help="use non-bold colors; recommended for solarized",
 622 |     )
 623 |     parser.add_option(
 624 |         "--no-headers",
 625 |         default=False,
 626 |         action="store_true",
 627 |         help="don't label the left and right sides " "with their file names",
 628 |     )
 629 |     parser.add_option(
 630 |         "--output-encoding",
 631 |         default="utf-8",
 632 |         help="specify the output encoding; defaults to utf8",
 633 |     )
 634 |     parser.add_option(
 635 |         "-r",
 636 |         "--recursive",
 637 |         default=False,
 638 |         action="store_true",
 639 |         help="recursively compare subdirectories",
 640 |     )
 641 |     parser.add_option(
 642 |         "-s",
 643 |         "--report-identical-files",
 644 |         default=False,
 645 |         action="store_true",
 646 |         help="report when two files are the same",
 647 |     )
 648 |     parser.add_option(
 649 |         "--show-all-spaces",
 650 |         default=False,
 651 |         action="store_true",
 652 |         help="color all non-matching whitespace including "
 653 |         "that which is not needed for drawing the eye to "
 654 |         "changes.  Slow, ugly, displays all changes",
 655 |     )
 656 |     parser.add_option(
 657 |         "--show-no-spaces",
 658 |         default=False,
 659 |         action="store_true",
 660 |         help="don't color whitespace-only changes",
 661 |     )
 662 |     parser.add_option("--tabsize", default=8, help="tab stop spacing")
 663 |     parser.add_option(
 664 |         "-t",
 665 |         "--truncate",
 666 |         default=False,
 667 |         action="store_true",
 668 |         help="truncate long lines instead of wrapping them",
 669 |     )
 670 |     parser.add_option(
 671 |         "-u",
 672 |         "--patch",
 673 |         default=True,
 674 |         action="store_true",
 675 |         help="generate patch. This is always true, "
 676 |         "and only exists for compatibility",
 677 |     )
 678 |     parser.add_option(
 679 |         "-U",
 680 |         "--unified",
 681 |         "--numlines",
 682 |         default=5,
 683 |         metavar="NUM",
 684 |         help="how many lines of context to print; "
 685 |         "can't be combined with --whole-file",
 686 |     )
 687 |     parser.add_option(
 688 |         "-W",
 689 |         "--whole-file",
 690 |         default=False,
 691 |         action="store_true",
 692 |         help="show the whole file instead of just changed "
 693 |         "lines and context",
 694 |     )
 695 |     parser.add_option(
 696 |         "-P",
 697 |         "--permissions",
 698 |         default=False,
 699 |         action="store_true",
 700 |         help="compare the file permissions as well as the "
 701 |         "content of the file",
 702 |     )
 703 |     parser.add_option(
 704 |         "--strip-trailing-cr",
 705 |         default=False,
 706 |         action="store_true",
 707 |         help="strip any trailing carriage return at the end of "
 708 |         "an input line",
 709 |     )
 710 |     parser.add_option(
 711 |         "--color-map",
 712 |         default=None,
 713 |         help="choose which colors are used for which items. "
 714 |         "Default is --color-map='"
 715 |         + ",".join("%s:%s" % x for x in sorted(color_mapping.items()))
 716 |         + "'"
 717 |         ".  You don't have to override all of them: "
 718 |         "'--color-map=separator:white,description:cyan",
 719 |     )
 720 |     parser.add_option(
 721 |         "--is-git-diff",
 722 |         default=False,
 723 |         action="store_true",
 724 |         help="Show the real file name when displaying " "git-diff result",
 725 |     )
 726 |     parser.add_option(
 727 |         "-x",
 728 |         "--exclude",
 729 |         metavar="PAT",
 730 |         action="append",
 731 |         default=[],
 732 |         help="exclude files that match PAT",
 733 |     )
 734 |     return parser
 735 | 
 736 | 
 737 | def set_cols_option(options):
 738 |     if os.name == "nt":
 739 |         try:
 740 |             import struct
 741 |             from ctypes import windll, create_string_buffer
 742 | 
 743 |             fh = windll.kernel32.GetStdHandle(-12)  # stderr is -12
 744 |             csbi = create_string_buffer(22)
 745 |             windll.kernel32.GetConsoleScreenBufferInfo(fh, csbi)
 746 |             res = struct.unpack("hhhhHhhhhhh", csbi.raw)
 747 |             options.cols = res[7] - res[5] + 1  # right - left + 1
 748 |             return
 749 | 
 750 |         except Exception:
 751 |             pass
 752 | 
 753 |     else:
 754 | 
 755 |         def ioctl_GWINSZ(fd):
 756 |             try:
 757 |                 import fcntl
 758 |                 import termios
 759 |                 import struct
 760 | 
 761 |                 cr = struct.unpack(
 762 |                     "hh", fcntl.ioctl(fd, termios.TIOCGWINSZ, "1234")
 763 |                 )
 764 |             except Exception:
 765 |                 return None
 766 |             return cr
 767 | 
 768 |         cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
 769 |         if cr and cr[1] > 0:
 770 |             options.cols = cr[1]
 771 |             return
 772 |     options.cols = 80
 773 | 
 774 | 
 775 | def validate_has_two_arguments(parser, args):
 776 |     if len(args) != 2:
 777 |         parser.print_help()
 778 |         sys.exit(EXIT_CODE_DIFF)
 779 | 
 780 | 
 781 | def start():
 782 |     diffs_found = False
 783 |     parser = create_option_parser()
 784 |     options, args = parser.parse_args()
 785 |     validate_has_two_arguments(parser, args)
 786 |     if not options.cols:
 787 |         set_cols_option(options)
 788 |     try:
 789 |         diffs_found = diff(options, *args)
 790 |     except KeyboardInterrupt:
 791 |         pass
 792 |     except IOError as e:
 793 |         if e.errno == errno.EPIPE:
 794 |             pass
 795 |         else:
 796 |             raise
 797 | 
 798 |     # Close stderr to prevent printing errors when icdiff is piped to
 799 |     # something that closes before icdiff is done writing
 800 |     #
 801 |     # See: https://stackoverflow.com/questions/26692284/...
 802 |     #      ...how-to-prevent-brokenpipeerror-when-doing-a-flush-in-python
 803 |     sys.stderr.close()
 804 |     sys.exit(EXIT_CODE_DIFF if diffs_found else EXIT_CODE_SUCCESS)
 805 | 
 806 | 
 807 | def codec_print(s, options):
 808 |     s = "%s\n" % s
 809 |     if hasattr(sys.stdout, "buffer"):
 810 |         sys.stdout.buffer.write(s.encode(options.output_encoding))
 811 |     else:
 812 |         sys.stdout.write(s.encode(options.output_encoding))
 813 | 
 814 | 
 815 | def cmp_perms(options, a, b):
 816 |     return not options.permissions or (
 817 |         os.lstat(a).st_mode == os.lstat(b).st_mode
 818 |     )
 819 | 
 820 | 
 821 | def should_be_excluded(name, pats):
 822 |     return any(fnmatch.fnmatchcase(name, pat) for pat in pats)
 823 | 
 824 | 
 825 | def diff(options, a, b):
 826 |     def print_meta(s):
 827 |         codec_print(simple_colorize(s, "meta"), options)
 828 | 
 829 |     # We start out and assume that no diffs have been found (so far)
 830 |     diffs_found = False
 831 | 
 832 |     # Don't use os.path.isfile; it returns False for file-like entities like
 833 |     # bash's process substitution (/dev/fd/N).
 834 |     is_a_file = not os.path.isdir(a)
 835 |     is_b_file = not os.path.isdir(b)
 836 | 
 837 |     if is_a_file and is_b_file:
 838 |         try:
 839 |             if not (
 840 |                 filecmp.cmp(a, b, shallow=False) and cmp_perms(options, a, b)
 841 |             ):
 842 |                 diffs_found = diffs_found | diff_files(options, a, b)
 843 |             elif options.report_identical_files:
 844 |                 print("Files %s and %s are identical." % (a, b))
 845 |         except OSError as e:
 846 |             if e.errno == errno.ENOENT:
 847 |                 print_meta("error: file '%s' was not found" % e.filename)
 848 |                 sys.exit(EXIT_CODE_ERROR)
 849 |             else:
 850 |                 raise (e)
 851 | 
 852 |     elif not is_a_file and not is_b_file:
 853 |         a_contents = set(os.listdir(a))
 854 |         b_contents = set(os.listdir(b))
 855 | 
 856 |         for child in sorted(a_contents.union(b_contents)):
 857 |             if should_be_excluded(child, options.exclude):
 858 |                 continue
 859 |             if child not in b_contents:
 860 |                 print_meta("Only in %s: %s" % (a, child))
 861 |             elif child not in a_contents:
 862 |                 print_meta("Only in %s: %s" % (b, child))
 863 |             elif options.recursive:
 864 |                 diffs_found = diffs_found | diff(
 865 |                     options, os.path.join(a, child), os.path.join(b, child)
 866 |                 )
 867 |     elif not is_a_file and is_b_file:
 868 |         print_meta("File %s is a directory while %s is a file" % (a, b))
 869 |         diffs_found = True
 870 | 
 871 |     elif is_a_file and not is_b_file:
 872 |         print_meta("File %s is a file while %s is a directory" % (a, b))
 873 |         diffs_found = True
 874 | 
 875 |     return diffs_found
 876 | 
 877 | 
 878 | def read_file(fname, options):
 879 |     try:
 880 |         with codecs.open(fname, encoding=options.encoding, mode="rb") as inf:
 881 |             return inf.readlines()
 882 |     except UnicodeDecodeError as e:
 883 |         codec_print(
 884 |             "error: file '%s' not valid with encoding '%s': <%s> at %s-%s."
 885 |             % (fname, options.encoding, e.reason, e.start, e.end),
 886 |             options,
 887 |         )
 888 |         raise
 889 |     except LookupError:
 890 |         codec_print(
 891 |             "error: encoding '%s' was not found." % (options.encoding), options
 892 |         )
 893 |         sys.exit(EXIT_CODE_ERROR)
 894 | 
 895 | 
 896 | def format_label(path, label="{path}"):
 897 |     """Format a label using a file's path and basename.
 898 | 
 899 |     Example:
 900 |       For file `/foo/bar.py` and label "Yours: {basename}" -
 901 |       The output is "Yours: bar.py"
 902 |     """
 903 |     return label.format(path=path, basename=os.path.basename(path))
 904 | 
 905 | 
 906 | def diff_files(options, a, b):
 907 |     diff_found = False
 908 |     if options.is_git_diff is True:
 909 |         # Use $BASE as label when displaying git-diff result
 910 |         base = os.getenv("BASE")
 911 |         headers = [format_label(a, base), format_label(b, base)]
 912 |     else:
 913 |         if options.labels:
 914 |             if len(options.labels) == 2:
 915 |                 headers = [
 916 |                     format_label(a, options.labels[0]),
 917 |                     format_label(b, options.labels[1]),
 918 |                 ]
 919 |             else:
 920 |                 codec_print(
 921 |                     "error: to use arbitrary file labels, "
 922 |                     "specify -L twice.",
 923 |                     options,
 924 |                 )
 925 |                 sys.exit(EXIT_CODE_ERROR)
 926 |         else:
 927 |             headers = a, b
 928 |     if options.no_headers:
 929 |         headers = None, None
 930 | 
 931 |     head = int(options.head)
 932 | 
 933 |     assert not os.path.isdir(a)
 934 |     assert not os.path.isdir(b)
 935 | 
 936 |     try:
 937 |         lines_a = read_file(a, options)
 938 |         lines_b = read_file(b, options)
 939 |     except UnicodeDecodeError:
 940 |         return diff_found
 941 | 
 942 |     if head != 0:
 943 |         lines_a = lines_a[:head]
 944 |         lines_b = lines_b[:head]
 945 | 
 946 |     if options.matcher:
 947 |         lines_a = [
 948 |             line_a
 949 |             for line_a in lines_a
 950 |             if not re.search(options.matcher, line_a)
 951 |         ]
 952 |         lines_b = [
 953 |             line_b
 954 |             for line_b in lines_b
 955 |             if not re.search(options.matcher, line_b)
 956 |         ]
 957 | 
 958 |     # Determine if a difference has been detected
 959 |     diff_found = lines_a != lines_b or not cmp_perms(options, a, b)
 960 | 
 961 |     if options.no_bold:
 962 |         for key in color_mapping:
 963 |             color_mapping[key] = color_mapping[key].replace("_bold", "")
 964 | 
 965 |     if options.color_map:
 966 |         command_for_errors = '--color-map="%s"' % (options.color_map)
 967 |         for mapping in options.color_map.split(","):
 968 |             category, color = mapping.split(":", 1)
 969 | 
 970 |             if category not in color_mapping:
 971 |                 print(
 972 |                     "Invalid category '%s' in '%s'.  Valid categories are: %s."
 973 |                     % (
 974 |                         category,
 975 |                         command_for_errors,
 976 |                         ", ".join(sorted(color_mapping.keys())),
 977 |                     )
 978 |                 )
 979 |                 sys.exit(EXIT_CODE_ERROR)
 980 | 
 981 |             if color not in color_codes:
 982 |                 print(
 983 |                     "Invalid color '%s' in '%s'.  Valid colors are: %s."
 984 |                     % (
 985 |                         color,
 986 |                         command_for_errors,
 987 |                         ", ".join(
 988 |                             [
 989 |                                 raw_colorize(x, x)
 990 |                                 for x in sorted(color_codes.keys())
 991 |                             ]
 992 |                         ),
 993 |                     )
 994 |                 )
 995 |                 sys.exit(EXIT_CODE_ERROR)
 996 | 
 997 |             color_mapping[category] = color
 998 | 
 999 |     if options.permissions:
1000 |         mode_a = os.lstat(a).st_mode
1001 |         mode_b = os.lstat(b).st_mode
1002 |     else:
1003 |         mode_a = None
1004 |         mode_b = None
1005 | 
1006 |     cd = ConsoleDiff(
1007 |         cols=int(options.cols),
1008 |         show_all_spaces=options.show_all_spaces,
1009 |         show_no_spaces=options.show_no_spaces,
1010 |         highlight=options.highlight,
1011 |         line_numbers=options.line_numbers,
1012 |         tabsize=int(options.tabsize),
1013 |         truncate=options.truncate,
1014 |         strip_trailing_cr=options.strip_trailing_cr,
1015 |     )
1016 |     for line in cd.make_table(
1017 |         lines_a,
1018 |         lines_b,
1019 |         headers[0],
1020 |         headers[1],
1021 |         mode_a,
1022 |         mode_b,
1023 |         context=(not options.whole_file),
1024 |         numlines=int(options.unified),
1025 |     ):
1026 |         codec_print(line, options)
1027 |         sys.stdout.flush()
1028 | 
1029 |     return diff_found
1030 | 
1031 | 
1032 | if __name__ == "__main__":
1033 |     start()
1034 | 


--------------------------------------------------------------------------------
/icdiff.py:
--------------------------------------------------------------------------------
1 | icdiff


--------------------------------------------------------------------------------
/requirements-dev.txt:
--------------------------------------------------------------------------------
1 | flake8==2.4.0
2 | mccabe==0.3
3 | pep8==1.5.7
4 | pyflakes==0.8.1
5 | black==22.3.0
6 | 


--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
 1 | from setuptools import setup
 2 | from icdiff import __version__
 3 | 
 4 | setup(
 5 |     name="icdiff",
 6 |     version=__version__,
 7 |     url="https://www.jefftk.com/icdiff",
 8 |     project_urls={
 9 |         "Source": "https://github.com/jeffkaufman/icdiff",
10 |     },
11 |     classifiers=[
12 |         "License :: OSI Approved :: Python Software Foundation License"
13 |     ],
14 |     author="Jeff Kaufman",
15 |     author_email="jeff@jefftk.com",
16 |     description="improved colored diff",
17 |     long_description=open('README.md').read(),
18 |     long_description_content_type='text/markdown',
19 |     scripts=['git-icdiff'],
20 |     py_modules=['icdiff'],
21 |     entry_points={
22 |         'console_scripts': [
23 |             'icdiff=icdiff:start',
24 |         ],
25 |     },
26 | )
27 | 


--------------------------------------------------------------------------------
/test.sh:
--------------------------------------------------------------------------------
  1 | #!/bin/bash
  2 | 
  3 | # Usage: ./test.sh [--regold] [test-name] python[3]
  4 | # Example:
  5 | #   Run all tests:
  6 | #     ./test.sh python3
  7 | #   Regold all tests:
  8 | #     ./test.sh --regold python3
  9 | #   Run one test:
 10 | #     ./test.sh tests/gold-45-sas-h-nb.txt python3
 11 | #   Regold one test:
 12 | #     ./test.sh --regold tests/gold-45-sas-h-nb.txt python3
 13 | 
 14 | if [ "$#" -gt 1 -a "$1" = "--regold" ]; then
 15 |   REGOLD=true
 16 |   shift
 17 | else
 18 |   REGOLD=false
 19 | fi
 20 | 
 21 | TEST_NAME=all
 22 | if [ "$#" -gt 1 ]; then
 23 |   TEST_NAME=$1
 24 |   shift
 25 | fi
 26 | 
 27 | if [ "$#" != 1 ]; then
 28 |   echo "Usage: '$0 [--regold] [test-name] python[3]'"
 29 |   exit 1
 30 | fi
 31 | 
 32 | PYTHON="$1"
 33 | ICDIFF="icdiff"
 34 | 
 35 | if [ ! -z "$INSTALLED" ]; then
 36 |   INVOCATION="$ICDIFF"
 37 | else
 38 |   INVOCATION="$PYTHON $ICDIFF"
 39 | fi
 40 | 
 41 | function fail() {
 42 |   echo "FAIL"
 43 |   exit 1
 44 | }
 45 | 
 46 | function check_gold() {
 47 |   local error_code
 48 |   local expect=$1
 49 |   local gold=tests/$2
 50 |   shift
 51 |   shift
 52 | 
 53 |   if [ $TEST_NAME != "all" -a $TEST_NAME != $gold ]; then
 54 |     return
 55 |   fi
 56 | 
 57 |   echo "    check_gold $gold matches $@"
 58 |   local tmp=/tmp/icdiff.output
 59 |   $INVOCATION "$@" &> $tmp
 60 |   error_code=$?
 61 | 
 62 |   if $REGOLD; then
 63 |     if [ -e $gold ] && diff $tmp $gold > /dev/null; then
 64 |       echo "Did not need to regold $gold"
 65 |     else
 66 |       cat $tmp
 67 |       read -p "Is this correct? y/n > " -n 1 -r
 68 |       echo
 69 |       if [[ $REPLY =~ ^[Yy]$ ]]; then
 70 |         mv $tmp $gold
 71 |         echo "Regolded $gold."
 72 |       else
 73 |         echo "Did not regold $gold."
 74 |       fi
 75 |     fi
 76 |     return
 77 |   fi
 78 | 
 79 |   if ! diff $gold $tmp; then
 80 |     echo "Got: ($tmp)"
 81 |     cat $tmp
 82 |     echo "Expected: ($gold)"
 83 |     cat $gold
 84 |     fail
 85 |   fi
 86 | 
 87 |   if [[ $error_code != $expect ]]; then
 88 |     echo "Got error code:      $error_code"
 89 |     echo "Expected error code: $expect"
 90 |     fail
 91 |   fi
 92 | }
 93 | 
 94 | FIRST_TIME_CHECK_GIT_DIFF=true
 95 | function check_git_diff() {
 96 |   local gitdiff=tests/$1
 97 |   shift
 98 | 
 99 |   echo "    check_gitdiff $gitdiff matches git icdiff $@"
100 |   # Check when using icdiff in git
101 |   if $FIRST_TIME_CHECK_GIT_DIFF; then
102 |     FIRST_TIME_CHECK_GIT_DIFF=false
103 |     # Set default args when first time check git diff
104 |     yes | git difftool --extcmd icdiff > /dev/null
105 |     git config --global icdiff.options '--cols=80'
106 |     export PATH="$(pwd)":$PATH
107 |   fi
108 |   local tmp=/tmp/git-icdiff.output
109 |   git icdiff $1 $2 &> $tmp
110 |   if ! diff $tmp $gitdiff; then
111 |     echo "Got: ($tmp)"
112 |     cat $tmp
113 |     echo "Expected: ($gitdiff)"
114 |     fail
115 |   fi
116 | }
117 | 
118 | check_gold 1 gold-recursive.txt       --recursive tests/{a,b} --cols=80
119 | check_gold 1 gold-exclude.txt         --exclude-lines '^#|  pad' tests/input-4-cr.txt tests/input-4-partial-cr.txt --cols=80
120 | check_gold 0 gold-dir.txt             tests/{a,b} --cols=80
121 | check_gold 1 gold-12.txt              tests/input-{1,2}.txt --cols=80
122 | check_gold 1 gold-12-t.txt            tests/input-{1,2}.txt --cols=80 --truncate
123 | check_gold 0 gold-3.txt               tests/input-{3,3}.txt
124 | check_gold 1 gold-45.txt              tests/input-{4,5}.txt --cols=80
125 | check_gold 1 gold-45-95.txt           tests/input-{4,5}.txt --cols=95
126 | check_gold 1 gold-45-sas.txt          tests/input-{4,5}.txt --cols=80 --show-all-spaces
127 | check_gold 1 gold-45-h.txt            tests/input-{4,5}.txt --cols=80 --highlight
128 | check_gold 1 gold-45-nb.txt           tests/input-{4,5}.txt --cols=80 --no-bold
129 | check_gold 1 gold-45-sas-h.txt        tests/input-{4,5}.txt --cols=80 --show-all-spaces --highlight
130 | check_gold 1 gold-45-sas-h-nb.txt     tests/input-{4,5}.txt --cols=80 --show-all-spaces --highlight --no-bold
131 | check_gold 1 gold-sas.txt             tests/input-{10,11}.txt --cols=80 --show-all-spaces
132 | check_gold 1 gold-sns.txt             tests/input-{10,11}.txt --cols=80 --show-no-spaces
133 | check_gold 1 gold-show-spaces.txt     tests/input-{10,11}.txt --cols=80
134 | check_gold 1 gold-45-h-nb.txt         tests/input-{4,5}.txt --cols=80 --highlight --no-bold
135 | check_gold 1 gold-45-ln.txt           tests/input-{4,5}.txt --cols=80 --line-numbers
136 | check_gold 1 gold-45-ln-color.txt     tests/input-{4,5}.txt --cols=80 --line-numbers --color-map='line-numbers:cyan'
137 | check_gold 1 gold-45-nh.txt           tests/input-{4,5}.txt --cols=80 --no-headers
138 | check_gold 1 gold-45-h3.txt           tests/input-{4,5}.txt --cols=80 --head=3
139 | check_gold 2 gold-45-l.txt            tests/input-{4,5}.txt --cols=80 -L left
140 | check_gold 1 gold-45-lr.txt           tests/input-{4,5}.txt --cols=80 -L left -L right
141 | check_gold 1 gold-45-lbrb.txt         tests/input-{4,5}.txt --cols=80 -L "L {basename}" -L "R {basename}"
142 | check_gold 1 gold-45-pipe.txt         tests/input-4.txt <(cat tests/input-5.txt) --cols=80 --no-headers
143 | check_gold 1 gold-4dn.txt             tests/input-4.txt /dev/null --cols=80 -L left -L right
144 | check_gold 1 gold-dn5.txt             /dev/null tests/input-5.txt --cols=80 -L left -L right
145 | check_gold 1 gold-67.txt              tests/input-{6,7}.txt --cols=80
146 | check_gold 1 gold-67-wf.txt           tests/input-{6,7}.txt --cols=80 --whole-file
147 | check_gold 1 gold-67-ln.txt           tests/input-{6,7}.txt --cols=80 --line-numbers
148 | check_gold 1 gold-67-u3.txt           tests/input-{6,7}.txt --cols=80 -U 3
149 | check_gold 1 gold-tabs-default.txt    tests/input-{8,9}.txt --cols=80
150 | check_gold 1 gold-tabs-4.txt          tests/input-{8,9}.txt --cols=80 --tabsize=4
151 | check_gold 2 gold-file-not-found.txt  tests/input-4.txt nonexistent_file
152 | check_gold 1 gold-strip-cr-off.txt    tests/input-4.txt tests/input-4-cr.txt --cols=80
153 | check_gold 1 gold-strip-cr-on.txt     tests/input-4.txt tests/input-4-cr.txt --cols=80 --strip-trailing-cr
154 | check_gold 1 gold-no-cr-indent        tests/input-4-cr.txt tests/input-4-partial-cr.txt --cols=80
155 | check_gold 1 gold-hide-cr-if-dos      tests/input-4-cr.txt tests/input-5-cr.txt --cols=80
156 | check_gold 1 gold-12-subcolors.txt    tests/input-{1,2}.txt --cols=80 --color-map='change:magenta,description:cyan_bold'
157 | check_gold 2 gold-subcolors-bad-color tests/input-{1,2}.txt --cols=80 --color-map='change:mageta,description:cyan_bold'
158 | check_gold 2 gold-subcolors-bad-cat tests/input-{1,2}.txt --cols=80 --color-map='chnge:magenta,description:cyan_bold'
159 | check_gold 2 gold-subcolors-bad-fmt tests/input-{1,2}.txt --cols=80 --color-map='change:magenta:gold,description:cyan_bold'
160 | check_gold 0 gold-identical-on.txt tests/input-{1,1}.txt -s
161 | check_gold 2 gold-bad-encoding.txt tests/input-{1,2}.txt --encoding=nonexistend_encoding
162 | check_gold 0 gold-recursive-with-exclude.txt --recursive -x c tests/{a,b} --cols=80
163 | check_gold 1 gold-recursive-with-exclude2.txt --recursive -x 'excl*' tests/test-with-exclude/{a,b} --cols=80
164 | check_gold 0 gold-exit-process-sub tests/input-1.txt <(cat tests/input-1.txt) --no-headers --cols=80
165 | 
166 | rm -f tests/permissions-{a,b}
167 | touch tests/permissions-{a,b}
168 | check_gold 0 gold-permissions-same.txt tests/permissions-{a,b} -P --cols=80
169 | 
170 | chmod 666 tests/permissions-a
171 | chmod 665 tests/permissions-b
172 | check_gold 1 gold-permissions-diff.txt tests/permissions-{a,b} -P --cols=80
173 | 
174 | echo "some text" >> tests/permissions-a
175 | check_gold 1 gold-permissions-diff-text.txt tests/permissions-{a,b} -P --cols=80
176 | 
177 | echo -e "\04" >> tests/permissions-b
178 | check_gold 1 gold-permissions-diff-binary.txt tests/permissions-{a,b} -P --cols=80
179 | rm -f tests/permissions-{a,b}
180 | 
181 | if git show 4e86205629 &> /dev/null; then
182 |   # We're in the repo, so test git.
183 |   check_git_diff gitdiff-only-newlines.txt 4e86205629~1 4e86205629
184 | else
185 |   echo "Not in icdiff repo; skipping git test"
186 | fi
187 | 
188 | # Testing pipe behavior doesn't fit well with the check_gold system
189 | $INVOCATION tests/input-{4,5}.txt 2>/tmp/icdiff-pipe-error-output | head -n 1
190 | if [ -s /tmp/icdiff-pipe-error-output ]; then
191 |   echo 'emitting errors on early pipe closure'
192 |   fail
193 | fi
194 | 
195 | VERSION=$($INVOCATION --version | awk '{print $NF}')
196 | if [ "$VERSION" != $(head -n 1 ChangeLog) ]; then
197 |   echo "Version mismatch between ChangeLog and icdiff source."
198 |   fail
199 | fi
200 | 
201 | function ensure_installed() {
202 |   if ! command -v "$1" >/dev/null 2>&1; then
203 |     echo "Could not find $1."
204 |     echo 'Ensure it is installed and on your $PATH.'
205 |     if [ -z "$VIRTUAL_ENV" ]; then
206 |       echo 'It appears you have have forgotten to activate your virtualenv.'
207 |     fi
208 |     echo 'See README.md for details on setting up your environment.'
209 |     fail
210 |   fi
211 | }
212 | 
213 | ensure_installed "black"
214 | echo 'Running black formatter...'
215 | if ! black icdiff --quiet --line-length 79 --check; then
216 |   echo ""
217 |   echo 'Consider running `black icdiff --line-length 79`'
218 |   fail
219 | fi
220 | 
221 | ensure_installed "flake8"
222 | echo 'Running flake8 linter...'
223 | if ! flake8 icdiff; then
224 |   fail
225 | fi
226 | 
227 | if ! $REGOLD; then
228 |   echo PASS
229 | fi
230 | 


--------------------------------------------------------------------------------
/tests/a/1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeffkaufman/icdiff/7b3692c79555e981e3cdc6da1fdfabf5e7b0a4ea/tests/a/1


--------------------------------------------------------------------------------
/tests/a/c/e:
--------------------------------------------------------------------------------
1 | 1
2 | 


--------------------------------------------------------------------------------
/tests/a/c/f:
--------------------------------------------------------------------------------
1 | 2
2 | 


--------------------------------------------------------------------------------
/tests/a/j:
--------------------------------------------------------------------------------
1 | 7
2 | 


--------------------------------------------------------------------------------
/tests/b/1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeffkaufman/icdiff/7b3692c79555e981e3cdc6da1fdfabf5e7b0a4ea/tests/b/1


--------------------------------------------------------------------------------
/tests/b/c/e:
--------------------------------------------------------------------------------
1 | 1
2 | 


--------------------------------------------------------------------------------
/tests/b/c/f:
--------------------------------------------------------------------------------
1 | 3
2 | 


--------------------------------------------------------------------------------
/tests/b/c/g:
--------------------------------------------------------------------------------
1 | 4
2 | 


--------------------------------------------------------------------------------
/tests/b/c/h:
--------------------------------------------------------------------------------
1 | 5
2 | 


--------------------------------------------------------------------------------
/tests/b/d/q:
--------------------------------------------------------------------------------
1 | 9
2 | 


--------------------------------------------------------------------------------
/tests/b/i:
--------------------------------------------------------------------------------
1 | 6
2 | 


--------------------------------------------------------------------------------
/tests/gitdiff-only-newlines.txt:
--------------------------------------------------------------------------------
 1 | README                                  README                                 
 2 |   --show-all-spaces    color all non-m    --show-all-spaces    color all non-m 
 3 | atching whitespace including            atching whitespace including           
 4 |                        that which is n                         that which is n 
 5 | ot needed for drawing the eye to        ot needed for drawing the eye to       
 6 |                        changes. Slow,                          changes. Slow,  
 7 | ugly, displays all changes              ugly, displays all changes             
 8 |   --print-headers      label the left     --print-headers      label the left  
 9 | and right sides with their file         and right sides with their file        
10 |                        names                                   names           
11 |                                                                                
12 |                                         License:                               
13 |                                                                                
14 |                                           This file is derived from difflib.Ht 
15 |                                         mlDiff which is under the license:     
16 |                                                                                
17 |                                             http://www.python.org/download/rel 
18 |                                         eases/2.6.2/license/                   
19 |                                                                                
20 |                                           I release my changes here under the  
21 |                                         same license.  This is GPL compatible. 
22 |                                                                                
23 | 


--------------------------------------------------------------------------------
/tests/gold-12-subcolors.txt:
--------------------------------------------------------------------------------
1 | tests/input-1.txt                       tests/input-2.txt                      
2 | 测试行abc测试测试行abc,测试测试行abc测 测试行adc测试测试行adc,测试测试行adc测
3 | 试测试行abc测试测试行abc测试测试行abc测 试测试行adc测试测试行adc测试测试行adc测
4 | 试测试行abc测试测试行abc测试测试行abc测 试测试行adc测试测试行adc测试测试行adc测
5 | 试                                      试                                     
6 | 


--------------------------------------------------------------------------------
/tests/gold-12-t.txt:
--------------------------------------------------------------------------------
1 | tests/input-1.txt                       tests/input-2.txt                      
2 | 测试行abc测试测试行abc,测试测试行abc测 测试行adc测试测试行adc,测试测试行adc测
3 | 


--------------------------------------------------------------------------------
/tests/gold-12.txt:
--------------------------------------------------------------------------------
1 | tests/input-1.txt                       tests/input-2.txt                      
2 | 测试行abc测试测试行abc,测试测试行abc测 测试行adc测试测试行adc,测试测试行adc测
3 | 试测试行abc测试测试行abc测试测试行abc测 试测试行adc测试测试行adc测试测试行adc测
4 | 试测试行abc测试测试行abc测试测试行abc测 试测试行adc测试测试行adc测试测试行adc测
5 | 试                                      试                                     
6 | 


--------------------------------------------------------------------------------
/tests/gold-3.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeffkaufman/icdiff/7b3692c79555e981e3cdc6da1fdfabf5e7b0a4ea/tests/gold-3.txt


--------------------------------------------------------------------------------
/tests/gold-45-95.txt:
--------------------------------------------------------------------------------
 1 | tests/input-4.txt                              tests/input-5.txt                             
 2 | #input, #button {                              #input, #button {                             
 3 |   width: 350px;                                  width: 400px;                               
 4 |   height: 40px;                                  height: 40px;                               
 5 |                                                  font-size: 30px;                            
 6 |   margin: 0px;                                   margin: 0;                                  
 7 |   padding: 0px;                                  padding: 0;                                 
 8 |   margin-bottom: 15px;                                                                       
 9 |   text-align: center;                            text-align: center;                         
10 | }                                              }                                             
11 | 


--------------------------------------------------------------------------------
/tests/gold-45-h-nb.txt:
--------------------------------------------------------------------------------
 1 | tests/input-4.txt                       tests/input-5.txt                      
 2 | #input, #button {                       #input, #button {                      
 3 |   width: 350px;                           width: 400px;                        
 4 |   height: 40px;                           height: 40px;                        
 5 |                                           font-size: 30px;                     
 6 |   margin: 0px;                            margin: 0;                           
 7 |   padding: 0px;                           padding: 0;                          
 8 |   margin-bottom: 15px;                                                         
 9 |   text-align: center;                     text-align: center;                  
10 | }                                       }                                      
11 | 


--------------------------------------------------------------------------------
/tests/gold-45-h.txt:
--------------------------------------------------------------------------------
 1 | tests/input-4.txt                       tests/input-5.txt                      
 2 | #input, #button {                       #input, #button {                      
 3 |   width: 350px;                           width: 400px;                        
 4 |   height: 40px;                           height: 40px;                        
 5 |                                           font-size: 30px;                     
 6 |   margin: 0px;                            margin: 0;                           
 7 |   padding: 0px;                           padding: 0;                          
 8 |   margin-bottom: 15px;                                                         
 9 |   text-align: center;                     text-align: center;                  
10 | }                                       }                                      
11 | 


--------------------------------------------------------------------------------
/tests/gold-45-h3.txt:
--------------------------------------------------------------------------------
1 | tests/input-4.txt                       tests/input-5.txt                      
2 | #input, #button {                       #input, #button {                      
3 |   width: 350px;                           width: 400px;                        
4 |   height: 40px;                           height: 40px;                        
5 | 


--------------------------------------------------------------------------------
/tests/gold-45-l.txt:
--------------------------------------------------------------------------------
1 | error: to use arbitrary file labels, specify -L twice.
2 | 


--------------------------------------------------------------------------------
/tests/gold-45-lbrb.txt:
--------------------------------------------------------------------------------
 1 | L input-4.txt                           R input-5.txt                          
 2 | #input, #button {                       #input, #button {                      
 3 |   width: 350px;                           width: 400px;                        
 4 |   height: 40px;                           height: 40px;                        
 5 |                                           font-size: 30px;                     
 6 |   margin: 0px;                            margin: 0;                           
 7 |   padding: 0px;                           padding: 0;                          
 8 |   margin-bottom: 15px;                                                         
 9 |   text-align: center;                     text-align: center;                  
10 | }                                       }                                      
11 | 


--------------------------------------------------------------------------------
/tests/gold-45-ln-color.txt:
--------------------------------------------------------------------------------
 1 | tests/input-4.txt                       tests/input-5.txt                      
 2 |        1 #input, #button {                     1 #input, #button {             
 3 |        2   width: 350px;                       2   width: 400px;               
 4 |        3   height: 40px;                       3   height: 40px;               
 5 |                                                4   font-size: 30px;            
 6 |        4   margin: 0px;                        5   margin: 0;                  
 7 |        5   padding: 0px;                       6   padding: 0;                 
 8 |        6   margin-bottom: 15px;                                                
 9 |        7   text-align: center;                 7   text-align: center;         
10 |        8 }                                     8 }                             
11 | 


--------------------------------------------------------------------------------
/tests/gold-45-ln.txt:
--------------------------------------------------------------------------------
 1 | tests/input-4.txt                       tests/input-5.txt                      
 2 |        1 #input, #button {                     1 #input, #button {             
 3 |        2   width: 350px;                       2   width: 400px;               
 4 |        3   height: 40px;                       3   height: 40px;               
 5 |                                                4   font-size: 30px;            
 6 |        4   margin: 0px;                        5   margin: 0;                  
 7 |        5   padding: 0px;                       6   padding: 0;                 
 8 |        6   margin-bottom: 15px;                                                
 9 |        7   text-align: center;                 7   text-align: center;         
10 |        8 }                                     8 }                             
11 | 


--------------------------------------------------------------------------------
/tests/gold-45-lr.txt:
--------------------------------------------------------------------------------
 1 | left                                    right                                  
 2 | #input, #button {                       #input, #button {                      
 3 |   width: 350px;                           width: 400px;                        
 4 |   height: 40px;                           height: 40px;                        
 5 |                                           font-size: 30px;                     
 6 |   margin: 0px;                            margin: 0;                           
 7 |   padding: 0px;                           padding: 0;                          
 8 |   margin-bottom: 15px;                                                         
 9 |   text-align: center;                     text-align: center;                  
10 | }                                       }                                      
11 | 


--------------------------------------------------------------------------------
/tests/gold-45-nb.txt:
--------------------------------------------------------------------------------
 1 | tests/input-4.txt                       tests/input-5.txt                      
 2 | #input, #button {                       #input, #button {                      
 3 |   width: 350px;                           width: 400px;                        
 4 |   height: 40px;                           height: 40px;                        
 5 |                                           font-size: 30px;                     
 6 |   margin: 0px;                            margin: 0;                           
 7 |   padding: 0px;                           padding: 0;                          
 8 |   margin-bottom: 15px;                                                         
 9 |   text-align: center;                     text-align: center;                  
10 | }                                       }                                      
11 | 


--------------------------------------------------------------------------------
/tests/gold-45-nh.txt:
--------------------------------------------------------------------------------
 1 | #input, #button {                       #input, #button {                      
 2 |   width: 350px;                           width: 400px;                        
 3 |   height: 40px;                           height: 40px;                        
 4 |                                           font-size: 30px;                     
 5 |   margin: 0px;                            margin: 0;                           
 6 |   padding: 0px;                           padding: 0;                          
 7 |   margin-bottom: 15px;                                                         
 8 |   text-align: center;                     text-align: center;                  
 9 | }                                       }                                      
10 | 


--------------------------------------------------------------------------------
/tests/gold-45-pipe.txt:
--------------------------------------------------------------------------------
 1 | #input, #button {                       #input, #button {                      
 2 |   width: 350px;                           width: 400px;                        
 3 |   height: 40px;                           height: 40px;                        
 4 |                                           font-size: 30px;                     
 5 |   margin: 0px;                            margin: 0;                           
 6 |   padding: 0px;                           padding: 0;                          
 7 |   margin-bottom: 15px;                                                         
 8 |   text-align: center;                     text-align: center;                  
 9 | }                                       }                                      
10 | 


--------------------------------------------------------------------------------
/tests/gold-45-sas-h-nb.txt:
--------------------------------------------------------------------------------
 1 | tests/input-4.txt                       tests/input-5.txt                      
 2 | #input, #button {                       #input, #button {                      
 3 |   width: 350px;                           width: 400px;                        
 4 |   height: 40px;                           height: 40px;                        
 5 |                                           font-size: 30px;                     
 6 |   margin: 0px;                            margin: 0;                           
 7 |   padding: 0px;                           padding: 0;                          
 8 |   margin-bottom: 15px;                                                         
 9 |   text-align: center;                     text-align: center;                  
10 | }                                       }                                      
11 | 


--------------------------------------------------------------------------------
/tests/gold-45-sas-h.txt:
--------------------------------------------------------------------------------
 1 | tests/input-4.txt                       tests/input-5.txt                      
 2 | #input, #button {                       #input, #button {                      
 3 |   width: 350px;                           width: 400px;                        
 4 |   height: 40px;                           height: 40px;                        
 5 |                                           font-size: 30px;                     
 6 |   margin: 0px;                            margin: 0;                           
 7 |   padding: 0px;                           padding: 0;                          
 8 |   margin-bottom: 15px;                                                         
 9 |   text-align: center;                     text-align: center;                  
10 | }                                       }                                      
11 | 


--------------------------------------------------------------------------------
/tests/gold-45-sas.txt:
--------------------------------------------------------------------------------
 1 | tests/input-4.txt                       tests/input-5.txt                      
 2 | #input, #button {                       #input, #button {                      
 3 |   width: 350px;                           width: 400px;                        
 4 |   height: 40px;                           height: 40px;                        
 5 |                                           font-size: 30px;                     
 6 |   margin: 0px;                            margin: 0;                           
 7 |   padding: 0px;                           padding: 0;                          
 8 |   margin-bottom: 15px;                                                         
 9 |   text-align: center;                     text-align: center;                  
10 | }                                       }                                      
11 | 


--------------------------------------------------------------------------------
/tests/gold-45.txt:
--------------------------------------------------------------------------------
 1 | tests/input-4.txt                       tests/input-5.txt                      
 2 | #input, #button {                       #input, #button {                      
 3 |   width: 350px;                           width: 400px;                        
 4 |   height: 40px;                           height: 40px;                        
 5 |                                           font-size: 30px;                     
 6 |   margin: 0px;                            margin: 0;                           
 7 |   padding: 0px;                           padding: 0;                          
 8 |   margin-bottom: 15px;                                                         
 9 |   text-align: center;                     text-align: center;                  
10 | }                                       }                                      
11 | 


--------------------------------------------------------------------------------
/tests/gold-4dn.txt:
--------------------------------------------------------------------------------
 1 | left                                    right                                  
 2 | #input, #button {                                                              
 3 |   width: 350px;                                                                
 4 |   height: 40px;                                                                
 5 |   margin: 0px;                                                                 
 6 |   padding: 0px;                                                                
 7 |   margin-bottom: 15px;                                                         
 8 |   text-align: center;                                                          
 9 | }                                                                              
10 | 


--------------------------------------------------------------------------------
/tests/gold-67-ln.txt:
--------------------------------------------------------------------------------
 1 | tests/input-6.txt                       tests/input-7.txt                      
 2 |        8 h                                     8 h                             
 3 |        9 i                                     9 i                             
 4 |       10 j                                    10 j                             
 5 |       11 k                                    11 k                             
 6 |       12 l                                    12 l                             
 7 |                                               13 m                             
 8 |                                               14 m                             
 9 |       13 m                                    15 m                             
10 |       14 n                                    16 n                             
11 |       15 o                                    17 o                             
12 |       16 p                                    18 p                             
13 |       17 q                                    19 q                             
14 | 


--------------------------------------------------------------------------------
/tests/gold-67-u3.txt:
--------------------------------------------------------------------------------
 1 | tests/input-6.txt                       tests/input-7.txt                      
 2 | j                                       j                                      
 3 | k                                       k                                      
 4 | l                                       l                                      
 5 |                                         m                                      
 6 |                                         m                                      
 7 | m                                       m                                      
 8 | n                                       n                                      
 9 | o                                       o                                      
10 | 


--------------------------------------------------------------------------------
/tests/gold-67-wf.txt:
--------------------------------------------------------------------------------
 1 | tests/input-6.txt                       tests/input-7.txt                      
 2 | a                                       a                                      
 3 | b                                       b                                      
 4 | c                                       c                                      
 5 | d                                       d                                      
 6 | e                                       e                                      
 7 | f                                       f                                      
 8 | g                                       g                                      
 9 | h                                       h                                      
10 | i                                       i                                      
11 | j                                       j                                      
12 | k                                       k                                      
13 | l                                       l                                      
14 |                                         m                                      
15 |                                         m                                      
16 | m                                       m                                      
17 | n                                       n                                      
18 | o                                       o                                      
19 | p                                       p                                      
20 | q                                       q                                      
21 | r                                       r                                      
22 | s                                       s                                      
23 | t                                       t                                      
24 | u                                       u                                      
25 | z                                       z                                      
26 | w                                       w                                      
27 | x                                       x                                      
28 | y                                       y                                      
29 | z                                       z                                      
30 | 


--------------------------------------------------------------------------------
/tests/gold-67.txt:
--------------------------------------------------------------------------------
 1 | tests/input-6.txt                       tests/input-7.txt                      
 2 | h                                       h                                      
 3 | i                                       i                                      
 4 | j                                       j                                      
 5 | k                                       k                                      
 6 | l                                       l                                      
 7 |                                         m                                      
 8 |                                         m                                      
 9 | m                                       m                                      
10 | n                                       n                                      
11 | o                                       o                                      
12 | p                                       p                                      
13 | q                                       q                                      
14 | 


--------------------------------------------------------------------------------
/tests/gold-bad-encoding.txt:
--------------------------------------------------------------------------------
1 | error: encoding 'nonexistend_encoding' was not found.
2 | 


--------------------------------------------------------------------------------
/tests/gold-dir.txt:
--------------------------------------------------------------------------------
1 | Only in tests/b: d
2 | Only in tests/b: i
3 | Only in tests/a: j
4 | 


--------------------------------------------------------------------------------
/tests/gold-dn5.txt:
--------------------------------------------------------------------------------
 1 | left                                    right                                  
 2 |                                         #input, #button {                      
 3 |                                           width: 400px;                        
 4 |                                           height: 40px;                        
 5 |                                           font-size: 30px;                     
 6 |                                           margin: 0;                           
 7 |                                           padding: 0;                          
 8 |                                           text-align: center;                  
 9 |                                         }                                      
10 | 


--------------------------------------------------------------------------------
/tests/gold-exclude.txt:
--------------------------------------------------------------------------------
1 | tests/input-4-cr.txt                    tests/input-4-partial-cr.txt           
2 |   width: 350px;                           width: 350px;                        
3 |   height: 40px;                           height: 40px;                        
4 |   margin: 0px;                            margin: 0px;                         
5 |   margin-bottom: 15px;                    margin-bottom: 15px;                 
6 |   text-align: center;\r                   text-align: center;                  
7 | }                                       }                                      
8 | 


--------------------------------------------------------------------------------
/tests/gold-exit-process-sub:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeffkaufman/icdiff/7b3692c79555e981e3cdc6da1fdfabf5e7b0a4ea/tests/gold-exit-process-sub


--------------------------------------------------------------------------------
/tests/gold-file-not-found.txt:
--------------------------------------------------------------------------------
1 | error: file 'nonexistent_file' was not found
2 | 


--------------------------------------------------------------------------------
/tests/gold-hide-cr-if-dos:
--------------------------------------------------------------------------------
 1 | tests/input-4-cr.txt                    tests/input-5-cr.txt                   
 2 | #input, #button {                       #input, #button {                      
 3 |   width: 350px;                           width: 400px;                        
 4 |   height: 40px;                           height: 40px;                        
 5 |                                           font-size: 30px;                     
 6 |   margin: 0px;                            margin: 0;                           
 7 |   padding: 0px;                           padding: 0;                          
 8 |   margin-bottom: 15px;                                                         
 9 |   text-align: center;                     text-align: center;                  
10 | }                                       }                                      
11 | 


--------------------------------------------------------------------------------
/tests/gold-identical-on.txt:
--------------------------------------------------------------------------------
1 | Files tests/input-1.txt and tests/input-1.txt are identical.
2 | 


--------------------------------------------------------------------------------
/tests/gold-no-cr-indent:
--------------------------------------------------------------------------------
1 | tests/input-4-cr.txt                    tests/input-4-partial-cr.txt           
2 |   width: 350px;                           width: 350px;                        
3 |   height: 40px;                           height: 40px;                        
4 |   margin: 0px;                            margin: 0px;                         
5 |   padding: 0px;                           padding: 0px;                        
6 |   margin-bottom: 15px;                    margin-bottom: 15px;                 
7 |   text-align: center;\r                   text-align: center;                  
8 | }                                       }                                      
9 | 


--------------------------------------------------------------------------------
/tests/gold-permissions-diff-binary.txt:
--------------------------------------------------------------------------------
1 | tests/permissions-a                     tests/permissions-b                    
2 | -rw-rw-rw- (100666)                     -rw-rw-r-x (100665)                    
3 | some text                                                                     
4 | 


--------------------------------------------------------------------------------
/tests/gold-permissions-diff-text.txt:
--------------------------------------------------------------------------------
1 | tests/permissions-a                     tests/permissions-b                    
2 | -rw-rw-rw- (100666)                     -rw-rw-r-x (100665)                    
3 | some text                                                                      
4 | 


--------------------------------------------------------------------------------
/tests/gold-permissions-diff.txt:
--------------------------------------------------------------------------------
1 | tests/permissions-a                     tests/permissions-b                    
2 | -rw-rw-rw- (100666)                     -rw-rw-r-x (100665)                    
3 | 


--------------------------------------------------------------------------------
/tests/gold-permissions-same.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeffkaufman/icdiff/7b3692c79555e981e3cdc6da1fdfabf5e7b0a4ea/tests/gold-permissions-same.txt


--------------------------------------------------------------------------------
/tests/gold-recursive-with-exclude.txt:
--------------------------------------------------------------------------------
1 | error: file 'tests/b/1' not valid with encoding 'utf-8': <invalid start byte> at 4461-4462.
2 | Only in tests/b: d
3 | Only in tests/b: i
4 | Only in tests/a: j
5 | 


--------------------------------------------------------------------------------
/tests/gold-recursive-with-exclude2.txt:
--------------------------------------------------------------------------------
1 | error: file 'tests/test-with-exclude/b/1' not valid with encoding 'utf-8': <invalid start byte> at 4461-4462.
2 | tests/test-with-exclude/a/c/f           tests/test-with-exclude/b/c/f          
3 | 2                                       3                                      
4 | Only in tests/test-with-exclude/b/c: g
5 | Only in tests/test-with-exclude/b/c: h
6 | Only in tests/test-with-exclude/b: d
7 | Only in tests/test-with-exclude/b: i
8 | Only in tests/test-with-exclude/a: j
9 | 


--------------------------------------------------------------------------------
/tests/gold-recursive.txt:
--------------------------------------------------------------------------------
1 | error: file 'tests/b/1' not valid with encoding 'utf-8': <invalid start byte> at 4461-4462.
2 | tests/a/c/f                             tests/b/c/f                            
3 | 2                                       3                                      
4 | Only in tests/b/c: g
5 | Only in tests/b/c: h
6 | Only in tests/b: d
7 | Only in tests/b: i
8 | Only in tests/a: j
9 | 


--------------------------------------------------------------------------------
/tests/gold-sas.txt:
--------------------------------------------------------------------------------
 1 | tests/input-10.txt                      tests/input-11.txt                     
 2 | void main ()                            void main ()                           
 3 | {                                       {                                      
 4 |   int x;                                  int x;                               
 5 |   int y;                                  int y;                               
 6 | }                                       }                                      
 7 |                                                                                
 8 |                                         void foo ()                            
 9 |                                         {                                      
10 |                                                                                
11 |                                         }                                      
12 | 


--------------------------------------------------------------------------------
/tests/gold-show-spaces.txt:
--------------------------------------------------------------------------------
 1 | tests/input-10.txt                      tests/input-11.txt                     
 2 | void main ()                            void main ()                           
 3 | {                                       {                                      
 4 |   int x;                                  int x;                               
 5 |   int y;                                  int y;                               
 6 | }                                       }                                      
 7 |                                                                                
 8 |                                         void foo ()                            
 9 |                                         {                                      
10 |                                                                                
11 |                                         }                                      
12 | 


--------------------------------------------------------------------------------
/tests/gold-sns.txt:
--------------------------------------------------------------------------------
 1 | tests/input-10.txt                      tests/input-11.txt                     
 2 | void main ()                            void main ()                           
 3 | {                                       {                                      
 4 |   int x;                                  int x;                               
 5 |   int y;                                  int y;                               
 6 | }                                       }                                      
 7 |                                                                                
 8 |                                         void foo ()                            
 9 |                                         {                                      
10 |                                                                                
11 |                                         }                                      
12 | 


--------------------------------------------------------------------------------
/tests/gold-strip-cr-off.txt:
--------------------------------------------------------------------------------
 1 | tests/input-4.txt                       tests/input-4-cr.txt                   
 2 | #input, #button {                       #input, #button {\r                    
 3 |   width: 350px;                           width: 350px;\r                      
 4 |   height: 40px;                           height: 40px;\r                      
 5 |   margin: 0px;                            margin: 0px;\r                       
 6 |   padding: 0px;                           padding: 0px;\r                      
 7 |   margin-bottom: 15px;                    margin-bottom: 15px;\r               
 8 |   text-align: center;                     text-align: center;\r                
 9 | }                                       }\r                                    
10 | 


--------------------------------------------------------------------------------
/tests/gold-strip-cr-on.txt:
--------------------------------------------------------------------------------
1 | tests/input-4.txt                       tests/input-4-cr.txt                   
2 | 


--------------------------------------------------------------------------------
/tests/gold-subcolors-bad-cat:
--------------------------------------------------------------------------------
1 | Invalid category 'chnge' in '--color-map="chnge:magenta,description:cyan_bold"'.  Valid categories are: add, change, description, line-numbers, meta, permissions, separator, subtract.
2 | 


--------------------------------------------------------------------------------
/tests/gold-subcolors-bad-color:
--------------------------------------------------------------------------------
1 | Invalid color 'mageta' in '--color-map="change:mageta,description:cyan_bold"'.  Valid colors are: black, black_bold, blue, blue_bold, cyan, cyan_bold, green, green_bold, magenta, magenta_bold, none, red, red_bold, white, white_bold, yellow, yellow_bold.
2 | 


--------------------------------------------------------------------------------
/tests/gold-subcolors-bad-fmt:
--------------------------------------------------------------------------------
1 | Invalid color 'magenta:gold' in '--color-map="change:magenta:gold,description:cyan_bold"'.  Valid colors are: black, black_bold, blue, blue_bold, cyan, cyan_bold, green, green_bold, magenta, magenta_bold, none, red, red_bold, white, white_bold, yellow, yellow_bold.
2 | 


--------------------------------------------------------------------------------
/tests/gold-tabs-4.txt:
--------------------------------------------------------------------------------
1 | tests/input-8.txt                       tests/input-9.txt                      
2 |     abc def                                 aQc dQf                            
3 | 


--------------------------------------------------------------------------------
/tests/gold-tabs-default.txt:
--------------------------------------------------------------------------------
1 | tests/input-8.txt                       tests/input-9.txt                      
2 |         abc     def                             aQc     dQf                    
3 | 


--------------------------------------------------------------------------------
/tests/input-1.txt:
--------------------------------------------------------------------------------
1 | 测试行abc测试测试行abc,测试测试行abc测试测试行abc测试测试行abc测试测试行abc测试测试行abc测试测试行abc测试测试行abc测试
2 | 


--------------------------------------------------------------------------------
/tests/input-10.txt:
--------------------------------------------------------------------------------
1 | void main ()
2 | {
3 |   int x;
4 |   int y;
5 | }
6 | 


--------------------------------------------------------------------------------
/tests/input-11.txt:
--------------------------------------------------------------------------------
 1 | void main ()
 2 | {
 3 |   int x;
 4 |   int y;
 5 | }
 6 | 
 7 | void foo ()
 8 | {
 9 | 
10 | }
11 | 


--------------------------------------------------------------------------------
/tests/input-2.txt:
--------------------------------------------------------------------------------
1 | 测试行adc测试测试行adc,测试测试行adc测试测试行adc测试测试行adc测试测试行adc测试测试行adc测试测试行adc测试测试行adc测试
2 | 


--------------------------------------------------------------------------------
/tests/input-3.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeffkaufman/icdiff/7b3692c79555e981e3cdc6da1fdfabf5e7b0a4ea/tests/input-3.txt


--------------------------------------------------------------------------------
/tests/input-4-cr.txt:
--------------------------------------------------------------------------------
1 | #input, #button {
2 |   width: 350px;
3 |   height: 40px;
4 |   margin: 0px;
5 |   padding: 0px;
6 |   margin-bottom: 15px;
7 |   text-align: center;
8 | }
9 | 


--------------------------------------------------------------------------------
/tests/input-4-partial-cr.txt:
--------------------------------------------------------------------------------
1 | #input, #button {
2 |   width: 350px;
3 |   height: 40px;
4 |   margin: 0px;
5 |   padding: 0px;
6 |   margin-bottom: 15px;
7 |   text-align: center;
8 | }
9 | 


--------------------------------------------------------------------------------
/tests/input-4.txt:
--------------------------------------------------------------------------------
1 | #input, #button {
2 |   width: 350px;
3 |   height: 40px;
4 |   margin: 0px;
5 |   padding: 0px;
6 |   margin-bottom: 15px;
7 |   text-align: center;
8 | }
9 | 


--------------------------------------------------------------------------------
/tests/input-5-cr.txt:
--------------------------------------------------------------------------------
1 | #input, #button {
2 |   width: 400px;
3 |   height: 40px;
4 |   font-size: 30px;
5 |   margin: 0;
6 |   padding: 0;
7 |   text-align: center;
8 | }
9 | 


--------------------------------------------------------------------------------
/tests/input-5.txt:
--------------------------------------------------------------------------------
1 | #input, #button {
2 |   width: 400px;
3 |   height: 40px;
4 |   font-size: 30px;
5 |   margin: 0;
6 |   padding: 0;
7 |   text-align: center;
8 | }
9 | 


--------------------------------------------------------------------------------
/tests/input-6.txt:
--------------------------------------------------------------------------------
 1 | a
 2 | b
 3 | c
 4 | d
 5 | e
 6 | f
 7 | g
 8 | h
 9 | i
10 | j
11 | k
12 | l
13 | m
14 | n
15 | o
16 | p
17 | q
18 | r
19 | s
20 | t
21 | u
22 | z
23 | w
24 | x
25 | y
26 | z
27 | 


--------------------------------------------------------------------------------
/tests/input-7.txt:
--------------------------------------------------------------------------------
 1 | a
 2 | b
 3 | c
 4 | d
 5 | e
 6 | f
 7 | g
 8 | h
 9 | i
10 | j
11 | k
12 | l
13 | m
14 | m
15 | m
16 | n
17 | o
18 | p
19 | q
20 | r
21 | s
22 | t
23 | u
24 | z
25 | w
26 | x
27 | y
28 | z
29 | 


--------------------------------------------------------------------------------
/tests/input-8.txt:
--------------------------------------------------------------------------------
1 | 	abc	def
2 | 


--------------------------------------------------------------------------------
/tests/input-9.txt:
--------------------------------------------------------------------------------
1 | 	aQc	dQf
2 | 


--------------------------------------------------------------------------------
/tests/test-with-exclude/a/1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeffkaufman/icdiff/7b3692c79555e981e3cdc6da1fdfabf5e7b0a4ea/tests/test-with-exclude/a/1


--------------------------------------------------------------------------------
/tests/test-with-exclude/a/c/e:
--------------------------------------------------------------------------------
1 | 1
2 | 


--------------------------------------------------------------------------------
/tests/test-with-exclude/a/c/f:
--------------------------------------------------------------------------------
1 | 2
2 | 


--------------------------------------------------------------------------------
/tests/test-with-exclude/a/exclude/text.txt:
--------------------------------------------------------------------------------
1 | excluded a
2 | 


--------------------------------------------------------------------------------
/tests/test-with-exclude/a/j:
--------------------------------------------------------------------------------
1 | 7
2 | 


--------------------------------------------------------------------------------
/tests/test-with-exclude/b/1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeffkaufman/icdiff/7b3692c79555e981e3cdc6da1fdfabf5e7b0a4ea/tests/test-with-exclude/b/1


--------------------------------------------------------------------------------
/tests/test-with-exclude/b/c/e:
--------------------------------------------------------------------------------
1 | 1
2 | 


--------------------------------------------------------------------------------
/tests/test-with-exclude/b/c/f:
--------------------------------------------------------------------------------
1 | 3
2 | 


--------------------------------------------------------------------------------
/tests/test-with-exclude/b/c/g:
--------------------------------------------------------------------------------
1 | 4
2 | 


--------------------------------------------------------------------------------
/tests/test-with-exclude/b/c/h:
--------------------------------------------------------------------------------
1 | 5
2 | 


--------------------------------------------------------------------------------
/tests/test-with-exclude/b/d/q:
--------------------------------------------------------------------------------
1 | 9
2 | 


--------------------------------------------------------------------------------
/tests/test-with-exclude/b/exclude/text.txt:
--------------------------------------------------------------------------------
1 | excluded b
2 | 


--------------------------------------------------------------------------------
/tests/test-with-exclude/b/i:
--------------------------------------------------------------------------------
1 | 6
2 | 


--------------------------------------------------------------------------------