Toggle comment in AppleScript Editor

I’m currently using this to add single-line comments:


tell application "AppleScript Editor"
	set sel to contents of selection of document 1
end tell
if sel = "" then return

set l to paragraphs of sel
set c to count l
if item -1 of l = "" then set c to c - 1

repeat with i from 1 to c
	set item i of l to "-- " & item i of l
end repeat

set text item delimiters to return

tell application "AppleScript Editor"
	set contents of selection of document 1 to l as text
end tell

How would you extend this into something like Toggle Comment in TextMate’s Source bundle? If all lines are already commented, it uncomments them (once) ” otherwise it adds eg "-- " to the start of each line.

This reverses whole-line commenting within the selection on a line-by-line basis:


tell application "AppleScript Editor" to set sel to contents of selection of document 1
if sel = "" then return

set l to paragraphs of sel
set c to count l
if item -1 of l = "" then set c to c - 1

set astid to AppleScript's text item delimiters
ignoring white space -- Makes 'begins with' ignore any leading tabs.
	repeat with i from 1 to c
		set thisLine to item i of l
		if (thisLine begins with "--") then
			if (thisLine begins with "-- ") then
				set AppleScript's text item delimiters to "-- "
			else
				set AppleScript's text item delimiters to "--"
			end if
			if (thisLine's text items is {"", ""}) then
				set item i of l to ""
			else
				set item i of l to text from text item 2 to -1 of thisLine
			end if
		else
			set item i of l to "-- " & thisLine
		end if
	end repeat
end ignoring

set text item delimiters to return

tell application "AppleScript Editor" to set contents of selection of document 1 to l as text

set AppleScript's text item delimiters to astid

Nice, I’ll use this for now.

The standard (not line by line) behavior could be more convenient though. (If a selection has both commented and uncommented lines, the already commented ones are commented again.)

It could also support removing (* *) and # style comments, or if # is the preferred style.

Maybe most importantly, it could apply for the current line if there’s no selection. Is there a better way than this?

if sel = "" then
	try
		tell application "System Events"
			key code 123 using {command down, shift down}
			key code 124 using {command down, shift down}
		end tell
	on error
		return
	end try
end if

As a matter of interest, the two ‘key code’ commands can be combined:

tell application "AppleScript Editor" to set sel to contents of selection of document 1

if (sel = "") then
	tell application "System Events" to key code {123, 124} using {command down, shift down}
	tell application "AppleScript Editor" to set sel to contents of selection of document 1
end if

But for the same effect without System Events:

tell application "AppleScript Editor"
	tell document 1
		set sel to contents of selection
		if (sel = "") then
			set theText to its text
			set cursorPos to beginning of (get character range of selection)
			set cursorLine to (count (text 1 thru cursorPos of theText) each paragraph)
			set sel to paragraph cursorLine of theText
			-- This is possible:
			-- set selection to paragraph cursorLine of its text
			-- But to exclude the line-ending, like the System Events method:
			set lineLen to (count sel)
			if (lineLen > 0) then
				set b to (count text 1 thru paragraph cursorLine of theText)
				set a to b - lineLen + 1
				set selection to characters a thru b of its text
			end if
		end if
	end tell
end tell
set text item delimiters to linefeed
set nl to {linefeed, return}
tell application "AppleScript Editor" to tell document 1
	set txt to its text
	if txt is "" then
		set contents of selection to "--"
		set selection to insertion point 3
		return
	end if
	set {chr1, chr2} to character range of selection
	if chr1 is 0 then
		set p1 to 1
	else
		set p1 to count paragraphs of text 1 thru chr1 of txt
	end if
	if chr2 is 0 then
		set p2 to 1
	else
		set p2 to count paragraphs of text 1 thru chr2 of txt
		if nl contains item chr2 of txt and p1 is not p2 then set p2 to p2 - 1
	end if
	
	set selparas to paragraphs p1 thru p2 of txt
	set selection to paragraphs p1 thru p2
	set qf to quoted form of (selparas as text)
	set un to (do shell script "echo " & qf & " | tr -d ' 	' | sed '/^$/d' | sed '/^#/d' | sed '/^--/d'") is ""
	if un then
		set out to do shell script "/bin/bash -c " & quoted form of ("echo " & qf & " | sed 's/^\\([ |	]*\\)--[ |	]*/\\1/'g | sed 's/^\\([ |	]*\\)#[ |	]*/\\1/'g")
	else
		set out to do shell script "/bin/bash -c " & quoted form of ("echo " & qf & " | sed 's/^\\(	*\\)/\\1--/'g")
	end if
	set contents of selection to out & linefeed
	set {chr1, chr2} to character range of selection
	set selection to insertion point chr2
end tell

Edit: Workaround for sh’s echo interpreting escape sequences (like \) inside single quotes. See MacScripter / do shell script: echo double backslash.