2020
2121; ;; Code:
2222
23+ (require  'cl-lib )
24+ (require  'dash )
25+ (require  'ht )
26+ (require  'json )
27+ 
2328(require  'dap-mode )
2429(require  'dap-utils )
2530
@@ -34,43 +39,243 @@ Link: https://marketplace.visualstudio.com/items?itemName=webfreak.debug ."
3439  :group  'dap-js 
3540  :type  '(repeat  string))
3641
37- (defun  dap-js-setup  (&optional  forced )
38-   " Downloading webfreak.debug to path specified.
39- With prefix, FORCED to redownload the extension."  
40-   (interactive  " P" 
41-   (unless  (and  (not  forced) (file-exists-p  dap-js-path))
42-     (lsp-download-install
43-      (lambda  (&rest  _ ) (lsp--info " Downloaded extension!" 
44-      (lambda  (error )  (lsp--error " Failed Downloaded extension %s!" error ))
45-      :url  (lsp--find-latest-gh-release-url
46-            " https://api.github.com/repos/microsoft/vscode-js-debug/releases/latest" 
47-            " js-debug-dap" 
48-      :store-path  dap-js-path
49-      :decompress  :targz )))
42+ (defcustom  dap-js-output-telemetry  t 
43+   " Output telemetry data from js-debug server if non-nil." 
44+   :group  'dap-js 
45+   :type  'boolean )
46+ 
47+ (defcustom  dap-js-extension-version  " latest" 
48+   " The version of the github release found at
49+ https://github.com/microsoft/vscode-js-debug/releases"  
50+   :group  'dap-js 
51+   :type  'string )
52+ 
53+ (dap-utils-github-extension-setup-function " dap-js" " microsoft" " vscode-js-debug" 
54+                                            dap-js-extension-version
55+                                            dap-js-path
56+                                            #'dap-js-extension-build  )
57+ 
58+ (defun  dap-js-extension-build  ()
59+   " Callback from setup function in order to install extension node deps and compile." 
60+   (message  " Building ms-vscode.js-debug in %s  directory. "  dap-js-path)
61+   (let  ((buf (get-buffer-create  " *dap-js extension build*" 
62+         (default-directory  (concat  dap-js-path " /extension" 
63+     (async-shell-command 
64+      " npm install --sav-dev --force; npm run compile -- dapDebugServer" 
65+ 
66+ (cl-defun  dap-js-extension-update  (&optional  (ask-upgrade t ))
67+   " Check for update, and if `ask-upgrade'  arg is non-nil will prompt user to upgrade." 
68+   (interactive )
69+   (let*  ((url (format  dap-utils-github-extension-releases-info-url " microsoft" 
70+                       " vscode-js-debug" " latest" 
71+          (cur-version
72+           (let  ((file (f-join dap-js-path " extension/package.json" 
73+             (when  (file-exists-p  file)
74+               (with-temp-buffer 
75+                 (insert-file-contents  file)
76+                 (goto-char  (point-min ))
77+                 (cdr  (assoc  'version  (json-read )))))))
78+          (latest-version
79+           (let  ((inhibit-message dap-inhibit-io))
80+             (with-current-buffer 
81+                 (if-let  ((buf (url-retrieve-synchronously  url t  t  10 )))
82+                     buf ; returned
83+                   (progn 
84+                     ; ; Probably timeout
85+                     (message  " Problem getting latest version from: %s  "  url)
86+                     (generate-new-buffer  " *dap-js-temp*" 
87+               (if  (/=  (point-max ) 1 )
88+                   (progn 
89+                     (goto-char  (point-min ))
90+                     (re-search-forward  " ^$" 
91+                     (substring  (cdr  (assoc  'tag_name  (json-read ))) 1 ))
92+                 (progn 
93+                   (kill-buffer )
94+                   cur-version))))))
95+     (if  (string=  cur-version latest-version)
96+         (when  ask-upgrade
97+           (message  " ms-vscode.js-debug extension is up to date at version: %s  " 
98+                    latest-version))
99+       (let  ((msg (format  " Newer version (%s ) of vscode/ms-vscode.js-debug exists than \  
100+ currently installed version (%s ). "  latest-version cur-version)))
101+         (if  ask-upgrade
102+             (when  (y-or-n-p  (concat  msg "  Do you want to upgrade now?" 
103+               (dap-js-setup t ))
104+           (message  " %s  Upgrade with `M-x dap-js-extension-update'"  msg))))))
105+ 
106+ ; ; Check extension version when loading, and give a message about upgrading.
107+ (dap-js-extension-update nil )
50108
51109(defun  dap-js--populate-start-file-args  (conf )
52-   " Populate CONF with the required arguments." 
53-   (let  ((port (dap--find-available-port)))
54-     (->  conf
55-         (append 
56-          (list  :debugServer  port
57-                :host  " localhost" 
58-                :type  " pwa-node" 
59-                :program-to-start  (concat  (s-join "  " 
60-                                          "  " 
61-                                          (number-to-string  port))))
62-         (dap--put-if-absent :cwd  default-directory)
63-         (dap--put-if-absent :name  " Node Debug" 
110+   " Load up the start config CONF for the debug adapter from launch.json, and default
111+    required attributes if missing. See full options: 
112+    `https://github.com/microsoft/vscode-js-debug/blob/main/OPTIONS.md' "  
113+   (dap--put-if-absent conf :type  " chrome" 
114+   (dap--put-if-absent conf :cwd  (lsp-workspace-root))
115+   (dap--put-if-absent conf :request  " launch" 
116+   (dap--put-if-absent conf :console  " internalConsole" 
117+   (dap--put-if-absent conf :name  (concat  (plist-get  conf :type ) " -js-debug" 
118+   (let  ((debug-port (dap--find-available-port)))
119+     (dap--put-if-absent conf :host  " localhost" 
120+     (dap--put-if-absent conf :debugServer  debug-port)
121+     (dap--put-if-absent conf :debugPort  debug-port)
122+     (dap--put-if-absent conf :program-to-start 
123+                         (if  (not  (file-exists-p  dap-js-path))
124+                             (error  " DAP program path: %s  does not exist! "  dap-js-path)
125+                           (format  " %s  %s  %s " 
126+                                   (mapconcat  'identity  dap-js-debug-program "  " 
127+                                   (plist-get  conf :debugPort )
128+                                   (plist-get  conf :host )))))
129+   (if  (plist-member  conf :url )
130+       (progn 
131+         ; ;(plist-put conf :mode "url")
132+         (dap--put-if-absent conf :url  (read-string 
133+                                        " Browse url: " 
134+                                        " http://localhost:3000" t ))
135+         (dap--put-if-absent conf :webRoot  (lsp-workspace-root))))
136+   (if  (plist-member  conf :file )
137+       (if  (plist-get  conf :url )
138+           (error  " Both \" file\"  and \" url\"  properties are set in launch.json. \  
139+ Choose one. " )
140+         (progn 
141+           (plist-put  conf :mode  " file" 
142+           (dap--put-if-absent conf :file 
143+                               (read-file-name  " Select the file to open in the browser:" 
144+                                               nil  (buffer-file-name ) t )))))
145+   (if  (plist-member  conf :program )
146+       (dap--put-if-absent conf :program  (read-file-name 
147+                                          " Select the Node.js program to run: " 
148+                                          nil  (buffer-file-name ) t )))
149+   (when  (string=  " node-terminal" plist-get  conf :type ))
150+     (error  " In launch.json \" node-terminal\"  debug type is currently not supported. " ))
151+   (when  (string=  " integratedTerminal" plist-get  conf :console ))
152+     (error  " In launch.json \" console\" :\" integratedTerminal\"  not supported at this \  
153+ time, use \" console\" :\" internalConsole\"  instead " ))
154+   (unless  dap-inhibit-io
155+     (message  " dap-js---populate-start-file-args: %s  "  conf))
156+   conf)
64157
158+ (dap-register-debug-provider " node" #'dap-js--populate-start-file-args  )
159+ (dap-register-debug-provider " node-terminal" #'dap-js--populate-start-file-args  )
160+ (dap-register-debug-provider " chrome" #'dap-js--populate-start-file-args  )
161+ (dap-register-debug-provider " msedge" #'dap-js--populate-start-file-args  )
65162(dap-register-debug-provider " pwa-node" #'dap-js--populate-start-file-args  )
163+ (dap-register-debug-provider " pwa-node" #'dap-js--populate-start-file-args  )
164+ (dap-register-debug-provider " pwa-chrome" #'dap-js--populate-start-file-args  )
165+ (dap-register-debug-provider " pwa-msedge" #'dap-js--populate-start-file-args  )
166+ 
167+ (dap-register-debug-template " Node.js Launch Program" 
168+                              (list  :type  " node" 
169+                                    :cwd  nil 
170+                                    :request  " launch" 
171+                                    :program  nil 
172+                                    :name  " Node.js Launch Program" 
173+ 
174+ (dap-register-debug-template " Chrome Launch File" 
175+                              (list  :type  " chrome" 
176+                                    :cwd  nil 
177+                                    :request  " launch" 
178+                                    :file  nil 
179+                                    :name  " Chrome Launch File" 
180+ 
181+ (dap-register-debug-template " Chrome Launch URL" 
182+                              (list  :type  " chrome" 
183+                                    :cwd  nil 
184+                                    :request  " launch" 
185+                                    :webRoot  nil 
186+                                    :url  nil 
187+                                    :name  " Chrome Launch URL" 
188+ 
189+ 
190+ (add-hook  'dap-session-created-hook  #'dap-js--session-created  )
191+ (defun  dap-js--session-created  (debug-session )
192+   " Set up so that processes won't ask about closing." 
193+   (when-let  (proc (dap--debug-session-program-proc debug-session))
194+     (set-process-query-on-exit-flag  proc nil )))
195+ 
196+ (defun  dap-js--output-filter-function  (debug-session  event )
197+   " Output event data, including for vscode-js-debug, some useful telemetry data.
198+    Future can do something more with the telemetry data than just printing."  
199+   (-let [(&hash " seq" " event" " body" 
200+     (if  (hash-table-p  body)
201+         (progn 
202+           (if  (and  (bound-and-true-p  dap-js-output-telemetry)
203+                    (string=  (gethash  " category" " telemetry" 
204+               (dap--print-to-output-buffer
205+                debug-session (concat  (dap--json-encode body) " \n " 
206+             (dap--print-to-output-buffer
207+              debug-session (concat  (dap--output-buffer-format body) " \n " 
208+ 
209+ (add-hook  'dap-terminated-hook  #'dap-js--term-parent  )
210+ (defun  dap-js--term-parent  (debug-session )
211+   " Kill off parent process when child is disconnected." 
212+   (if  (eq  debug-session (if  (boundp  'parent-debug-session ) parent-debug-session nil ))
213+       (progn 
214+         (when-let  (proc (dap--debug-session-program-proc debug-session))
215+           (when  (process-live-p  proc)
216+             (makunbound  'parent-debug-session )
217+             (set-process-query-on-exit-flag  proc nil )
218+             (with-current-buffer  (process-buffer  proc)
219+               ; ; Switching mode, prevents triggering to open err file after killing proc
220+               (shell-script-mode )
221+               (kill-buffer ))
222+             (dap-delete-session debug-session)))))
223+   (kill-buffer  (dap--debug-session-output-buffer debug-session)))
66224
67- (dap-register-debug-template
68-  " Node Run Configuration (new)" 
69-  (list  :type  " pwa-node" 
70-        :cwd  nil 
71-        :request  " launch" 
72-        :program  nil 
73-        :name  " Node::Run" 
225+ (add-hook  'dap-executed-hook  #'dap-js--reverse-request-handler  )
226+ (defun  dap-js--reverse-request-handler  (debug-session  command )
227+   " Callback hook to get messages from dap-mode reverse requests." 
228+   ; ;This is set with `add-hook'  above.
229+   (unless  dap-inhibit-io
230+     (message  " dap-js--reverse-request-handler -> command: %s  "  command))
231+   (pcase  command
232+     ((guard (string=  command " startDebugging" 
233+      ; ; Assume current session now parent requesting start debugging in child session
234+      (setq  parent-debug-session debug-session)
235+      (-let [(&hash " seq" " command" " arguments" 
236+                    (&hash " request" " configuration" 
237+                           (&hash?  " type" " __pendingTargetId" 
238+             (dap--debug-session-metadata debug-session)]
239+        (-let (((&plist  :mode  :url  :file  :webroot  :program  :outputCapture 
240+                         :skipFiles  :timeout  :host  :name  :debugPort )
241+                (dap--debug-session-launch-args debug-session))
242+               (conf `(:request  , request
243+          ; ; DAP Spec says not to include client variables to start child, including type
244+          ; ;(plist-put conf :type type)
245+          (plist-put  conf :name  (concat  type " -" 
246+          (plist-put  conf :__pendingTargetId  __pendingTargetId)
247+          (plist-put  conf :outputCapture  outputCapture)
248+          (plist-put  conf :skipFiles  skipFiles)
249+          (plist-put  conf :timeout  timeout)
250+          (plist-put  conf :host  host)
251+          (plist-put  conf :debugServer  debugPort)
252+          (plist-put  conf :debugPort  debugPort)
253+          (if  (or  (string=  " pwa-node" string=  " node" 
254+              (plist-put  conf :program  program)
255+            (progn 
256+              (if  (string=  mode " file" 
257+                  (plist-put  conf :file  file)
258+                (progn 
259+                  (plist-put  conf :url  url)
260+                  (plist-put  conf :webroot  webroot)))))
261+          (unless  dap-inhibit-io
262+            (message  " dap-js startDebugging conf: %s  "  conf))
263+          (dap-start-debugging-noexpand conf)
264+          ; ; Remove child session if stored in list of recent/last configurations to
265+          ; ; allow `dap-debug-last'  to work by getting parent not child.
266+          (when-let  ((last-conf (cdr  (cl-first  dap--debug-configuration)))
267+                     (_ptid-equal (string=  __pendingTargetId
268+                                           (plist-get  last-conf :__pendingTargetId ))))
269+            (pop  dap--debug-configuration))
270+          ; ; success
271+          (dap--send-message (dap--make-success-response seq command)
272+                             (dap--resp-handler) debug-session))))
273+     ; ; This is really just confirmation response, but good place to ensure session
274+     ; ; selected
275+     (" launch" 
276+     (_
277+      (unless  dap-inhibit-io
278+        (message  " command: %s  wasn't handled by dap-js. "  command)))))
74279
75280(provide  'dap-js )
76281; ;; dap-js.el ends here
0 commit comments