helberg acl-final

71
Arbortext Command Language (ACL) Basics Clay Helberg The MathWorks

Upload: clay-helberg

Post on 08-Aug-2015

100 views

Category:

Documents


2 download

TRANSCRIPT

Arbortext Command Language (ACL) BasicsClay Helberg

The MathWorks

Arbortext Command Language (ACL)

• ACL is a scripting language embedded in Arbortext Editor

• Provides ways to:

– Control the software

– Make dialogs work

– Navigate and manipulate documents

– Interface with other software components (e.g. Publishing Engine, Dynamic Link Manager, Content Manager, etc.)

– Interact with user

Arbortext Command Language (ACL)

• Basic syntax

• Variables and arrays

• Defining and using functions

• Working with files and documents

• Modifying the content of documents

• Using callbacks and hooks to handle events

• Integrating ACL scripts into your application

Basic Syntax

• ACL is sort of Perl-ish, sort of C-ish

– Like Perl, without the “line noise”

– Like C, without the pointer arithmetic and memory management

• Statements are the fundamental steps in a program

– Two types of statements: commands and functions

ACL Commands

• Commands use syntax like this:

commandname argument argument …

• Commands don’t return a value

• BUT May store information in system variables about error status, etc.

• Example:

print composed current

ACL Functions

• Functions use syntax like this:

functionname ( argument, argument, …)

• Functions often, but not always, return a value

– Result of calculation or transformation

– Status of operation (success/failure)

• Example:

if (doc_name(doc)==“foo.xml”) …

ACL Functions

• Gotcha: Return value vs. updated parameter

– Example:

Global $windows[]$return = window_list($windows);

– $return is number indicating status (number of windows), not the list itself

– The actual list (array) of windows is stored in $windows

ACL Comments

• Comments start with a hash #

• Everything after the hash is ignored

# This function is really coolfunction reallyCoolFunction(input) {

# do some really cool stuff here}

• You can stick a comment at the end of a line after some “real” code

