-
-@class UDiffScriptBuilder;
-@class UDiffChange;
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface UDiffFileData : NSObject {
- /** Vector, indexed by line number, containing an equivalence code for
- each line. It is this vector that is actually compared with that
- of another file to generate differences. */
- int* equivs;
-
- int* pequiv_max;
- BOOL* pno_discards;
-}
-
-/** Number of elements (lines) in this file. */
-@property (assign) NSUInteger buffered_lines;
-/** Array, indexed by real origin-1 line number, containing true for a line that is an insertion or a deletion. */
-@property (assign, nullable) BOOL* changed_flag;
-/** Vector, like the previous one except that the elements for discarded lines have been squeezed out. */
-@property (assign) int* undiscarded;
-/** Vector mapping virtual line numbers (not counting discarded lines) to real ones (counting those lines). Both are origin-0. */
-@property (assign) int* realindexes;
-/** Total number of nondiscarded lines. */
-@property (assign) int nondiscarded_lines;
-
-+ (instancetype)fileData:(NSArray*)data h:(NSMutableDictionary*)h equivMax:(int*)ppequiv_max noDiscards:(BOOL*)ppnoDiscards
- stringifier:(NSString* (^)(id obj))block;
-- (instancetype)initWithData:(NSArray*)data h:(NSMutableDictionary*)h equivMax:(int*)ppequiv_max noDiscards:(BOOL*)ppnoDiscards
- stringifier:(NSString* (^)(id obj))block;
-
-@end
-
-@interface UnifiedDiff : NSObject {
-@private
- /** 1 more than the maximum equivalence value used for this or its
- sibling file. */
- int equiv_max;
-
- /** When set to true, the comparison uses a heuristic to speed it up.
- With this heuristic, for files with a constant small density
- of changes, the algorithm is linear in the file size. */
- BOOL heuristic;
-
- /** When set to true, the algorithm returns a guarranteed minimal
- set of changes. This makes things slower, sometimes much slower. */
- BOOL no_discards;
-
- int* xvec, *yvec; /* Vectors being compared. */
- int* fdiag; /* Vector, indexed by diagonal, containing
- the X coordinate of the point furthest
- along the given diagonal in the forward
- search of the edit matrix. */
- int* bdiag; /* Vector, indexed by diagonal, containing
- the X coordinate of the point furthest
- along the given diagonal in the backward
- search of the edit matrix. */
- int fdiagoff, bdiagoff;
- int cost;
-
- BOOL inhibit;
-}
-
-- (instancetype)initWithOriginalLines:(NSArray*)a revisedLines:(NSArray*)b stringifier:(NSString* (^)(id obj))block;
-- (nullable UDiffChange*)diff_2:(BOOL)reverse;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/Sources/Legacy/DiffEngine/UnifiedDiff.m b/Sources/Legacy/DiffEngine/UnifiedDiff.m
deleted file mode 100644
index 38ba620..0000000
--- a/Sources/Legacy/DiffEngine/UnifiedDiff.m
+++ /dev/null
@@ -1,739 +0,0 @@
-//
-// UnifiedDiff.m
-// VisualDiffer
-//
-// Created by davide ficano on 23/05/12.
-// Copyright (c) 2012 visualdiffer.com
-//
-
-#import "UnifiedDiff.h"
-#import "UDiffScriptBuilder.h"
-
-/** Snakes bigger than this are considered "big". */
-static const NSInteger SNAKE_LIMIT = 20;
-
-static UDiffScriptBuilder* forwardScript;
-static UDiffScriptBuilder* reverseScript;
-
-@interface UDiffFileData()
-- (char*)discardable:(int*)counts NS_RETURNS_INNER_POINTER;
-- (void)filterDiscards:(char*)discards;
-- (void)discard:(char*)discards;
-@end
-
-@interface UnifiedDiff()
-- (UDiffChange*)diff:(UDiffScriptBuilder*)bld;
-@end
-
-@implementation UDiffFileData
-
-+ (instancetype)fileData:(NSArray*)data h:(NSMutableDictionary*)h equivMax:(int*)ppequiv_max noDiscards:(BOOL*)ppno_discards
- stringifier:(NSString* (^)(id obj))block {
- return [[self alloc] initWithData:data h:h equivMax:ppequiv_max noDiscards:ppno_discards stringifier:block];
-}
-
-- (instancetype)initWithData:(NSArray*)data h:(NSMutableDictionary*)h equivMax:(int*)ppequiv_max noDiscards:(BOOL*)ppno_discards
- stringifier:(NSString* (^)(id obj))block {
- self = [super init];
-
- if (self) {
- pequiv_max = ppequiv_max;
- pno_discards = ppno_discards;
- _buffered_lines = data.count;
-
- equivs = calloc(_buffered_lines, sizeof(int));
- _undiscarded = calloc(_buffered_lines, sizeof(int));
- _realindexes = calloc(_buffered_lines, sizeof(int));
- _changed_flag = NULL;
-
- int i = 0;
- for (id o in data) {
- NSString* str = block(o);
- NSNumber* ir = h[str];
- if (ir == nil) {
- h[str] = @(equivs[i] = *pequiv_max);
- (*pequiv_max)++;
- } else {
- equivs[i] = [ir intValue];
- }
- ++i;
- }
- }
-
- return self;
-}
-
-- (void)dealloc {
- free(equivs);
- free(_undiscarded);
- free(_realindexes);
- free(_changed_flag);
-
-}
-
-/** Allocate changed array for the results of comparison. */
-- (void)clear {
- /* Allocate a flag for each line of each file, saying whether that line
- is an insertion or deletion.
- Allocate an extra element, always zero, at each end of each vector.
- */
- _changed_flag = calloc(_buffered_lines + 2, sizeof(BOOL));
-}
-
-/** Return equiv_count[I] as the number of lines in this file
- that fall in equivalence class I.
- @return the array of equivalence class counts.
- */
-- (int*)equivCount {
- int equiv_max = *pequiv_max;
- int* equiv_count = calloc(equiv_max, sizeof(int));
- for (int i = 0; i < (NSInteger)_buffered_lines; ++i)
- ++equiv_count[equivs[i]];
- return equiv_count;
-}
-
-/** Discard lines that have no matches in another file.
-
- A line which is discarded will not be considered by the actual
- comparison algorithm; it will be as if that line were not in the file.
- The file's `realindexes' table maps virtual line numbers
- (which don't count the discarded lines) into real line numbers;
- this is how the actual comparison algorithm produces results
- that are comprehensible when the discarded lines are counted.
-
- When we discard a line, we also mark it as a deletion or insertion
- so that it will be printed in the output.
- @param f the other file
- */
-- (void)discard_confusing_lines:(UDiffFileData*)f {
- [self clear];
- /* Set up table of which lines are going to be discarded. */
- int* tempEquivCount = [f equivCount];
- char* discarded = [self discardable:tempEquivCount];
-
- /* Don't really discard the provisional lines except when they occur
- in a run of discardables, with nonprovisionals at the beginning
- and end. */
- [self filterDiscards:discarded];
-
- /* Actually discard the lines. */
- [self discard:discarded];
-
- free(discarded);
- free(tempEquivCount);
-}
-
-/** Mark to be discarded each line that matches no line of another file.
- If a line matches many lines, mark it as provisionally discardable.
- @see equivCount()
- @param counts The count of each equivalence number for the other file.
- @return 0=nondiscardable, 1=discardable or 2=provisionally discardable
- for each line
- */
-
-- (char*)discardable:(int*)counts {
- NSInteger end = (NSInteger)_buffered_lines;
- char* discards = calloc(end, sizeof(char));
- int many = 5;
- NSUInteger tem = end / 64;
-
- /* Multiply MANY by approximate square root of number of lines.
- That is the threshold for provisionally discardable lines. */
- while ((tem = tem >> 2) > 0)
- many *= 2;
-
- for (int i = 0; i < end; i++)
- {
- int nmatch;
- if (equivs[i] == 0)
- continue;
- nmatch = counts[equivs[i]];
- if (nmatch == 0)
- discards[i] = 1;
- else if (nmatch > many)
- discards[i] = 2;
- }
- return discards;
-}
-
-/** Don't really discard the provisional lines except when they occur
- in a run of discardables, with nonprovisionals at the beginning
- and end. */
-
-- (void)filterDiscards:(char*)discards {
- NSInteger end = (NSInteger)_buffered_lines;
-
- for (int i = 0; i < end; i++)
- {
- /* Cancel provisional discards not in middle of run of discards. */
- if (discards[i] == 2)
- discards[i] = 0;
- else if (discards[i] != 0)
- {
- /* We have found a nonprovisional discard. */
- int j;
- int length;
- int provisional = 0;
-
- /* Find end of this run of discardable lines.
- Count how many are provisionally discardable. */
- for (j = i; j < end; j++)
- {
- if (discards[j] == 0)
- break;
- if (discards[j] == 2)
- ++provisional;
- }
-
- /* Cancel provisional discards at end, and shrink the run. */
- while (j > i && discards[j - 1] == 2) {
- discards[--j] = 0; --provisional;
- }
-
- /* Now we have the length of a run of discardable lines
- whose first and last are not provisional. */
- length = j - i;
-
- /* If 1/4 of the lines in the run are provisional,
- cancel discarding of all provisional lines in the run. */
- if (provisional * 4 > length)
- {
- while (j > i)
- if (discards[--j] == 2)
- discards[j] = 0;
- }
- else
- {
- int consec;
- int minimum = 1;
- int tem = length / 4;
-
- /* MINIMUM is approximate square root of LENGTH/4.
- A subrun of two or more provisionals can stand
- when LENGTH is at least 16.
- A subrun of 4 or more can stand when LENGTH >= 64. */
- while ((tem = tem >> 2) > 0)
- minimum *= 2;
- minimum++;
-
- /* Cancel any subrun of MINIMUM or more provisionals
- within the larger run. */
- for (j = 0, consec = 0; j < length; j++)
- if (discards[i + j] != 2)
- consec = 0;
- else if (minimum == ++consec)
- /* Back up to start of subrun, to cancel it all. */
- j -= consec;
- else if (minimum < consec)
- discards[i + j] = 0;
-
- /* Scan from beginning of run
- until we find 3 or more nonprovisionals in a row
- or until the first nonprovisional at least 8 lines in.
- Until that point, cancel any provisionals. */
- for (j = 0, consec = 0; j < length; j++)
- {
- if (j >= 8 && discards[i + j] == 1)
- break;
- if (discards[i + j] == 2) {
- consec = 0; discards[i + j] = 0;
- }
- else if (discards[i + j] == 0)
- consec = 0;
- else
- consec++;
- if (consec == 3)
- break;
- }
-
- /* I advances to the last line of the run. */
- i += length - 1;
-
- /* Same thing, from end. */
- for (j = 0, consec = 0; j < length; j++)
- {
- if (j >= 8 && discards[i - j] == 1)
- break;
- if (discards[i - j] == 2) {
- consec = 0; discards[i - j] = 0;
- }
- else if (discards[i - j] == 0)
- consec = 0;
- else
- consec++;
- if (consec == 3)
- break;
- }
- }
- }
- }
-}
-
-/** Actually discard the lines.
- @param discards flags lines to be discarded
- */
-- (void)discard:(char*)discards {
- NSInteger end = (NSInteger)_buffered_lines;
- int j = 0;
- for (int i = 0; i < end; ++i)
- if (*pno_discards || discards[i] == 0)
- {
- _undiscarded[j] = equivs[i];
- _realindexes[j++] = i;
- }
- else
- _changed_flag[1+i] = true;
- _nondiscarded_lines = j;
-}
-
-/** Adjust inserts/deletes of blank lines to join changes
- as much as possible.
-
- We do something when a run of changed lines include a blank
- line at one end and have an excluded blank line at the other.
- We are free to choose which blank line is included.
- `compareseq' always chooses the one at the beginning,
- but usually it is cleaner to consider the following blank line
- to be the "change". The only exception is if the preceding blank line
- would join this change to other changes.
- @param f the file being compared against
- */
-
-- (void)shift_boundaries:(UDiffFileData*)f {
- BOOL* changed = _changed_flag;
- BOOL* other_changed = f.changed_flag;
- int i = 0;
- int j = 0;
- NSInteger i_end = (NSInteger)_buffered_lines;
- int preceding = -1;
- int other_preceding = -1;
-
- for (;;)
- {
- int start, end, other_start;
-
- /* Scan forwards to find beginning of another run of changes.
- Also keep track of the corresponding point in the other file. */
-
- while (i < i_end && !changed[1+i])
- {
- while (other_changed[1+j++])
- /* Non-corresponding lines in the other file
- will count as the preceding batch of changes. */
- other_preceding = j;
- i++;
- }
-
- if (i == i_end)
- break;
-
- start = i;
- other_start = j;
-
- for (;;)
- {
- /* Now find the end of this run of changes. */
-
- while (i < i_end && changed[1+i]) i++;
- end = i;
-
- /* If the first changed line matches the following unchanged one,
- and this run does not follow right after a previous run,
- and there are no lines deleted from the other file here,
- then classify the first changed line as unchanged
- and the following line as changed in its place. */
-
- /* You might ask, how could this run follow right after another?
- Only because the previous run was shifted here. */
-
- if (end != i_end
- && equivs[start] == equivs[end]
- && !other_changed[1+j]
- && end != i_end
- && !((preceding >= 0 && start == preceding)
- || (other_preceding >= 0
- && other_start == other_preceding)))
- {
- changed[1+end++] = true;
- changed[1+start++] = false;
- ++i;
- /* Since one line-that-matches is now before this run
- instead of after, we must advance in the other file
- to keep in synch. */
- ++j;
- }
- else
- break;
- }
-
- preceding = i;
- other_preceding = j;
- }
-}
-@end
-
-#pragma mark -
-#pragma mark UnifiedDiff methods
-
-@interface UnifiedDiff()
-@property (strong) UDiffFileData* filevec0;
-@property (strong) UDiffFileData* filevec1;
-@end
-
-@implementation UnifiedDiff
-
-/** Prepare to find differences between two arrays. Each element of
- the arrays is translated to an "equivalence number" based on
- the result of equals. The original Object arrays
- are no longer needed for computing the differences. They will
- be needed again later to print the results of the comparison as
- an edit script, if desired.
- */
-- (instancetype)initWithOriginalLines:(NSArray*)a revisedLines:(NSArray*)b stringifier:(NSString* (^)(id obj))block {
- static dispatch_once_t pred;
- dispatch_once(&pred, ^{
- forwardScript = [[UDiffForwardScript alloc] init];
- reverseScript = [[UDiffReverseScript alloc] init];
- });
- self = [super init];
-
- if (self) {
- equiv_max = 1;
- heuristic = NO;
- no_discards = NO;
- inhibit = NO;
- NSMutableDictionary* h = [NSMutableDictionary dictionaryWithCapacity:a.count + b.count];
- _filevec0 = [UDiffFileData fileData:a h:h equivMax:&equiv_max noDiscards:&no_discards stringifier:block];
- _filevec1 = [UDiffFileData fileData:b h:h equivMax:&equiv_max noDiscards:&no_discards stringifier:block];
- }
-
- return self;
-}
-
-/** Find the midpoint of the shortest edit script for a specified
- portion of the two files.
-
- We scan from the beginnings of the files, and simultaneously from the ends,
- doing a breadth-first search through the space of edit-sequence.
- When the two searches meet, we have found the midpoint of the shortest
- edit sequence.
-
- The value returned is the number of the diagonal on which the midpoint lies.
- The diagonal number equals the number of inserted lines minus the number
- of deleted lines (counting only lines before the midpoint).
- The edit cost is stored into COST; this is the total number of
- lines inserted or deleted (counting only lines before the midpoint).
-
- This function assumes that the first lines of the specified portions
- of the two files do not match, and likewise that the last lines do not
- match. The caller must trim matching lines from the beginning and end
- of the portions it is going to specify.
-
- Note that if we return the "wrong" diagonal value, or if
- the value of bdiag at that diagonal is "wrong",
- the worst this can do is cause suboptimal diff output.
- It cannot cause incorrect diff output. */
-
-- (int)diag:(int)xoff xlim:(int)xlim yoff:(int)yoff ylim:(int)ylim {
- int* fd = fdiag; // Give the compiler a chance.
- int* bd = bdiag; // Additional help for the compiler.
- int* xv = xvec; // Still more help for the compiler.
- int* yv = yvec; // And more and more . . .
- int dmin = xoff - ylim; // Minimum valid diagonal.
- int dmax = xlim - yoff; // Maximum valid diagonal.
- int fmid = xoff - yoff; // Center diagonal of top-down search.
- int bmid = xlim - ylim; // Center diagonal of bottom-up search.
- int fmin = fmid, fmax = fmid; // Limits of top-down search.
- int bmin = bmid, bmax = bmid; // Limits of bottom-up search.
- /* True if southeast corner is on an odd
- diagonal with respect to the northwest. */
- BOOL odd = (fmid - bmid & 1) != 0;
-
- fd[fdiagoff + fmid] = xoff;
- bd[bdiagoff + bmid] = xlim;
-
- for (int c = 1;; ++c)
- {
- int d; /* Active diagonal. */
- BOOL big_snake = NO;
-
- /* Extend the top-down search by an edit step in each diagonal. */
- if (fmin > dmin)
- fd[fdiagoff + --fmin - 1] = -1;
- else
- ++fmin;
- if (fmax < dmax)
- fd[fdiagoff + ++fmax + 1] = -1;
- else
- --fmax;
- for (d = fmax; d >= fmin; d -= 2)
- {
- int x, y, oldx, tlo = fd[fdiagoff + d - 1], thi = fd[fdiagoff + d + 1];
-
- if (tlo >= thi)
- x = tlo + 1;
- else
- x = thi;
- oldx = x;
- y = x - d;
- while (x < xlim && y < ylim && xv[x] == yv[y]) {
- ++x; ++y;
- }
- if (x - oldx > SNAKE_LIMIT)
- big_snake = true;
- fd[fdiagoff + d] = x;
- if (odd && bmin <= d && d <= bmax && bd[bdiagoff + d] <= fd[fdiagoff + d])
- {
- cost = 2 * c - 1;
- return d;
- }
- }
-
- /* Similar extend the bottom-up search. */
- if (bmin > dmin)
- bd[bdiagoff + --bmin - 1] = INT_MAX;
- else
- ++bmin;
- if (bmax < dmax)
- bd[bdiagoff + ++bmax + 1] = INT_MAX;
- else
- --bmax;
- for (d = bmax; d >= bmin; d -= 2)
- {
- int x, y, oldx, tlo = bd[bdiagoff + d - 1], thi = bd[bdiagoff + d + 1];
-
- if (tlo < thi)
- x = tlo;
- else
- x = thi - 1;
- oldx = x;
- y = x - d;
- while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1]) {
- --x; --y;
- }
- if (oldx - x > SNAKE_LIMIT)
- big_snake = true;
- bd[bdiagoff + d] = x;
- if (!odd && fmin <= d && d <= fmax && bd[bdiagoff + d] <= fd[fdiagoff + d])
- {
- cost = 2 * c;
- return d;
- }
- }
-
- /* Heuristic: check occasionally for a diagonal that has made
- lots of progress compared with the edit distance.
- If we have any such, find the one that has made the most
- progress and return it as if it had succeeded.
-
- With this heuristic, for files with a constant small density
- of changes, the algorithm is linear in the file size. */
-
- if (c > 200 && big_snake && heuristic)
- {
- int best = 0;
- int bestpos = -1;
-
- for (d = fmax; d >= fmin; d -= 2)
- {
- int dd = d - fmid;
- int x = fd[fdiagoff + d];
- int y = x - d;
- int v = (x - xoff) * 2 - dd;
- if (v > 12 * (c + (dd < 0 ? -dd : dd)))
- {
- if (v > best
- && xoff + SNAKE_LIMIT <= x && x < xlim
- && yoff + SNAKE_LIMIT <= y && y < ylim)
- {
- /* We have a good enough best diagonal;
- now insist that it end with a significant snake. */
- int k;
-
- for (k = 1; xvec[x - k] == yvec[y - k]; k++)
- if (k == SNAKE_LIMIT)
- {
- best = v;
- bestpos = d;
- break;
- }
- }
- }
- }
- if (best > 0)
- {
- cost = 2 * c - 1;
- return bestpos;
- }
-
- best = 0;
- for (d = bmax; d >= bmin; d -= 2)
- {
- int dd = d - bmid;
- int x = bd[bdiagoff + d];
- int y = x - d;
- int v = (xlim - x) * 2 + dd;
- if (v > 12 * (c + (dd < 0 ? -dd : dd)))
- {
- if (v > best
- && xoff < x && x <= xlim - SNAKE_LIMIT
- && yoff < y && y <= ylim - SNAKE_LIMIT)
- {
- /* We have a good enough best diagonal;
- now insist that it end with a significant snake. */
- int k;
-
- for (k = 0; xvec[x + k] == yvec[y + k]; k++)
- if (k == SNAKE_LIMIT)
- {
- best = v;
- bestpos = d;
- break;
- }
- }
- }
- }
- if (best > 0)
- {
- cost = 2 * c - 1;
- return bestpos;
- }
- }
- }
-}
-
-/** Compare in detail contiguous subsequences of the two files
- which are known, as a whole, to match each other.
-
- The results are recorded in the vectors filevec[N].changed_flag, by
- storing a 1 in the element for each line that is an insertion or deletion.
-
- The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1.
-
- Note that XLIM, YLIM are exclusive bounds.
- All line numbers are origin-0 and discarded lines are not counted. */
-
-- (void)compareseq:(int)xoff xlim:(int)xlim yoff:(int)yoff ylim:(int)ylim {
- /* Slide down the bottom initial diagonal. */
- while (xoff < xlim && yoff < ylim && xvec[xoff] == yvec[yoff]) {
- ++xoff; ++yoff;
- }
- /* Slide up the top initial diagonal. */
- while (xlim > xoff && ylim > yoff && xvec[xlim - 1] == yvec[ylim - 1]) {
- --xlim; --ylim;
- }
-
- /* Handle simple cases. */
- if (xoff == xlim)
- while (yoff < ylim)
- self.filevec1.changed_flag[1 + self.filevec1.realindexes[yoff++]] = YES;
- else if (yoff == ylim)
- while (xoff < xlim)
- self.filevec0.changed_flag[1 + self.filevec0.realindexes[xoff++]] = YES;
- else
- {
- /* Find a point of correspondence in the middle of the files. */
-
- int d = [self diag:xoff xlim:xlim yoff:yoff ylim:ylim];
- int c = cost;
-// int f = fdiag[fdiagoff + d];
- int b = bdiag[bdiagoff + d];
-
- if (c == 1)
- {
- /* This should be impossible, because it implies that
- one of the two subsequences is empty,
- and that case was handled above without calling `diag'.
- Let's verify that this is true. */
-// /throw new IllegalArgumentException("Empty subsequence");
- }
- else
- {
- /* Use that point to split this problem into two subproblems. */
- [self compareseq:xoff xlim:b yoff:yoff ylim:b - d];
- /* This used to use f instead of b,
- but that is incorrect!
- It is not necessarily the case that diagonal d
- has a snake from b to f. */
- [self compareseq:b xlim:xlim yoff:b - d ylim:ylim];
- }
- }
-}
-
-/** Discard lines from one file that have no matches in the other file.
- */
-
-- (void)discard_confusing_lines {
- [self.filevec0 discard_confusing_lines:self.filevec1];
- [self.filevec1 discard_confusing_lines:self.filevec0];
-}
-
-/** Adjust inserts/deletes of blank lines to join changes
- as much as possible.
- */
-
-- (void)shift_boundaries {
- if (inhibit)
- return;
- [self.filevec0 shift_boundaries:self.filevec1];
- [self.filevec1 shift_boundaries:self.filevec0];
-}
-
-/* Report the differences of two files. */
-- (UDiffChange*)diff_2:(BOOL)reverse {
- return [self diff:reverse ? reverseScript : forwardScript];
-}
-
-/** Get the results of comparison as an edit script. The script
- is described by a list of changes. The standard ScriptBuilder
- implementations provide for forward and reverse edit scripts.
- Alternate implementations could, for instance, list common elements
- instead of differences.
- @param bld an object to build the script from change flags
- @return the head of a list of changes
- */
-- (UDiffChange*)diff:(UDiffScriptBuilder*)bld {
-
- /* Some lines are obviously insertions or deletions
- because they don't match anything. Detect them now,
- and avoid even thinking about them in the main comparison algorithm. */
-
- [self discard_confusing_lines];
-
- /* Now do the main comparison algorithm, considering just the
- undiscarded lines. */
-
- xvec = self.filevec0.undiscarded;
- yvec = self.filevec1.undiscarded;
-
- int diags = self.filevec0.nondiscarded_lines + self.filevec1.nondiscarded_lines + 3;
- fdiag = calloc(diags, sizeof(int));
- fdiagoff = self.filevec1.nondiscarded_lines + 1;
- bdiag = calloc(diags, sizeof(int));
- bdiagoff = self.filevec1.nondiscarded_lines + 1;
-
- [self compareseq:0
- xlim:self.filevec0.nondiscarded_lines
- yoff:0
- ylim:self.filevec1.nondiscarded_lines];
- fdiag = nil;
- bdiag = nil;
-
- /* Modify the results slightly to make them prettier
- in cases where that can validly be done. */
-
- [self shift_boundaries];
-
- /* Get the results of comparison in the form of a chain
- of struct change's -- an edit script. */
- return [bld build_script:self.filevec0.changed_flag
- len0:self.filevec0.buffered_lines
- changed1:self.filevec1.changed_flag
- len1:self.filevec1.buffered_lines];
-}
-
-/** Data on one input file being compared.
- */
-
-
-@end
diff --git a/Sources/SharedKit/Extensions/CoreData/NSManagedObjectContext+Helpers.swift b/Sources/SharedKit/Extensions/CoreData/NSManagedObjectContext+Helpers.swift
deleted file mode 100644
index 3147db5..0000000
--- a/Sources/SharedKit/Extensions/CoreData/NSManagedObjectContext+Helpers.swift
+++ /dev/null
@@ -1,24 +0,0 @@
-//
-// NSManagedObjectContext+Helpers.swift
-// VisualDiffer
-//
-// Created by davide ficano on 10/10/15.
-// Copyright (c) 2015 visualdiffer.com
-//
-
-extension NSManagedObjectContext {
- ///
- /// Wrap the block around disable/enable undo registration pair
- ///
- /// Parameters:
- /// - block: the code to execute with registration disabled
- @MainActor
- func updateWithoutRecordingModifications(_ block: () -> Void) {
- undoManager?.disableUndoRegistration()
-
- block()
-
- processPendingChanges()
- undoManager?.enableUndoRegistration()
- }
-}
diff --git a/Sources/SharedKit/Extensions/String/String+Highlights.swift b/Sources/SharedKit/Extensions/String/String+Highlights.swift
index cfabb45..304e487 100644
--- a/Sources/SharedKit/Extensions/String/String+Highlights.swift
+++ b/Sources/SharedKit/Extensions/String/String+Highlights.swift
@@ -58,4 +58,26 @@ extension String {
highlightStyle: hightlightStyle
)
}
+
+ // the offsets must be ascending and non overlapping, the string is walked once,
+ // the offsets starting past the end are dropped and the others are clamped
+ func characterRanges(from offsets: [Range]) -> [Range] {
+ let length = count
+ var ranges = [Range]()
+ var start = startIndex
+ var startOffset = 0
+
+ for offsetRange in offsets where offsetRange.lowerBound < length {
+ let clampedUpper = min(offsetRange.upperBound, length)
+ let lower = index(start, offsetBy: offsetRange.lowerBound - startOffset)
+ let upper = index(lower, offsetBy: clampedUpper - offsetRange.lowerBound)
+
+ ranges.append(lower ..< upper)
+
+ start = upper
+ startOffset = clampedUpper
+ }
+
+ return ranges
+ }
}
diff --git a/Sources/SharedKit/Extensions/String/String+RegularExpression.swift b/Sources/SharedKit/Extensions/String/String+RegularExpression.swift
index be93ee1..a110a68 100644
--- a/Sources/SharedKit/Extensions/String/String+RegularExpression.swift
+++ b/Sources/SharedKit/Extensions/String/String+RegularExpression.swift
@@ -8,53 +8,6 @@
import Foundation
-private struct GlobConverter {
- private var regex = [NSRegularExpression]()
- private var templates = [String]()
-
- init() {
- let globs = [
- ("([.^$+(){}\\[\\]\\\\|])", "\\\\$1"),
- ("\\?", "(.|[\r\n])"),
- ("\\*", "(.|[\r\n])*"),
- ]
-
- for (regexString, templateString) in globs {
- do {
- let re = try NSRegularExpression(
- pattern: regexString,
- options: .caseInsensitive
- )
- regex.append(re)
- templates.append(templateString)
- } catch {
- preconditionFailure("invalid static regex pattern '\(regexString)': \(error)")
- }
- }
- }
-
- private func replace(index: Int, in str: String) -> String {
- let re = regex[index]
- let template = templates[index]
-
- return re.stringByReplacingMatches(
- in: str,
- options: [],
- range: NSRange(location: 0, length: str.utf16.count),
- withTemplate: template
- )
- }
-
- func convert(_ str: String) -> String {
- var re = str
-
- for i in 0 ..< regex.count {
- re = replace(index: i, in: re)
- }
- return re
- }
-}
-
public extension String {
/**
* Replace tagged expressions ($1, $2, ...) present in template
@@ -124,21 +77,4 @@ public extension String {
}
return inString
}
-
- /**
- * Convert a glob string to a valid regular expression string
- * Strings like "*m" are converted to ".*m"
- * Brackets and "?" are correctly escaped
- */
- private func _convertGlobMetaCharsToRegexpMetaChars() -> String {
- enum Static {
- static let converter: GlobConverter = .init()
- }
-
- return Static.converter.convert(self)
- }
-
- func convertGlobMetaCharsToRegexpMetaChars() -> String {
- _convertGlobMetaCharsToRegexpMetaChars()
- }
}
diff --git a/Sources/SharedKit/Extensions/Workspace/NSWorkspace+Finder.swift b/Sources/SharedKit/Extensions/Workspace/NSWorkspace+Finder.swift
index 9c84644..7c72a1b 100644
--- a/Sources/SharedKit/Extensions/Workspace/NSWorkspace+Finder.swift
+++ b/Sources/SharedKit/Extensions/Workspace/NSWorkspace+Finder.swift
@@ -6,7 +6,6 @@
// Copyright (c) 2014 visualdiffer.com
//
-let suppressShowInFinder = "suppressShowInFinder"
let maxFoldersToShowWithoutAlert = 8
extension NSWorkspace {
@@ -21,7 +20,7 @@ extension NSWorkspace {
let confirmOpen = NSAlert.showModalConfirm(
messageText: String(format: NSLocalizedString("Are you sure you want to open %lu Finder windows?", comment: ""), paths.count),
informativeText: NSLocalizedString("You have chosen to open a large number of windows. This can take a long time", comment: ""),
- suppressPropertyName: suppressShowInFinder,
+ suppressPropertyName: CommonPrefs.Name.confirmShowInFinder.rawValue,
yesText: nil,
noText: nil
)
diff --git a/Sources/SharedKit/Utilities/Image/IconUtils.swift b/Sources/SharedKit/Utilities/Image/IconUtils.swift
index 1e3c843..5629ada 100644
--- a/Sources/SharedKit/Utilities/Image/IconUtils.swift
+++ b/Sources/SharedKit/Utilities/Image/IconUtils.swift
@@ -15,8 +15,15 @@ import UniformTypeIdentifiers
public class IconUtils: @unchecked Sendable {
static let shared = IconUtils()
+ // the cached image is resized to the requested size, so the size belongs to the key,
+ // otherwise the first caller decides the size for every other one
+ private struct IconKey: Hashable {
+ let name: String
+ let size: CGFloat
+ }
+
private let lock = NSLock()
- private var icons = [String: NSImage]()
+ private var icons = [IconKey: NSImage]()
private init() {}
@@ -60,13 +67,9 @@ public class IconUtils: @unchecked Sendable {
}
public func icon(forEmptyPath size: CGFloat) -> NSImage {
- guard let icon = NSImage(systemSymbolName: "square.dashed", accessibilityDescription: "Empty Path") else {
- fatalError("Unable to create empty path icon")
+ cachedIcon(for: VDSymbol.Asset.emptyPath.rawValue, size: size) {
+ VDSymbol.Asset.emptyPath.image()
}
-
- icon.size = NSSize(width: size, height: size)
-
- return icon
}
private func iconNamed(_ name: String, size: CGFloat) -> NSImage {
@@ -87,7 +90,9 @@ public class IconUtils: @unchecked Sendable {
lock.lock()
defer { lock.unlock() }
- if let icon = icons[name] {
+ let key = IconKey(name: name, size: size)
+
+ if let icon = icons[key] {
return icon
}
@@ -102,7 +107,7 @@ public class IconUtils: @unchecked Sendable {
}
icon.size = NSSize(width: size, height: size)
- icons[name] = icon
+ icons[key] = icon
return icon
}
diff --git a/Sources/SharedKit/Utilities/String/DisplayLine.swift b/Sources/SharedKit/Utilities/String/DisplayLine.swift
new file mode 100644
index 0000000..97a3ebf
--- /dev/null
+++ b/Sources/SharedKit/Utilities/String/DisplayLine.swift
@@ -0,0 +1,29 @@
+//
+// DisplayLine.swift
+// VisualDiffer
+//
+// Created by davide ficano on 12/08/26.
+// Copyright (c) 2026 visualdiffer.com
+//
+
+/// text of a line as it gets drawn, together with the mapping needed to translate
+/// the character offsets of the source text into offsets of the drawn text
+///
+/// Tab expansion changes the length of a line, so an offset in the source text does
+/// not match the same offset in the drawn one. Everything else is replaced one
+/// character at a time, therefore a line without tabs needs no mapping at all.
+struct DisplayLine {
+ let text: String
+
+ // one entry per source character, plus the past the end offset,
+ // empty when the drawn text matches the source text character by character
+ let offsets: [Int]
+
+ func displayOffset(for sourceOffset: Int) -> Int {
+ if offsets.isEmpty {
+ return sourceOffset
+ }
+
+ return sourceOffset < offsets.count ? offsets[sourceOffset] : text.count
+ }
+}
diff --git a/Sources/SharedKit/Utilities/String/VisibleWhitespaces.swift b/Sources/SharedKit/Utilities/String/VisibleWhitespaces.swift
index 983d20f..e036c23 100644
--- a/Sources/SharedKit/Utilities/String/VisibleWhitespaces.swift
+++ b/Sources/SharedKit/Utilities/String/VisibleWhitespaces.swift
@@ -19,49 +19,73 @@ class VisibleWhitespaces: NSObject {
return String(ch)
}
- func getString(_ component: DiffLineComponent, isWhitespacesVisible: Bool) -> String {
+ func getString(_ component: DiffLineComponent, isWhitespacesVisible: Bool) -> DisplayLine {
if isWhitespacesVisible {
return showWhitespaces(component.text + component.eol.visibleSymbol)
}
return Self.tabs2space(component.text, tabWidth: tabWidth)
}
- static func tabs2space(_ line: String, tabWidth: Int) -> String {
- guard tabWidth > 0 else {
- return line
+ static func tabs2space(_ line: String, tabWidth: Int) -> DisplayLine {
+ guard tabWidth > 0, line.contains("\t") else {
+ return DisplayLine(text: line, offsets: [])
}
var dest = ""
+ var destCount = 0
+ var offsets = [Int]()
+
+ offsets.reserveCapacity(line.count + 1)
for ch in line {
+ offsets.append(destCount)
+
if ch == "\t" {
- let spaces = tabWidth - (dest.count % tabWidth)
+ let spaces = tabWidth - (destCount % tabWidth)
dest += String(repeating: " ", count: spaces)
+ destCount += spaces
} else {
dest.append(ch)
+ destCount += 1
}
}
- return dest
+ offsets.append(destCount)
+
+ return DisplayLine(text: dest, offsets: offsets)
}
- func showWhitespaces(_ line: String) -> String {
+ func showWhitespaces(_ line: String) -> DisplayLine {
guard tabWidth > 0 else {
- return line
+ return DisplayLine(text: line, offsets: [])
}
let whitespaces = CharacterSet.whitespaces
+ // every character but a tab is replaced one by one, so the mapping is needed
+ // only when the line contains a tab
+ let needsOffsets = line.contains("\t")
var dest = ""
+ var destCount = 0
+ var offsets = [Int]()
+
+ if needsOffsets {
+ offsets.reserveCapacity(line.count + 1)
+ }
for ch in line {
+ if needsOffsets {
+ offsets.append(destCount)
+ }
+
guard let scalar = ch.unicodeScalars.first,
whitespaces.contains(scalar) else {
dest.append(ch)
+ destCount += 1
continue
}
if ch == "\t" {
// subtract from spaces the character representing TAB
- let spaces = (tabWidth - (dest.count % tabWidth)) - 1
+ let spaces = (tabWidth - (destCount % tabWidth)) - 1
if spaces > 0 {
let leftSpaces = spaces / 2
let rightSpaces = spaces - leftSpaces
@@ -73,13 +97,21 @@ class VisibleWhitespaces: NSObject {
if rightSpaces > 0 {
dest += String(repeating: " ", count: rightSpaces)
}
+ destCount += spaces + 1
} else {
dest += Self.visibleTab
+ destCount += 1
}
} else {
dest += getVisibleCharFor(ch)
+ destCount += 1
}
}
- return dest
+
+ if needsOffsets {
+ offsets.append(destCount)
+ }
+
+ return DisplayLine(text: dest, offsets: offsets)
}
}
diff --git a/Sources/SharedKit/Utilities/TextField/RSVerticallyCenteredTextFieldCell.swift b/Sources/SharedKit/Utilities/TextField/RSVerticallyCenteredTextFieldCell.swift
deleted file mode 100644
index eec11dc..0000000
--- a/Sources/SharedKit/Utilities/TextField/RSVerticallyCenteredTextFieldCell.swift
+++ /dev/null
@@ -1,35 +0,0 @@
-//
-// RSVerticallyCenteredTextFieldCell.swift
-// VisualDiffer
-//
-// Created by Daniel Jalkut on 6/17/06.
-// Copyright 2006 Red Sweater Software. All rights reserved.
-//
-
-class RSVerticallyCenteredTextFieldCell: NSTextFieldCell {
- private var isEditingOrSelecting = false
-
- override func drawingRect(forBounds rect: NSRect) -> NSRect {
- // Get the parent's idea of where we should draw
- var newRect = super.drawingRect(forBounds: rect)
-
- // When the text field is being
- // edited or selected, we have to turn off the magic because it screws up
- // the configuration of the field editor. We sneak around this by
- // intercepting selectWithFrame and editWithFrame and sneaking a
- // reduced, centered rect in at the last minute.
- if !isEditingOrSelecting {
- // Get our ideal size for current text
- let textSize = cellSize(forBounds: rect)
-
- // Center that in the proposed rect
- let heightDelta = newRect.size.height - textSize.height
- if heightDelta > 0 {
- newRect.size.height -= heightDelta
- newRect.origin.y += (heightDelta / 2)
- }
- }
-
- return newRect
- }
-}
diff --git a/Sources/SharedKit/Utilities/View/ActionBar/ActionBarView.swift b/Sources/SharedKit/Utilities/View/ActionBar/ActionBarView.swift
index cb9c0d7..1ee7dd7 100644
--- a/Sources/SharedKit/Utilities/View/ActionBar/ActionBarView.swift
+++ b/Sources/SharedKit/Utilities/View/ActionBar/ActionBarView.swift
@@ -48,7 +48,6 @@ class ActionBarView: NSStackView {
secondButton.widthAnchor.constraint(equalToConstant: 24),
secondButton.heightAnchor.constraint(equalToConstant: 24),
- popup.widthAnchor.constraint(equalToConstant: 32),
popup.heightAnchor.constraint(equalToConstant: 24),
])
}
diff --git a/Sources/SharedKit/Utilities/View/Console/ConsoleView.swift b/Sources/SharedKit/Utilities/View/Console/ConsoleView.swift
index e04e6bc..bebc8ee 100644
--- a/Sources/SharedKit/Utilities/View/Console/ConsoleView.swift
+++ b/Sources/SharedKit/Utilities/View/Console/ConsoleView.swift
@@ -6,12 +6,13 @@
// Copyright (c) 2012 visualdiffer.com
//
+@MainActor
protocol ConsoleViewDelegate: AnyObject {
func hide(console: ConsoleView)
}
class ConsoleView: NSView, NSTextViewDelegate {
- var delegate: ConsoleViewDelegate?
+ weak var delegate: ConsoleViewDelegate?
private lazy var dateFormatter: DateFormatter = {
let dateFormatter = DateFormatter()
@@ -74,9 +75,9 @@ class ConsoleView: NSView, NSTextViewDelegate {
setupViews()
}
- @available(*, unavailable)
- required init(coder _: NSCoder) {
- fatalError("init(coder:) has not been implemented")
+ @available(*, unavailable, message: "use init(frame:)")
+ required init?(coder _: NSCoder) {
+ nil
}
private func setupViews() {
diff --git a/Sources/SharedKit/Utilities/View/DualPane/DualPaneSplitView.swift b/Sources/SharedKit/Utilities/View/DualPane/DualPaneSplitView.swift
index 37da868..42b2c82 100644
--- a/Sources/SharedKit/Utilities/View/DualPane/DualPaneSplitView.swift
+++ b/Sources/SharedKit/Utilities/View/DualPane/DualPaneSplitView.swift
@@ -6,29 +6,40 @@
// Copyright (c) 2025 visualdiffer.com
//
+// size used until the user resizes the collapsable pane
+private let defaultCollapsablePaneSize: CGFloat = 120
+
+private let userResizeKey = "NSSplitViewUserResizeKey"
+
class DualPaneSplitView: NSSplitView {
- var isSubviewCollapsed = false
+ var collapsablePaneSize: CGFloat = defaultCollapsablePaneSize
+
+ // the paired split view is not retained, the view hierarchy keeps it alive
+ private weak var synchronizedSplitView: DualPaneSplitView?
+
+ // the collapsed state is owned by the app through isHidden because
+ // NSSplitView.isSubviewCollapsed(_:) reports true also for a pane not laid out yet
+ var hasSubviewCollapsed: Bool {
+ subviews.isEmpty || subviews.contains { $0.isHidden }
+ }
- @objc var firstViewSize: CGFloat = 0
+ // the collapsable pane is the one the delegate allows to collapse
+ private var collapsablePaneIndex: Int? {
+ subviews.firstIndex { delegate?.splitView?(self, canCollapseSubview: $0) == true }
+ }
+
+ override var dividerThickness: CGFloat {
+ hasSubviewCollapsed ? 0.0 : super.dividerThickness
+ }
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
- NotificationCenter.default.addObserver(
- self,
- selector: #selector(subviewResized),
- name: NSSplitView.didResizeSubviewsNotification,
- object: self
- )
+ observeUserResize()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
- NotificationCenter.default.addObserver(
- self,
- selector: #selector(subviewResized),
- name: NSSplitView.didResizeSubviewsNotification,
- object: self
- )
+ observeUserResize()
}
deinit {
@@ -41,80 +52,113 @@ class DualPaneSplitView: NSSplitView {
@objc
func subviewResized(_ notification: Notification) {
- if hasSubviewCollapsed {
- return
- }
- guard let num = notification.userInfo?["NSSplitViewUserResizeKey"] as? NSNumber else {
+ // only a manual drag defines the size to remember; on a window
+ // resize NSSplitView scales the panes proportionally and that size is not a user choice
+ guard let userResize = notification.userInfo?[userResizeKey] as? NSNumber,
+ userResize.boolValue,
+ !hasSubviewCollapsed,
+ let index = collapsablePaneIndex else {
return
}
- let isUserResize = num.boolValue
- if isUserResize {
- let view = subviews[0]
- firstViewSize = isVertical ? view.frame.width : view.frame.height
+ let currentSize = paneSize(of: subviews[index])
+ if currentSize > 0 {
+ collapsablePaneSize = currentSize
+ synchronizedSplitView?.matchCollapsablePaneSize(currentSize)
}
}
- @objc var hasSubviewCollapsed: Bool {
- if subviews.isEmpty {
- return true
- }
- for view in subviews where isSubviewCollapsed(view) {
- return true
- }
- return false
+ /**
+ Pair the split view with another one so they collapse, expand and resize together
+ self is paired with other and other is paired with self, too
+ */
+ func setSynchronized(splitView: DualPaneSplitView) {
+ synchronizedSplitView = splitView
+ splitView.synchronizedSplitView = self
}
- @objc
- func toggleSubview(at index: Int) {
+ func toggleSubview() {
if hasSubviewCollapsed {
- expandSubview(at: index)
+ expandSubview()
} else {
- collapseSubview(at: index)
+ collapseSubview()
}
}
- @objc
- func collapseSubview(at index: Int) {
- if hasSubviewCollapsed {
+ func collapseSubview() {
+ guard let index = collapsablePaneIndex else {
return
}
- if index == 0 {
- let collapseView = subviews[0]
- collapseView.isHidden = true
- setPosition(0, ofDividerAt: 0)
- } else if index == 1 {
- let expandView = subviews[0]
- let collapseView = subviews[1]
- collapseView.isHidden = true
- let position = isVertical ? expandView.frame.width : expandView.frame.height
- setPosition(position, ofDividerAt: 0)
- } else {
+
+ let collapseView = subviews[index]
+
+ // returning when already collapsed also stops the pair from calling back
+ if collapseView.isHidden {
return
}
+ collapseView.isHidden = true
adjustSubviews()
+ // force a layout pass so AppKit removes the collapsed divider layer
+ needsLayout = true
+ synchronizedSplitView?.collapseSubview()
}
- @objc
- func expandSubview(at index: Int) {
- if !hasSubviewCollapsed {
+ func expandSubview() {
+ guard let index = collapsablePaneIndex else {
return
}
- if index == 0 {
- let collapseView = subviews[0]
- collapseView.isHidden = false
- setPosition(firstViewSize, ofDividerAt: 0)
- } else if index == 1 {
- let collapseView = subviews[1]
- collapseView.isHidden = false
- setPosition(firstViewSize, ofDividerAt: 0)
- } else {
+
+ let expandView = subviews[index]
+
+ // returning when already expanded also stops the pair from calling back
+ if !expandView.isHidden {
return
}
+ expandView.isHidden = false
+ moveDivider(collapsableIndex: index)
+ synchronizedSplitView?.expandSubview()
+ }
+
+ // applies the size the paired split view got from the user, the comparison
+ // stops the pair from bouncing the change back
+ private func matchCollapsablePaneSize(_ size: CGFloat) {
+ guard !hasSubviewCollapsed,
+ let index = collapsablePaneIndex,
+ paneSize(of: subviews[index]) != size else {
+ return
+ }
+
+ collapsablePaneSize = size
+ moveDivider(collapsableIndex: index)
+ }
+
+ // the position is derived from the current size and kept inside the
+ // range allowed by the delegate, otherwise NSSplitView collapses the pane again
+ private func moveDivider(collapsableIndex index: Int) {
+ let available = paneSize(of: self)
+ let position = index == 0 ? collapsablePaneSize : available - collapsablePaneSize - dividerThickness
+
+ setPosition(constrain(position: position, available: available), ofDividerAt: 0)
adjustSubviews()
}
- override var dividerThickness: CGFloat {
- hasSubviewCollapsed ? 0.0 : super.dividerThickness
+ private func observeUserResize() {
+ NotificationCenter.default.addObserver(
+ self,
+ selector: #selector(subviewResized),
+ name: NSSplitView.didResizeSubviewsNotification,
+ object: self
+ )
+ }
+
+ private func paneSize(of view: NSView) -> CGFloat {
+ isVertical ? view.frame.width : view.frame.height
+ }
+
+ private func constrain(position: CGFloat, available: CGFloat) -> CGFloat {
+ let minPosition = delegate?.splitView?(self, constrainMinCoordinate: 0, ofSubviewAt: 0) ?? 0
+ let maxPosition = delegate?.splitView?(self, constrainMaxCoordinate: available, ofSubviewAt: 0) ?? available
+
+ return min(max(position, minPosition), maxPosition)
}
}
diff --git a/Sources/SharedKit/Utilities/View/DualPane/DualPaneSplitViewDelegate.swift b/Sources/SharedKit/Utilities/View/DualPane/DualPaneSplitViewDelegate.swift
index e7172ca..a885c27 100644
--- a/Sources/SharedKit/Utilities/View/DualPane/DualPaneSplitViewDelegate.swift
+++ b/Sources/SharedKit/Utilities/View/DualPane/DualPaneSplitViewDelegate.swift
@@ -7,21 +7,21 @@
//
class DualPaneSplitViewDelegate: NSObject, NSSplitViewDelegate {
- var minSize: CGFloat = 0
- var maxSize: CGFloat = 0
+ var minFirstPaneSize: CGFloat = 0
+ var minSecondPaneSize: CGFloat = 0
var collapsableSubviewIndex = 0
@objc
init(
collapsableSubViewIndex index: Int,
- minSize: CGFloat,
- maxSize: CGFloat
+ minFirstPaneSize: CGFloat,
+ minSecondPaneSize: CGFloat
) {
super.init()
collapsableSubviewIndex = index
- self.minSize = minSize
- self.maxSize = maxSize
+ self.minFirstPaneSize = minFirstPaneSize
+ self.minSecondPaneSize = minSecondPaneSize
}
func splitView(_: NSSplitView, shouldHideDividerAt _: Int) -> Bool {
@@ -29,11 +29,11 @@ class DualPaneSplitViewDelegate: NSObject, NSSplitViewDelegate {
}
func splitView(_: NSSplitView, constrainMinCoordinate proposedMinimumPosition: CGFloat, ofSubviewAt _: Int) -> CGFloat {
- proposedMinimumPosition + minSize
+ proposedMinimumPosition + minFirstPaneSize
}
func splitView(_: NSSplitView, constrainMaxCoordinate proposedMaximumPosition: CGFloat, ofSubviewAt _: Int) -> CGFloat {
- proposedMaximumPosition - maxSize
+ proposedMaximumPosition - minSecondPaneSize
}
func splitView(_ splitView: NSSplitView, canCollapseSubview subview: NSView) -> Bool {
diff --git a/Sources/SharedKit/Utilities/View/Encoding/SelectEncodingsPanel.swift b/Sources/SharedKit/Utilities/View/Encoding/SelectEncodingsPanel.swift
index c61ae55..65468e7 100644
--- a/Sources/SharedKit/Utilities/View/Encoding/SelectEncodingsPanel.swift
+++ b/Sources/SharedKit/Utilities/View/Encoding/SelectEncodingsPanel.swift
@@ -7,25 +7,7 @@
//
class SelectEncodingsPanel: NSWindow, NSTableViewDataSource, NSTableViewDelegate {
- private lazy var titleText: NSTextField = {
- let view = NSTextField(frame: .zero)
-
- view.isEditable = false
- view.isBordered = false
- view.drawsBackground = false
- view.translatesAutoresizingMaskIntoConstraints = false
-
- let cell = TextFieldVerticalCentered()
- cell.lineBreakMode = .byClipping
- cell.title = NSLocalizedString("Select encodings to show on the main list", comment: "")
-
- view.cell = cell
-
- // set the font after the cell otherwise it is lost
- view.font = NSFont.systemFont(ofSize: NSFont.smallSystemFontSize)
-
- return view
- }()
+ private let titleText = NSTextField.hintWithTitle(NSLocalizedString("Select encodings to show on the main list", comment: ""))
private lazy var scrollView: NSScrollView = {
let view = NSScrollView(frame: .zero)
diff --git a/Sources/SharedKit/Utilities/View/ProgressBar/ProgressBarView.swift b/Sources/SharedKit/Utilities/View/ProgressBar/ProgressBarView.swift
index 577ed82..3d554ec 100644
--- a/Sources/SharedKit/Utilities/View/ProgressBar/ProgressBarView.swift
+++ b/Sources/SharedKit/Utilities/View/ProgressBar/ProgressBarView.swift
@@ -7,6 +7,9 @@
//
class ProgressBarView: NSView {
+ private static let stopButtonWidth: CGFloat = 16
+ private static let stopButtonSpacing: CGFloat = 4
+
private lazy var progressIndicator: NSProgressIndicator = {
let view = NSProgressIndicator(frame: .zero)
@@ -51,16 +54,32 @@ class ProgressBarView: NSView {
view.imagePosition = .imageOnly
view.imageScaling = .scaleProportionallyDown
view.keyEquivalent = KeyEquivalent.escape
+ view.isHidden = true
return view
}()
+ private lazy var stopButtonWidthConstraint = stopButton.widthAnchor.constraint(
+ equalToConstant: 0
+ )
+
+ private lazy var stopButtonSpacingConstraint = progressIndicator.leadingAnchor.constraint(
+ equalTo: stopButton.trailingAnchor,
+ constant: 0
+ )
+
var waitStopMessage = ""
+ // a comparison that cannot be interrupted never sets a stop action, the button would
+ // be inert there so it takes no room either
+ private var isStopButtonHidden: Bool {
+ stopButton.target == nil
+ }
+
override var isHidden: Bool {
didSet {
if !isHidden {
- stopButton.isEnabled = true
+ stopButton.isEnabled = !isStopButtonHidden
messageText.stringValue = ""
setProgress(position: 0, maxValue: 1)
}
@@ -73,9 +92,9 @@ class ProgressBarView: NSView {
setupViews()
}
- @available(*, unavailable)
- required init(coder _: NSCoder) {
- fatalError("init(coder:) has not been implemented")
+ @available(*, unavailable, message: "use init(frame:)")
+ required init?(coder _: NSCoder) {
+ nil
}
func setupViews() {
@@ -91,9 +110,9 @@ class ProgressBarView: NSView {
stopButton.leadingAnchor.constraint(equalTo: leadingAnchor),
stopButton.topAnchor.constraint(equalTo: topAnchor),
stopButton.bottomAnchor.constraint(equalTo: bottomAnchor),
- stopButton.widthAnchor.constraint(equalToConstant: 16),
+ stopButtonWidthConstraint,
- progressIndicator.leadingAnchor.constraint(equalTo: stopButton.trailingAnchor, constant: 4),
+ stopButtonSpacingConstraint,
progressIndicator.topAnchor.constraint(equalTo: topAnchor),
progressIndicator.bottomAnchor.constraint(equalTo: bottomAnchor),
progressIndicator.widthAnchor.constraint(equalToConstant: 250),
@@ -114,8 +133,9 @@ class ProgressBarView: NSView {
}
func setProgress(position: Double, maxValue: Double) {
- progressIndicator.doubleValue = position
+ // the range must be set before the value or it clamps the value
progressIndicator.maxValue = maxValue
+ progressIndicator.doubleValue = position
}
func advanceProgress() {
@@ -130,5 +150,20 @@ class ProgressBarView: NSView {
func setStop(action: Selector, target: AnyObject) {
stopButton.target = target
stopButton.action = action
+
+ stopButton.isHidden = false
+ stopButtonWidthConstraint.constant = Self.stopButtonWidth
+ stopButtonSpacingConstraint.constant = Self.stopButtonSpacing
+ }
+
+ // for the callers that are about to block the main thread, the next display cycle
+ // happens only once that work is over
+ func displayMessage(_ text: String) {
+ updateMessage(text)
+
+ // a window that is not on screen draws into a surface nobody sees
+ if window?.isVisible == true {
+ displayIfNeeded()
+ }
}
}
diff --git a/Sources/SharedKit/Utilities/Window/WindowCancelOperation.swift b/Sources/SharedKit/Utilities/Window/WindowCancelOperation.swift
index 6a3dba5..7f3bc49 100644
--- a/Sources/SharedKit/Utilities/Window/WindowCancelOperation.swift
+++ b/Sources/SharedKit/Utilities/Window/WindowCancelOperation.swift
@@ -7,6 +7,12 @@
//
class WindowCancelOperation: NSWindow {
+ private static let maxContentSize = NSSize(width: 1100, height: 600)
+ private static let minWindowSize = NSSize(width: 480, height: 400)
+ private static let minContentSize = NSSize(width: 300, height: 200)
+ // a window opened for the first time never covers more than this fraction of the visible screen
+ private static let maxScreenFillRatio = 0.75
+
override func cancelOperation(_ sender: Any?) {
// override NSWindow.cancelOperation() instead of NSWindowController.cancelOperation()
// because on NSWindowController the standard beep is played
@@ -34,7 +40,7 @@ class WindowCancelOperation: NSWindow {
let styleMask: NSWindow.StyleMask = [.titled, .closable, .miniaturizable, .resizable]
let window = WindowCancelOperation(
- contentRect: NSRect(x: 500, y: 600, width: 1100, height: 600),
+ contentRect: NSRect(origin: .zero, size: defaultContentSize()),
styleMask: styleMask,
backing: .buffered,
defer: false
@@ -44,10 +50,25 @@ class WindowCancelOperation: NSWindow {
window.allowsToolTipsWhenApplicationIsInactive = true
window.autorecalculatesKeyViewLoop = false
window.setIsVisible(false)
- window.minSize = NSSize(width: 480, height: 400)
- window.contentMinSize = NSSize(width: 300, height: 200)
+ window.minSize = minWindowSize
+ window.contentMinSize = minContentSize
window.contentView?.autoresizingMask = [.width, .height]
+ // a fixed origin lands on a different screen spot depending on the screen size,
+ // center() keeps the window above the visual center as the fixed origin used to do
+ window.center()
+
return window
}
+
+ private static func defaultContentSize() -> NSSize {
+ guard let visibleFrame = NSScreen.main?.visibleFrame else {
+ return maxContentSize
+ }
+
+ return NSSize(
+ width: min(maxContentSize.width, visibleFrame.width * maxScreenFillRatio),
+ height: min(maxContentSize.height, visibleFrame.height * maxScreenFillRatio)
+ )
+ }
}
diff --git a/Sources/SharedUI/Components/ComparisonActivityDisplayable.swift b/Sources/SharedUI/Components/ComparisonActivityDisplayable.swift
new file mode 100644
index 0000000..3386cdd
--- /dev/null
+++ b/Sources/SharedUI/Components/ComparisonActivityDisplayable.swift
@@ -0,0 +1,42 @@
+//
+// ComparisonActivityDisplayable.swift
+// VisualDiffer
+//
+// Created by davide ficano on 08/09/26.
+// Copyright (c) 2026 visualdiffer.com
+//
+
+// the status bar and the controls a running comparison takes over, shared by the file
+// and the folder window so the two cannot drift apart again
+@MainActor
+protocol ComparisonActivityDisplayable: AnyObject {
+ var differenceCounters: DifferenceCounters { get }
+ var statusbarText: NSTextField { get }
+ var progressView: ProgressBarView { get }
+ var window: NSWindow? { get }
+
+ var lockedScopeBar: ScopeBarView { get }
+ var lockedPathViews: [PathView] { get }
+}
+
+extension ComparisonActivityDisplayable {
+ // the progress replaces the counters and the status text while a comparison runs
+ func setProgressHidden(_ hidden: Bool) {
+ differenceCounters.isHidden = !hidden
+ statusbarText.isHidden = !hidden
+ progressView.isHidden = hidden
+ }
+
+ func setComparisonRunning(_ running: Bool) {
+ setProgressHidden(!running)
+
+ for pathView in lockedPathViews {
+ pathView.isEnabled = !running
+ }
+ lockedScopeBar.setEnabledAllGroups(!running)
+
+ // the toolbar is the only always visible validated control, it would otherwise
+ // keep the items it draws until AppKit decides to validate again
+ window?.toolbar?.validateVisibleItems()
+ }
+}
diff --git a/Sources/SharedUI/Components/ConsoleDisplayable.swift b/Sources/SharedUI/Components/ConsoleDisplayable.swift
new file mode 100644
index 0000000..7126a7a
--- /dev/null
+++ b/Sources/SharedUI/Components/ConsoleDisplayable.swift
@@ -0,0 +1,78 @@
+//
+// ConsoleDisplayable.swift
+// VisualDiffer
+//
+// Created by davide ficano on 11/09/26.
+// Copyright (c) 2026 visualdiffer.com
+//
+
+// the console pane is laid out by the splitter, so its frame is still the seed one when the
+// constraints are first evaluated and it must already clear the height its own content needs,
+// or that first pass is unsatisfiable and causes AppKit to log a conflict
+private let consoleSeedHeight: CGFloat = 120.0
+
+// the log console pane, shared by the file and the folder window so the two cannot drift apart
+@MainActor
+protocol ConsoleDisplayable: ConsoleViewDelegate {
+ var consoleView: ConsoleView { get }
+ var consoleSplitter: DualPaneSplitView { get }
+ var consoleDelegate: DualPaneSplitViewDelegate { get }
+ var window: NSWindow? { get }
+
+ // the console takes the focus when it opens, hiding it hands the focus back to this view
+ var consoleFocusView: NSView { get }
+}
+
+extension ConsoleDisplayable {
+ func createConsoleView() -> ConsoleView {
+ let view = ConsoleView(frame: NSRect(x: 0, y: 0, width: 1, height: consoleSeedHeight))
+ view.delegate = self
+
+ return view
+ }
+
+ func createConsoleSplitter() -> DualPaneSplitView {
+ let view = DualPaneSplitView(frame: .zero)
+ view.translatesAutoresizingMaskIntoConstraints = false
+
+ return view
+ }
+
+ func setupConsoleSplitter() {
+ consoleSplitter.delegate = consoleDelegate
+ consoleSplitter.collapseSubview()
+ }
+
+ // MARK: - Delegate
+
+ func hide(console _: ConsoleView) {
+ if consoleSplitter.hasSubviewCollapsed {
+ showConsoleView()
+ } else {
+ hideConsoleView()
+ }
+ }
+
+ // MARK: - ConsoleSplitView
+
+ func log(error: String) {
+ showConsoleView()
+ consoleView.log(error: error)
+ }
+
+ func logComparisonCompleted(elapsedTimeText: String) {
+ consoleView.log(info: String(format: NSLocalizedString("Comparison completed in %@", comment: ""), elapsedTimeText))
+ }
+
+ func showConsoleView() {
+ consoleSplitter.expandSubview()
+ consoleView.focus()
+ }
+
+ func hideConsoleView() {
+ consoleSplitter.collapseSubview()
+ // focus lost on console hide, AppKit leaves the first responder on the
+ // hidden text view and the window moves it to the toolbar
+ window?.makeFirstResponder(consoleFocusView)
+ }
+}
diff --git a/Sources/SharedUI/Components/FindOptions.swift b/Sources/SharedUI/Components/FindOptions.swift
new file mode 100644
index 0000000..be634b3
--- /dev/null
+++ b/Sources/SharedUI/Components/FindOptions.swift
@@ -0,0 +1,73 @@
+//
+// FindOptions.swift
+// VisualDiffer
+//
+// Created by davide ficano on 22/08/26.
+// Copyright (c) 2026 visualdiffer.com
+//
+
+enum FindMode: Int, CaseIterable {
+ case containingText = 1
+ case matchingWord
+ case regularExpression
+
+ var title: String {
+ switch self {
+ case .containingText:
+ NSLocalizedString("Containing Text", comment: "")
+ case .matchingWord:
+ NSLocalizedString("Matching Word", comment: "")
+ case .regularExpression:
+ NSLocalizedString("Regular Expression", comment: "")
+ }
+ }
+}
+
+struct FindOptions {
+ var mode = FindMode.containingText
+ var matchCase = false
+ var matchFiles = true
+ var matchFolders = true
+
+ // nil when the pattern is not a valid regular expression
+ func matcher(for pattern: String) -> ((String) -> Bool)? {
+ if mode == .containingText {
+ // the string search also matches canonically equivalent forms, e.g. composed and decomposed accents
+ let compareOptions: String.CompareOptions = matchCase ? [] : .caseInsensitive
+
+ return { $0.range(of: pattern, options: compareOptions) != nil }
+ }
+
+ // the regular expression compares code units, both sides are precomposed
+ // so that a decomposed file name matches a composed pattern
+ guard let re = regex(for: pattern.precomposedStringWithCanonicalMapping) else {
+ return nil
+ }
+
+ return { text in
+ let text = text.precomposedStringWithCanonicalMapping
+
+ return re.firstMatch(
+ in: text,
+ options: [],
+ range: NSRange(location: 0, length: text.utf16.count)
+ ) != nil
+ }
+ }
+
+ private func regex(for pattern: String) -> NSRegularExpression? {
+ let expression = switch mode {
+ case .matchingWord:
+ // \b matches the word boundaries around the searched text
+ "\\b\(NSRegularExpression.escapedPattern(for: pattern))\\b"
+ // .containingText is matched without a regular expression, it never reaches here
+ case .containingText, .regularExpression:
+ pattern
+ }
+
+ return try? NSRegularExpression(
+ pattern: expression,
+ options: matchCase ? [] : .caseInsensitive
+ )
+ }
+}
diff --git a/Sources/SharedUI/Components/FindText.swift b/Sources/SharedUI/Components/FindText.swift
index 9cd6bf1..00792ea 100644
--- a/Sources/SharedUI/Components/FindText.swift
+++ b/Sources/SharedUI/Components/FindText.swift
@@ -11,15 +11,25 @@ protocol FindTextDelegate: AnyObject {
func find(findText: FindText, moveToMatchIndex index: Int) -> Bool
func numberOfMatches(in findText: FindText) -> Int
func clearMatches(in findText: FindText)
+ func selectAllMatches(in findText: FindText, side: DisplaySide)
}
-class FindText: NSView, NSSearchFieldDelegate {
+class FindText: NSView, NSSearchFieldDelegate, NSMenuItemValidation {
private static let viewHeight: CGFloat = 25
private var lastIndexFound = -1
var delegate: FindTextDelegate?
+ // files and folders can be matched separately only when searching a folders comparison
+ var showsFileFilters = false {
+ didSet {
+ updateSearchMenu()
+ }
+ }
+
+ private(set) var findOptions = FindOptions()
+
private lazy var rewindView: WindowOSD = .init(
image: VDSymbol.Asset.rewind.image(),
parent: window
@@ -87,6 +97,48 @@ class FindText: NSView, NSSearchFieldDelegate {
return view
}()
+ private lazy var matchCaseItem = menuItem(
+ NSLocalizedString("Match Case", comment: ""),
+ action: #selector(toggleMatchCase)
+ )
+
+ private lazy var matchFilesItem = menuItem(
+ NSLocalizedString("Match Files", comment: ""),
+ action: #selector(toggleMatchFiles)
+ )
+
+ private lazy var matchFoldersItem = menuItem(
+ NSLocalizedString("Match Folders", comment: ""),
+ action: #selector(toggleMatchFolders)
+ )
+
+ private lazy var modeItems: [NSMenuItem] = FindMode.allCases.map { mode in
+ let item = NSMenuItem(
+ title: mode.title,
+ action: #selector(selectFindMode),
+ keyEquivalent: ""
+ )
+
+ item.target = self
+ // the tag is the only way to know the clicked mode because the menu shown
+ // by the search field is a copy of this template
+ item.tag = mode.rawValue
+
+ return item
+ }
+
+ private lazy var searchMenu: NSMenu = {
+ let menu = NSMenu()
+
+ modeItems.forEach { menu.addItem($0) }
+ menu.addItem(.separator())
+ menu.addItem(matchCaseItem)
+ menu.addItem(matchFilesItem)
+ menu.addItem(matchFoldersItem)
+
+ return menu
+ }()
+
var placeholder: String {
get { searchField.placeholderString ?? "" }
set { searchField.placeholderString = newValue }
@@ -108,6 +160,8 @@ class FindText: NSView, NSSearchFieldDelegate {
addSubview(arrows)
addSubview(countLabel)
+ updateSearchMenu()
+
setupConstraints()
}
@@ -174,6 +228,8 @@ class FindText: NSView, NSSearchFieldDelegate {
if delegate.find(findText: self, searchPattern: pattern) {
moveToMatch(true)
+ } else {
+ updateCount()
}
}
@@ -246,4 +302,72 @@ class FindText: NSView, NSSearchFieldDelegate {
// doesn't expose searchField field but allow to set first responder
searchField.becomeFirstResponder()
}
+
+ @objc
+ private func toggleMatchCase(_: AnyObject) {
+ findOptions.matchCase.toggle()
+ optionsChanged()
+ }
+
+ @objc
+ private func toggleMatchFiles(_: AnyObject) {
+ findOptions.matchFiles.toggle()
+ optionsChanged()
+ }
+
+ @objc
+ private func toggleMatchFolders(_: AnyObject) {
+ findOptions.matchFolders.toggle()
+ optionsChanged()
+ }
+
+ @objc
+ private func selectFindMode(_ sender: NSMenuItem) {
+ guard let mode = FindMode(rawValue: sender.tag),
+ mode != findOptions.mode else {
+ return
+ }
+
+ findOptions.mode = mode
+ optionsChanged()
+ }
+
+ private func optionsChanged() {
+ // the matches found with the previous options are no longer valid
+ search(self)
+ }
+
+ private func updateSearchMenu() {
+ matchFilesItem.isHidden = !showsFileFilters
+ matchFoldersItem.isHidden = !showsFileFilters
+
+ // the template is copied when it is assigned, so it must be assigned again to show the changes
+ searchField.searchMenuTemplate = searchMenu
+ }
+
+ // the shown items are copies of the template ones, their state is set while the menu is validated
+ func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
+ if menuItem.action == #selector(toggleMatchCase) {
+ menuItem.state = findOptions.matchCase ? .on : .off
+ } else if menuItem.action == #selector(selectFindMode) {
+ menuItem.state = menuItem.tag == findOptions.mode.rawValue ? .on : .off
+ } else if menuItem.action == #selector(toggleMatchFiles) {
+ menuItem.state = findOptions.matchFiles ? .on : .off
+ // the last checked file type cannot be turned off, nothing could be found anymore
+ return findOptions.matchFolders || !findOptions.matchFiles
+ } else if menuItem.action == #selector(toggleMatchFolders) {
+ menuItem.state = findOptions.matchFolders ? .on : .off
+ return findOptions.matchFiles || !findOptions.matchFolders
+ }
+
+ return true
+ }
+
+ private func menuItem(_ title: String, action: Selector) -> NSMenuItem {
+ let item = NSMenuItem(title: title, action: action, keyEquivalent: "")
+
+ item.target = self
+
+ return item
+ }
}
diff --git a/Sources/SharedUI/Components/NSTextField+CenterVertically.swift b/Sources/SharedUI/Components/NSTextField+CenterVertically.swift
deleted file mode 100644
index 5615207..0000000
--- a/Sources/SharedUI/Components/NSTextField+CenterVertically.swift
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// NSTextField+CenterVertically.swift
-// VisualDiffer
-//
-// Created by davide ficano on 24/03/25.
-// Copyright (c) 2025 visualdiffer.com
-//
-
-extension NSTextField {
- func centerVertically() {
- let centeredCell = RSVerticallyCenteredTextFieldCell(textCell: "")
-
- centeredCell.controlSize = .small
- centeredCell.isScrollable = true
- centeredCell.lineBreakMode = .byClipping
- centeredCell.alignment = .center
-
- cell = centeredCell
- }
-}
diff --git a/Sources/SharedUI/Components/PathControl.swift b/Sources/SharedUI/Components/PathControl.swift
index 8febe83..ae32edf 100644
--- a/Sources/SharedUI/Components/PathControl.swift
+++ b/Sources/SharedUI/Components/PathControl.swift
@@ -24,6 +24,10 @@ protocol PathControlDelegate: NSPathControlDelegate {
@objc
@MainActor
optional func saveFile(_ sender: AnyObject?)
+
+ @objc
+ @MainActor
+ optional func pathControlCanChoosePath(_ pathControl: PathControl) -> Bool
}
public class PathControl: NSPathControl, NSMenuItemValidation {
@@ -183,6 +187,10 @@ public class PathControl: NSPathControl, NSMenuItemValidation {
return
}
+ if delegate.pathControlCanChoosePath?(self) == false {
+ return
+ }
+
let openPanel = NSOpenPanel()
openPanel.directoryURL = safePathComponentItem?.url ?? url
diff --git a/Sources/SharedUI/Components/PathView.swift b/Sources/SharedUI/Components/PathView.swift
index 4e19e5f..552f9c7 100644
--- a/Sources/SharedUI/Components/PathView.swift
+++ b/Sources/SharedUI/Components/PathView.swift
@@ -10,7 +10,10 @@ class PathView: NSView {
var isEnabled = false {
didSet {
for view in stackView.views {
- if let control = view as? NSControl {
+ // the save button is driven by its .enabled binding to isDirty, forcing it
+ // here would leave it lit on a file that has nothing to save
+ if let control = view as? NSControl,
+ control !== saveButton {
control.isEnabled = isEnabled
}
}
@@ -231,4 +234,10 @@ class PathView: NSView {
}
}
}
+
+ func unbindControls() {
+ lockButton.unbind(.value)
+ pathControl.unbind(.value)
+ saveButton.unbind(.enabled)
+ }
}
diff --git a/Sources/SharedUI/Components/TablePanelView.swift b/Sources/SharedUI/Components/TablePanelView.swift
index 6201f45..3ee263e 100644
--- a/Sources/SharedUI/Components/TablePanelView.swift
+++ b/Sources/SharedUI/Components/TablePanelView.swift
@@ -32,9 +32,9 @@ class TablePanelView, Bot
setupViews()
}
- @available(*, unavailable)
- required init(coder _: NSCoder) {
- fatalError("init(coder:) has not been implemented")
+ @available(*, unavailable, message: "use init(frame:)")
+ required init?(coder _: NSCoder) {
+ nil
}
func setupViews() {
@@ -129,4 +129,8 @@ class TablePanelView, Bot
}
func updateBottomBar() {}
+
+ func unbindControls() {
+ pathView.unbindControls()
+ }
}
diff --git a/Sources/SharedUI/Components/TimeToleranceView.swift b/Sources/SharedUI/Components/TimeToleranceView.swift
index bea2f3a..ed11184 100644
--- a/Sources/SharedUI/Components/TimeToleranceView.swift
+++ b/Sources/SharedUI/Components/TimeToleranceView.swift
@@ -9,9 +9,21 @@
class TimeToleranceView: NSView, NSTextFieldDelegate {
private lazy var inputText: NSTextField = createInputText()
private lazy var stepper: NSStepper = createStepper()
+ private lazy var stackView: NSStackView = createStackView()
var onTextChanged: ((TimeToleranceView) -> Void)?
+ // the row is disabled instead of hidden, hiding it changes the height the panel requires
+ var isEnabled = true {
+ didSet {
+ for view in stackView.views {
+ if let control = view as? NSControl {
+ control.isEnabled = isEnabled
+ }
+ }
+ }
+ }
+
var tolerance = 0 {
didSet {
if let onTextChanged {
@@ -29,7 +41,7 @@ class TimeToleranceView: NSView, NSTextFieldDelegate {
}
private func setupViews() {
- addSubview(createStackView())
+ addSubview(stackView)
}
@available(*, unavailable)
diff --git a/Tests/AppConfig.xcconfig b/Tests/AppConfig.xcconfig
index d9ae040..d1272ef 100644
--- a/Tests/AppConfig.xcconfig
+++ b/Tests/AppConfig.xcconfig
@@ -10,5 +10,14 @@ PRODUCT_BUNDLE_IDENTIFIER = com.visualdiffer.tests
ENABLE_APP_SANDBOX = NO
+// see the note in AppConfig.xcconfig: the entitlements belong to the target, not to the machine
+CODE_SIGN_ENTITLEMENTS = ./Tests/NoSandbox.entitlements
+
+// the XCTest, Testing and libXCTestSwiftSupport libraries shipped with Xcode are built for macOS 14.0,
+// so linking the test bundle at the app deployment target of 13.5 emits "built for newer version" warnings
+// the test bundle is never shipped, it runs only on the developer machine and on CI, so it can require a
+// newer minimum than the app, which stays on 13.5 for its users
+MACOSX_DEPLOYMENT_TARGET = 14.0
+
#include "Signing.local.xcconfig"
#include "Versions.local.xcconfig"
diff --git a/Tests/Sources/FileCompare/DiffResult/Tests/DiffResultTests.swift b/Tests/Sources/FileCompare/DiffResult/Tests/DiffResultTests.swift
index f4d46bd..7c28659 100644
--- a/Tests/Sources/FileCompare/DiffResult/Tests/DiffResultTests.swift
+++ b/Tests/Sources/FileCompare/DiffResult/Tests/DiffResultTests.swift
@@ -709,6 +709,64 @@ final class DiffResultTests: DiffResultBaseTests {
#expect(rightLine == diffRightLine.text)
}
}
+
+ @Test
+ func insertKeepsDestinationEOL() {
+ let leftText = "alpha\r\nbeta\r\ngamma"
+ let rightText = "alpha\r\ngamma"
+
+ let diffResult = DiffResult()
+ diffResult.diff(leftText: leftText, rightText: rightText)
+
+ assert(lines: diffResult.leftSide.lines, expectedValue: [.matching, .deleted, .matching])
+ assert(lines: diffResult.rightSide.lines, expectedValue: [.matching, .missing, .matching])
+
+ // pasted text always carries a unix line ending, the destination one must win
+ diffResult.insert(text: "beta\n", at: 1, side: .right)
+
+ assert(lines: diffResult.leftSide.lines, expectedValue: [.matching, .matching, .matching])
+ assert(lines: diffResult.rightSide.lines, expectedValue: [.matching, .matching, .matching])
+ #expect(diffResult.rightSide.lines[1].component.eol == .pcCRLF)
+ }
+
+ @Test
+ func insertOfCanonicallyEquivalentLineIsChanged() {
+ let leftText = "caf\u{00E9}\nsecond"
+ let rightText = "second"
+
+ let diffResult = DiffResult()
+ diffResult.diff(leftText: leftText, rightText: rightText)
+
+ assert(lines: diffResult.leftSide.lines, expectedValue: [.deleted, .matching])
+ assert(lines: diffResult.rightSide.lines, expectedValue: [.missing, .matching])
+
+ // String considers the two spellings equal, the paste must not
+ diffResult.insert(text: "cafe\u{0301}\n", at: 0, side: .right)
+
+ assert(lines: diffResult.leftSide.lines, expectedValue: [.changed, .matching])
+ assert(lines: diffResult.rightSide.lines, expectedValue: [.changed, .matching])
+ #expect(diffResult.leftSide.lines[0].inlineRanges == [3 ..< 4])
+ #expect(diffResult.rightSide.lines[0].inlineRanges == [3 ..< 4])
+ }
+
+ @Test
+ func insertHonoursTheComparisonOptions() {
+ let leftText = "ALPHA\nsecond"
+ let rightText = "second"
+
+ let diffResult = DiffResult(options: [.ignoreCharacterCase])
+ diffResult.diff(leftText: leftText, rightText: rightText)
+
+ assert(lines: diffResult.leftSide.lines, expectedValue: [.deleted, .matching])
+ assert(lines: diffResult.rightSide.lines, expectedValue: [.missing, .matching])
+
+ diffResult.insert(text: "alpha\n", at: 0, side: .right)
+
+ assert(lines: diffResult.leftSide.lines, expectedValue: [.matching, .matching])
+ assert(lines: diffResult.rightSide.lines, expectedValue: [.matching, .matching])
+ #expect(diffResult.leftSide.lines[0].hasIgnoredDifferences)
+ #expect(diffResult.rightSide.lines[0].hasIgnoredDifferences)
+ }
}
// swiftlint:enable file_length line_length
diff --git a/Tests/Sources/FileCompare/DiffResult/Tests/InlineDiffTests.swift b/Tests/Sources/FileCompare/DiffResult/Tests/InlineDiffTests.swift
new file mode 100644
index 0000000..6f6fda1
--- /dev/null
+++ b/Tests/Sources/FileCompare/DiffResult/Tests/InlineDiffTests.swift
@@ -0,0 +1,257 @@
+//
+// InlineDiffTests.swift
+// VisualDiffer
+//
+// Created by davide ficano on 12/08/26.
+// Copyright (c) 2026 visualdiffer.com
+//
+
+import Testing
+@testable import VisualDiffer
+
+final class InlineDiffTests: DiffResultBaseTests {
+ private static let longLineLength = 3000
+
+ @Test
+ func identicalLines() {
+ let diff = inlineDiff("hello", "hello")
+
+ #expect(diff.leftRanges.isEmpty)
+ #expect(diff.rightRanges.isEmpty)
+ }
+
+ @Test
+ func emptyLines() {
+ let diff = inlineDiff("", "")
+
+ #expect(diff.leftRanges.isEmpty)
+ #expect(diff.rightRanges.isEmpty)
+ }
+
+ @Test
+ func emptyAgainstFilledLine() {
+ let diff = inlineDiff("", "abc")
+
+ #expect(diff.leftRanges.isEmpty)
+ #expect(diff.rightRanges == [0 ..< 3])
+ }
+
+ @Test
+ func oneCharacterInTheMiddle() {
+ let diff = inlineDiff("abcde", "abXde")
+
+ #expect(diff.leftRanges == [2 ..< 3])
+ #expect(diff.rightRanges == [2 ..< 3])
+ }
+
+ @Test
+ func changeAtTheStart() {
+ let diff = inlineDiff("Xbcde", "abcde")
+
+ #expect(diff.leftRanges == [0 ..< 1])
+ #expect(diff.rightRanges == [0 ..< 1])
+ }
+
+ @Test
+ func changeAtTheEnd() {
+ let diff = inlineDiff("abcdX", "abcde")
+
+ #expect(diff.leftRanges == [4 ..< 5])
+ #expect(diff.rightRanges == [4 ..< 5])
+ }
+
+ @Test
+ func pureInsertion() {
+ let diff = inlineDiff("abc", "abXYc")
+
+ #expect(diff.leftRanges.isEmpty)
+ #expect(diff.rightRanges == [2 ..< 4])
+ }
+
+ @Test
+ func pureDeletion() {
+ let diff = inlineDiff("abXYc", "abc")
+
+ #expect(diff.leftRanges == [2 ..< 4])
+ #expect(diff.rightRanges.isEmpty)
+ }
+
+ @Test
+ func severalDisjointChanges() {
+ let diff = inlineDiff("abcXefgYijk", "abcQefgRijk")
+
+ #expect(diff.leftRanges == [3 ..< 4, 7 ..< 8])
+ #expect(diff.rightRanges == [3 ..< 4, 7 ..< 8])
+ }
+
+ @Test
+ func changedIdentifierKeepsCommonPrefixAndSuffix() {
+ let diff = inlineDiff("let value = computeTotal(a, b)", "let value = computeSum(a, b)")
+
+ #expect(diff.leftRanges == [19 ..< 24])
+ #expect(diff.rightRanges == [19 ..< 22])
+ }
+
+ @Test
+ func characterCaseIsHonouredOnlyWhenIgnored() {
+ let sensitive = inlineDiff("Hello", "hello")
+ let insensitive = inlineDiff("Hello", "hello", options: [.ignoreCharacterCase])
+
+ #expect(sensitive.leftRanges == [0 ..< 1])
+ #expect(sensitive.rightRanges == [0 ..< 1])
+ #expect(insensitive.leftRanges.isEmpty)
+ #expect(insensitive.rightRanges.isEmpty)
+ }
+
+ @Test
+ func canonicallyEquivalentCharactersAreDifferent() {
+ let precomposed = "caf\u{00E9}"
+ let decomposed = "cafe\u{0301}"
+
+ // Character compares the two spellings as equal and both count as one character,
+ // the comparison must still report the difference
+ #expect(precomposed == decomposed)
+ #expect(precomposed.count == decomposed.count)
+
+ let diff = inlineDiff(precomposed, decomposed)
+
+ #expect(diff.leftRanges == [3 ..< 4])
+ #expect(diff.rightRanges == [3 ..< 4])
+ }
+
+ @Test
+ func canonicallyEquivalentCharactersDifferWhileIgnoringCase() {
+ let diff = inlineDiff("CAF\u{00C9}", "cafe\u{0301}", options: [.ignoreCharacterCase])
+
+ #expect(diff.leftRanges == [3 ..< 4])
+ #expect(diff.rightRanges == [3 ..< 4])
+ }
+
+ @Test
+ func canonicallyEquivalentLinesAreReportedAsChanged() {
+ let diffResult = DiffResult()
+ diffResult.diff(leftText: "caf\u{00E9}\nsecond", rightText: "cafe\u{0301}\nsecond")
+
+ #expect(diffResult.leftSide.lines[0].type == .changed)
+ #expect(diffResult.rightSide.lines[0].type == .changed)
+ #expect(diffResult.leftSide.lines[0].inlineRanges == [3 ..< 4])
+ #expect(diffResult.rightSide.lines[0].inlineRanges == [3 ..< 4])
+ #expect(diffResult.leftSide.lines[1].type == .matching)
+ }
+
+ @Test
+ func longLinesDegradeToASingleRange() {
+ let filler = String(repeating: "a", count: Self.longLineLength)
+ let diff = inlineDiff(filler + "X" + filler, filler + "Y" + filler)
+
+ #expect(diff.leftRanges == [Self.longLineLength ..< Self.longLineLength + 1])
+ #expect(diff.rightRanges == [Self.longLineLength ..< Self.longLineLength + 1])
+ }
+
+ @Test
+ func longIdenticalLinesHaveNoRanges() {
+ let filler = String(repeating: "a", count: Self.longLineLength)
+ let diff = inlineDiff(filler, filler)
+
+ #expect(diff.leftRanges.isEmpty)
+ #expect(diff.rightRanges.isEmpty)
+ }
+
+ @Test
+ func longLineAgainstItsOwnPrefix() {
+ let filler = String(repeating: "a", count: Self.longLineLength)
+ let diff = inlineDiff(filler, filler + "X")
+
+ #expect(diff.leftRanges.isEmpty)
+ #expect(diff.rightRanges == [Self.longLineLength ..< Self.longLineLength + 1])
+ }
+
+ @Test
+ func longLineChangedAtTheStart() {
+ let filler = String(repeating: "a", count: Self.longLineLength)
+ let diff = inlineDiff("X" + filler, "Y" + filler)
+
+ #expect(diff.leftRanges == [0 ..< 1])
+ #expect(diff.rightRanges == [0 ..< 1])
+ }
+
+ @Test
+ func longLineChangedAtTheEnd() {
+ let filler = String(repeating: "a", count: Self.longLineLength)
+ let diff = inlineDiff(filler + "X", filler + "Y")
+
+ #expect(diff.leftRanges == [Self.longLineLength ..< Self.longLineLength + 1])
+ #expect(diff.rightRanges == [Self.longLineLength ..< Self.longLineLength + 1])
+ }
+
+ @Test
+ func longLinesIgnoringCharacterCase() {
+ let filler = String(repeating: "a", count: Self.longLineLength)
+ let diff = inlineDiff(filler + "X", filler.uppercased() + "y", options: [.ignoreCharacterCase])
+
+ #expect(diff.leftRanges == [Self.longLineLength ..< Self.longLineLength + 1])
+ #expect(diff.rightRanges == [Self.longLineLength ..< Self.longLineLength + 1])
+ }
+
+ @Test
+ func longLinesKeepTheExactComparison() {
+ let filler = String(repeating: "a", count: Self.longLineLength)
+ let diff = inlineDiff(filler + "caf\u{00E9}" + filler, filler + "cafe\u{0301}" + filler)
+ let expected = [Self.longLineLength + 3 ..< Self.longLineLength + 4]
+
+ #expect(diff.leftRanges == expected)
+ #expect(diff.rightRanges == expected)
+ }
+
+ @Test
+ func changedPairCarriesRanges() {
+ let diffResult = DiffResult()
+ diffResult.diff(leftText: "alpha\nbeta1\ngamma", rightText: "alpha\nbeta2\ngamma")
+
+ #expect(diffResult.leftSide.lines[1].type == .changed)
+ #expect(diffResult.leftSide.lines[1].inlineRanges == [4 ..< 5])
+ #expect(diffResult.rightSide.lines[1].inlineRanges == [4 ..< 5])
+ #expect(diffResult.leftSide.lines[0].inlineRanges.isEmpty)
+ #expect(diffResult.leftSide.lines[2].inlineRanges.isEmpty)
+ }
+
+ @Test
+ func replacingComponentClearsRanges() {
+ let line = DiffLine(
+ with: .changed,
+ number: 1,
+ component: DiffLineComponent(text: "abc", eol: .unix)
+ )
+ line.inlineRanges = [0 ..< 1]
+
+ line.component = DiffLineComponent(text: "xyz", eol: .unix)
+
+ #expect(line.inlineRanges.isEmpty)
+ }
+
+ @Test
+ func missingLineClearsRanges() {
+ let line = DiffLine(
+ with: .changed,
+ number: 1,
+ component: DiffLineComponent(text: "abc", eol: .unix)
+ )
+ line.inlineRanges = [0 ..< 1]
+
+ line.makeMissing()
+
+ #expect(line.inlineRanges.isEmpty)
+ }
+
+ private func inlineDiff(
+ _ leftText: String,
+ _ rightText: String,
+ options: DiffResult.Options = []
+ ) -> InlineDiff {
+ InlineDiff.between(
+ DiffLineComponent(text: leftText, eol: .missing),
+ DiffLineComponent(text: rightText, eol: .missing),
+ options: options
+ )
+ }
+}
diff --git a/Tests/Sources/FileCompare/DiffResult/Tests/SequenceDiffTests.swift b/Tests/Sources/FileCompare/DiffResult/Tests/SequenceDiffTests.swift
new file mode 100644
index 0000000..f0e5f26
--- /dev/null
+++ b/Tests/Sources/FileCompare/DiffResult/Tests/SequenceDiffTests.swift
@@ -0,0 +1,128 @@
+//
+// SequenceDiffTests.swift
+// VisualDiffer
+//
+// Created by davide ficano on 12/08/26.
+// Copyright (c) 2026 visualdiffer.com
+//
+
+import Testing
+@testable import VisualDiffer
+
+final class SequenceDiffTests: DiffResultBaseTests {
+ @Test
+ func emptySequences() {
+ #expect(changes([], []).isEmpty)
+ }
+
+ @Test
+ func identicalSequences() {
+ #expect(changes(["a", "b", "c"], ["a", "b", "c"]).isEmpty)
+ }
+
+ @Test
+ func insertedIntoEmptySequence() {
+ #expect(changes([], ["a", "b"]) == [DiffChange(line0: 0, line1: 0, deleted: 0, inserted: 2)])
+ }
+
+ @Test
+ func deletedWholeSequence() {
+ #expect(changes(["a", "b"], []) == [DiffChange(line0: 0, line1: 0, deleted: 2, inserted: 0)])
+ }
+
+ @Test
+ func deletedFromMiddle() {
+ #expect(changes(["a", "b", "c"], ["a", "c"]) == [DiffChange(line0: 1, line1: 1, deleted: 1, inserted: 0)])
+ }
+
+ @Test
+ func replacedElement() {
+ #expect(changes(["a", "b", "c"], ["a", "x", "c"]) == [DiffChange(line0: 1, line1: 1, deleted: 1, inserted: 1)])
+ }
+
+ @Test
+ func twoSeparateHunks() {
+ let result = changes(["a", "b", "c", "d", "e"], ["x", "b", "c", "y", "e"])
+
+ #expect(result == [
+ DiffChange(line0: 0, line1: 0, deleted: 1, inserted: 1),
+ DiffChange(line0: 3, line1: 3, deleted: 1, inserted: 1),
+ ])
+ }
+
+ @Test
+ func blankLineDeletion() {
+ let result = changes(["a", "", "b", "", "c"], ["a", "b", "", "c"])
+
+ #expect(result == [DiffChange(line0: 1, line1: 1, deleted: 1, inserted: 0)])
+ }
+
+ @Test
+ func repeatedRunTrimmedAtBothEnds() {
+ let result = changes(["x", "a", "a", "a", "y"], ["a", "a", "a"])
+
+ #expect(result == [
+ DiffChange(line0: 0, line1: 0, deleted: 1, inserted: 0),
+ DiffChange(line0: 4, line1: 3, deleted: 1, inserted: 0),
+ ])
+ }
+
+ @Test
+ func insertionNextToABlankLine() {
+ let result = changes(["a", "b", "", "c", "d"], ["a", "b", "", "x", "", "c", "d"])
+
+ #expect(result == [DiffChange(line0: 3, line1: 3, deleted: 0, inserted: 2)])
+ }
+
+ @Test
+ func duplicateHeavySequenceKeepsTheDiscardHeuristicHonest() {
+ let lineCount = 80
+ let distinctCount = 4
+ let base = (0 ..< lineCount).map { "line \($0 % distinctCount)" }
+ var mutated = base
+
+ mutated[10] = "unique A"
+ mutated[40] = "unique B"
+ mutated.insert("unique C", at: 60)
+ mutated.remove(at: 20)
+
+ #expect(changes(base, mutated) == [
+ DiffChange(line0: 10, line1: 10, deleted: 1, inserted: 1),
+ DiffChange(line0: 20, line1: 20, deleted: 1, inserted: 0),
+ DiffChange(line0: 40, line1: 39, deleted: 1, inserted: 1),
+ DiffChange(line0: 60, line1: 59, deleted: 0, inserted: 1),
+ ])
+ }
+
+ @Test
+ func canonicallyEquivalentLinesAreDifferent() {
+ let precomposed = "caf\u{00E9}"
+ let decomposed = "cafe\u{0301}"
+
+ // String compares the two spellings as equal, the diff engine must not,
+ // otherwise a real file difference would be silently hidden
+ #expect(precomposed == decomposed)
+
+ #expect(changes([precomposed], [decomposed]) == [DiffChange(line0: 0, line1: 0, deleted: 1, inserted: 1)])
+ }
+
+ @Test
+ func ignoredDiscardsKeepFrequentElements() {
+ // without ignoresDiscards the frequent element would be provisionally discarded
+ // and the whole sequence would be reported as changed
+ let left = Array(String(repeating: "a", count: 100) + "X" + String(repeating: "a", count: 100))
+ let right = Array(String(repeating: "a", count: 100) + "Y" + String(repeating: "a", count: 100))
+
+ let result = SequenceDiff.changes(left: left, right: right, ignoresDiscards: true)
+
+ #expect(result == [DiffChange(line0: 100, line1: 100, deleted: 1, inserted: 1)])
+ }
+
+ /// compares through the exact code unit key, as the file comparison does
+ private func changes(_ left: [String], _ right: [String]) -> [DiffChange] {
+ SequenceDiff.changes(
+ left: left.map { SequenceDiff.TextKey($0) },
+ right: right.map { SequenceDiff.TextKey($0) }
+ )
+ }
+}
diff --git a/Tests/Sources/FileCompare/DiffResult/Tests/WhitespacesTests.swift b/Tests/Sources/FileCompare/DiffResult/Tests/WhitespacesTests.swift
index 29e1ab4..7dabdbb 100644
--- a/Tests/Sources/FileCompare/DiffResult/Tests/WhitespacesTests.swift
+++ b/Tests/Sources/FileCompare/DiffResult/Tests/WhitespacesTests.swift
@@ -19,8 +19,8 @@ final class WhitespacesTests: DiffResultBaseTests {
" leading spaces\n" +
"another line"
- let diffResult = DiffResult()
- diffResult.diff(leftText: leftText, rightText: rightText, options: .ignoreLeadingWhitespaces)
+ let diffResult = DiffResult(options: .ignoreLeadingWhitespaces)
+ diffResult.diff(leftText: leftText, rightText: rightText)
let leftChangeType: [DiffChangeType] = [.matching, .matching]
assert(lines: diffResult.leftSide.lines, expectedValue: leftChangeType)
@@ -44,8 +44,8 @@ final class WhitespacesTests: DiffResultBaseTests {
"line1\n" +
"another text tabs and spaces"
- let diffResult = DiffResult()
- diffResult.diff(leftText: leftText, rightText: rightText, options: .ignoreInternalWhitespaces)
+ let diffResult = DiffResult(options: .ignoreInternalWhitespaces)
+ diffResult.diff(leftText: leftText, rightText: rightText)
let leftChangeType: [DiffChangeType] = [.changed, .matching]
assert(lines: diffResult.leftSide.lines, expectedValue: leftChangeType)
@@ -71,8 +71,8 @@ final class WhitespacesTests: DiffResultBaseTests {
"another text tabs and spaces\n" +
" last line"
- let diffResult = DiffResult()
- diffResult.diff(leftText: leftText, rightText: rightText, options: [.allIgnoreWhitespaces, .ignoreLineEndings])
+ let diffResult = DiffResult(options: [.allIgnoreWhitespaces, .ignoreLineEndings])
+ diffResult.diff(leftText: leftText, rightText: rightText)
let leftChangeType: [DiffChangeType] = [.matching, .matching, .matching]
assert(lines: diffResult.leftSide.lines, expectedValue: leftChangeType)
@@ -98,8 +98,8 @@ final class WhitespacesTests: DiffResultBaseTests {
"another text tabs and spaces\n" +
" last line"
- let diffResult = DiffResult()
- diffResult.diff(leftText: leftText, rightText: rightText, options: [.allIgnoreWhitespaces])
+ let diffResult = DiffResult(options: [.allIgnoreWhitespaces])
+ diffResult.diff(leftText: leftText, rightText: rightText)
let leftChangeType: [DiffChangeType] = [.matching, .changed, .matching]
assert(lines: diffResult.leftSide.lines, expectedValue: leftChangeType)
@@ -123,8 +123,8 @@ final class WhitespacesTests: DiffResultBaseTests {
"line One\n" +
"another line"
- let diffResult = DiffResult()
- diffResult.diff(leftText: leftText, rightText: rightText, options: .ignoreCharacterCase)
+ let diffResult = DiffResult(options: .ignoreCharacterCase)
+ diffResult.diff(leftText: leftText, rightText: rightText)
let leftChangeType: [DiffChangeType] = [.matching, .matching]
assert(lines: diffResult.leftSide.lines, expectedValue: leftChangeType)
@@ -150,8 +150,8 @@ final class WhitespacesTests: DiffResultBaseTests {
"inserted line\n" +
" spaced line"
- let diffResult = DiffResult()
- diffResult.diff(leftText: leftText, rightText: rightText, options: .ignoreLeadingWhitespaces)
+ let diffResult = DiffResult(options: .ignoreLeadingWhitespaces)
+ diffResult.diff(leftText: leftText, rightText: rightText)
let leftChangeType: [DiffChangeType] = [.matching, .missing, .missing, .matching]
assert(lines: diffResult.leftSide.lines, expectedValue: leftChangeType)
@@ -170,11 +170,10 @@ final class WhitespacesTests: DiffResultBaseTests {
@Test
func refreshSummaryAfterDeletingFilteredMatch() {
- let diffResult = DiffResult()
+ let diffResult = DiffResult(options: .ignoreLeadingWhitespaces)
diffResult.diff(
leftText: " leading spaces",
- rightText: "leading spaces",
- options: .ignoreLeadingWhitespaces
+ rightText: "leading spaces"
)
let filtered = DiffResult.justMatchingLines(diffResult)
diff --git a/Tests/Sources/FileSystem/CaseSensitiveBaseTest.swift b/Tests/Sources/FileSystem/CaseSensitiveBaseTest.swift
index d184b07..cfb0783 100644
--- a/Tests/Sources/FileSystem/CaseSensitiveBaseTest.swift
+++ b/Tests/Sources/FileSystem/CaseSensitiveBaseTest.swift
@@ -28,7 +28,7 @@ open class CaseSensitiveBaseTest: BaseTests {
if !FileManager.default.fileExists(atPath: volumePath.osPath) {
let process = Process()
process.executableURL = URL(filePath: "/bin/sh")
- process.arguments = ["-c", "diskutil erasevolume 'Case-sensitive HFS+' '\(volumeName)' `hdiutil attach -nomount ram://1048576`"]
+ process.arguments = ["-c", "diskutil erasevolume 'Case-sensitive HFS+' '\(volumeName)' $(diskutil image attach ram://1048576)"]
do {
try process.run()
} catch {
diff --git a/VisualDiffer.xctestplan b/Tests/VisualDiffer.xctestplan
similarity index 100%
rename from VisualDiffer.xctestplan
rename to Tests/VisualDiffer.xctestplan
diff --git a/Versions-Template.xcconfig b/Versions-Template.xcconfig
index daf4d96..692dac5 100644
--- a/Versions-Template.xcconfig
+++ b/Versions-Template.xcconfig
@@ -6,7 +6,7 @@
// Copyright (c) 2022 visualdiffer.com
//
-// Copy this file to Versions.xcconfig and edit the values
+// scripts/setup-local-env.sh copies this file to Versions.local.xcconfig, edit the values there
APP_VERSION = 1.0.0
APP_BUNDLE_VERSION = $(APP_VERSION)
diff --git a/VisualDiffer-Bridging-Header.h b/VisualDiffer-Bridging-Header.h
index 99175c7..738ca76 100644
--- a/VisualDiffer-Bridging-Header.h
+++ b/VisualDiffer-Bridging-Header.h
@@ -7,5 +7,3 @@
#import "TitlePredicateEditorRowTemplate.h"
#import "TOPFileSizePredicateEditorRowTemplate.h"
#import "TOPTimestampPredicateEditorRowTemplate.h"
-#import "UnifiedDiff.h"
-#import "UDiffScriptBuilder.h"
diff --git a/VisualDiffer.xcodeproj/project.pbxproj b/VisualDiffer.xcodeproj/project.pbxproj
index 2d20e59..4cdb885 100644
--- a/VisualDiffer.xcodeproj/project.pbxproj
+++ b/VisualDiffer.xcodeproj/project.pbxproj
@@ -3,348 +3,11 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 60;
+ objectVersion = 90;
objects = {
/* Begin PBXBuildFile section */
2F7446AB0DB6BCF400F9684A /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2F7446A70DB6BCF400F9684A /* MainMenu.xib */; };
- 551DE39F2ED422820067AB18 /* FilesWindowController+SessionPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 551DE39E2ED422820067AB18 /* FilesWindowController+SessionPreferences.swift */; };
- 551DE3A62ED4237B0067AB18 /* FileSessionPreferencesWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 551DE3A42ED4237B0067AB18 /* FileSessionPreferencesWindow.swift */; };
- 551DE3AA2ED428B40067AB18 /* FilePreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 551DE3A92ED428A50067AB18 /* FilePreferences.swift */; };
- 551DE3B42ED42AD90067AB18 /* FilePreferencesComparisonPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 551DE3B32ED42AD00067AB18 /* FilePreferencesComparisonPanel.swift */; };
- 551DE3B62ED42B4E0067AB18 /* FileComparisonBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 551DE3B52ED42B4E0067AB18 /* FileComparisonBox.swift */; };
- 551DE3B82ED439AF0067AB18 /* PreferencesBoxDataSource+Default.swift in Sources */ = {isa = PBXBuildFile; fileRef = 551DE3B72ED4399B0067AB18 /* PreferencesBoxDataSource+Default.swift */; };
- 552430412F7673F800951F1A /* FileDifferenceNavigatorBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 552430402F7673F800951F1A /* FileDifferenceNavigatorBox.swift */; };
- 552B85082F5FE29A00A9268A /* VDDocumentController+BlankDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 552B85072F5FE29400A9268A /* VDDocumentController+BlankDocument.swift */; };
- 5536ADBA2EF169820019EFBF /* SessionDiff+ExtraData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5536ADB92EF169820019EFBF /* SessionDiff+ExtraData.swift */; };
- 553741792E9372DF00AB56D0 /* NSAppearance+DarkMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740E52E9372DF00AB56D0 /* NSAppearance+DarkMode.swift */; };
- 5537417A2E9372DF00AB56D0 /* QLPreviewPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740FD2E9372DF00AB56D0 /* QLPreviewPanel.swift */; };
- 5537417B2E9372DF00AB56D0 /* TrustedPathsPreferencesPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740A12E9372DF00AB56D0 /* TrustedPathsPreferencesPanel.swift */; };
- 5537417C2E9372DF00AB56D0 /* TouchPickersStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740142E9372DF00AB56D0 /* TouchPickersStackView.swift */; };
- 5537417D2E9372DF00AB56D0 /* BasePreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740862E9372DF00AB56D0 /* BasePreferences.swift */; };
- 5537417E2E9372DF00AB56D0 /* DualPaneSplitViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741532E9372DF00AB56D0 /* DualPaneSplitViewDelegate.swift */; };
- 5537417F2E9372DF00AB56D0 /* FoldersOutlineView+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FED2E9372DF00AB56D0 /* FoldersOutlineView+Menu.swift */; };
- 553741802E9372DF00AB56D0 /* AlignRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373F8F2E9372DF00AB56D0 /* AlignRule.swift */; };
- 553741812E9372DF00AB56D0 /* VisualizationBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537409F2E9372DF00AB56D0 /* VisualizationBox.swift */; };
- 553741822E9372DF00AB56D0 /* CommonPrefs+FileCompare.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373F992E9372DF00AB56D0 /* CommonPrefs+FileCompare.swift */; };
- 553741832E9372DF00AB56D0 /* TablePanelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741732E9372DF00AB56D0 /* TablePanelView.swift */; };
- 553741852E9372DF00AB56D0 /* NSOpenPanel+Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740FC2E9372DF00AB56D0 /* NSOpenPanel+Application.swift */; };
- 553741862E9372DF00AB56D0 /* ConfirmReplace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740012E9372DF00AB56D0 /* ConfirmReplace.swift */; };
- 553741872E9372DF00AB56D0 /* SessionDiff.ItemType+Paths.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FA62E9372DF00AB56D0 /* SessionDiff.ItemType+Paths.swift */; };
- 553741882E9372DF00AB56D0 /* FileSizeFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537412C2E9372DF00AB56D0 /* FileSizeFormatter.swift */; };
- 553741892E9372DF00AB56D0 /* TOPTimestampPredicateEditorRowTemplate.m in Sources */ = {isa = PBXBuildFile; fileRef = 553740DB2E9372DF00AB56D0 /* TOPTimestampPredicateEditorRowTemplate.m */; };
- 5537418A2E9372DF00AB56D0 /* DocumentWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373F9F2E9372DF00AB56D0 /* DocumentWindow.swift */; };
- 5537418B2E9372DF00AB56D0 /* CommonPrefs+Name.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373F9D2E9372DF00AB56D0 /* CommonPrefs+Name.swift */; };
- 5537418D2E9372DF00AB56D0 /* FilePathTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537416D2E9372DF00AB56D0 /* FilePathTextField.swift */; };
- 5537418E2E9372DF00AB56D0 /* CopyCompareItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740392E9372DF00AB56D0 /* CopyCompareItem.swift */; };
- 5537418F2E9372DF00AB56D0 /* ColoredFoldersManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FE62E9372DF00AB56D0 /* ColoredFoldersManager.swift */; };
- 553741902E9372DF00AB56D0 /* FilesTableView+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FB72E9372DF00AB56D0 /* FilesTableView+Menu.swift */; };
- 553741912E9372DF00AB56D0 /* NSBox+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741172E9372DF00AB56D0 /* NSBox+Helper.swift */; };
- 553741922E9372DF00AB56D0 /* FontPreferencesPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740942E9372DF00AB56D0 /* FontPreferencesPanel.swift */; };
- 553741932E9372DF00AB56D0 /* DisplayOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537404B2E9372DF00AB56D0 /* DisplayOptions.swift */; };
- 553741942E9372DF00AB56D0 /* FilesWindowController+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FCE2E9372DF00AB56D0 /* FilesWindowController+Menu.swift */; };
- 553741952E9372DF00AB56D0 /* OptionSet+Toggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740F92E9372DF00AB56D0 /* OptionSet+Toggle.swift */; };
- 553741962E9372DF00AB56D0 /* URL+Finder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741102E9372DF00AB56D0 /* URL+Finder.swift */; };
- 553741982E9372DF00AB56D0 /* CommonPrefs+FolderCompare.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373F9A2E9372DF00AB56D0 /* CommonPrefs+FolderCompare.swift */; };
- 553741992E9372DF00AB56D0 /* FoldersWindowController+PathControlDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537402E2E9372DF00AB56D0 /* FoldersWindowController+PathControlDelegate.swift */; };
- 5537419A2E9372DF00AB56D0 /* FontBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740932E9372DF00AB56D0 /* FontBox.swift */; };
- 5537419B2E9372DF00AB56D0 /* FilesTableViewFindTextDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FB82E9372DF00AB56D0 /* FilesTableViewFindTextDelegate.swift */; };
- 5537419C2E9372DF00AB56D0 /* DeleteFileOperationExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FFD2E9372DF00AB56D0 /* DeleteFileOperationExecutor.swift */; };
- 5537419D2E9372DF00AB56D0 /* DualPaneSplitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741522E9372DF00AB56D0 /* DualPaneSplitView.swift */; };
- 5537419E2E9372DF00AB56D0 /* StandardButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537414D2E9372DF00AB56D0 /* StandardButtons.swift */; };
- 5537419F2E9372DF00AB56D0 /* ConfirmationsFoldersBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537408B2E9372DF00AB56D0 /* ConfirmationsFoldersBox.swift */; };
- 553741A02E9372DF00AB56D0 /* DifferenceNavigatorBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537408E2E9372DF00AB56D0 /* DifferenceNavigatorBox.swift */; };
- 553741A12E9372DF00AB56D0 /* FolderReaderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740602E9372DF00AB56D0 /* FolderReaderDelegate.swift */; };
- 553741A22E9372DF00AB56D0 /* UDiffScriptBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 553740BD2E9372DF00AB56D0 /* UDiffScriptBuilder.m */; };
- 553741A32E9372DF00AB56D0 /* String+RegularExpression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741072E9372DF00AB56D0 /* String+RegularExpression.swift */; };
- 553741A42E9372DF00AB56D0 /* FileSystemController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740182E9372DF00AB56D0 /* FileSystemController.swift */; };
- 553741A52E9372DF00AB56D0 /* ComparatorOptions+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740482E9372DF00AB56D0 /* ComparatorOptions+Helper.swift */; };
- 553741A62E9372DF00AB56D0 /* AppearanceBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740962E9372DF00AB56D0 /* AppearanceBox.swift */; };
- 553741A72E9372DF00AB56D0 /* FolderComparisonBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740972E9372DF00AB56D0 /* FolderComparisonBox.swift */; };
- 553741A82E9372DF00AB56D0 /* FoldersWindowController+Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740242E9372DF00AB56D0 /* FoldersWindowController+Document.swift */; };
- 553741A92E9372DF00AB56D0 /* FilterConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537405D2E9372DF00AB56D0 /* FilterConfig.swift */; };
- 553741AA2E9372DF00AB56D0 /* IconUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537412F2E9372DF00AB56D0 /* IconUtils.swift */; };
- 553741AC2E9372DF00AB56D0 /* NSTextView+Style.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741202E9372DF00AB56D0 /* NSTextView+Style.swift */; };
- 553741AD2E9372DF00AB56D0 /* FoldersOutlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FE72E9372DF00AB56D0 /* FoldersOutlineView.swift */; };
- 553741AE2E9372DF00AB56D0 /* PreferredEditorBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740992E9372DF00AB56D0 /* PreferredEditorBox.swift */; };
- 553741AF2E9372DF00AB56D0 /* MoveCompareItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740412E9372DF00AB56D0 /* MoveCompareItem.swift */; };
- 553741B12E9372DF00AB56D0 /* TextFieldSelectionHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537415C2E9372DF00AB56D0 /* TextFieldSelectionHolder.swift */; };
- 553741B22E9372DF00AB56D0 /* TouchFileOperationExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740132E9372DF00AB56D0 /* TouchFileOperationExecutor.swift */; };
- 553741B32E9372DF00AB56D0 /* NSTextFieldCell+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741452E9372DF00AB56D0 /* NSTextFieldCell+Helper.swift */; };
- 553741B42E9372DF00AB56D0 /* NSApplication.ModalResponse+ReplaceFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740032E9372DF00AB56D0 /* NSApplication.ModalResponse+ReplaceFile.swift */; };
- 553741B52E9372DF00AB56D0 /* DiffOpenerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FA42E9372DF00AB56D0 /* DiffOpenerDelegate.swift */; };
- 553741B72E9372DF00AB56D0 /* PreferencesCheckbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740832E9372DF00AB56D0 /* PreferencesCheckbox.swift */; };
- 553741B82E9372DF00AB56D0 /* FileManager+Attributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740F12E9372DF00AB56D0 /* FileManager+Attributes.swift */; };
- 553741B92E9372DF00AB56D0 /* MainThreadFolderReaderDelegateBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537401C2E9372DF00AB56D0 /* MainThreadFolderReaderDelegateBridge.swift */; };
- 553741BA2E9372DF00AB56D0 /* VisibleWhitespaces.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537413F2E9372DF00AB56D0 /* VisibleWhitespaces.swift */; };
- 553741BB2E9372DF00AB56D0 /* DisplayPositionable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373F912E9372DF00AB56D0 /* DisplayPositionable.swift */; };
- 553741BC2E9372DF00AB56D0 /* AlignRuleWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740AA2E9372DF00AB56D0 /* AlignRuleWindow.swift */; };
- 553741BD2E9372DF00AB56D0 /* DeleteCompareItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537403A2E9372DF00AB56D0 /* DeleteCompareItem.swift */; };
- 553741BE2E9372DF00AB56D0 /* DiffChangeType+Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FDD2E9372DF00AB56D0 /* DiffChangeType+Color.swift */; };
- 553741BF2E9372DF00AB56D0 /* DescriptionOutlineNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741412E9372DF00AB56D0 /* DescriptionOutlineNode.swift */; };
- 553741C02E9372DF00AB56D0 /* FilesTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FB62E9372DF00AB56D0 /* FilesTableView.swift */; };
- 553741C12E9372DF00AB56D0 /* String+Occcurrences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741052E9372DF00AB56D0 /* String+Occcurrences.swift */; };
- 553741C22E9372DF00AB56D0 /* FoldersWindowController+QLPreviewPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537402F2E9372DF00AB56D0 /* FoldersWindowController+QLPreviewPanel.swift */; };
- 553741C32E9372DF00AB56D0 /* FoldersOutlineView+DifferenceNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537405A2E9372DF00AB56D0 /* FoldersOutlineView+DifferenceNavigator.swift */; };
- 553741C42E9372DF00AB56D0 /* JumpToLineWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FE32E9372DF00AB56D0 /* JumpToLineWindow.swift */; };
- 553741C52E9372DF00AB56D0 /* EncodingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741282E9372DF00AB56D0 /* EncodingError.swift */; };
- 553741C62E9372DF00AB56D0 /* FileExtraOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537404E2E9372DF00AB56D0 /* FileExtraOptions.swift */; };
- 553741C72E9372DF00AB56D0 /* Array+MoveIndexes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740E72E9372DF00AB56D0 /* Array+MoveIndexes.swift */; };
- 553741C82E9372DF00AB56D0 /* BigFileFileOperationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 553740C82E9372DF00AB56D0 /* BigFileFileOperationManager.m */; };
- 553741C92E9372DF00AB56D0 /* FoldersWindowController+BaseFolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740202E9372DF00AB56D0 /* FoldersWindowController+BaseFolder.swift */; };
- 553741CB2E9372DF00AB56D0 /* FoldersWindowController+UICreation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740322E9372DF00AB56D0 /* FoldersWindowController+UICreation.swift */; };
- 553741CC2E9372DF00AB56D0 /* FilesWindowController+UICreation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FD82E9372DF00AB56D0 /* FilesWindowController+UICreation.swift */; };
- 553741CD2E9372DF00AB56D0 /* NSTableView+Row.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537410A2E9372DF00AB56D0 /* NSTableView+Row.swift */; };
- 553741CE2E9372DF00AB56D0 /* FindText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537416E2E9372DF00AB56D0 /* FindText.swift */; };
- 553741CF2E9372DF00AB56D0 /* FoldersTraversalBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740902E9372DF00AB56D0 /* FoldersTraversalBox.swift */; };
- 553741D02E9372DF00AB56D0 /* FileError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741342E9372DF00AB56D0 /* FileError.swift */; };
- 553741D12E9372DF00AB56D0 /* OpenEditorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537413B2E9372DF00AB56D0 /* OpenEditorError.swift */; };
- 553741D22E9372DF00AB56D0 /* GeneralPreferencesPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740982E9372DF00AB56D0 /* GeneralPreferencesPanel.swift */; };
- 553741D32E9372DF00AB56D0 /* CompareItem+DifferenceNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537405B2E9372DF00AB56D0 /* CompareItem+DifferenceNavigator.swift */; };
- 553741D42E9372DF00AB56D0 /* PreferencesBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740812E9372DF00AB56D0 /* PreferencesBox.swift */; };
- 553741D52E9372DF00AB56D0 /* NSAlert+ReplaceFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740022E9372DF00AB56D0 /* NSAlert+ReplaceFile.swift */; };
- 553741D72E9372DF00AB56D0 /* URL+SymLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741152E9372DF00AB56D0 /* URL+SymLink.swift */; };
- 553741D82E9372DF00AB56D0 /* RecentDocumentPopupMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FA22E9372DF00AB56D0 /* RecentDocumentPopupMenu.swift */; };
- 553741D92E9372DF00AB56D0 /* FoldersWindowController+FoldersOutlineViewContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740282E9372DF00AB56D0 /* FoldersWindowController+FoldersOutlineViewContextMenu.swift */; };
- 553741DA2E9372DF00AB56D0 /* FileAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537403B2E9372DF00AB56D0 /* FileAttributes.swift */; };
- 553741DB2E9372DF00AB56D0 /* SyncFileController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537400C2E9372DF00AB56D0 /* SyncFileController.swift */; };
- 553741DC2E9372DF00AB56D0 /* ConfirmationsFilesBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537408A2E9372DF00AB56D0 /* ConfirmationsFilesBox.swift */; };
- 553741DD2E9372DF00AB56D0 /* CompareItem+Accessors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740502E9372DF00AB56D0 /* CompareItem+Accessors.swift */; };
- 553741DE2E9372DF00AB56D0 /* FilesWindowController+JumpLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FCC2E9372DF00AB56D0 /* FilesWindowController+JumpLine.swift */; };
- 553741DF2E9372DF00AB56D0 /* CommonPrefs+ConsoleLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740362E9372DF00AB56D0 /* CommonPrefs+ConsoleLog.swift */; };
- 553741E02E9372DF00AB56D0 /* NSToolbar+Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537410C2E9372DF00AB56D0 /* NSToolbar+Create.swift */; };
- 553741E12E9372DF00AB56D0 /* String+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741032E9372DF00AB56D0 /* String+Helper.swift */; };
- 553741E32E9372DF00AB56D0 /* LineNumberTableRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FC02E9372DF00AB56D0 /* LineNumberTableRowView.swift */; };
- 553741E42E9372DF00AB56D0 /* FolderReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537405E2E9372DF00AB56D0 /* FolderReader.swift */; };
- 553741E52E9372DF00AB56D0 /* DateFormatter+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740F32E9372DF00AB56D0 /* DateFormatter+Helper.swift */; };
- 553741E62E9372DF00AB56D0 /* FoldersWindowController+Navigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537402B2E9372DF00AB56D0 /* FoldersWindowController+Navigation.swift */; };
- 553741E72E9372DF00AB56D0 /* HistoryEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FAB2E9372DF00AB56D0 /* HistoryEntity.swift */; };
- 553741E82E9372DF00AB56D0 /* CompareItem+Clone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740512E9372DF00AB56D0 /* CompareItem+Clone.swift */; };
- 553741E92E9372DF00AB56D0 /* URL+Path.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741122E9372DF00AB56D0 /* URL+Path.swift */; };
- 553741EA2E9372DF00AB56D0 /* PathChooser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FA12E9372DF00AB56D0 /* PathChooser.swift */; };
- 553741EB2E9372DF00AB56D0 /* VDDocumentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FA92E9372DF00AB56D0 /* VDDocumentController.swift */; };
- 553741EC2E9372DF00AB56D0 /* CopyFileOperationExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FFB2E9372DF00AB56D0 /* CopyFileOperationExecutor.swift */; };
- 553741ED2E9372DF00AB56D0 /* FoldersOutlineView+Columns.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FE92E9372DF00AB56D0 /* FoldersOutlineView+Columns.swift */; };
- 553741EE2E9372DF00AB56D0 /* NSTextField+CenterVertically.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537416F2E9372DF00AB56D0 /* NSTextField+CenterVertically.swift */; };
- 553741EF2E9372DF00AB56D0 /* BufferedInputStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741322E9372DF00AB56D0 /* BufferedInputStream.swift */; };
- 553741F02E9372DF00AB56D0 /* ComparisonStandardUserDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740802E9372DF00AB56D0 /* ComparisonStandardUserDataSource.swift */; };
- 553741F12E9372DF00AB56D0 /* TextPreferencesPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537409E2E9372DF00AB56D0 /* TextPreferencesPanel.swift */; };
- 553741F22E9372DF00AB56D0 /* AlignPopupButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741642E9372DF00AB56D0 /* AlignPopupButtonCell.swift */; };
- 553741F32E9372DF00AB56D0 /* FolderSelectionInfo+ViewerActionValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537406D2E9372DF00AB56D0 /* FolderSelectionInfo+ViewerActionValidator.swift */; };
- 553741F52E9372DF00AB56D0 /* OpenEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741392E9372DF00AB56D0 /* OpenEditor.swift */; };
- 553741F62E9372DF00AB56D0 /* NSMenu+File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740F72E9372DF00AB56D0 /* NSMenu+File.swift */; };
- 553741F72E9372DF00AB56D0 /* FilesWindowController+FileInfoBarDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FC92E9372DF00AB56D0 /* FilesWindowController+FileInfoBarDelegate.swift */; };
- 553741F82E9372DF00AB56D0 /* KeyboardPreferencesPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537409C2E9372DF00AB56D0 /* KeyboardPreferencesPanel.swift */; };
- 553741F92E9372DF00AB56D0 /* CompareItem+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740402E9372DF00AB56D0 /* CompareItem+Metadata.swift */; };
- 553741FA2E9372DF00AB56D0 /* TextFieldVerticalCentered.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FC32E9372DF00AB56D0 /* TextFieldVerticalCentered.swift */; };
- 553741FB2E9372DF00AB56D0 /* KeyEquivalent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373F932E9372DF00AB56D0 /* KeyEquivalent.swift */; };
- 553741FC2E9372DF00AB56D0 /* CompareItem+VisibleItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740572E9372DF00AB56D0 /* CompareItem+VisibleItem.swift */; };
- 553741FD2E9372DF00AB56D0 /* FoldersWindowController+SessionPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740312E9372DF00AB56D0 /* FoldersWindowController+SessionPreferences.swift */; };
- 553741FE2E9372DF00AB56D0 /* CompareItemTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FF62E9372DF00AB56D0 /* CompareItemTableCellView.swift */; };
- 553741FF2E9372DF00AB56D0 /* ProgressBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741582E9372DF00AB56D0 /* ProgressBarView.swift */; };
- 553742002E9372DF00AB56D0 /* FolderManagerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537403F2E9372DF00AB56D0 /* FolderManagerError.swift */; };
- 553742012E9372DF00AB56D0 /* FolderSelectionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537401E2E9372DF00AB56D0 /* FolderSelectionInfo.swift */; };
- 553742022E9372DF00AB56D0 /* SynchroScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537415A2E9372DF00AB56D0 /* SynchroScrollView.swift */; };
- 553742032E9372DF00AB56D0 /* FilesWindowController+Save.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FD52E9372DF00AB56D0 /* FilesWindowController+Save.swift */; };
- 553742042E9372DF00AB56D0 /* FoldersWindowController+ConsoleViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740222E9372DF00AB56D0 /* FoldersWindowController+ConsoleViewDelegate.swift */; };
- 553742052E9372DF00AB56D0 /* PreferencesBoxDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740822E9372DF00AB56D0 /* PreferencesBoxDataSource.swift */; };
- 553742062E9372DF00AB56D0 /* TOPFileSizePredicateEditorRowTemplate.m in Sources */ = {isa = PBXBuildFile; fileRef = 553740D92E9372DF00AB56D0 /* TOPFileSizePredicateEditorRowTemplate.m */; };
- 553742072E9372DF00AB56D0 /* FolderReader+Detached.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537401B2E9372DF00AB56D0 /* FolderReader+Detached.swift */; };
- 553742082E9372DF00AB56D0 /* ViewLinkable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373F962E9372DF00AB56D0 /* ViewLinkable.swift */; };
- 553742092E9372DF00AB56D0 /* SessionPreferencesFiltersBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740B42E9372DF00AB56D0 /* SessionPreferencesFiltersBox.swift */; };
- 5537420A2E9372DF00AB56D0 /* FilesWindowController+Common.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FC72E9372DF00AB56D0 /* FilesWindowController+Common.swift */; };
- 5537420B2E9372DF00AB56D0 /* FilesWindowController+NSToolbarDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FD12E9372DF00AB56D0 /* FilesWindowController+NSToolbarDelegate.swift */; };
- 5537420C2E9372DF00AB56D0 /* FilesWindowController+TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FD72E9372DF00AB56D0 /* FilesWindowController+TableView.swift */; };
- 5537420D2E9372DF00AB56D0 /* NSProgressIndicator+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537411C2E9372DF00AB56D0 /* NSProgressIndicator+Helper.swift */; };
- 5537420E2E9372DF00AB56D0 /* ComparatorOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740462E9372DF00AB56D0 /* ComparatorOptions.swift */; };
- 5537420F2E9372DF00AB56D0 /* PathTimestamps.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740422E9372DF00AB56D0 /* PathTimestamps.swift */; };
- 553742102E9372DF00AB56D0 /* FilesWindowController+Clipboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FC62E9372DF00AB56D0 /* FilesWindowController+Clipboard.swift */; };
- 553742112E9372DF00AB56D0 /* RSVerticallyCenteredTextFieldCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741462E9372DF00AB56D0 /* RSVerticallyCenteredTextFieldCell.swift */; };
- 553742122E9372DF00AB56D0 /* CompareItem+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740532E9372DF00AB56D0 /* CompareItem+Description.swift */; };
- 553742132E9372DF00AB56D0 /* SessionPreferencesWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740A62E9372DF00AB56D0 /* SessionPreferencesWindow.swift */; };
- 553742142E9372DF00AB56D0 /* UserDefinedRulesBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740AF2E9372DF00AB56D0 /* UserDefinedRulesBox.swift */; };
- 553742162E9372DF00AB56D0 /* ProgressIndicatorController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740092E9372DF00AB56D0 /* ProgressIndicatorController.swift */; };
- 553742172E9372DF00AB56D0 /* FolderPanelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FF52E9372DF00AB56D0 /* FolderPanelView.swift */; };
- 553742182E9372DF00AB56D0 /* ComparatorOptions+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740472E9372DF00AB56D0 /* ComparatorOptions+Description.swift */; };
- 553742192E9372DF00AB56D0 /* FoldersOutlineView+Clipboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FE82E9372DF00AB56D0 /* FoldersOutlineView+Clipboard.swift */; };
- 5537421A2E9372DF00AB56D0 /* DatePickersStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740112E9372DF00AB56D0 /* DatePickersStackView.swift */; };
- 5537421B2E9372DF00AB56D0 /* UnifiedDiff.m in Sources */ = {isa = PBXBuildFile; fileRef = 553740BF2E9372DF00AB56D0 /* UnifiedDiff.m */; };
- 5537421C2E9372DF00AB56D0 /* SyncOutlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537400F2E9372DF00AB56D0 /* SyncOutlineView.swift */; };
- 5537421D2E9372DF00AB56D0 /* CompareItem+Comparison.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740522E9372DF00AB56D0 /* CompareItem+Comparison.swift */; };
- 5537421E2E9372DF00AB56D0 /* NSError+Format.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740EF2E9372DF00AB56D0 /* NSError+Format.swift */; };
- 5537421F2E9372DF00AB56D0 /* RefreshInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740612E9372DF00AB56D0 /* RefreshInfo.swift */; };
- 553742202E9372DF00AB56D0 /* FileDropView+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741562E9372DF00AB56D0 /* FileDropView+Helper.swift */; };
- 553742212E9372DF00AB56D0 /* SyncFileOperationExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537400D2E9372DF00AB56D0 /* SyncFileOperationExecutor.swift */; };
- 553742222E9372DF00AB56D0 /* CompareItem+FilterConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740542E9372DF00AB56D0 /* CompareItem+FilterConfig.swift */; };
- 553742232E9372DF00AB56D0 /* NSStackView+PreferencesPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740A32E9372DF00AB56D0 /* NSStackView+PreferencesPanel.swift */; };
- 553742242E9372DF00AB56D0 /* CustomValidationToolbarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741482E9372DF00AB56D0 /* CustomValidationToolbarItem.swift */; };
- 553742252E9372DF00AB56D0 /* VisibleItem+Sort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740732E9372DF00AB56D0 /* VisibleItem+Sort.swift */; };
- 553742262E9372DF00AB56D0 /* LineNumberTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FBF2E9372DF00AB56D0 /* LineNumberTableCellView.swift */; };
- 553742272E9372DF00AB56D0 /* FilesWindowController+Slider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FD62E9372DF00AB56D0 /* FilesWindowController+Slider.swift */; };
- 553742282E9372DF00AB56D0 /* VDDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FA82E9372DF00AB56D0 /* VDDocument.swift */; };
- 553742292E9372DF00AB56D0 /* FilesWindowController+Read.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FD42E9372DF00AB56D0 /* FilesWindowController+Read.swift */; };
- 5537422A2E9372DF00AB56D0 /* PowerAssertion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741352E9372DF00AB56D0 /* PowerAssertion.swift */; };
- 5537422C2E9372DF00AB56D0 /* FilesWindowController+UISetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FD92E9372DF00AB56D0 /* FilesWindowController+UISetup.swift */; };
- 5537422D2E9372DF00AB56D0 /* CompareUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741332E9372DF00AB56D0 /* CompareUtil.swift */; };
- 5537422E2E9372DF00AB56D0 /* DisplayFiltersScopeBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FF42E9372DF00AB56D0 /* DisplayFiltersScopeBar.swift */; };
- 5537422F2E9372DF00AB56D0 /* HistorySessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FAC2E9372DF00AB56D0 /* HistorySessionManager.swift */; };
- 553742302E9372DF00AB56D0 /* FilePanelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FBB2E9372DF00AB56D0 /* FilePanelView.swift */; };
- 553742312E9372DF00AB56D0 /* FilesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FC52E9372DF00AB56D0 /* FilesWindowController.swift */; };
- 553742322E9372DF00AB56D0 /* FilesWindowController+MenuDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FCF2E9372DF00AB56D0 /* FilesWindowController+MenuDelegate.swift */; };
- 553742332E9372DF00AB56D0 /* DifferenceCounters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537416B2E9372DF00AB56D0 /* DifferenceCounters.swift */; };
- 553742342E9372DF00AB56D0 /* ReplaceFileAttributeKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740042E9372DF00AB56D0 /* ReplaceFileAttributeKey.swift */; };
- 553742352E9372DF00AB56D0 /* FoldersWindowController+Select.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740302E9372DF00AB56D0 /* FoldersWindowController+Select.swift */; };
- 553742362E9372DF00AB56D0 /* FoldersWindowController+Comparison.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740212E9372DF00AB56D0 /* FoldersWindowController+Comparison.swift */; };
- 553742372E9372DF00AB56D0 /* PathView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741712E9372DF00AB56D0 /* PathView.swift */; };
- 553742382E9372DF00AB56D0 /* DiffLine+Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FDB2E9372DF00AB56D0 /* DiffLine+Color.swift */; };
- 553742392E9372DF00AB56D0 /* FileDropView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741552E9372DF00AB56D0 /* FileDropView.swift */; };
- 5537423A2E9372DF00AB56D0 /* PreferredEditorPopupCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537413D2E9372DF00AB56D0 /* PreferredEditorPopupCell.swift */; };
- 5537423B2E9372DF00AB56D0 /* FilePanelView+File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FBC2E9372DF00AB56D0 /* FilePanelView+File.swift */; };
- 5537423C2E9372DF00AB56D0 /* KeyboardDocumentBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537409B2E9372DF00AB56D0 /* KeyboardDocumentBox.swift */; };
- 5537423D2E9372DF00AB56D0 /* FoldersOutlineView+VisibleItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FEE2E9372DF00AB56D0 /* FoldersOutlineView+VisibleItem.swift */; };
- 5537423E2E9372DF00AB56D0 /* FileNameCaseBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740AE2E9372DF00AB56D0 /* FileNameCaseBox.swift */; };
- 5537423F2E9372DF00AB56D0 /* URL+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741112E9372DF00AB56D0 /* URL+Metadata.swift */; };
- 553742402E9372DF00AB56D0 /* FoldersWindowController+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740292E9372DF00AB56D0 /* FoldersWindowController+Menu.swift */; };
- 553742412E9372DF00AB56D0 /* OperationSummaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740192E9372DF00AB56D0 /* OperationSummaryView.swift */; };
- 553742422E9372DF00AB56D0 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373F8D2E9372DF00AB56D0 /* AppDelegate.swift */; };
- 553742432E9372DF00AB56D0 /* ExpressionBox+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740AD2E9372DF00AB56D0 /* ExpressionBox+Menu.swift */; };
- 553742442E9372DF00AB56D0 /* FilesWindowController+PathControlDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FD32E9372DF00AB56D0 /* FilesWindowController+PathControlDelegate.swift */; };
- 553742452E9372DF00AB56D0 /* VisibleItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537406F2E9372DF00AB56D0 /* VisibleItem.swift */; };
- 553742462E9372DF00AB56D0 /* DiffChangeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FDE2E9372DF00AB56D0 /* DiffChangeType.swift */; };
- 553742472E9372DF00AB56D0 /* NotificationCenter+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373F942E9372DF00AB56D0 /* NotificationCenter+Helper.swift */; };
- 553742482E9372DF00AB56D0 /* NSImage+Tint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740F52E9372DF00AB56D0 /* NSImage+Tint.swift */; };
- 553742492E9372DF00AB56D0 /* NSButton+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741192E9372DF00AB56D0 /* NSButton+Helper.swift */; };
- 5537424A2E9372DF00AB56D0 /* FoldersWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537401F2E9372DF00AB56D0 /* FoldersWindowController.swift */; };
- 5537424B2E9372DF00AB56D0 /* VisibleItem+Find.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740702E9372DF00AB56D0 /* VisibleItem+Find.swift */; };
- 5537424C2E9372DF00AB56D0 /* String+Highlights.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741042E9372DF00AB56D0 /* String+Highlights.swift */; };
- 5537424D2E9372DF00AB56D0 /* SyncItemsInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537400E2E9372DF00AB56D0 /* SyncItemsInfo.swift */; };
- 5537424E2E9372DF00AB56D0 /* FileOperationManager+FileOperationManagerAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537403D2E9372DF00AB56D0 /* FileOperationManager+FileOperationManagerAction.swift */; };
- 5537424F2E9372DF00AB56D0 /* NoodleCustomImageRep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741302E9372DF00AB56D0 /* NoodleCustomImageRep.swift */; };
- 553742502E9372DF00AB56D0 /* FoldersWindowController+FileSystemControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740262E9372DF00AB56D0 /* FoldersWindowController+FileSystemControllerDelegate.swift */; };
- 553742512E9372DF00AB56D0 /* FilesWindowController+NSWindowDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FD22E9372DF00AB56D0 /* FilesWindowController+NSWindowDelegate.swift */; };
- 553742522E9372DF00AB56D0 /* FilesWindowController+Navigate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FD02E9372DF00AB56D0 /* FilesWindowController+Navigate.swift */; };
- 553742532E9372DF00AB56D0 /* DiffCountersItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741692E9372DF00AB56D0 /* DiffCountersItem.swift */; };
- 553742542E9372DF00AB56D0 /* SaveFileAccessoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FC22E9372DF00AB56D0 /* SaveFileAccessoryView.swift */; };
- 553742552E9372DF00AB56D0 /* FileThumbnailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FBE2E9372DF00AB56D0 /* FileThumbnailView.swift */; };
- 553742562E9372DF00AB56D0 /* FilesTableView+EditorData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FE12E9372DF00AB56D0 /* FilesTableView+EditorData.swift */; };
- 553742572E9372DF00AB56D0 /* ComparatorPopUpButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741652E9372DF00AB56D0 /* ComparatorPopUpButtonCell.swift */; };
- 553742582E9372DF00AB56D0 /* IntegerFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537412D2E9372DF00AB56D0 /* IntegerFormatter.swift */; };
- 553742592E9372DF00AB56D0 /* SessionDiff+ResolvePath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FB22E9372DF00AB56D0 /* SessionDiff+ResolvePath.swift */; };
- 5537425A2E9372DF00AB56D0 /* CompareItem+NSTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FF12E9372DF00AB56D0 /* CompareItem+NSTableCellView.swift */; };
- 5537425B2E9372DF00AB56D0 /* DocumentError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FA52E9372DF00AB56D0 /* DocumentError.swift */; };
- 5537425C2E9372DF00AB56D0 /* FolderSelectionInfo+FileSystemActionValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537406A2E9372DF00AB56D0 /* FolderSelectionInfo+FileSystemActionValidator.swift */; };
- 5537425D2E9372DF00AB56D0 /* FoldersWindowController+Exclude.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740252E9372DF00AB56D0 /* FoldersWindowController+Exclude.swift */; };
- 5537425E2E9372DF00AB56D0 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740872E9372DF00AB56D0 /* Preferences.swift */; };
- 5537425F2E9372DF00AB56D0 /* OutlineViewItemDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740342E9372DF00AB56D0 /* OutlineViewItemDelegate.swift */; };
- 553742622E9372DF00AB56D0 /* TableViewContextMenuDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741432E9372DF00AB56D0 /* TableViewContextMenuDelegate.swift */; };
- 553742632E9372DF00AB56D0 /* NSPredicate+Objc.m in Sources */ = {isa = PBXBuildFile; fileRef = 553740D52E9372DF00AB56D0 /* NSPredicate+Objc.m */; };
- 553742642E9372DF00AB56D0 /* FileSummaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740172E9372DF00AB56D0 /* FileSummaryView.swift */; };
- 553742652E9372DF00AB56D0 /* CompareItemTableRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FF72E9372DF00AB56D0 /* CompareItemTableRowView.swift */; };
- 553742662E9372DF00AB56D0 /* FolderSelectionInfo+FolderActionValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537406C2E9372DF00AB56D0 /* FolderSelectionInfo+FolderActionValidator.swift */; };
- 553742672E9372DF00AB56D0 /* CommonPrefs+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373F9C2E9372DF00AB56D0 /* CommonPrefs+Helper.swift */; };
- 553742682E9372DF00AB56D0 /* FilePathTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741672E9372DF00AB56D0 /* FilePathTableCellView.swift */; };
- 553742692E9372DF00AB56D0 /* AttributedMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741372E9372DF00AB56D0 /* AttributedMenuItem.swift */; };
- 5537426A2E9372DF00AB56D0 /* URL+StructuredContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741142E9372DF00AB56D0 /* URL+StructuredContent.swift */; };
- 5537426B2E9372DF00AB56D0 /* SessionPreferencesComparisonPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740B12E9372DF00AB56D0 /* SessionPreferencesComparisonPanel.swift */; };
- 5537426C2E9372DF00AB56D0 /* FolderCompareInfoWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740762E9372DF00AB56D0 /* FolderCompareInfoWindow.swift */; };
- 5537426D2E9372DF00AB56D0 /* NSToolbarItem+Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537410D2E9372DF00AB56D0 /* NSToolbarItem+Create.swift */; };
- 5537426E2E9372DF00AB56D0 /* MoveFileOperationExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FFF2E9372DF00AB56D0 /* MoveFileOperationExecutor.swift */; };
- 5537426F2E9372DF00AB56D0 /* URL+FileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537410F2E9372DF00AB56D0 /* URL+FileManager.swift */; };
- 553742712E9372DF00AB56D0 /* ConfirmationsDocumentsBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740892E9372DF00AB56D0 /* ConfirmationsDocumentsBox.swift */; };
- 553742722E9372DF00AB56D0 /* ExpressionBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740AC2E9372DF00AB56D0 /* ExpressionBox.swift */; };
- 553742732E9372DF00AB56D0 /* CompareItem+LeafPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FF02E9372DF00AB56D0 /* CompareItem+LeafPath.swift */; };
- 553742742E9372DF00AB56D0 /* SessionDiff.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FAE2E9372DF00AB56D0 /* SessionDiff.swift */; };
- 553742762E9372DF00AB56D0 /* TimeToleranceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741742E9372DF00AB56D0 /* TimeToleranceView.swift */; };
- 553742782E9372DF00AB56D0 /* FoldersOutlineView+Enumerate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FEA2E9372DF00AB56D0 /* FoldersOutlineView+Enumerate.swift */; };
- 553742792E9372DF00AB56D0 /* HistoryController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537407A2E9372DF00AB56D0 /* HistoryController.swift */; };
- 5537427A2E9372DF00AB56D0 /* ConsoleToolbarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537414F2E9372DF00AB56D0 /* ConsoleToolbarView.swift */; };
- 5537427B2E9372DF00AB56D0 /* HistorySearchField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537407D2E9372DF00AB56D0 /* HistorySearchField.swift */; };
- 5537427C2E9372DF00AB56D0 /* URL+ResourceFork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741132E9372DF00AB56D0 /* URL+ResourceFork.swift */; };
- 5537427D2E9372DF00AB56D0 /* LinkButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537414C2E9372DF00AB56D0 /* LinkButton.swift */; };
- 5537427E2E9372DF00AB56D0 /* ReplaceInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537400A2E9372DF00AB56D0 /* ReplaceInfoView.swift */; };
- 5537427F2E9372DF00AB56D0 /* NSAlert+DirtyFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FC12E9372DF00AB56D0 /* NSAlert+DirtyFiles.swift */; };
- 553742802E9372DF00AB56D0 /* CommonPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373F982E9372DF00AB56D0 /* CommonPrefs.swift */; };
- 553742812E9372DF00AB56D0 /* FilesWindowController+LinesDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FCD2E9372DF00AB56D0 /* FilesWindowController+LinesDetail.swift */; };
- 553742822E9372DF00AB56D0 /* FileOperationManager+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537403E2E9372DF00AB56D0 /* FileOperationManager+Util.swift */; };
- 553742832E9372DF00AB56D0 /* ConsoleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741502E9372DF00AB56D0 /* ConsoleView.swift */; };
- 553742842E9372DF00AB56D0 /* CommonPrefs+DifferenceNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740592E9372DF00AB56D0 /* CommonPrefs+DifferenceNavigator.swift */; };
- 553742852E9372DF00AB56D0 /* FileOperationExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740162E9372DF00AB56D0 /* FileOperationExecutor.swift */; };
- 553742862E9372DF00AB56D0 /* AlignmentPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740A92E9372DF00AB56D0 /* AlignmentPanel.swift */; };
- 553742872E9372DF00AB56D0 /* FoldersOutlineView+ExternalApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FEB2E9372DF00AB56D0 /* FoldersOutlineView+ExternalApp.swift */; };
- 553742882E9372DF00AB56D0 /* PreferencesPanelDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740B92E9372DF00AB56D0 /* PreferencesPanelDataSource.swift */; };
- 553742892E9372DF00AB56D0 /* DiffCountersTextFieldCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537416A2E9372DF00AB56D0 /* DiffCountersTextFieldCell.swift */; };
- 5537428A2E9372DF00AB56D0 /* FoldersWindowController+FoldersOutlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740272E9372DF00AB56D0 /* FoldersWindowController+FoldersOutlineView.swift */; };
- 5537428B2E9372DF00AB56D0 /* TableViewCommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741422E9372DF00AB56D0 /* TableViewCommon.swift */; };
- 5537428C2E9372DF00AB56D0 /* CompareItem+Path.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740562E9372DF00AB56D0 /* CompareItem+Path.swift */; };
- 5537428D2E9372DF00AB56D0 /* FolderPreferencesPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537408F2E9372DF00AB56D0 /* FolderPreferencesPanel.swift */; };
- 5537428E2E9372DF00AB56D0 /* FileOperationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537403C2E9372DF00AB56D0 /* FileOperationManager.swift */; };
- 5537428F2E9372DF00AB56D0 /* StandardUserPreferencesBoxDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740842E9372DF00AB56D0 /* StandardUserPreferencesBoxDataSource.swift */; };
- 553742902E9372DF00AB56D0 /* SecureBookmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741262E9372DF00AB56D0 /* SecureBookmark.swift */; };
- 553742912E9372DF00AB56D0 /* FilesScopeBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FBD2E9372DF00AB56D0 /* FilesScopeBar.swift */; };
- 553742922E9372DF00AB56D0 /* OpenEditorAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537413A2E9372DF00AB56D0 /* OpenEditorAttribute.swift */; };
- 553742932E9372DF00AB56D0 /* WindowCancelOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537415F2E9372DF00AB56D0 /* WindowCancelOperation.swift */; };
- 553742942E9372DF00AB56D0 /* VisibleItem+QLPreviewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740722E9372DF00AB56D0 /* VisibleItem+QLPreviewItem.swift */; };
- 553742952E9372DF00AB56D0 /* FilesWindowController+FilesTableViewContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FCB2E9372DF00AB56D0 /* FilesWindowController+FilesTableViewContextMenu.swift */; };
- 553742962E9372DF00AB56D0 /* FolderSelectionInfo+CompareActionValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740692E9372DF00AB56D0 /* FolderSelectionInfo+CompareActionValidator.swift */; };
- 553742982E9372DF00AB56D0 /* DiffCountersItem+DiffResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FE02E9372DF00AB56D0 /* DiffCountersItem+DiffResult.swift */; };
- 553742992E9372DF00AB56D0 /* FileOperationManagerDelegateImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740082E9372DF00AB56D0 /* FileOperationManagerDelegateImpl.swift */; };
- 5537429A2E9372DF00AB56D0 /* SessionDiff+AlignRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FAF2E9372DF00AB56D0 /* SessionDiff+AlignRule.swift */; };
- 5537429B2E9372DF00AB56D0 /* FoldersWindowController+MenuDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537402A2E9372DF00AB56D0 /* FoldersWindowController+MenuDelegate.swift */; };
- 5537429D2E9372DF00AB56D0 /* FolderSelectionInfo+FilterActionValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537406B2E9372DF00AB56D0 /* FolderSelectionInfo+FilterActionValidator.swift */; };
- 5537429E2E9372DF00AB56D0 /* OpenDiffCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740E22E9372DF00AB56D0 /* OpenDiffCommand.swift */; };
- 5537429F2E9372DF00AB56D0 /* RenameCompareItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740432E9372DF00AB56D0 /* RenameCompareItem.swift */; };
- 553742A02E9372DF00AB56D0 /* DisplayOptions+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537404C2E9372DF00AB56D0 /* DisplayOptions+Helper.swift */; };
- 553742A12E9372DF00AB56D0 /* SessionPreferencesWindow+Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740A72E9372DF00AB56D0 /* SessionPreferencesWindow+Data.swift */; };
- 553742A22E9372DF00AB56D0 /* FolderReader+Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537405F2E9372DF00AB56D0 /* FolderReader+Log.swift */; };
- 553742A32E9372DF00AB56D0 /* NSArrayController+Paths.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FA02E9372DF00AB56D0 /* NSArrayController+Paths.swift */; };
- 553742A42E9372DF00AB56D0 /* NSPredicateEditor+Fix.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741012E9372DF00AB56D0 /* NSPredicateEditor+Fix.swift */; };
- 553742A52E9372DF00AB56D0 /* FoldersWindowController+NSToolbarDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537402C2E9372DF00AB56D0 /* FoldersWindowController+NSToolbarDelegate.swift */; };
- 553742A62E9372DF00AB56D0 /* NSAlert+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740FB2E9372DF00AB56D0 /* NSAlert+Helper.swift */; };
- 553742A72E9372DF00AB56D0 /* FoldersWindowController+NSWindowDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537402D2E9372DF00AB56D0 /* FoldersWindowController+NSWindowDelegate.swift */; };
- 553742A82E9372DF00AB56D0 /* FilesWindowController+FilesScopeBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FCA2E9372DF00AB56D0 /* FilesWindowController+FilesScopeBar.swift */; };
- 553742A92E9372DF00AB56D0 /* NSManagedObjectContext+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740EB2E9372DF00AB56D0 /* NSManagedObjectContext+Helpers.swift */; };
- 553742AA2E9372DF00AB56D0 /* String+Path.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741062E9372DF00AB56D0 /* String+Path.swift */; };
- 553742AB2E9372DF00AB56D0 /* TimeInterval+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740ED2E9372DF00AB56D0 /* TimeInterval+Helper.swift */; };
- 553742AC2E9372DF00AB56D0 /* ColorScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373F902E9372DF00AB56D0 /* ColorScheme.swift */; };
- 553742AD2E9372DF00AB56D0 /* FilesWindowController+Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FC82E9372DF00AB56D0 /* FilesWindowController+Document.swift */; };
- 553742AE2E9372DF00AB56D0 /* PathControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741702E9372DF00AB56D0 /* PathControl.swift */; };
- 553742AF2E9372DF00AB56D0 /* TouchController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740122E9372DF00AB56D0 /* TouchController.swift */; };
- 553742B02E9372DF00AB56D0 /* CompletionIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740062E9372DF00AB56D0 /* CompletionIndicator.swift */; };
- 553742B12E9372DF00AB56D0 /* FoldersWindowController+UISetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740332E9372DF00AB56D0 /* FoldersWindowController+UISetup.swift */; };
- 553742B22E9372DF00AB56D0 /* NSTableView+Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741092E9372DF00AB56D0 /* NSTableView+Font.swift */; };
- 553742B32E9372DF00AB56D0 /* ActionBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537414A2E9372DF00AB56D0 /* ActionBarView.swift */; };
- 553742B42E9372DF00AB56D0 /* TouchCompareItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740442E9372DF00AB56D0 /* TouchCompareItem.swift */; };
- 553742B52E9372DF00AB56D0 /* HistoryFetchedResultsControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537407C2E9372DF00AB56D0 /* HistoryFetchedResultsControllerDelegate.swift */; };
- 553742B62E9372DF00AB56D0 /* CommonPrefs+Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373F9B2E9372DF00AB56D0 /* CommonPrefs+Font.swift */; };
- 553742B72E9372DF00AB56D0 /* NSWorkspace+Finder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741232E9372DF00AB56D0 /* NSWorkspace+Finder.swift */; };
- 553742B82E9372DF00AB56D0 /* FoldersOutlineViewFindTextDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FEF2E9372DF00AB56D0 /* FoldersOutlineViewFindTextDelegate.swift */; };
- 553742B92E9372DF00AB56D0 /* AlignTestResultBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740AB2E9372DF00AB56D0 /* AlignTestResultBox.swift */; };
- 553742BA2E9372DF00AB56D0 /* VisibleItem+Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740712E9372DF00AB56D0 /* VisibleItem+Log.swift */; };
- 553742BB2E9372DF00AB56D0 /* HistoryTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537407E2E9372DF00AB56D0 /* HistoryTableView.swift */; };
- 553742BC2E9372DF00AB56D0 /* SessionDiff+NSSortDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FB12E9372DF00AB56D0 /* SessionDiff+NSSortDescriptor.swift */; };
- 553742BD2E9372DF00AB56D0 /* NSPopUpButton+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537411A2E9372DF00AB56D0 /* NSPopUpButton+Helper.swift */; };
- 553742BE2E9372DF00AB56D0 /* NSColor+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740E92E9372DF00AB56D0 /* NSColor+Hex.swift */; };
- 553742BF2E9372DF00AB56D0 /* FileInfoBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FBA2E9372DF00AB56D0 /* FileInfoBar.swift */; };
- 553742C02E9372DF00AB56D0 /* TitlePredicateEditorRowTemplate.m in Sources */ = {isa = PBXBuildFile; fileRef = 553740D72E9372DF00AB56D0 /* TitlePredicateEditorRowTemplate.m */; };
- 553742C12E9372DF00AB56D0 /* ErrorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740072E9372DF00AB56D0 /* ErrorsView.swift */; };
- 553742C22E9372DF00AB56D0 /* IconUtils+CompareItemIconUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FF22E9372DF00AB56D0 /* IconUtils+CompareItemIconUtils.swift */; };
- 553742C32E9372DF00AB56D0 /* SessionTypeError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FA72E9372DF00AB56D0 /* SessionTypeError.swift */; };
- 553742C42E9372DF00AB56D0 /* FoldersOutlineView+FileCount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FEC2E9372DF00AB56D0 /* FoldersOutlineView+FileCount.swift */; };
- 553742C52E9372DF00AB56D0 /* SessionPreferencesFiltersPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740B52E9372DF00AB56D0 /* SessionPreferencesFiltersPanel.swift */; };
- 553742C62E9372DF00AB56D0 /* FoldersWindowController+DisplayFiltersScopeBarDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740232E9372DF00AB56D0 /* FoldersWindowController+DisplayFiltersScopeBarDelegate.swift */; };
- 553742C72E9372DF00AB56D0 /* DiffCountersItem+CompareItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740372E9372DF00AB56D0 /* DiffCountersItem+CompareItem.swift */; };
- 553742C82E9372DF00AB56D0 /* DisplayFiltersPopUpButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741662E9372DF00AB56D0 /* DisplayFiltersPopUpButtonCell.swift */; };
- 553742C92E9372DF00AB56D0 /* NSEvent+VirtualKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537412A2E9372DF00AB56D0 /* NSEvent+VirtualKeys.swift */; };
- 553742CA2E9372DF00AB56D0 /* DescriptionOutlineNode+FolderCompareInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740752E9372DF00AB56D0 /* DescriptionOutlineNode+FolderCompareInfo.swift */; };
- 553742CB2E9372DF00AB56D0 /* WindowOSD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553741602E9372DF00AB56D0 /* WindowOSD.swift */; };
- 553742CC2E9372DF00AB56D0 /* NSPasteboard+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740FF2E9372DF00AB56D0 /* NSPasteboard+Helper.swift */; };
- 553742CD2E9372DF00AB56D0 /* ConfirmationsPreferencesPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537408C2E9372DF00AB56D0 /* ConfirmationsPreferencesPanel.swift */; };
- 553742CE2E9372DF00AB56D0 /* CompareItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537404F2E9372DF00AB56D0 /* CompareItem.swift */; };
- 553742CF2E9372DF00AB56D0 /* NSTextField+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537411E2E9372DF00AB56D0 /* NSTextField+Helper.swift */; };
- 553742D02E9372DF00AB56D0 /* FolderViewBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740912E9372DF00AB56D0 /* FolderViewBox.swift */; };
- 553742D12E9372DF00AB56D0 /* SessionDiff+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55373FB32E9372DF00AB56D0 /* SessionDiff+Types.swift */; };
- 553742D22E9372DF00AB56D0 /* FiltersPredicateEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553740B32E9372DF00AB56D0 /* FiltersPredicateEditor.swift */; };
- 553742D32E9372DF00AB56D0 /* HistoryEntityTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5537407B2E9372DF00AB56D0 /* HistoryEntityTableCellView.swift */; };
5537434E2E937B7F00AB56D0 /* VDDefaults.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5537434C2E937B7F00AB56D0 /* VDDefaults.plist */; };
5537434F2E937B7F00AB56D0 /* colors.json in Resources */ = {isa = PBXBuildFile; fileRef = 5537434A2E937B7F00AB56D0 /* colors.json */; };
553743502E937B7F00AB56D0 /* colorsDark.json in Resources */ = {isa = PBXBuildFile; fileRef = 5537434B2E937B7F00AB56D0 /* colorsDark.json */; };
@@ -355,114 +18,23 @@
5541CE482FFCD8DA0044A569 /* mask-back-white.png in Resources */ = {isa = PBXBuildFile; fileRef = 5541CE402FFCD8DA0044A569 /* mask-back-white.png */; };
5541CE492FFCD8DA0044A569 /* mask-back.png in Resources */ = {isa = PBXBuildFile; fileRef = 5541CE3F2FFCD8DA0044A569 /* mask-back.png */; };
5541CE4B2FFCD9E70044A569 /* vd.iconset in Resources */ = {isa = PBXBuildFile; fileRef = 5541CE4A2FFCD9E70044A569 /* vd.iconset */; };
- 55450B172ED4790B0048619F /* TextPreferencesPanel+PreferencesBoxDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55450B162ED4790B0048619F /* TextPreferencesPanel+PreferencesBoxDataSource.swift */; };
- 55450B192ED47B700048619F /* FileSessionPreferencesWindow+PreferencesBoxDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55450B182ED47B680048619F /* FileSessionPreferencesWindow+PreferencesBoxDataSource.swift */; };
- 554750C62F5C0A1100C1747A /* CommonAncestorPathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 554750C52F5C0A0A00C1747A /* CommonAncestorPathTests.swift */; };
- 5548ABA82F7FE2BB0064B964 /* LineDetailTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5548ABA72F7FE2BB0064B964 /* LineDetailTextView.swift */; };
- 554B4A452E9B7B8F0023AAF0 /* EndOfLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 554B4A3A2E9B7B8F0023AAF0 /* EndOfLine.swift */; };
- 554B4A462E9B7B8F0023AAF0 /* DiffSide.swift in Sources */ = {isa = PBXBuildFile; fileRef = 554B4A402E9B7B8F0023AAF0 /* DiffSide.swift */; };
- 554B4A472E9B7B8F0023AAF0 /* DiffSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 554B4A412E9B7B8F0023AAF0 /* DiffSection.swift */; };
- 554B4A482E9B7B8F0023AAF0 /* DiffResult+Dump.swift in Sources */ = {isa = PBXBuildFile; fileRef = 554B4A3D2E9B7B8F0023AAF0 /* DiffResult+Dump.swift */; };
- 554B4A4A2E9B7B8F0023AAF0 /* DiffResult+Section.swift in Sources */ = {isa = PBXBuildFile; fileRef = 554B4A3F2E9B7B8F0023AAF0 /* DiffResult+Section.swift */; };
- 554B4A4B2E9B7B8F0023AAF0 /* DiffResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 554B4A3B2E9B7B8F0023AAF0 /* DiffResult.swift */; };
- 554B4A4D2E9B7B8F0023AAF0 /* DiffResult+Lines.swift in Sources */ = {isa = PBXBuildFile; fileRef = 554B4A3E2E9B7B8F0023AAF0 /* DiffResult+Lines.swift */; };
- 554B4A4E2E9B7B8F0023AAF0 /* DiffLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 554B4A432E9B7B8F0023AAF0 /* DiffLine.swift */; };
5550B5931A21CD1F009BC4A4 /* aliasbadge@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5550B5921A21CD1F009BC4A4 /* aliasbadge@2x.png */; };
5550B5951A21D2F3009BC4A4 /* empty@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5550B5941A21D2F3009BC4A4 /* empty@2x.png */; };
557315B12551307800CF4372 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 557315B02551307800CF4372 /* Images.xcassets */; };
55740BF512D710EC004BF6CC /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55740BF412D710EC004BF6CC /* IOKit.framework */; };
55740BF912D71103004BF6CC /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55740BF812D71103004BF6CC /* Security.framework */; };
- 5577FFE82FAF2FC30084FB06 /* PopUpButtonURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5577FFE72FAF2FC30084FB06 /* PopUpButtonURL.swift */; };
557A47F22FF7DE3800D0F6B4 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 557A47F12FF7DE3800D0F6B4 /* Localizable.xcstrings */; };
- 557BBB0E2ED1BBB00016CBD4 /* DiffLineComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557BBB0D2ED1BBB00016CBD4 /* DiffLineComponent.swift */; };
- 557C18182E7E6E0100381A3A /* big_file_5000_lines.txt in Resources */ = {isa = PBXBuildFile; fileRef = 557C18162E7E6E0100381A3A /* big_file_5000_lines.txt */; };
- 557C18232E7E8C0D00381A3A /* Signing.local.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 557C18212E7E8C0D00381A3A /* Signing.local.xcconfig */; };
- 557C18242E7E8C0D00381A3A /* Versions.local.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 557C18222E7E8C0D00381A3A /* Versions.local.xcconfig */; };
- 557C18252E7E8C0D00381A3A /* AppConfig.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 557C18202E7E8C0D00381A3A /* AppConfig.xcconfig */; };
- 55858304300DD8B100EDC56C /* DiffResult.Options+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55858303300DD8B100EDC56C /* DiffResult.Options+Description.swift */; };
- 55858306300DE12E00EDC56C /* ScopeBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55858305300DE12E00EDC56C /* ScopeBarView.swift */; };
- 558DEAC62EA263DE00F05A10 /* CFStringEncoding+StringEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558DEAC42EA263DE00F05A10 /* CFStringEncoding+StringEncoding.swift */; };
- 558DEACB2EA263F500F05A10 /* EncodingManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558DEAC72EA263F500F05A10 /* EncodingManager.swift */; };
- 558DEACC2EA263F500F05A10 /* SelectEncodingsPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558DEAC92EA263F500F05A10 /* SelectEncodingsPanel.swift */; };
- 558DEACD2EA263F500F05A10 /* EncodingPopUpButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558DEAC82EA263F500F05A10 /* EncodingPopUpButtonCell.swift */; };
- 558DEAD02EA2642100F05A10 /* NSWindow+Editing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558DEACE2EA2642100F05A10 /* NSWindow+Editing.swift */; };
- 558DEAD22EA26C5B00F05A10 /* Logger+App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558DEAD12EA26C5800F05A10 /* Logger+App.swift */; };
+ 557EBD89305AC79D00A9BBD2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 557EBD88305AC79D00A9BBD2 /* Cocoa.framework */; };
55916A102E8A814200ED6629 /* MyDocument.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 55916A092E8A814200ED6629 /* MyDocument.xcdatamodeld */; };
55916A112E8A814200ED6629 /* History.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 55916A082E8A814200ED6629 /* History.xcdatamodeld */; };
- 559186412E9B821B00A30620 /* DiffSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559186402E9B821B00A30620 /* DiffSummary.swift */; };
- 5595901D2EABA7FE00B5AB0B /* CompareSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5595901C2EABA7FE00B5AB0B /* CompareSummary.swift */; };
- 5595901F2EABA8A100B5AB0B /* CompareChangeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5595901E2EABA8A100B5AB0B /* CompareChangeType.swift */; };
- 559590212EABAFC200B5AB0B /* SessionDiff+ItemComparator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559590202EABAFC200B5AB0B /* SessionDiff+ItemComparator.swift */; };
- 559590262EABB06100B5AB0B /* ItemComparator+AlignRegularExpression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559590242EABB06100B5AB0B /* ItemComparator+AlignRegularExpression.swift */; };
- 559590272EABB06100B5AB0B /* ItemComparator+Align.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559590232EABB06100B5AB0B /* ItemComparator+Align.swift */; };
- 559590282EABB06100B5AB0B /* ItemComparator+Compare.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559590252EABB06100B5AB0B /* ItemComparator+Compare.swift */; };
- 559590292EABB06100B5AB0B /* ItemComparator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 559590222EABB06100B5AB0B /* ItemComparator.swift */; };
- 5595902B2EABB15F00B5AB0B /* MockItemComparatorDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5595902A2EABB15F00B5AB0B /* MockItemComparatorDelegate.swift */; };
559614B114B0471E0075ED34 /* aliasbadge.png in Resources */ = {isa = PBXBuildFile; fileRef = 559614B014B0471E0075ED34 /* aliasbadge.png */; };
55A027D4158242310004583F /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55A027D3158242310004583F /* Quartz.framework */; };
- 55A4DF322E9A49B000ED11BB /* EndOfLineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55A4DF312E9A49A700ED11BB /* EndOfLineTests.swift */; };
- 55A4DF342FFD200100ED11BB /* DiffSideTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55A4DF332FFD1FFF00ED11BB /* DiffSideTests.swift */; };
- 55A585772F52BD8A006DD544 /* FileOperationDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55A585762F52BD88006DD544 /* FileOperationDestination.swift */; };
- 55B1CE2B2E9934E900426FEC /* DateBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B1CE2A2E9934E900426FEC /* DateBuilder.swift */; };
- 55B1CE312E9934F800426FEC /* DiffResultBaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B1CE2E2E9934F800426FEC /* DiffResultBaseTests.swift */; };
- 55B1CE322E9934F800426FEC /* DiffResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B1CE2C2E9934F800426FEC /* DiffResultTests.swift */; };
- 55B93A452FAC42950024AEC0 /* DiffProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B93A442FAC42910024AEC0 /* DiffProcessor.swift */; };
- 55B9B73E2F5C26F800DB8326 /* BaseTests+CompareItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B9B73D2F5C26F800DB8326 /* BaseTests+CompareItem.swift */; };
- 55BC333E2EDAC69C004035A0 /* RowHeightCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55BC333D2EDAC69C004035A0 /* RowHeightCalculator.swift */; };
- 55BC33402EDAC96F004035A0 /* TiledImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55BC333F2EDAC96F004035A0 /* TiledImageView.swift */; };
- 55BC33432EDACB09004035A0 /* FilesWindowController+RowHeightDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55BC33412EDACB09004035A0 /* FilesWindowController+RowHeightDataSource.swift */; };
- 55BC33442EDACB09004035A0 /* FilesWindowController+SplitViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55BC33422EDACB09004035A0 /* FilesWindowController+SplitViewDelegate.swift */; };
- 55BCFE472F627DDF00E704D8 /* SessionPopupButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55BCFE462F627DDF00E704D8 /* SessionPopupButton.swift */; };
55C165622EE444050082A24C /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 55C165612EE444050082A24C /* Sparkle */; };
- 55C1CBFD2E8BB6AD004FE322 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C1CBF42E8BB6AD004FE322 /* main.swift */; };
55C1CC012E8BB755004FE322 /* visdiff in Copy Visdiff to Helpers */ = {isa = PBXBuildFile; fileRef = 55C1CBE22E8BB6A2004FE322 /* visdiff */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
- 55C1CC072E8BBD85004FE322 /* DocumentWaiter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C1CC062E8BBAD1004FE322 /* DocumentWaiter.swift */; };
55C84A712DA93ADB00BA39DA /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55C84A702DA93ADB00BA39DA /* UserNotifications.framework */; };
- 55CE5BC62FFCBC8500B0F3F5 /* VDSymbol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55CE5BC52FFCBC8500B0F3F5 /* VDSymbol.swift */; };
- 55D352E72EFD0C5B00C944D5 /* FileSystemTestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55D352E62EFD0C4D00C944D5 /* FileSystemTestHelper.swift */; };
- 55D71FD62EE584B7007E0FA0 /* AppUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55D71FD52EE584B7007E0FA0 /* AppUpdater.swift */; };
- 55D8812E2F3DA332008DE497 /* CopyFinderMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55D8812D2F3DA329008DE497 /* CopyFinderMetadata.swift */; };
- 55DF3DD22E924BB10044CC0C /* BaseTests+FileSystemOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DC52E924BB10044CC0C /* BaseTests+FileSystemOperations.swift */; };
- 55DF3DD32E924BB10044CC0C /* FiltersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DBF2E924BB10044CC0C /* FiltersTests.swift */; };
- 55DF3DD42E924BB10044CC0C /* LeafPathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DC82E924BB10044CC0C /* LeafPathTests.swift */; };
- 55DF3DD52E924BB10044CC0C /* DeleteFileTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DBC2E924BB10044CC0C /* DeleteFileTests.swift */; };
- 55DF3DD62E924BB10044CC0C /* TagsCopyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DB32E924BB10044CC0C /* TagsCopyTests.swift */; };
- 55DF3DD82E924BB10044CC0C /* CopyFilesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DBB2E924BB10044CC0C /* CopyFilesTests.swift */; };
- 55DF3DD92E924BB10044CC0C /* StringUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DCE2E924BB10044CC0C /* StringUtils.swift */; };
- 55DF3DDB2E924BB10044CC0C /* BufferedInputStreamTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DB92E924BB10044CC0C /* BufferedInputStreamTests.swift */; };
- 55DF3DDC2E924BB10044CC0C /* TagsMoveTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DB62E924BB10044CC0C /* TagsMoveTests.swift */; };
- 55DF3DDD2E924BB10044CC0C /* CaseSensitiveBaseTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DC62E924BB10044CC0C /* CaseSensitiveBaseTest.swift */; };
- 55DF3DDE2E924BB10044CC0C /* BaseTests+AssertCompareItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DAA2E924BB10044CC0C /* BaseTests+AssertCompareItem.swift */; };
- 55DF3DDF2E924BB10044CC0C /* AlignmentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DB82E924BB10044CC0C /* AlignmentTests.swift */; };
- 55DF3DE02E924BB10044CC0C /* RefreshInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DCB2E924BB10044CC0C /* RefreshInfoTests.swift */; };
- 55DF3DE12E924BB10044CC0C /* EmptyFolderColorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DBE2E924BB10044CC0C /* EmptyFolderColorTests.swift */; };
- 55DF3DE22E924BB10044CC0C /* BaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DA92E924BB10044CC0C /* BaseTests.swift */; };
- 55DF3DE32E924BB10044CC0C /* FoldersWindowControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DCA2E924BB10044CC0C /* FoldersWindowControllerTests.swift */; };
- 55DF3DE42E924BB10044CC0C /* TagsDeleteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DB52E924BB10044CC0C /* TagsDeleteTests.swift */; };
- 55DF3DE52E924BB10044CC0C /* ComparatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DBA2E924BB10044CC0C /* ComparatorTests.swift */; };
- 55DF3DE62E924BB10044CC0C /* TouchFilesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DC22E924BB10044CC0C /* TouchFilesTests.swift */; };
- 55DF3DE72E924BB10044CC0C /* DisplayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DBD2E924BB10044CC0C /* DisplayTests.swift */; };
- 55DF3DE82E924BB10044CC0C /* BaseTests+AssertFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DC42E924BB10044CC0C /* BaseTests+AssertFileSystem.swift */; };
- 55DF3DE92E924BB10044CC0C /* LabelsCreateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DB12E924BB10044CC0C /* LabelsCreateTests.swift */; };
- 55DF3DEA2E924BB10044CC0C /* MockFileOperationManagerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DAC2E924BB10044CC0C /* MockFileOperationManagerDelegate.swift */; };
- 55DF3DEB2E924BB10044CC0C /* LabelsMoveTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DB22E924BB10044CC0C /* LabelsMoveTests.swift */; };
- 55DF3DEC2E924BB10044CC0C /* MoveFilesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DC02E924BB10044CC0C /* MoveFilesTests.swift */; };
- 55DF3DED2E924BB10044CC0C /* TagsCreateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DB42E924BB10044CC0C /* TagsCreateTests.swift */; };
- 55DF3DEE2E924BB10044CC0C /* LabelsCopyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DB02E924BB10044CC0C /* LabelsCopyTests.swift */; };
- 55DF3DEF2E924BB10044CC0C /* MockFolderReaderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DAD2E924BB10044CC0C /* MockFolderReaderDelegate.swift */; };
- 55DF3DF02E924BB10044CC0C /* RenameFilesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DF3DC12E924BB10044CC0C /* RenameFilesTests.swift */; };
55E1029A12C9E17300432C61 /* empty.png in Resources */ = {isa = PBXBuildFile; fileRef = 55E1029912C9E17300432C61 /* empty.png */; };
- 55E381C12EEFFD0500CB2F00 /* SymbolicLinkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E381C02EEFFCF500CB2F00 /* SymbolicLinkTests.swift */; };
55E3A5661826552A002A890B /* lockedbadge.png in Resources */ = {isa = PBXBuildFile; fileRef = 55E3A5641826552A002A890B /* lockedbadge.png */; };
55E3A5671826552A002A890B /* lockedbadge@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 55E3A5651826552A002A890B /* lockedbadge@2x.png */; };
- 55EC0A4B2F3868E4008201E1 /* CopyFilesTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55EC0A4A2F3868E4008201E1 /* CopyFilesTag.swift */; };
- 55F42EE12F76798A009B211C /* CommonPrefs+FileDifferenceNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55F42EDF2F76798A009B211C /* CommonPrefs+FileDifferenceNavigator.swift */; };
- 55F4A0032FEE100000A1B2C3 /* ExternalFileOperationContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55F4A0012FEE100000A1B2C3 /* ExternalFileOperationContext.swift */; };
- 55F9BAF22FA7259B004EA543 /* FoldersWindowController+Observers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55F9BAF12FA7259B004EA543 /* FoldersWindowController+Observers.swift */; };
- 55F9E79A2EDD5DBD001218C7 /* DiffResult.Options.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55F9E7992EDD5DAD001218C7 /* DiffResult.Options.swift */; };
- 55F9E79C2EDD6221001218C7 /* WhitespacesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55F9E79B2EDD6221001218C7 /* WhitespacesTests.swift */; };
- 55FE894A2F054B260003864A /* FlagSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55FE89492F054B260003864A /* FlagSet.swift */; };
- 775DFF38067A968500C5B868 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */; };
8D15AC2C0486D014006FF6A4 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */; };
/* End PBXBuildFile section */
@@ -486,387 +58,24 @@
/* Begin PBXCopyFilesBuildPhase section */
5504B6FF255FCBBA00CDE04A /* Copy Visdiff to Helpers */ = {
isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
dstPath = Contents/Helpers;
- dstSubfolderSpec = 1;
+ dstSubfolder = Wrapper;
files = (
55C1CC012E8BB755004FE322 /* visdiff in Copy Visdiff to Helpers */,
);
name = "Copy Visdiff to Helpers";
- runOnlyForDeploymentPostprocessing = 0;
};
55943C852EE43E3800DE513B /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
- buildActionMask = 12;
dstPath = "";
- dstSubfolderSpec = 10;
+ dstSubfolder = Frameworks;
files = (
);
name = "Embed Frameworks";
- runOnlyForDeploymentPostprocessing = 0;
- };
- 55C1CBE02E8BB6A2004FE322 /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = /usr/share/man/man1/;
- dstSubfolderSpec = 0;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
- 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; };
- 2A37F4C4FDCFA73011CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; };
- 2A37F4C5FDCFA73011CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; };
- 32DBCF750370BD2300C91783 /* VisualDiffer_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VisualDiffer_Prefix.pch; sourceTree = ""; };
- 550A2CC113FF973B00981A9B /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = System/Library/Frameworks/ApplicationServices.framework; sourceTree = SDKROOT; };
- 551DE39E2ED422820067AB18 /* FilesWindowController+SessionPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+SessionPreferences.swift"; sourceTree = ""; };
- 551DE3A42ED4237B0067AB18 /* FileSessionPreferencesWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileSessionPreferencesWindow.swift; sourceTree = ""; };
- 551DE3A92ED428A50067AB18 /* FilePreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePreferences.swift; sourceTree = ""; };
- 551DE3B32ED42AD00067AB18 /* FilePreferencesComparisonPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePreferencesComparisonPanel.swift; sourceTree = ""; };
- 551DE3B52ED42B4E0067AB18 /* FileComparisonBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileComparisonBox.swift; sourceTree = ""; };
- 551DE3B72ED4399B0067AB18 /* PreferencesBoxDataSource+Default.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreferencesBoxDataSource+Default.swift"; sourceTree = ""; };
- 552430402F7673F800951F1A /* FileDifferenceNavigatorBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileDifferenceNavigatorBox.swift; sourceTree = ""; };
- 552B85072F5FE29400A9268A /* VDDocumentController+BlankDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VDDocumentController+BlankDocument.swift"; sourceTree = ""; };
- 553033AC2E5DBABF0016F101 /* VisualDiffer.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = VisualDiffer.xctestplan; sourceTree = SOURCE_ROOT; };
- 5536ADB92EF169820019EFBF /* SessionDiff+ExtraData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SessionDiff+ExtraData.swift"; sourceTree = ""; };
- 55373F8D2E9372DF00AB56D0 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
- 55373F8F2E9372DF00AB56D0 /* AlignRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlignRule.swift; sourceTree = ""; };
- 55373F902E9372DF00AB56D0 /* ColorScheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorScheme.swift; sourceTree = ""; };
- 55373F912E9372DF00AB56D0 /* DisplayPositionable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayPositionable.swift; sourceTree = ""; };
- 55373F932E9372DF00AB56D0 /* KeyEquivalent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyEquivalent.swift; sourceTree = ""; };
- 55373F942E9372DF00AB56D0 /* NotificationCenter+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NotificationCenter+Helper.swift"; sourceTree = ""; };
- 55373F962E9372DF00AB56D0 /* ViewLinkable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewLinkable.swift; sourceTree = ""; };
- 55373F982E9372DF00AB56D0 /* CommonPrefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonPrefs.swift; sourceTree = ""; };
- 55373F992E9372DF00AB56D0 /* CommonPrefs+FileCompare.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CommonPrefs+FileCompare.swift"; sourceTree = ""; };
- 55373F9A2E9372DF00AB56D0 /* CommonPrefs+FolderCompare.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CommonPrefs+FolderCompare.swift"; sourceTree = ""; };
- 55373F9B2E9372DF00AB56D0 /* CommonPrefs+Font.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CommonPrefs+Font.swift"; sourceTree = ""; };
- 55373F9C2E9372DF00AB56D0 /* CommonPrefs+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CommonPrefs+Helper.swift"; sourceTree = ""; };
- 55373F9D2E9372DF00AB56D0 /* CommonPrefs+Name.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CommonPrefs+Name.swift"; sourceTree = ""; };
- 55373F9F2E9372DF00AB56D0 /* DocumentWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentWindow.swift; sourceTree = ""; };
- 55373FA02E9372DF00AB56D0 /* NSArrayController+Paths.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSArrayController+Paths.swift"; sourceTree = ""; };
- 55373FA12E9372DF00AB56D0 /* PathChooser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathChooser.swift; sourceTree = ""; };
- 55373FA22E9372DF00AB56D0 /* RecentDocumentPopupMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentDocumentPopupMenu.swift; sourceTree = ""; };
- 55373FA42E9372DF00AB56D0 /* DiffOpenerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiffOpenerDelegate.swift; sourceTree = ""; };
- 55373FA52E9372DF00AB56D0 /* DocumentError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentError.swift; sourceTree = ""; };
- 55373FA62E9372DF00AB56D0 /* SessionDiff.ItemType+Paths.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SessionDiff.ItemType+Paths.swift"; sourceTree = ""; };
- 55373FA72E9372DF00AB56D0 /* SessionTypeError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionTypeError.swift; sourceTree = ""; };
- 55373FA82E9372DF00AB56D0 /* VDDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VDDocument.swift; sourceTree = ""; };
- 55373FA92E9372DF00AB56D0 /* VDDocumentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VDDocumentController.swift; sourceTree = ""; };
- 55373FAB2E9372DF00AB56D0 /* HistoryEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryEntity.swift; sourceTree = ""; };
- 55373FAC2E9372DF00AB56D0 /* HistorySessionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistorySessionManager.swift; sourceTree = ""; };
- 55373FAE2E9372DF00AB56D0 /* SessionDiff.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionDiff.swift; sourceTree = ""; };
- 55373FAF2E9372DF00AB56D0 /* SessionDiff+AlignRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SessionDiff+AlignRule.swift"; sourceTree = ""; };
- 55373FB12E9372DF00AB56D0 /* SessionDiff+NSSortDescriptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SessionDiff+NSSortDescriptor.swift"; sourceTree = ""; };
- 55373FB22E9372DF00AB56D0 /* SessionDiff+ResolvePath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SessionDiff+ResolvePath.swift"; sourceTree = ""; };
- 55373FB32E9372DF00AB56D0 /* SessionDiff+Types.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SessionDiff+Types.swift"; sourceTree = ""; };
- 55373FB62E9372DF00AB56D0 /* FilesTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesTableView.swift; sourceTree = ""; };
- 55373FB72E9372DF00AB56D0 /* FilesTableView+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesTableView+Menu.swift"; sourceTree = ""; };
- 55373FB82E9372DF00AB56D0 /* FilesTableViewFindTextDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesTableViewFindTextDelegate.swift; sourceTree = ""; };
- 55373FBA2E9372DF00AB56D0 /* FileInfoBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileInfoBar.swift; sourceTree = ""; };
- 55373FBB2E9372DF00AB56D0 /* FilePanelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePanelView.swift; sourceTree = ""; };
- 55373FBC2E9372DF00AB56D0 /* FilePanelView+File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilePanelView+File.swift"; sourceTree = ""; };
- 55373FBD2E9372DF00AB56D0 /* FilesScopeBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesScopeBar.swift; sourceTree = ""; };
- 55373FBE2E9372DF00AB56D0 /* FileThumbnailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileThumbnailView.swift; sourceTree = ""; };
- 55373FBF2E9372DF00AB56D0 /* LineNumberTableCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineNumberTableCellView.swift; sourceTree = ""; };
- 55373FC02E9372DF00AB56D0 /* LineNumberTableRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineNumberTableRowView.swift; sourceTree = ""; };
- 55373FC12E9372DF00AB56D0 /* NSAlert+DirtyFiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAlert+DirtyFiles.swift"; sourceTree = ""; };
- 55373FC22E9372DF00AB56D0 /* SaveFileAccessoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveFileAccessoryView.swift; sourceTree = ""; };
- 55373FC32E9372DF00AB56D0 /* TextFieldVerticalCentered.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldVerticalCentered.swift; sourceTree = ""; };
- 55373FC52E9372DF00AB56D0 /* FilesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesWindowController.swift; sourceTree = ""; };
- 55373FC62E9372DF00AB56D0 /* FilesWindowController+Clipboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+Clipboard.swift"; sourceTree = ""; };
- 55373FC72E9372DF00AB56D0 /* FilesWindowController+Common.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+Common.swift"; sourceTree = ""; };
- 55373FC82E9372DF00AB56D0 /* FilesWindowController+Document.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+Document.swift"; sourceTree = ""; };
- 55373FC92E9372DF00AB56D0 /* FilesWindowController+FileInfoBarDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+FileInfoBarDelegate.swift"; sourceTree = ""; };
- 55373FCA2E9372DF00AB56D0 /* FilesWindowController+FilesScopeBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+FilesScopeBar.swift"; sourceTree = ""; };
- 55373FCB2E9372DF00AB56D0 /* FilesWindowController+FilesTableViewContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+FilesTableViewContextMenu.swift"; sourceTree = ""; };
- 55373FCC2E9372DF00AB56D0 /* FilesWindowController+JumpLine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+JumpLine.swift"; sourceTree = ""; };
- 55373FCD2E9372DF00AB56D0 /* FilesWindowController+LinesDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+LinesDetail.swift"; sourceTree = ""; };
- 55373FCE2E9372DF00AB56D0 /* FilesWindowController+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+Menu.swift"; sourceTree = ""; };
- 55373FCF2E9372DF00AB56D0 /* FilesWindowController+MenuDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+MenuDelegate.swift"; sourceTree = ""; };
- 55373FD02E9372DF00AB56D0 /* FilesWindowController+Navigate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+Navigate.swift"; sourceTree = ""; };
- 55373FD12E9372DF00AB56D0 /* FilesWindowController+NSToolbarDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+NSToolbarDelegate.swift"; sourceTree = ""; };
- 55373FD22E9372DF00AB56D0 /* FilesWindowController+NSWindowDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+NSWindowDelegate.swift"; sourceTree = ""; };
- 55373FD32E9372DF00AB56D0 /* FilesWindowController+PathControlDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+PathControlDelegate.swift"; sourceTree = ""; };
- 55373FD42E9372DF00AB56D0 /* FilesWindowController+Read.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+Read.swift"; sourceTree = ""; };
- 55373FD52E9372DF00AB56D0 /* FilesWindowController+Save.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+Save.swift"; sourceTree = ""; };
- 55373FD62E9372DF00AB56D0 /* FilesWindowController+Slider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+Slider.swift"; sourceTree = ""; };
- 55373FD72E9372DF00AB56D0 /* FilesWindowController+TableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+TableView.swift"; sourceTree = ""; };
- 55373FD82E9372DF00AB56D0 /* FilesWindowController+UICreation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+UICreation.swift"; sourceTree = ""; };
- 55373FD92E9372DF00AB56D0 /* FilesWindowController+UISetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesWindowController+UISetup.swift"; sourceTree = ""; };
- 55373FDB2E9372DF00AB56D0 /* DiffLine+Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiffLine+Color.swift"; sourceTree = ""; };
- 55373FDD2E9372DF00AB56D0 /* DiffChangeType+Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiffChangeType+Color.swift"; sourceTree = ""; };
- 55373FDE2E9372DF00AB56D0 /* DiffChangeType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiffChangeType.swift; sourceTree = ""; };
- 55373FE02E9372DF00AB56D0 /* DiffCountersItem+DiffResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiffCountersItem+DiffResult.swift"; sourceTree = ""; };
- 55373FE12E9372DF00AB56D0 /* FilesTableView+EditorData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FilesTableView+EditorData.swift"; sourceTree = ""; };
- 55373FE32E9372DF00AB56D0 /* JumpToLineWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JumpToLineWindow.swift; sourceTree = ""; };
- 55373FE62E9372DF00AB56D0 /* ColoredFoldersManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColoredFoldersManager.swift; sourceTree = ""; };
- 55373FE72E9372DF00AB56D0 /* FoldersOutlineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FoldersOutlineView.swift; sourceTree = ""; };
- 55373FE82E9372DF00AB56D0 /* FoldersOutlineView+Clipboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersOutlineView+Clipboard.swift"; sourceTree = ""; };
- 55373FE92E9372DF00AB56D0 /* FoldersOutlineView+Columns.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersOutlineView+Columns.swift"; sourceTree = ""; };
- 55373FEA2E9372DF00AB56D0 /* FoldersOutlineView+Enumerate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersOutlineView+Enumerate.swift"; sourceTree = ""; };
- 55373FEB2E9372DF00AB56D0 /* FoldersOutlineView+ExternalApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersOutlineView+ExternalApp.swift"; sourceTree = ""; };
- 55373FEC2E9372DF00AB56D0 /* FoldersOutlineView+FileCount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersOutlineView+FileCount.swift"; sourceTree = ""; };
- 55373FED2E9372DF00AB56D0 /* FoldersOutlineView+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersOutlineView+Menu.swift"; sourceTree = ""; };
- 55373FEE2E9372DF00AB56D0 /* FoldersOutlineView+VisibleItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersOutlineView+VisibleItem.swift"; sourceTree = ""; };
- 55373FEF2E9372DF00AB56D0 /* FoldersOutlineViewFindTextDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FoldersOutlineViewFindTextDelegate.swift; sourceTree = ""; };
- 55373FF02E9372DF00AB56D0 /* CompareItem+LeafPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CompareItem+LeafPath.swift"; sourceTree = ""; };
- 55373FF12E9372DF00AB56D0 /* CompareItem+NSTableCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CompareItem+NSTableCellView.swift"; sourceTree = ""; };
- 55373FF22E9372DF00AB56D0 /* IconUtils+CompareItemIconUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IconUtils+CompareItemIconUtils.swift"; sourceTree = ""; };
- 55373FF42E9372DF00AB56D0 /* DisplayFiltersScopeBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayFiltersScopeBar.swift; sourceTree = ""; };
- 55373FF52E9372DF00AB56D0 /* FolderPanelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderPanelView.swift; sourceTree = ""; };
- 55373FF62E9372DF00AB56D0 /* CompareItemTableCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompareItemTableCellView.swift; sourceTree = ""; };
- 55373FF72E9372DF00AB56D0 /* CompareItemTableRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompareItemTableRowView.swift; sourceTree = ""; };
- 55373FFB2E9372DF00AB56D0 /* CopyFileOperationExecutor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyFileOperationExecutor.swift; sourceTree = ""; };
- 55373FFD2E9372DF00AB56D0 /* DeleteFileOperationExecutor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteFileOperationExecutor.swift; sourceTree = ""; };
- 55373FFF2E9372DF00AB56D0 /* MoveFileOperationExecutor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoveFileOperationExecutor.swift; sourceTree = ""; };
- 553740012E9372DF00AB56D0 /* ConfirmReplace.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmReplace.swift; sourceTree = ""; };
- 553740022E9372DF00AB56D0 /* NSAlert+ReplaceFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAlert+ReplaceFile.swift"; sourceTree = ""; };
- 553740032E9372DF00AB56D0 /* NSApplication.ModalResponse+ReplaceFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSApplication.ModalResponse+ReplaceFile.swift"; sourceTree = ""; };
- 553740042E9372DF00AB56D0 /* ReplaceFileAttributeKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplaceFileAttributeKey.swift; sourceTree = ""; };
- 553740062E9372DF00AB56D0 /* CompletionIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompletionIndicator.swift; sourceTree = ""; };
- 553740072E9372DF00AB56D0 /* ErrorsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorsView.swift; sourceTree = ""; };
- 553740082E9372DF00AB56D0 /* FileOperationManagerDelegateImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileOperationManagerDelegateImpl.swift; sourceTree = ""; };
- 553740092E9372DF00AB56D0 /* ProgressIndicatorController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressIndicatorController.swift; sourceTree = ""; };
- 5537400A2E9372DF00AB56D0 /* ReplaceInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplaceInfoView.swift; sourceTree = ""; };
- 5537400C2E9372DF00AB56D0 /* SyncFileController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncFileController.swift; sourceTree = ""; };
- 5537400D2E9372DF00AB56D0 /* SyncFileOperationExecutor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncFileOperationExecutor.swift; sourceTree = ""; };
- 5537400E2E9372DF00AB56D0 /* SyncItemsInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncItemsInfo.swift; sourceTree = ""; };
- 5537400F2E9372DF00AB56D0 /* SyncOutlineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncOutlineView.swift; sourceTree = ""; };
- 553740112E9372DF00AB56D0 /* DatePickersStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatePickersStackView.swift; sourceTree = ""; };
- 553740122E9372DF00AB56D0 /* TouchController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TouchController.swift; sourceTree = ""; };
- 553740132E9372DF00AB56D0 /* TouchFileOperationExecutor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TouchFileOperationExecutor.swift; sourceTree = ""; };
- 553740142E9372DF00AB56D0 /* TouchPickersStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TouchPickersStackView.swift; sourceTree = ""; };
- 553740162E9372DF00AB56D0 /* FileOperationExecutor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileOperationExecutor.swift; sourceTree = ""; };
- 553740172E9372DF00AB56D0 /* FileSummaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileSummaryView.swift; sourceTree = ""; };
- 553740182E9372DF00AB56D0 /* FileSystemController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileSystemController.swift; sourceTree = ""; };
- 553740192E9372DF00AB56D0 /* OperationSummaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationSummaryView.swift; sourceTree = ""; };
- 5537401B2E9372DF00AB56D0 /* FolderReader+Detached.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FolderReader+Detached.swift"; sourceTree = ""; };
- 5537401C2E9372DF00AB56D0 /* MainThreadFolderReaderDelegateBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainThreadFolderReaderDelegateBridge.swift; sourceTree = ""; };
- 5537401E2E9372DF00AB56D0 /* FolderSelectionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderSelectionInfo.swift; sourceTree = ""; };
- 5537401F2E9372DF00AB56D0 /* FoldersWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FoldersWindowController.swift; sourceTree = ""; };
- 553740202E9372DF00AB56D0 /* FoldersWindowController+BaseFolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+BaseFolder.swift"; sourceTree = ""; };
- 553740212E9372DF00AB56D0 /* FoldersWindowController+Comparison.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+Comparison.swift"; sourceTree = ""; };
- 553740222E9372DF00AB56D0 /* FoldersWindowController+ConsoleViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+ConsoleViewDelegate.swift"; sourceTree = ""; };
- 553740232E9372DF00AB56D0 /* FoldersWindowController+DisplayFiltersScopeBarDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+DisplayFiltersScopeBarDelegate.swift"; sourceTree = ""; };
- 553740242E9372DF00AB56D0 /* FoldersWindowController+Document.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+Document.swift"; sourceTree = ""; };
- 553740252E9372DF00AB56D0 /* FoldersWindowController+Exclude.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+Exclude.swift"; sourceTree = ""; };
- 553740262E9372DF00AB56D0 /* FoldersWindowController+FileSystemControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+FileSystemControllerDelegate.swift"; sourceTree = ""; };
- 553740272E9372DF00AB56D0 /* FoldersWindowController+FoldersOutlineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+FoldersOutlineView.swift"; sourceTree = ""; };
- 553740282E9372DF00AB56D0 /* FoldersWindowController+FoldersOutlineViewContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+FoldersOutlineViewContextMenu.swift"; sourceTree = ""; };
- 553740292E9372DF00AB56D0 /* FoldersWindowController+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+Menu.swift"; sourceTree = ""; };
- 5537402A2E9372DF00AB56D0 /* FoldersWindowController+MenuDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+MenuDelegate.swift"; sourceTree = ""; };
- 5537402B2E9372DF00AB56D0 /* FoldersWindowController+Navigation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+Navigation.swift"; sourceTree = ""; };
- 5537402C2E9372DF00AB56D0 /* FoldersWindowController+NSToolbarDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+NSToolbarDelegate.swift"; sourceTree = ""; };
- 5537402D2E9372DF00AB56D0 /* FoldersWindowController+NSWindowDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+NSWindowDelegate.swift"; sourceTree = ""; };
- 5537402E2E9372DF00AB56D0 /* FoldersWindowController+PathControlDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+PathControlDelegate.swift"; sourceTree = ""; };
- 5537402F2E9372DF00AB56D0 /* FoldersWindowController+QLPreviewPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+QLPreviewPanel.swift"; sourceTree = ""; };
- 553740302E9372DF00AB56D0 /* FoldersWindowController+Select.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+Select.swift"; sourceTree = ""; };
- 553740312E9372DF00AB56D0 /* FoldersWindowController+SessionPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+SessionPreferences.swift"; sourceTree = ""; };
- 553740322E9372DF00AB56D0 /* FoldersWindowController+UICreation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+UICreation.swift"; sourceTree = ""; };
- 553740332E9372DF00AB56D0 /* FoldersWindowController+UISetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersWindowController+UISetup.swift"; sourceTree = ""; };
- 553740342E9372DF00AB56D0 /* OutlineViewItemDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutlineViewItemDelegate.swift; sourceTree = ""; };
- 553740362E9372DF00AB56D0 /* CommonPrefs+ConsoleLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CommonPrefs+ConsoleLog.swift"; sourceTree = ""; };
- 553740372E9372DF00AB56D0 /* DiffCountersItem+CompareItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiffCountersItem+CompareItem.swift"; sourceTree = ""; };
- 553740392E9372DF00AB56D0 /* CopyCompareItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyCompareItem.swift; sourceTree = ""; };
- 5537403A2E9372DF00AB56D0 /* DeleteCompareItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteCompareItem.swift; sourceTree = ""; };
- 5537403B2E9372DF00AB56D0 /* FileAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileAttributes.swift; sourceTree = ""; };
- 5537403C2E9372DF00AB56D0 /* FileOperationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileOperationManager.swift; sourceTree = ""; };
- 5537403D2E9372DF00AB56D0 /* FileOperationManager+FileOperationManagerAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileOperationManager+FileOperationManagerAction.swift"; sourceTree = ""; };
- 5537403E2E9372DF00AB56D0 /* FileOperationManager+Util.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileOperationManager+Util.swift"; sourceTree = ""; };
- 5537403F2E9372DF00AB56D0 /* FolderManagerError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderManagerError.swift; sourceTree = ""; };
- 553740402E9372DF00AB56D0 /* CompareItem+Metadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CompareItem+Metadata.swift"; sourceTree = ""; };
- 553740412E9372DF00AB56D0 /* MoveCompareItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoveCompareItem.swift; sourceTree = ""; };
- 553740422E9372DF00AB56D0 /* PathTimestamps.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathTimestamps.swift; sourceTree = ""; };
- 553740432E9372DF00AB56D0 /* RenameCompareItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RenameCompareItem.swift; sourceTree = ""; };
- 553740442E9372DF00AB56D0 /* TouchCompareItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TouchCompareItem.swift; sourceTree = ""; };
- 553740462E9372DF00AB56D0 /* ComparatorOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComparatorOptions.swift; sourceTree = ""; };
- 553740472E9372DF00AB56D0 /* ComparatorOptions+Description.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ComparatorOptions+Description.swift"; sourceTree = ""; };
- 553740482E9372DF00AB56D0 /* ComparatorOptions+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ComparatorOptions+Helper.swift"; sourceTree = ""; };
- 5537404B2E9372DF00AB56D0 /* DisplayOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayOptions.swift; sourceTree = ""; };
- 5537404C2E9372DF00AB56D0 /* DisplayOptions+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DisplayOptions+Helper.swift"; sourceTree = ""; };
- 5537404E2E9372DF00AB56D0 /* FileExtraOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileExtraOptions.swift; sourceTree = ""; };
- 5537404F2E9372DF00AB56D0 /* CompareItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompareItem.swift; sourceTree = ""; };
- 553740502E9372DF00AB56D0 /* CompareItem+Accessors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CompareItem+Accessors.swift"; sourceTree = ""; };
- 553740512E9372DF00AB56D0 /* CompareItem+Clone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CompareItem+Clone.swift"; sourceTree = ""; };
- 553740522E9372DF00AB56D0 /* CompareItem+Comparison.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CompareItem+Comparison.swift"; sourceTree = ""; };
- 553740532E9372DF00AB56D0 /* CompareItem+Description.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CompareItem+Description.swift"; sourceTree = ""; };
- 553740542E9372DF00AB56D0 /* CompareItem+FilterConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CompareItem+FilterConfig.swift"; sourceTree = ""; };
- 553740562E9372DF00AB56D0 /* CompareItem+Path.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CompareItem+Path.swift"; sourceTree = ""; };
- 553740572E9372DF00AB56D0 /* CompareItem+VisibleItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CompareItem+VisibleItem.swift"; sourceTree = ""; };
- 553740592E9372DF00AB56D0 /* CommonPrefs+DifferenceNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CommonPrefs+DifferenceNavigator.swift"; sourceTree = ""; };
- 5537405A2E9372DF00AB56D0 /* FoldersOutlineView+DifferenceNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FoldersOutlineView+DifferenceNavigator.swift"; sourceTree = ""; };
- 5537405B2E9372DF00AB56D0 /* CompareItem+DifferenceNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CompareItem+DifferenceNavigator.swift"; sourceTree = ""; };
- 5537405D2E9372DF00AB56D0 /* FilterConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterConfig.swift; sourceTree = ""; };
- 5537405E2E9372DF00AB56D0 /* FolderReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderReader.swift; sourceTree = ""; };
- 5537405F2E9372DF00AB56D0 /* FolderReader+Log.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FolderReader+Log.swift"; sourceTree = ""; };
- 553740602E9372DF00AB56D0 /* FolderReaderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderReaderDelegate.swift; sourceTree = ""; };
- 553740612E9372DF00AB56D0 /* RefreshInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshInfo.swift; sourceTree = ""; };
- 553740692E9372DF00AB56D0 /* FolderSelectionInfo+CompareActionValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FolderSelectionInfo+CompareActionValidator.swift"; sourceTree = ""; };
- 5537406A2E9372DF00AB56D0 /* FolderSelectionInfo+FileSystemActionValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FolderSelectionInfo+FileSystemActionValidator.swift"; sourceTree = ""; };
- 5537406B2E9372DF00AB56D0 /* FolderSelectionInfo+FilterActionValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FolderSelectionInfo+FilterActionValidator.swift"; sourceTree = ""; };
- 5537406C2E9372DF00AB56D0 /* FolderSelectionInfo+FolderActionValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FolderSelectionInfo+FolderActionValidator.swift"; sourceTree = ""; };
- 5537406D2E9372DF00AB56D0 /* FolderSelectionInfo+ViewerActionValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FolderSelectionInfo+ViewerActionValidator.swift"; sourceTree = ""; };
- 5537406F2E9372DF00AB56D0 /* VisibleItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleItem.swift; sourceTree = ""; };
- 553740702E9372DF00AB56D0 /* VisibleItem+Find.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleItem+Find.swift"; sourceTree = ""; };
- 553740712E9372DF00AB56D0 /* VisibleItem+Log.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleItem+Log.swift"; sourceTree = ""; };
- 553740722E9372DF00AB56D0 /* VisibleItem+QLPreviewItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleItem+QLPreviewItem.swift"; sourceTree = ""; };
- 553740732E9372DF00AB56D0 /* VisibleItem+Sort.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleItem+Sort.swift"; sourceTree = ""; };
- 553740752E9372DF00AB56D0 /* DescriptionOutlineNode+FolderCompareInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DescriptionOutlineNode+FolderCompareInfo.swift"; sourceTree = ""; };
- 553740762E9372DF00AB56D0 /* FolderCompareInfoWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderCompareInfoWindow.swift; sourceTree = ""; };
- 5537407A2E9372DF00AB56D0 /* HistoryController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryController.swift; sourceTree = ""; };
- 5537407B2E9372DF00AB56D0 /* HistoryEntityTableCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryEntityTableCellView.swift; sourceTree = ""; };
- 5537407C2E9372DF00AB56D0 /* HistoryFetchedResultsControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryFetchedResultsControllerDelegate.swift; sourceTree = ""; };
- 5537407D2E9372DF00AB56D0 /* HistorySearchField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistorySearchField.swift; sourceTree = ""; };
- 5537407E2E9372DF00AB56D0 /* HistoryTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryTableView.swift; sourceTree = ""; };
- 553740802E9372DF00AB56D0 /* ComparisonStandardUserDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComparisonStandardUserDataSource.swift; sourceTree = ""; };
- 553740812E9372DF00AB56D0 /* PreferencesBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesBox.swift; sourceTree = ""; };
- 553740822E9372DF00AB56D0 /* PreferencesBoxDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesBoxDataSource.swift; sourceTree = ""; };
- 553740832E9372DF00AB56D0 /* PreferencesCheckbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesCheckbox.swift; sourceTree = ""; };
- 553740842E9372DF00AB56D0 /* StandardUserPreferencesBoxDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardUserPreferencesBoxDataSource.swift; sourceTree = ""; };
- 553740862E9372DF00AB56D0 /* BasePreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasePreferences.swift; sourceTree = ""; };
- 553740872E9372DF00AB56D0 /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; };
- 553740892E9372DF00AB56D0 /* ConfirmationsDocumentsBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationsDocumentsBox.swift; sourceTree = ""; };
- 5537408A2E9372DF00AB56D0 /* ConfirmationsFilesBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationsFilesBox.swift; sourceTree = ""; };
- 5537408B2E9372DF00AB56D0 /* ConfirmationsFoldersBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationsFoldersBox.swift; sourceTree = ""; };
- 5537408C2E9372DF00AB56D0 /* ConfirmationsPreferencesPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationsPreferencesPanel.swift; sourceTree = ""; };
- 5537408E2E9372DF00AB56D0 /* DifferenceNavigatorBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DifferenceNavigatorBox.swift; sourceTree = ""; };
- 5537408F2E9372DF00AB56D0 /* FolderPreferencesPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderPreferencesPanel.swift; sourceTree = ""; };
- 553740902E9372DF00AB56D0 /* FoldersTraversalBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FoldersTraversalBox.swift; sourceTree = ""; };
- 553740912E9372DF00AB56D0 /* FolderViewBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderViewBox.swift; sourceTree = ""; };
- 553740932E9372DF00AB56D0 /* FontBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontBox.swift; sourceTree = ""; };
- 553740942E9372DF00AB56D0 /* FontPreferencesPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontPreferencesPanel.swift; sourceTree = "