vipercard > script reference

Overview | Commands | Syntax | Properties | Functions | Event Handlers | Compatibility

Introduction

Welcome to ViperCard, an open source re-creation and re-imagination of 1987's HyperCard. We suggest first watching the example videos (here).

Scripting

All objects (all buttons, fields, and cards) have an associated set of code called a "script."

Here is an example script:

on mouseUp
    answer "hello, world"
end mouseUp

If this script is placed in a button, and the Browse tool is chosen (looks like a hand), the code will be run when the button is clicked.

A line of code beginning with -- is ignored. This is often used to write explanatory comments. It can also be used to temporarily "disable" some code. You can press Cmd+Q in the script editor to quickly comment-out or uncomment a line.

on mouseUp
    -- this line is a comment
    answer "hello, world"
end mouseUp

The indentation helps readability, but it is not mandatory. The code editor will automatically add indentation whenever you press Tab or Enter.

A long line of code can be continued with a backslash, e.g.

answer ("here is how to continue" & \
    "code across two lines")

To have a comment spanning many lines, do this,

on mouseUp
    --[[this line is a comment
    and so is this
    and also this]]
    answer "hello, world"
end mouseUp

The language is not case sensitive. on mouseup and on mouseUp are equivalent.

A common data type is a string (i.e. text).

put "abc" into x

