Skip to content

Lay the groundwork for multiple file editing#1240

Merged
shepmaster merged 15 commits into
mainfrom
multifile
Jul 21, 2026
Merged

Lay the groundwork for multiple file editing#1240
shepmaster merged 15 commits into
mainfrom
multifile

Conversation

@shepmaster

Copy link
Copy Markdown
Member

No description provided.

@shepmaster shepmaster added the enhancement Something new the playground could do label Jul 6, 2026
We now accept a single string (preserving backwards compatibility) or
an array of file names and contents.

We ensure that any of `build.rs` / `src/main.rs` / `src/lib.rs` are
deleted, if the user does not supply them. These files impact how
Cargo builds.

The "compilation" and "macro expansion" functions now pass `--lib` or
`--bin` to Cargo to specify what it is that we want to focus on.
The `code` parameter has been enhanced to support either a single
string (preserving backwards compatibility) or a vector of file names
and contents.

I'm deliberately leaving the `evaluate` endpoint as only accepting a
single string as I don't really care to encourage usage of that
organically-grown endpoint.
The gist endpoints' `code` parameter now uses a string (as before) or
a vector of names and contents.

On saving, we submit all those files to GitHub. However, GitHub
doesn't allow slashes in gist file names, so we encode them with a
simple percent-encoding scheme. To know if we should decode filenames
on load, we add our own meta configuration file. When that file is
present, we know to perform the decoding.

On load, we effectively pass multiple files back unchanged. If there's
zero or one file loaded, we use the single-string form.

There's a small change here where we no longer concatenate multiple
files together, which means there could be a period where the frontend
receives multiple files and doesn't understand that, but I'm not
worried about that.
For now, only show a placeholder file tree.
@shepmaster
shepmaster force-pushed the multifile branch 2 times, most recently from ddbc186 to 9c672cf Compare July 20, 2026 14:09
The playground now supports multiple files in the UI instead of a
single implicit file. Users can create, rename, and delete files and
directories from a file tree panel alongside the editor.

We do not (yet) transfer all of the files to the server at build time,
so this effectively only allows editing multiple disparate files
concurrently.

Other details:

- The directory structure is derived from file paths rather than
  tracked separately. Only files are stored in the Redux state.

- Validation rules live in a standalone domain logic module that's
  used by both the UI and the reducers.

- The transient UI state uses Jotai instead of the global Redux
  store. Using Jotai over `useState` reduces the number of re-renders
  as the state is used across multiple components. We also tried
  Zustand, but it had staleness issues with React Compiler.

Written and reviewed in collaboration with eca + qwen3.6-35b-a3b.
These editors have a notion of "data corresponding to the current
content being edited", which we can keep in a cache and swap around as
we change files. This includes things like selection position and undo
history.

Unfortunately, we can't do much for the simple editor. The simple
editor relies on the browser to maintain the undo stack. To preserve
that, we'd need to keep all the `textarea`s in the DOM. This is
possible, but even when doing so, *something* causes some of the undo
stacks to get confused.

[Here's a small test][test]. In general, fill in one textarea, switch
to the other, fill the other in, switch back to the original, then try
to undo / redo.

In Safari (26.4 / 21624.1.16.11.4), undo commands apply across
the textareas, even when one is hidden.

In Firefox (150.0.2), the undo stack is fully lost when switching
between textareas.

In Chrome (147.0.7727.117), there's an extra "undo step" and then you
can undo. However, if you switch back to the second textarea, you
can't undo that anymore, unless you fully redo any changes to the
first textarea. If you play around switching between the two and
undoing / redoing, sometimes you are able to "redo" more than you ever
typed!

[test]: https://codepen.io/shepmaster/pen/QwGyXaM?editors=1010
Most endpoints can be straight-forwardly updated to send the
string-or-file-array.

Gists and formatting are more complicated because they now might
return multiple files.

Gists have logic to tell if the editor no longer matches with what the
gist was saved with, which becomes more complicated and gains some tests.

Sharing code, such as via the `code` query parameter or when linking
to URLO, now also has to deal with encoding multiple files.
Like we do for sending data to the backend, the `code` parameter is
extended to be either a single string or an array of `{ name, content
}` objects. When deserializing from storage, we check the type and
reconstruct the Redux state's file array (with new IDs) when needed.
Everywhere now accounts for multiple files
Adding a main function can add a `main.rs` file and adding a crate
type can modify `lib.rs`. Adding imports or feature flags needs far
more clever parsing of the error messages, so just disable them for
now.
@shepmaster
shepmaster merged commit a62f64a into main Jul 21, 2026
8 checks passed
@shepmaster
shepmaster deleted the multifile branch July 21, 2026 11:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Something new the playground could do

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant