Skip to content

Jamie-Cui/overleaf-project

Repository files navigation

overleaf-project

Chinese README: README.zh.org

Inspired by vale981/overleaf.el.

The key difference from the original: overleaf.el provides a single-buffer live editing workflow where each save syncs one file in real time. overleaf-project instead treats the whole Overleaf project as a Git repository — you commit locally at your own pace and push/pull entire snapshots, which makes conflict resolution and history management much more tractable.

overleaf-project provides project-level Overleaf integration for Emacs:

  • clone a full Overleaf project to a local Git repository
  • keep editing locally with normal Git commits
  • push committed local snapshots to Overleaf and pull remote updates back
  • resolve local/remote divergence with normal git merge on a dedicated branch

This package no longer provides the old single-buffer live editing workflow. Load overleaf-project directly in both new and existing configs.

Installation

Add the package to your load path and require overleaf-project, or use use-package:

(use-package overleaf-project
  :custom
  (overleaf-project-url "https://www.overleaf.com"))

The package targets Emacs 29.4+ and depends on the Elisp packages websocket and webdriver.

The package feature, interactive commands, and customization variables use the overleaf-project- prefix to avoid colliding with overleaf.el.

If you use a self-hosted Overleaf instance, set the server URL:

(setopt overleaf-project-url "https://latex.example.edu")

External tools

Project push/pull expects these executables to be available:

  • git
  • curl
  • unzip

