今天又玩了一下 lsp-mode, python 和 ruby 都可以很好的工作了.
只是有一个小不爽, 当 kill ruby buffer 以后, 会导致一下的错误:
Debugger entered--Lisp error: (error "lsp-ruby TCP connection: Cannot communicate with the process (closed)")
signal(error ("lsp-ruby TCP connection: Cannot communicate with the process (closed)"))
error("%s: Cannot communicate with the process (%s)" "lsp-ruby TCP connection" closed)
(progn (error "%s: Cannot communicate with the process (%s)" (process-name proc) (process-status proc)))
(if (memq (process-status proc) '(stop exit closed failed nil)) (progn (error "%s: Cannot communicate with the process (%s)" (process-name proc) (process-status proc))))
lsp--send-no-wait("Content-Length: 3939\15\n\15\n{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didOpen\",\"params\":{\"textDocument\":{\"uri\":\"file:///Users/andy/tower-ng/app/controllers/members_controller.rb\",\"languageId\":\"ruby\",\"version\":0,\"text\":\"# frozen_string_literal: true\\n\\n# Control team member.\\nclass MembersController < ApplicationController\\n def index\\n # Create memeber array.\\n @member_array = []\\n\\n # Push creator at first.\\n team = current_team\\n team_creator = User.find_by_email(team.creator)\\n\\n @member_array.push(user_hashid: team_creator.hashid,\\n name: team_creator.name,\\n type: \\\"超级管理员\\\",\\n email: team_creator.email,\\n color: \\\"member-type-super-admin\\\",\\n photo_url: current_user.avatar_url)\\n\\n # Push team members.\\n TeamAdmin.select { |t| t.team_id == team.id }.each do |team_admin|\\n user = User.find_by_id(team_admin.user_id)\\n\\n member_type = team_admin.is_administrator ? \\\"管理员\\\" : \\\"成员\\\"\\n member_color = team_admin.is_administrator ? \\\"member-type-admin\\\" : \\\"member-type-member\\\"\\n\\n if user&.activated?\\n @member_array.push(user_hashid: user.hashid,\\n name: user.name,\\n type: member_type,\\n email: user.email,\\n color: member_color,\\n photo_url: user.avatar_url)\\n\\n elsif !user.nil?\\n @member_array.push(user_hashid: user.hashid,\\n name: user.email.split(\\\"@\\\")[0],\\n type: \\\"已邀请\\\",\\n email: user.email,\\n color: member_color,\\n photo_url: user.avatar_url)\\n\\n end\\n end\\n end\\n\\n def new; end\\n\\n def show\\n @project = Project.find_by_hashid(params[:id])\\n @user = User.find_by_hashid(params[:id])\\n\\n if @user&.activated?\\n redirect_to user_path(@user.id)\\n else\\n @user_name = @user.email.split(\\\"@\\\")[0]\\n end\\n end\\n\\n def create\\n params[:members].values.reverse.uniq { |m| m[0] }.reverse_each do |member|\\n user = User.find_by_email(member[0])\\n\\n unless user\\n user = User.new(email: member[0])\\n user.save\\n\\n print(\\\"Send activation mail: \\\", edit_account_activation_url(user.activation_token, email: user.email, team_id: current_team.hashid), \\\"\\\\n\\\")\\n end\\n\\n team_admin = TeamAdmin.new(team_id: current_team.id, user_id: user.id, is_administrator: member[1] == \\\"admin\\\")\\n team_admin.save\\n end\\n\\n redirect_to team_members_path\\n end\\n\\n def edit\\n if params[:action_type] == \\\"cancel_invite\\\"\\n\\n user = User.find_by_hashid(params[:id])\\n\\n if user&.activated?\\n redirect_to user_path(user.id)\\n else\\n team_admin = TeamAdmin.find_by_user_id(user.id)\\n team_admin&.destroy\\n\\n user&.destroy\\n\\n respond_to do |format|\\n format.json do\\n render json: { status: \\\"successful\\\",\\n redirect: team_members_url(current_team.hashid) }\\n end\\n end\\n end\\n\\n elsif params[:action_type] == \\\"resend_invite_email\\\"\\n\\n user = User.find_by_hashid(params[:id])\\n\\n if user&.activated?\\n redirect_to user_path(user.id)\\n else\\n user_activation_token = User.new_token\\n user_activation_digest = User.digest(user_activation_token)\\n user.update_attribute(:activation_digest, user_activation_digest)\\n\\n print(\\\"Send activation mail: \\\", edit_account_activation_url(user_activation_token, email: user.email, team_id: current_team.hashid), \\\"\\\\n\\\")\\n\\n respond_to do |format|\\n format.json do\\n render json: { status: \\\"successful\\\" }\\n end\\n end\\n end\\n\\n end\\n end\\nend\\n\"}}}" #<process lsp-ruby TCP connection>)
lsp--text-document-did-open()
(let* ((root (file-truename (funcall (progn (or (and ... t) (signal ... ...)) (aref client 7))))) (workspace (gethash root lsp--workspaces)) new-conn response init-params parser proc cmd-proc) (if workspace (progn (setq lsp--cur-workspace workspace) (lsp-mode 1)) (progn (setq parser (record 'lsp--parser nil nil 'nil nil nil nil 0 nil nil nil nil)) (setq lsp--cur-workspace (make-lsp--workspace :parser parser :file-versions (make-hash-table :test 'equal) :root root :client client)) (progn (or (and (memq (type-of parser) cl-struct-lsp--parser-tags) t) (signal 'wrong-type-argument (list 'lsp--parser parser))) (let* ((v parser)) (aset v 11 lsp--cur-workspace))) (setq new-conn (funcall (progn (or (and ... t) (signal ... ...)) (aref client 5)) (lsp--parser-make-filter parser (progn (or ... ...) (aref client 8))) (lsp--make-sentinel lsp--cur-workspace))) (setq cmd-proc (if (consp new-conn) (car new-conn) new-conn)) (setq proc (if (consp new-conn) (cdr new-conn) new-conn)) (progn (or (and (memq (type-of lsp--cur-workspace) cl-struct-lsp--workspace-tags) t) (signal 'wrong-type-argument (list 'lsp--workspace lsp--cur-workspace))) (let* ((v lsp--cur-workspace)) (aset v 8 proc))) (progn (or (and (memq (type-of lsp--cur-workspace) cl-struct-lsp--workspace-tags) t) (signal 'wrong-type-argument (list 'lsp--workspace lsp--cur-workspace))) (let* ((v lsp--cur-workspace)) (aset v 9 cmd-proc)))) (puthash root lsp--cur-workspace lsp--workspaces) (lsp-mode 1) (run-hooks 'lsp-before-initialize-hook) (setq init-params (list ':processId (emacs-pid) ':rootPath root ':rootUri (concat lsp--uri-file-prefix (url-hexify-string (file-truename root) url-path-allowed-chars)) ':capabilities (lsp--client-capabilities) ':initializationOptions (if (functionp extra-init-params) (funcall extra-init-params lsp--cur-workspace) extra-init-params))) (setq response (lsp--send-request (plist-put (progn (progn (or ... ...) nil) (list :jsonrpc "2.0" :method "initialize" :params init-params)) :id (progn (or (and ... t) (signal ... ...)) (let* (...) (aset v 14 ...)))))) (if response nil (signal 'lsp-empty-response-error (list "initialize"))) (progn (or (and (memq (type-of lsp--cur-workspace) cl-struct-lsp--workspace-tags) t) (signal 'wrong-type-argument (list 'lsp--workspace lsp--cur-workspace))) (let* ((v lsp--cur-workspace)) (aset v 3 (gethash "capabilities" response)))) (lsp--send-no-wait (let* ((json-encoding-pretty-print lsp-print-io) (json-false :json-false) (body (json-encode (progn ... ...)))) (format "Content-Length: %d\15\n\15\n%s" (string-bytes body) body)) (progn (or (and (memq (type-of lsp--cur-workspace) cl-struct-lsp--workspace-tags) t) (signal 'wrong-type-argument (list 'lsp--workspace lsp--cur-workspace))) (aref lsp--cur-workspace 8))) (run-hooks 'lsp-after-initialize-hook)) (lsp--text-document-did-open))
lsp--start(#s(lsp--client :language-id (closure ((stderr . "*lsp-ruby stderr*<2>") (prefix-function) (enable-function . lsp-ruby-enable) (initialize-fn . lsp-ruby--initialize-client) (extra-init-params) (ignore-messages) (ignore-regexps) (port . 7658) (host . "127.0.0.1") (command-fn) (command "solargraph" "socket") (root-directory-fn closure ((name closure (t) (dir) (directory-files dir nil "\\(Rakefile\\|Gemfile\\)")) lsp--no-response t) nil (let ((dir ...)) (if dir (file-truename dir) (if lsp-message-project-root-warning ... ... default-directory)))) (language-id-fn) (language-id . "ruby") (--cl-rest-- :language-id "ruby" :language-id-fn nil :root-directory-fn (closure ((name closure ... ... ...) lsp--no-response t) nil (let (...) (if dir ... ...))) :command ("solargraph" "socket") :command-fn nil :host "127.0.0.1" :port 7658 :ignore-regexps nil :ignore-messages nil :extra-init-params nil :initialize-fn lsp-ruby--initialize-client :enable-function lsp-ruby-enable :prefix-function nil) (name . lsp-ruby) t) (_) language-id) :send-sync nil :send-async nil :type nil :new-connection (closure ((stderr . "*lsp-ruby stderr*<2>") (port . 7658) (host . "127.0.0.1") (command-fn) (command "solargraph" "socket") (name . "lsp-ruby") t) (filter sentinel) (let* ((command (if command-fn (funcall command-fn) command)) (final-command (if (consp command) command (list command))) proc tcp-proc) (if (executable-find (nth 0 final-command)) nil (error (format "Couldn't find executable %s" (nth 0 final-command)))) (setq proc (make-process :name name :connection-type 'pipe :coding 'no-conversion :command final-command :sentinel sentinel :stderr stderr :noquery t) tcp-proc (open-network-stream (concat name " TCP connection") nil host port :type 'plain)) (set-process-query-on-exit-flag (get-buffer-process (get-buffer stderr)) nil) (set-process-query-on-exit-flag tcp-proc nil) (set-process-filter tcp-proc filter) (cons proc tcp-proc))) :stderr "*lsp-ruby stderr*<2>" :get-root (closure ((name closure (t) (dir) (directory-files dir nil "\\(Rakefile\\|Gemfile\\)")) lsp--no-response t) nil (let ((dir (locate-dominating-file "." name))) (if dir (file-truename dir) (if lsp-message-project-root-warning (message "Couldn't find project root, using the current directory as the root.") (lsp-warn "Couldn't find project root, using the current directory as the root.") default-directory)))) :ignore-regexps nil :ignore-messages nil :notification-handlers #<hash-table equal 0/65 0x40d79a69> :request-handlers #<hash-table equal 0/65 0x40d79b91> :response-handlers #<hash-table eql 0/65 0x5c75e545> :string-renderers (("ruby" . lsp-ruby--render-string)) :last-id 0 :enable-function lsp-ruby-enable :prefix-function nil :uri-handlers #<hash-table equal 0/65 0x5c75e87d> :action-handlers #<hash-table equal 0/65 0x5c010cb9> :default-renderer nil) nil)
(if (lsp--should-start-p root) (lsp--start client extra-init-params) (message "Not initializing project %s" root))
(let ((root (funcall (progn (or (and (memq ... cl-struct-lsp--client-tags) t) (signal 'wrong-type-argument (list ... client))) (aref client 7))))) (if (lsp--should-start-p root) (lsp--start client extra-init-params) (message "Not initializing project %s" root)))
(let* ((stderr (generate-new-buffer-name (concat "*" (symbol-name name) " stderr*"))) (client (make-lsp--client :language-id (or language-id-fn #'(lambda (_) language-id)) :new-connection (lsp--make-tcp-connection (symbol-name name) command command-fn host port stderr) :stderr stderr :get-root root-directory-fn :ignore-regexps ignore-regexps :ignore-messages ignore-messages :enable-function enable-function :prefix-function prefix-function))) (if initialize-fn (progn (funcall initialize-fn client))) (let ((root (funcall (progn (or (and ... t) (signal ... ...)) (aref client 7))))) (if (lsp--should-start-p root) (lsp--start client extra-init-params) (message "Not initializing project %s" root))))
(progn (let* ((stderr (generate-new-buffer-name (concat "*" (symbol-name name) " stderr*"))) (client (make-lsp--client :language-id (or language-id-fn #'(lambda ... language-id)) :new-connection (lsp--make-tcp-connection (symbol-name name) command command-fn host port stderr) :stderr stderr :get-root root-directory-fn :ignore-regexps ignore-regexps :ignore-messages ignore-messages :enable-function enable-function :prefix-function prefix-function))) (if initialize-fn (progn (funcall initialize-fn client))) (let ((root (funcall (progn (or ... ...) (aref client 7))))) (if (lsp--should-start-p root) (lsp--start client extra-init-params) (message "Not initializing project %s" root)))))
(if (and (not lsp-mode) (buffer-file-name)) (progn (let* ((stderr (generate-new-buffer-name (concat "*" (symbol-name name) " stderr*"))) (client (make-lsp--client :language-id (or language-id-fn #'...) :new-connection (lsp--make-tcp-connection (symbol-name name) command command-fn host port stderr) :stderr stderr :get-root root-directory-fn :ignore-regexps ignore-regexps :ignore-messages ignore-messages :enable-function enable-function :prefix-function prefix-function))) (if initialize-fn (progn (funcall initialize-fn client))) (let ((root (funcall (progn ... ...)))) (if (lsp--should-start-p root) (lsp--start client extra-init-params) (message "Not initializing project %s" root))))))
(progn (progn (or (symbolp name) (signal 'wrong-type-argument (list 'symbol name 'name))) nil) (progn (or (or (null language-id) (stringp language-id)) (signal 'wrong-type-argument (list '(or null string) language-id 'language-id))) nil) (progn (or (or (null language-id-fn) (functionp language-id-fn)) (signal 'wrong-type-argument (list '(or null function) language-id-fn 'language-id-fn))) nil) (progn (or (or (null root-directory-fn) (functionp root-directory-fn)) (signal 'wrong-type-argument (list '(or null function) root-directory-fn 'root-directory-fn))) nil) (progn (or (listp command) (signal 'wrong-type-argument (list 'list command 'command))) nil) (progn (or (or (null command-fn) (functionp command-fn)) (signal 'wrong-type-argument (list '(or null function) command-fn 'command-fn))) nil) (progn (or (stringp host) (signal 'wrong-type-argument (list 'string host 'host))) nil) (progn (or (and (integerp port) (>= port '1) (<= port '65535)) (signal 'wrong-type-argument (list '(integer 1 65535) port 'port))) nil) (progn (or (listp ignore-regexps) (signal 'wrong-type-argument (list 'list ignore-regexps 'ignore-regexps))) nil) (progn (or (listp ignore-messages) (signal 'wrong-type-argument (list 'list ignore-messages 'ignore-messages))) nil) (progn (or (or (listp extra-init-params) (functionp extra-init-params)) (signal 'wrong-type-argument (list '(or list function) extra-init-params 'extra-init-params))) nil) (progn (or (or (null initialize-fn) (functionp initialize-fn)) (signal 'wrong-type-argument (list '(or null function) initialize-fn 'initialize-fn))) nil) (progn (or (or (null prefix-function) (functionp prefix-function)) (signal 'wrong-type-argument (list '(or null function) prefix-function 'prefix-function))) nil) (if (and (not lsp-mode) (buffer-file-name)) (progn (let* ((stderr (generate-new-buffer-name (concat "*" ... " stderr*"))) (client (make-lsp--client :language-id (or language-id-fn ...) :new-connection (lsp--make-tcp-connection ... command command-fn host port stderr) :stderr stderr :get-root root-directory-fn :ignore-regexps ignore-regexps :ignore-messages ignore-messages :enable-function enable-function :prefix-function prefix-function))) (if initialize-fn (progn (funcall initialize-fn client))) (let ((root (funcall ...))) (if (lsp--should-start-p root) (lsp--start client extra-init-params) (message "Not initializing project %s" root)))))))
(progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) '(:language-id :language-id-fn :root-directory-fn :command :command-fn :host :port :ignore-regexps :ignore-messages :extra-init-params :initialize-fn :enable-function :prefix-function :allow-other-keys)) (setq --cl-keys-- (cdr (cdr --cl-keys--)))) ((car (cdr (memq ... --cl-rest--))) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:language-id :language-id-fn :root-directory-fn :command :command-fn :host :port :ignore-regexps :ignore-messages :extra-init-params :initialize-fn :enable-function :prefix-function)" (car --cl-keys--)))))) (progn (progn (or (symbolp name) (signal 'wrong-type-argument (list 'symbol name 'name))) nil) (progn (or (or (null language-id) (stringp language-id)) (signal 'wrong-type-argument (list '(or null string) language-id 'language-id))) nil) (progn (or (or (null language-id-fn) (functionp language-id-fn)) (signal 'wrong-type-argument (list '(or null function) language-id-fn 'language-id-fn))) nil) (progn (or (or (null root-directory-fn) (functionp root-directory-fn)) (signal 'wrong-type-argument (list '(or null function) root-directory-fn 'root-directory-fn))) nil) (progn (or (listp command) (signal 'wrong-type-argument (list 'list command 'command))) nil) (progn (or (or (null command-fn) (functionp command-fn)) (signal 'wrong-type-argument (list '(or null function) command-fn 'command-fn))) nil) (progn (or (stringp host) (signal 'wrong-type-argument (list 'string host 'host))) nil) (progn (or (and (integerp port) (>= port '1) (<= port '65535)) (signal 'wrong-type-argument (list '(integer 1 65535) port 'port))) nil) (progn (or (listp ignore-regexps) (signal 'wrong-type-argument (list 'list ignore-regexps 'ignore-regexps))) nil) (progn (or (listp ignore-messages) (signal 'wrong-type-argument (list 'list ignore-messages 'ignore-messages))) nil) (progn (or (or (listp extra-init-params) (functionp extra-init-params)) (signal 'wrong-type-argument (list '(or list function) extra-init-params 'extra-init-params))) nil) (progn (or (or (null initialize-fn) (functionp initialize-fn)) (signal 'wrong-type-argument (list '(or null function) initialize-fn 'initialize-fn))) nil) (progn (or (or (null prefix-function) (functionp prefix-function)) (signal 'wrong-type-argument (list '(or null function) prefix-function 'prefix-function))) nil) (if (and (not lsp-mode) (buffer-file-name)) (progn (let* ((stderr (generate-new-buffer-name ...)) (client (make-lsp--client :language-id ... :new-connection ... :stderr stderr :get-root root-directory-fn :ignore-regexps ignore-regexps :ignore-messages ignore-messages :enable-function enable-function :prefix-function prefix-function))) (if initialize-fn (progn (funcall initialize-fn client))) (let ((root ...)) (if (lsp--should-start-p root) (lsp--start client extra-init-params) (message "Not initializing project %s" root))))))))
(let* ((language-id (car (cdr (plist-member --cl-rest-- ':language-id)))) (language-id-fn (car (cdr (plist-member --cl-rest-- ':language-id-fn)))) (root-directory-fn (car (cdr (plist-member --cl-rest-- ':root-directory-fn)))) (command (car (cdr (plist-member --cl-rest-- ':command)))) (command-fn (car (cdr (plist-member --cl-rest-- ':command-fn)))) (host (car (cdr (plist-member --cl-rest-- ':host)))) (port (car (cdr (plist-member --cl-rest-- ':port)))) (ignore-regexps (car (cdr (plist-member --cl-rest-- ':ignore-regexps)))) (ignore-messages (car (cdr (plist-member --cl-rest-- ':ignore-messages)))) (extra-init-params (car (cdr (plist-member --cl-rest-- ':extra-init-params)))) (initialize-fn (car (cdr (plist-member --cl-rest-- ':initialize-fn)))) (enable-function (car (cdr (plist-member --cl-rest-- ':enable-function)))) (prefix-function (car (cdr (plist-member --cl-rest-- ':prefix-function))))) (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) '...) (setq --cl-keys-- (cdr ...))) ((car (cdr ...)) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:language-id :language-id-fn :root-directory-fn :command :command-fn :host :port :ignore-regexps :ignore-messages :extra-init-params :initialize-fn :enable-function :prefix-function)" (car --cl-keys--)))))) (progn (progn (or (symbolp name) (signal 'wrong-type-argument (list 'symbol name 'name))) nil) (progn (or (or (null language-id) (stringp language-id)) (signal 'wrong-type-argument (list '... language-id 'language-id))) nil) (progn (or (or (null language-id-fn) (functionp language-id-fn)) (signal 'wrong-type-argument (list '... language-id-fn 'language-id-fn))) nil) (progn (or (or (null root-directory-fn) (functionp root-directory-fn)) (signal 'wrong-type-argument (list '... root-directory-fn 'root-directory-fn))) nil) (progn (or (listp command) (signal 'wrong-type-argument (list 'list command 'command))) nil) (progn (or (or (null command-fn) (functionp command-fn)) (signal 'wrong-type-argument (list '... command-fn 'command-fn))) nil) (progn (or (stringp host) (signal 'wrong-type-argument (list 'string host 'host))) nil) (progn (or (and (integerp port) (>= port '1) (<= port '65535)) (signal 'wrong-type-argument (list '... port 'port))) nil) (progn (or (listp ignore-regexps) (signal 'wrong-type-argument (list 'list ignore-regexps 'ignore-regexps))) nil) (progn (or (listp ignore-messages) (signal 'wrong-type-argument (list 'list ignore-messages 'ignore-messages))) nil) (progn (or (or (listp extra-init-params) (functionp extra-init-params)) (signal 'wrong-type-argument (list '... extra-init-params 'extra-init-params))) nil) (progn (or (or (null initialize-fn) (functionp initialize-fn)) (signal 'wrong-type-argument (list '... initialize-fn 'initialize-fn))) nil) (progn (or (or (null prefix-function) (functionp prefix-function)) (signal 'wrong-type-argument (list '... prefix-function 'prefix-function))) nil) (if (and (not lsp-mode) (buffer-file-name)) (progn (let* ((stderr ...) (client ...)) (if initialize-fn (progn ...)) (let (...) (if ... ... ...))))))))
lsp--enable-tcp-client(lsp-ruby :language-id "ruby" :language-id-fn nil :root-directory-fn (closure ((name closure (t) (dir) (directory-files dir nil "\\(Rakefile\\|Gemfile\\)")) lsp--no-response t) nil (let ((dir (locate-dominating-file "." name))) (if dir (file-truename dir) (if lsp-message-project-root-warning (message "Couldn't find project root, using the current directory as the root.") (lsp-warn "Couldn't find project root, using the current directory as the root.") default-directory)))) :command ("solargraph" "socket") :command-fn nil :host "127.0.0.1" :port 7658 :ignore-regexps nil :ignore-messages nil :extra-init-params nil :initialize-fn lsp-ruby--initialize-client :enable-function lsp-ruby-enable :prefix-function nil)
lsp-ruby-enable()
run-hooks(change-major-mode-after-body-hook prog-mode-hook ruby-mode-hook)
apply(run-hooks (change-major-mode-after-body-hook prog-mode-hook ruby-mode-hook))
run-mode-hooks(ruby-mode-hook)
ruby-mode()
LSP 针对 kill buffer 有没有保护措施或者 restart 措施?
看着错误像 kill-buffer 导致 lsp-ruby 的 process 被 killed, 再次打开 ruby buffer 的时候, 触发了lsp–send-no-wait 里面的进程检查错误.
还在研究中, 欢迎玩 lsp-mode 比较溜的同学指导下.