Skip to content

Commit

Permalink
Merge pull request #731 from werhner/work-with-tramp
Browse files Browse the repository at this point in the history
lsp-bridge can work with tramp
  • Loading branch information
manateelazycat committed Oct 11, 2023
2 parents a6b83b6 + 18f2b87 commit 303d3d1
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 12 deletions.
2 changes: 1 addition & 1 deletion core/remote_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ def handle_close_file(self, data, client_socket):
path = data["path"]

if path in self.file_dict:
self.file_dict[path] = ""
del self.file_dict[path]

def save_ip_to_file(ip, filename):
with open(filename, 'r') as f:
Expand Down
9 changes: 6 additions & 3 deletions core/search_file_words.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,13 @@ def index_file(self, filepath, content):

self.search_words_queue.put("search_words")

def load_file(self, filepath):
def load_file(self, filepath, from_file_server=False):
try:
with open(filepath) as f:
content = f.read()
if from_file_server:
content = get_file_content_from_file_server(filepath)
else:
with open(filepath) as f:
content = f.read()
except:
return

Expand Down
11 changes: 11 additions & 0 deletions core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,14 @@ def get_buffer_content(filename, buffer_name):
else:
return get_emacs_func_result('get-buffer-content', buffer_name)

def get_file_content_from_file_server(filename):
global remote_file_server

if filename in remote_file_server.file_dict:
return remote_file_server.file_dict[filename]
else:
return ""

def get_current_line():
return get_emacs_func_result('get-current-line')

Expand Down Expand Up @@ -423,6 +431,9 @@ def split_ssh_path(ssh_path):
else:
return None

def is_remote_path(filepath):
return filepath.startswith("/ssh:")

def eval_sexp_in_emacs(sexp):
epc_client.call("eval-in-emacs", [sexp])

Expand Down
65 changes: 57 additions & 8 deletions lsp-bridge.el
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@
:group 'applications)

(require 'acm)
(require 'tramp)
(defvar lsp-bridge-tramp-alias-alist nil)

(setq acm-backend-lsp-fetch-completion-item-func 'lsp-bridge-fetch-completion-item-info)

Expand Down Expand Up @@ -649,6 +651,15 @@ you can customize `lsp-bridge-get-workspace-folder' to return workspace folder p
"Open characters for string interpolation. The elements are cons cell (major-mode . open-char-regexp)"
:type 'cons)

(defvar lsp-bridge-enable-with-tramp nil
"Whether enable lsp-bridge when editing tramp file.")

(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)))

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

(defun lsp-bridge--get-indent-width (mode)
"Get indentation offset for MODE."
(or (alist-get mode lsp-bridge-formatting-indent-alist)
Expand Down Expand Up @@ -690,9 +701,11 @@ So we build this macro to restore postion after code format."
(defun lsp-bridge-get-match-buffer-by-remote-file (host path)
(cl-dolist (buffer (buffer-list))
(with-current-buffer buffer
(when (string-equal (buffer-name) (format "[LBR] %s" (file-name-nondirectory path)))
(cl-return buffer))
)))
(when (and (boundp 'lsp-bridge-remote-file-path)
(string-equal lsp-bridge-remote-file-path path)
(boundp 'lsp-bridge-remote-file-host)
(string-equal lsp-bridge-remote-file-host host))
(cl-return buffer)))))

(defun lsp-bridge-get-match-buffer-by-filepath (name)
(cl-dolist (buffer (buffer-list))
Expand Down Expand Up @@ -1389,7 +1402,7 @@ So we build this macro to restore postion after code format."
;; Codeium search.
(when (and acm-enable-codeium
;; Codeium backend not support remote file now, disable it temporary.
(not (lsp-bridge-is-remote-file))
(or (not (lsp-bridge-is-remote-file)) lsp-bridge-use-local-codeium)
;; Don't enable codeium on Markdown mode, Org mode, ielm and minibuffer, very disruptive to writing.
(not (or (derived-mode-p 'markdown-mode)
(eq major-mode 'org-mode)
Expand Down Expand Up @@ -1489,8 +1502,7 @@ So we build this macro to restore postion after code format."
(defun lsp-bridge-search-words-update (begin-pos end-pos change-text)
(if (lsp-bridge-is-remote-file)
(progn
(lsp-bridge-remote-save-buffer)
(lsp-bridge-remote-send-func-request "search_file_words_load_file" (list lsp-bridge-remote-file-path)))
(lsp-bridge-remote-send-func-request "search_file_words_load_file" (list lsp-bridge-remote-file-path t)))
(when (lsp-bridge-epc-live-p lsp-bridge-epc-process)
(lsp-bridge-call-async "search_file_words_change_buffer"
(buffer-name)
Expand Down Expand Up @@ -1697,8 +1709,9 @@ Off by default."
(let (position-before-jump)
(lsp-bridge-define--jump-record-postion)

(if (string-equal filehost "")
(if (or (string-equal filehost "") lsp-bridge-enable-with-tramp)
(progn
(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)
Expand Down Expand Up @@ -2232,6 +2245,9 @@ We need exclude `markdown-code-fontification:*' buffer in `lsp-bridge-monitor-be
(= after-point buffer-max)
max-num-results))))