Optional authentication through the browser also needs geckodriver (https://github.com/mozilla/geckodriver).

Development

For local validation, the repository includes a small Makefile:

make
make help
make clean

If your Emacs binary is not available on PATH as emacs, override it explicitly:

make EMACS=/path/to/Emacs

Authentication

You need valid Overleaf session cookies before cloning, pushing, or pulling.

overleaf-project-authenticate

By default, overleaf-project-authenticate stores cookies in Emacs auth-source. It uses the first plain file entry from auth-sources, falling back to ~/.authinfo. The package keeps one Overleaf-managed record per host, using login overleaf-project and port overleaf-project-cookie. Re-authentication replaces that managed record instead of appending stale copies.

If you prefer a plain file instead, set:

(setopt overleaf-project-cookie-storage "~/.overleaf-project-cookies")

If you want cookies to stay only in memory for the current Emacs session, set:

(setopt overleaf-project-cookie-storage nil)

For fully custom setups, you can still set overleaf-project-cookies and overleaf-project-save-cookies directly, or use the file helpers overleaf-project-read-cookies-from-file and overleaf-project-save-cookies-to-file.

Then run:

M-x overleaf-project-authenticate

If overleaf-project-clone, overleaf-project-init, overleaf-project-push, overleaf-project-overwrite-remote, or overleaf-project-pull starts without valid cookies, the command asks in the minibuffer whether it should run overleaf-project-authenticate immediately. For cookies saved by overleaf-project-authenticate, expiry is checked from the locally saved session-cookie expiry before any network request; short-lived analytics cookies are ignored for that check.

Workflow

Clone a project

Run:

M-x overleaf-project-clone

This command:

  • uses the configured overleaf-project-url and prompts for the project
  • downloads the full project zip
  • creates a local Git repository
  • commits the imported snapshot
  • stores Overleaf metadata in the repo’s local Git config

Bind an existing Git repo

If you already have a local Git repository with the project files, run:

M-x overleaf-project-init

This command:

  • prompts for the remote Overleaf project
  • stores Overleaf metadata in the repo’s local Git config
  • initializes the hidden base snapshot used by later push/pull operations
  • does not automatically pull from or push to Overleaf

Edit locally

After cloning, work in the repo normally:

  • edit files locally
  • optionally stage only the changes you want to include
  • run M-x overleaf-project-push to upload local commits
  • run M-x overleaf-project-pull to bring remote Overleaf changes back

overleaf-project-push prepares the local branch before talking to Overleaf:

  • if there are staged changes, it commits them automatically
  • if there are unstaged or untracked files, it asks whether to stage all changes first
  • it then fetches the latest remote Overleaf snapshot and uploads HEAD only when the remote has not diverged

overleaf-project-pull requires a clean working tree and merges the latest Overleaf snapshot into the current branch.

When used interactively, the commands collect minibuffer input and confirmation in the foreground, then run the long network, unzip, and Git work in the background by default. This keeps Emacs responsive while clone, init, push, pull, remote overwrite, authentication, and Magit remote refreshes are waiting on Overleaf or external tools. Set overleaf-project-async-commands to nil if you need the older fully synchronous command behavior.

Both commands still have to run from a normal branch rather than a detached HEAD.

By default, successful push operations also maintain a root-level .overleaf-project-sync.json file on the Overleaf project. That file records the last local Git commit/tree uploaded by this package. It is removed from downloaded snapshots before Git comparisons, so it acts as remote sync bookkeeping rather than normal project content.

The package also creates local safety refs under refs/overleaf-project/backups/ before sync steps that can move the current branch or complete pending sync state. These refs keep previous local commits reachable independently of branch movement and reflog expiry.

Push to Overleaf

Run:

M-x overleaf-project-push

The command compares three states:

  • the last successfully synced Git commit
  • the current local HEAD
  • the latest project snapshot downloaded from Overleaf

Then it behaves as follows:

  • if only local changed, it uploads HEAD to Overleaf
  • if remote already matches HEAD, it only updates the base ref
  • if only remote changed, it stops and asks you to run overleaf-project-pull
  • if both changed differently, it stops and asks you to run overleaf-project-pull first

Overwrite the Overleaf remote

Run:

M-x overleaf-project-overwrite-remote

This command uses the same local auto-commit preparation as overleaf-project-push, but always replaces the remote Overleaf project contents with the local HEAD snapshot. Use it only as a recovery command when you intentionally want local files to replace the remote state.

Pull from Overleaf

Run:

M-x overleaf-project-pull

The command compares the same three states and then behaves as follows:

  • if only remote changed, it fast-forwards your current branch locally
  • if local already matches the remote snapshot, it only updates the base ref
  • if there are no remote changes, it reports that nothing needs to be pulled
  • if both changed differently, it merges the remote snapshot into the current branch; after a clean merge, run overleaf-project-push to publish the merged result back to Overleaf

The clone, config, push, and pull commands store project metadata in the repository’s local Git config, so later pushes and pulls can run from anywhere inside that repo.

Conflict handling

When both local and remote changed, run overleaf-project-pull first. It merges the downloaded remote snapshot into the current branch with normal Git merge machinery.

If the merge conflicts:

  • the current branch is left in Git’s normal conflicted merge state
  • you resolve conflicts with Magit or plain Git
  • after creating the merge commit, run overleaf-project-push to upload the merged result

This keeps conflict resolution entirely inside Git instead of ediff.

Push on Commit

If you commit from Emacs via Magit / git-commit, you can trigger push automatically after each commit:

(with-eval-after-load 'git-commit
  (add-hook 'git-commit-post-finish-hook
            (lambda () (overleaf-project-push nil t))))

The hook only pushes repositories that already contain Overleaf project metadata. With the default overleaf-project-async-commands setting, this hook starts the push in the background instead of blocking Emacs.

Magit Status

If you want an Overleaf section inside magit-status, load the optional overleaf-project-magit integration and enable it once:

(with-eval-after-load 'magit
  (require 'overleaf-project-magit)
  (overleaf-project-magit-setup))

For Overleaf-managed repositories, each magit-status refresh then also may start an asynchronous refresh of the remote Overleaf snapshot. The automatic refresh is throttled by overleaf-project-magit-auto-refresh-remote-interval so ordinary Magit refreshes do not repeatedly download snapshots and trigger Overleaf rate limits. When the download finishes, the status buffer refreshes again and shows the remote diff against the last synced base snapshot.

If you prefer to keep remote refresh manual, set overleaf-project-magit-auto-refresh-remote to nil. You can still run M-x overleaf-project-magit-refresh-remote manually.

Commands

The main interactive commands are:

  • overleaf-project-authenticate
  • overleaf-project-clone
  • overleaf-project-init
  • overleaf-project-push
  • overleaf-project-overwrite-remote
  • overleaf-project-pull
  • overleaf-project-browse-remote
  • overleaf-project-log
  • overleaf-project-log-clear

You can also bind the provided command map:

(global-set-key (kbd "C-c o") overleaf-project-command-map)

The default bindings inside that map are:

  • a -> overleaf-project-authenticate
  • b -> overleaf-project-browse-remote
  • c -> overleaf-project-clone
  • l -> overleaf-project-pull
  • p -> overleaf-project-push
  • s -> overleaf-project-push (compatibility shortcut)

Customization

Useful options include:

  • overleaf-project-url for the Overleaf server URL
  • overleaf-project-cache-cookies to force cookie reloads instead of caching
  • overleaf-project-debug for verbose logging
  • overleaf-project-log-buffer-name for the global log buffer name
  • overleaf-project-log-echo to control whether log entries also appear in the minibuffer
  • overleaf-project-log-time-format to customize log entry timestamps
  • overleaf-project-sync-auto-commit-message for the automatic local checkpoint commit before pushing
  • overleaf-project-async-commands to keep interactive commands and push hooks from blocking Emacs during network, unzip, and Git work
  • overleaf-project-magit-auto-refresh-remote-interval to throttle automatic Magit remote snapshot downloads
  • overleaf-project-sync-metadata-enabled to control whether push writes remote sync metadata
  • overleaf-project-sync-metadata-file to rename the reserved remote metadata file
  • overleaf-project-local-backups-enabled to control whether sync operations create local safety refs
  • overleaf-project-local-backup-ref-prefix to choose the backup ref namespace
  • overleaf-project-socket-timeout if project tree websocket fetches need longer
  • overleaf-project-curl-connect-timeout and overleaf-project-curl-max-time to cap curl calls during Overleaf HTTP requests
  • overleaf-project-git-executable, overleaf-project-curl-executable and overleaf-project-unzip-executable if the tools are not on your PATH

Notes

  • Overleaf messages, warnings, and debug entries are written to the global *overleaf-project-log* buffer. Each entry includes timestamp, level, and the best available project, repository, or Overleaf URL context so logs from different projects can be distinguished.
  • Push currently recreates changed remote files instead of preserving old Overleaf document ids. That is acceptable for the new project-level workflow, but it is different from the old live buffer integration.
  • overleaf-project-overwrite-remote overwrites remote Overleaf files with the local HEAD snapshot.
  • .overleaf-project-sync.json is reserved for remote sync metadata when metadata support is enabled. It should not be tracked in the local Git repository.
  • Local safety refs can be inspected with:
    git show-ref refs/overleaf-project/backups
        

    To recover one, create a normal branch from the backup ref:

    git branch recover-overleaf refs/overleaf-project/backups/...
        
  • Empty directories are not tracked by Git and therefore are not preserved by push/pull.
  • Verbose debug entries can be enabled by setting overleaf-project-debug to t.

About

Project-level Overleaf integration for Emacs

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors