|
| 1 | +# Emacs TRAMP |
| 2 | + |
| 3 | +[Emacs TRAMP](https://www.emacswiki.org/emacs/TrampMode) is a method of running |
| 4 | +editing operations on a remote server. |
| 5 | + |
| 6 | +## Connecting To A Workspace |
| 7 | + |
| 8 | +To connect to your workspace first run: |
| 9 | + |
| 10 | +``` |
| 11 | +coder config-ssh |
| 12 | +``` |
| 13 | + |
| 14 | +Then you can connect to your workspace by its name in the format: |
| 15 | +`coder.<WORKSPACE NAME>`. |
| 16 | + |
| 17 | +In Emacs type `C-x d` and then input: `/-:coder.<WORKSPACE NAME>:` and hit |
| 18 | +enter. This will open up Dired on the workspace's home directory. |
| 19 | + |
| 20 | +### Using SSH |
| 21 | + |
| 22 | +By default Emacs TRAMP is setup to use SCP to access files on the Coder |
| 23 | +workspace instance. However you might want to use SSH if you have a jumpbox or |
| 24 | +some other complex network setup. |
| 25 | + |
| 26 | +To do so set the following in your Emacs `init.el` file: |
| 27 | + |
| 28 | +```lisp |
| 29 | +(setq tramp-default-method "ssh") |
| 30 | +``` |
| 31 | + |
| 32 | +Then when you access the workspace instance via `/-:coder.<WORKSPACE NAME>` |
| 33 | +Emacs will use SSH. Setting `tramp-default-method` will also tell `ansi-term` |
| 34 | +mode the correct way to access the remote when directory tracking. |
| 35 | + |
| 36 | +## Directory Tracking |
| 37 | + |
| 38 | +### ansi-term |
| 39 | + |
| 40 | +If you run your terminal in Emacs via `ansi-term` then you might run into a |
| 41 | +problem where while SSH-ed into a workspace Emacs will not change its |
| 42 | +`default-directory` to open files in the directory your shell is in. |
| 43 | + |
| 44 | +To fix this: |
| 45 | + |
| 46 | +1. In your workspace Terraform template be sure to add the following: |
| 47 | + |
| 48 | + ```hcl |
| 49 | + data "coder_workspace" "me" { |
| 50 | + } |
| 51 | +
|
| 52 | + resource "coder_agent" "main" { |
| 53 | + # ... |
| 54 | + env = { |
| 55 | + name = "CODER_WORKSPACE_NAME" |
| 56 | + value = data.coder_workspace.me.name |
| 57 | + } |
| 58 | + } |
| 59 | + ``` |
| 60 | + |
| 61 | +2. Next in the shell profile file on the workspace (ex., `~/.bashrc` for Bash |
| 62 | + and `~/.zshrc` for Zsh) add the following: |
| 63 | + |
| 64 | + ```bash |
| 65 | + ansi_term_announce_host() { |
| 66 | + printf '\033AnSiTh %s\n' "coder.$CODER_WORKSPACE_NAME" |
| 67 | + } |
| 68 | + |
| 69 | + ansi_term_announce_user() { |
| 70 | + printf '\033AnSiTu %s\n' "$USER" |
| 71 | + } |
| 72 | + |
| 73 | + ansi_term_announce_pwd() { |
| 74 | + printf '\033AnSiTc %s\n' "$PWD" |
| 75 | + } |
| 76 | + |
| 77 | + ansi_term_announce() { |
| 78 | + ansi_term_announce_host |
| 79 | + ansi_term_announce_user |
| 80 | + ansi_term_announce_pwd |
| 81 | + } |
| 82 | + |
| 83 | + cd() { command cd "$@"; ansi_term_announce_pwd; } |
| 84 | + pushd() { command pushd "$@"; ansi_term_announce_pwd; } |
| 85 | + popd() { command popd "$@"; ansi_term_announce_pwd; } |
| 86 | + |
| 87 | + ansi_term_announce |
| 88 | + ``` |
| 89 | + |
| 90 | + Ansi Term expects the terminal running inside of it to send escape codes to |
| 91 | + inform Emacs of the hostname, user, and working directory. The above code |
| 92 | + sends these escape codes and associated data whenever the terminal logs in |
| 93 | + and whenever the directory changes. |
| 94 | + |
| 95 | +### eshell |
| 96 | + |
| 97 | +The `eshell` mode will perform directory tracking by default, no additional |
| 98 | +configuration is needed. |
| 99 | + |
| 100 | +## Language Servers (Code Completion) |
| 101 | + |
| 102 | +If you use [`lsp-mode`](https://emacs-lsp.github.io/lsp-mode) for code |
| 103 | +intelligence and completion some additional configuration is required. |
| 104 | + |
| 105 | +In your Emacs `init.el` file you must register a LSP client and tell `lsp-mode` |
| 106 | +how to find it on the remote machine using the `lsp-register-client` function. |
| 107 | +For each LSP server you want to use in your workspace add the following: |
| 108 | + |
| 109 | +```lisp |
| 110 | +(lsp-register-client (make-lsp-client :new-connection (lsp-tramp-connection "<LSP SERVER BINARY>") |
| 111 | + :major-modes '(<LANGUAGE MODE>) |
| 112 | + :remote? t |
| 113 | + :server-id '<LANGUAGE SERVER ID>)) |
| 114 | +``` |
| 115 | + |
| 116 | +This tells `lsp-mode` to look for a language server binary named |
| 117 | +`<LSP SERVER BINARY>` for use in `<LANGUAGE MODE>` on a machine named |
| 118 | +`coder.<WORKSPACE NAME>`. Be sure to replace the values between angle brackets: |
| 119 | + |
| 120 | +- `<LSP SERVER BINARY>` : The name of the language server binary, without any |
| 121 | + path components. For example to use the Deno Javascript language server use |
| 122 | + the value `deno`. |
| 123 | +- `<LANGUAGE MODE>`: The name of the Emacs major mode for which the language |
| 124 | + server should be used. For example to enable the language server for |
| 125 | + Javascript development use the value `web-mode`. |
| 126 | +- `<LANGUAGE SERVER ID>`: This is just the name that `lsp-mode` will use to |
| 127 | + refer to this language server. If you are ever looking for output buffers or |
| 128 | + files they may have this name in them. |
| 129 | + |
| 130 | +Calling the `lsp-register-client` function will tell `lsp-mode` the name of the |
| 131 | +LSP server binary. However this binary must be accessible via the path. If the |
| 132 | +language server binary is not in the path you must modify `tramp-remote-path` so |
| 133 | +that `lsp-mode` knows in what directories to look for the LSP server. To do this |
| 134 | +use TRAMP's connection profiles functionality. These connection profiles let you |
| 135 | +customize variables depending on what machine you are connected to. Add the |
| 136 | +following to your `init.el`: |
| 137 | + |
| 138 | +```lisp |
| 139 | +(connection-local-set-profile-variables 'remote-path-lsp-servers |
| 140 | + '((tramp-remote-path . ("<PATH TO ADD>" tramp-default-remote-path)))) |
| 141 | +(connection-local-set-profiles '(:machine "coder.<WORKSPACE NAME>") 'remote-path-lsp-servers) |
| 142 | +``` |
| 143 | + |
| 144 | +The `connection-local-set-profile-variables` function creates a new connection |
| 145 | +profile by the name `remote-path-lsp-servers`. The |
| 146 | +`connection-local-set-profiles` then indicates this `remote-path-lsp-servers` |
| 147 | +connection profile should be used when connecting to a server named |
| 148 | +`coder.<WORKSPACE NAME>`. Be sure to replace `<PATH TO ADD>` with the directory |
| 149 | +in which a LSP server is present. |
| 150 | + |
| 151 | +TRAMP and `lsp-mode` are fickle friends, sometimes there is weird behavior. If |
| 152 | +you find that language servers are hanging in the `starting` state then |
| 153 | +[it might be helpful](https://github.com/emacs-lsp/lsp-mode/issues/2709#issuecomment-800868919) |
| 154 | +to set the `lsp-log-io` variable to `t`. |
| 155 | + |
| 156 | +More details on configuring `lsp-mode` for TRAMP can be found |
| 157 | +[in the `lsp-mode` documentation](https://emacs-lsp.github.io/lsp-mode/page/remote/). |
| 158 | +The |
| 159 | +[TRAMP `tramp-remote-path` documentation](https://www.gnu.org/software/emacs/manual/html_node/tramp/Remote-programs.html#Remote-programs) |
| 160 | +contains more examples and details of connection profiles. |
0 commit comments