Double-quotes ("), not single-quotes ('), must be used. A string with length 0, "", is perfectly valid and used often to represent a missing value. You may see this referred to as an 'empty string'. You can easily test for an empty string with code like:

if x is "" then
    answer "empty string"
end if

To include a double-quote character in a string, use the quote constant,

answer (quote & "a" & quote) -- displays "a"

Valid numbers include 123, 123.456, and scientific notation like 1.23e6 which means 1.23 multiplied by (10 to the 6th power). Numbers can be in the range [-1e18, 1e18], if a number is taken outside this range a runtime error will be thrown. Division by zero, logarithm of a negative, and so on will also cause a runtime error.

sqrt(0.5) is a function call meaning to take the square root of 0.5. sum(1, 2) is a function call that adds 1 and 2 and returns 3. A comma separates the values sent. Function calls can be nested, for example, sum(1, sum(2, 3)).

You can call a function in two ways. the mouseLoc is the same as mouseLoc(). the length of "abc" is the same as length("abc").

Buttons and fields are referred to as "objects". Cards are also a type of object. And, the entire project, referred to as a "stack", is an object.

A script can set properties of an object with syntax like:

set the width of cd btn "myBtn" to 450

Choose the button tool and select a button, and its id will be shown in the panel on the right. One can refer to an object by id in a script:

set the width of cd btn id 1234 to 450

When you are in the Browse tool and you interact with the page by clicking on buttons or pressing keystrokes, this causes messages to be fired. If you click a button, and if that button has a script that happens to have a function called on mouseUp defined, then the code inside on mouseUp will be run.

The documentation here has a list of Commands, Event Handlers, and Properties that can be set.

Expressions

You can use expressions like put 1+2+3+4 into x or put sqrt(0.5) + sqrt(0.6) into y in your code.

Expressions can use parentheses to contain any level of nested sub-expressions, for example,

sqrt(0.5)
sqrt(0.5 + sqrt(0.6))
sqrt(0.5 + sqrt(0.6 + sqrt(0.7)))

are all valid.

Parentheses are used to dictate the order of operations, since

3*(4+5)

gives a different answer than

(3*4)+5

Parentheses are also used for grouping an expression. For example, we needed to get the (n + 1)th line of a variable, we would type (line (n + 1) of x)

Do not type something like

answer (line n + 1 of x) -- this is hard to read.

which is unclear,

answer (line (n + 1) of x) -- this is preferred.

In the expression 2 + 3, the symbol + is called an operator.

ViperCard also has logical operators like and, or, and not.

See the operators page in the Syntax documentation section

for more information.

Message Box

Open the Message Box by choosing 'Message Box' from the Go menu, or by pressing Cmd+M.

The message box can be used to quickly try out snippets of code. For example, if you want to evaluate some math, you can open the message box, type put 12*34, and press Enter. The result will be shown below.

As another example, if you have two buttons, and you want to align the left sides of the buttons, you can type set the left of cd btn 2 to the left of cd btn 1, and press Enter, and the action will be performed.

You can use the Up and Down arrow keys to see previously typed commands.

You can use a semicolon to combine many lines, for example put 2 into x; put x * 3

You can use the message box to check or change the contents of a global variable. In fact, any variable mentioned in the message box will be assumed to be a global, so you can write put 4 into myGlobal without first needing to declare global myGlobal.

In your script, you can add debugging statements that trace a value and show it in the message box, as long as the message box is currently open.


put 45 * 56 into x
-- if the msg box is open, will show the value of x
-- otherwise, the line is ignored
put x into the msg box
-- code will continue running

The shortened form,


put 45 * 56 into x
-- if the msg box is open, will show the value of x
put x

is also supported.

Lists/Arrays

Here's a common way to create a list:

put "" into myList
repeat with x = 1 to 5
    put 0 into line x of myList
end repeat

Append a number to the list:

put newline & 20 after myList

Insert a number in the list (if the line doesn't yet exist, it will be added)

put 6 into line 8 of myList

Add 10 to each element of the list:

repeat with x = 1 to the number of lines in myList
    put (line x of myList) + 10 into line x of myList
end repeat

myList is a normal variable, it can be passed as an argument and so on.

Two-dimensional lists

Here's a common way to create a 2-d list:

put "" into myList
repeat with x = 1 to 5
    repeat with y = 1 to 5
        put 0 into item x of line y of myList
    end repeat
end repeat

Insert a new number into the list (it's ok if the line or item does not yet exist, it will be created):

put 3 into item 6 of line 8

Add 10 to each element of the list:

repeat with y = 1 to the number of lines in myList
    repeat with x = 1 to the number of items in line y of myList
        if length(item x of line y of theLine) > 0 theLine
            add 10 to item x of line y of theLine
        end if
    end repeat
end repeat

Variables

Use a statement like

put 3 into x

to put the value "3" into a variable named "x". You don't need to first declare x as a variable.

Variable names and function names are case insensitive.

Variable names cannot begin with a numeral, and can contain underscores but no other punctuation. Certain words cannot be used as variable names because they are already keywords or built-in functions. For example, you cannot have a variable named "line" because this is a keyword. You cannot have a variable named "result" because this is a built-in function.

If you try to read from a variable before it has been introduced, a runtime error will occur. put notSeenBefore into x will cause an error unless there is a statement assigning a value to notSeenBefore.

Use "global" to declare a variable as a global.

1) it can be accessed from any other script

2) its contents are saved even after the function is complete.

For example,

global coordX, coordY
put 1 into coordX
put 2 into coordY

If another script says

global coordX, coordY
answer coordX, coordY

it will read the values that were set.

Global variables are, though, reset when you close the stack (the values

are not saved as part of the project.)

Data types

A runtime error can be thrown if a value has the wrong

type, e.g.

put "abc" + 4 into z

causes a runtime error! The addition operator requires numbers, and so creates a runtime error when getting the string "abc".

If you need to convert from a text type to a number, you can use the functions strToNumber and numberToStr. For example,

ask "please enter a number"
put it into x
if strToNumber(x) is not false then
    answer "the number plus one is" && (strToNumber(x) + 1)
end if

For if and else if, only true or false are accepted, any other value is a runtime error. For example, to check that a string is not empty, you cannot say if myVar then, you have to say something like if length(myVar) > 0 then instead.

Note that equality checks account for different data types:

if (456 is "456.00") then answer "yes" -- answers yes

A "point" data type is two numbers separated by a comma. You can write:


put 1 into x
put 2 into y
set the topleft of cd btn "myBtn" to x, y

This is the same as writing


set the topleft of cd btn "myBtn" to 1, 2
set the topleft of cd btn "myBtn" to "1, 2"
-- or
set the top of cd btn "myBtn" to 1
set the left of cd btn "myBtn" to 2

User Functions

An example of how to define and call a custom function:

function myAddition p1, p2
    return p1 + p2
end myAddition
on mouseUp
    put myAddition(1,2) into x
end mouseUp

An example of how to define and call a custom handler:

on showMessage p1, p2
    put p1 into cd fld "results1"
    put p2 into cd fld "results2"
end showMessage
on mouseUp
    showMessage "hello", "world"
end mouseUp

You can define variadic functions (that accept any number of values), see the documentation for the paramCount() function.

No error is thrown if the incorrect number of arguments is given. Missing arguments are given the empty string ("").

myAddition(7, 8, 9) -- the extra argument 9 is ignored
myAddition(7, 8) -- p1 is assigned 7, p2 is assigned 8
myAddition(7) -- p1 is assigned 7, p2 is assigned ""
myAddition() -- p1 is assigned "", p2 is assigned ""

You can use recursion.

You can place common code in the current card's script, or the stack's script, so that it can be called by many objects. This is because of the message hierarchy:

Messages bubble upwards from a button or field, to the parent card, to the stack, until they are handled.

Calling exit to ViperCard passes the message up to ViperCard to be handled, and then exits all code execution. So it has two uses, it will exit all code execution, and will also fall back to the default ViperCard behavior.

See documentation of the 'pass' command for more information.

Calls to custom commands and procedures also bubble upwards in the same way. A function in the stack's script can be called from any handler on a card, field, or button. A function in the card's script can be called from any handler in a field or button. So, it is useful to put commonly used utility code in a stack script so that it can be called from anywhere.

Text and Chunks

Lines

Use newline to refer to a new line character.

Let's say you wanted two lines of text in a field, you would use

the following:

put "first line" & newline & "second line" into cd fld "myFld"

(You shouldn't have to be concerned with platform differences: the constants 'return', 'cr', 'linefeed' are present for compatibility, but they are all equivalent. For convenience, copying and pasting text in and out of ViperCard will automatically translate newline characters, for example if you are running windows, when you copy text we'll automatically convert to \r\n newlines so it will work seemlessly with other software. Internally, ASCII 10 represents newline.)

Chunks

ViperCard can process text by using chunks. If you have a tab-separated list you can get the nth item like this:


put "ab" & tab & "cd" & tab & "ef" into myList
set the itemDelimiter to tab
put 2 into n
answer "Result:" & item n of myList

If you have a comma-separated list you can get the nth item like this:


put "ab,cd,ef" into myList
set the itemDelimiter to ","
put 2 into n
answer "Result:" & item n of myList

More advanced examples:


answer char 2 of "abcd"
answer char (n + 1) of "abcd"
answer char 2 to 4 of "abcd"

answer item 2 of "ab,cd,ef,gh"
answer item (n + 1) of "ab,cd,ef,gh"
answer item 2 to 4 of "ab,cd,ef,gh"

answer first item of "ab,cd,ef,gh"
answer last item of "ab,cd,ef,gh"
answer any item of "ab,cd,ef,gh"

put "ab" & newline & "cd" & newline & "ef" into myList
answer line 2 of myList
answer line (n + 1) of myList
answer line 2 to 3 of myList

Recursive scopes:


put "ab,cd" & newline & "ef,gh" & newline & "ij,kl" into myList

answer item 2 of line 2 of myList
answer char 2 of line 2 of myList
answer char 2 of item 2 of line 2 of myList

answer char 2 to 3 of item 2 to 3 of line 2 to 3 of myList

Modifying by chunk


put "abcd" into x
put "A" into char 2 of x
put "A" into char 2 to 4 of x

put "10,20,30" into myList
put "A" into item 2 of myList
put "A" into item 2 to 3 of myList
multiply item 2 of myList by 5
add 1 to item 2 of myList

put "A" into first item of myList
put "A" into last item of myList
put "A" into any item of myList

put "A" into before item 2 of myList
put "A" into after item 2 of myList
put "A" into before char 2 of item 2 of myList

put "A" into before item 2 of cd fld "myFld"
put "A" into after item 2 of cd fld "myFld"
put "A" into before char 2 of item 2 of cd fld "myFld"

put "ab,cd" & newline & "ef,gh" & newline & "ij,kl" into myList
put "A" into item 2 of line 2 of myList
put "A" into char 2 of line 2 of myList
put "A" into char 2 of item 2 of line 2 of myList

put "A" into char 2 to 3 of item 2 to 3 of line 2 to 3 of myList

Backwards compatiblity

We went to much effort to maintain fidelity with HyperCard's chunk processing. All of the above can be done with words:


put "ab cd ef" into x
answer word 2 of x
answer word 2 to 3 of x
put "A" into word 2 of x
put "A" into word 2 to 3 of x
put "A" into char 2 to 3 of word 2 to 3 of x

To enable full compatibility with HyperCard, go to Object->Stack info... and turn on compatibility mode. Chunk handling will now be identical (including the non-intuitive behavior seen below).


-- if compatibility mode is on:
-- we follow HyperCard's non-intuitive behavior for the following:
put "ab,cd" & newline & "ef,gh" & newline & "ij,kl" into myList
put "A" into item 3 of item 4 of myList
put "A" into item 3 of char 2 of myList
delete item 3 of item 4 of myList
delete item 3 of char 2 of myList
add 1 to item 3 of item 4 of myList
add 1 to item 3 of char 2 of myList
answer item 0 of myList
put "A" into item 0 of myList
answer item 4 to 1 of myList
put "A" into item 4 to 1 of myList


-- The only known cases we don't support (we'll throw a runtime error):
answer item -1 of myList
put "A" into item -1 of myList
delete item -1 of myList
answer char 2 of item 4 to 1 of myList
put "A" into char 2 of item 4 to 1 of myList
delete char 2 of item 4 to 1 of myList
delete item 2 to 3 of myList

