{"id":13769771,"url":"https://github.com/kneasle/sapling","last_synced_at":"2025-05-15T07:06:14.729Z","repository":{"id":37940328,"uuid":"296399864","full_name":"kneasle/sapling","owner":"kneasle","description":"A highly experimental vi-inspired editor where you edit code, not text.","archived":false,"fork":false,"pushed_at":"2025-02-04T19:49:38.000Z","size":739,"stargazers_count":745,"open_issues_count":19,"forks_count":20,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-04-11T18:24:57.950Z","etag":null,"topics":["code-editor","editor","experimental","rust","structured-editing","text-editor","vim"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kneasle.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-17T17:43:57.000Z","updated_at":"2025-03-06T19:20:54.000Z","dependencies_parsed_at":"2024-02-09T02:10:54.025Z","dependency_job_id":"ea5c5941-cba2-4112-ab88-789113d6ebf5","html_url":"https://github.com/kneasle/sapling","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kneasle%2Fsapling","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kneasle%2Fsapling/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kneasle%2Fsapling/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kneasle%2Fsapling/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kneasle","download_url":"https://codeload.github.com/kneasle/sapling/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254292042,"owners_count":22046426,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-editor","editor","experimental","rust","structured-editing","text-editor","vim"],"created_at":"2024-08-03T17:00:31.379Z","updated_at":"2025-05-15T07:06:09.710Z","avatar_url":"https://github.com/kneasle.png","language":"Rust","readme":"\u003cimg src=\"https://raw.githubusercontent.com/kneasle/sapling/master/resources/sapling.gif\" alt=\"Sapling Logo\" align=\"right\" /\u003e\n\n# Sapling\n\nA highly experimental code editor where you edit code, not text.\n\n_I (@kneasle) don't currently have time to work on Sapling (I have exams coming up\nand other projects are requiring my time).  This doesn't mean the project is dead or that I've\nforgotten about it - I still think it's cool and the community support has been crazy.  I'm also\nnot currently streaming development, but all vods are still on\n[my YouTube channel](https://www.youtube.com/channel/UCKl0T4IDZC3vUz152hDAzGw) for anyone\ninterested.  There's also a discord server for discussions about Sapling and structured editing in\ngeneral ([invite link](https://discord.gg/Amv3Tsb4fV)). OK enough from me, onto the real README!_\n\nMost of the ideas for this project come from my friend Shtanton's\n[blog post](http://shtanton.com/posts/ex.html).  The concept of directly editing syntax trees is called\n['structured editing'](https://en.wikipedia.org/wiki/Structure_editor) and is not new;\nthe purpose of Sapling is to use ideas from structured editing to **speed up** moment-to-moment\ncode editing, much how editors like Vim and Emacs speed up editing.  Sapling's editing model will\nbe largely inspired by [Vim](https://github.com/vim/vim)/[NeoVim](https://github.com/neovim/neovim)\nand [kakoune](https://github.com/mawww/kakoune).  Sapling also aims to be **general purpose** -\nSapling should be able to edit any language, given that a suitable grammar is provided.\n\n_Contributions of all kinds are very welcome!_\n\nIt is worth noting that Sapling is primarily **an experiment** to determine whether or not such an\neditor could work.  Therefore, for the time being, Sapling can be expected to change at any time.\nHopefully the design of Sapling will converge over time - its current state is similar to how\npre-1.0 Rust was continually evolving and making potentially-breaking changes so that post-1.0 Rust\ncould be as useful as possible.\n\n## Contents\n\n- [**But Why?**](#but-why)\n- [**Goals of Sapling**](#goals-of-sapling)\n- [**Inspirations**](#inspirations)\n- [**Quick Start**](#quick-startplay-with-sapling)\n- [**Pros of AST-based Editing**](#pros-of-ast-based-editing)\n- [**'Extra Fun Challenges'**](#cons-of-ast-based-editing-otherwise-known-as-extra-fun-challenges)\n- [**What's an AST?**](#whats-an-ast)\n\n---\n\n## But why?\n\nWhen writing code with any text editor, you are usually only interested in a tiny subset of all the\npossible strings of text - those that correspond to valid programs in whatever language you're\nwriting.  In a **text** editor, you will spend the overwhelming majority of your time with the text\nin your editor being invalid as you make edits to move between valid programs.  This is inefficient\nfor the programmer, and causes lots of issues for software like Language Servers which have to cope\nas best they can with these invalid states.\n\nTo be fair, editors like Vim, Emacs and Kakoune do better than most by providing shortcuts to do \ncommon text manipulations, which is a step in the right direction.  Interestingly, though, the most \nuseful of these shortcuts are those correspond to modifications of the syntax tree (e.g. `ci)` to\nremove the replace the contents of `()` in Vim), and so it seems logical to apply modal editing to\ndirectly modifying the syntax trees of programs.\n\nSapling takes the idea of keystrokes primarily modifying text, but instead applies those keystrokes\nas actions to the syntax tree of your program.  I have no idea if this will be useful, but it seems\nworth a try.\n\n## Goals of Sapling\n\nThese goals are roughly in order of importance, with the most important first:\n\n- **Editing Speed**: Sapling should be an editor that allows power users to edit code as close\n  to their thinking speed as possible.  Flattening the learning curve is also important, but\n  Sapling is not trying to be an editor for every single developer and is designed primarily with\n  power users in mind.\n- **Stability**: Sapling should not, under any circumstances, corrupt the user's data or crash.\n  Either of these are considered critical bugs and should be reported.\n- **Generality**: Sapling should, in theory, be able to edit any language.  This will likely be done\n  with making the language plug-in-able and probably specified by some kind of grammar.\n- **Familiarity**: Sapling should feel familiar to people who are used to modal editors such as Vim\n  and Kakoune.  However, some alterations are required for Sapling to edit ASTs and not just text.\n- **Interactivity**: Sapling should always give the user immediate feedback about their actions.\n  Kakoune is a model example of this, and Vim/NeoVim does pretty well too.\n- **Performance**: The user should not have to wait for Sapling to do anything.  Sapling should also\n  have a small resource footprint - an editor should not have to use several hundred megabytes of\n  RAM when idling.\n\n## Inspirations:\n\n- _[Vim](https://github.com/vim/vim), [NeoVim](https://github.com/neovim/neovim) and\n  [Kakoune](https://github.com/mawww/kakoune)_:\n  'Modal' editors where keystrokes can correspond to _actions_ on the text rather than always\n  inserting directly to the text buffer.  Shoutout in particular to Kakoune for its beautiful\n  multi-selection based editing model.\n- _[Tree Sitter](https://github.com/tree-sitter/tree-sitter)_: A generic, flexible, error-handling\n  parser that is not language specific.  Designed primarily to provide better syntax highlighting\n  for [the Atom text editor](https://github.com/atom/atom).\n- _[grasp](http://www.graspjs.com/)_: A regex-like language for searching JavaScript ASTs.\n- _[r/nosyntax](https://reddit.com/r/nosyntax)_: A subreddit for strutured and projectional editors.  They also have\n  [a list](https://www.reddit.com/r/nosyntax/comments/6xv61b/list_of_projects/) of such projects.\n- _[Barista](https://www.researchgate.net/publication/221518157_Barista_An_implementation_framework_for_enabling_new_tools_interaction_techniques_and_views_in_code_editors)_:\n  A structured editor that allows the user to fall back on text editing if required, which is\n  something I'd like to explore for Sapling.  The source code is\n  [here](https://github.com/amyjko/citrus-barista), but since this was a research project it\n  seems to be unmaintained.\n  \n## Quick Start/Play with Sapling\n\n### Installation\n\nSapling is not yet on [crates.io](crates.io) and is very much still in early development, but if you\nwant to play around with Sapling as it currently stands, the best way is to clone the repository and\nbuild from source (you'll need [Rust](https://www.rust-lang.org/learn/get-started) installed in\norder to do this):\n```bash\ngit clone https://github.com/kneasle/sapling.git\ncargo run 2\u003e log\n```\n\nIf you have Nix you can also run `nix build` and `./result/bin/sapling 2\u003e log`, or if you don't mind\nseeing stderr output even quicker with `nix run`. \n\n### Demo\n\n![Demo GIF](https://user-images.githubusercontent.com/60934058/112751246-d8e23f00-8fc4-11eb-9a15-8a3ef32d54a4.gif)\n\n### Current Keybindings\n\n#### Misc\n\n- `q`: Quit Sapling\n- `u`: Undo a change\n- `R`: Redo a change\n\n#### Cursor Movement\n\n- `h`/`k`: Move the cursor to the previous sibling of the current node\n- `j`/`l`: Move the cursor to the next sibling of the current node\n- `c`: Move the cursor to the first child of the current node (if it exists)\n- `p`: Move the cursor to the parent of the node it's currently at\n\n#### Modify the tree\n- `r*`: Replace the node under the cursor with the node represented by the key `*`\n- `x`: Delete the node under the cursor\n- `o*`: Insert a new node represented by `*` as a **child** of the cursor\n- `a*`/`i*`: Insert a new node represented by `*` before or after the cursor respectively\n\nAs with Vim, all commands can be repeated by inserting a count before them.  For example, `3u` will\nundo 3 steps in one go.\n\nSapling can currently only edit JSON with the following keys: `[a]rray`, `[o]bject`, `[t]rue`,\n`[f]alse`, `[n]ull`, `[s]tring`.  There is currently no way to insert text into a string or to open\nand close files (yet!).\n\nSapling handle multiple nodes in one go by adding a count before the node name, for example `i3t`\nwill insert 3 `true`s before the cursor.\n\n## Pros of AST-based editing\n\n- Because the editor already knows the syntactic structure of your program, the following are\n  **much** easier to implement for every language supported by Sapling:\n  - Syntax highlighting\n  - Code folding\n  - Auto-formatting of code (in fact, this is nearly automatic and elegantly preserving code\n    formatting is hard)\n- It will hopefully be **FAST** to edit code\n- It might actually be more intuitive than text-based editing\n\n## Cons of AST-based editing (otherwise known as 'Extra Fun Challenges')\n\nBecause the editor *has* to hold a valid program, the following things that other editors take for\ngranted are hard to implement:\n- Searching a file - because only syntax tree nodes can be selected, we need a way to concisely\n  search for nodes in a tree.  [grasp](http://www.graspjs.com/) seems like it'd be good inspiration\n  for this.\n- Just opening a file - opening a syntactically correct file is essentially the same as writing a\n  compiler-esque parser for every language you want to load (not an easy task but there's plenty of\n  literature/libraries already existing for this).  The real issue is that Sapling has to at least \n  attempt to open any file, regardless of syntactic correctness, and this essentially boils down to\n  building an error-correcting parser that's generic enough to parse any language.\n  \n  [Tree Sitter](https://github.com/tree-sitter/tree-sitter) has already had a good crack at this\n  problem, but Tree Sitter is geared towards providing accurate syntax highlighting and has a few\n  missing features that Sapling needs:\n  - Sapling needs comments to be preserved when parsing (but whitespace is perhaps not so essential)\n  - Sapling needs to be able to render ASTs back to text, which I don't think Tree Sitter's grammars\n    can handle\n  \n  For the sake of pragmatism, I think we should initially write a wrapper around tree-sitter for\n  parsing/reading files so that Sapling at least works whilst we decide if a custom grammar is\n  required (and if it is, how it should work).\n  \n## What's an AST?\n\nAST stands for ['Abstract Syntax Tree'](https://en.wikipedia.org/wiki/Abstract_syntax_tree), and in\nessence it is a tree-like representation of only the structure of a program, without any details\nabout formatting.\n\nFor example, the following Rust code:\n```rust\nfn foo(y: u64, z: u32) {\n    let x = y * 3 + z as u64;\n    combine(x, y);\n}\n```\nwould correspond to a syntax tree something like the following (simplified for demonstration\npurposes).  Notice how each 'element' of the code corresponds to one 'node' in the syntax tree:\n\n![Example tree](/resources/example_tree.png)\n","funding_links":[],"categories":["Rust","Structural code editor projects"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkneasle%2Fsapling","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkneasle%2Fsapling","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkneasle%2Fsapling/lists"}