Edit text with indentations

applescriptautomator

When editing text in selection using Applescript in an Automator service, is it possible to keep the original indentation whilst adding tabbed spaces in front of it?

Automator Workflow and Script

screenshot of automator workflow

on run {input, parameters}
   if "/*" is in item 1 of input then
      set input to replace("/*", "", input as string)
      set input to replace("*/", "", input as string)
      set input to extract(2, 2, input)
      set input to indent(input, false)
      return input
   else
      set input to indent(input, true)
      set input to "/*" & return & (input as string) & return & "*/"
      return input as text
   end if
end run

on replace(searchString, editString, inputString)
   set previousDelimiters to AppleScript's text item delimiters
   set AppleScript's text item delimiters to searchString
   set stringItems to text items of inputString
   set AppleScript's text item delimiters to editString
   set outputString to stringItems as string
   set AppleScript's text item delimiters to previousDelimiters
   return outputString
end replace

on indent(input, incrementing)
   set spacing to tab
   set input to input's text items
   if not incrementing then
      set previousDelimiters to AppleScript's text item delimiters
      set AppleScript's text item delimiters to ""
      set output to replace(spacing, "", input as string)
      set AppleScript's text item delimiters to previousDelimiters
      return output
   else
      set previousDelimiters to AppleScript's text item delimiters
      set output to item 1 of input as text
      set AppleScript's text item delimiters to linefeed & spacing
      set output to spacing & (every paragraph of output) as string
      set AppleScript's text item delimiters to ""
      return output
   end if
end indent

on extract(startOffset, endOffset, input)
   set firstParagraph to (first paragraph of input)
   set lastParagraph to (last paragraph of input)
   set firstLine to length of firstParagraph
   set lastLine to length of lastParagraph
   set input to text (firstLine + startOffset) thru -(lastLine + endOffset) of input
   return input
end extract

The following snippet demonstrates expected results and current output using the aforementioned workflow and script:

Sample Input

let c1 = CLLocation(latitude: self.latitude, longitude: self.longitude)
let c2 = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)

Expected Result

/*
    let c1 = CLLocation(latitude: self.latitude, longitude: self.longitude)
    let c2 = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
*/

Current Output

/*
 let c1 = CLLocation(latitude: self.latitude, longitude: self.longitude)
 let c2 = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
 */

Best Answer

Updated to reflect updated question along with comments to achieve the goal of toggling comments in Xcode.

The following example AppleScript code, shown further below, used in an Automator Service was tested in macOS Sierra and Xcode 8.3.3 and works to comment the selected code or uncomment the selected code, within the manner of coding in the example AppleScript code.

In other words, if the selected code looks like:

void myDelay(float value) {
    NSDate *future = [NSDate dateWithTimeIntervalSinceNow:value];
    [NSThread sleepUntilDate:future];
}

And the Automator Service is run on the selected code above, it will look like:

/*
    void myDelay(float value) {
        NSDate *future = [NSDate dateWithTimeIntervalSinceNow:value];
        [NSThread sleepUntilDate:future];
    }
*/

Or if the selected code looks like:

/*
    void myDelay(float value) {
        NSDate *future = [NSDate dateWithTimeIntervalSinceNow:value];
        [NSThread sleepUntilDate:future];
    }
*/

And the Automator Service is run on the selected code above, it will look like:

void myDelay(float value) {
    NSDate *future = [NSDate dateWithTimeIntervalSinceNow:value];
    [NSThread sleepUntilDate:future];
}

Example AppleScript code for use in a Run AppleScript action in an Automator Service.

on run {input, parameters}
    set selectedText to item 1 of input as text
    set outputText to {}
    if selectedText contains "/*" then
        repeat with i from 2 to ((count paragraphs of selectedText) - 1)
            if (count characters of paragraph i of selectedText as text) is 1 then
                copy "" to end of outputText
            else
                copy (characters 2 thru -1 of paragraph i of selectedText as text) to end of outputText
            end if
        end repeat
    else
        copy "/*" to end of outputText
        repeat with i from 1 to (count paragraphs of selectedText)
            copy tab & paragraph i of selectedText to end of outputText
        end repeat
        copy "*/" to end of outputText
    end if
    set AppleScript's text item delimiters to {linefeed}
    set outputText to outputText as text
    set AppleScript's text item delimiters to {}
    return outputText
end run

Notes:

Xcode (8.8.3 anyway) does not support nested block commented code, meaning that if you comment some code with this script and then select additional code that includes code previously commented by this script, it will throw an error when running the service. You can work around this by changing:

if selectedText contains "/*" then

To:

if first paragraph of selectedText contains "/*" then

However Xcode will then show the nested commented code as having errors. So the real value of this script is to use it only on code that will not then be selected again as a larger block after the original commenting by this script.

When uncommenting code you should always be sure to select so the first and last lines of selection contain the block comment characters, /* and */, with no leading or trailing blank lines in the selection.

Also, Xcode has a built-in keyboard shortcut to comment selected lines with a leading // by selecting the code and pressing command/. Pressing the same keyboard shortcut removes the leading //. This is some ways negates the need to use this scripted solution.

There are third-party plugins for comments in Xcode and a Google search should be fruitful.

One example is: BlockComment for Xcode


See edit history for original answer before the OP was updated with actual details of the objective.


Note: The example AppleScript code is just that and does not employ any error handling and is meant only to show one of many ways accomplish a task. The onus is always upon the User to add/use appropriate error handling as needed/wanted.