See also documentation for the delete command.

Objects

Ways to refer to a button or field:


cd btn id 1234
cd btn "myBtn"
cd btn 2
first cd btn
any cd btn
last cd btn

Ways to refer to a card:


this card
prev card
next card
first card
second card
last card
card 1
card id 1234
card "name"

Ways to refer to a background:


this background
prev background
next background
first background
second background
last background
bg 1
bg id 1234
bg "name"

Ways to refer to a stack:


this stack
stack 1
stack "name"

Other ways to refer to objects:


answer the name of the target
answer the name of me
answer the name of the owner of cd btn id 1234
put "cd btn id 1234" into x
answer the name of x

function whichObject
    return "cd btn id 1234"
end whichObject
answer the name of whichObject()

Structure

Loops

repeat with x = 1 to 3
    ...other code here...
end repeat

Refer to repeat under "syntax" for more information.

If statements

if x > 1 then
    ...other code here...
else
    ...other code here...
end if

Refer to if under "syntax" for more information.

Scripts

No code can exist outside of a handler or function.

Handlers

Handlers look like this

on mouseup 
    answer "hello world"
end mouseup

and respond to an event message.

Functions

Functions look like this

function myAddition p1, p2
    return p1 + p2
end myAddition

They can then be called with code like

put myAddition(1,2) into x

