An Introduction to beorg Scripting

Introduction

beorg comes with a scripting language based on Scheme. Some examples of what you can use this for:

The version of Scheme included in beorg is called BiwaScheme, you can find out more on the BiwaScheme home page.

The REPL

The beorg REPL allows you to type Scheme expressions (commands) and see the results immediately.

To start the REPL,

Here is a very simple example of using the REPL which just parrots back “Hello, World”:

> "Hello, World"
"Hello, World"

You can use the beorg REPL to do simple calculations:

> (+ 3 4)
7

This is equivalent to writing 3 + 4.

Getting started

A little more about Scheme

Scheme is conceptually very simple. Most Scheme expressions are in parenthesis and start with the name of a function followed by some arguments. In the example of (+ 3 4) the function is + and the arguments are 3 and 4.

You can nest Scheme expressions. For example:

> (+ 3 (* 2 5))
13

That adds 3 to the result of multiplying 5 and 2.

Scheme is based on lists (Scheme is in the Lisp family of languages and the name Lisp comes from LISt Processor). Both Scheme programs and data are written as lists. If you want a list where the first item isn’t a function to execute you need to write it like this:

> '(apple banana orange)
(apple banana orange)

In the above example you’ve created a list of the symbols apple, banana and orange. A symbol is different from a string in that it can be used to represent the name of a variable or function. If you wanted a list of strings you would write them like this:

'("apple" "banana" "orange")

There are lots of tutorials and books about Scheme and Lisp available on the web.

Variables

You’ll be using Scheme to customize beorg in ways you can’t on the Settings tab.

One example might be wanting to use a different font in the notes editor. It isn’t currently possible to change this from the settings tab, but you can by writing some Scheme. Here is what you’d write if you wanted to use the font Baskerville at size 14pt:

(set! editor-font "Baskerville 14")

You can try this by starting the beorg REPL, writing the above Scheme expression and then editing a note. Note that it won’t affect any editors currently open.

To get help on a particular variable you can use the function documentation. For example:

> (documentation 'editor-font)
The font to use in the REPL. The format is '<FONT NAME> <FONT SIZE>'. For example 'Menlo 15'.

Note that when using set! don’t put a ' before the name, however you must put a ' when using the documentation function.

Saving your customizations

When beorg starts it looks for a file called init.org. This is the same sort of file you use for tasks and notes, however it contains Scheme expressions. The Scheme expressions are in special blocks so that they can be interspersed with normal text. Here is an example of what a simple init.org might look like to change the editor font:

* Fonts
#+begin_src scheme
(set! editor-font "Baskerville 14")
#+end_src

The special blocks indicating the Scheme expressions start with #+begin_src scheme and end with #+end_src.

You can edit your init.org using beorg and the outline editor, however you may find it easier doing so using a text editor on your computer and then syncing with beorg.

Customizations

Fonts

Changing the font used in the editor:

(set! editor-font "<font-name> <font-size>")

For example:

(set! editor-font "Menlo 15")

For a list of the available fonts in iOS check out iOS Fonts.

Changing the font used in the REPL:

(set! repl-font "<font-name> <font-size>")

Editor and REPL keyboard toolbars

A toolbar is shown above the keyboard when editing notes and using the REPL.

Here is an example of an editor toolbar definition:

(set! editor-toolbar-items '(("icon-left" (backward-char))
                             ("icon-right" (forward-char))
                             ("icon-list" (insert "+ "))
                             ("icon-change" (show-transform-commands))
                             ("icon-settings" (insert-code-snippet))))

This toolbar has five icons. You can add as many icons as you wish. If there are more than can be displayed on the screen they will be scrolled horizontally. The variable editor-toolbar-items is a list of lists. Each list, which defines one toolbar item, has either an icon name or some text to display followed by some Scheme to execute.

Show available icons

Changing the REPL toolbar is exactly the same, just use the variable name repl-toolbar-items.

By default the toolbar will only be shown in a full screen editor. If you would like it shown always then add the following to your init.org:

