Orgstar

Code blocks

Orgstar runs and tangles source blocks the way Org Babel does, and refuses anything it would run differently.

Source blocks

A source block holds code in a named language:

#+begin_src python
return 6 * 7
#+end_src

Orgstar reads the same syntax Org does: the language after #+begin_src, then any switches such as -i or -r, then header arguments. A #+NAME: line above a block names it, so other blocks, #+CALL: lines and :var references can refer to it.

Lines inside a block that start with * or #+ are protected with a leading comma, as Org does (org-escape-code-in-region). The comma is removed when the block runs, tangles or exports, and when you edit the block apart.

Syntax highlighting

On the Mac, the code in a block is highlighted in the editor and in the block editor. Highlighting uses tree-sitter grammars for these language names:

Language namesGrammar
sh, bash, shell, zshBash
python, python3, pyPython
emacs-lisp, elispEmacs Lisp
cC
c++, cppC++
rR
js, javascript, nodeJavaScript
javaJava
schemeScheme
clojure, cljClojure
haskellHaskell
rustRust
goGo
rubyRuby
jsonJSON
yaml, ymlYAML
toml, conf-tomlTOML
luaLua

Names are matched without regard to case. Blocks in any other language show as plain monospaced text. The iOS app does not highlight code.

Editing a block apart

org-edit-special edits a block's contents in a separate editor. Put the caret in a src, example or export block (or on a #+TBLFM: line; see Tables) and run Edit Block.

PresetKey
EmacsC-c '
DoomC-c ', or SPC m ' in normal state
Mac⌃⌘'

On the Mac the block opens in a sheet titled with the block's kind and language, with the same highlighting as the main editor. The protecting commas are removed while you edit and added back when you save.

ActionKeys
SaveC-c ' or ⌘Return, or Save Block
LeaveC-c C-k or Escape, or Cancel

If the block changed in the main editor while you edited it, the edit is not saved and the message area says so.

On iOS the block opens in a plain text sheet with Cancel and Save buttons.

Running a block

C-c C-c in a source block runs it (org-babel-execute-src-block) and writes its result under it. The same command runs a #+CALL: line or an inline src_ block when the caret is on one.

PresetKey
EmacsC-c C-c
DoomC-c C-c in normal, insert and visual state
Mac⌃⌘X

The program runs in the folder of the file, or in :dir. It reads the code on standard input. While it runs, the message area shows "Running language block…"; when it ends, it shows "Code block evaluation complete." or the problem.

If the program writes to standard error or exits with a non-zero status, the message area shows the exit status and the first line of standard error. The result is still inserted, as Emacs does.

The block's text is remembered when the run starts. If you edit the block while it runs, so it can no longer be found, the result is not written.

Languages that run

On the Mac, Orgstar starts each interpreter through /usr/bin/env. Because an app opened from the Dock does not see your shell's PATH, Orgstar adds /opt/homebrew/bin, /usr/local/bin, /Library/TeX/texbin, /usr/bin and /bin to the end of it.

LanguageProgram run
sh, bash, zsh, fish, ksh, dash, ash, csh, mksh, poshThe shell of that name
shellThe shell in SHELL, or /bin/sh
pythonpython3, or the program in :python
emacs-lisp, elispemacs -Q --batch; see Emacs Lisp blocks below
rubyruby
js, javascriptnode
RRscript -
awkawk -f /dev/stdin
dot, plantuml, mermaiddot, plantuml, mmdc; see Graphics below

For ruby, js, javascript, R and awk, :cmd names a different program. These languages always return their standard output, and :var is refused for them.

Any other language is refused with "No way to run language blocks yet."

A run that takes longer than five minutes is stopped. Runs in a :session have no time limit.

The trust prompt

Before a block runs, Orgstar asks "Run this language block? (yes, no, always)", as org-confirm-babel-evaluate does.

A remembered block is identified by the file's path and the exact text of the block. Any change to the block, or moving the file, makes Orgstar ask again. The remembered hashes are kept in trusted.json in Orgstar's Application Support folder (~/Library/Application Support/Orgstar on the Mac). The same file records table formulas you allowed to run Lisp. To forget every choice, delete the file while Orgstar is not running.

When a block's :var or :stdin refers to other blocks that have to run first, you are asked once for all of them. The prompt covers the block you ran and every block its references reach. If any of those blocks changes while the chain runs, Orgstar stops with "The blocks changed while running; nothing more was run."

:eval

ValueEffect
never, noThe block does not run: "Evaluation of this language code block is disabled."
queryAsks every time, with only yes and no. A block reached through :var with :eval query makes the whole chain ask every time.
anything else, or absentRuns after the trust prompt.

never-export and no-export only stop evaluation during export in Org. Orgstar does not run blocks during export, so with these values the block runs from C-c C-c like any other.

Cancelling a run

On the Mac, Edit ▸ Cancel Running Task (⌘.) stops the running block. Its result is not inserted, and the message area shows "Code block canceled." The same command stops an export or table recalculation running in Emacs (see Export and Tables). With nothing running it shows "Nothing is running". The command is also in the command palette.

Only one block runs at a time. Starting another block cancels the one that is running.

Cancelling a block that runs in a :session stops the session's interpreter, so the session's state is lost. The next block in that session starts a new one.

The iOS app has no cancel command.

Results

The result is written after a #+RESULTS: line below the block (org-babel-insert-result). Running again replaces it. A named block's result goes under #+RESULTS: name, wherever that line is in the file. An unnamed block's result is the #+RESULTS: line right after it, past blank lines. The result keeps the block's indentation, so a block inside a list item keeps its result inside the item.

#+begin_src sh
echo hello
#+end_src

#+RESULTS:
: hello

By default a result is shaped like this:

Value or output

WordResult
valueThe value of the block. This is the default.
outputEverything the program printed on standard output.

What "value" means depends on the language:

LanguageValue
Shells, by defaultStandard output, read as a table: tab-separated columns, then comma-separated, then space-separated; a single field is a plain value.
Shells, :results value written outThe exit status of the last command.
PythonWhat the block returns. The body runs as a function, so it needs return. :return expr adds a final return expr.
Python in a :sessionThe value of the last expression.
Emacs LispThe value of the last form.
ruby, js, R, awkStandard output, always.

Python lists of lists become tables, with None rows as rules. A flat list becomes a one-row table. Emacs Lisp lists become tables the same way, with hline for rules. Numbers are written the way Emacs prints them.

Result types

WordEffect
table, vectorRead the result as a table. This is the default for values.
listWrite a plain list, one =- = item per line or per element.
scalar, verbatimWrite the result as text without reading it as a table.
fileWrite a link to a file (see Results in files below).

:results verbatim on an Emacs Lisp value writes it as prin1 would, with quotes around strings.

Result formats

WordWritten as
rawThe text as it is, so Org markup in it takes effect.
drawerBetween :results: and :end:.
codeIn a #+begin_src block of the block's language.
orgIn a #+begin_src org block.
htmlIn a #+begin_export html block.
latexIn a #+begin_export latex block.
ppPython: formatted with pprint; written as text.

Lines that start with * or #+ inside code, org, html and latex results are comma-protected.

Inserting

WordEffect
replaceReplace the previous result. This is the default.
appendAdd after the previous result.
prependAdd before the previous result.
silentShow the output in the message area and write nothing.
none, discardWrite nothing.

Words from different groups combine: :results output list append. A later word replaces an earlier one from the same group.

:wrap

:wrap puts the result in a block, ahead of any format word.

ValueWrapped in
:wrap alone#+begin_results … #+end_results
:wrap example#+begin_example … #+end_example
:wrap src python#+begin_src python … #+end_src
:wrap export html#+begin_export html … #+end_export
:wrap no, :wrap nilNo wrapping

Inside example, src and export wrappers, lines starting with * or #+ are comma-protected.

Results in files

With :results file, the result is a link instead of text.

HeaderEffect
:file nameWrite the result into name and link to it. Without :results file, :file has no effect, except in graphics blocks.
:output-dir dirPut :file under dir. The folder must exist.
:file-desc textGive the link a description: [[file:name][text]]. An empty :file-desc uses the file name.

A relative :file is written in the folder the block ran in: the file's folder, or :dir. Without :file, :results file takes the result itself as the path to link to.

#+begin_src sh :results file :file out.txt :file-desc Output
echo hello
#+end_src

#+RESULTS:
[[file:out.txt][Output]]

Header arguments

Where they come from

