Using line breaks in records

This is probably an appleScript compiler issue, but I recall something similar with lists that seems to have been corrected, but I’ll just throw this out there.

I’d like to add line-breaks (option-return) to records so they’re easier to read in compiled scripts. Below is a visual example of what I mean.

Is there anything that can be done to correct the munging of line breaks in records when compiled?


--This is what it looks like

set progressRecord to {ProgressTotal:10, progressCompleted:0, progressDesc:"Filtering unwanted email from Calendar Mail", progressAddDesc:"Reading saved unwanted email addresses"}

--This is how I'd like it to look:

set progressRecord to {ProgressTotal:10, ¬

progressCompleted:0, ¬

progressDesc:"Filtering unwanted email from Calendar Mail", ¬

progressAddDesc:"Reading saved unwanted email addresses"}

--But this is how that compiles

set progressRecord to ¬

¬

{ProgressTotal:10, progressCompleted:0, progressDesc:"Filtering unwanted email from Calendar Mail", progressAddDesc:"Reading saved unwanted email addresses"} ¬

--This is the best I can do (but, no.)

set progressRecord to {ProgressTotal:¬

10, progressCompleted:¬

0, progressDesc:¬

"Filtering unwanted email from Calendar Mail", progressAddDesc:¬

"Reading saved unwanted email addresses"}

I feel your pain :slight_smile:. This, as you guessed, an AppleScript issue. The problem lies with the AppleScript compiler which reformats scripts according to its own indentation rules when they are displayed (i.e. decompiled). This happens (a) when opening a script, and (b) after compiling a script.

One solution I’ve found is to use multiple assignments:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

set r to {} -- using `r` to make the text shorter.
set r to r & {ProgressTotal:10}
set r to r & {progressCompleted:0}
set r to r & {progressDesc:"Filtering unwanted email from Calendar Mail"}
set r to r & {progressAddDesc:"Reading saved unwanted email addresses"}

set progressRecord to r

Its not optimal and fractionally slower, but it does let you break up a large record declaration into pieces.

Or if you are deriving any of the values at run-time, and want to zip them up with the keys and fold the whole lot into a record ‘just in time’, then perhaps something like:

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

on run
    set ks to {"ProgressTotal", "progressCompleted", "progressDesc", "progressAddDesc"}
    set vs to {10, 0, "Filtering unwanted email from Calendar Mail", "Reading saved unwanted email addresses"}
    
    script field
        on |λ|(acc, kv)
            set {k, v} to kv
            insertMap(acc, k, v)
        end |λ|
    end script
    
    foldl(field, {} as record, zip(ks, vs))
end run



-- GENERIC ------------------------------------------------------

-- https://github.com/RobTrew/prelude-applescript


-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
    tell mReturn(f)
        set v to startValue
        set lng to length of xs
        repeat with i from 1 to lng
            set v to |λ|(v, item i of xs, i, xs)
        end repeat
        return v
    end tell
end foldl


-- insertMap :: Dict -> String -> a -> Dict
on insertMap(rec, k, v)
    tell (current application's NSMutableDictionary's ¬
        dictionaryWithDictionary:rec)
        its setValue:v forKey:(k as string)
        return it as record
    end tell
end insertMap

-- min :: Ord a => a -> a -> a
on min(x, y)
    if y < x then
        y
    else
        x
    end if
end min

-- Lift 2nd class handler function into 1st class script wrapper 
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    if class of f is script then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn

-- zip :: [a] -> [b] -> [(a, b)]
on zip(xs, ys)
    set lng to min(length of xs, length of ys)
    set lst to {}
    repeat with i from 1 to lng
        set end of lst to {item i of xs, item i of ys}
    end repeat
    return lst
end zip

Or take advantage or the more foldable nature of lists with:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

on run
    set kvs to {{ProgressTotal:10}, {progressCompleted:0}, ¬
        {progressDesc:"Filtering unwanted email from Calendar Mail"}, ¬
        {progressAddDesc:"Reading saved unwanted email addresses"}}
    
    
    script
        on |λ|(acc, rec)
            acc & rec
        end |λ|
    end script
    foldl(result, {} as record, kvs)
end run


-- GENERIC ------------------------------------------------------

-- https://github.com/RobTrew/prelude-applescript

-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
    tell mReturn(f)
        set v to startValue
        set lng to length of xs
        repeat with i from 1 to lng
            set v to |λ|(v, item i of xs, i, xs)
        end repeat
        return v
    end tell
end foldl

-- Lift 2nd class handler function into 1st class script wrapper 
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    if class of f is script then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn

How about using the continuation character (¬) to define line breaks? There’s no slowdown.

Stan C.

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

set r to {¬
  {ProgressTotal:10}, ¬
  {progressCompleted:0}, ¬
  {progressDesc:"Filtering unwanted email from Calendar Mail"}, ¬
  {progressAddDesc:"Reading saved unwanted email addresses"} ¬
}
set progressRecord to r

Unfortunately, this approach produces a list of records:

07%20PM

In my case I’m defining a record.

In your example you’re defining a list of records.

(For some reason when I paste in the SD output into a forum post it’s changing it to double spaces.)

Whereas with lists, you can insert the continuation character after a comma, with records, you can insert them before the comma. Note that a continuation character can’t follow a string, but this can be circumvented by enclosing a string in parentheses.

set progressRecord to {ProgressTotal:10 ¬
	, progressCompleted:0 ¬
	, progressDesc:("Filtering unwanted email from Calendar Mail") ¬
	, progressAddDesc:("Reading saved unwanted email addresses")}
2 Likes

Ah, of course! I was in a hurry and followed your code example a bit too closely. I should’ve omitted all the curly braces appearing inside the outermost pair.

As CJK points out, there are rules for using the continuation character, so those would need to have been moved to before the commas, in this case.

Stan C.

Thanks, that is better, still looks yucky, but I’ll use it. The parens tip particularly helps!