Functions inside of functions are not supported.

Statements

You cannot have a line that is just

sqrt(0.5)

with no command, this is a syntax error.

Statements occur on separate lines, there's no way to have more than one statement on a line.

Expressions

A set of computations such as 1+2+3+4 or sqrt(0.5) + sqrt(0.6) is an expression. Most places that take a value can be given an expression, for example,

go card 2
-- is the same as
put 1 into x
go card (x + 1)

put "abc" into cd fld "myFld1"
put "abc" into cd fld (prefix & "1")

put "a" into line 4 of myList
put "a" into line (x+1) of myList

set the left of cd btn "myBtn" to x
set the left of cd btn "myBtn" to (45 + 50 * cos(theta))

Examples

The tutorial videos show helpful example code.

Example 1:


-- after creating a field called "myFld":
-- create a btn and put this in its script:
on mouseUp
    -- when you click button "Go", you get 10 points!
    put cd fld "myFld" into score
    put (score + 10) into score
    put score into cd fld "myFld"
end mouseUp

Example 2:


-- after creating a btn called "fish":
-- create a btn and put this in its script:
on mouseUp
    -- when you click this, the fish moves
    put the top of cd btn "fish" into y
    subtract 10 from y
    set the top of cd btn "fish" to y
end mouseUp

Example 3:


-- create interactive art.
-- put this in the card script,
-- then when you choose the browse tool and 
-- click on the card, it will draw lines.

on mouseUp
    put the clickH into X
    put the clickV into y

    -- choose the line tool to draw lines
    choose "line" tool

    -- make a loop that will repeat 10 times
    repeat 10 times
        put random(80) into randx
        put random(80) into randy
        -- will get random # between 1 and 80
        drag from x, y to (x + randx), (y + randy)
    end repeat
end mouseUp

Tips & Shortcuts

General tips

Keyboard shortcuts when editing text,

Some of the main differences between ViperCard and HyperCard:

A few of the differences between ViperCard and HyperCard:

What's New

New in 0.24

Credits

ViperCard

https://github.com/moltenform/vipercard

Copyright (C) 2020 Ben Fisher

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

ViperCard uses the following libraries: