Compare Two Text Files for Differences

I revised the File Compare script to use the swiftDialog app to both get the files that will be compared and to display the results in a markdown table. Please note the swiftDialog display options that alter window size in the showTable handler.

--Compare two text files and display result in a markdown table
--Requires swiftDialog app
--Revised 2024.09.05

use framework "Foundation"
use scripting additions

on main()
	set {fileOne, fileTwo} to showDialog()
	if (fileOne's isEqualToString:"") is true or (fileTwo's isEqualToString:"") is true then display dialog "A file was not selected" buttons {"OK"} cancel button 1 default button 1 with icon stop
	
	set stringOne to current application's NSString's stringWithContentsOfFile:fileOne encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
	if stringOne is (missing value) then display dialog "Text was not found in File One" buttons {"OK"} cancel button 1 default button 1 with icon stop
	set stringOne to cleanString(stringOne)
	set arrayOne to (stringOne's componentsSeparatedByString:linefeed)
	
	set stringTwo to current application's NSString's stringWithContentsOfFile:fileTwo encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
	if stringTwo is (missing value) then display dialog "Text was not found in File Two" buttons {"OK"} cancel button 1 default button 1 with icon stop
	set stringTwo to cleanString(stringTwo)
	set arrayTwo to (stringTwo's componentsSeparatedByString:linefeed)
	
	set arrayOneUnique to current application's NSMutableArray's new()
	set arrayTwoUnique to arrayTwo's mutableCopy()
	set commonArray to current application's NSMutableArray's new()
	repeat with anItem in arrayOne
		if (arrayTwoUnique's containsObject:anItem) is true then --item in both arrays
			(commonArray's addObject:anItem)
			(arrayTwoUnique's removeObjectAtIndex:(arrayTwoUnique's indexOfObject:anItem))
		else --item in arrayOne only
			(arrayOneUnique's addObject:anItem)
		end if
	end repeat
	
	set arrayCount to {arrayOneUnique's |count|(), arrayTwoUnique's |count|(), commonArray's |count|()}
	set arrayCount to current application's NSArray's arrayWithArray:arrayCount
	set arrayCount to (arrayCount's valueForKeyPath:"@max.self") as integer
	
	set theTable to current application's NSMutableArray's new()
	set emptyString to current application's NSString's stringWithString:""
	repeat with i from 0 to (arrayCount - 1)
		try
			set columnOne to truncateString(commonArray's objectAtIndex:i)
		on error
			set columnOne to emptyString
		end try
		try
			set columnTwo to truncateString(arrayOneUnique's objectAtIndex:i)
		on error
			set columnTwo to emptyString
		end try
		try
			set columnThree to truncateString(arrayTwoUnique's objectAtIndex:i)
		on error
			set columnThree to emptyString
		end try
		set aRow to current application's NSString's stringWithFormat_("| %@ | %@ | %@ |", columnOne, columnTwo, columnThree)
		(theTable's addObject:aRow)
	end repeat
	set theTable to (theTable's componentsJoinedByString:linefeed)
	
	set theHeader to "| Both Files | File One Only | File Two Only |"
	set theFormatter to "| :--- | :--- | :--- |"
	set theLinefeed to linefeed
	set theString to current application's NSString's stringWithFormat_("%@%@%@%@%@", theHeader, theLinefeed, theFormatter, theLinefeed, theTable) as text
	showTable(theString)
end main

on showDialog()
	try
		set userInput to do shell script "/usr/local/bin/dialog --title 'File Compare' --titlefont 'size=15' --message 'Select two text files to compare:' --messagefont 'size=14' --messageposition top --button2 --width 400 --height 230 --hideicon --moveable --textfield 'File One,fileselect' --textfield 'File Two,fileselect'"
	on error
		error number -128
	end try
	set userInput to current application's NSMutableString's stringWithString:userInput
	(userInput's replaceOccurrencesOfString:"(?m)^.* : (.*)$" withString:"$1" options:1024 range:{0, userInput's |length|()}) --option 1024 implements regex
	return (userInput's componentsSeparatedByString:return)
end showDialog

on showTable(theString)
	do shell script "/usr/local/bin/dialog --title none --message " & quoted form of theString & " --messagefont 'size=14' --hideicon --position top --moveable" --consider resizable, and width and height options
end showTable

on cleanString(theString) --disable any of the following
	set theString to theString's stringByReplacingOccurrencesOfString:"([*#$>|])" withString:"\\\\$1" options:1024 range:{0, theString's |length|()} --escape markdown characters
	set theString to theString's stringByReplacingOccurrencesOfString:"(?m)^\\h+|\\h+$" withString:"" options:1024 range:{0, theString's |length|()} --remove leading and trailing whitespace every line
	set theString to theString's stringByReplacingOccurrencesOfString:"^\\s*\\R|\\s*$" withString:"" options:1024 range:{0, theString's |length|()} --remove blank lines at beginning and end of string
	set theString to theString's stringByReplacingOccurrencesOfString:"(\\R)\\s*\\R" withString:"$1" options:1024 range:({0, theString's |length|()}) --remove blank lines except at beginning and end of string
end cleanString

on truncateString(theString) --truncate lines at 100 characters
	set theRange to theString's rangeOfString:".{100}" options:1024
	if theRange's |length| is 0 then return theString
	return (theString's substringWithRange:theRange)'s stringByAppendingString:"..."
end truncateString

main()

I don’t know if it’s even remotely possible, but it doesn’t hurt to ask. For those of us that have never used a markdown application (and really don’t want to install one), would it be possible to have the resulting file not be a markdown (MD) file, but a PDF on even a simple Text file? For whichever of the scripts in this thread you feel works best.

Homer712. It’s possible but would involve a lot of work. To get a text file as output, it’s about as good just to use whatever shell utility returns the desired information. For example,

set outputFile to POSIX path of (path to desktop) & "Text File Comparison.txt"
set fileOne to POSIX path of (choose file)
set fileTwo to POSIX path of (choose file)

try
	do shell script "/usr/bin/sdiff -a " & quoted form of fileOne & space & quoted form of fileTwo & " > " & quoted form of outputFile
	display dialog "The selected files were the same" buttons {"OK"} cancel button 1 default button 1
end try

Thank you yet again. It seems that no matter what my question is, you always come up with a solution, and this one can best be described as “Slick”. Works perfectly, returned “The selected files were the same”, and after changing the first script by a couple of lines and running it again a Text file was written to the Desktop stating “Binary files /Users/homer/Desktop/List Select Folder.scpt and /Users/homer/Desktop/XMenu Listing Revised.scpt differ”.