Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand directory wildcards (#293) #293

Merged

Conversation

juergenhoetzel
Copy link
Contributor

This commit prevents watching directories that contain wildcards.

I have run into the following error when using ccls, which returns a extglob **/* globPattern:

Debugger entered--Lisp error: (file-notify-error "Directory does not exist" "/home/juergen/shared/cxx/hello/src/**")
  signal(file-notify-error ("Directory does not exist" "/home/juergen/shared/cxx/hello/src/**"))
  file-notify-add-watch("**/" (change) (closure ((--cl-handle-event-- . #3) (file-globs ".ccls-cache/" ".ccls-cache/") (globs "**/*") (success) (watchers . [(:globPattern "**/*")]) (--cl-rest-- :watchers [(:globPattern "**/*")]) (id . "didChangeWatchedFiles") (method . workspace/didChangeWatchedFiles) (server . #<eglot-lsp-server eglot-lsp-server>) t) (event) (let* ((x108 (car event)) (x109 (cdr event)) (x110 (car x109)) (x111 (cdr x109)) (x112 (car x111)) (x113 (cdr x111)) (x114 (car x113)) (x115 (cdr x113))) (let ((file1 x114) (file x112) (action x110) (desc x108)) (cond ((and (memq action ...) (cl-find file globs :test ...)) (jsonrpc-notify server :workspace/didChangeWatchedFiles (list ... ...))) ((eq action (quote renamed)) (funcall --cl-handle-event-- (quote ...)) (funcall --cl-handle-event-- (quote ...))))))))
  (let* ((v (file-notify-add-watch dir (quote (change)) --cl-handle-event--)) (v id) (v (eglot--file-watches server))) (puthash v (cons v (gethash v v)) v))
  (let ((dir (car --dolist-tail--))) (let* ((v (file-notify-add-watch dir (quote (change)) --cl-handle-event--)) (v id) (v (eglot--file-watches server))) (puthash v (cons v (gethash v v)) v)) (setq --dolist-tail-- (cdr --dolist-tail--)))
  (while --dolist-tail-- (let ((dir (car --dolist-tail--))) (let* ((v (file-notify-add-watch dir (quote (change)) --cl-handle-event--)) (v id) (v (eglot--file-watches server))) (puthash v (cons v (gethash v v)) v)) (setq --dolist-tail-- (cdr --dolist-tail--))))
  (let ((--dolist-tail-- (delete-dups (mapcar (function file-name-directory) globs)))) (while --dolist-tail-- (let ((dir (car --dolist-tail--))) (let* ((v (file-notify-add-watch dir (quote ...) --cl-handle-event--)) (v id) (v (eglot--file-watches server))) (puthash v (cons v (gethash v v)) v)) (setq --dolist-tail-- (cdr --dolist-tail--)))))
  (progn (let ((--dolist-tail-- (delete-dups (mapcar (function file-name-directory) globs)))) (while --dolist-tail-- (let ((dir (car --dolist-tail--))) (let* ((v (file-notify-add-watch dir ... --cl-handle-event--)) (v id) (v (eglot--file-watches server))) (puthash v (cons v (gethash v v)) v)) (setq --dolist-tail-- (cdr --dolist-tail--))))) (setq success (list (quote :message) (format "OK, watching %s watchers" (length watchers)))))
  (unwind-protect (progn (let ((--dolist-tail-- (delete-dups (mapcar (function file-name-directory) globs)))) (while --dolist-tail-- (let ((dir (car --dolist-tail--))) (let* ((v ...) (v id) (v ...)) (puthash v (cons v ...) v)) (setq --dolist-tail-- (cdr --dolist-tail--))))) (setq success (list (quote :message) (format "OK, watching %s watchers" (length watchers))))) (if success nil (eglot-unregister-capability server method id)))
  (let (--cl-handle-event--) (setq --cl-handle-event-- (function (lambda (event) (let* ((x108 (car event)) (x109 (cdr event)) (x110 (car x109)) (x111 (cdr x109)) (x112 (car x111)) (x113 (cdr x111)) (x114 (car x113)) (x115 (cdr x113))) (let ((file1 x114) (file x112) (action x110) (desc x108)) (cond (... ...) (... ... ...))))))) (unwind-protect (progn (let ((--dolist-tail-- (delete-dups (mapcar ... globs)))) (while --dolist-tail-- (let ((dir ...)) (let* (... ... ...) (puthash v ... v)) (setq --dolist-tail-- (cdr --dolist-tail--))))) (setq success (list (quote :message) (format "OK, watching %s watchers" (length watchers))))) (if success nil (eglot-unregister-capability server method id))))
  (let* (success (globs (mapcar (function (lambda (jsonrpc-lambda-elem27) (let (...) (let* ... ...)))) watchers)) (file-globs (mapcan (function (lambda (f) (mapcar (function file-name-directory) (file-expand-wildcards f)))) globs))) (let (--cl-handle-event--) (setq --cl-handle-event-- (function (lambda (event) (let* ((x108 ...) (x109 ...) (x110 ...) (x111 ...) (x112 ...) (x113 ...) (x114 ...) (x115 ...)) (let (... ... ... ...) (cond ... ...)))))) (unwind-protect (progn (let ((--dolist-tail-- (delete-dups ...))) (while --dolist-tail-- (let (...) (let* ... ...) (setq --dolist-tail-- ...)))) (setq success (list (quote :message) (format "OK, watching %s watchers" (length watchers))))) (if success nil (eglot-unregister-capability server method id)))))
  (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) (quote (:watchers :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 (:watchers)" (car --cl-keys--)))))) (eglot-unregister-capability server method id) (let* (success (globs (mapcar (function (lambda (jsonrpc-lambda-elem27) (let ... ...))) watchers)) (file-globs (mapcan (function (lambda (f) (mapcar ... ...))) globs))) (let (--cl-handle-event--) (setq --cl-handle-event-- (function (lambda (event) (let* (... ... ... ... ... ... ... ...) (let ... ...))))) (unwind-protect (progn (let ((--dolist-tail-- ...)) (while --dolist-tail-- (let ... ... ...))) (setq success (list (quote :message) (format "OK, watching %s watchers" ...)))) (if success nil (eglot-unregister-capability server method id))))))
  (let* ((watchers (car (cdr (plist-member --cl-rest-- (quote :watchers)))))) (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) (quote ...)) (setq --cl-keys-- (cdr ...))) ((car (cdr ...)) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:watchers)" (car --cl-keys--)))))) (eglot-unregister-capability server method id) (let* (success (globs (mapcar (function (lambda ... ...)) watchers)) (file-globs (mapcan (function (lambda ... ...)) globs))) (let (--cl-handle-event--) (setq --cl-handle-event-- (function (lambda (event) (let* ... ...)))) (unwind-protect (progn (let (...) (while --dolist-tail-- ...)) (setq success (list ... ...))) (if success nil (eglot-unregister-capability server method id)))))))
  (progn (let* ((watchers (car (cdr (plist-member --cl-rest-- (quote :watchers)))))) (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq ... ...) (setq --cl-keys-- ...)) ((car ...) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:watchers)" ...))))) (eglot-unregister-capability server method id) (let* (success (globs (mapcar (function ...) watchers)) (file-globs (mapcan (function ...) globs))) (let (--cl-handle-event--) (setq --cl-handle-event-- (function (lambda ... ...))) (unwind-protect (progn (let ... ...) (setq success ...)) (if success nil (eglot-unregister-capability server method id))))))))
  (closure (t) (server method id &rest --cl-rest--) "Handle dynamic registration of workspace/didChangeWatchedFiles\n\n(fn SERVER METHOD ID &key WATCHERS)" (progn (let* ((watchers (car (cdr (plist-member --cl-rest-- ...))))) (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond (... ...) (... ...) (t ...)))) (eglot-unregister-capability server method id) (let* (success (globs (mapcar ... watchers)) (file-globs (mapcan ... globs))) (let (--cl-handle-event--) (setq --cl-handle-event-- (function ...)) (unwind-protect (progn ... ...) (if success nil ...))))))))(#<eglot-lsp-server eglot-lsp-server> workspace/didChangeWatchedFiles "didChangeWatchedFiles" :watchers [(:globPattern "**/*")])
  apply((closure (t) (server method id &rest --cl-rest--) "Handle dynamic registration of workspace/didChangeWatchedFiles\n\n(fn SERVER METHOD ID &key WATCHERS)" (progn (let* ((watchers (car (cdr ...)))) (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ... ... ...))) (eglot-unregister-capability server method id) (let* (success (globs ...) (file-globs ...)) (let (--cl-handle-event--) (setq --cl-handle-event-- ...) (unwind-protect ... ...))))))) #<eglot-lsp-server eglot-lsp-server> workspace/didChangeWatchedFiles ("didChangeWatchedFiles" :watchers [(:globPattern "**/*")]))
  eglot-register-capability(#<eglot-lsp-server eglot-lsp-server> workspace/didChangeWatchedFiles "didChangeWatchedFiles" :watchers [(:globPattern "**/*")])
  apply(eglot-register-capability #<eglot-lsp-server eglot-lsp-server> workspace/didChangeWatchedFiles "didChangeWatchedFiles" (:watchers [(:globPattern "**/*")]))
  (closure ((registerOptions :watchers [(:globPattern "**/*")]) (method . "workspace/didChangeWatchedFiles") (id . "didChangeWatchedFiles") (--cl-rest-- :id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")])) (object-once :id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")])) (thing :id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")])) (--cl-var-- (:id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")]))) (how . register) (things . [(:id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")]))]) (server . #<eglot-lsp-server eglot-lsp-server>) eglot--managed-mode t) nil (apply (cond ((eql how (quote register)) (quote eglot-register-capability)) ((eql how (quote unregister)) (quote eglot-unregister-capability)) ((error "cl-ecase failed: %s, %s" how (quote (register unregister))) nil)) server (intern method) id registerOptions))()
  funcall((closure ((registerOptions :watchers [(:globPattern "**/*")]) (method . "workspace/didChangeWatchedFiles") (id . "didChangeWatchedFiles") (--cl-rest-- :id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")])) (object-once :id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")])) (thing :id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")])) (--cl-var-- (:id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")]))) (how . register) (things . [(:id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [...]))]) (server . #<eglot-lsp-server eglot-lsp-server>) eglot--managed-mode t) nil (apply (cond ((eql how (quote register)) (quote eglot-register-capability)) ((eql how (quote unregister)) (quote eglot-unregister-capability)) ((error "cl-ecase failed: %s, %s" how (quote (register unregister))) nil)) server (intern method) id registerOptions)))
  eglot--call-with-interface((Registration (:id :method) (:registerOptions)) (:id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")])) (closure ((registerOptions :watchers [(:globPattern "**/*")]) (method . "workspace/didChangeWatchedFiles") (id . "didChangeWatchedFiles") (--cl-rest-- :id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")])) (object-once :id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")])) (thing :id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")])) (--cl-var-- (:id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")]))) (how . register) (things . [(:id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [...]))]) (server . #<eglot-lsp-server eglot-lsp-server>) eglot--managed-mode t) nil (apply (cond ((eql how (quote register)) (quote eglot-register-capability)) ((eql how (quote unregister)) (quote eglot-unregister-capability)) ((error "cl-ecase failed: %s, %s" how (quote (register unregister))) nil)) server (intern method) id registerOptions)))
  (let* ((--cl-rest-- object-once) (id (car (cdr (plist-member --cl-rest-- (quote :id))))) (method (car (cdr (plist-member --cl-rest-- (quote :method))))) (registerOptions (car (cdr (plist-member --cl-rest-- (quote :registerOptions)))))) (eglot--call-with-interface (assoc (quote Registration) eglot--lsp-interface-alist) object-once (function (lambda nil (apply (cond ((eql how ...) (quote eglot-register-capability)) ((eql how ...) (quote eglot-unregister-capability)) ((error "cl-ecase failed: %s, %s" how ...) nil)) server (intern method) id registerOptions)))))
  (let ((object-once thing)) (let* ((--cl-rest-- object-once) (id (car (cdr (plist-member --cl-rest-- (quote :id))))) (method (car (cdr (plist-member --cl-rest-- (quote :method))))) (registerOptions (car (cdr (plist-member --cl-rest-- (quote :registerOptions)))))) (eglot--call-with-interface (assoc (quote Registration) eglot--lsp-interface-alist) object-once (function (lambda nil (apply (cond (... ...) (... ...) (... nil)) server (intern method) id registerOptions))))))
  (while (consp --cl-var--) (setq thing (car --cl-var--)) (let ((object-once thing)) (let* ((--cl-rest-- object-once) (id (car (cdr (plist-member --cl-rest-- ...)))) (method (car (cdr (plist-member --cl-rest-- ...)))) (registerOptions (car (cdr (plist-member --cl-rest-- ...))))) (eglot--call-with-interface (assoc (quote Registration) eglot--lsp-interface-alist) object-once (function (lambda nil (apply (cond ... ... ...) server (intern method) id registerOptions)))))) (setq --cl-var-- (cdr --cl-var--)))
  (let* ((--cl-var-- (cl-coerce things (quote list))) (thing nil)) (while (consp --cl-var--) (setq thing (car --cl-var--)) (let ((object-once thing)) (let* ((--cl-rest-- object-once) (id (car (cdr ...))) (method (car (cdr ...))) (registerOptions (car (cdr ...)))) (eglot--call-with-interface (assoc (quote Registration) eglot--lsp-interface-alist) object-once (function (lambda nil (apply ... server ... id registerOptions)))))) (setq --cl-var-- (cdr --cl-var--))) nil)
  eglot--register-unregister(#<eglot-lsp-server eglot-lsp-server> [(:id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")]))] register)
  (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) (quote (:registrations :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 (:registrations)" (car --cl-keys--)))))) (eglot--register-unregister server registrations (quote register)))
  (let* ((registrations (car (cdr (plist-member --cl-rest-- (quote :registrations)))))) (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) (quote ...)) (setq --cl-keys-- (cdr ...))) ((car (cdr ...)) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:registrations)" (car --cl-keys--)))))) (eglot--register-unregister server registrations (quote register))))
  (progn (let* ((registrations (car (cdr (plist-member --cl-rest-- (quote :registrations)))))) (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq ... ...) (setq --cl-keys-- ...)) ((car ...) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:registrations)" ...))))) (eglot--register-unregister server registrations (quote register)))))
  (closure (eglot--managed-mode t) (server _method &rest --cl-rest--) "Handle server request client/registerCapability\n\n(fn SERVER METHOD &key REGISTRATIONS)" (progn (let* ((registrations (car (cdr (plist-member --cl-rest-- ...))))) (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond (... ...) (... ...) (t ...)))) (eglot--register-unregister server registrations (quote register))))))(#<eglot-lsp-server eglot-lsp-server> client/registerCapability :registrations [(:id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")]))])
  apply((closure (eglot--managed-mode t) (server _method &rest --cl-rest--) "Handle server request client/registerCapability\n\n(fn SERVER METHOD &key REGISTRATIONS)" (progn (let* ((registrations (car (cdr ...)))) (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ... ... ...))) (eglot--register-unregister server registrations (quote register)))))) #<eglot-lsp-server eglot-lsp-server> client/registerCapability (:registrations [(:id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")]))]))
  eglot-handle-request(#<eglot-lsp-server eglot-lsp-server> client/registerCapability :registrations [(:id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")]))])
  apply(eglot-handle-request #<eglot-lsp-server eglot-lsp-server> client/registerCapability (:registrations [(:id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")]))]))
  (closure ((fn . eglot-handle-request) (initargs :process (closure ((contact "ccls") (autostart-inferior-process) (readable-name . "EGLOT (src/c++-mode)") (nickname . "src") (contact "ccls") (class . eglot-lsp-server) (project transient . "/home/juergen/shared/cxx/hello/src/") (managed-major-mode . c++-mode) eglot--managed-mode t) nil (make-process :name readable-name :command contact :connection-type (quote pipe) :coding (quote utf-8-emacs-unix) :noquery t :stderr (get-buffer-create (format "*%s stderr*" readable-name))))) (contact "ccls") (autostart-inferior-process) (readable-name . "EGLOT (src/c++-mode)") (nickname . "src") (contact "ccls") (class . eglot-lsp-server) (project transient . "/home/juergen/shared/cxx/hello/src/") (managed-major-mode . c++-mode) eglot--managed-mode t) (server method params) (apply fn server method (append params nil)))(#<eglot-lsp-server eglot-lsp-server> client/registerCapability (:registrations [(:id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")]))]))
  funcall((closure ((fn . eglot-handle-request) (initargs :process (closure ((contact "ccls") (autostart-inferior-process) (readable-name . "EGLOT (src/c++-mode)") (nickname . "src") (contact "ccls") (class . eglot-lsp-server) (project transient . "/home/juergen/shared/cxx/hello/src/") (managed-major-mode . c++-mode) eglot--managed-mode t) nil (make-process :name readable-name :command contact :connection-type (quote pipe) :coding (quote utf-8-emacs-unix) :noquery t :stderr (get-buffer-create (format "*%s stderr*" readable-name))))) (contact "ccls") (autostart-inferior-process) (readable-name . "EGLOT (src/c++-mode)") (nickname . "src") (contact "ccls") (class . eglot-lsp-server) (project transient . "/home/juergen/shared/cxx/hello/src/") (managed-major-mode . c++-mode) eglot--managed-mode t) (server method params) (apply fn server method (append params nil))) #<eglot-lsp-server eglot-lsp-server> client/registerCapability (:registrations [(:id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")]))]))
  (list (quote :result) (funcall (jsonrpc--request-dispatcher connection) connection (intern method) params))
  (condition-case oops (list (quote :result) (funcall (jsonrpc--request-dispatcher connection) connection (intern method) params)) (jsonrpc-error (list (quote :error) (list (quote :code) (or (alist-get (quote jsonrpc-error-code) (cdr oops)) -32603) (quote :message) (or (alist-get (quote jsonrpc-error-message) (cdr oops)) "Internal error")))))
  (condition-case _ignore (condition-case oops (list (quote :result) (funcall (jsonrpc--request-dispatcher connection) connection (intern method) params)) (jsonrpc-error (list (quote :error) (list (quote :code) (or (alist-get (quote jsonrpc-error-code) (cdr oops)) -32603) (quote :message) (or (alist-get (quote jsonrpc-error-message) (cdr oops)) "Internal error"))))) ((debug error) (quote (:error (:code -32603 :message "Internal error")))))
  (let* ((debug-on-error (and debug-on-error (not (ert-running-test)))) (reply (condition-case _ignore (condition-case oops (list (quote :result) (funcall (jsonrpc--request-dispatcher connection) connection (intern method) params)) (jsonrpc-error (list (quote :error) (list ... ... ... ...)))) ((debug error) (quote (:error (:code -32603 :message "Internal error"))))))) (apply (function jsonrpc--reply) connection id reply))
  (cond ((and method id) (let* ((debug-on-error (and debug-on-error (not (ert-running-test)))) (reply (condition-case _ignore (condition-case oops (list ... ...) (jsonrpc-error ...)) ((debug error) (quote ...))))) (apply (function jsonrpc--reply) connection id reply))) (method (funcall (jsonrpc--notification-dispatcher connection) connection (intern method) params)) ((setq continuations (and id (gethash id (jsonrpc--request-continuations connection)))) (let ((timer (nth 2 continuations))) (if timer (progn (cancel-timer timer)))) (remhash id (jsonrpc--request-continuations connection)) (if error (funcall (nth 1 continuations) error) (funcall (nth 0 continuations) result))))
  (let (continuations) (jsonrpc--log-event connection message (quote server)) (let* ((v connection)) (\(setf\ jsonrpc-last-error\) error v)) (cond ((and method id) (let* ((debug-on-error (and debug-on-error (not ...))) (reply (condition-case _ignore (condition-case oops ... ...) (... ...)))) (apply (function jsonrpc--reply) connection id reply))) (method (funcall (jsonrpc--notification-dispatcher connection) connection (intern method) params)) ((setq continuations (and id (gethash id (jsonrpc--request-continuations connection)))) (let ((timer (nth 2 continuations))) (if timer (progn (cancel-timer timer)))) (remhash id (jsonrpc--request-continuations connection)) (if error (funcall (nth 1 continuations) error) (funcall (nth 0 continuations) result)))) (jsonrpc--call-deferred connection))
  (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) (quote (:method :id :error :params :result :jsonrpc :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 (:method :id :error :params :result :jsonrpc)" (car --cl-keys--)))))) (let (continuations) (jsonrpc--log-event connection message (quote server)) (let* ((v connection)) (\(setf\ jsonrpc-last-error\) error v)) (cond ((and method id) (let* ((debug-on-error (and debug-on-error ...)) (reply (condition-case _ignore ... ...))) (apply (function jsonrpc--reply) connection id reply))) (method (funcall (jsonrpc--notification-dispatcher connection) connection (intern method) params)) ((setq continuations (and id (gethash id (jsonrpc--request-continuations connection)))) (let ((timer (nth 2 continuations))) (if timer (progn (cancel-timer timer)))) (remhash id (jsonrpc--request-continuations connection)) (if error (funcall (nth 1 continuations) error) (funcall (nth 0 continuations) result)))) (jsonrpc--call-deferred connection)))
  (let* ((--cl-rest-- message) (method (car (cdr (plist-member --cl-rest-- (quote :method))))) (id (car (cdr (plist-member --cl-rest-- (quote :id))))) (error (car (cdr (plist-member --cl-rest-- (quote :error))))) (params (car (cdr (plist-member --cl-rest-- (quote :params))))) (result (car (cdr (plist-member --cl-rest-- (quote :result))))) (_jsonrpc (car (cdr (plist-member --cl-rest-- (quote :jsonrpc)))))) (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) (quote ...)) (setq --cl-keys-- (cdr ...))) ((car (cdr ...)) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:method :id :error :params :result :jsonrpc)" (car --cl-keys--)))))) (let (continuations) (jsonrpc--log-event connection message (quote server)) (let* ((v connection)) (\(setf\ jsonrpc-last-error\) error v)) (cond ((and method id) (let* ((debug-on-error ...) (reply ...)) (apply (function jsonrpc--reply) connection id reply))) (method (funcall (jsonrpc--notification-dispatcher connection) connection (intern method) params)) ((setq continuations (and id (gethash id ...))) (let ((timer ...)) (if timer (progn ...))) (remhash id (jsonrpc--request-continuations connection)) (if error (funcall (nth 1 continuations) error) (funcall (nth 0 continuations) result)))) (jsonrpc--call-deferred connection))))
  jsonrpc-connection-receive(#<eglot-lsp-server eglot-lsp-server> (:jsonrpc "2.0" :method "client/registerCapability" :id 0 :params (:registrations [(:id "didChangeWatchedFiles" :method "workspace/didChangeWatchedFiles" :registerOptions (:watchers [(:globPattern "**/*")]))])))
  (progn (jsonrpc-connection-receive connection json-message))
  (unwind-protect (progn (jsonrpc-connection-receive connection json-message)) (and (buffer-name temp-buffer) (kill-buffer temp-buffer)))
  (save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn (jsonrpc-connection-receive connection json-message)) (and (buffer-name temp-buffer) (kill-buffer temp-buffer))))
  (let ((temp-buffer (generate-new-buffer " *temp*"))) (save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn (jsonrpc-connection-receive connection json-message)) (and (buffer-name temp-buffer) (kill-buffer temp-buffer)))))
  (progn (let ((temp-buffer (generate-new-buffer " *temp*"))) (save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn (jsonrpc-connection-receive connection json-message)) (and (buffer-name temp-buffer) (kill-buffer temp-buffer))))))
  (if json-message (progn (let ((temp-buffer (generate-new-buffer " *temp*"))) (save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn (jsonrpc-connection-receive connection json-message)) (and (buffer-name temp-buffer) (kill-buffer temp-buffer)))))))
  (let* ((json-message (condition-case oops (jsonrpc--json-read) ((debug error) (jsonrpc--warn "Invalid JSON: %s %s" (cdr oops) (buffer-string)) nil)))) (if json-message (progn (let ((temp-buffer (generate-new-buffer " *temp*"))) (save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn (jsonrpc-connection-receive connection json-message)) (and (buffer-name temp-buffer) (kill-buffer temp-buffer))))))))
  (save-restriction (narrow-to-region (point) message-end) (let* ((json-message (condition-case oops (jsonrpc--json-read) ((debug error) (jsonrpc--warn "Invalid JSON: %s %s" (cdr oops) (buffer-string)) nil)))) (if json-message (progn (let ((temp-buffer (generate-new-buffer " *temp*"))) (save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn ...) (and ... ...))))))))
  (unwind-protect (save-restriction (narrow-to-region (point) message-end) (let* ((json-message (condition-case oops (jsonrpc--json-read) ((debug error) (jsonrpc--warn "Invalid JSON: %s %s" ... ...) nil)))) (if json-message (progn (let ((temp-buffer ...)) (save-current-buffer (set-buffer temp-buffer) (unwind-protect ... ...))))))) (goto-char message-end) (delete-region (point-min) (point)) (setq expected-bytes nil))
  (let* ((message-end (byte-to-position (+ (position-bytes (point)) expected-bytes)))) (unwind-protect (save-restriction (narrow-to-region (point) message-end) (let* ((json-message (condition-case oops (jsonrpc--json-read) (... ... nil)))) (if json-message (progn (let (...) (save-current-buffer ... ...)))))) (goto-char message-end) (delete-region (point-min) (point)) (setq expected-bytes nil)))
  (cond ((>= available-bytes expected-bytes) (let* ((message-end (byte-to-position (+ (position-bytes ...) expected-bytes)))) (unwind-protect (save-restriction (narrow-to-region (point) message-end) (let* ((json-message ...)) (if json-message (progn ...)))) (goto-char message-end) (delete-region (point-min) (point)) (setq expected-bytes nil)))) (t (setq done :waiting-for-more-bytes-in-this-message)))
  (let ((available-bytes (- (position-bytes (process-mark proc)) (position-bytes (point))))) (cond ((>= available-bytes expected-bytes) (let* ((message-end (byte-to-position (+ ... expected-bytes)))) (unwind-protect (save-restriction (narrow-to-region (point) message-end) (let* (...) (if json-message ...))) (goto-char message-end) (delete-region (point-min) (point)) (setq expected-bytes nil)))) (t (setq done :waiting-for-more-bytes-in-this-message))))
  (cond ((not expected-bytes) (setq expected-bytes (and (search-forward-regexp "\\(?:.*: .*\015\n\\)*Content-Length: *\\([[:digit:]]+\\)\015\n\\(?:.*: .*\015\n\\)*\015\n" (+ (point) 100) t) (string-to-number (match-string 1)))) (if expected-bytes nil (setq done :waiting-for-new-message))) (t (let ((available-bytes (- (position-bytes (process-mark proc)) (position-bytes (point))))) (cond ((>= available-bytes expected-bytes) (let* ((message-end ...)) (unwind-protect (save-restriction ... ...) (goto-char message-end) (delete-region ... ...) (setq expected-bytes nil)))) (t (setq done :waiting-for-more-bytes-in-this-message))))))
  (while (not done) (cond ((not expected-bytes) (setq expected-bytes (and (search-forward-regexp "\\(?:.*: .*\015\n\\)*Content-Length: *\\([[:digit:]]+\\)\015\n\\(?:.*: .*\015\n\\)*\015\n" (+ (point) 100) t) (string-to-number (match-string 1)))) (if expected-bytes nil (setq done :waiting-for-new-message))) (t (let ((available-bytes (- (position-bytes ...) (position-bytes ...)))) (cond ((>= available-bytes expected-bytes) (let* (...) (unwind-protect ... ... ... ...))) (t (setq done :waiting-for-more-bytes-in-this-message)))))))
  (let (done) (while (not done) (cond ((not expected-bytes) (setq expected-bytes (and (search-forward-regexp "\\(?:.*: .*\015\n\\)*Content-Length: *\\([[:digit:]]+\\)\015\n\\(?:.*: .*\015\n\\)*\015\n" (+ ... 100) t) (string-to-number (match-string 1)))) (if expected-bytes nil (setq done :waiting-for-new-message))) (t (let ((available-bytes (- ... ...))) (cond ((>= available-bytes expected-bytes) (let* ... ...)) (t (setq done :waiting-for-more-bytes-in-this-message))))))))
  (unwind-protect (let (done) (while (not done) (cond ((not expected-bytes) (setq expected-bytes (and (search-forward-regexp "\\(?:.*: .*\015\n\\)*Content-Length: *\\([[:digit:]]+\\)\015\n\\(?:.*: .*\015\n\\)*\015\n" ... t) (string-to-number ...))) (if expected-bytes nil (setq done :waiting-for-new-message))) (t (let ((available-bytes ...)) (cond (... ...) (t ...))))))) (let* ((v connection)) (\(setf\ jsonrpc--expected-bytes\) expected-bytes v)))
  (let* ((inhibit-read-only t) (connection (process-get proc (quote jsonrpc-connection))) (expected-bytes (jsonrpc--expected-bytes connection))) (save-excursion (goto-char (process-mark proc)) (insert string) (set-marker (process-mark proc) (point))) (unwind-protect (let (done) (while (not done) (cond ((not expected-bytes) (setq expected-bytes (and ... ...)) (if expected-bytes nil (setq done :waiting-for-new-message))) (t (let (...) (cond ... ...)))))) (let* ((v connection)) (\(setf\ jsonrpc--expected-bytes\) expected-bytes v))))
  (save-current-buffer (set-buffer (process-buffer proc)) (let* ((inhibit-read-only t) (connection (process-get proc (quote jsonrpc-connection))) (expected-bytes (jsonrpc--expected-bytes connection))) (save-excursion (goto-char (process-mark proc)) (insert string) (set-marker (process-mark proc) (point))) (unwind-protect (let (done) (while (not done) (cond ((not expected-bytes) (setq expected-bytes ...) (if expected-bytes nil ...)) (t (let ... ...))))) (let* ((v connection)) (\(setf\ jsonrpc--expected-bytes\) expected-bytes v)))))
  (progn (save-current-buffer (set-buffer (process-buffer proc)) (let* ((inhibit-read-only t) (connection (process-get proc (quote jsonrpc-connection))) (expected-bytes (jsonrpc--expected-bytes connection))) (save-excursion (goto-char (process-mark proc)) (insert string) (set-marker (process-mark proc) (point))) (unwind-protect (let (done) (while (not done) (cond (... ... ...) (t ...)))) (let* ((v connection)) (\(setf\ jsonrpc--expected-bytes\) expected-bytes v))))))
  (if (buffer-live-p (process-buffer proc)) (progn (save-current-buffer (set-buffer (process-buffer proc)) (let* ((inhibit-read-only t) (connection (process-get proc (quote jsonrpc-connection))) (expected-bytes (jsonrpc--expected-bytes connection))) (save-excursion (goto-char (process-mark proc)) (insert string) (set-marker (process-mark proc) (point))) (unwind-protect (let (done) (while (not done) (cond ... ...))) (let* ((v connection)) (\(setf\ jsonrpc--expected-bytes\) expected-bytes v)))))))
  jsonrpc--process-filter(#<process EGLOT (src/c++-mode)> "Content-Length: 220\015\n\015\n{\"jsonrpc\":\"2.0\",\"method\":\"client/registerCapability\",\"id\":0,\"params\":{\"registrations\":[{\"id\":\"didChangeWatchedFiles\",\"method\":\"workspace/didChangeWatchedFiles\",\"registerOptions\":{\"watchers\":[{\"globPattern\":\"**/*\"}]}}]}}")

@MaskRay
**/* matches also non-source files: Could you elobarate on that?

@joaotavora BTW: Thank you so much for creating this project. I'm currently porting F#-mode to LSP and eglot's simple elegant design makes it really easy for me to get started: I see it critical when today many elisp projects use tons of melpa libraries which force a foreign programming style (clojure style for example) which often also has negative effects on performance and security).

juergenhoetzel added a commit to juergenhoetzel/eglot that referenced this pull request Aug 10, 2019
* eglot.el (eglot-register-capability): prevent watching directories
that contain wildcards.
@juergenhoetzel juergenhoetzel changed the title Expand directory wildcards (#289) Expand directory wildcards (#293) Aug 10, 2019
@joaotavora
Copy link
Owner

Hello and thank you for the carefully crafted commit. It looks good, but since it's been a while since I've looked at this, I need you to clarify the main purpose of this commit.

The commit says "expand directory wildcards: prevents watching directories that contain wildcards", and this confuses me a little. It will potentially confuse me even more in the future.

Do you think this might be a slightly more adequate commit message? Your answer would help me understand if I'm getting this right.

Expand directory watcher globs containing **

Previously, if the server requested a glob pattern like foo/**/* 
to be watched, we would just error.  Now we watch foo/bar/* 
and foo/baz/* as if the server had requested those two watchers 
instead of just the one with the **. 

* eglot.el (eglot-register-capability): Use file-expand-wildcards to 
make a ** glob into multiple **-less globs.

If it is, please use it instead.

Regarding the code itself, I would just just use the mapcan on the existing
form, and keep using a single variable. It doesn't look like the old globs value
is used anywhere else after your changes, right?
Instead of file-globs you can also call the new variable flattened-globs or resolved-globs or expanded-globs or just globs. It would also be nice to report below that we might
be watching n watchers but m directories (length of watchers vs length of file-globs).

Finally, have you assigned copyright papers for Emacs' contributions? (your patch is small enough to go in regardless).

@joaotavora
Copy link
Owner

I've had a closer look at this and it seems file-expand-wildcards does more than we need. If we

(file-expand-wildcards "foo/**/*")

We get all the files foo/bar/quux1.txt and foo/bar/quux2.txt and foo/baz/buux3.txt, which I think would lead to watching foo/bar twice (incorrectly) and foo/baz once (correctly). So somewhere a delete-dups with a string= test is needed. Can you confirm this and correct accordingly?

juergenhoetzel added a commit to juergenhoetzel/eglot that referenced this pull request Aug 11, 2019
Previously, if the server requested a glob pattern like foo/**/*
to be watched, we would just error.  Now we watch foo/bar/
and foo/baz/ as if the server had requested those two watchers
instead of just the one with the **.

* eglot.el (eglot-register-capability): Use file-expand-wildcards to
make a ** glob into multiple **-less globs.
@juergenhoetzel
Copy link
Contributor Author

Do you think this might be a slightly more adequate commit message? Your answer would help me understand if I'm getting this right.

Indeed the message was somewhat misleading.

But the change does not correspond exactly to your suggestion: We only watch directories, not files. So "**/" instead of "**/*". I try to express it better in the amended commit.

Also the Code doesn't handle ** globstars, only * globs. Theres is code in various (m)elpa packages which handle globstars. So at the moment we only handle 1 level of subdirs.

Regarding the code itself, I would just just use the mapcan on the existing
form, and keep using a single variable. It doesn't look like the old globs value
is used anywhere else after your changes, right?

Yes, in my original commit indeed. But I think this was an error (fixed in the amended commit). Because if we only filter the files in a expanded glob like "*/*.c" -> ("foo/a.cc" "foo/b.cc") we would filter out new files created after exanding the glob, for example "foo/new.cc".

Instead of file-globs you can also call the new variable flattened-globs or resolved-globs or expanded-globs or just globs.

resolved-globs: That's exactly what it is. Thanks.

It would also be nice to report below that we might be watching n watchers but m directories (length of watchers vs length of file-globs).

good suggestion: Added in the amended commit.

We get all the files foo/bar/quux1.txt and foo/bar/quux2.txt and foo/baz/buux3.txt, which I think would lead to watching foo/bar twice (incorrectly) and foo/baz once (correctly). So somewhere a delete-dups with a string= test is needed. Can you confirm this and correct accordingly

This is already handled in the existing code:
(delete-dups (mapcar #'file-name-directory resolved-globs)))

delete-dups uses equal fot tests. I also edebuged it to check it.

Finally, have you assigned copyright papers for Emacs' contributions? (your patch is small enough to go in regardless).

I signed the papers many years ago. But there seems no public lists of the persons who have signed? I'm also a tramp developer:

https://savannah.gnu.org/project/memberlist.php?group=tramp

@joaotavora
Copy link
Owner

But the change does not correspond exactly to your suggestion: We only watch directories, not files. So "/" instead of "/*". I try to express it better in the amended commit.

It's easier to understand. Thanks.

resolved-globs: That's exactly what it is. Thanks.

If you like the name, I also propose that you use only this variable, i.e. assign it all the transformations in one simpler step (just one mapcan required):

(let ((resolved-globs ;; or `dirs-to-watch', also a decent name
       (delete-dups
        (mapcan (eglot--lambda ((FileSystemWatcher) globPattern)
                               (file-name-directory
                                (file-expand-wildcards globPattern)))
                watchers))))
  ...)

So at the moment we only handle 1 level of subdirs.

OK, so if we have this limitation, please add a second paragraph to the commit message explaining so, or a small FIXME-style comment to the code, or both.

Theres is code in various (m)elpa packages which handle globstars.

Maybe, in a subsequent commit, if you think it is useful, we could import one of those functions into eglot.el, if it's small enough.

I signed the papers many years ago. But there seems no public lists of the persons who have signed? I'm also a tramp developer:

Cool. The list is not public, but if you have access to a gnu.org machine (I have, but I can't find my key right now) you can supposedly consult the file. I find it easier to just ask :-)

So, to summarize:

  1. Comment on the 1-level-only limitation
  2. Optionally simplify the code as suggested

juergenhoetzel added a commit to juergenhoetzel/eglot that referenced this pull request Aug 12, 2019
Previously, if the server requested a glob pattern like foo/**/*
to be watched, we would just error.  Now we watch foo/bar/
and foo/baz/ as if the server had requested those two watchers
instead of just the one with the **.

Limitation: The implementation of file-expand-wildcards doesn't handle
globstars (** does match at most one path segment).

* eglot.el (eglot-register-capability): Use file-expand-wildcards to
make a ** glob into multiple **-less globs.
@juergenhoetzel
Copy link
Contributor Author

resolved-globs: That's exactly what it is. Thanks.

If you like the name, I also propose that you use only this variable, i.e. assign it all the transformations in one simpler step (just one mapcan required):

(let ((resolved-globs ;; or `dirs-to-watch', also a decent name
       (delete-dups
        (mapcan (eglot--lambda ((FileSystemWatcher) globPattern)
                               (file-name-directory
                                (file-expand-wildcards globPattern)))
                watchers))))
  ...)

Maybe you missed my comment above:

Regarding the code itself, I would just just use the mapcan on the existing
form, and keep using a single variable. It doesn't look like the old globs value
is used anywhere else after your changes, right?

Yes, in my original commit indeed. But I think this was an error (fixed in the amended commit). Because if we only filter the files in a expanded glob like "*/*.c" -> ("foo/a.cc" "foo/b.cc") we would filter out new files created after exanding the glob, for example "foo/new.cc".

The expanded list of files might also get very large and hit performance.

OK, so if we have this limitation, please add a second paragraph to the commit message explaining so, or a small FIXME-style comment to the code, or both.

Done in the amended commit.

@joaotavora
Copy link
Owner

Maybe you missed my comment above:

Indeed you're right, I did miss it: we need to keep globs (until a better solution is found, at least. It doesn't make a lot of sense to search all the globs for file changes inside a directory spawned from a single glob).

But anyway for, resolved-globs (which I would now call glob-dirs, btw) you can still do the delete-dups + file-name-directory dance in the initial variable assignment, right?

Also, there seems to be something off in the indentation inside the last progn. It seems it was already broken. Fix that if you can, please.

Previously, if the server requested a glob pattern like foo/**/*
to be watched, we would just error.  Now we watch foo/bar/
and foo/baz/ as if the server had requested those two watchers
instead of just the one with the **.

Limitation: The implementation of file-expand-wildcards doesn't handle
globstars (** does match at most one path segment).

* eglot.el (eglot-register-capability): Use file-expand-wildcards to
make a ** glob into multiple **-less globs.
@juergenhoetzel
Copy link
Contributor Author

Maybe you missed my comment above:

Indeed you're right, I did miss it: we need to keep globs (until a better solution is found, at least. It doesn't make a lot of sense to search all the globs for file changes inside a directory spawned from a single glob).

But anyway for, resolved-globs (which I would now call glob-dirs, btw) you can still do the delete-dups + file-name-directory dance in the initial variable assignment, right?

Good catch!

Also, there seems to be something off in the indentation inside the last progn. It seems it was already broken. Fix that if you can, please.

Of course.

I amended the commit.

@joaotavora joaotavora merged commit 6a7ce66 into joaotavora:master Aug 12, 2019
@joaotavora
Copy link
Owner

Thanks!

nemethf added a commit that referenced this pull request Sep 10, 2019
Previous default (move-to-column) works on visual columns, the LSP
specification and the new default (eglot-move-to-column) use "real"
columns.  Fixes #293 and #297.

* eglot.el (eglot-move-to-column): New function.
(eglot-move-to-column-function): Use it as default.
bhankas pushed a commit to bhankas/emacs that referenced this pull request Sep 18, 2022
Previous default (move-to-column) works on visual columns, the LSP
specification and the new default (eglot-move-to-column) use "real"
columns.  Fixes joaotavora/eglot#293 and joaotavora/eglot#297.

* eglot.el (eglot-move-to-column): New function.
(eglot-move-to-column-function): Use it as default.
bhankas pushed a commit to bhankas/emacs that referenced this pull request Sep 19, 2022
Previous default (move-to-column) works on visual columns, the LSP
specification and the new default (eglot-move-to-column) use "real"
columns.  Fixes joaotavora/eglot#293 and joaotavora/eglot#297.

* eglot.el (eglot-move-to-column): New function.
(eglot-move-to-column-function): Use it as default.
bhankas pushed a commit to bhankas/emacs that referenced this pull request Sep 19, 2022
Previously, if the server requested a glob pattern like foo/**/*
to be watched, we would just error.  Now we watch foo/bar/ and
foo/baz/ as if the server had requested those two watchers
instead of just the one with the **.

As a limitation, the implementation of file-expand-wildcards
doesn't fully handle ** globstars (** matches at most one path
segment).

