Theory Server

(*:maxLineLen=78:*)

theory Server
imports Base
begin

chapter ‹The Isabelle server›

text ‹
  An Isabelle session requires at least two processes, which are both rather
  heavy: Isabelle/Scala for the system infrastructure and Isabelle/ML for the
  logic session (e.g.\ HOL). In principle, these processes can be invoked
  directly on the command-line, e.g.\ via @{tool java}, @{tool scala}, @{tool
  process}, @{tool console}, but this approach is inadequate for reactive
  applications that require quick responses from the prover.

  In contrast, the Isabelle server exposes Isabelle/Scala as a
  ``terminate-stay-resident'' application that manages multiple logic
  ‹sessions› and concurrent tasks to use ‹theories›. This is analogous to
  MLThy_Info.use_theories in Isabelle/ML, with proper support for
  concurrent invocations.

  The client/server arrangement via TCP sockets also opens possibilities for
  remote Isabelle services that are accessed by local applications, e.g.\ via
  an SSH tunnel.
›


section ‹Command-line tools›

subsection ‹Server \label{sec:tool-server}›

text ‹
  The @{tool_def server} tool manages resident server processes:
  @{verbatim [display]
‹Usage: isabelle server [OPTIONS]

  Options are:
    -L FILE      logging on FILE
    -c           console interaction with specified server
    -l           list servers (alternative operation)
    -n NAME      explicit server name (default: isabelle)
    -p PORT      explicit server port
    -s           assume existing server, no implicit startup
    -x           exit specified server (alternative operation)

  Manage resident Isabelle servers.›}

  The main operation of ‹isabelle server› is to ensure that a named server is
  running, either by finding an already running process (according to the
  central database file path‹$ISABELLE_HOME_USER/servers.db›) or by
  becoming itself a new server that accepts connections on a particular TCP
  socket. The server name and its address are printed as initial output line.
  If another server instance is already running, the current
  ‹isabelle server› process will terminate; otherwise, it keeps running as a
  new server process until an explicit ‹shutdown› command is received.
  Further details of the server socket protocol are explained in
  \secref{sec:server-protocol}.

  Other server management operations are invoked via options ‹-l› and ‹-x›
  (see below).

  
  Option ‹-n› specifies an alternative server name: at most one process for
  each name may run, but each server instance supports multiple connections
  and logic sessions.

  
  Option ‹-p› specifies an explicit TCP port for the server socket (which is
  always on ‹localhost›): the default is to let the operating system assign a
  free port number.

  
  Option ‹-s› strictly assumes that the specified server process is already
  running, skipping the optional server startup phase.

  
  Option ‹-c› connects the console in/out channels after the initial check
  for a suitable server process. Also note that the @{tool client} tool
  (\secref{sec:tool-client}) provides a command-line editor to interact with
  the server.

  
  Option ‹-L› specifies a log file for exceptional output of internal server
  and session operations.

  
  Operation ‹-l› lists all active server processes with their connection
  details.

  
  Operation ‹-x› exits the specified server process by sending it a
  ‹shutdown› command.
›


subsection ‹Client \label{sec:tool-client}›

text ‹
  The @{tool_def client} tool provides console interaction for Isabelle
  servers:
  @{verbatim [display]
‹Usage: isabelle client [OPTIONS]

  Options are:
    -n NAME      explicit server name
    -p PORT      explicit server port

  Console interaction for Isabelle server (with line-editor).›}

  This is a wrapper to ‹isabelle server -s -c› for interactive
  experimentation, which uses @{setting ISABELLE_LINE_EDITOR} if available.
  The server name is sufficient for identification, as the client can
  determine the connection details from the local database of active servers.

  
  Option ‹-n› specifies an explicit server name as in @{tool server}.

  
  Option ‹-p› specifies an explicit server port as in @{tool server}.
›


subsection ‹Examples›

text ‹
  Ensure that a particular server instance is running in the background:
  @{verbatim [display] ‹isabelle server -n test &›}

  The first line of output presents the connection details:‹This information
  may be used in other TCP clients, without access to Isabelle/Scala and the
  underlying database of running servers.›
  @{verbatim [display] ‹server "test" = 127.0.0.1:4711 (password "XYZ")›}

  
  List available server processes:
  @{verbatim [display] ‹isabelle server -l›}

  
  Connect the command-line client to the above test server:
  @{verbatim [display] ‹isabelle client -n test›}

  Interaction now works on a line-by-line basis, with commands like ‹help› or
  ‹echo›. For example, some JSON values may be echoed like this:

  @{verbatim [display]
‹echo 42
echo [1, 2, 3]
echo {"a": "text", "b": true, "c": 42}›}

  Closing the connection (via CTRL-D) leaves the server running: it is
  possible to reconnect again, and have multiple connections at the same time.

  
  Exit the named server on the command-line:
  @{verbatim [display] ‹isabelle server -n test -x›}


section ‹Protocol messages \label{sec:server-protocol}›

text ‹
  The Isabelle server listens on a regular TCP socket, using a line-oriented
  protocol of structured messages. Input ‹commands› and output ‹results›
  (via ‹OK› or ‹ERROR›) are strictly alternating on the toplevel, but
  commands may also return a ‹task› identifier to indicate an ongoing
  asynchronous process that is joined later (via ‹FINISHED› or ‹FAILED›).
  Asynchronous ‹NOTE› messages may occur at any time: they are independent of
  the main command-result protocol.

  For example, the synchronous ‹echo› command immediately returns its
  argument as ‹OK› result. In contrast, the asynchronous ‹session_build›
  command returns ‹OK {"task":›id›‹}› and continues in the background. It
  will eventually produce ‹FINISHED {"task":›id›‹,›…›‹}› or
  ‹FAILED {"task":›id›‹,›…›‹}› with the final result. Intermediately, it
  may emit asynchronous messages of the form ‹NOTE {"task":›id›‹,›…›‹}›
  to inform about its progress. Due to the explicit task identifier, the
  client can show these messages in the proper context, e.g.\ a GUI window for
  this particular session build job.

  \medskip Subsequently, the protocol message formats are described in further
  detail.
›


subsection ‹Byte messages \label{sec:byte-messages}›

text ‹
  The client-server connection is a raw byte-channel for bidirectional
  communication, but the Isabelle server always works with messages of a
  particular length. Messages are written as a single chunk that is flushed
  immediately.

  Message boundaries are determined as follows:

     A ‹short message› consists of a single line: it is a sequence of
    arbitrary bytes excluding CR (13) and LF (10), and terminated by CR-LF or
    just LF.

     A ‹long message› starts with a single line consisting of decimal
    digits: these are interpreted as length of the subsequent block of
    arbitrary bytes. A final line-terminator (as above) may be included here,
    but is not required.

  Messages in JSON format (see below) always fit on a single line, due to
  escaping of newline characters within string literals. This is convenient
  for interactive experimentation, but it can impact performance for very long
  messages. If the message byte-length is given on the preceding line, the
  server can read the message more efficiently as a single block.
›


subsection ‹Text messages›

text ‹
  Messages are read and written as byte streams (with byte lengths), but the
  content is always interpreted as plain text in terms of the UTF-8
  encoding.‹See also the ``UTF-8 Everywhere Manifesto''
  🌐‹https://utf8everywhere.org›.›

  Note that line-endings and other formatting characters are invariant wrt.
  UTF-8 representation of text: thus implementations are free to determine the
  overall message structure before or after applying the text encoding.
›


subsection ‹Input and output messages \label{sec:input-output-messages}›

text ‹
  The uniform format for server input and output messages is name argument›,
  such that:

     name› is the longest prefix consisting of ASCII letters, digits,
    ``‹_›'', ``‹.›'',

     the separator between name› and argument› is the longest possible
    sequence of ASCII blanks (it could be empty, e.g.\ when the argument
    starts with a quote or bracket),

     argument› is the rest of the message without line terminator.

  
  Input messages are sent from the client to the server. Here the name›
  specifies a ‹server command›: the list of known commands may be
  retrieved via the ‹help› command.

  
  Output messages are sent from the server to the client. Here the name›
  specifies the ‹server reply›, which always has a specific meaning as
  follows:

     synchronous results: ‹OK› or ‹ERROR›
     asynchronous results: ‹FINISHED› or ‹FAILED›
     intermediate notifications: ‹NOTE›

  
  The argument› format is uniform for both input and output messages:

     empty argument (Scala type ‹Unit›)
     XML element in YXML notation (Scala type ‹XML.Elem›)
     JSON value (Scala type ‹JSON.T›)

  JSON values may consist of objects (records), arrays (lists), strings,
  numbers, bools, or null.‹See also the official specification
  🌐‹https://www.json.org› and unofficial explorations ``Parsing JSON is a
  Minefield'' 🌐‹http://seriot.ch/parsing_json.php›.› Since JSON requires
  explicit quotes and backslash-escapes to represent arbitrary text, the YXML
  notation for XML trees (\secref{sec:yxml-vs-xml}) works better
  for large messages with a lot of PIDE markup.

  Nonetheless, the most common commands use JSON by default: big chunks of
  text (theory sources etc.) are taken from the underlying file-system and
  results are pre-formatted for plain-text output, without PIDE markup
  information. This is a concession to simplicity: the server imitates the
  appearance of command-line tools on top of the Isabelle/PIDE infrastructure.
›


subsection ‹Initial password exchange›

text ‹
  Whenever a new client opens the server socket, the initial message needs to
  be its unique password as a single line, without length indication (i.e.\ a
  ``short message'' in the sense of \secref{sec:byte-messages}).

  The server replies either with ‹OK› (and some information about the
  Isabelle version) or by silent disconnection of what is considered an
  illegal connection attempt. Note that @{tool client} already presents the
  correct password internally.

  Server passwords are created as Universally Unique Identifier (UUID) in
  Isabelle/Scala and stored in a per-user database, with restricted
  file-system access only for the current user. The Isabelle/Scala server
  implementation is careful to expose the password only on private output
  channels, and not on a process command-line (which is accessible to other
  users, e.g.\ via the ‹ps› command).
›


subsection ‹Synchronous commands›

text ‹
  A ‹synchronous command› corresponds to regular function application in
  Isabelle/Scala, with single argument and result (regular or error). Both the
  argument and the result may consist of type ‹Unit›, ‹XML.Elem›, ‹JSON.T›.
  An error result typically consists of a JSON object with error message and
  potentially further result fields (this resembles exceptions in Scala).

  These are the protocol exchanges for both cases of command execution:
  \begin{center}
  \begin{tabular}{rl}
  ‹input:› & command argument› \\
  (a) regular ‹output:› & ‹OK› result› \\
  (b) error ‹output:› & ‹ERROR› result› \\
  \end{tabular}
  \end{center}
›


subsection ‹Asynchronous commands›

text ‹
  An ‹asynchronous command› corresponds to an ongoing process that finishes
  or fails eventually, while emitting arbitrary notifications in between.
  Formally, it starts as synchronous command with immediate result ‹OK›
  giving the ‹task› identifier, or an immediate ‹ERROR› that indicates bad
  command syntax. For a running task, the termination is indicated later by
  ‹FINISHED› or ‹FAILED›, together with its ultimate result value.

  These are the protocol exchanges for various cases of command task
  execution:

  \begin{center}
  \begin{tabular}{rl}
  ‹input:› & command argument› \\
  immediate ‹output:› & ‹OK {"task":›id›‹}› \\
  intermediate ‹output:› & ‹NOTE {"task":›id›‹,›…›‹}› \\
  (a) regular ‹output:› & ‹FINISHED {"task":›id›‹,›…›‹}› \\
  (b) error ‹output:› & ‹FAILED {"task":›id›‹,›…›‹}› \\[3ex]
  ‹input:› & command argument› \\
  immediate ‹output:› & ‹ERROR›~…› \\
  \end{tabular}
  \end{center}

  All asynchronous messages are decorated with the task identifier that was
  revealed in the immediate (synchronous) result. Thus the client can
  invoke further asynchronous commands and still dispatch the resulting stream of
  asynchronous messages properly.

  The synchronous command ‹cancel {"task":›~id›‹}› tells the specified task
  to terminate prematurely: usually causing a ‹FAILED› result, but this is
  not guaranteed: the cancel event may come too late or the running process
  may just ignore it.
›


section ‹Types for JSON values \label{sec:json-types}›

