Architecture

This is important if you plan to use Quills with your own interpreter, or if you will be maintaining the framework.
You may also just find it interesting.

Quills Framework

For flexibility, the API is a framework, with no embedded interpreter. Unlike other applications that have script bindings, MacTerm
does not always need to “run” first in order to execute script code, nor are your scripts constrained to a particular Python version.

One advantage of this is that scripts are not gratuitously forced to run in MacTerm. If the script never has to launch anything
graphical (such as a terminal window), the user might not even know that MacTerm code was used.

Sometimes, you have to use other Python code that has more stringent version requirements; for instance, you may wish to use a version
of Python that is newer than the default on macOS, requiring you to build your own python. This is another advantage of
the framework approach: since you are not using an interpreter embedded in MacTerm, you are not forced to use a particular version of
the interpreter. Usually, you can just import Quills normally into your alternate interpreter version.

The framework contains a few different builds, to maximize the chances of binary compatibility. Of course, the source code is
also available, if it should ever be necessary to rebuild the bindings for another interpreter; you may also contact the lead MacTerm
developer to request binary wrappers that support a newer version of Python.

The directory structure of the framework (ignoring top-level symbolic links and resources) is:

The “A” and “B” versions reflect the microprocessor architecture. Version “A” no longer exists; it historically supported
Panther, because only PowerPC-specific binaries worked on that system. Version “B” is a Universal binary.

The MacTermQuills binary file is unique to each architecture; it contains the vast majority
of C++ code to implement Quills (and therefore MacTerm).

To tie C++ to Python, each lib contains bindings (see below for more information on bindings). There will usually
be one of these for each binary-incompatible version of Python. Since a significant number of modern macOS releases have not changed
the available versions of Python, the included bindings have worked for many years now.

Each _quills.so and quills.py combination represents a module that can be loaded with import quills
in Python, depending also on the MacTermQuills binary. The right Python and C++ library search paths must be set for this to work.

Note: See the importing page for examples of how to import the Quills module
from Python. It should be obvious from the above that the correct library paths will vary significantly based on the OS and
architecture, and that importing is non-trivial. However, the code to do importing correctly is already written (used in the
MacTerm main entry point), and you are encouraged to simply do what it does, in your own scripts.

PyMacTerm Framework

Note that MacTerm also includes the PyMacTerm framework. This is not part of Quills; PyMacTerm actually depends on
Quills, and implements MacTerm features entirely in Python!

You can use the PyMacTerm framework as a source of good examples on how to use Quills successfully. You can also use it to
restore default behavior (the main MacTerm script in the application bundle shows you which PyMacTerm functions are registered).

API Design

The Quills API is currently quite simple, and there are many plans to improve it. It is split into domains, similar to those seen
elsewhere in MacTerm; for instance, Session deals with running commands, and Terminal customizes the emulator.

Quills is heavily callback based. It is almost never correct to look for a global function to sequentially perform an
action; instead, there will be a way to request that the C++ implementation invoke one or more Python functions at key points. This
is the basis for customization, and can be extremely powerful even with the small API that is available so far!

The primary reason for callbacks is that you often will run the main event loop (launching the MacTerm graphical user interface),
and doing so will prevent Python from returning normally to your script. Without callbacks, you would be forced to perform every
possible Python action up front, which is simply not useful.

Quills callbacks will not incur performance penalties by invoking Python code in critical places. Some callbacks will
be called earlier than you might think, so that results can be cached for good performance when the information is actually required.

The Quills API is carefully edited to provide only unique functionality. You will not see pointless routines that are wrappers
for something else. For instance, there are other ways to access MacTerm low-level settings (such as the defaults program),
so there are no Quills APIs to duplicate that; on the other hand, there are Preferences APIs for accessing and changing things that
would be cumbersome to find using defaults, such as the names of available collections.

Also, the API is not designed to cover things that are appropriately handled using data files. For example, the “factory defaults”
in MacTerm are defined by DefaultPreferences.plist in its main bundle, which is a much more convenient way to make initial
settings.

In general, exceptions flow gracefully across Python and C++ boundaries in either direction; so you may catch standard
exception types in your Python code to find problems, and raise errors that you want Quills to know about. This is a key
debugging feature. However, it has a cost; in the future, some APIs may choose to forego exception handling for performance reasons,
and will be documented as such.

Bindings

MacTerm uses the Simple Wrapper Interface Generator (SWIG) to generate its bindings between
Python 2.x and C++ code. (Python 3.x support is planned only when Apple includes a default macOS interpreter for 3.x.)

SWIG supports a variety of scripting languages from one source. Only a small amount of Python-specific code is currently
required, so an interesting project would be to add support for additional languages someday.

The advantages of bindings are clear. MacTerm features can be implemented entirely in Python, taking advantage of the whole
Python standard library. Code is easier to write, test, debug, and maintain in Python than in C++. Advanced users can perform
unheard-of customizations.