This is the documentation for the Symex package for Emacs.

This work is not owned by anyone. Please see the Declaration of Non-Ownership (https://github.com/drym-org/foundation/blob/main/DECLARATION-OF-NON-OWNERSHIP.md).

Symex - An Expressive Modal Way to Write Code
*********************************************

Symex Logo

This manual is for Symex (version 2.0).

A quick movement out of the corner of your eye, but it’s gone as you turn to look. A rustle in the trees, or did you imagine it? A shadow passing overhead, and a blinding flash as you look up. Was that the Sun, or the gleam in the eye of Symex the Squirrel, as it soared above the treetops?

You’ll never know. The legendary Squirrel is said to possess startling agility and speed, capable of executing mind-bending maneuvers in the trees, traversing impossible distances in a single leap. So they say. Yet, no one has ever seen Symex. Some say that it is much too quick for our eyes to see. Others say that no one has seen Symex because, you fool (they say), Symex isn’t some squirrel out there — it’s the squirrel in you.

What is Symex?
**************

Symex (pronounced sim-ex) is an intuitive modal way to edit code.

It's built on top of an expressive domain-specific language (DSL) for tree-oriented operations. This design allows it to offer a large array of useful features with short and memorable (and of course, customizable) keybindings, allowing you to edit code fluently. It also gives you the ability to define your own structural operations using the same DSL that Symex implements many of its features in.

In addition, ``symex'' is also just a more versatile term for talking about the ``S-expressions'' or ``symbolic expressions'' that form the syntax of Lisp code. Symex was originally designed to be a Lisp editor, but you can now use it with any language via Treesitter (https://tree-sitter.github.io/tree-sitter/), included in Emacs 29+.

A Note on the Name
==================

Symex was originally a tool for editing Lisp code, although it can be used with many languages, now.

Lisp has inherited a few oddball names from its deep prehistory, including the infamous car and cdr for the first and the rest of the elements in a list (https://www.blogbyben.com/2011/04/best-bumper-sticker-ever.html). But S-expression / sex-puh / symbolic expression — referring to the makeup of Lisp syntax — are all somewhat of a mouthful, too. Here are a few reasons why we might consider using "sym-ex" instead:

  * "Symbolic expression": 6 syllables, long in written form too.

  * "S-expression": 4 syllables, and confusing at least partially because it is a single-letter acronym, which is unusual. In addition, it is long in written form.

  * "Sexpuh" / "sex-p" / "sexpr": 2 syllables, short in written form. But I mean, these are terrible.

  * "s-ex": Speaks for itself.

  * "Symex": 2 syllables, short in written form, has normal linguistic analogues like "complex/complexes," and it's fun to say! Symex also sounds like Ibex, and that's obviously a plus.

Symex is a Friend to All
========================

Symex follows Attribution Based Economics and is owned by no one.

Please see the Declaration of Non-Ownership (https://github.com/drym-org/foundation/blob/main/Declaration_of_Non_Ownership.md).

Comparison with Similar Packages
================================

This section compares Symex with related editing tools available for Emacs.

An important thing to remember about Symex is that using it requires you to enter a specific mode on-demand. Due to this modal nature, you can generally use any other editing tool you may be familiar with alongside Symex — including most of the options discussed below — and there shouldn't be any conflict. Symex is a friend to all!

At the same time, Symex is designed in a standalone way and doesn't assume you are using other tools. Consequently, in some cases, you may need to disable some default customizations to avoid conflicts with these other packages that you may like to use for particular purposes, as the sections below explain. Some pairings definitely make more sense than others!

Evil
----

The essential idea of Vim/Evil is that there are motions (nouns) that may be combined with operators (verbs), so that many complex operations on text can be expressed in this compositional manner. Although precise and expressive, this Vim-style interface has a steep learning curve and, out of the box, it isn't appropriate for structural code editing as there is no symex noun for dealing with expressions of code. Extending Evil by adding such a noun (or ``text object,'' in Vim parlance) would be one way to allow precise operation on symexes, but there are a few reasons why Symex did not choose to go this route: (1) it leaves out vanilla Emacs users who may not be familiar with Evil at all, and (2) it inflates Evil — an already substantial interface — with yet another noun that would compete for keybinding real estate with other nouns such as words and paragraphs.

Yet, augmenting Evil with a symex text object would be a valuable alternative way to achieve a Symex-like experience, and that's what Evil-Cleverparens (another package discussed below) does.

Symex and Evil go very well together. Please see Symex and Evil for instructions on using them together.

Lispy
-----

Lispy addresses the problem of leveraging known context (i.e., that you are engaged in editing symexes) by having keybindings take on special meaning depending on the cursor's position in relation to the expression as a whole. This approach is as efficient as it gets, and many find it intuitive and fun.

As it requires placing the cursor at special points in order to achieve the desired transformations, the paradigm is difficult to scale for complex or batch tasks. Symex's pointfree modal style allows it to emulate this desirable property of Vim/Evil while still exhibiting simplicity and efficiency like Lispy.

The choice to use Lispy or Symex is mostly a matter of personal preference. Lispy offers a compromise between modal and modeless editing that may be favored by those used to the modeless style, gaining some benefits of the former while still exhibiting the latter. Symex is minimally, yet formally, modal, with all that comes along with that.

You can still use these two packages together, but as their functionality overlaps to a great extent, this is perhaps inadvisable.

Paredit
-------

Paredit is perhaps the original structural editing tool. Its basic functionality of balancing parentheses is still essential to preserve the structure of the code, and Symex uses this functionality from Paredit even today.

Fundamentally, Paredit is a low level Lisp parser. Symex builds on top of it (in addition to native Emacs facilities including tree-sitter) to provide a high level DSL for structural editing. This DSL allows us to easily implement paredit-like features without needing to write Emacs Lisp (for example, paste for a basic implementation of ``emit forward'' (aka ``barf'')). Many features included in Symex out of the box --- including the many ways to get around: leaping, traversing, climbing and descending --- are written in this DSL. The Symex DSL is easy to learn, and expresses computations in a very intuitive way.

From a UI standpoint, Symex's modal nature is its primary difference from Paredit.

Symex uses Paredit to balance parentheses in Lisp languages. If you're prefer to use a different tool for this purpose, please see Balancing Parentheses.

Tree-Edit
---------

Tree-Edit (https://github.com/ethan-leba/tree-edit) was one of the first packages to offer structural editing for non-Lisp languages via Tree-sitter. It is composed of two packages. First, a core library containing a reasoning engine built on top of tree-sitter, along with commands for structural and templated editing. And another package for an evil state that leverages these features in a user interface. The latter provides a ``point-free'' editing experience similar to Symex.

While there is some overlap in functionality at the UI level, the core features offered by the packages are fairly distinct, and it's likely that they could be leveraged by either package, someday.

For instance, Symex provides a very basic set of insertion commands. ``Inserting after'' an if block in Symex would just put the cursor at the right spot and leave the rest to you, but Tree-Edit would wrap the insertion point with else! On the other hand, Symex provides a rich array of traversals via the DSL, which Tree-Edit doesn't have today.

For most other packages on this list, it's easy to use them together with Symex, but for Tree-Edit, as it, too, is modal, using them together may not be straightforward. It likely makes a lot more sense to integrate these packages at the library level, which we hope to explore.

Combobulate
-----------

Combobulate is similar to Symex in its aims to be precise and intuitive. It differs in the style of interface and the feature set, providing a lot more grammar-aware and IDE-like features than Symex does. Symex has a minimal interface and offers more diverse features for elementary structural manipulation.

Ultimately, while there is some overlap in features, there's also a lot offered by each that's not present in the other, so that it might make sense to use one and cherry-pick features from the other. For instance, to employ specific Combobulate features from Symex, you could use a similar recipe as Symex and Evil. It may also be feasible to integrate them more at a library level. As part of the 2.0 release, Symex --- a formerly monolithic package --- was decomposed into small and modular packages in order to facilitate such goals.

Combobulate is thoughtfully designed and sophisticated, and may be a good fit for you. Try both and see which one (or both!) fits your style better!

Smartparens
-----------

Smartparens is like Paredit but for any language, and supports all types of ``pairs'' (e.g., including HTML tags) and not only parentheses and brackets.

For non-Lisp languages, using Smartparens together with Symex is recommended! See Balancing Parentheses for more.

For Lisp, Symex already includes parenthesis balancing via Paredit, so using Smartparens in addition likely would not be useful. But if you still would prefer to, then you can disable Symex's parenthesis balancing so that you can use whatever package you may already have configured for this purpose (e.g., either Smartparens or Paredit).

Please note: Symex relies on code being structurally valid, so if you choose to disable this, you must provide an alternative, either via Paredit or Smartparens or another similar package, so that the structural integrity of the code is always maintained.

Evil Cleverparens
-----------------

This package provides a text object for Evil for working with symexes. It also prevents normal Evil commands like dd (delete line) from breaking parenthesis structure. If you are an Evil user, this would be a good way to edit Lisp code that augments the familiar Evil compositional style.

Symex is harmonious with Evil but totally separate from it, as it is a distinct mode. While Evil-Cleverparens makes Normal state behave better with respect to structure, Symex is oriented directly around structure, offering a large array of structural features. Due to this different emphasis, if you are an Evil user, you may prefer to use Evil Cleverparens together with Symex, to simultaneously gain advanced tree-structured editing while also enhancing Normal state to be structure-aware.

Parinfer
--------

Parinfer exploits a duality between indentation and parenthesis nesting to handle either for you when you change the other.

You should be able to use this together with Symex. If you do, you will likely want to set symex-tidy-after-transforming-p to nil, and possibly also symex-ensure-structure-p to nil. See Customizing Symex for more information.

Installation and Setup
**********************

This section covers installing Symex and setting it up, and information about supported languages.

Installing Symex
================

Symex is distributed as a collection of small, composable packages, hosted directly at the source repository. This allows you maximum flexibility to install just the functionality you actually need, without getting anything extra. But it also means that you must explicitly list the Symex packages you are interested in. Each of the Symex packages is described below, along with sample installation config using Straight.el (if you are using another package manager, see Instructions for Other Package Managers).

Note that the config below includes inline package recipes which tell Straight.el where to find these packages and how to build them, but if you are using Elacarte, you do not need to include these inline recipes.

 1. symex-core. This includes a DSL for structural operations, which is the core functionality of Symex, and is required for all users of Symex.

          (use-package symex-core
            :straight
            (symex-core
             :host github
             :repo "drym-org/symex.el"
             :files ("symex-core/symex*.el")))

     This core package provides the structural editing engine, supporting both Lisp (via paredit) and other languages (via Treesitter). This is a lean package with few dependencies, so that, in addition to use by end users, it's also appropriate as a library dependency for third party packages to gain Symex features.

     Note that if you are using Elacarte, you do not need to declare this package in your config as it will be implicitly installed as a dependency.

 2. symex. The main user-facing package, required for all end users. It provides the modal UI that makes Symex features easy to use.

          (use-package symex
            :after (symex-core)
            :straight
            (symex
             :host github
             :repo "drym-org/symex.el"
             :files ("symex/symex*.el" "symex/doc/*.texi" "symex/doc/figures"))
            :config
            (symex-mode 1)
            (global-set-key (kbd "s-;") #'symex-mode-interface))  ; or whatever keybinding you like
            ;; and any other customizations you like

     Note the keybinding ``s-;`` which enters the Symex modal UI. Feel free to set it to whatever you find convenient. There are many ways to enter Symex mode in different contexts, and we'll cover these in detail as we go along.

     All of the remaining packages in this list depend on, and extend, this modal UI package.

 3. symex-ide. A recommended, optional, extension integrating Symex with major modes for IDE-like features, such as easy evaluation and documentation lookup, and entering a REPL.

          (use-package symex-ide
            :after (symex)
            :straight
            (symex-ide
             :host github
             :repo "drym-org/symex.el"
             :files ("symex-ide/symex*.el"))
            :config
            (symex-ide-mode 1))

 4. symex-evil. An extension for integration with Evil mode, including familiar keybindings, advising Evil functions to play well with Symex mode, and other functionality to make using Symex with Evil seamless. This is only required for Evil users.

          (use-package symex-evil
            :after (symex evil)
            :straight
            (symex-evil
             :host github
             :repo "drym-org/symex.el"
             :files ("symex-evil/symex*.el"))
            :config
            (symex-evil-mode 1))

 5. symex-rigpa. This integrates Symex with Rigpa, allowing you to conveniently manage Symex as a mode within the broader Rigpa modal framework, including defining convenient entry and exit via familiar key sequences such as Enter and Escape. This is only required for Rigpa users.

          (use-package symex-rigpa
            :after (symex rigpa symex-evil)
            :straight
            (symex-rigpa
             :host github
             :repo "drym-org/symex.el"
             :files ("symex-rigpa/symex*.el"))
            :config
            (symex-rigpa-mode 1))

If you're wondering which use-package declaration to put your customizations in, please see Where Should I Put My Customizations?.

Instructions for Other Package Managers
=======================================

The sample installation instructions in the previous section use Straight.el and use-package, but if you are using another package manager, the present section provides some guidance on translating the configuration for your needs.

Package.el
----------

Symex is hosted directly at its source repository, so you'll likely need to use the :vc flag in your use-package config (requires Emacs 30+), either by pointing it straight at the upstream repository, or potentially cloning the repo locally first.

The following instructions use the latter approach (warning: untested):

     ;; First, clone the repo to /path/to/symex
     ;; Then:

     (use-package symex
       :vc t
       :load-path ("/path/to/symex/symex-core"
                   "/path/to/symex/symex"
                   "/path/to/symex/symex-ide"      ; if desired
                   "/path/to/symex/symex-evil"     ; if desired
                   "/path/to/symex/symex-rigpa")   ; if desired
       :config
       (symex-mode 1)
       (global-set-key (kbd "s-;") #'symex-mode-interface)
       ;; allow emacs to find the Info manual
       (add-to-list 'Info-directory-list
                    (expand-file-name "/path/to/symex/symex/doc/")))

If you try this and it doesn't work, or if you get it to work and have alternative instructions, please consider contributing them or at least notifying Symex contributors about it so that we can update these instructions for the next person.

If these instructions don't work, and if you're keen on using Package.el (and perhaps you are on an older version of Emacs that doesn't support installing directly from source repositories), then fear not, as you can still install Symex using Quelpa (see Quelpa).

Straight.el
-----------

Please see Installing Symex which uses Straight.el.

Elpaca
------

Elpaca instructions for installing each of the packages described in the previous section are below (please only install the ones you want, as described in see Installing Symex):

     (use-package symex-core
       :ensure (:host github
                 :repo "drym-org/symex.el"
                 :files ("symex-core/symex*.el")))

     (use-package symex
       :after symex-core
       :ensure (:host github
                 :repo "drym-org/symex.el"
                 :files ("symex/symex*.el"
                         "symex/doc/*.texi"
                         "symex/doc/figures"))
       :config
       (symex-mode 1)
       (global-set-key (kbd "s-;") #'symex-mode-interface))  ; or whatever keybinding you like
       ;; and any other customizations you like

     (use-package symex-ide
       :after symex
       :ensure (:host github
                 :repo "drym-org/symex.el"
                 :files ("symex-ide/symex*.el"))
       :config
       (symex-ide-mode 1))

     (use-package symex-evil
       :after (symex evil)
       :ensure (:host github
                 :repo "drym-org/symex.el"
                 :files ("symex-evil/symex*.el"))
       :config
       (symex-evil-mode 1))

     (use-package symex-rigpa
       :ensure (:recipe
                (:host github
                 :repo "drym-org/symex.el"
                 :files ("symex-rigpa/symex*.el")))
       :after (symex rigpa symex-evil)
       :config
       (symex-rigpa-mode 1))

Quelpa
------

Quelpa allows you to maintain a local recipe repository in an ordinary folder on disk that is treated no differently from standard online recipe repositories such as MELPA. Consult the Quelpa docs on how to set this up. The following instructions are not tested (please send feedback if you try them!).

Likely, you could create a local folder on disk to hold recipes, say, /path/to/my/recipes. Add this folder to Quelpa's known recipe stores:

     (add-to-list 'quelpa-melpa-recipe-stores "/path/to/my/recipes")

Then, create files there named symex-core, symex, symex-ide, symex-evil, and symex-rigpa, with no extension, and depending on which packages you want to install. These files should contain something like:

symex-core:

     (symex-core
      :fetcher github
      :repo "drym-org/symex.el"
      :files ("symex-core/symex*.el"))

symex:

     (symex
      :fetcher github
      :repo "drym-org/symex.el"
      :files ("symex/symex*.el" "symex/doc/*.texi" "symex/doc/figures"))

symex-ide:

     (symex-ide
      :fetcher github
      :repo "drym-org/symex.el"
      :files ("symex-ide/symex*.el"))

symex-evil:

     (symex-evil
      :fetcher github
      :repo "drym-org/symex.el"
      :files ("symex-evil/symex*.el"))

symex-rigpa:

     (symex-rigpa
      :fetcher github
      :repo "drym-org/symex.el"
      :files ("symex-rigpa/symex*.el"))

With the package recipes added, you should now be able to install the packages using quelpa-use-package (https://github.com/quelpa/quelpa-use-package):

     (use-package symex-core
       :quelpa t)

     (use-package symex
       :quelpa t
       :after (symex-core)
       :config
       (symex-mode 1)
       (global-set-key (kbd "s-;") #'symex-mode-interface))  ; or whatever keybinding you like
       ;; and any other customizations you like

     (use-package symex-ide
       :quelpa t
       :after (symex)
       :config
       (symex-ide-mode 1))

     (use-package symex-evil
       :quelpa t
       :after (symex evil)
       :config
       (symex-evil-mode 1))

     (use-package symex-rigpa
       :quelpa t
       :after (symex rigpa symex-evil)
       :config
       (symex-rigpa-mode 1))

Elacarte
--------

Elacarte (https://github.com/countvajhula/elacarte) enables you to discover authoritative package recipes without reliance on centralized package archives. These recipes are maintained in a local recipe repository that is maintained as part of your Emacs configuration. In this respect, it is similar to Quelpa. It differs in that Quelpa is tightly coupled with Package.el and specific package archives such as MELPA, whereas Elacarte uses Straight.el and supports any package archive or, especially, even no package archive.

Once Elacarte reaches an initial stable version, it is intended to be the recommended way of installing Symex (in combination with your package manager of choice).

It is currently a proof-of-concept, but you can already use it today if you'd like to be an early adopter (Your feedback would be valuable and appreciated!).

To do this, assuming you already have Elacarte installed (see the instructions in its README):

 1. Run M-x elacarte-discover-recipes-by-url RET https://github.com/drym-org/symex.el RET.

     Or, if you prefer, evaluate this expression using C-x C-e:

          (elacarte-discover-recipes-by-url "https://github.com/drym-org/symex.el")

     This adds package recipes for Symex and its dependencies to your Elacarte cookbook, making it easy to install them.

 2. Declare the packages you want to use in your config, as usual (see Installing Symex for descriptions of the Symex packages). For example:

          (use-package symex
            :config
            (symex-mode 1)
            (global-set-key (kbd "s-;") #'symex-mode-interface))  ; or whatever keybinding you like
            ;; and any other customizations you like

          (use-package symex-ide
            :after (symex)
            :config
            (symex-ide-mode 1))

          (use-package symex-evil
            :after (symex evil)
            :config
            (symex-evil-mode 1))

          (use-package symex-rigpa
            :after (symex rigpa symex-evil)
            :config
            (symex-rigpa-mode 1))

 3. That's it!

Symex and Evil
==============

If you happen to be an Evil user, using Symex should feel familiar (although as we saw in Point-Free Modal Editing, Symex exhibits a simpler modal style, making it accessible to those who aren't familiar with Vim/Evil).

For a seamless integration with Evil, it is essential to install the symex-evil package. See Installing Symex for instructions on that.

This ensures that insertion commands that exit Symex enter Insert state to put you in a position to enter text, as intended, as opposed to leaving you in Normal state. It also supports generic keybindings from Normal state that are useful to retain in Symex mode, such as undo and redo, scrolling, searching, and various other navigations. In addition, it also ensures that such Evil operations performed while in Symex mode preserve a sensible symex selection.

For other useful options on using Symex with Evil, see Escaping to Symex Instead of Normal State and see Easy Entry Into Symex Mode.

Symex and Rigpa
===============

Rigpa (https://github.com/countvajhula/rigpa) is a structured and flexible way to manage modal user interfaces like Symex and Evil. It allows you to visually define transitions between different modes via keybindings like Enter and Escape, making it convenient to use modal UIs (such as Symex and Evil) together. Note that the package, although fairly mature, is not yet available on Emacs package archives, and must be installed directly from the source repository using Straight or Elpaca. In addition to installing Rigpa, you'll also need the symex-evil package mentioned in the previous section (currently, Rigpa does assume that you are an Evil user) as well as symex-rigpa which integrates Symex with Rigpa for smooth operation.

Please see the Rigpa documentation for instructions on installing Rigpa, and see Installing Symex for instructions on installing symex-evil and symex-rigpa.

Languages Supported
===================

Symex natively supports all flavors of Lisp, as well as many other languages via Emacs's built-in Treesitter facility (included in Emacs 29+).

Lisp
----

Symex provides expressive structural editing for any flavor of Lisp. In addition to this core functionality, it also includes convenient integration with popular development environments for some Lisps, via the symex-ide package (see Installing Symex):

Flavor
     Runtime and docs

Racket
     Racket Mode

Emacs Lisp
     Native/IELM

Clojure
     CIDER

Common Lisp
     Slime or Sly. This defaults to Slime, but you can use Sly by putting this in the :custom (not :config) section of your use-package declaration: (symex-common-lisp-backend 'sly)

Scheme
     Geiser

Arc
     Arc.el

Fennel
     fennel-mode.el

Tree-Sitter
-----------

To use Symex with Tree-sitter, just ensure that you're using the Tree-sitter enabled major mode for your language. For example, for Python, you must use `python-ts-mode' rather than `python-mode`.

Of course, this assumes that you already have Tree-sitter set up! If not, and if you'd like to use Symex with a non-Lisp language, you will need to do three things:

 1. Use Emacs 29+

 2. Install a grammar for your language

 3. Install a Tree-sitter-aware major mode for your language

The first is self-explanatory. For the grammar, first find a Tree-sitter grammar for your language and then install it. You can find helpful instructions for this on Mastering Emacs (https://www.masteringemacs.org/article/how-to-get-started-tree-sitter). Finally, for the major mode, Emacs already includes such modes for some popular languages such as Python, but if your favorite language isn't included, you may also find the Tree-sitter major mode for it on standard Emacs package archives like MELPA. These typically have the suffix -ts-mode in their name, for instance, python-ts-mode. Once installed, you will need to enable this major mode in your (e.g., Python) buffer, instead of the usual major mode (e.g., use python-ts-mode instead of python-mode).

And if you've done all that, you should now be able to use Symex with your language!

If you feel that support for your favorite language could be improved, we want to hear from you! Please submit an issue (https://github.com/drym-org/symex.el/issues) and let's discuss your ideas.

Using Symex with Clojure
------------------------

Clojure is a language that is both a Lisp and has a Tree-sitter enabled major mode. In this case, you could use either Symex's Lisp parser or Tree-Sitter parser. But, as the Lisp parser is more mature and provides a tailored experience for Lisp, it's recommended when using Symex with Clojure, at least for the moment, that you use clojure-mode rather than clojure-ts-mode.

Upgrading from Symex v1 to v2
=============================

Formerly, Symex could be installed and used with a single use-package form. Now, the original functionality has been decomposed into smaller, tailored packages. You need one use-package form for each of these packages that you are interested in (see Installing Symex). Some typical cases are covered below.

Which Packages Should I Install?
--------------------------------

If you aren't an Evil user, using symex-core, symex, and symex-ide together provide the same (but improved) experience as before. If you are an Evil user, you would additionally install symex-evil to get the same experience as before. If you are a Rigpa user, install symex-rigpa in addition, for the same experience as before.

Which Parts of My Configuration are Still Valid?
------------------------------------------------

  * Use (symex-mode 1) now, instead of (symex-initialize).

  * You no longer need symex-modal-backend (as Symex uses Lithium now).

  * You don't need any workarounds for Evil interoperation such as for evil-surround (Symex doesn't use Evil in its implementation anymore).

  * If you have any configuration associated with evil-symex-state (e.g., configuring a leader key, or setting the cursor type with (setq evil-symex-state-cursor 'box)), those are still valid, as the symex-evil package does still define a Symex evil state.

  * For any custom keybindings, you may formerly have used symex--user-evil-keyspec or Hydra+. These should now use lithium-define-keys instead, as described in see Custom Keybindings.

See Installing Symex for example config for v2.0+, including the new package recipes you'll need in your config.

Where Should I Put My Customizations?
-------------------------------------

You would typically put customizations in either the :config or :custom sections of the use-package declaration for the symex package, unless it is specific to an optional package like symex-ide or symex-evil, in which case you should include the config with these packages.

You should avoid placing customizations with symex-core (put them with symex, instead) as, if Symex were to be hosted on a package archive, symex-core would not need to be explicitly declared in your config at all, and would be installed behind-the-scenes as a dependency.

What if I'm Directly Using Symex Mode Hooks?
--------------------------------------------

The former symex-mode minor mode had a narrow focus on balancing parentheses in Lisp modes. As Symex now works with any language, this general name for such a specific mode was no longer appropriate, and so it was renamed to symex-lisp-mode. Formerly, setting up the ability to use Symex in any buffer required directly calling symex-initialize in user config. A new, global mode named symex-mode (replacing the former mode of the same name) was introduced in 2.0 to handle this in a standard way simply as (symex-mode 1).

For any buffer-specific configuration for which you might have used symex-mode hooks formerly, you should use symex-editing-mode instead. This is the local mode that is active in a buffer when you actually enter the modal UI. The next section summarizes the purpose of each Symex minor mode.

About Symex Minor Modes
-----------------------

Here's a short summary of the minor modes used by Symex, in case you need to attach any custom behavior to them.

 1. symex-editing-mode --- the local minor mode enabled and disabled upon entry and exit from the modal UI. This is probably the one you need for your customizations.

 2. symex-mode --- a global mode for one-time initial setup to use the Symex modal UI. Most users will need to enable this in their init config.

 3. symex-ide-mode --- a global mode for one-time initial setup to use the IDE features provided by the symex-ide package. If you are using this package, you will need to enable this mode in your init config.

 4. symex-evil-mode --- a global mode for one-time initial setup to use Symex together with Evil via the symex-evil package. If you are using this package, you will need to enable this mode in your init config.

 5. symex-rigpa-mode --- a global mode for one-time initial setup to use Symex together with Rigpa via the symex-rigpa package. If you are using this package, you will need to enable this mode in your init config.

 6. symex-lisp-mode --- a local minor mode for balancing parentheses in Lisp modes. You typically don't need to interact with this as it is done behind the scenes.

 7. symex-core-mode --- a global mode for one-time initialization of core Lisp and Tree-Sitter parsers. You typically don't need to interact with this as it is done behind the scenes.

Getting Started
***************

Let's jump right in and get a feel for Symex. Open a buffer in your favorite language (ideally, a Lisp!), and, if you prefer, make a copy of it first so that you can make changes without worry. If you are viewing this documentation within Emacs, then keep this window open in a split pane (e.g., via C-x 3) alongside your source buffer so that you can follow along while trying things out.

If your source buffer is not a Lisp, ensure that you are in the Tree-sitter enabled major mode for that language, for instance, python-ts-mode.

Moving Around
=============

In your source buffer, enter Symex mode using the keybinding that you configured for symex-mode-interface (see Installing Symex).

Now, try moving around using these commands:

Key   Command   Description

h
symex-move-backward
Move to the previous expression.

j
symex-move-down
Move down the tree to the ``parent'' node. Note that this is oriented with the root being the ``lowest,'' and the most nested expression being the ``highest.'' This orientation is customizable (see Up and Down).

k
symex-move-up
Move up the tree to a ``child'' node. Note that this is oriented with the root being the ``lowest,'' and the most nested expression being the ``highest.'' This orientation is customizable (see Up and Down).

l
symex-move-forward
Move to the next expression.

The first thing you'll notice is Symex's modal nature. If you've used Evil or Vim, then it should feel familiar. But if not, don't worry, as Symex isn't anything as complex as Vim. As you can already see, it uses a simple modal style — a style that we call ``point-free'' editing. This style of interface is designed to be precise and efficient while also being easy to learn and use.

You may notice, as you wander the source tree, that Symex remembers branch positions, so that you can go up and down without losing context.

But you may not always want to navigate using such explicit movements. Sometimes, you just want to traverse trees forwards and backwards to find the right spot.

Key   Command   Description

f
symex-traverse-forward
Traverse forward in the tree.

b
symex-traverse-backward
Traverse backwards in the tree.

Symex offers many such ways to get around. Next, we'll see some ways to transform the source code.

Transforming Code
=================

So far, we've seen a few basic ways to get around in source trees. But once we're where we want to be, we usually want to make changes to the source buffer, whether that's to modify existing code or to insert new code. Let's see how to do that.

Modifying Existing Code
-----------------------

Try these commands to modify code:

Key   Command   Description

x
symex-delete
Delete an expression. This accepts counts, so 3x deletes three expressions.

c
symex-change
Change an expression to whatever you enter. This leaves Symex mode so that you can enter the replacement in the buffer. This accepts counts, so 3c changes three expressions.

y
symex-yank
Copy the expression to the kill ring. This accepts counts, so 3y copies three expressions.

p
symex-paste-after
Paste from the kill ring, after the current expression. This accepts counts, so 3p pastes three times.

P
symex-paste-before
Paste from the kill ring, before the current expression. This accepts counts, so 3p pastes three times.

<tab>
symex-tidy
Tidies and indents the expression. This accepts counts, so 3<tab> indents three expressions.

Next, we'll see a few simple ways to enter new code into the buffer in a context-sensitive way.

Inserting New Code
------------------

There are a few different ways to insert new code, and they are all expressed in relation to the current expression.

Key   Command   Description

i
symex-insert-at-beginning
Insert at the start of the expression. If it is a form, then insert inside the form.

a
symex-append-at-end
Insert at the end of the expression. If it is a form, then insert inside the form.

I
symex-insert-before
Insert before the expression. If it is a form, then insert outside the form.

A
symex-insert-after
Insert after the expression. If it is a form, then insert outside the form.

Learning More
=============

The commands we've seen so far are only a small sampling of the available operations.

As you become more familiar with Symex, it will be useful to refer to the Keybinding Cheat Sheet to discover more capabilities, and also the Resources for further study. For tips and tricks, see Squirrel on a Speedrun - Tips and Tricks.

Feel free to dive into any of those, but if you'd like to understand things at a high level first, the next section gives an idea of the kinds of features and what they enable you to do.

Features
********

Symex allows you to edit and interact with code structurally using a modal UI. The Animated Guide (https://countvajhula.com/2021/09/25/the-animated-guide-to-symex/) is a good way to see many of these features in operation, but this chapter provides an overview and an idea of the kinds of features, and why they exist.

When you're using Symex, because these operations are so convenient and intuitive, you'll find that you use a lot of them, all the time. It's just like speaking a language. We don't typically count the distinct words we use in speech, but if we did, we'd find that we routinely use a lot of them, without breaking a sweat! Symex is a language, too.

Point-Free Modal Editing
========================

Symex exhibits a ``point-free'' modal experience (The term is borrowed from functional programming, where it refers to being able to code in a very succinct way in cases where the data can be implicit. With Symex, the ``implicit data'' is the expression indicated by the cursor.) allowing the expression of a rich array of commands with few keystrokes.

The archetypical modal editing tool is, of course, Vim. As Vim addresses the general task of editing text, its interface is necessarily complex and subtle, requiring years to master. Although Symex draws inspiration from Vim, it exhibits a different, simpler, modal style that is specialized to the comparatively narrow task of editing code.

Specifically, Vim's (and Evil's) interface exhibits a compositional style, where verbs (operators like ``delete'') are combined with nouns (motions or text objects, e.g., relating to words or paragraphs) to form commands. In Symex, all motions and operators are implicitly in relation to the currently selected expression, so that we only ever need to express a verb (like delete), and no composition is needed. The interface does still support narrower forms of composition, for instance in accepting counts for most commands via a numeric prefix argument.

The modal interface is implemented using a dedicated, lightweight, modal interface library called Lithium (https://github.com/countvajhula/lithium).

The next few sections describe the specific faculties made accessible via this modal UI.

Getting Around
==============

Typical cursor movements in Emacs navigate the two-dimensional plane of buffer rows and columns, so that left, right, up and down mean moving by column and by row, respectively. This is a very general way of moving around that you can use for any kind of text, including code.

Symex motions are more specialized and navigate the two-dimensional tree structure of your code, so that left and right (h and l) move to adjacent expressions, and up and down (k and j) move across nesting depth. When you're working with code, this is more precise, and often, therefore, more efficient and more scalable.

In addition to these basic motions, Symex also provides many other ways to get around that are intuitive for trees but which don't have analogues for unstructured, coordinate-based buffer navigation. For instance, ``traversing'' forwards and backwards (f and b) visits every expression at every depth, precisely and in a predictable order, while ``skipping,'' ``climbing,'' and ``descending'' offer ways to get around faster in specific directions when you know where you're trying to go. Finally, you can also ``leap'' to nearby branches at the same height as your current position without explicitly navigating to them. This is very common as code frequently has repeating shapes and patterns --- patterns which you may wish to exploit to get around quickly or even for automating repetitive tasks via macros.

See Movement for the full list of movement commands and keybindings.

Having rich faculties for getting around is just one aspect of Symex. Another is that it enables convenient and expressive structural editing, as the next section describes.

Editing Features
================

Symex provides structural features for manipulating code, metacommands to reflect on and repeat actions from your own command history, as well as rich macros for automating repetitive tasks. The following sections describe these features.

For the full list of editing commands and keybindings, see Editing.

Structural features
-------------------

Symex allows you to delete expressions (e.g., x), change them to something else (e.g., c), move them around (e.g., H and L), translate them lower or higher in the tree, detach them from one branch and attach them to another, and so on.

These operations are all strict about structure, so, for instance, you cannot accidentally shift an expression out to a lower or higher level if you are using a lateral shift operator like symex-shift-backward (H) or symex-shift-forward (L).

The strictness of these operations allows you to be precise about code transformations. This is useful not just at the time of performing the action, but pays compounding dividends when you consider that macros and repetition can formally repeat these actions in new contexts, as the next section elaborates.

Macros and Repetition
---------------------

Symex includes an advanced command repetition feature, accessible via .. This simply replays your most recent command. This command could even include insertion of text into the buffer, and even the use of completion frameworks during such insertion. . will repeat the command, in all cases.

This feature is similar to Vim's well-known ``dot'' command, but in addition, it also maintains a history of recent commands on a ``repeat ring,'' so after pressing ., you can cycle through recent repetitions using C-.. This ability to repeat recent commands is similar to Evil's implementation of ``dot'' which includes the analogous ``repeat-pop'' feature.

Symex's repeat feature uses the standalone repeat-ring (https://github.com/countvajhula/repeat-ring) package and the mantra (https://github.com/countvajhula/mantra) parsing library. These packages were developed to support Symex, but they enable any package to develop and provide very general and highly customizable repeat functionality.

See Macros for ways to record and repeat longer sequences of commands.

IDE Features
============

Symex provides, via the optional symex-ide extension (see Installing Symex), a handful of ways to conveniently leverage major mode features for languages, via short keybindings.

For instance, for some languages (especially Lisp languages), e evaluates the selected expression in a REPL, ? looks up documentation on the selected expression (identifier), and r enters a REPL.

These easy integrations with important coding facilities can help you get quick feedback during development. As generations of Lisp users attest, such tight feedback loops are the engines of quick progress on any task.

See IDE for the full list of IDE commands and keybindings.

Customizing Symex
*****************

You can customize most any aspect of Symex to tailor it to your preferences and to operate harmoniously with other packages that you might be using.

Most of the customizations below go in the :custom section of your use-package declaration, unless otherwise specified.

Up and Down
===========

The default keybindings in Symex mode treat increasingly nested code as being ``lower,'' and elements closer to the root as ``higher.'' This may be familiar from the sense of ``tree'' in computer science, which is ``inverted'' from the orientation of actual trees growing outside. You can, if you like, flip this to correspond to the latter, which was formerly the default orientation of Symex. The latter orientation would mean thinking as a squirrel would — going ``up'' to the nest and ``down'' to the root. Choose whatever you may find most natural by putting the following in the :custom section of your use-package declaration:

     (symex-orientation 'squirrel)  ; either 'squirrel or 'inverted (the default)

Branch Memory
=============

When going up and down, the choice of initial position on the branch is arbitrary. By default, the first position is picked initially, and then Symex the squirrel remembers where it was on each branch after that, so that you return to your last position when going up and down the tree. If you'd like to move to the first or last position at any point, you could use (for instance) M-h or M-l at each level, as usual, or traverse the tree using f and b, instead.

If, on the other hand, you'd like to start always at the first position when going up (as it was in older versions of Symex), disable the branch memory feature by adding this to the :custom section (not the :config section) of youruse-package form:

     (symex-remember-branch-position-p nil)

Highlighting
============

The current expression is highlighted by default using an overlay. If you'd like to disable highlighting, add this to the :custom section (not the :config section) of your use-package form:

     (symex-highlight-p nil)

You can also customize the face used for this by configuring the symex-highlight-face. This can be done using the Customize interface (accessible by M-x customize; see Easy Customization (the GNU Emacs manual) also see Face Customization (the GNU Emacs manual)).

Alternatively you can use Elisp to set the face programmatically. Using set-face-attribute will allow you to change any attribute of the face. For example, this sets Symex's highlight face to inherit from the italic and region faces and to extend the face all the way to the edge of the window when selecting over multiple lines.

     (set-face-attribute 'symex-highlight-face nil :extend t :inherit '(italic region))

Warning: set-face-attribute will only set the attributes you tell it to. It does not clear attributes that are already set. This means that if you play around with it, you can end up with something that looks different from what you would get running the latest thing from a clean slate. This won't be a problem once your configuration is ready and Emacs is just running it when it starts up, but keep it in mind as you try things out.

You can also eval a defface form to set the entire face specification, though that can interfere with documentation or groups is anything has changed.

     (defface symex-highlight-face
       '((nil :extend nil :inherit (italic region)))
       "Face used to highlight the current ."
       :group 'symex-faces)

Some quick tips: You can use the describe-face command to see lots of different faces and then :inherit from one(s) you like. If you choose a standard face like region, highlight, or underline it will use the face definition from your theme. Finally, if you want to still see code highlighting, make sure that your face does not set the foreground color as that will cause the overlay override the foreground property set by the highlighter.

Here are some basic options that you could try:

Underline: It is very compatible across different themes. If you want something that is guaranteed to be readable and not interfere with highlighting this is a good choice.

     (set-face-attribute 'symex-highlight-face nil :extend nil :underline t :inherit '(underline))

Italic + Region: Uses the normal region face (the one used when you mark/select a region of text) but with italics to visually set it apart from the former use. It is readable and works with syntax highlighting in many themes and is the default.

     (set-face-attribute 'symex-highlight-face nil :extend nil :inherit '(italic region))

Highlight: The legacy default. In many themes it is a bolder color (sometimes to the extent that it becomes hard to read). It also sets the foreground in some themes; thus, breaking syntax highlighting.

     (set-face-attribute 'symex-highlight-face nil :extend nil :inherit '(highlight))

Also see Look and Feel for other ways to customize the UI.

Point Placement on Entry
========================

Upon entry into Symex mode, point is positioned at the start of the currently selected symex. If you'd like to preserve point at its original location, instead, so that entry into Symex mode is ``idempotent,'' then add this to the :custom section (not the :config section) of your use-package form:

     (symex-preserve-point-on-entry-p t)

Auto-Indenting
==============

Symex reindents expressions after each transformation (i.e., which mutates the buffer), for which purpose it uses standard Emacs utilities such as indent-region, which ultimately derive their sense of proper indentation from the major mode. If you'd like to customize indentation, you should explore the facilities the major mode offers for this purpose (as Symex does not itself define this). On the other hand, if you'd like to use your own indenting framework or another package such as Parinfer for this purpose, you could disable Symex's automatic indentation.

     (symex-tidy-after-transforming-p nil)

Balancing Parentheses
=====================

Lisp
----

While editing Lisp, Symex relies on the code having valid structure. If that structure is ever broken, i.e., if parentheses become unbalanced, things may behave unexpectedly as Symex can no longer reliably reason about the code.

In order to ensure this structural integrity, Symex implicitly balances parentheses during any edits you make, using the well-known Paredit library for this purpose. But if you prefer to use another strategy for keeping parentheses balanced, such as Smartparens or Parinfer or even Paredit itself, you may prefer to disable this built-in parenthesis balancing behavior. Use this to do that:

     (symex-ensure-structure-p nil)

Non-Lisp (Tree-sitter) Languages
--------------------------------

For non-Lisp (Tree-sitter) languages like Python, Symex does not do any parenthesis balancing. If you'd like to have this feature, we recommend using a package like Smartparens for this purpose alongside Symex, and there would be no conflict with Symex.

Quoting Styles
==============

Symex provides convenient ways to add common prefixes and also remove them from any expression. This is useful especially when editing Lisp code for managing syntax quoting, e.g., turning (a b c) into '(a b c) — a standard thing one might do in Lisp — without needing to exit Symex mode.

You could configure any prefixes here that you may find yourself using often, and they don't have to have anything to do with quoting, or even with Lisp.

By default, C-' and C-, cycle through standard quoting and unquoting prefixes (', ` and ,, ,@, respectively) recognizable to all Lisps. But some Lisps, such as Racket, provide additional quoting styles that you may want to add here. To add custom prefixes, add something like this to the :custom section (not the :config section) of your use-package form:

     (symex-quote-prefix-list (list "'" "`" "#'" "#`"))
     (symex-unquote-prefix-list (list "," ",@" "#,@"))

Look and Feel
=============

The section on Highlighting covers customizing the face used in highlighting the current expression. There may be many other things you'd like to customize about Symex which aren't included as customizations, such as how the cursor looks or how the mode line looks. These may be specific to your own Emacs configuration or just to your unique preferences. Symex provides lifecycle hooks that allow you to customize it any way you like:

  * symex-editing-mode-pre-entry-hook — Called right before entering Symex mode.

  * symex-editing-mode-post-entry-hook — Called right after entering Symex mode.

  * symex-editing-mode-pre-exit-hook — Called right before exiting Symex mode.

  * symex-editing-mode-post-exit-hook — Called right after exiting Symex mode.

For example, since Symex already includes a customizable overlay to highlight selected expressions, you may prefer to disable the regular Emacs cursor upon entry to Symex mode, and re-enable it upon exit. To do this, add this somewhere in your Emacs config for Symex:

     (defun my-enable-cursor ()
       "Enable the cursor."
       (internal-show-cursor nil t))

     (defun my-disable-cursor ()
       "Disable the cursor."
       (internal-show-cursor nil nil))

     (add-hook 'symex-editing-mode-post-entry-hook
               #'my-disable-cursor)
     (add-hook 'symex-editing-mode-post-exit-hook
               #'my-enable-cursor)

Custom Keybindings
==================

Symex uses Lithium (https://github.com/countvajhula/lithium) to implement its modal UI. You may add any custom keybindings, or customize any existing keybinding, by using the underlying Lithium facilities for this purpose (please see the Lithium documentation). For instance, to bind a key to visit an anonymous ``scratch'' buffer for the current major mode using the Mindstream (https://github.com/countvajhula/mindstream) package, you could do the following:

       (lithium-define-keys symex-editing-mode
         (("t" mindstream-enter-anonymous-session)))

PLEASE NOTE: if you use custom keybindings, it is essential to preserve the intended ``exiting'' behavior of the commands. For instance, all insertion commands in Symex are designated with :exit in the keybinding specification, which ensures that it exits the Lithium mode to allow you to enter text. If you choose to override these, remember to retain the :exit flag (described further in the Lithium documentation).

Also see Point-Free Modal Editing for more on the modal UI and Lithium.

Squirrel on a Speedrun - Tips and Tricks
****************************************

Now that we've learned the basics, let's learn some ways to be even more precise and efficient.

Escaping to Symex Instead of Normal State
=========================================

For Evil users, when you ``escape'' from Insert state, you may prefer to enter Symex state rather than Normal state while in Lisp buffers.

Please see Symex and Rigpa for the recommended way of achieving this.

If you're not using Rigpa, you could still write one-off keybindings to achieve this, as described in see Easy Entry Into Symex Mode.

Macros
======

Ordinary keyboard macros are already very useful, allowing you to carefully construct repeatable actions to automate batch tasks. But with Symex, they become much more powerful, since the keystrokes recorded by the macros represent not elementary cursor movements and manual edits, but complex traversals and rich structural operations.

When you define macros in symex mode (e.g., via C-x (, or via q for Evil users), make sure that the commands you use are those that have the same effect in every situation. For instance, the ``up'' and ``down'' motions (default: k and j) could vary based on ``branch memory'' — up may sometimes move you to the first position on the higher level, but at other times it may move you to the third position, if that happens to be your most recent position. Using up and down in your macro would mean that it could have different results in each tree depending on your activities in the tree, unless you remember to reset the frame of reference by using something like 0 or $. Instead, it may be more natural to use the ``flow'' traversal commands (default: f and b), repeating them or prefixing them with count arguments if necessary, to move around in a fully deterministic way. This will ensure that your macros behave the same way in every case.

Mode Line Enhancements
======================

The vanilla mode line in Emacs does show some textual indication of your current evil state, e.g. <N> for Normal state, and <λ> for Symex state, and this kind of visual feedback is helpful, yet also subtle. If you'd like more pronounced visual feedback, you might try extensions such as powerline (https://github.com/milkypostman/powerline) or telephone-line (https://github.com/dbordak/telephone-line), which provide customizable color coded indicators for each evil state in the mode line. For example, for telephone-line, you could use the following config in the config section of the use-package declaration for telephone-line:

     (defface telephone-line-evil-symex
       '((t (:background "SlateBlue3" :inherit telephone-line-evil)))
       "Face used in evil color-coded segments when in Symex state."
       :group 'telephone-line-evil)

Easy Entry Into Symex Mode
==========================

Here are a few user-contributed recipes for easy entry into Symex mode. Currently, these recipes are relevant specifically for Evil users, but they may suggest approaches for users of other modal systems or vanilla Emacs. If you have a recipe to contribute for another such UI, please get in touch.

 1. For Evil users, user @doyougnu suggests binding your local leader to , (instead of the default, \), which frees up \ to be used as entry into Symex Mode. This is convenient as \ feels like another Esc but dedicated to Symex mode instead of Normal state. The drawback is that , is an otherwise useful key in Normal state (for in-line repeat search backwards). Although, using it for the local leader is a widely used pattern by Vim and Evil users, and if you are one of them, then this might be a good option for you.

     With this option, entering Symex from Normal state is convenient, but you'd still need to visit Normal state on your way to Symex mode from Insert state.

 2. This recipe to alternate Symex and Normal (https://github.com/drym-org/symex.el/issues/24#issuecomment-815110143) by @tommy-mor provides another option, making it convenient to alternate between Symex and Normal modes, starting in Symex mode when leaving Insert state.

 3. This recipe to additionally remember the most recent editing mode (https://github.com/drym-org/symex.el/issues/164#issuecomment-3431456812) by @jmckernon builds upon the previous recipe to also keep track of the most recent mode from which Insert state is entered.

See Escaping to Symex Instead of Normal State for a formal way to structure modes.

Making Parentheses Convenient
=============================

In writing Lisp code, parentheses are among the most commonly typed characters, and yet, these require us to leave home position dramatically to type! I recommend a keybinding resembling the following to make it more efficient. Of course this applies only in Insert state (for Evil users) or in vanilla Emacs state, as you can insert and modulate delimiters in other ways while in Symex state:

     (define-key
       symex-lisp-mode-map
       (kbd "C-w")
       (lambda ()
         (interactive)
         (execute-kbd-macro (kbd "("))))

You could think of ``w'' as ``wrap'' in this context, as in, ``to wrap with parentheses,'' and it matches a similar binding in symex state (i.e. w to wrap an expression and enter insert state). For the closing parenthesis, you could just use Emacs's C-f to move forward a character — since symex (via paredit) ensures that parentheses are balanced, you rarely need to actually type a closing delimiter. The binding C-w would be fine for Evil users, but vanilla Emacs users may need to find something else here. Of course it goes without saying that the Control key should be conveniently accessible without having to leave home position. I have Control under my right thumb, and Escape in place of Caps Lock.

The Symex DSL
*************

The Symex DSL powers many of Symex's features, and you can use it, too.

The DSL allows you to specify any tree traversal in a cursor-oriented manner. That is, instead of describing traversals from an absolute reference point such as a root node, it allows you to describe traversals from the first-person vantage point of the cursor — what would you do if you were where this cursor is right now? It allows you to describe what you'd like to do in intuitive terms that make sense for movement in a tree. Symex is the language a squirrel might use to describe their exploits to another squirrel.

Let's now take a journey inside the mind of the squirrel.

Usage
=====

The main entry point to Symex from ELisp is the symex-traversal form, which can also be used via the definition form, symex-deftraversal. These forms allow you to define traversals (e.g., movements or transformations of code) using the Symex language, and they are analogous to lambda and defun (for defining functions in ELisp), respectively. Traversals defined this way may be evaluated using symex-eval and would execute in relation to the selected expression. Symex considers point (i.e., the cursor) to indicate the start of the selected expression.

Here is what performing a very basic traversal looks like. You could try it, if you like, by placing point at the start of any symex, and then evaluating this code using M-:.

     (symex-eval
       (symex-traversal
         (do (move up)
             (move forward))))

We'll soon learn more about what this code means.

Language
========

The Symex DSL allows you to specify traversals. A traversal may be a movement from one part of the tree to another, or it may be an action to take at a particular point in a tree such as ``taking'' (deleting) an expression or ``dropping'' (pasting) something, ``carefully'' checking conditions, or even performing an arbitrary ``effect.''

Symex gives you several linguistic forms with which to describe such traversals in precise ways.

Each form of the language has its own syntax, and typically the clauses of these forms are expected to be traversals themselves. For instance, the maneuver form specifies a traversal as a sequence of other traversals to be executed in order.

Typically, if a traversal succeeds, it returns a list of executed moves which if replayed manually from the starting position would have the same effect as running the traversal did. If the traversal fails, it returns nil.

move
----

Syntax
------

(move forward|backward|up|down)

Description
-----------

The most basic movement, a move simply takes a single step in a particular direction, to a neighboring node in the tree.

Examples
--------

"Move forward."

     (symex-eval
       (symex-traversal
         (move forward)))

"Move backward."

     (symex-eval
       (symex-traversal
         (move backward)))

"Move up."

     (symex-eval
       (symex-traversal
         (move up)))

"Move down."

     (symex-eval
       (symex-traversal
         (move down)))

Note that in the Symex language, "up" and "down" are defined in relation to the root node being considered the bottom of the tree and increasingly nested expressions as being higher. We "go down towards the root and up towards the nest."

The variable symex--move-zero can be used in traversals to indicate an intentional absence of motion, and would be treated as a successful move.

maneuver
--------

Syntax
------

(maneuver traversal ...)

or

(do traversal ...)

Description
-----------

Execute a sequence of traversals in order. The maneuver succeeds if all of the traversals succeed. If any of them fail, then the entire maneuver is aborted and nothing happens. In other words, the maneuver has "all or nothing" semantics. To accept partial completion, use venture instead.

Examples
--------

"Go forward, then up, and then forward again."

     (symex-eval
       (symex-traversal
         (do (move forward)
             (move up)
             (move forward))))

"Go up and then keep going forward, and then go up again."

     (symex-eval
       (symex-traversal
         (do (move up)
             (repeat (move forward))
             (move up))))

venture
-------

Syntax
------

(venture traversal ...)

or

(try traversal ...)

Description
-----------

Execute a sequence of traversals in order. If the venture is partially completed, i.e. if at least one traversal was executed, then the venture is treated as successful. Otherwise it is considered to have failed.

Examples
--------

"Venture to go forward, then up, and then forward again."

     (symex-eval
       (symex-traversal
         (try (move forward)
              (move up)
              (move forward))))

"Go up and then all the way forward, and then try going up again."

     (symex-eval
       (symex-traversal
         (try (do (move up)
                  (repeat (move forward)))
              (move up))))

protocol
--------

Syntax
------

(protocol traversal ...)

or

(any traversal ...)

Description
-----------

Try executing traversals, in order, until one succeeds (and then stop).

Examples
--------

"Try going forward, if that doesn't work try going backward."

     (symex-eval
       (symex-traversal
         (any (move forward)
              (move backward))))

"Try going forward and up, if that doesn't work try going backward and down."

     (symex-eval
       (symex-traversal
         (any (do (move forward)
                  (move up))
              (do (move backward)
                  (move down)))))

detour
------

Syntax
------

(detour reorientation-traversal main-traversal)

Description
-----------

Try executing a traversal by first reorienting yourself. If the main traversal fails, reorient yourself ("take a detour") and then try again. Keep repeating this until either the main traversal succeeds, or the reorientation fails. Both the main traversal as well as the reorientation can be any traversal.

Note that the reorientation is always executed prior to trying the main traversal, even the first time.

Examples
--------

"Attempt to go forward by first going down, and keep going down to try again."

     (symex-eval
       (symex-traversal
         (detour (move down)
                 (move forward))))

"Attempt to go forward by first going down, and keep going down to try again as long as we don't descend to the root of the tree."

     (symex-eval
       (symex-traversal
         (detour (carefully (move down)
                            (afterwards (not (at root))))
                 (move forward))))

decision
--------

Syntax
------

(decision condition traversal-A traversal-B)

or

(if condition traversal-A traversal-B)

Description
-----------

Do either traversal A or traversal B, depending on whether a condition holds.

The condition can be any predicate — either a built-in predicate form, or an arbitrary traversal, including a lambda. See Predicates for details.

Examples
--------

"If we're at the root of the tree, then go forward, otherwise go down."

     (symex-eval
       (symex-traversal
         (if (at root)
             (move forward)
             (move down))))

"If we are somewhere before a previously stored position in the buffer, then go forward, otherwise don't move."

     (symex-eval
      (symex-traversal
        (if (lambda (_computation _result)
              (< (point) previously-stored-position))
            (move forward)
            symex--move-zero)))

We'll ignore the arguments of the lambda here, for now, and will soon see what they're for. symex--move-zero is just a convenient traversal for cases where you need to indicate a traversal but would like to not move at all. It is defined as (symex-make-move 0 0).

circuit
-------

Syntax
------

(circuit traversal [times])

or

(repeat traversal [times])

Description
-----------

Repeat a traversal a given number of times or as long as it succeeds. When it fails, stop.

Examples
--------

"Move forward three times."

     (symex-eval
       (symex-traversal
         (repeat (move forward) 3)))

"Keep moving forward."

     (symex-eval
       (symex-traversal
         (repeat (move forward))))

"Keep moving down and forward, as long as we don't descend to the root node."

     (symex-eval
       (symex-traversal
         (repeat
           (carefully
             (try (move down)
                  (move forward))
             (afterwards (not (at root)))))))

loop
----

Syntax
------

(loop traversal condition)

Description
-----------

Repeat a traversal until a condition is met. If the traversal fails without the condition being met, the traversal is considered to have failed and no move is made.

The condition can be any predicate — either a built-in predicate form, or an arbitrary traversal, including a lambda. See Predicates for details.

This is fairly similar to circuit, but is more natural in some cases where using conditions via precautions may be awkward.

Examples
--------

"Move down until we reach the root."

     (symex-eval
       (symex-traversal
         (loop (move down) (at root))))

precaution
----------

Syntax
------

(precaution traversal [(beforehand condition)|(afterwards condition)])

or

(carefully traversal [(beforehand condition)|(afterwards condition)])

Description
-----------

Execute a traversal, but ensure that certain conditions hold either before or after executing the traversal (or both). If a condition does not hold, then abort the traversal, considering it to have failed.

Each of the conditions can be any predicate — either a built-in predicate form, or an arbitrary traversal, including a lambda. See Predicates for details.

Note that, as the predicates could be lambdas, you could also perform effects resembling effect (say, setting an ELisp variable) using precaution, either before or after the traversal. If you'd like to do this, just remember that the effect function you use, as a predicate, must return a truthy value. And further, as a traversal, it must accept the two standard arguments to traversals (see Lambdas).

Examples
--------

"Go down but don't descend to the root node."

     (symex-eval
       (symex-traversal
         (carefully (move down)
                    (afterwards (not (at root))))))

"Go backward as long as we aren't at the first node at this level."

     (symex-eval
       (symex-traversal
         (carefully (move backward)
                    (beforehand (not (at first))))))

Note that this executes a *single* traversal while taking precautions. It is not repeated unless wrapped in a circuit or employed as a detour.

delete
------

Syntax
------

(delete [this|previous|next])

or

(take [this|previous|next])

Description
-----------

Delete the indicated expression. Prefer previous and next as those are deterministic in the placement of point after the transformation, i.e., they don't need to move point.

Examples
--------

"Swap current and previous expression."

     (symex-eval
       (symex-traversal
         (do (take previous)
             (drop after))))

paste
-----

Syntax
------

(paste [before|after])

or

(drop [before|after])

Description
-----------

Paste the ``current kill'' either before or after the current expression.

Examples
--------

"Emit forward."

     (symex-eval
       (symex-traversal
         (do (move up)
             (repeat (move forward))
             (take this)
             (move down)
             (drop after))))

effect
------

Syntax
------

(effect effect-fn [main-traversal])

Description
-----------

Execute the main traversal (if present) and then, if it succeeds, call the ``effect'' lambda, ignoring its output. The effect could be anything, allowing us to attach arbitrary semantics to traversals.

Note that you could also perform such effects using precaution, either before or after the traversal, which makes that approach more flexible. Yet, that approach requires the lambdas used to fulfill the traversal interface in terms of arguments and return values (see Lambdas), so it's a little more to think about. Performing an effect along with a traversal without consideration for return values or input arguments is such a common case, and that's why effect is provided as a convenience.

Typically, we are interested in attaching such effects to a repeated traversal so that the effect is performed at each step of the traversal as long as it succeeds.

Examples
--------

"Print each expression until the end."

     (symex-eval
      (symex-traversal
        (repeat
          (effect (lambda ()
                    (print (thing-at-point 'sexp)))
                  (move forward)))))

Note, again, that the lambda used in an effect accepts no arguments, and its return value is disregarded.

Lambdas
-------

Finally, a traversal can also be any ELisp function, including a lambda defined inline.

Such a lambda would be called with two arguments — the same two used by any traversal — a specification of the computation to be performed, and the in-progress accumulated result. It is expected to synthesize its result with the accumulated result to return a valid traversal result in the context of the containing computation.

In practice, using a lambda as a traversal will never be done, except when defining conditions for use in conditional traversals like decision or precaution. In such cases, use of a lambda is common. Here, as the result of the traversal is only conditioned upon and isn't integrated into the containing traversal, the only thing relevant to the execution of the traversal is that the lambda return a truthy value on whatever it considers to be ``success,'' and nil, otherwise. It must, however, still accept the two standard arguments, even if it doesn't use them.

If you find yourself writing a lambda for any other purpose than as a condition, it would be advisable to discern whether your need for this lambda suggests the addition of a new form to the DSL that would make your lambda unnecessary, so please consider contributing an issue (https://github.com/drym-org/symex.el/issues) describing your use case.

Examples
--------

"If we are somewhere before a previously stored position in the buffer, then go forward, otherwise don't move."

     (symex-eval
      (symex-traversal
        (if (lambda (_computation _result)
              (< (point) previously-stored-position))
            (move forward)
            symex--move-zero)))

Predicates
----------

Symex offers a few standard predicates to use as conditions in traversals like decision, precaution, and loop, usable via a convenient syntax.

  * (at root) — Are we (i.e. is the cursor) at the root node? Any toplevel form in the source file is considered to be a root node.

  * (at first) — Are we at the first node at the present level / on the current branch of the tree?

  * (at last) — Are we at the last node at the present level / on the current branch of the tree?

  * (at initial) — Are we at the first root-level node in the entire file?

  * (at final) — Are we at the last root-level node in the entire file?

In addition to supporting the above syntax, the conditions in traversals like decision, precaution, and loop, are simply traversals themselves, so you may use any traversal as a predicate, including, in particular, any lambda (see Lambdas).

Composing Predicates
--------------------

The modifier not can be used to negate any of the above predicates (or the result of arbitrary lambdas). E.g. (not (at root)) returns true if cursor is not at the root node of the tree.

and and or form the conjunction and disjunction of predicates (including lambdas), e.g., (and (not (at root)) (not (at first))).

Evaluation Model
================

Typically, when executing traversals, we only need to know whether a traversal succeeded or failed. For this purpose, it's sufficient to check whether the traversal evaluates to a non-nil result in order to infer success.

But there are cases when you may need to modulate the computation being performed as part of the traversal. For instance, the ``leap'' feature in Symex computes a delta of each position in relation to the initial position, as it traverses, and stops traversing when the delta reaches 0 in both x (horizontal position along branch) and y (height from root) directions.

The remainder of this section explains how computations work, so that you can write similar traversals that may need to perform custom computations.

Symex executes traversals while evaluating an associated ``fold''-like computation. By default, that computation simply assembles a sequence of the moves made during traversal evaluation, producing this full list as the result.

The computation is specified in terms of a ``perceiving'' operation that represents the underlying move (every traversal is ultimately composed of elementary moves) in a way that is relevant for the computation, and a ``synthesizing'' operation that combines the accumulated result with the new perceived input.

Traversals may be evaluated with arbitrary computations that are specified in this way. The in-progress result is always available to traversals as an argument, so that they may condition on this in-progress result (as ``leap'' does, stopping when a condition on the result is met).

For example, the following computation simply counts the number of moves made during traversal evaluation:

     (defvar my-symex-compute-moves
             (symex-make-computation :perceive (lambda (_x) 1)
                                     :synthesize #'+)

It may be used as follows:

     (symex-eval (symex-traversal
                   (circuit (move forward)))
                 my-symex-compute-moves)

This counts the number of moves made in traversing forward to the end of the containing expression.

Note that traversals sometimes return ``zero'' moves, that is, (move 0 0), to indicate an intentional absence of movement, as opposed to nil which indicates a failed traversal, so this computed result may return more moves than the actual number of steps taken. It is just an example of a simple computation, though, perhaps, not a very useful one.

Expressive Power
================

As the Symex DSL includes loops, conditionals, and more, theoretically, it is more expressive than regular expressions, and at least as expressive as a "pushdown" automaton (i.e., state machine with stack-based memory). With its ability to interpolate ELisp in traversals, it could perhaps be considered Turing Complete, or could be made so if there is a need for a feature that cannot easily be implemented in the DSL in its current form (please submit an issue describing your desired feature!).

Full DSL Code Example
=====================

Because the DSL expresses traversals in a natural way in relation to the cursor, it often allows the implementation of tree algorithms to be simple enough that, even as a casual user, you might consider extending Symex to support features you might need. As an illustration, imagine that you are editing some Lisp code. You often find that you need to transform something like this:

     (a (b (c (d e))))

… to this:

     (a
      (b
       (c
        (d
         e))))

To perform the above transformation, intuitively, you might say, ``go up into the expression, then go forward, then add a newline there, and then keep repeating the same thing until we reach the end.'' Indeed, using the Symex modal UI, you can manually implement this, for this particular example, as kl>kl>kl>kl>.

But you'd like a general command to do this that works in every case, no matter how deep or shallow the expression may be.

You could write a Symex command to do that, using the linguistic forms we learned about.

     (symex-define-command my-cascade ()
       (interactive)
       (symex-eval
        (symex-traversal
          (repeat
           (try (move up)
                (move forward)
                (lambda (_computation _result)
                  (newline-and-indent 1)))))))

The important part is within symex-traversal, and if you squint just a bit, you'll see that it's exactly the intuitive algorithm we came up with just now! repeat, as the name implies, repeats the contained traversal until it fails. try attempts a sequence of traversals in order, stopping when anything doesn't work. A move is a single step in any direction. And you can provide any ELisp code (in this case, to add a newline with proper indentation) by entering a lambda (see Lambdas for more on the unused arguments here). Now just compare that with our intuitive algorithm, reproduced here:

``go up into the expression, then go forward, then add a newline there, and then keep repeating the same thing until we reach the end.''

For the logistical aspects of this implementation, recall that you define a Symex program using symex-traversal and evaluate it using symex-eval. Symex commands often need to do some standard things like fix indentation after execution, or set some metadata that may help Emacs treat your command as you expect. Using symex-define-command instead of defun takes care of these things for you, but it's not required. Finally, interactive is Emacs's standard way of making the command executable by you via M-x.

Debugging
=========

There are many strategies for gaining visibility into, and debugging, Symex traversals. Some of these strategies are standard and applicable to ELisp as well, while others are specific to Symex.

Directly Evaluating Expressions
-------------------------------

You can always run traversals in a source buffer by using M-: to evaluate an ELisp expression. This can be a cumbersome way to try things out, however.

Using a REPL
------------

Another strategy is to open a REPL in an adjacent window and run code in the REPL while having it take effect in the source buffer alongside.

To do this, open an IELM buffer in a window next to a source buffer, and use this snippet in the REPL:

     (with-current-buffer (window-buffer (other-window 1))
       (symex-eval
        (symex-traversal
         (maneuver (move forward)
                   (move up))))
       (other-window 1))

Here, you can substitute the contents of (symex-traversal ...) with whatever traversal you like.

Using a Debugger (EDebug)
-------------------------

Another way is to use the ELisp Debugger, EDebug. This allows you to see the exact steps the DSL evaluator goes through in executing a traversal and the effects it has on the code, and can be helpful if you want to understand why a traversal isn't doing what you think it should be doing, or even if you just want to understand how the DSL works! A good debugger isn't just for debugging problems, it's also an exploratory tool for quick feedback at the creative stage when you're implementing new functionality. It can help you be more efficient at every stage of development.

To use it, first evaluate the relevant traversal evaluator (for instance, the symex-eval function) for debugging by placing point somewhere within it and then invoking M-x edebug-defun (a convenient keybinding for this, e.g., via a Hydra, is recommended). Now, if you execute a traversal (e.g., via the REPL as in the recipe above, or with a test expression in the Scratch buffer, or even just by invoking the relevant feature on source code while in Symex mode), it will put you in the debugger and allow you to step through the code. Handy commands for EDebug:

  * s — step forward

  * i — step in

  * o — step out

  * g — go until next breakpoint

  * q — quit

There are also lots of other features like setting and unsetting breakpoints (b and u), seeing a backtrace (d), evaluating expressions in the evaluation context (e), and lots more, making it an indispensible tool for ELisp debugging.

When you're done debugging, you can remove the debugger hooks by just evaluating the debugged functions in the usual way (e.g. via M-x eval-defun or M-x eval-buffer).

Also see this series on ELisp debugging (https://endlessparentheses.com/debugging-emacs-lisp-part-1-earn-your-independence.html) for more tips.

Troubleshooting
---------------

Debugging Macros vs Functions
-----------------------------

If you are attempting to debug a feature implemented as a macro like symex-define-command, you would need to evaluate the primitive functions for debugging, rather than the macro, or if necessary, copy the contents of the command to a new function and call that function from the macro, in order to be able to debug it. To be clear, you would need to evaluate the function for debugging rather than the macro. Naively, if you attempt to debug the macro, the debugger is triggered at compile time (i.e., as soon as you attempt to evaluate it for debugging!) and not at runtime when you're actually interested in using it. For the same reason, if you attempt to ``step into'' a macro invocation while the debugger is active, it won't do anything. You can only debug functions. If what you are interested in debugging is not a function, then put it in a function and debug that.

``Buffer is read-only''
-----------------------

If you're an Evil user, sometimes, the debugger appears to get overridden by Evil keybindings, complaining that the ``Buffer is read-only'' when you attempt to s to step forward. Saving the buffer (as opposed to debugging an unsaved buffer) seems to solve these issues, and if not, killing and reopening the buffer does.

Better Stack Traces
-------------------

The Symex modal UI is written in Lithium which wraps the underlying Symex commands with error handling, and this wrapping code may be byte-compiled. This could make the stack traces hard to read in the event of an error, so if you are encountering an issue with an interactive feature that you are using through the modal UI, then debug it by invoking that function directly, using M-x <symex-command-name> or via programmatic invocation in IELM or via M-:. That will show you a clean stack trace.

For instance, instead of x in Symex mode, use M-x symex-delete.

Print Statements and Asserts
----------------------------

Don't hesitate to add print statements (e.g., print or message) to trace the execution path. Such trace logs can also serve as evidence from which to form hypotheses about bugs. You could also use cl-assert to assert assumptions at specific points.

Minimizing Complexity
---------------------

Disable Advice
--------------

Symex uses advice (https://www.gnu.org/software/emacs/manual/html_node/elisp/Advising-Functions.html) to implement some features such as adding a selection overlay. To minimize complexity while debugging, it may be advisable (so to speak) in certain cases to disable such advice. To do this, find the place in the code where the advice is added, and execute the corresponding function to remove it. Something like, (advice-remove #'symex-user-select-nearest #'symex-mode-highlight-selected). Of course, if disabling the advice causes the error to go away, then you can focus your efforts on debugging the advice itself in isolation!

Comment Out Macros
------------------

It may also be advisable to comment out macros like symex-save-excursion to see if the problem persists. Commenting out macros like symex--with-undo-collapse will also help you use the debugger in code wrapped by such macros.

Also see Troubleshooting.

Gotchas
-------

The symex-traversal form accepts a single traversal argument. If you'd like to do more than one thing, then wrap the steps in a maneuver or a venture.

symex-deftraversal is equivalent to (defvar name (symex-traversal traversal)). As it uses defvar, once defined, you cannot use the same form to redefine the traversal (e.g., if you are debugging it). You will need to use setq directly — e.g., replace defvar with setq in the expanded version of this form.

Keybinding Cheat Sheet
**********************

The table below lists the key bindings in Symex mode. You can always use Emacs's C-h k to learn what a key does, of course, as another way to learn these bindings. But as the underlying commands are wrapped by Lithium, you would need to visually parse through the Lithium logic to spot the wrapped command in the result.

Finally, the Animated Guide to Symex (https://countvajhula.com/2021/09/25/the-animated-guide-to-symex/) shows each of these commands in action and includes tips on their usage.

Movement
========

Key   Action   Remarks

h, j, k, l
Backwards, down, up, forwards

gj, gk
Linewise down, up
Don't rely too heavily on these — e.g. "leap branch" is often better

f, b
Traverse forwards, backwards

C-f, C-b
Traverse forwards, backwards more
Quicker ways to get around

F, B
Skip forwards, backwards
Quick ways to move forwards and backwards — traverse without entering nested expressions

{, }
Leap backwards, forwards
"Leap" to adjacent branches in the current tree, preserving position on branch

M-{, M-}
Soar backwards, forwards
Leap, but crossing trees if necessary

C-k, C-j
Climb, descend
A quick way to go up and down a tree

0 / M-h
Go to first symex at this level

$, M-l
Go to last symex at this level

M-j, M-k
Go to lowest, highest symex in the tree

Editing
=======

Key   Action   Remarks

w, W
Wrap with parens and insert, wrap and append

x, X, D
Delete, delete backwards, delete remaining

c, C
Change, change remaining

y, Y, p, P
Yank (copy), yank remaining, paste after, paste before

C--, s
Clear, replace/substitute

S
Change "surrounding" delimiter

H, L
Move/shift symex backwards, forwards

M-H, M-L
Move/shift symex backwards, forwards as far as possible on line or column
Remember that usually the Meta prefix M- means "the most" and the Shift prefix S- means an action or "to shift" in a direction

K
Raise

C-S-j / C-{, C-S-k / C-}
Emit backwards, forwards

C-S-h / C-(, C-S-l / C-)
Capture backwards, forwards

z, Z
Swallow head, swallow tail

|, &
Split, join/merge

-
Splice
Clip the delimiters, joining the symex to the containing expression

>, C-> / C-S-o
Insert newline before, append newline after

<,  J / C-<
Join with preceding line, join with next line

M-J / M-<
Collapse to a single line

M->
Unfurl across multiple lines

C-M-<, C-M->
Collapse remaining, unfurl remaining

=, <tab>
Tidy
Indent and remove extraneous whitespace

C-=, C-<tab>
Tidy remaining
Tidy remaining symexes at this level

M-= / M-<tab>
Tidy recursively
Tidies while traversing the symex from the highest branch to the root, for cases where a simple tidy isn't adequate

;, M-;
Comment out, comment out remaining

i, a
Insert at beginning, append at end

I, A
Insert before, append after

o, O
Open line below, above

(, [
Create symex with indicated delimiter

), ]
Wrap symex with indicated delimiter

C-', C-,, `, C-`
Cycle quoting, cycle unquoting, add quoting level, remove quoting level

., C-.
Repeat last command, cycle through recent commands
Similar to Evil's ``dot'' operator and ``repeat-pop'' command

<return>
Enter insertion state

<escape>
Exit

IDE
===

These are included in the symex-ide package (see Installing Symex).

Key   Action   Remarks

e, E, d, M-e, C-M-e, T
Evaluate, evaluate remaining, evaluate definition, evaluate recursively, pretty evaluate, evaluate as "thunk"
T evaluates the indicated symex as if it were wrapped with parentheses, i.e. invoking it as a function, passing no arguments

r
Go to REPL

R / X
Run/eval the buffer

C-;
Evaluate, and insert result

H-h
Toggle highlight

?
Describe / lookup documentation

Contributing to Symex
*********************

There are many ways to contribute to Symex, and all contributions are welcome.

Bugs or Features
================

Please create an issue to report bugs or request features. We want to hear from you!

If you'd like to take matters into your own hands and submit a PR, that's fantastic! You're still welcome to start the process with an issue to solicit input from other Symex contributors and users, so that your PR can be informed by these perspectives. But if you feel you already have a good idea of what you're going for, then by all means, jump straight to the PR, and feel free to reach out for help.

Contributing Money
==================

If you'd like to contribute money to support Symex development, thank you. Please make the contribution either:

  * by Venmo to @Sid-K

  * by Paypal to skasivaj at gmail dot com

  * if there is another way you'd prefer or recommend, please let us know! We are looking for ways to allow people to contribute securely with low fees.

Please remember to mention "Symex" in your message.

The money you contribute will be distributed amongst contributors and the broader ecosystem in accordance with the principles of Attribution Based Economics, as the next section elaborates.

Symex Follows Attribution Based Economics
=========================================

This project follows Attribution-Based Economics (https://github.com/drym-org/foundation). Any financial contributions will be distributed to contributors and antecedents as agreed-upon in a collective process that anyone may participate in (https://drym-org.github.io/dia/). To see the current distributions, take a look at abe/attributions.txt (https://github.com/drym-org/symex.el/blob/main/abe/attributions.txt). To see payments made into and out of the project, see the abe (https://github.com/drym-org/symex.el/blob/main/abe/) folder. If your payment is not reflected there within 3 days, or if you would prefer to, you are welcome to submit an issue or pull request to report the payment yourself — all payments into and out of the repository are publicly reported (but may be anonymized if desired).

Additionally, if your voluntary payments exceed the agreed-upon ``market price'' of the project (see price.txt (https://github.com/drym-org/symex.el/blob/main/abe/price.txt)), that additional amount will be treated as an investment, entitling you to a share in future revenues, including payments made to the project in the future or attributive revenue from other projects.

This project will distribute payments according to the ABE guidelines specified in the constitution. In particular, it may take up to 90 days to distribute the initial payments if DIA has not already been conducted for this project. After that, payments will be distributed to contributors (including investors) at each meeting of the DIA congress (https://github.com/drym-org/dia-symex) (e.g. approximately quarterly).

Non-Ownership
=============

This work is not owned by anyone. Please see the Declaration of Non-Ownership (https://github.com/drym-org/foundation/blob/main/Declaration_of_Non_Ownership.md).

Community
*********

Where to find and connect with the Symex and broader Emacs community.

  * Symex.el (https://github.com/drym-org/symex.el) — the Symex project repository. Report bugs, request features, discuss issues, follow updates.

  * #emacs (https://www.emacswiki.org/emacs/EmacsChannel) — Symex contributors sometimes hang out on IRC in #emacs. It could be a good place to ask for help.

  * Look for Emacs meetups in your town! Like EmacsSF (https://www.meetup.com/Emacs-SF/) in the San Francisco Bay Area.

  * ABE Calendar (https://calendar.google.com/calendar/u/0/embed?src=4a464a65d09d47948cfb879659b77f56c293b588990ae718302530412265589b@group.calendar.google.com) — Symex is part of the ABE community, which meets regularly to work on open source and broader economic and accounting issues.

  * Any other ideas for connecting with fellow Symex users? Let us know!

Resources
*********

Here are some helpful resources for further study.

  * The Animated Guide to Symex (https://countvajhula.com/2021/09/25/the-animated-guide-to-symex/) — contains animations as well as tips for leveling up!

  * Symex Mode: Editing Lisp Code in a Vim-like Way (https://www.youtube.com/watch?v=a5s1ScTx8Zk) — a ``deep dive'' video presentation at EmacsSF

  * Drym.org (https://drym.org) — portal for Attribution Based Economics (ABE) and related efforts.

Symex Origins
*************

We would like to thank:

  * Ariana, for naming Symex and giving us the term ``symex.''

  * Soumya, for gentle encouragement to release this package when it was just sitting in Sid's Emacs config.

  * Jeff, for organizing a meetup in San Francisco where Symex was presented for the first time.

  * Oleh, for the Hydra package which made it easy to prototype Symex.

  * Alan, for making the best logo ever.

  * Squirrels in gardens everywhere, for inspiration.

  * And many, many others (https://github.com/drym-org/symex.el/blob/main/abe/attributions.txt) who contribute in ways small and large.