text ‹
  In order to specify concrete JSON types for command arguments and result
  messages, the following type definition language shall be used:

  rail@{syntax type_def}: @'type' @{syntax name} '=' @{syntax type}
    ;
    @{syntax type}: @{syntax name} | @{syntax value} | 'any' | 'null' |
      'bool' | 'int' | 'long' | 'double' | 'string' | '[' @{syntax type} ']' |
      '{' (@{syntax field_type} ',' *) '}' |
      @{syntax type} '⊕' @{syntax type} |
      @{syntax type} '|' @{syntax type} |
      '(' @{syntax type} ')'
    ;
    @{syntax field_type}: @{syntax name} ('?'?) ':' @{syntax type}

  This is a simplified variation of TypeScript
  interfaces.🌐‹https://www.typescriptlang.org/docs/handbook/interfaces.html›
  The meaning of these types is specified wrt. the Isabelle/Scala
  implementation as follows.

   A name› refers to a type defined elsewhere. The environment of type
  definitions is given informally: put into proper foundational order, it
  needs to specify a strongly normalizing system of syntactic abbreviations;
  type definitions may not be recursive.

   A value› in JSON notation represents the singleton type of the given
  item. For example, the string ‹"error"› can be used as type for a slot that
  is guaranteed to contain that constant.

   Type any› is the super type of all other types: it is an untyped slot in
  the specification and corresponds to ‹Any› or ‹JSON.T› in Isabelle/Scala.

   Type null› is the type of the improper value null›; it corresponds to
  type ‹Null› in Scala and is normally not used in Isabelle/Scala.‹See also
  ``Null References: The Billion Dollar Mistake'' by Tony Hoare
  🌐‹https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare›.›

   Type bool› is the type of the truth values ‹true› and ‹false›; it
  corresponds to ‹Boolean› in Scala.

   Types int›, long›, double› are specific versions of the generic
  number› type, corresponding to ‹Int›, ‹Long›, ‹Double› in Scala, but
  ‹Long› is limited to 53 bit precision.‹Implementations of JSON typically
  standardize number› to ‹Double›, which can absorb ‹Int› faithfully, but
  not all of ‹Long›.›

   Type string› represents Unicode text; it corresponds to type ‹String› in
  Scala.

   Type [t]› is the array (or list) type over t›; it corresponds to
  ‹List[t]› in Scala. The list type is co-variant as usual (i.e.\ monotonic
  wrt. the subtype relation).

   Object types describe the possible content of JSON records, with field
  names and types. A question mark after a field name means that it is
  optional. In Scala this could refer to an explicit type ‹Option[t]›, e.g.\
  {a: int, b?: string}› corresponding to a Scala case class with arguments
  ‹a: Int›, ‹b: Option[String]›.

  Alternatively, optional fields can have a default value. If nothing else is
  specified, a standard ``empty value'' is used for each type, i.e.\ ‹0› for
  the number types, ‹false› for bool›, or the empty string, array, object
  etc.

  Object types are ‹permissive› in the sense that only the specified field
  names need to conform to the given types, but unspecified fields may be
  present as well.

   The type expression t1 ⊕ t2 only works for two object types with
  disjoint field names: it is the concatenation of the respective @{syntax
  field_type} specifications taken together. For example: {task: string} ⊕
  {ok: bool}› is the equivalent to {task: string, ok: bool}›.

   The type expression t1 | t2 is the disjoint union of two types, either
  one of the two cases may occur.

   Parentheses (t)› merely group type expressions syntactically.


  These types correspond to JSON values in an obvious manner, which is not
  further described here. For example, the JSON array ‹[1, 2, 3]› conforms to
  types [int]›, [long]›, [double]›, [any]›, any›.

  Note that JSON objects require field names to be quoted, but the type
  language omits quotes for clarity. Thus the object ‹{"a": 42, "b": "xyz"}›
  conforms to the type {a: int, b: string}›, for example.

  
  The absence of an argument or result is represented by the Scala type
  ‹Unit›: it is written as empty text in the message argument›
  (\secref{sec:input-output-messages}). This is not part of the JSON language.

  Server replies have name tags like ‹OK›, ‹ERROR›: these are used literally
  together with type specifications to indicate the particular name with the
  type of its argument, e.g.\ ‹OK›~[string]› for a regular result that is a
  list (JSON array) of strings.

  
  Here are some common type definitions, for use in particular specifications
  of command arguments and results.

   ‹type›~position = {line?: int, offset?: int, end_offset?: int, file?:
  string, id?: long}› describes a source position within Isabelle text. Only
  the line› and file› fields make immediate sense to external programs.
  Detailed offset› and end_offset› positions are counted according to
  Isabelle symbols, see ML_typeSymbol.symbol in Isabelle/ML cite"isabelle-implementation". The position id› belongs to the representation
  of command transactions in the Isabelle/PIDE protocol: it normally does not
  occur in externalized positions.

   ‹type›~message = {kind: string, message: string, pos?: position}› where
  the kind› provides some hint about the role and importance of the message.
  The main message kinds are ‹writeln› (for regular output), ‹warning›,
  ‹error›.

   ‹type›~error_message = {kind:›~‹"error"›, message: string}› refers to
  error messages in particular. These occur routinely with ‹ERROR› or
  ‹FAILED› replies, but also as initial command syntax errors (which are
  omitted in the command specifications below).

   ‹type›~theory_progress = {kind:›~‹"writeln"›, message: string, theory:
  string, session: string, percentage?: int}› reports formal progress in
  loading theories (e.g.\ when building a session image). Apart from a regular
  output message, it also reveals the formal theory name (e.g.\ ‹"HOL.Nat"›)
  and session name (e.g.\ ‹"HOL"›). Note that some rare theory names lack a
  proper session prefix, e.g.\ theory ‹"Main"› in session ‹"HOL"›. The
  optional percentage has the same meaning as in ‹type›~node_status› below.

   ‹type›~timing = {elapsed: double, cpu: double, gc: double}› refers to
  common Isabelle timing information in seconds, usually with a precision of
  three digits after the point (whole milliseconds).

   ‹type›~uuid = string› refers to a Universally Unique Identifier (UUID)
  as plain text.‹See 🌐‹https://www.ietf.org/rfc/rfc4122.txt› and
  🌐‹https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/UUID.html›.› Such
  identifiers are created as private random numbers of the server and only
  revealed to the client that creates a certain resource (e.g.\ task or
  session). A client may disclose this information for use in a different
  client connection: this allows to share sessions between multiple
  connections.

  Client commands need to provide syntactically wellformed UUIDs: this is
  trivial to achieve by using only identifiers that have been produced by the
  server beforehand.

   ‹type›~task = {task: uuid}› identifies a newly created asynchronous task
  and thus allows the client to control it by the ‹cancel› command. The same
  task identification is included in all messages produced by this task.

   ‹type› session_id = {session_id: uuid}› identifies a newly created PIDE
  session managed by the server. Sessions are independent of client
  connections and may be shared by different clients, as long as the internal
  session identifier is known.

   ‹type› node = {node_name: string, theory_name: string}› represents the
  internal node name of a theory. The node_name› is derived from the
  canonical theory file-name (e.g.\ ‹"~~/src/HOL/Examples/Seq.thy"› after
  normalization within the file-system). The theory_name› is the
  session-qualified theory name (e.g.\ ‹HOL-Examples.Seq›).

   ‹type› node_status = {ok: bool, total: int, unprocessed: int, running:
  int, warned: int, failed: int, finished: int, canceled: bool, consolidated:
  bool, percentage: int}› represents a formal theory node status of the PIDE
  document model as follows.

     Fields total›, unprocessed›, running›, warned›, failed›, finished›
      account for individual commands within a theory node; ok› is an
      abstraction for failed = 0›.

     The canceled› flag tells if some command in the theory has been
      spontaneously canceled (by an Interrupt exception that could also
      indicate resource problems).

     The consolidated› flag indicates whether the outermost theory command
    structure has finished (or failed) and the final end command has been
    checked.

     The percentage› field tells how far the node has been processed. It
    ranges between 0 and 99 in normal operation, and reaches 100 when the node
    has been formally consolidated as described above.
›



section ‹Server commands and results›

text ‹
  Here follows an overview of particular Isabelle server commands with their
  results, which are usually represented as JSON values with types according
  to \secref{sec:json-types}. The general format of input and output messages
  is described in \secref{sec:input-output-messages}. The relevant
  Isabelle/Scala source files are:

  
  \begin{tabular}{l}
  🗏‹$ISABELLE_HOME/src/Pure/Tools/server_commands.scala› \\
  🗏‹$ISABELLE_HOME/src/Pure/Tools/server.scala› \\
  🗏‹$ISABELLE_HOME/src/Pure/General/json.scala› \\
  \end{tabular}
›


subsection ‹Command ‹help›

text ‹
  \begin{tabular}{ll}
  regular result: & ‹OK› [string]› \\
  \end{tabular}
  

  The ‹help› command has no argument and returns the list of server command
  names. This is occasionally useful for interactive experimentation (see also
  @{tool client} in \secref{sec:tool-client}).
›


subsection ‹Command ‹echo›

text ‹
  \begin{tabular}{ll}
  argument: & any› \\
  regular result: & ‹OK› any› \\
  \end{tabular}
  

  The ‹echo› command is the identity function: it returns its argument as
  regular result. This is occasionally useful for testing and interactive
  experimentation (see also @{tool client} in \secref{sec:tool-client}).

  The Scala type of ‹echo› is actually more general than given above:
  ‹Unit›, ‹XML.Elem›, ‹JSON.T› work uniformly. Note that ‹XML.Elem› might
  be difficult to type on the console in its YXML syntax
  (\secref{sec:yxml-vs-xml}).
›


subsection ‹Command ‹shutdown›

text ‹
  \begin{tabular}{ll}
  regular result: & ‹OK› \\
  \end{tabular}
  

  The ‹shutdown› command has no argument and result value. It forces a
  shutdown of the connected server process, stopping all open sessions and
  closing the server socket. This may disrupt pending commands on other
  connections!

  
  The command-line invocation ‹isabelle server -x› opens a server connection
  and issues a ‹shutdown› command (see also \secref{sec:tool-server}).
›


subsection ‹Command ‹cancel›

text ‹
  \begin{tabular}{ll}
  argument: & task› \\
  regular result: & ‹OK› \\
  \end{tabular}
  

  The command ‹cancel {"task":›~id›‹}› attempts to cancel the specified
  task.

  Cancellation is merely a hint that the client prefers an ongoing process to
  be stopped. The command always succeeds formally, but it may get ignored by
  a task that is still running; it might also refer to a non-existing or
  no-longer existing task (without producing an error).

  Successful cancellation typically leads to an asynchronous failure of type
  ‹FAILED {›task: uuid, message:›~‹"Interrupt"}›. A different message is
  also possible, depending how the task handles the event.
›


subsection ‹Command ‹session_build› \label{sec:command-session-build}›

text ‹
  \begin{tabular}{lll}
  argument: & session_build_args› \\
  immediate result: & ‹OK› task› \\
  notifications: & ‹NOTE› task ⊕ (theory_progress | message)› \\
  regular result: & ‹FINISHED› task ⊕ session_build_results› \\
  error result: & ‹FAILED› task ⊕ error_message ⊕ session_build_results› \\[2ex]
  \end{tabular}

  \begin{tabular}{lll}
  ‹type› session_build_args =› \\
  \quad{session: string,› \\
  \quad~~preferences?: string,› & ‹default:› server preferences \\
  \quad~~options?: [string],› \\
  \quad~~dirs?: [string],› \\
  \quad~~include_sessions: [string],› \\
  \quad~~verbose?: bool}› \\[2ex]
  \end{tabular}

  \begin{tabular}{ll}
  ‹type› session_build_result =› \\
  \quad{session: string,› \\
  \quad~~ok: bool,› \\
  \quad~~return_code: int,› \\
  \quad~~timeout: bool,› \\
  \quad~~timing: timing}› \\[2ex]

  ‹type› session_build_results =› \\
  \quad{ok: bool,› \\
  \quad~~return_code: int,› \\
  \quad~~sessions: [session_build_result]}› \\
  \end{tabular}
