Skip to content

Commit

Permalink
Merge pull request #1009 from nohzafk/feature/devcontainer
Browse files Browse the repository at this point in the history
Support lsp-bridge in container correctly
  • Loading branch information
manateelazycat authored Aug 3, 2024
2 parents aa30cd3 + 5f734d0 commit 2363b87
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 53 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,13 @@ start the devcontainer and use `file-find` `/docker:user@container:/path/to/file
more detail please refer to [devcontainer-feature-emacs-lsp-bridge](https://github.com/nohzafk/devcontainer-feature-emacs-lsp-bridge).

If you use `apheleia` as formatter, `lsp-bridge` now support auto formatting file on devcontainer.
```elisp
;; setup PATH for remote command execution
(with-eval-after-load 'tramp
(add-to-list 'tramp-remote-path "~/.nix-profile/bin")
(add-to-list 'tramp-remote-path 'tramp-own-remote-path))
```elsip
(use-package! apheleia
(use-package apheleia
:config
;; which formatter to use
(setf (alist-get 'python-mode apheleia-mode-alist) 'ruff)
Expand Down
2 changes: 1 addition & 1 deletion core/remote_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ def get_container_local_ip(container_name):
result = subprocess.check_output(command, shell=True, text=True).strip()
return result
except subprocess.CalledProcessError:
message_emacs(f"{traceback.format_exc()}")
message_emacs(f"get_container_local_ip error: {traceback.format_exc()}")
return None


Expand Down
87 changes: 41 additions & 46 deletions lsp-bridge.el
Original file line number Diff line number Diff line change
Expand Up @@ -843,9 +843,14 @@ you can customize `lsp-bridge-get-workspace-folder' to return workspace folder p

(defun lsp-bridge-find-file-hook-function ()
(when (and lsp-bridge-enable-with-tramp (file-remote-p (buffer-file-name)))
(lsp-bridge-sync-tramp-remote nil)
(when (string-prefix-p "/docker:" (buffer-file-name))
(lsp-bridge-call-async "open_remote_file" (buffer-file-name) (list :line 0 :character 0)))))
(lsp-bridge-sync-tramp-remote nil)))

(defun lsp-bridge--setup-tramp-docker-buffer (tramp-file-name)
"Setup the buffer of TRAMP-FILE-NAME as if it is a non-file buffer."
(with-current-buffer (get-file-buffer tramp-file-name)
(setq buffer-file-name nil)
(setq buffer-file-truename nil)
(message "set buffer %s buffer-file-name to nil" (buffer-name))))

(add-hook 'find-file-hook #'lsp-bridge-find-file-hook-function)

Expand Down Expand Up @@ -2058,40 +2063,36 @@ Then we need call `lsp-bridge--set-mark-ring-in-new-buffer' in new buffer after
(defun lsp-bridge--set-mark-ring-in-new-buffer ()
(setq-local lsp-bridge-mark-ring (append (list lsp-bridge-position-before-jump) mark-ring)))

(defun lsp-bridge-find-window-match-filename (filename)
(cl-dolist (window (window-list))
(when (string-equal filename (buffer-file-name (window-buffer window)))
(cl-return window))))

(defun lsp-bridge-define--jump (filename filehost position)
(let (lsp-bridge-position-before-jump)
(lsp-bridge--record-mark-ring)

(if (or (string-equal filehost "") lsp-bridge-enable-with-tramp)
(progn
;; filehost sent by lsp-bridge server running inside docker is 127.0.0.1
(when (and lsp-bridge-remote-file-host (string= filehost "127.0.0.1"))
(setq filehost lsp-bridge-remote-file-host))

(setq filename (concat (cdr (assoc filehost lsp-bridge-tramp-alias-alist)) filename))
(let ((match-window (lsp-bridge-find-window-match-filename filename)))
(if (and lsp-bridge-find-def-select-in-open-windows
match-window)
;; Try select to window if `lsp-bridge-find-def-select-in-open-windows' is non-nil.
(select-window match-window)
;; Jump to define.
;; Show define in other window if `lsp-bridge-jump-to-def-in-other-window' is non-nil.
(if lsp-bridge-jump-to-def-in-other-window
(find-file-other-window filename)
(find-file filename))
))
(if (and (not (string= filehost ""))
(not lsp-bridge-enable-with-tramp))
(lsp-bridge-call-async "open_remote_file" (format "%s:%s" filehost filename) position)
;; filehost is not empty or lsp-bridge-enable-with-tramp is t
(when (string= filehost "127.0.0.1")
(setq filehost lsp-bridge-remote-file-host))

(let ((match-window (lsp-bridge--with-file-buffer filename filehost (get-buffer-window))))
;; select the window to display definition
(if match-window
;; if match-window is found, avoid using find-file to open the file twice
(progn
(cond
(lsp-bridge-find-def-select-in-open-windows (select-window match-window))
(lsp-bridge-jump-to-def-in-other-window (select-window match-window))
(t (switch-to-buffer (window-buffer match-window)))))
;; match-window not found, we need to open the file
(let* ((tramp-file-name (concat (cdr (assoc filehost lsp-bridge-tramp-alias-alist)) filename)))
(if lsp-bridge-jump-to-def-in-other-window
(find-file-other-window tramp-file-name)
(find-file tramp-file-name))))

;; Init jump history in new buffer.
(lsp-bridge--set-mark-ring-in-new-buffer)

(lsp-bridge-define--jump-flash position))
(lsp-bridge-call-async "open_remote_file" (format "%s:%s" filehost filename) position))
))
(lsp-bridge-define--jump-flash position)))))

(defun lsp-bridge-define--jump-flash (position)
;; We need call `display' before `goto-char',
Expand Down Expand Up @@ -2813,6 +2814,7 @@ We need exclude `markdown-code-fontification:*' buffer in `lsp-bridge-monitor-be
(defvar-local lsp-bridge-remote-file-host nil)
(defvar-local lsp-bridge-remote-file-port nil)
(defvar-local lsp-bridge-remote-file-path nil)
;; TODO need to consider tramp docker file pattern
(defvar lsp-bridge-remote-file-pattern
(rx bos (? "/")
;; username
Expand Down Expand Up @@ -2851,9 +2853,11 @@ We need exclude `markdown-code-fontification:*' buffer in `lsp-bridge-monitor-be
"Conditionally execute BODY with the buffer associated with TRAMP-FILE-NAME.
If the buffer is created by TRAMP with TRAMP-FILE-NAME, BODY is executed within
the context of that buffer. If the buffer is created by
`lsp-bridge-open-remote-file--response', `lsp-bridge--with-file-buffer' is used
with PATH and HOST to find the buffer, then BODY is executed within that buffer."
the context of that buffer.
If the buffer is created by `lsp-bridge-open-remote-file--response',
`lsp-bridge--with-file-buffer' is used with PATH and HOST to find the buffer,
then BODY is executed within that buffer."

`(if (get-file-buffer ,tramp-file-name)
(with-current-buffer (get-file-buffer ,tramp-file-name)
Expand Down Expand Up @@ -2911,18 +2915,19 @@ I haven't idea how to make lsp-bridge works with `electric-indent-mode', PR are
(port (tramp-file-name-port tramp-vec))
(path (tramp-file-name-localname tramp-vec))
(tramp-connection-info (substring file-name 0 (+ 1 (string-match ":" file-name (+ 1 (string-match ":" file-name))))))
(ip-host (cdr (assoc tramp-connection-info lsp-bridge-tramp-connection-info))))
(connected-host (cdr (assoc tramp-connection-info lsp-bridge-tramp-connection-info))))

