copilot.el

repository·main·Indexed 25 days ago

https://github.com/copilot-emacs/copilot.el

An Emacs plugin for GitHub Copilot that provides inline completions (ghost text), an interactive chat interface, and Next Edit Suggestions (NES) using the official GitHub Copilot language server. It includes support for agent modes, Model Context Protocol (MCP) servers, and integration with Doom Emacs and Spacemacs.

Tokens
6.8K
Snippets
17
Records
32
Agent score
31%

What's inside copilot.el

  1. How copilot.el architecture works

    main

    copilot.el is an Emacs client for GitHub Copilot that communicates with the @github/copilot-language-server via JSON-RPC. It is designed as a single global server instance (copilot--connection) shared across all buffers and projects in an Emacs session.

    The architecture is modular, consisting of five primary components:

    • copilot.el (Core): Manages server lifecycle, document synchronization, authentication, and inline completions.
    • copilot-chat.el: Provides a Chat UI using conversation/* JSON-RPC methods.
    • copilot-nes.el: Provides Next Edit Suggestions (NES) via textDocument/copilotInlineEdit.
    • copilot-balancer.el: A standalone Lisp parentheses post-processor for completions.
    • copilot-menu.el: A Transient menu (copilot-menu) for interactive commands.

    Chat and NES are self-contained modules that depend on the core for server connections but can be enabled or disabled independently.

  2. How the completion pipeline works

    main

    The inline completion flow follows these stages:

    1. Trigger: copilot--post-command checks predicates and schedules copilot-complete via an idle timer (configured by copilot-idle-delay).
    2. Request: copilot--get-completion sends a textDocument/inlineCompletion request. Any pending requests are cancelled via $/cancelRequest.
    3. Response: The server returns completion items which are cached in copilot--completion-cache for cycling.
    4. Post-processing: In Lisp modes, copilot-balancer-fix-completion rebalances parentheses.
    5. Display: copilot--display-overlay-completion renders the text as a ghost-text overlay using the copilot-completion-map keymap.
    6. Acceptance: copilot-accept-completion inserts the text. Partial acceptance (by word, line, etc.) inserts a prefix and sends textDocument/didPartiallyAcceptCompletion to the server.

    Users can cycle through cached alternatives using copilot-next-completion and copilot-previous-completion without new server requests.

  3. How Chat and Next Edit Suggestions (NES) work

    main

    Both Chat and NES are independent modules that layer on top of the core infrastructure.

    Chat (copilot-chat.el)

    Manages conversations using conversation/create, conversation/turn, and conversation/destroy methods. Responses stream in via $/progress notifications. It also registers a conversation/context request handler so the server can retrieve editor context (file, cursor, source text). The UI is contained in a *copilot-chat* buffer.

    Next Edit Suggestions (copilot-nes.el)

    Predicts edits based on recent history using textDocument/copilotInlineEdit. It displays suggestions as two overlays: one for deleted text (strikethrough) and one for inserted text. Unlike inline completions, NES can modify or delete text anywhere in the file. Acceptance is a two-step process: the first TAB press jumps to the edit location, and the second applies it.

  4. Document synchronization and UTF-16 offsets

    main

    copilot.el uses track-changes (Emacs 30+) to send incremental textDocument/didChange notifications.

    Key technical requirements:

    • Offsets: All positions must use UTF-16 code-unit offsets as required by the LSP specification. The function copilot--utf16-offset is used to handle characters outside the Basic Multilingual Plane.
    • Lifecycle Notifications:
      • textDocument/didOpen: Sent when a buffer with copilot-mode active first gains focus.
      • textDocument/didFocus: Sent on subsequent focus changes.
      • textDocument/didClose: Sent when the buffer is killed or copilot-mode is disabled.
    • Truncation: For large buffers, text is truncated based on copilot-max-char (default 100,000 characters) using a windowing strategy centered around the point.
  5. Quick Start with Copilot.el

    main

    To get started with copilot.el, add the following configuration to your Emacs setup to enable it in programming modes and bind common completion keys. After configuring, you must run two commands to finalize the setup:

    1. M-x copilot-install-server to download the language server.
    2. M-x copilot-login to authenticate with GitHub.
    (use-package copilot
      :ensure t
      :hook (prog-mode . copilot-mode)
      :bind (:map copilot-completion-map
                  ("<tab>" . copilot-accept-completion)
                  ("TAB" . copilot-accept-completion)
                  ("C-<tab>" . copilot-accept-completion-by-word)
                  ("C-TAB" . copilot-accept-completion-by-word)
                  ("C-n" . copilot-next-completion)
                  ("C-p" . copilot-previous-completion)))
  6. Install Copilot.el in Doom Emacs

    main

    To use copilot.el in Doom Emacs, follow these two steps:

    1. Add the package definition to ~/.doom.d/packages.el:
    (package! copilot
      :recipe (:host github :repo "copilot-emacs/copilot.el" :files ("*.el")))
    1. Configure it in ~/.doom.d/config.el:
    ;; accept completion from copilot and fallback to company
    (use-package! copilot
      :hook (prog-mode . copilot-mode)
      :bind (:map copilot-completion-map
                  ("<tab>" . 'copilot-accept-completion)
                  ("TAB" . 'copilot-accept-completion)
                  ("C-TAB" . 'copilot-accept-completion-by-word)
                  ("C-<tab>" . 'copilot-accept-completion-by-word)))

    Note: It is strongly recommended to enable the childframe option in your company module ((company +childframe)) to prevent overlay conflicts.

  7. Configure Copilot Network Proxy and TLS

    main

    Network Proxy

    Set copilot-network-proxy using the following format: '(:host "HOST" :port PORT :username "USER" :password "PASS").

    (setq copilot-network-proxy '(:host "127.0.0.1" :port 7890))

    Handling TLS-inspecting Proxies (e.g., Zscaler)

    If your proxy intercepts TLS and uses self-signed certificates, you have two options:

    1. Tell the language server to reject unauthorized certificates:

      (setq copilot-network-proxy '(:host "127.0.0.1" :port 7890 :rejectUnauthorized :json-false))
    2. Make the server trust your CA by exporting NODE_EXTRA_CA_CERTS before starting Emacs:

      export NODE_EXTRA_CA_CERTS=/path/to/ca-chain.pem
      emacs

      Alternatively, set it via (setenv "NODE_EXTRA_CA_CERTS" "...") in your config, provided it is done before the language server process starts.

  8. Use on-demand completions with `copilot-complete`

    main
    You do not need to enable copilot-mode globally to use Copilot. You can call M-x copilot-complete manually in any buffer. This will automatically start the server and open the document. To dismiss a suggestion, use copilot-clear-overlay or simply continue typing.
    M-x copilot-complete
  9. Enable Copilot completions

    main

    You can enable Copilot completions automatically for programming buffers using copilot-mode. Alternatively, you can enable it globally using global-copilot-mode.

    To customize when completions trigger or are displayed, use the following predicate functions:

    • copilot-enable-predicates / copilot-disable-predicates (triggering)
    • copilot-enable-display-predicates / copilot-disable-display-predicates (displaying)

    For manual control, you can call copilot-complete directly and use copilot-clear-overlay in a post-command-hook to dismiss them.

  10. Install Copilot.el on Emacs 30+ using :vc

    main

    For Emacs 30 and newer, you can install directly from the GitHub repository using the :vc keyword in use-package.

    (use-package copilot
      :vc (:url "https://github.com/copilot-emacs/copilot.el"
                :rev :newest
                :branch "main"))
  11. Use the Copilot Menu for quick access

    main

    M-x copilot-menu opens a transient menu (built on the transient package) that provides one-keystroke access to common commands. It serves as a status overview, showing the current state of copilot-mode, agent mode, and the selected chat model. It includes sections for completions, chat, agent mode, account/usage info, and server management.

    Note: On Emacs 27.2, transient may not be available, but copilot.el will still function normally.

    If you don't want to use the menu, you can always use M-x copilot- followed by TAB to search for commands.

    M-x copilot-menu