›

text ‹
  The ‹session_build› command prepares a session image for interactive use of
  theories. This is a limited version of command-line tool @{tool build}
  (\secref{sec:tool-build}), with specific options to request a formal context
  for an interactive PIDE session.

  The build process is asynchronous, with notifications that inform about the
  progress of loaded theories. Some further informative messages are output as
  well.

  Coordination of independent build processes is at the discretion of the
  client (or end-user), just as for @{tool build} and @{tool jedit}. There is
  no built-in coordination of conflicting builds with overlapping hierarchies
  of session images. In the worst case, a session image produced by one task
  may get overwritten by another task!
›


subsubsection ‹Arguments›

text ‹
  The session› field specifies the target session name. The build process
  will produce all required ancestor images according to the overall session
  graph.

  
  The environment of Isabelle system options is determined from preferences›
  that are augmented by options›, which is a list individual updates of the
  form the name›‹=›value› or name› (the latter abbreviates
  name›‹=true›); see also command-line option ‹-o› for @{tool build}. The
  preferences are loaded from the file
  path‹$ISABELLE_HOME_USER/etc/preferences› by default, but the client may
  provide alternative contents for it (as text, not a file-name). This could
  be relevant in situations where client and server run in different
  operating-system contexts.

  
  The dirs› field specifies additional directories for session ROOT and ROOTS
  files (\secref{sec:session-root}). This augments the name space of available
  sessions; see also option ‹-d› in @{tool build}.

  
  The include_sessions› field specifies sessions whose theories should be
  included in the overall name space of session-qualified theory names. This
  corresponds to a ‹sessions› specification in ROOT files
  (\secref{sec:session-root}). It enables the ‹use_theories› command
  (\secref{sec:command-use-theories}) to refer to sources from other sessions
  in a robust manner, instead of relying on directory locations.
›


subsubsection ‹Intermediate output›

text ‹
  The asynchronous notifications of command ‹session_build› mainly serve as
  progress indicator: the output resembles that of the session build window of
  Isabelle/jEdit after startup cite"isabelle-jedit".

  For the client it is usually sufficient to print the messages in plain text,
  but note that theory_progress› also reveals formal theory› and
  session› names directly.
›


subsubsection ‹Results›

text ‹
  The overall session_build_results› contain both a summary and an entry
  session_build_result› for each session in the build hierarchy. The result
  is always provided, independently of overall success (‹FINISHED› task) or
  failure (‹FAILED› task).

  The ok› field tells abstractly, whether all required session builds came
  out as ok›, i.e.\ with zero return_code›. A non-zero return_code›
  indicates an error according to usual POSIX conventions for process exit.

  The individual session_build_result› entries provide extra fields:

   timeout› tells if the build process was aborted after running too long,

   timing› gives the overall process timing in the usual Isabelle format
  with elapsed, CPU, GC time.
›


subsubsection ‹Examples›

text ‹
  Build of a session image from the Isabelle distribution:
  @{verbatim [display] ‹session_build {"session": "HOL-Algebra"}›}

  Build a session image from the Archive of Formal Proofs:
  @{verbatim [display] ‹session_build {"session": "Coinductive", "dirs": ["$AFP_BASE/thys"]}›}


subsection ‹Command ‹session_start› \label{sec:command-session-start}›

text ‹
  \begin{tabular}{lll}
  argument: & session_build_args ⊕ {print_mode?: [string]}› \\
  immediate result: & ‹OK› task› \\
  notifications: & ‹NOTE› task ⊕ (theory_progress | message)› \\
  regular result: & ‹FINISHED› task ⊕ session_id ⊕ {tmp_dir: string}› \\
  error result: & ‹FAILED› task ⊕ error_message› \\[2ex]
  \end{tabular}

  
  The ‹session_start› command starts a new Isabelle/PIDE session with
  underlying Isabelle/ML process, based on a session image that it produces on
  demand using ‹session_build›. Thus it accepts all session_build_args› and
  produces similar notifications, but the detailed session_build_results› are
  omitted.

  The session build and startup process is asynchronous: when the task is
  finished, the session remains active for commands, until a ‹session_stop›
  or ‹shutdown› command is sent to the server.

  Sessions are independent of client connections: it is possible to start a
  session and later apply ‹use_theories› on different connections, as long as
  the internal session identifier is known: shared theory imports will be used
  only once (and persist until purged explicitly).
›


subsubsection ‹Arguments›

text ‹
  Most arguments are shared with ‹session_build›
  (\secref{sec:command-session-build}).

  
  The print_mode› field adds identifiers of print modes to be made active for
  this session. For example, ‹"print_mode": ["ASCII"]› prefers ASCII
  replacement syntax over mathematical Isabelle symbols. See also option ‹-m›
  in @{tool process} (\secref{sec:tool-process}).
›


subsubsection ‹Results›

text ‹
  The session_id› provides the internal identification of the session object
  within the server process. It can remain active as long as the server is
  running, independently of the current client connection.

  
  The tmp_dir› field refers to a temporary directory that is specifically
  created for this session and deleted after it has been stopped. This may
  serve as auxiliary file-space for the ‹use_theories› command, but
  concurrent use requires some care in naming temporary files, e.g.\ by
  using sub-directories with globally unique names.

  As tmp_dir› is the default master_dir› for commands ‹use_theories› and
  ‹purge_theories›, theory files copied there may be used without further
  path specification.
›


subsubsection ‹Examples›

text ‹
  Start a default Isabelle/HOL session:
  @{verbatim [display] ‹session_start {"session": "HOL"}›}

  Start a session from the Archive of Formal Proofs:
  @{verbatim [display] ‹session_start {"session": "Coinductive", "dirs": ["$AFP_BASE/thys"]}›}

  Start a session with fine-tuning of options:
  @{verbatim [display] ‹session_start {"session": "HOL",
  "options": ["headless_consolidate_delay=0.5", "headless_prune_delay=5"]}›}


subsection ‹Command ‹session_stop›

text ‹
  \begin{tabular}{ll}
  argument: & session_id› \\
  immediate result: & ‹OK› task› \\
  regular result: & ‹FINISHED› task ⊕ session_stop_result› \\
  error result: & ‹FAILED› task ⊕ error_message ⊕ session_stop_result› \\[2ex]
  \end{tabular}

  \begin{tabular}{l}
  ‹type› session_stop_result = {ok: bool, return_code: int}›
  \end{tabular}

  
  The ‹session_stop› command forces a shutdown of the identified PIDE
  session. This asynchronous tasks usually finishes quickly. Failure only
  happens in unusual situations, according to the return code of the
  underlying Isabelle/ML process.
›


subsubsection ‹Arguments›

text ‹
  The session_id› provides the UUID originally created by the server for this
  session.
›


subsubsection ‹Results›

text ‹
  The ok› field tells abstractly, whether the Isabelle/ML process has
  terminated properly.

  The return_code› field expresses this information according to usual POSIX
  conventions for process exit.
›


subsection ‹Command ‹use_theories› \label{sec:command-use-theories}›

text ‹
  \begin{tabular}{ll}
  argument: & use_theories_arguments› \\
  immediate result: & ‹OK› task› \\
  regular result: & ‹FINISHED› use_theories_results› \\
  \end{tabular}

  \begin{tabular}{ll}
  ‹type› use_theories_arguments =› \\
  \quad{session_id: uuid,› \\
  \quad~~theories: [string],› \\
  \quad~~master_dir?: string,› & ‹default:› session tmp_dir› \\
  \quad~~pretty_margin?: double,› & ‹default:› ‹76› \\
  \quad~~unicode_symbols?: bool,› \\
  \quad~~export_pattern?: string,› \\
  \quad~~check_delay?: double,›  & ‹default:› ‹0.5› \\
  \quad~~check_limit?: int,› \\
  \quad~~watchdog_timeout?: double,› & ‹default:› ‹600.0› \\
  \quad~~nodes_status_delay?: double}›  & ‹default:› ‹-1.0› \\
  \end{tabular}

  \begin{tabular}{ll}
  ‹type› export =› \\
  \quad~~{name: string, base64: bool, body: string}› \\
  ‹type› node_results =› \\
  \quad~~{status: node_status, messages: [message], exports: [export]}› \\
  ‹type› nodes_status =› \\
  \quad~~[node ⊕ {status: node_status}]› \\
  ‹type› use_theories_results =› \\
  \quad{ok: bool,› \\
  \quad~~errors: [message],› \\
  \quad~~nodes: [node ⊕ node_results]}› \\
  \end{tabular}

  
  The ‹use_theories› command updates the identified session by adding the
  current version of theory files to it, while dependencies are resolved
  implicitly. The command succeeds eventually, when all theories have status
  ‹terminated› or ‹consolidated› in the sense of node_status›
  (\secref{sec:json-types}).

  Already used theories persist in the session until purged explicitly
  (\secref{sec:command-purge-theories}). This also means that repeated
  invocations of ‹use_theories› are idempotent: it could make sense to do
  that with different values for pretty_margin› or unicode_symbols› to get
  different formatting for errors› or messages›.

   A non-empty export_pattern› means that theory exports› are retrieved
  (see \secref{sec:tool-export}). An export› name› roughly follows
  file-system standards: ``‹/›'' separated list of base names (excluding
  special names like ``‹.›'' or ``‹..›''). The base64› field specifies the
  format of the body› string: it is true for a byte vector that cannot be
  represented as plain text in UTF-8 encoding, which means the string needs to
  be decoded as in ‹java.util.Base64.getDecoder.decode(String)›.

   The status of PIDE processing is checked every check_delay› seconds, and
  bounded by check_limit› attempts (default: 0, i.e.\ unbounded). A
  check_limit > 0› effectively specifies a global timeout of check_delay ×
  check_limit› seconds.

   If watchdog_timeout› is greater than 0, it specifies the timespan (in
  seconds) after the last command status change of Isabelle/PIDE, before
  finishing with a potentially non-terminating or deadlocked execution.

   A non-negative nodes_status_delay› enables continuous notifications of
  kind nodes_status›, with a field of name and type nodes_status›. The time
  interval is specified in seconds; by default it is negative and thus
  disabled.
