Lay the groundwork for multiple file editing#1240
Merged
Merged
Conversation
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
force-pushed
the
multifile
branch
2 times, most recently
from
July 20, 2026 14:09
ddbc186 to
9c672cf
Compare
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.