{"id":20565001,"url":"https://github.com/nohzafk/emacs-devcontainer","last_synced_at":"2025-07-01T11:40:15.757Z","repository":{"id":251661065,"uuid":"838025332","full_name":"nohzafk/emacs-devcontainer","owner":"nohzafk","description":"Doom Emacs config works with LSP in Devcontainer","archived":false,"fork":false,"pushed_at":"2024-10-19T20:33:02.000Z","size":22,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-07T19:39:02.695Z","etag":null,"topics":["devcontainer-feature","doom-emacs-configuration","emacs","lsp-client"],"latest_commit_sha":null,"homepage":"","language":"Emacs Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nohzafk.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-04T18:08:29.000Z","updated_at":"2025-03-07T10:25:51.000Z","dependencies_parsed_at":"2024-08-04T22:14:57.424Z","dependency_job_id":"afd6337d-beae-48a5-a2b4-076c8071bbda","html_url":"https://github.com/nohzafk/emacs-devcontainer","commit_stats":null,"previous_names":["nohzafk/emacs-devcontainer"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/nohzafk/emacs-devcontainer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nohzafk%2Femacs-devcontainer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nohzafk%2Femacs-devcontainer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nohzafk%2Femacs-devcontainer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nohzafk%2Femacs-devcontainer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nohzafk","download_url":"https://codeload.github.com/nohzafk/emacs-devcontainer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nohzafk%2Femacs-devcontainer/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262954395,"owners_count":23390411,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["devcontainer-feature","doom-emacs-configuration","emacs","lsp-client"],"created_at":"2024-11-16T04:30:17.726Z","updated_at":"2025-07-01T11:40:15.724Z","avatar_url":"https://github.com/nohzafk.png","language":"Emacs Lisp","funding_links":[],"categories":[],"sub_categories":[],"readme":"* Emacs with LSP in Devcontainer\n\nThis is a [[https://github.com/doomemacs/doomemacs][doom emacs]] configuration of how to use emacs with language server in devcontainer.\n\n- use [[https://github.com/manateelazycat/lsp-bridge][lsp-bridge]] as the LSP client\n- use [[https://github.com/nohzafk/devcontainer-feature-emacs-lsp-bridge][devcontainer-feature-emacs-lsp-bridge]] to install lsp-bridge and the language server inside the container\n- creation of the devcontainer is delegated to VSCode with [[https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers][Dev Containers Extension]]\n\n** status of devcontainer support\n\nCurrently I'm the main contributor of lsp-bridge's devcontainer support. Here I trace the features that I'd like to add, and what I've done for Emacs to work with devcontainer.\n\n| status | scope                |                                                                                        |\n|--------+----------------------+----------------------------------------------------------------------------------------|\n| DONE   | devcontainer-feature | able to install lsp-bridge                                                             |\n| DONE   | devcontainer-feature | able to install any language server that lsp-bridge supports [1]                       |\n| DONE   | devcontainer-feature | daily auto update latest version of lsp-bridge and release                             |\n| DONE   | lsp-bridge           | open container file using =find-file= /docker:                                           |\n| DONE   | lsp-bridge           | enable auto-completion                                                                 |\n| DONE   | lsp-bridge           | save file by =lsp-bridge-remote-save-buffer=                                             |\n| DONE   | lsp-bridge           | format buffer using =apheleia=                                                           |\n| DONE   | lsp-bridge           | jump to definition and jump back                                                       |\n| DONE   | doom-emacs           | ripgrep search in container                                                            |\n| DONE   | doom-emacs           | open vTerm with =bash= in container                                                      |\n| DONE   | devcontainer-feature | instructions of how to setup with =Python= projects                                      |\n| TBD    | devcontainer         | manage container in Emacs with [[https://github.com/nohzafk/cli2eli][CLI2ELI]]                                                 |\n| TBD    | devcontainer         | get rid of VSCode [2]                                                                  |\n| TBD    | lsp-bridge           | auto re-connect to the new container and re-open file if devcontainer has been rebuilt |\n\n\n- [1] Consider it's done, while a few language servers are missing at Nixpkgs or require special setting, also language server which runs on Windows is not supported\n- [2] Currently VSCode is needed as port forward is not implemented by =devcontainer CLI=. POC at [[https://github.com/nohzafk/devcontainer-cli-port-forwarder][devcontainer-cli-port-forwarder]]\n\n* Remote Editing Configuration\n** TRAMP\n- Use =M-x tramp-cleanup-all-connections= to remove all cached connection history.\n- Use =M-x tramp-cleanup-all-buffers= to close all remote buffers.\n\n** install additional tools\nTo install additional tools like =ripgrep= in a devcontainer, you can use the =features/nix=.\n\nAdd this to your [[https://code.visualstudio.com/docs/devcontainers/create-dev-container][devcontainer.json]],\n\n#+begin_src json :tangle no\n{\n  \"features\": {\n    \"ghcr.io/devcontainers/features/nix:1\": {\n       \"packages\": \"ripgrep\"\n    }\n  }\n}\n#+end_src\n\nuse nix to install tools that you want to use in the container.\n\n** tramp-remote-path\nEnsure that =~/.nix-profile/bin= is included in the =PATH= when executing remote commands.\n\n#+begin_src elisp :tangle config.el\n(after! tramp\n  (add-to-list 'tramp-remote-path \"~/.nix-profile/bin\")\n  (add-to-list 'tramp-remote-path 'tramp-own-remote-path))\n#+end_src\n\nthis will make search tools such as =ripgrep.el= and =projectile-ripgrep= works with remote files.\n\n** lsp-bridge\n#+begin_src elisp :tangle packages.el\n(when (package! lsp-bridge\n        :recipe (:host github\n                 :repo \"manateelazycat/lsp-bridge\"\n                 :branch \"master\"\n                 :files (\"*.el\" \"*.py\" \"acm\" \"core\" \"langserver\" \"multiserver\" \"resources\")\n                 :build (:not compile)))\n  ;; doom-emacs has mardown-mode\n  ;; (package! markdown-mode)\n  (package! yasnippet)\n  (package! topsy)\n  (package! flymake-bridge\n    :recipe (:host github :repo \"liuyinz/flymake-bridge\" :branch \"master\")))\n#+end_src\n#+begin_src elisp :tangle config.el\n(use-package! lsp-bridge\n  :config\n\n  ;; for muscle memory to save buffer\n  (defun my/save-buffer ()\n    (interactive)\n    (if lsp-bridge-remote-file-flag\n        (call-interactively #'lsp-bridge-remote-save-buffer)\n      (call-interactively #'save-buffer)))\n\n  (map! \"C-x C-s\" #'my/save-buffer))\n\n(use-package! flymake-bridge\n  :after lsp-bridge\n  :hook (lsp-bridge-mode . flymake-bridge-setup))\n\n(map! :after flymake\n      \"M-n\" #'flymake-goto-next-error\n      \"M-p\" #'flymake-goto-prev-error)\n#+end_src\n\n** formatter support\nEnable =format= feature in =init.el=, it will install the =apheleia= package.\n\nuse =SPC c f= to format the buffer.\n\n#+begin_src elisp :tangle config.el\n(use-package! apheleia\n  :after lsp-bridge\n  :config\n  ;; don't mess up with lsp-mode\n  (setq +format-with-lsp nil)\n  (setq apheleia-remote-algorithm 'remote))\n#+end_src\n\n** remote file indicator\n\nAdd a sticky header to indicate editing remote file\n\n#+begin_src elisp :tangle config.el\n(use-package! topsy\n  :after lsp-bridge\n  :config\n  ;; display a bar to remind editing remote file\n  (setcdr (assoc nil topsy-mode-functions)\n          (lambda ()\n            (when (lsp-bridge-is-remote-file) \"[LBR] REMOTE FILE\")))\n\n  ;; do not activate when the current major mode is org-mode\n  (add-hook 'lsp-bridge-mode-hook (lambda ()\n                                    (unless (derived-mode-p 'org-mode)\n                                      (topsy-mode 1)))))\n#+end_src\n\n** vTerm\nEnable =vterm= feature in =init.el=\n\nuse =/bin/bash= for vterm when editing container file, use =SPC o t= to open vTerm buffer\n\n#+begin_src elisp :tangle config.el\n(after! vterm\n  (defun my/set-vterm-shell ()\n    (when (string-prefix-p \"/docker:\" (file-remote-p default-directory))\n      (when (eq major-mode 'vterm-mode)\n        (let ((shell (if (string-prefix-p \"/docker:\" (file-remote-p default-directory))\n                         \"/bin/bash\"\n                       (or (getenv \"SHELL\") \"/bin/bash\"))))\n          (vterm-send-string (format \"exec %s\\n\" shell))\n          (vterm-send-string \"clear\\n\")))))\n\n  (add-hook 'vterm-mode-hook #'my/set-vterm-shell))\n#+end_src\n\n** how to setup language server for python project (using basedpyright)\nIt should be clearly stated to avoid any confusing that lsp-bridge itself runs\nin a python process, and basedpyright-langserver uses another python process.\n\nNormally you created a virtual environment using tools like *uv* or *pdm* at the\nroot directory, suppose the name of the virtual environment is \".venv\".\n\nYou need to add a section to the *pyproject.toml*, and basedpyright will inspect\nthe virtual environment correctly, [[https://docs.basedpyright.com/latest/configuration/config-files/][more details]].\n\n#+begin_src toml\n[tool.basedpyright]\nvenvPath = \".\"\nvenv = \".venv\"\n#+end_src\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnohzafk%2Femacs-devcontainer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnohzafk%2Femacs-devcontainer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnohzafk%2Femacs-devcontainer/lists"}