›


subsubsection ‹Arguments›

text ‹
  The session_id› is the identifier provided by the server, when the session
  was created (possibly on a different client connection).

  
  The theories› field specifies theory names as in theory imports or in
  ROOT ‹theories›.

  
  The master_dir› field specifies the master directory of imported theories:
  it acts like the ``current working directory'' for locating theory files.
  This is irrelevant for theories› with an absolute path name (e.g.\
  ‹"~~/src/HOL/Examples/Seq.thy"›) or session-qualified theory name (e.g.\
  ‹"HOL-Examples.Seq"›).

  
  The pretty_margin› field specifies the line width for pretty-printing. The
  default is suitable for classic console output. Formatting happens at the
  end of ‹use_theories›, when all prover messages are exported to the client.

  
  The unicode_symbols› field set to ‹true› renders message output for direct
  output on a Unicode capable channel, ideally with the Isabelle fonts as in
  Isabelle/jEdit. The default is to keep the symbolic representation of
  Isabelle text, e.g.\ ‹∀› instead of its rendering as ∀›. This means the
  client needs to perform its own rendering before presenting it to the
  end-user.
›


subsubsection ‹Results›

text ‹
  The ok› field indicates overall success of processing the specified
  theories with all their dependencies.

  When ok› is ‹false›, the errors› field lists all errors cumulatively
  (including imported theories). The messages contain position information for
  the original theory nodes.

  
  The nodes› field provides detailed information about each imported theory
  node. The individual fields are as follows:

   node_name›: the canonical name for the theory node, based on its
  file-system location;

   theory_name›: the logical theory name;

   status›: the overall node status, e.g.\ see the visualization in the
  Theories› panel of Isabelle/jEdit cite"isabelle-jedit";

   messages›: the main bulk of prover messages produced in this theory
  (with kind ‹writeln›, ‹warning›, ‹error›).
›


subsubsection ‹Examples›

text ‹
  Process some example theory from the Isabelle distribution, within the
  context of an already started session for Isabelle/HOL (see also
  \secref{sec:command-session-start}):
  @{verbatim [display] ‹use_theories {"session_id": ..., "theories": ["~~/src/HOL/Examples/Seq"]}›}

  
  Process some example theories in the context of their (single) parent
  session:

  @{verbatim [display] ‹session_start {"session": "HOL-Library"}
use_theories {"session_id": ..., "theories": ["~~/src/HOL/Unix/Unix"]}
session_stop {"session_id": ...}›}

  
  Process some example theories that import other theories via
  session-qualified theory names:

  @{verbatim [display] ‹session_start {"session": "HOL", "include_sessions": ["HOL-Unix"]}
use_theories {"session_id": ..., "theories": ["HOL-Unix.Unix"]}
session_stop {"session_id": ...}›}


subsection ‹Command ‹purge_theories› \label{sec:command-purge-theories}›

text ‹
  \begin{tabular}{ll}
  argument: & purge_theories_arguments› \\
  regular result: & ‹OK› purge_theories_result› \\
  \end{tabular}

  \begin{tabular}{lll}
  ‹type› purge_theories_arguments =› \\
  \quad{session_id: uuid,› \\
  \quad~~theories: [string],› \\
  \quad~~master_dir?: string,› & ‹default:› session tmp_dir› \\
  \quad~~all?: bool}› \\[2ex]
  \end{tabular}

  \begin{tabular}{ll}
  ‹type› purge_theories_result = {purged: [string]}› \\
  \end{tabular}

  
  The ‹purge_theories› command updates the identified session by removing
  theories that are no longer required: theories that are used in pending
  ‹use_theories› tasks or imported by other theories are retained.
›


subsubsection ‹Arguments›

text ‹
  The session_id› is the identifier provided by the server, when the session
  was created (possibly on a different client connection).

  
  The theories› field specifies theory names to be purged: imported
  dependencies are ‹not› completed. Instead it is possible to provide the
  already completed import graph returned by ‹use_theories› as nodes› /
  node_name›.

  
  The master_dir› field specifies the master directory as in ‹use_theories›.
  This is irrelevant, when passing fully-qualified theory node names (e.g.\
  node_name› from nodes› in use_theories_results›).

  
  The all› field set to ‹true› attempts to purge all presently loaded
  theories.
›


subsubsection ‹Results›

text ‹
  The purged› field gives the theory nodes that were actually removed.

  
  The retained› field gives the remaining theory nodes, i.e.\ the complement
  of purged›.
›

end