--Applescript direct
-- Script to close a begin/end block
-- Ramon Figueroa-Centeno March 10, 2009

tell application "TeXShop"
	
	-- The linefeed character.
	set linefeed to ASCII character 10
	
	set the front_document to the front document
	-- set the front_document to document #DOCUMENTNAME#
	
	-- The whole text of the document
	set whole_document to (the text of the front_document) as string
	
	-- If the front document is not saved dump its 
	-- content to a temporary file and use that
	if the front_document is modified then
		tell me
			set texpath to do shell script "mktemp /tmp/XXXXXXXX"
			set TMP to POSIX file texpath
			open for access TMP with write permission
			write whole_document to TMP
			close access TMP
		end tell
	else
		set texpath to the path of the front_document
		-- set texpath to the #FILEPATH#
	end if
	
	-- The offset of the selection
	set selection_offset to offset of the selection of the front_document
	
	-- Move the insertion point to the beginning of the selected word.
	-- Unless we are at the end of a line.
	-- If one removes " " (space) from the list  the insertion point moves to the
	-- beginning of the line. 
	
	try
		if the character (selection_offset + 1) of the whole_document is not in {linefeed, return} then
			repeat until (selection_offset = 0) or ¬
				(character selection_offset of the whole_document is in {linefeed, return, " "})
				set selection_offset to selection_offset - 1
			end repeat
			set the offset of the selection of the front_document to selection_offset
		end if
	on error
		-- It appears that we are at the end of the file!
	end try
	
	-- Stop if the insertion point is at the beginning of the document
	if selection_offset = 0 then
		return
	end if
	
	-- The document up to the selection
	set partial_document to ¬
		(characters 1 thru (selection_offset) of the whole_document) as string
	
	-- Let selection_line_number be the number of the line of the start of the current selection
	set selection_line_number to count paragraphs of the partial_document
	
	set report to "selection line: " & selection_line_number & return
	
	-- The total number of lines
	set total_lines to count paragraphs of the whole_document
	
	set report to report & "total # of lines: " & total_lines & return
	
	-- The "command" is a shell script that does this: 
	-- delete all comments:
	-- sed 's/%.*$//'  (or sed '/%.*$/ s/%.*$//' for speed)
	set command to " | sed '/%.*$/ s/%.*$//'"
	-- replace all "\" with a linefeed character:
	-- tr -s "\\" "\n" 
	set command to command & " | tr -s \"\\\\\" \"\\n\""
	-- delete everything after and including the first "}":
	-- sed 's/}.*//'  (or sed '/}.*/ s/}.*//'  for speed)
	set command to command & " | sed '/}.*/ s/}.*//'"
	-- keep only the lines that start with "begin{" or "end{":
	-- egrep -e '^begin{|^end{' 
	set command to command & " | egrep -e '^begin{|^end{'"
	-- replace all "{" by spaces:
	-- tr -s "{" " " 
	set command to command & " | tr -s \"{\" \" \""
	
	-- shell command to convert returns (\r) to line feeds (\n)
	set mac2unix to "tr \\\\r \\\\n"
	
	--select insertion point before the selection
	set length of the selection of the front_document to 0
	
	-- Divide the line of the selection into two chunks
	-- one before and another after the beginning of the selection
	try
		set firstLineChunk to the last paragraph of the partial_document
	on error
		set firstLineChunk to ""
	end try
	set the_line to paragraph selection_line_number of the whole_document
	try
		set secondLineChunk to characters ((count of the firstLineChunk) + 1) ¬
			thru (count of the_line) of the_line as string
	on error
		set secondLineChunk to ""
	end try
	
	-- Set list_1 to a list that contains strings, each with two words
	-- the first word is "begin" or "end" and the second is the 
	-- name of the corresponding environment
	
	set list_1 to {}
	
	set command_2 to ¬
		mac2unix & " < " & (quoted form of texpath) ¬
		& " | head -n " & (selection_line_number - 1) & command
	tell me to set parsed to do shell script command_2
	if parsed is not "" then
		set list_1 to list_1 & (paragraphs of parsed)
	end if
	
	set command_2 to ¬
		"echo " & (quoted form of firstLineChunk) & " | " & mac2unix & command
	tell me to set parsed to do shell script command_2
	if parsed is not "" then
		set list_1 to list_1 & (paragraphs of parsed)
	end if
	
	-- If list_1 is empty then there is no environment to close
	if (count of list_1) = 0 then
		beep
		say "There are no environments before this point."
		--display dialog "There are no environments before this point." buttons {"OK"} default button 1 with icon caution
		return
	end if
	
	set flips to 0
	repeat with i from (count list_1) to 1 by -1
		if word 1 of item i of list_1 is "end" then
			set flips to flips + 1
		else
			set flips to flips - 1
		end if
		
		if flips = -1 -- The next line does this:			-- The next line does this:
			-- but handles starred commands correctly
			tell me to  to set environment_name to do shell script ¬
				"echo \"" & (item i of list_1) & "\" |  sed '/.* / s/.* //'"
			exit repeat
		end if
		
	end repeat
	if not (flips = -1) then
		beep
		say "I did not find an open environment!"
		--display dialog "I did not find an open environment!" buttons {"OK"} default button 1 with icon caution
		return
	end if
	
	-- Now we check to see if the environment we are in is already closed
	
	set list_2 to {}
	
	set command_2 to ¬
		"echo " & (quoted form of secondLineChunk) & " | " & mac2unix & command
	tell me to set parsed to do shell script command_2
	if parsed is not "" then
		set list_2 to paragraphs of parsed
	end if
	
	set command_2 to ¬
		mac2unix & " < " & (quoted form of texpath) ¬
		& " | tail -n +" & (selection_line_number + 1) & command
	tell me to set parsed to do shell script command_2
	if parsed is not "" then
		set list_2 to list_2 & (paragraphs of parsed)
	end if
	
	set close_environment to true
	
	if (count of list_2) > 0 then
		set flips to 0
		repeat with i from 1 to (count list_2)
			if word 1 of item i of list_2 is "begin" then
				set flips to flips + 1
			else
				set flips to flips - 1
			end if
			if flips = -1 then
				-- The next line does this:
				-- set environment_name_2 to word 2 of item i of list_2
				-- but handles starred commands correctly
				set environment_name_2 to do shell script ¬
					"echo \"" & (item i of list_2) & "\" |  sed '/.* / s/.* //'"
				if environment_name_2 = environment_name then
					beep
					activate
					display dialog "The environment \"" & environment_name ¬
						& "\"" & return & "you are working on is already closed." & return ¬
						& "Do you still want to close it?" buttons {"No", "Yes"} ¬
						default button "No" with icon note
					set close_environment to (button returned of the result is not "No")
				end if
				exit repeat
			end if
		end repeat
	end if
	
	-- Close the environment
	if close_environment then
		if the_line = "" then
			set the content of the selection of the front_document to ¬
				"\\end{" & environment_name & "}"
		else
			-- If we are at the beginning of a line then close the environment
			-- and then enter a return. Otherwise, enter a return before doing so.
			if (character selection_offset of the whole_document is in {linefeed, return}) then
				set the content of the selection of the front_document to ¬
					"\\end{" & environment_name & "}" & linefeed
			else
				set the content of the selection of the front_document to ¬
					linefeed & "\\end{" & environment_name & "}" & linefeed
			end if
		end if
	end if
	
	-- If a temporary file was created delete it.
	try
		do shell script "rm " & POSIX path of TMP
	end try
	
end tell