if (oid_type($oid) == 4) { # type 4 -> equation

ACL Blocks

• A block is a section of a program that is a cohesive unit

• Delimited with curly braces { }

• Examples:

– Function definitions

– The branches of if/else statements

– The guts of while and for loops

ACL Flow Control

• The usual flow control structures are supported

– for loops

for (i=1; i < count($arr); i++) { doc_close($arr[i]);}

– while loops

find “Leno”while ($status == 0) { delete_mark; insert_string “O’Brien” find “Leno”}

More ACL Flow Control

– if/else branches

if ($size == “legal”) { set stylesheet=“legal.style”}else { set stylesheet=“letter.style”}

Still more flow control

– switch trees:

$resp = response(“Save Changes?”,”Yes”,”No”,”Cancel”);

switch ($resp) {

case 1:

doc_save(current_doc());

break;

case 2:

set modified=off;

doc_close(current_doc());

break;

case 3:

# do nothing

}

ACL Packages

• Analogous to Java or Perl packages

• Similar to namespaces in XML

package log;

global $errlog = “C:\temp\apterr.txt”;function error(msg) {

local $fid = open($log::errlog,a);put($fid, “*** ERROR: $msg\n”);flush($fid);close($fid);

}

Using Packages

• Use require to import a package’s code

• Use package::functionname to call a function in another package

package custom;require log;

function load_doc(docname) {local $docid = doc_open(docname);if ($docid == -1) {

log::error(“Couldn’t open $docname”);}

}

ACL Variables

• Variables in ACL are dynamically typed

– Automatically assumes the required type for the value

• Name is sometimes preceded with a $ like Perl (optional)

– But arrays are NOT preceded with an @

• You can define scope with local and global keywords

– Default is local scope

– Local variables are only accessible in the block in which they are declared (e.g. inside a function)

– Global variables are accessible anywhere

Assigning Values to Variables

• Assign values using the assignment operator =

– $mydoc = “C:\\temp\\mydocs\\mydoc.xml”;

• You can use expressions in assignment

– $mydoc = current_doc();

– $mypath = dirname(doc_path(current_doc()));

Assigning Values to Variables

• You can also use shortcut assignment operators

– $linecount += 1;

– $product *= get_multiplier();

• Use . (dot) operator for string concatenation

– $msg = “Do you want to close “ . doc_name() . “?”;

ACL Variable Evaluation

• Variables are evaluated

– Variable references inside double quotes are evaluated

•$docname = “foo.xml”;

•$msg = “Close $docname?”# returns “Close foo.xml?”

– References inside single quotes are not

•$msg = ‘Close $docname?’# returns “Close $docname?”

Deferred Evaluation of Variables

• Gotcha: In commands, you may need to defer evaluation

– Ex: (wrong way – prints first doc repeatedly)for ($i in $doclist) {

print composed $doclist[$i];}

• Use execute or eval commands to defer

– Ex: (right way – prints each document once)for ($i in $doclist) {

execute(“print composed $doclist[$i]”);}

ACL Arrays

• ACL supports two kinds of arrays

– Normal arrays, indexed by number

$array[1] = “foo”

– Associative arrays, indexed by key

$array[“foo”] = “bar”

• Gotcha: ACL arrays are indexed from one, not zero

Declaring ACL Arrays

• Both types have the same declaration syntax:

– [local | global] $arrayname[];

• Most arrays resize dynamically as necessary

– Unless declared using global and a fixed size

•global $myarray[10];

• Use square brackets [] to access array elements

– $msg = “the first element is $myarray[1]”;

– $msg = “owner of $docname is $owners[$docname]”;

Using ACL Arrays

• You can iterate over items in an array usingfor (… in …) construction

– for ($i in $myarray) {if ($myarray[$i]==doc_name()) {

response(doc_name() . “ is in array”);

break;}

}

• This works for both types of arrays

• Gotcha: Loop index is the array index, not the array value for that index

ACL Built-in Functions

• ACL has a wide variety of built-in functions

User-Defined Functions in ACL

• You can define your own functions

– function functionname(param1, param2) {# do some stuff herereturn result of operation;

}

• Example:

– function doc_dir(doc) {local $docname = doc_name(doc);return dirname($docname);

}

Forward Declarations

• In an ACL file, you often have multiple function definitions

• A function can’t use another function if it hasn’t been defined yet

Why You Need Forward Declarations

• This will fail:

function launch_browser(filename) {local $url = file_to_url(filename);system(“start $url”);

}

function file_to_url(filename) {gsub(filename,”\\”,”/”);return("http://". filename);

}

• We try to use file_to_url() before it is defined

How to Write a Forward Declaration

• Forward declaration is an empty function definition at the top of the file

• Lets other functions know that you're going to define the function later

Forward Declaration Example

• This will work because of the forward declaration:

function file_to_url() {}; # forward decl

function launch_browser(filename) {local $url = file_to_url(filename);system(“start $url”);

}

function file_to_url(filename) {gsub(filename,”\\”,”/”);return("http://". filename);

}

A Brief Tour of Built-In Functions

• Arbortext provides a ton of built-in functions for various purposes

• We'll look at some of the most useful categories

– document and file handling

– document content manipulation

– user interaction

• For more information see the online help

– ACL reference in online help is very complete

– If you don't know what it's called, try search

– If you still can't find it, try Adepters email!

Working with Files and Documents

• current_doc() - gets a handle (ID number) for the currently active document

• doc_open() - loads a document

– flags determine whether it's opened as XML or ASCII, whether context checking happens, etc.

• doc_name() - filename of the document

• doc_path() - fully-qualified pathname of the doc

• doc_incomplete() - tells whether doc is valid

• doc_save() - saves the document

• edit_new_window() - opens document in a new edit window

Working with Generic Files

• open() - open an arbitrary file for reading and/or writing (e.g. for logging messages or importing text content into a document)

• read() - read from a file

• getline() - read from a file one line at a time

• put() - write content to a file

• close() - close a file

General File System Info

• glob() - fills an array with names of files that match the globbing expression (e.g. "*.xml")

• file_directory() - tells whether specified filename is really a directory

• file_size() - size of the file

• file_newer() - determines if one file is newer than another

• username() - user name string (from OS)

• system() - execute an arbitrary system command

• file_selector() - starts a standard file selection dialog, returning the user's choice

Modifying Document Contents

• The OID is your friend (Object ID)

– Unique ID for each element in the document

– Can be used to find, access, change, or delete markup

• oid_root() - the root element of the doc

• oid_name() - the name of the specified element

• oid_caret() - the element containing the caret

• oid_attr() - gets the value of the specified attribute on the specified element

• oid_content() - returns the content of the element as a markup string

Moving Around with OIDs

• oid_first() - OID of first element in the doc

• oid_next() - OID of next element

• oid_prev() - OID of previous element

• oid_last() - OID of last element

• oid_parent() - OID of parent element

• oid_child() - OID of nth child element (or null OID if no such child exists)

• goto_oid() - moves the caret to an element

• oid_xpath_nodeset() - nodes that match an XPath expression (OIDs in an array)

Making Changes with OIDs

• oid_select() - selects the element

• oid_modify_attr() - changes an attribute value

• oid_delete_attr() - removes an attribute

• oid_delete - removes the element

• change_tag command - changes the element at the caret (use with goto_oid())

• insert_tag() - inserts a new element at the caret (use with goto_oid())

• insert() - inserts a markup string at the caret

OID example• Return the title of the nearest enclosing element based on

caret location

function oid_title(oid=oid_caret()) { # if this oid has a title, use that oid_find_children(oid,$titles,"title"); if (count($titles) > 0) { return oid_content($titles[1]); } # otherwise walk up the tree till we find one oid = oid_parent(oid); while (oid_valid(oid)) { oid_find_children(oid,$titles,"title"); if (count($titles) > 0) { return oid_content($titles[1]); } oid = oid_parent(oid); }}

Lots More Fun

• There are specific functions for navigating and changing special elements

– Tables

– Graphics

– Equations

– Entities and entity references

– Document objects from repositories

– Change tracking markup

• Too much to cover here--see the online help!

Getting User Input

• There are several ways to get user input in ACL

– response()

– list_response()

– readvar command

– file_selector()

– XUI dialogs

The response() Function

• Simple message with buttons for response

$answer = response(“Continue?”,”Yes”,”No”);

returns 1 returns 2

Multiple Response Buttons

• You can have as many buttons as you like

$ans = response(“Error! What do you want to do?”, \

“&Abort”, \

“&Retry”, \

“&Fail”, \

“Pull out &hair”, \

“&Defenestrate computer”, \

“&Move to MN and open a bait shop”);

The list_response() Function• Similar to response(), but uses an array to

generate a listbox

get_printers($options);

$ans = list_response($options,"Print",\

"Select a printer");

response("You selected $ans");

The readvar Command

• Lets user type a line of text

readvar -title "Notifications" \ -prompt "Enter emails to notify:" \ -value "[email protected]" \ notify;global $emails[];split($notify,$emails,',;');response("You want to notify:\n" . \ join($emails,"\n"));

The file_selector() Function• Use file_selector() to invoke the standard file

chooser for your OS

$fname = file_selector(doc_dir(),"xml",\ "XML files|*.xml|All files|*.*",\ "Select file to open");response("You selected $fname");

Using XUI dialogs

• See Jason & Asli's slides (Tues 1:15, "Using XUI to Manage Cross-References")

• Also dialog item callbacks are handy for this (a few slides from now)

Using Callbacks and Hooks

• Use your own functions to handle events

– document callbacks

– window callbacks

– session callbacks

– dialog item callbacks

• Callbacks vs. Hooks

– Hooks are global, callbacks can have limited scope

Using Callbacks

• Use *_add_callback() to add a callback to the desired item

– window_add_callback(0,"create","setupinfo");

• Use *_remove_callback() to remove a callback

– window_remove_callback(0,"create","setupinfo");

Document Callbacks

• Document callbacks can trigger actions when:

– User copies, cuts, pastes, deletes, inserts, or modifies content

– The document is saved or closed

– A table operation is done

– The document is printed

– Various other things (see online help)

Document Callback Example

• Auto-fill an attribute value when element is inserted

– uses insert_tag_after callback

function remark_add_user(doc,tag,oid,op) { if ((op == 1) && (tag == "remark")) { modify_attr("role",username()); }}

doc_add_callback(current_doc(),'insert_tag_after',\ 'remark_add_user');

Window Callbacks

• Window callbacks can trigger actions when:

– A window is created or destroyed

– A window gains or loses focus

– The caret moves

• Some window callbacks use window_add_callback(), others use window_set()

Window Callback Example

• Reports window information when window is created

function showinfo(win) { response("Window ID=" . win . ", doc ID=" .\ window_doc(win));}

window_add_callback(0,"create","showinfo");

Session Callbacks

• Session callbacks can trigger actions when:

– drag and drop operations happen

– the session ends (quit Arbortext)

Session callback example• Lets user control handling of dropped files using SHIFT

and CTRL keysfunction drop_handler(path,num,count,flags) { local $ext = tolower(substr($path,length($path)-3)); if ($ext == "xml") { if ($flags & 0x0001) { # SHIFT-drag # insert content inline execute("read " . $path); } else if ($flags & 0x0002) { # CTRL-drag # insert Xinclude reference $xi = "<xi:include href='" . $path . "'/>"; insert($xi); } else { execute("edit -newwindow " . path); } }}

session_add_callback("drop_file",drop_handler);

Dialog Item Callbacks

• Used to attach behaviors to dialog items

– Button clicked

– Listbox selection changed

– Checkbox checked or unchecked

– etc.

Dialog Item Callback Example

• Debug message for button

function buttoncb(win,dlgitem,event) { response("You clicked " . \ dlgitem_get($win,$dlgitem,"label"));}

dlgitem_add_callback($win,"MyButton",buttoncb);

Timer Callbacks

• Use a timer callback to make something happen after a specific delay, or repeatedly

Timer Callback Example

• Add autosave every 5 minutes

function autosave(doc) { doc_save(doc);}

timer_add_callback(30000,'autosave',current_doc());

Hooks

• Some overlap with callbacks, but hooks can respond to some things callbacks can’t

– Change tracking events

– Formatting stages (print composition)

– Import/Export

– Preference changes

Hook Example

• Return concurrent Print Composer License to server immediately after printing

function returnlicense() { if (license("PrintPublishing")!=0) { license_release("PrintPublishing"); }}

add_hook(printcompletehook,returnlicense);

Integrating ACL Code with Applications

• ACL code generally goes in the custom directory

– put in $EPIC\custom\...

OR

– set APTCUSTOM environment variable to the location

• e.g. shared configuration on a server

Where to Put ACL Scripts

• Where you put it determines when it runs

– custom\init: runs once when Arbortext starts

– ~/.pubrc (UNIX) or file pointed at by %APTRC% (Windows): User-specific startup script, runs once at startup

– custom\editinit: runs each time you open a document for editing

– custom\doctypes\{yourdoctype}\{yourdoctype}.acl: runs once when the doctype is referenced during a session

– custom\doctypes\{yourdoctype}\instance.acl: runs each time a document of that type is opened

– {document_directory}/{docname}.acl: document-specific, runs when you open {document_dir}/{docname}.xml

Where to Put Non-startup ACL Scripts

• For scripts that don’t need to run at startup, put them in custom\scripts to make them available

– use source {filename} to run from command line or another script

– use require {packagename} to load scripts in a package file from another context

• Gotcha: avoid circular references:

foo.acl:

package foo;require bar;

bar.acl:

package bar;require foo;

Customizing Arbortext Features• Much of Arbortext’s functionality is implemented as

ACL scripts

• By customizing those scripts you can customize how Arbortext works

– Make modified copies of the scripts in custom/scripts. These will override the default scripts.

– DON’T MODIFY ORIGINAL SCRIPTS IN $EPIC/packages or other install subdirectories

• You might want the originals back someday

• You might break something else and have to revert

• Your changes will get blown away next time you upgrade

Using alias Command to Customize

• You can use the alias command to change Arbortext’s definition of certain commands

alias FilePrint { customPrint(); }

Using ACL with Other Custom Code

• You can use ACL to interact with other custom code

– Java

– JavaScript

– VBscript & COM objects

ACL and Java

• Access static methods using java_static()

• Create instances with java_constructor()

• Execute instance methods with java_instance()

• Exchange array data with java_array_to_acl() and java_array_from_acl()

Accessing Java Fields

• No way to access java fields (properties) directly, but you can use reflection

function getJavaField(object,fldname) { class = java_instance(object,"getClass"); field = java_instance($class,"getField",fldname); value = java_instance($field,"get",object); valuestr = java_instance($value,"toString"); java_delete($class); java_delete($field); java_delete($value); return valuestr;}

ACL and JavaScript

• Use js_source() function to execute a JavaScript file

• The source command can also run JavaScript files

• Use javascript() function to execute a string of JavaScript code and return the value to ACL

# make array of day names

split("S,M,T,W,Th,F,S", $daynames, ",");

# use javascript to get today’s day of week

$dow = javascript("d = new Date(); d.getDay();") + 1;

# +1 because JS is zero-indexed but ACL is one-indexed

response("Today is $daynames[$dow]");

ACL and VBScript/COM

• Use source command to execute a VBS file

• com_*() functions provide access to COM objects

# start Excel

$excel = com_attach("Excel.Application");

$ex_wbs = com_prop_get($excel,"Workbooks");

# open our data file

$result = com_call($ex_wbs,"Open","C:\\temp\\data.xls");

# get value of cell A5

$mywb = com_prop_get($excel,"ActiveWorkbook");

$mysheet = com_prop_get($mywb,"Worksheets",1);

$mycell = com_prop_get($mysheet,"Cells",5,1);

$value = com_prop_get($mycell,"value");

# clean up objects with com_release()...

Running ACL Code From the Command Line

• You can run Arbortext in “batch” mode by giving it code on the command line

• Use the –c parameter to give it a string of ACL

• Use the –b parameter to suppress windows (batch mode)

epic –b –c “print composed; quit” foo.xml

Q & A

• Ask now (raise your hand)

• OR Ask later:

– Clay HelbergThe Mathworks

[email protected]