Conversation
Initial skeleton for Emacs integration: - elva-bridge.py: Python subprocess using pycrdt for Yjs protocol - elva.el: Emacs package for buffer synchronization - plan.org: Development plan and architecture notes
- Add proper Y-protocol message encoding/decoding - Implement SYNC_STEP1/SYNC_STEP2 handshake - Handle incremental updates (SYNC_UPDATE) - Fix echo prevention for bidirectional sync - Use "ytext" key to match Elva editor client
- Separate stderr to dedicated buffer so JSON parsing works - Fix text observer to send server changes to Emacs - Add fatal error logging with traceback - Update plan: Phase 3 complete, add future improvements
pycrdt uses UTF-8 byte positions while Emacs uses character positions. The bridge now converts between them: - _byte_pos_to_char_pos: for server -> Emacs messages - _char_pos_to_byte_pos: for Emacs -> server messages - _byte_count_to_char_count: for delete operations This fixes editing with multi-byte characters (CJK, emoji, etc).
Cursor preservation: - Point now adjusts correctly when remote edits occur before cursor - Inserts before cursor shift point forward - Deletes before cursor shift point backward Change batching: - Rapid local changes are batched with configurable delay (50ms default) - Reduces network traffic during fast typing - Can be disabled by setting elva-batch-delay to 0 Reconnection handling: - Automatic reconnection on connection loss - Configurable retry count and delay - Connection status tracking via elva-status
- Report HTTP errors with server's reason phrase to Emacs - Add "error" op handling in elva.el - Update plan with future improvements
- Update plan.org to mark error handling tasks as done - Update TEST.md with room listing documentation
- Emacs client has elva-default-port customization - Update documentation with new default port - Add TODOs for Emacs room listing and safe room connection
- Accept room-id only (uses localhost:7654) - Accept host/room-id (uses default port) - Accept host:port/room-id - Accept full ws:// URLs - Add elva-default-host customization - Update documentation
Room IDs must be 10-250 chars, alphanumeric plus hyphen/underscore
Room IDs must be 10-250 characters. Updated all examples to use "my-room-0001" which clearly shows the pattern.
Bridge now sends {op: "sync_complete", length, content} to Emacs
after receiving the first SYNC_STEP2 from the server. This allows
Emacs to know the initial room content before deciding whether to
push local buffer content.
- Display room name in modeline: Elva[room-id] - elva-connect creates new buffer *elva:room-id* for room content - Add elva-room-from-buffer to push buffer to empty rooms only - Fail with message if room already has content when pushing
- On reconnect, buffer content is restored to room if room is empty - Modeline shows connection status with colored faces: - Green (success): connected - Yellow (warning): offline or reconnecting - Push modes: 'if-empty (room-from-buffer) vs 'always (reconnect)
bridge identifies as "emacs"
- Clear buffer before connecting/reconnecting - Save content before clearing for reconnect case - Restore saved content only if room is empty after sync
Fetches available rooms from server and offers them as completion candidates, allowing use of icomplete or other completion frameworks.
- Import and initialize pycrdt Awareness - Handle incoming AWARENESS messages from server - Track and send local cursor position - Send awareness state updates to Emacs - Queue and send awareness updates to server
- Show remote users' cursors as colored highlights - Each user gets a unique color from palette - Send local cursor position to bridge on movement - Handle end-of-buffer cursor positions - Clean up overlays on disconnect
- Clear stale awareness entries on connect - Send awareness disconnect message on shutdown - Kill existing bridge process before starting new one in Emacs - Fix reconnection to properly load room content
- Add default case in sync_complete to load room content on normal connect - Allow elva-connect to disconnect and reconnect if already connected
- Only suppress cursor broadcast for remote edits, not local edits - Flush pending changes before applying remote edits - Redraw cursor overlays after text operations - Store cursor data for redrawing
Prevent cursor stretching and walking backward issues
- Mark awareness protocol and user identification as complete - Add detailed cursor awareness implementation checklist - Add technical notes on awareness protocol
- Only adjust remote cursor positions for local edits (not remote edits) - Remote clients send their own updated cursor positions after their edits - Fixes cursor "walking backwards" issue - Add bounds checking for cursor byte positions - Use refresh() instead of refresh_lines() for reliable cursor display
The bridge was computing character counts for DELETE operations using the document state AFTER the deletion, causing the deleted bytes to be missing from the calculation. This resulted in delete count of 0 for end-of-file deletes, causing Emacs buffers to desync. Fix: store pre-change text before applying server updates and use it for position/count conversion in the text change observer. Also add defensive bounds checking in elva.el to clamp insert positions to valid buffer range.
- Remove dead _send_update method from bridge - Use public awareness.client_states API instead of private _states - Remove unused variable binding in elva--sentinel - Fix process buffer leak: track and kill stdout/stderr buffers on disconnect and reconnect - Rewrite cursor overlay logic with clearer bounds handling
- Bridge UTF-8 byte<->char position conversion (ASCII, multibyte, clamping) - Bridge byte count to char count conversion - Pre-change text mechanism for server delete operations - Bridge delta processing (_on_text_change) - Awareness filtering and byte->char cursor conversion Also revert bridge _states->client_states change from previous cleanup: pycrdt.Awareness only exposes _states; the public client_states property is on elva.awareness.Awareness which the bridge doesn't use.
- Add `elva-list-rooms`: tabulated-list buffer showing active rooms from the server's /rooms endpoint (RET to connect, g to refresh) - Move `elva--fetch-rooms` to return full room alists (identifier, clients, persistent) and reuse for both room listing and elva-connect completion - Fix buffer leak: kill url-retrieve-synchronously temp buffer - Fix disconnect: kill process before its buffers so Emacs doesn't prompt about running processes on the stderr buffer
Collaborator
|
The emacs bridge probably needs to be matched in version to the elisp, so wondering how we advise users to do that: emacs can try to import it, and if missing provide the |
Member
Author
|
Given the For now though, I would keep |
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.
First version of an ELVA plugin for Emacs by @stefanv.
Todo (now or in future PRs):
elva.provider.WebsocketProviderinstead of custom message encoding/decoding and reconnection handlingelva-bridge.pya tool/package ready to be installed viauv tool installorpipx installor similar - or make it even installable as an ELVA app?Important
Do not merge before
have been merged.