--Applescript direct

-- Script that improves on the TeXShop default macro called "Program",
-- i.e., %!TEX TS-program =  #INS#
-- by letting the user choose which engine she/he wants to use,
-- deleting the first old (if any) engine command,
-- inserting the command at the beginning of the document, and
-- restoring the original selection.
-- It assumes that engines are installed in ~/Library/TeXShop/Engines/
-- Ramon Figueroa-Centeno (March 10, 2009)
-- http://www2.hawaii.edu/~ramonf

-- History:
-- 1.1: March 19, 2008
-- Added missing default engines: metapost, metafont, and context.
-- 1.2: March 28, 2009
-- Added code to respect first lines that start with "%&"


-- If you wish you can change this so that your favorite engine is the default choice
property default_engine : "pdflatexmk"

tell application "TeXShop"
	
	-- Get a sorted list of the default and installed TeXShop engines
	tell me
		-- Shell script to get the names of the engines installed in ~/Library/TeXShop/Engines/
		set command to "ls ~/Library/TeXShop/Engines/ | egrep -e '^.*\\.engine$' | sed 's/\\.engine//'"
		set engines to paragraphs of (do shell script command)
		set engines to sort({"tex", "latex", "pdflatex", "pdftex", "personaltex", "personallatex", "metapost", "metafont", "context"} & engines)
	end tell
	
	-- Figure out which is the index of the "default_engine" in the "engines" list
	if default_engine is in engines then
		repeat with i from 1 to count of engines
			if item i of engines is default_engine then
				exit repeat
			end if
		end repeat
	else
		-- if the "default_engine" is not among the engines then choose the alphabetically first available engine name
		set i to 1
	end if
	
	set the engine to choose from list engines with prompt "Pick an engine:" default items item i of engines OK button name "OK" cancel button name "Cancel" without multiple selections allowed and empty selection allowed
	if the result is false then
		return
	end if
	
	-- The linefeed character
	set linefeed to ASCII character 10
	
	-- The whole text of the document
	set whole_document to (the text of the front document) as string
	
	-- The offset of the selection
	set selection_offset to offset of the selection of the front document
	
	-- The length of the selection
	set selection_length to length of the selection of the front document
	
	-- Find and delete a previous engine specification
	-- (it will not handle more than one specification)
	set searchString1 to "%!TEX TS-program ="
	set search1 to (search for searchString1 starting from 0) of front document
	set searchString2 to "% !TEX TS-program ="
	set search2 to (search for searchString2 starting from 0) of front document
	
	if search1 * search2 > 0 then
		if search1 < search2 then
			set first_occurrence to search1
		else
			set first_occurrence to search2
		end if
	else if search1 > 0 then
		set first_occurrence to search1
	else
		set first_occurrence to search2
	end if
	if first_occurrence > 0 then
		set offset of selection of front document to (first_occurrence - 1)
		
		-- Get the offset of the line feed (or eof) ending the line containing "%!TEX TS-program ="
		-- (here we use a "try" statement to avoid  needing to have a saved file
		-- from which we could get the "eof") 
		set i to first_occurrence
		set end_of_file to false
		set char to character i of whole_document
		repeat while char is not in {linefeed, return}
			set i to i + 1
			try
				set char to character i of whole_document
			on error
				set end_of_file to true
				exit repeat
			end try
		end repeat
		
		-- Detect if the line starts with "% !TEX TS-program =" and it is not the last line,
		-- if so we will delete not only "% !TEX TS-program =..." but the whole line
		if ((first_occurrence = 1) or (character (first_occurrence - 1) of whole_document is in {linefeed, return})) and not end_of_file then
			set i to i + 1
		end if
		
		set length of selection of front document to (i - first_occurrence)
		-- Delete the line
		set the content of the selection of the front document to ""
		
		-- We will try to restore the selection the user had before invoking this script
		-- so we compute what the new selection_offset should be.
		if (selection_offset  first_occurrence - 1) and (selection_offset < i - 1) then
			set selection_offset to first_occurrence - 1
			set selection_length to 0
		else if selection_offset  i - 1 then
			set selection_offset to selection_offset - (i - first_occurrence)
		end if
	end if
	
	set program to "% !TEX TS-program = " & engine & linefeed
	set selection_offset to selection_offset + (count of program)
	
	-- If the first line starts with "%&" set the insertion offset
	-- to the beginning of the second line.
	try
		set first_line to paragraph 1 of the text of the front document as string
		if the first_line starts with "%&" then
			set insertion_offset to count the characters of the first_line
			try
				get paragraph 2 of the text of the front document
			on error -- There is only one line?
				set selection_offset to selection_offset + 1
				set program to linefeed & program
			end try
		else
			set insertion_offset to 0
		end if
	on error -- The document was empty?
		set insertion_offset to 0
	end try
	
	-- Insert Engine
	set offset of the selection of the front document to insertion_offset
	set length of the selection of the front document to 0
	set content of the selection of the front document to program
	
	-- Restore the offset of the selection
	set offset of the selection of the front document to selection_offset
	
	-- Restore the length of the selection
	set length of the selection of the front document to selection_length
	
end tell

(* 
http://www.macosxhints.com/article.php?story=20040513173003941
Sort lists in AppleScript using the Unix sort command
Mon, May 17 '04 at 09:13AM • from: erickaterman *)
on sort(the_list)
	set old_delims to AppleScript's text item delimiters
	set AppleScript's text item delimiters to {ASCII character 10} -- always a linefeed
	set list_string to (the_list as string)
	set new_string to do shell script "echo " & quoted form of list_string & " | sort -f -u"
	set new_list to (paragraphs of new_string)
	set AppleScript's text item delimiters to old_delims
	return new_list
end sort