This IDE script will intelligently close a quote or paren while you are typing in Xojo, emulating a feature found in other editors. If you enter a quote or opening paren, it will enter the closing character and position your cursor between. If you then “close” it again, it will remove the unneeded character and move the cursor for you.
I tied this to a Keyboard Maestro macro triggered by entering (, ), or ". When triggered by ), it delays by 0.2 seconds before running the script.
Enjoy.
//
// FUNCTIONS
//
Function IsEOLChar (char As String ) As Boolean
static eolChars() as string = array( chr( 10 ), chr( 13 ) )
return eolChars.IndexOf( char ) <> -1
End Function
//
// MAIN
//
if SelLength <> 0 then
return
end if
dim pos as integer = SelStart
dim code as string = Text
dim codeLen as integer = code.Len
if code.Trim = "" then
return
end if
//
// If we didn't just type the expected char then return
//
dim typedChar as string = code.Mid( pos, 1 )
dim typedIsParen as boolean = typedChar = "(" or typedChar = ")"
dim typedIsQuote as boolean = typedChar = """"
if not typedIsParen and not typedIsQuote then
return
end if
dim isContinueChar as boolean = false
dim inComment as boolean = false
dim inQuote as boolean = false
dim codeLineStart as integer = 1
for i as integer = 1 to pos - 1
dim thisChar as string = code.Mid( i, 1 )
dim twoChars as string = code.Mid( i, 2 )
dim fiveChars as string = code.Mid( i - 1 , 5 )
if IsEOLChar( thisChar ) then
inComment = false
if isContinueChar then
isContinueChar = false
else
codeLineStart = i + 1
end if
elseif inComment then
//
// Continue
//
elseif thisChar = """" then
inQuote = not inQuote
elseif inQuote then
//
// Continue
//
elseif thisChar = "'" or twoChars = "//" or fiveChars.Trim = "REM" then
inComment = true
elseif thisChar = "_" then
isContinueChar = true
elseif isContinueChar and thisChar <> " " and thisChar <> &u09 then
isContinueChar = false
end if
next
if inComment then
return
end if
dim codeLineLength as integer = codeLen - codeLineStart + 1
//
// Get the length of this code block
//
for i as integer = pos to codeLen
dim thisChar as string = code.Mid( i, 1 )
dim twoChars as string = codeLine.Mid( i, 2 )
dim fiveChars as string = codeLine.Mid( i - 1 , 5 )
if IsEOLChar( thisChar ) then
if isContinueChar then
isContinueChar = false
inComment = false
else
codeLineLength = i - codeLineStart
exit
end if
elseif inComment then
//
// Continue
//
elseif thisChar = """" then
inQuote = not inQuote
elseif inQuote then
//
// Continue
//
elseif thisChar = "'" or twoChars = "//" or fiveChars.Trim = "REM" then
inComment = true
elseif thisChar = "_" then
isContinueChar = true
elseif isContinueChar and thisChar <> " " then
isContinueChar = false
end if
next
dim codeLine as string = code.Mid( codeLineStart, codeLineLength )
dim codePos as integer = pos - codeLineStart + 1
//
// See if the opening and closing parens already balance
// and get the nextChar
//
dim nextChar as string
dim nextCharCodePos as integer = codeLineLength + 1
dim parenCount as integer
dim quoteCount as integer
isContinueChar = false
inComment = false
inQuote = false
for i as integer = 1 to codeLineLength
dim thisChar as string = codeLine.Mid( i, 1 )
dim twoChars as string = codeLine.Mid( i, 2 )
dim fiveChars as string = codeLine.Mid( i - 1 , 5 )
if IsEOLChar( thisChar ) then
inComment = false
isContinueChar = false
continue
elseif inComment then
continue
elseif thisChar = """" then
if inQuote then // Close quote
quoteCount = quoteCount - 1
inQuote = false
else // Open quote
quoteCount = quoteCount + 1
inQuote = true
end if
isContinueChar = false
elseif inQuote then
continue
elseif thisChar = "'" or twoChars = "//" or fiveChars.Trim = "REM" then
inComment = true
elseif thisChar = "_" then
isContinueChar = true
elseif thisChar = "(" then
parenCount = parenCount + 1
isContinueChar = false
elseif thisChar = ")" then
parenCount = parenCount - 1
isContinueChar = false
elseif thisChar <> " " then
isContinueChar = false
end if
//
// Won't get here if it's EOL or inComment or inQuote
//
if not isContinueChar and _
nextChar = "" and _
i > codePos and _
( typedIsQuote or ( thisChar <> " " and thisChar <> &u09 ) ) and _
true then
nextChar = thisChar
nextCharCodePos = i
end if
next
if ( typedIsQuote and quoteCount = 0 ) or ( typedIsParen and parenCount = 0 ) then
//
// Everything is already in balance, so let's not screw it up
//
return
end if
//
// We've met all the conditions, so do it
//
if ( typedChar = ")" and nextChar = ")" and parenCount < 0 ) or ( typedChar = """" and nextChar = """" and quoteCount > 0 ) then
//
// They have doubled up so removed the just typed character
//
SelStart = SelStart - 1
SelLength = 1
SelText = ""
SelStart = codeLineStart + nextCharCodePos - 2
elseif typedChar = ")" then
//
// Leave it alone
//
else // quote or open paren
//
// Insert the closing char
//
dim chars as string = if( typedIsQuote, """""", "()" )
SelStart = SelStart - 1
SelLength = 1
SelText = chars
SelStart = SelStart - 1
end if