* eglot.el (eglot-register-capability workspace/didChangeWatchedFiles):
Use file-expand-wildcards to make a ** glob into multiple **-less
globs.
(#293: joaotavora/eglot#293
bhankas pushed a commit to bhankas/emacs that referenced this pull request Sep 19, 2022
Previous default (move-to-column) works on visual columns, the LSP
specification and the new default (eglot-move-to-column) use "real"
columns.  Fixes #293 and #297.

* eglot.el (eglot-move-to-column): New function.
(eglot-move-to-column-function): Use it as default.

#293: joaotavora/eglot#293
#297: joaotavora/eglot#297
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this pull request Oct 12, 2022
Previously, if the server requested a glob pattern like foo/**/*
to be watched, we would just error.  Now we watch foo/bar/ and
foo/baz/ as if the server had requested those two watchers
instead of just the one with the **.

As a limitation, the implementation of file-expand-wildcards
doesn't fully handle ** globstars (** matches at most one path
segment).

* eglot.el (eglot-register-capability workspace/didChangeWatchedFiles):
Use file-expand-wildcards to make a ** glob into multiple **-less
globs.

GitHub-reference: joaotavora/eglot#293
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this pull request Oct 12, 2022
Previous default (move-to-column) works on visual columns, the LSP
specification and the new default (eglot-move-to-column) use "real"
columns.  Fixes joaotavora/eglot#293 and joaotavora/eglot#297.

* eglot.el (eglot-move-to-column): New function.
(eglot-move-to-column-function): Use it as default.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants