--Applescript direct

-- Script that improves on the TeXShop default macro called "Root",
-- i.e., %!TEX root =  #INS#
-- by letting the user choose which root document she/he wants to use
-- (as a relative or absolute path),
-- deleting the first old (if any) root command,
-- inserting the command at the beginning of the document, and
-- restoring the original selection.
-- Ramon Figueroa-Centeno (March 10, 2009)
-- http://www2.hawaii.edu/~ramonf

-- History: 
-- 1.1: March 18, 2009
-- Added code to respect first lines that start with "%&"


-- What is the default choice: relative or not relative (i.e. absolute)
property relative : true

tell application "TeXShop"
	
	try
		path of the front document
		set TeX_path to the result
	on error -- there is no front document  or it has not ever been saved
		beep
		display dialog "there is no front document" & return & "or it has not been saved ever!" buttons {"Ok"} default button "Ok" with icon caution giving up after 5
		return
	end try
	
	set TeX_path to do shell script "dirname " & quoted form of TeX_path
	
	-- Get the absolute path to the Root document
	try
		set Root_abs_path to POSIX path of (choose file with prompt "Pick the Root document:")
	on error
		return
	end try
	
	-- Use perl to convert the absolute path to the Root document 
	-- to a relative path to it.
	set command to "perl -e 'use File::Spec; "
	set command to command & "$rel_path = File::Spec->abs2rel"
	set command to command & "( \"" & Root_abs_path & "\","
	set command to command & "\"" & TeX_path & "\" ) ; "
	set command to command & "print $rel_path'"
	tell me to set Root_rel_path to do shell script command
	
	if relative then
		set i to 1
	else
		set i to 2
	end if
	
	set roots to {Root_rel_path, Root_abs_path}
	set the root to choose from list roots with prompt "Choose between a relative and absolute path:" default items item i of roots 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 encoding specification
	-- (it will not handle more than one specification)
	set searchString1 to "%!TEX root ="
	set search1 to (search for searchString1 starting from 0) of front document
	set searchString2 to "% !TEX root ="
	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 root ="
		-- (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 root =" and it is not the last line,
		-- if so we will delete not only "% !TEX root =..." 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 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 root = " & root & 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 Root
	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