(if (or force (not ip-host))
(if (or force (not connected-host))
(when (and (not (member tramp-method '("sudo" "sudoedit" "su" "doas")))
(not (member host lsp-bridge-tramp-blacklist)))
(read-only-mode 1)
(lsp-bridge-call-async "sync_tramp_remote" file-name tramp-method user host port path))
(lsp-bridge--conditional-update-tramp-file-info file-name path ip-host

(lsp-bridge--conditional-update-tramp-file-info file-name path connected-host
(setq-local lsp-bridge-remote-file-flag t)
(setq-local lsp-bridge-remote-file-tramp-method tramp-method)
(setq-local lsp-bridge-remote-file-user user)
(setq-local lsp-bridge-remote-file-host ip-host)
(setq-local lsp-bridge-remote-file-host connected-host)
(setq-local lsp-bridge-remote-file-path path)

(add-hook 'kill-buffer-hook 'lsp-bridge-remote-kill-buffer nil t)
Expand Down Expand Up @@ -2971,7 +2976,6 @@ SSH tramp file name is like /ssh:user@host#port:path"

(with-current-buffer (get-buffer-create buf-name)
(text-mode)

(read-only-mode -1)
(erase-buffer)
(insert (lsp-bridge-decode-base64 content))
Expand Down Expand Up @@ -3007,15 +3011,6 @@ SSH tramp file name is like /ssh:user@host#port:path"
;; Remote file can always edit and update content even some file haven't corresponding lsp server, such as *.txt
(lsp-bridge-mode 1))

(when (string-equal tramp-method "docker")
(let ((tramp-filename (lsp-bridge-construct-tramp-file-name lsp-bridge-remote-file-tramp-method
lsp-bridge-remote-file-user
lsp-bridge-remote-file-host
lsp-bridge-remote-file-port
lsp-bridge-remote-file-path)))
;; use `find-file' to open TRAMP docker file will open a tramp buffer, kill it
(kill-buffer (get-file-buffer tramp-filename))))

(when lsp-bridge-ref-open-remote-file-go-back-to-ref-window
(lsp-bridge-switch-to-ref-window)
(setq lsp-bridge-ref-open-remote-file-go-back-to-ref-window nil)))
Expand Down
8 changes: 4 additions & 4 deletions lsp_bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,8 @@ def init_search_backends(self):

@threaded
def init_remote_file_server(self):
print("* Running lsp-bridge in remote server, "
"use command 'lsp-bridge-open-remote-file' to open remote file, "
"or 'find-file' /docker: to open file in running container.")
print("* Running lsp-bridge on remote server. "
"Access files with 'lsp-bridge-open-remote-file' or 'find-file /docker:...'")

# Build loop for remote files management.
self.file_server = FileSyncServer("0.0.0.0", REMOTE_FILE_SYNC_CHANNEL)
Expand Down Expand Up @@ -437,6 +436,7 @@ def sync_tramp_remote(self, tramp_file_name, tramp_method, server_username, serv
self.remote_sync(container_name, tramp_connection_info)
# container_name is used for emacs buffer local variable lsp-bridge-remote-file-host
eval_in_emacs("lsp-bridge-update-tramp-file-info", tramp_file_name, tramp_connection_info, tramp_method, container_user, container_name, path)
eval_in_emacs("lsp-bridge--setup-tramp-docker-buffer", tramp_file_name)
self.sync_tramp_remote_complete_event.set()
except Exception as e:
logger.exception(e)
Expand Down Expand Up @@ -510,7 +510,7 @@ def open_remote_file(self, path, jump_define_pos):
"jump_define_pos": epc_arg_transformer(jump_define_pos)
})
else:
message_emacs("Please input valid path match rule: 'ip:/path/file'.")
message_emacs(f"Unsupported remote path {path}")

@threaded
def update_remote_file(self, remote_file_host, remote_file_path, content):
Expand Down

0 comments on commit 2363b87

Please sign in to comment.