Orgstar merges header arguments in this order, each layer overriding the ones before it (org-babel-get-src-block-info):

  1. #+PROPERTY: header-args … in the file, then header-args properties of the block's headings, from the outermost heading inwards.
  2. header-args:LANG the same way, for blocks in language LANG.
  3. The arguments on the #+begin_src line.
  4. #+HEADER: lines above the block.
  5. For a call, the call's arguments (see Calls below).

A property written with a +, such as header-args+, adds to the value inherited from above instead of replacing it. In a property drawer, :header-args:sh: is one property name, so its value applies only to sh blocks.

#+PROPERTY: header-args :results output

* Scripts
:PROPERTIES:
:header-args:sh: :dir /tmp
:END:

#+HEADER: :results verbatim
#+begin_src sh :var name="world"
echo "hello $name"
#+end_src

Without any of these, a block has :results replace, :exports code, :session none, :cache no, :noweb no, :hlines no and :tangle no. An inline src_ block defaults to :exports results and :hlines yes.

Lisp in header values

A header value that starts with (, ', ` or [ and is not in quotes is Lisp, as in org-babel-read. Orgstar evaluates it with its own Emacs Lisp interpreter, which also knows buffer-file-name, default-directory, system-type and the functions expand-file-name, file-name-directory, file-name-nondirectory, file-name-sans-extension and file-name-as-directory.

#+begin_src sh :dir (concat "/" "usr") :results output
pwd
#+end_src

A string or number takes the place of the form. Lisp that the interpreter cannot evaluate is refused where it matters: for :var ("is Lisp that only Emacs can evaluate"), :colnames and :rownames, and any header of a :cache yes block.

Header argument reference

ArgumentValuesEffect
:resultssee Results aboveHow the result is collected, shaped and inserted.
:wrapblock type and parametersWraps the result in a block.
:filefile nameWhere a file result goes; required for graphics.
:output-dirfolderFolder for :file.
:file-desctextDescription of a file result's link.
:varname=valuePasses a value in (see Variables below).
:colnamesyes, no, Lisp listHeader row of table variables (see Tables in variables below).
:rownamesyes, no, Lisp listFirst column of table variables.
:hlinesyes, noKeep rules in table variables.
:separatortextColumn separator for tables in shell variables; a tab by default.
:hline-stringtextWhat a rule becomes in a shell variable with :hlines yes; hline by default.
:dirfolderFolder to run in, relative to the file's folder. It must exist.
:sessionname, noneRuns in a long-lived interpreter (see Sessions below). Shells and Python only.
:stdinname of a table, list or blockFeeds the value to standard input. Shells only.
:cmdlineargumentsCommand-line arguments. Shells, dot, plantuml and mermaid only.
:shebang#!… lineRuns the block as a script with this first line. Shells only; also used by tangling.
:padlinenoNo blank line after the shebang of a script, or between tangled blocks.
:pythonprogramPython interpreter to use.
:cmdprogramInterpreter for ruby, js, javascript, R and awk.
:returnexpressionPython: the value to return.
:cacheyes, noSkip the run when the result is current (see Caching below).
:evalnever, no, query, …Whether and how to ask before running (see :eval above).
:nowebsee Noweb belowExpands <<name>> references.
:noweb-refnameMakes the block part of <<name>>.
:noweb-septextSeparator between blocks joined under one :noweb-ref; a newline by default.
:noweb-prefixnoDo not repeat the text before <<name>> on each expanded line.
:exportscode, results, both, noneWhat export shows (see Export).
:tanglesee Tangling belowWhere tangling writes the block.

Arguments that are refused

Orgstar does not run a block whose arguments it would handle differently from Emacs. Instead it says why and runs nothing.

ArgumentRefused forMessage
:prologue, :epilogue, :postevery language when running (tangling uses :prologue and :epilogue)":prologue isn't supported yet; nothing was run."
:stdin, :shebanglanguages other than shells":stdin isn't supported yet; nothing was run."
:cmdlinelanguages other than shells and graphics":cmdline isn't supported for language yet; nothing was run."
:sessionlanguages other than shells and Python":session isn't supported for language yet; nothing was run."
:varruby, js, javascript, R, awk":var isn't supported for language yet."

Variables

:var name=value passes a value into the block (org-babel-ref-resolve). One :var can hold several assignments separated by spaces, and you can repeat :var. A later assignment to the same name replaces an earlier one.

ValueMeaning
5, 2.5A number.
"two words"A string. \n and \t in it are a newline and a tab.
'(1 2), (+ 1 2), '((1 2) hline (3 4))Lisp: evaluated to a string, number, list or table.
tblThe table or plain list under #+NAME: tbl in the same file.
genThe result of the source block named gen, which runs first.
double(n=4)The result of the block named double, run with n set to 4.
#+NAME: nums
| 1 | 2 |
| 3 | 4 |

#+begin_src python :var t=nums :var scale=10
return [[c * scale for c in row] for row in t]
#+end_src

A referenced block runs before the block that refers to it, after the one trust prompt that covers them all. A block with :cache yes and a current result gives that result without running. A chain that leads back to itself is refused with "name refers to itself through :var".

These are not supported and are refused:

How a value reaches the code depends on the language:

LanguageScalarsListsTables
bashquoted stringindexed array (declare -a)two or more columns: associative array keyed by the first column (declare -A); one column: indexed array
other shellsquoted stringone item per linerows on lines, cells separated by a tab or :separator
fishset name 'value'as other shellsas other shells
Pythonliterallistlist of lists, None for rules
Emacs Lisplet-bound valuelistlist of lists, hline for rules

For shell blocks, the bash forms are used when SHELL is bash.

#+NAME: kv
| a | 1 |
| b | 2 |

#+begin_src bash :var t=kv :results output
echo ${t[a]} ${t[b]}
#+end_src

Tables in variables

A table passed as a variable loses some of its structure first (org-babel-disassemble-tables):

If the result is a table of the same width (for columns) or height (for rows), the names are put back on it (org-babel-reassemble-table). :colnames and :rownames can also be Lisp lists of names to put on the result, such as :colnames '("x" "y").

#+NAME: tbl
| a | b |
|---+---|
| 1 | x |
| 2 | y |

#+begin_src python :var t=tbl
return [r + ["!"] for r in t]
#+end_src

Standard input and arguments

For shell blocks, :stdin name sends a table, list or block result to standard input, a table as tab-separated lines. :cmdline gives the script arguments, and :shebang its first line. With any of the three, the block is written to an executable script and run by the shell (org-babel-sh-evaluate); without :shebang, the first line is #!/usr/bin/env and the shell's name. A block with :stdin or :cmdline runs as a script even with a :session, and leaves the session untouched; :shebang alone runs in the session.

#+begin_src sh :cmdline one "two words" :results output
for a in "$@"; do echo "[$a]"; done
#+end_src

Sessions

:session name runs the block in an interpreter that stays running, so variables, functions and the working folder carry over to the next block in the same session. Sessions work for shells and Python on the Mac.

#+begin_src python :session py :results output
a = 2
print("set")
#+end_src

#+begin_src python :session py
a * 3
#+end_src

Caching

With :cache yes, Orgstar computes a SHA-1 hash of the block's header arguments and expanded body, as org-babel-sha1-hash does, and writes it on the results line: #+RESULTS[hash]:. When you run the block again and the hash matches, nothing runs and the message area shows the cached value ("Cached: …").

Change the block or its arguments and it runs again. Results inserted with append or prepend carry no hash. Inline blocks are not cached. A cached block that has Lisp in its header arguments the interpreter cannot evaluate is refused.

C, C++, D, Fortran and Clojure blocks don't run in Orgstar, but their hash is taken over the body as tangling expands it (see Tangling below), as Emacs does. A result Emacs wrote for such a block with :cache yes is recognised as current, and C-c C-c shows it.

Noweb

A noweb reference <<name>> in a block's body stands for other code. Whether references expand depends on :noweb and on what is happening:

:nowebRunningTanglingExporting
no (default)nonono
yesexpandsexpandsno
tanglenoexpandsno
evalexpandsnono
no-exportexpandsexpandsno
strip-exportexpandsexpandsno
strip-tangleexpandsremoves the referencesno

Exported code always shows the references as written; see Export.

<<name>> expands to the first of these that exists:

  1. The contents of the heading whose ID property is name, or whose CUSTOM_ID is name without its leading #.
  2. The body of the source block named name.
  3. The bodies of all blocks with :noweb-ref name, joined by each block's :noweb-sep (a newline by default).

Blocks under a COMMENT heading are skipped. A referenced block expands its own references according to its own :noweb, up to 32 levels deep.

Text before the reference on its line is repeated before each line the reference brings in, so references inside comments or indented code keep their prefix. :noweb-prefix no turns this off.

#+NAME: greeting
#+begin_src sh
echo hello
#+end_src

#+begin_src sh :noweb yes
<<greeting>>
echo world
#+end_src

A reference that runs a block, <<name()>>, is refused: "Noweb references that run a block (…) aren't supported yet; nothing was run."

Calls

#+CALL: lines

#+CALL: runs a named block with other arguments, as Org's library of Babel calls do (org-babel-lob-get-info). Run it with C-c C-c on the line.

#+NAME: double
#+begin_src sh :var n=2
echo $((n*2))
#+end_src

#+CALL: double(n=5)

#+RESULTS:
: 10

The full form is #+CALL: name[inside](arguments) end:

The call also takes the header-args and header-args:LANG properties, and #+PROPERTY: lines, where the call is, with LANG the called block's language. They apply after the called block's own header arguments and before [inside], as in Org.

The result goes under the call. A #+NAME: line above the #+CALL: names the result.

Inline calls and blocks

An inline source block, src_sh{echo hi}, runs with C-c C-c on it. Header arguments go in brackets: src_sh[:var x=3]{echo $x}. The result is written right after the block as a results macro:

Text src_sh{echo hi} {{{results(=hi=)}}} end.

Running again replaces the macro. With :results raw the result goes in as it is, without the macro. An inline result must be one line, and a table result must be a single cell.

An inline call, call_double(n=6), has the same parts as a #+CALL: line: call_name[inside](arguments)[end]. C-c C-c on an inline call runs it, and its result is written after it as a results macro, as for inline blocks. It takes the properties where it is as a #+CALL: line does.

Emacs Lisp blocks

On the Mac, an emacs-lisp or elisp block runs in a new emacs -Q --batch for each run, with lexical binding on. -Q means your init file and packages are not loaded, and nothing carries over between runs. Orgstar looks for Emacs at ORGSTAR_EMACS, then /opt/homebrew/bin/emacs, /usr/local/bin/emacs, /Applications/Emacs.app/Contents/MacOS/Emacs, /run/current-system/sw/bin/emacs and /usr/bin/emacs. Without Emacs, the block fails with "Emacs isn't installed, so Emacs Lisp blocks can't run."

On iOS, Emacs Lisp blocks run in Orgstar's own Emacs Lisp interpreter. It covers ordinary list, string, number and control forms, princ and message. A block that uses something the interpreter does not have fails with "This block uses Emacs Lisp that runs only in Emacs, on the Mac." A Lisp error fails the run, as it does in Emacs.

Variables are bound with let around the body. :results output collects what the block prints with princ, prin1, print and terpri.

Graphics

dot (Graphviz), plantuml and mermaid blocks draw a picture into :file, and the result is a link to it. :file is required: "language code blocks need a :file header argument". The file's extension picks the output format; with none, png is used.

LanguageCommand
dotdot -T/ext/ -o file
plantumlplantuml -p -t/ext/, output to the file
mermaidmmdc -i input -o file

A plantuml body without an @start… line is wrapped in @startuml and @enduml. :cmdline adds options to the command. The program must be installed and on the PATH described under Languages that run.

#+begin_src dot :file graph.svg
digraph { a -> b }
#+end_src

#+RESULTS:
[[file:graph.svg]]

Tangling

Tangling writes source blocks to the files their :tangle argument names (org-babel-tangle).

CommandEmacs and DoomMacWhat it tangles
Tangle FileC-c C-v t, C-c C-v C-t⌃⌘VEvery block in the file
Tangle BlocknonenoneThe block at the caret (Emacs: C-u C-c C-v t)
Tangle Block's TargetnonenoneEvery block going to the same file as the one at the caret (Emacs: C-u C-u C-c C-v t)

All three are in the Org menu and the command palette. Tangling uses the text in the editor, saved or not, and the message area reports "Tangled N code blocks from file".

:tangle and file names

:tangleTarget
no (default)Not tangled.
yesThe Org file's name with the language's extension, as Org's language files define it (org-babel-tangle-lang-exts): py for python, rb for ruby, pl for perl, cpp for C++, d for D, awk, sed, lua, hs for haskell, java, tex for latex, ly for LilyPond, F90 for fortran, clj for clojure, cljs for clojurescript, cs for csharp, groovy, jl for julia, lisp, max for maxima, ml for ocaml, pde for processing, el for emacs-lisp and elisp, and bib for bibtex. Any other language is its own extension (notes.sh for sh).
a pathThat file, relative to the Org file's folder. ~ is expanded.
LispEvaluated as described under Lisp in header values, with buffer-file-name set to the Org file.

Blocks under a COMMENT heading, or a heading tagged ARCHIVE, are skipped. Blocks going to the same file are written in the order they appear.

#+PROPERTY: header-args:python :tangle script.py

* Tool
:PROPERTIES:
:header-args: :tangle bin/tool.sh :mkdirp yes :shebang "#!/bin/sh"
:END:

#+begin_src sh
echo tool
#+end_src

Tangling arguments

ArgumentValuesEffect
:mkdirpyesCreate the target's folder if it is missing.
:tangle-mode(identity #o755), #o755, o755, rwxr-xr-x, u+x,g-rSet the file's mode. A symbolic mode starts from 644. When several blocks give a mode, the first one counts.
:shebang#!… lineFirst line of the file, written once. Makes the file mode 755 unless :tangle-mode says otherwise.
:padlinenoNo blank line between this block and the one before it.
:commentsno, link, yes, org, both, nowebComments around each block (below).
:nowebsee Noweb aboveExpand or strip <<name>> references.
:prologue, :epiloguetextA line before and after the block's code.
:varas for runningShell scalars become assignments, Python values become assignments, Emacs Lisp values are let-bound. For the languages below, as their Org language files write them.
:no-expandanyWrite the body without :var, :prologue, :epilogue or the language's wrapping.

A table in :var loses its first row when its only rule is under that row, or with :colnames yes, and its rules unless :hlines yes, as when the block runs. This holds for every language.

C, C++, cpp, D, java, fortran and clojure blocks are written as Org's org-babel-expand-body:LANG writes them:

LanguageWritten
C, C++, cpp#include lines from :includes, #define lines from :defines, using namespace lines from :namespaces, the :var declarations with table sizes and column-name helpers, then the body between :prologue and :epilogue, wrapped in int main() unless it has a main or :main no is given.
Dmodule mmm;, import lines from :imports plus std.stdio and std.conv, the :var declarations, and the body wrapped in int main() as for C.
javaThe body between :prologue and :epilogue, wrapped in a main method when it has no method and in a class when it has none. The class is named by :classname or the body's own class; a dotted :classname adds a package line. :imports adds import lines, and :var values become static fields.
fortran#include and #define lines from :includes and :defines, then the :var declarations and the body in program main, unless the body has its own program statement (then :var is refused) or :main no is given.
clojure(ns …) from :ns, the body in a let of the :var values, and a printer around it unless :results output.

With :hlines yes, a table that keeps rules is refused for C, C++, D and Fortran; Java writes null for each rule.

Block switches also apply. -r removes coderef labels such as (ref:name), using the format from -l if given. -i keeps the block's indentation. Otherwise common indentation and surrounding blank lines are removed.

Comments

:commentsWritten
noThe code only.
link, yesA comment with a link back to the block before the code, and "name ends here" after it.
orgThe Org text between the heading (or the previous block) and this block, as a comment.
bothThe Org text and the link comments.
nowebLink comments, plus link comments around each expanded noweb reference.

The link is relative to the tangled file's folder. name is the block's #+NAME, or the heading's title and the block's number under that heading, such as Setup:2.

Comments need the language's comment syntax. Orgstar knows it for: emacs-lisp, elisp, lisp, scheme, asm (;;); python, ruby, perl, conf, toml, makefile, awk, tcl, m4, icon, desktop and the shells except fish (#); js, javascript, java, cpp, C++, objc, csharp, idl, pike, antlr, verilog (//); c, C, css (/* */); lua, sql, sqlite, vhdl (--); latex, tex, prolog (%%); ps, metapost (%); f90, dcl (!); html, xml, nxml, mhtml, sgml (<!-- -->); octave (##); pascal ({ }); texinfo (@c); bibtex (@Comment); nroff (\"); bat (rem). For any other language, :comments other than no stops tangling with a message.

Writing the files

What tangling refuses

Tangling stops, writes nothing and says why when:

On iOS

See iOS for the rest of the iOS app.