The contract

An action defines transform(text). Whatever it returns is turned into text and inserted where you are writing.

def transform(text):
    return text.upper()

Return None to insert nothing. For a quick experiment, assign a top level result variable instead of defining a function.

Where the text comes from

InputWhat the action gets
NothingGenerates text from scratch. transform("").
Current wordPasses the word you're typing into transform(text).
SelectionPasses the text you have selected, or nothing when there is no selection.
Current linePasses the line the cursor is on.
Current sentencePasses the sentence the cursor is in.
Text before cursorPasses everything before the cursor in.
Text after cursorPasses everything after the cursor in.
Whole fieldPasses the whole field in, on both sides of the cursor.
ClipboardPasses the clipboard text in. Needs Full Access.

Replace input decides whether the output takes the place of what went in. It applies to every source that reads the field. Nothing and Clipboard have nothing in the document to replace, so their output is always inserted.

def transform(text):
    words = len(text.split())
    return f"{words} words"
Reading the text before the cursor with Replace input off, this adds a count.

Asking the keyboard

An action can use the same commands a panel does, instead of returning one string. That is how an action makes more than one edit, or leaves the cursor somewhere particular.

def transform(text):
    replace(len(text), "(" + text + ")")
    move_cursor(-1)
Bracketing the word, then stepping back inside the bracket.

toast() and close() belong to panels: an action has no surface of its own to show a message on. Both still appear in the run console while you are writing one.

The language

Scripts run on Clink's own interpreter rather than CPython. It reads a useful subset of Python: comprehensions, lambdas, tuples, sets, f-string formats, try and except. The rest it refuses with a message that names the line.

Types

  • int
  • float
  • str
  • bool
  • None
  • list
  • tuple
  • dict
  • set

Keywords

  • if
  • elif
  • else
  • while
  • for
  • in
  • def
  • return
  • break
  • continue
  • pass
  • True
  • False
  • None
  • and
  • or
  • not
  • lambda
  • try
  • except
  • finally
  • raise
  • import
  • from
  • as
  • is
  • del
  • global

Builtins

  • len
  • str
  • repr
  • print
  • int
  • float
  • bool
  • abs
  • round
  • min
  • max
  • sum
  • range
  • sorted
  • reversed
  • list
  • dict
  • set
  • tuple
  • enumerate
  • zip
  • ord
  • chr
  • any
  • all
  • type
  • map
  • filter
  • divmod
  • pow
  • hex
  • bin
  • oct
  • format
  • isinstance
  • callable

String methods

  • upper
  • lower
  • casefold
  • title
  • capitalize
  • swapcase
  • strip
  • lstrip
  • rstrip
  • replace
  • split
  • rsplit
  • splitlines
  • join
  • startswith
  • endswith
  • find
  • rfind
  • index
  • rindex
  • count
  • partition
  • rpartition
  • zfill
  • ljust
  • rjust
  • center
  • isdigit
  • isnumeric
  • isalpha
  • isalnum
  • isspace
  • isupper
  • islower
  • istitle
  • removeprefix
  • removesuffix
  • format

List methods

  • append
  • extend
  • pop
  • insert
  • remove
  • index
  • count
  • sort
  • reverse
  • clear
  • copy

Dictionary methods

  • keys
  • values
  • items
  • get
  • pop
  • popitem
  • setdefault
  • update
  • clear
  • copy

Set methods

  • add
  • discard
  • remove
  • pop
  • clear
  • copy
  • update
  • union
  • intersection
  • difference
  • symmetric_difference
  • issubset
  • issuperset
  • isdisjoint

Tuple methods

  • count
  • index

Regex match methods

  • group
  • groups
  • groupdict
  • start
  • end
  • span

Exceptions

  • Exception
  • ValueError
  • TypeError
  • KeyError
  • IndexError
  • NameError
  • ZeroDivisionError
  • AttributeError
  • RuntimeError
  • StopIteration

Refused

  • class
  • with
  • nonlocal
  • assert
  • yield
  • async
  • await
  • match

Namespaces

These namespaces can be imported, and nothing else. Each one only computes: there is no filesystem, no network and no process for a script to reach.

import json

  • dumps
  • loads

import math

  • acos
  • asin
  • atan
  • atan2
  • ceil
  • comb
  • copysign
  • cos
  • degrees
  • e
  • exp
  • fabs
  • factorial
  • floor
  • fmod
  • gcd
  • hypot
  • inf
  • isfinite
  • isinf
  • isnan
  • lcm
  • log
  • log10
  • log2
  • nan
  • pi
  • pow
  • prod
  • radians
  • sin
  • sqrt
  • tan
  • tau
  • trunc

import random

  • choice
  • choices
  • randint
  • random
  • randrange
  • sample
  • seed
  • shuffle
  • uniform

import re

  • DOTALL
  • I
  • IGNORECASE
  • M
  • MULTILINE
  • S
  • escape
  • findall
  • finditer
  • fullmatch
  • match
  • search
  • split
  • sub
  • subn

import sys

  • version

import time

  • format
  • monotonic
  • parts
  • time
import re

def transform(text):
    return re.sub(r"\s+", " ", text).strip()
Collapsing runs of whitespace with a regular expression.

The regular-expression engine is Clink's own, and it spends the same step budget as the rest of your script, so a pattern that would otherwise take for ever ends with an error instead of a keyboard that stops answering. Backreferences and lookaround are not supported.

Why not CPython

A keyboard extension has a hard memory ceiling, and iOS ends it without warning when it goes over. A full Python runtime would not fit beside the keyboard, so Clink ships a small interpreter written for the job: no imports, no files, no network, and a step budget that ends a runaway script rather than the keyboard.

print goes to the console in the editor, never into what you are writing.

Sharing

Share action writes a .clinkext file, and Import action takes one back with a fresh id. An action stays under 48,000 bytes and has to define def transform(.

Creator ›
Download on the App Store