(h, j, k, l)


  • I Have Two Problems
  • const [, pkg] =

Atom Expat

  • 🧰 Hackability 🔌 Plugins 🐿️ TreeSitter
  • atom-regex-railroad screenshot of atom-regex-railroad plugin, showing the
plugin graphically illustrating the contents of a regular expression which
appears in the main buffer of the editor

Headline: GitHub's new CEO promises to save Atom post-Microsoft acquisition

Do YOU know any hackable editors?

screenshot of nvim plugin template git repo, cursor hovers on "use this template"

Doing NeoVim

  • 🌘 Moon-Oriented Programming 🖥️
  • 🐒 Climbing Trees 🌴

Code Spelunking

  • Components

    ⚙️ What are we saying?

  • Renderers

    ✍️ How are we saying it?

  • Buffers

    🪟 Where are we saying it?


local cursor_node = ts_utils.get_node_at_cursor()
local cursor_node = ts_utils.get_node_at_cursor()
local regexp_node = do_awful_hacks(cursor_node)


Everything we need

  • do hacks to cross between host language and regex trees
  • there's lots of room for improvement here
  1. Combine sequential pattern_characters
  2. Track capture groups and nesting levels
  3. Translate control chars / quantifiers
  4. Try to handle negative lookbehinds
  "regexp_string": "hello d([0-9]|o)lly",
  "components": [{
      "text": "hello d",
      "type": "pattern_character"
    }, {
      "capture_group": 1,
      "depth": 1,
      "text": "([0-9]|o)",
      "type": "anonymous_capturing_group",
      "children": [{
        "text": "[0-9]|o",
        "type": "alternation",
        "children": [{
          "text": "[0-9]",
          "type": "term",
          "children": [{
            "text": "0-9",
            "type": "class_range"
        }, {
          "text": "o",
          "type": "pattern_character"
    }, {
      "text": "lly",
      "type": "pattern_character"


local M: Renderer = {}

return M
local M: Renderer = {}

function M.set_lines(buffer: Renderer,
                     lines: {string}): {string}

return M
local M: Renderer = {}

function M.set_lines(buffer: Renderer,
                     lines: {string}): {string}

function M.get_lines(components: {Component},
                     options: Options,
                     state: RendererState): {string}

return M


  • demo of popup buffer
  • demo of split buffer
  • demo of debug buffer
  • demo of scratch buffer

Constructing a Narrative

function M.render(buffer: Buffer,
                  renderer: Renderer,
                  components: {Component},
                  options: Options,
                  state: RendererState)
  local lines = renderer
    .get_lines(components, options, state)
  buffer:init(lines, options, state)
  renderer.set_lines(buffer, lines)
  buffer:after(lines, options, state)

Demo Time!

Contributions Welcome

  • 💻 Graphic output
  • 👀 Negative Lookbehind
  • 🔨 Refactoring
  • 🥼 Tests


Benny Powers

Principal UX Engineer @
Eleventy Accessibility Accessibility Adobe Angular Apollo Atom Azure Bash CI/CD C# CSS3 Docker Elastic Search esbuild Firebase Fish Shell Google Cloud Platform GitHub GitHub GitLab GitLab GNOME Google GraphQL Gulp Three horizontal lines HTML5 IBM JavaScript Municipal Coat of Arms of Jerusalem LinkedIn LinkedIn Linux Lit Magento Mastodon Mastodon Microsoft neovim Node.js NoSQL NPM PatternFly Photoshop Polymer Print Progressive Web Apps Python React Reddit Red Hat REST Rollup RSS Salesforce SAP Scania Sketch SpaceX Loading... Stack Overflow Stack Overflow SVG Logo Designed for the SVG Logo Contest in 2006 by Harvey Rayner, and adopted by W3C in 2009. It is available under the Creative Commons license for those who have an SVG product or who are using SVG on their site. SVG Logo 14-08-2009 W3C Harvey Rayner, designer See document description image/svg+xml

Test-Driven Development Twitter Twitter TypeScript Unit Testing VIM Vue Web Components Wordle WordPress YouTube