(set! editor-toolbar-show-in-mini #t)

The editor and REPL buffer

The text shown in the editor and REPL is referred to as the buffer. There are various functions which operate on the buffer and retrieve information from the buffer either about the text or the cursor (known as the point). To get the current size of the buffer write (buffer-size).

The cursor/point

The cursor (or point) shows the user where any typed characters will appear. beorg can change the position of the point and get information about its current position.

In addition to the point (cursor) there is also the text currently selected - referred to here as the region.

NOTE: That if no text is selected then both (region-beginning) and (region-end) will be the same as (point).

Changing text in the buffer

To insert text into the buffer use the insert function. For example…

(insert "Hello")

… inserts the text Hello at the position of the point (i.e. the cursor). The point will now be at the end of the text just inserted.

To get some text, so you can manipulate it, use the buffer-substring function which takes two arguments - from and to. For example…

(buffer-substring (point-min) (point-max))

… gets all of the text in the buffer. This can also be achieved using (region).

To delete text in the buffer use delete-region which also takes the arguments from and to. For example…

(delete-region (point-min) (point-max))

… will delete all of the text in the buffer.

To replace the currently selected text use region-text-set. For example…

(region-text-set (string-upcase (region)))

…will convert any selected text into uppercase.

User Interface

Alerts

You can show an alert to the user using the alert function. It takes two arguments, the first is the title of the alert and the second the message. For example…

(alert "Welcome" "Hi there!")

… will show an alert with the text Hi there! to the user in an alerted titled Welcome.

Toasts

An alert requires the user to tap the OK button to dismiss. An alternative to an alert is a toast. This is a message which slides down from the top of the screen and then disappears shortly afterwards. The toast function has the same parameters as an alert, a title and a message. For example…

(toast "Calculation Result" (number->string (+ 2 3)))

… will show a toast with the title “Calculation Result” and the message “5”.

Sheets

To show the user a set of options from which to choose you can create a sheet. A sheet is similar to a toolbar in that it is a list of lists where the first item in each sublist is the text to display to the user (icons not supported here) followed by some Scheme code to run. For example…

(define (show-transform-commands)
  (if (string=? (region) "")
      (alert "" "No text is selected.")
      (sheet '(("Uppercase" (region-text-set (string-upcase (region))))
               ("Lowercase" (region-text-set (string-downcase (region))))))))

…creates a Scheme function which, if the user has some text selected, show a sheet with the options Uppercase and Lowercase. If the user selects Uppercase then their selected text will be converted to uppercase.

Sheets are a great way to extend the editor with functionality that fits your workflow.

Dates

You can request that the user provide a date using the date picker. This will present a date picker and then execute a provided callback. In addition to the callback the date picker function takes the default date to display and whether the date includes a time component. When the user has picked a date the callback will be provided a boolean saying whether or not the user cancelled/removed the date, the date itself and whether the user included a time with the date.

Here is an example:

(date-picker (current-date)
             #f
             (lambda (removed date includes-time)
               (if (not removed)
                   (alert "Date" (date->string date)))))

This will ask the user for a date and then if a date was picked (i.e. the user didn’t tap the trash can to remove the date) then the date will be displayed in an alert.

Custom TODO filters

On the TODO tab you can filter tasks. There are a number of built-in filters (for example only show tasks which have a priority set). Here is an example of a custom filter called “Top Priority” which only shows tasks which have their priority set to A:

(filter-add "Top Priority" (lambda (item) (string=? (item-priority item) "A")))

The first argument to the function filter-add is the name of the filter to show in the filter list. The second argument is a procedure which returns either true or false. In this case true is returned if the priority is A. The procedure will be passed an Org item. The following functions are available to retrieve data from the item:

Starting beorg on a specific tab

You can configure beorg to start on a specific tab (agenda, TODO or files). For example…

(set! ui-start-tab "todo")

…will tell beorg to start on the TODO tab. Other valid options are agenda and files.

Adding functionality to the item editor

(Requires beorg 3.19.0 or newer)

The item editor is the primary way to add and edit individual items. An example of an item in a .org file:

* TODO [#A] Plan next months newsletter :newsletter:
SCHEDULED: <2022-01-09 Mon>
Talk with Sheila about what she needs to include.

You can see the item has:

You can add functionality to the item editor to update most properties of an item with some Scheme code.

In library.org, the file which is read on startup by beorg, the following code creates a menu in the item editor with some useful quick actions:

(define (add-location-to-current-item)
  (location-get-lat-lon (lambda (lat lon) (set-current-item-property! "location" (string-append lat "," lon)))))
(define (make-current-item-top-priority-today)
  (begin (set-current-item-scheduled! (current-date))
         (set-current-item-priority! "A")))
(define (schedule-current-item-for-tomorrow)
  (set-current-item-scheduled! (date-adjust (current-date) 1 'days)))
(define (remove-all-dates-from-current-item)
  (begin (delete-current-item-scheduled!)
         (delete-current-item-deadline!)
         (delete-current-item-active-date!)))

(defvar item-editor-menu
  '(("Assign current location" (add-location-to-current-item))
    ("Make top priority today" (make-current-item-top-priority-today))
    ("Schedule for tomorrow" (schedule-current-item-for-tomorrow))
    ("Remove all dates" (remove-all-dates-from-current-item)))
  "The items defined here can be run directly from the item editor screen to make quick adjustments.")

The variable item-editor-menu has a list of menu items. Each list contains the name of the menu item, and then the code to execute when the item is selected.

For example the default menu includes an item with the title “Make top priority today” which executes the function make-current-item-top-priority-today which is defined as follows:

(define (make-current-item-top-priority-today)
  (begin (set-current-item-scheduled! (current-date))
         (set-current-item-priority! "A")))

The above code sets the scheduled date of the current item being shown in the item editor to the current date, and sets the priority to A.

If you want to define your own menu of quick actions use set! to change the variable item-editor-menu:

(set! item-editor-menu
  '(("Make top priority today" (make-current-item-top-priority-today))
    ("Remove all dates" (remove-all-dates-from-current-item))))

Here are the functions which can be used to modify the current item:

Function Example
set-current-item-headline! (set-current-item-headline! "Buy shoes")
set-current-item-state! (set-current-item-state! "IN-PROGRESS")
set-current-item-priority! (set-current-item-priority! "A")
set-current-item-scheduled! (set-current-item-scheduled! (date-adjust (current-date) 1 'months'))
set-current-item-deadline! (set-current-item-deadline! (current-date))
set-current-item-active-date! (set-current-item-active-date! (current-date))
set-current-item-scheduled-with-time! (set-current-item-scheduled-with-time! (current-date))
set-current-item-deadline-with-time! (set-current-item-deadline-with-time! (current-date))
set-current-item-active-date-with-time! (set-current-item-active-date-with-time! (current-date))
delete-current-item-scheduled! (delete-current-item-scheduled!)
delete-current-item-deadline! (delete-current-item-deadline!)
delete-current-item-active-date! (delete-current-item-active-date!)
set-current-item-tags! (set-current-item-tags! '("food" "shopping"))
set-current-item-property! (set-current-item-property! "effort" "2:00")

Export themes

If you have purchased the Export Themes in-app purchase extension then you can add your own themes for exporting documents.

Your themes need to be in a file which is then loaded using the load-themes Scheme function. You can add this to your init.org so that your themes get loaded everytime beorg starts.

A themes file must contain one or more headings under each being a source block of CSS. For example here is a very minimal theme file:

* My minimal theme
This is a description of my minimal theme

#+begin_src css
@include "beorg default theme";

body {
   font-family: monospace;
}
#+end_src

The above theme extends the default theme by setting the font to monospace.

As you can see above you can include another theme using the @include syntax. Note that the theme must have been read by beorg already, i.e. it cannot occur later in the file or in another file which hasn’t been read yet.

Each theme should have a unique name. In the above example the name of the theme is My minimal theme. If a theme is loaded with the name of another than it will override that theme.

If the name of a theme starts with an underscore then it won’t be shown in the theme selector UI.

Device information

beorg defines a number of variables with details about your device. These may be useful for conditionally customising beorg for iPhone and iPad differently. The variables are:

Useful scheme functions

Here are details of some other scheme functions defined by beorg which aren’t mentioned above.

open-url

Opens a URL, usually in the browser but may be handled by another app.

(open-url "https://beorg.app")

pasteboard

Grabs the current contents of the clipboard.

(pasteboard)

pasteboard-set!

Sets the clipboard.

(pasteboard-set! "Hello")

autocorrect-set!

Turns the editor autocorrect on or off.

(autocorrect-set! #t)

string-search-forward

Returns the point index of the next instance of a string in the editor from the current cursor position.

(string-search-forward "word")

string-search-backward

Returns the point index of the last instance of a string in the editor from the current cursor position.

(string-search-background "word")

date-adjust

Returns a date adjusted by the specified amount.

;; Return the current date + 1 year
(date-adjust (current-date) 1 'years)

You can provide the symbols 'years, 'months, 'days, 'hours, 'minutes, 'seconds to adjust by.

date-set

Changes a date component to a specific value and returns a new date.

;; Returns a date with the current month, year, etc but with the day set to the 1st
(date-set (current-date) 1 'year)

You can provide the symbols 'year, 'month, 'day, 'hour, 'minute, 'second to adjust by.

library.org

When beorg starts it reads a Scheme file which comes bundled with the app. This file contains a number of defaults and helper functions used by beorg. If you want to get serious about beorg scripting then you should take a look at this file to help you realise what’s possible.

View library.org (Please note the version with the current release of beorg may vary from this.)

You can view the version of library.org that is bundled with your installed version of beorg by tapping the help icon in the REPL.

Download now for iPhone and iPad

Follow us on Mastodon

Privacy Policy | Press Kit