(defvar lsp-bridge-use-local-codeium nil
"Whether use local codeium when editing remote file.")

(defun lsp-bridge-codeium-complete ()
(interactive)
(let ((all-text (buffer-substring-no-properties (point-min) (point-max)))
Expand All @@ -2241,7 +2257,7 @@ We need exclude `markdown-code-fontification:*' buffer in `lsp-bridge-monitor-be
(while (not (alist-get mode acm-backend-codeium-language-alist))
(setq mode (get mode 'derived-mode-parent)))
(alist-get mode acm-backend-codeium-language-alist))))
(if (lsp-bridge-is-remote-file)
(if (and (lsp-bridge-is-remote-file) (not lsp-bridge-use-local-codeium))
(lsp-bridge-remote-send-func-request "codeium_complete"
(list
(1- (point))
Expand Down Expand Up @@ -2368,6 +2384,39 @@ We need exclude `markdown-code-fontification:*' buffer in `lsp-bridge-monitor-be
(split-string (buffer-string) "\n" t)))))
(lsp-bridge-call-async "open_remote_file" path (list :line 0 :character 0))))

(defun lsp-bridge-sync-tramp-remote ()
(interactive)
(let* ((tramp-file-name (tramp-dissect-file-name (buffer-file-name)))
(username (tramp-file-name-user tramp-file-name))
(domain (tramp-file-name-domain tramp-file-name))
(port (tramp-file-name-port tramp-file-name))
(host (tramp-file-name-host tramp-file-name))
(path (tramp-file-name-localname tramp-file-name))
alias)

(unless (network-lookup-address-info host 'ipv4 'numeric)
(setq alias host))

(if alias
(if-let (alias-host (assoc alias lsp-bridge-tramp-alias-alist))
(setq host (cdr alias-host))
(let ((default-directory "~/"))
(setq host (string-trim (shell-command-to-string
(format "ssh -G -T %s | grep '^hostname' | cut -d ' ' -f 2" alias)))))
(push `(,alias . ,host) lsp-bridge-tramp-alias-alist)))

(unless (assoc host lsp-bridge-tramp-alias-alist)
(push `(,host . ,(concat (string-join (butlast (string-split (buffer-file-name) ":" t)) ":") ":"))
lsp-bridge-tramp-alias-alist))

(lsp-bridge-call-async "sync_tramp_remote" username host port alias)

(setq-local lsp-bridge-remote-file-flag t)
(setq-local lsp-bridge-remote-file-host host)
(setq-local lsp-bridge-remote-file-path path)

(add-hook 'kill-buffer-hook 'lsp-bridge-remote-kill-buffer nil t)))

(defun lsp-bridge-open-remote-file--response(server path content position)
(let ((buf-name (format "[LBR] %s" (file-name-nondirectory path))))
(lsp-bridge-define--jump-record-postion)
Expand Down
46 changes: 46 additions & 0 deletions lsp_bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import traceback
import json
import socket

from functools import wraps
from pathlib import Path

Expand Down Expand Up @@ -236,6 +237,49 @@ def open_remote_file(self, path, jump_define_pos):
else:
message_emacs("Please input valid path match rule: 'ip:/path/file'.")

@threaded
def sync_tramp_remote(self, server_username, server_host, ssh_port, alias):
import paramiko
if alias:
if alias in self.host_names:
server_host = self.host_names[alias]["server_host"]
server_username = self.host_names[alias]["username"]
ssh_port = self.host_names[alias]["ssh_port"]
else:
ssh_config = paramiko.SSHConfig()
ssh_config.parse(open(os.path.expanduser('~/.ssh/config')))
conf = ssh_config.lookup(alias)

server_host = conf.get('hostname', server_host)
server_username = conf.get('user', server_username)
ssh_port = conf.get('port', ssh_port)

self.host_names[alias] = {"server_host": server_host, "username": server_username, "ssh_port": ssh_port}

if not server_username:
if server_host in self.host_names:
server_username = self.host_names[server_host]["username"]
else:
server_username = "root"

if not ssh_port:
if server_host in self.host_names:
ssh_port = self.host_names[server_host]["ssh_port"]
else:
ssh_port = 22

self.host_names[server_host] = {"username": server_username, "ssh_port": ssh_port}

try:
client_id = f"{server_host}:{REMOTE_FILE_ELISP_CHANNEL}"
if client_id not in self.client_dict:
client = self.get_socket_client(server_host, REMOTE_FILE_ELISP_CHANNEL)
client.send_message("Connect")
message_emacs(f"Connect {server_username}@{server_host}#{ssh_port}...")

except paramiko.ssh_exception.ChannelException:
message_emacs(f"Connect {server_username}@{server_host}:{ssh_port} failed, please make sure `lsp_bridge.py` has start at server.")

@threaded
def save_remote_file(self, remote_file_host, remote_file_path):
self.send_remote_file_message(remote_file_host, {
Expand Down Expand Up @@ -682,6 +726,8 @@ def maybe_create_org_babel_server(self, filepath):

def build_file_action_function(self, name):
def _do(filepath, *args):
if is_remote_path(filepath):
return
open_file_success = True

if not is_in_path_dict(FILE_ACTION_DICT, filepath):
Expand Down

0 comments on commit 303d3d1

Please sign in to comment.