Skip to content

Commit 807f82d

Browse files
committed
WIP - check for emulators using flutter daemon
1 parent 2681876 commit 807f82d

File tree

2 files changed

+199
-10
lines changed

2 files changed

+199
-10
lines changed

lsp-dart-dap.el

Lines changed: 86 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
(require 'dap-utils)
3030

3131
(require 'lsp-dart-project)
32+
(require 'lsp-dart-flutter-daemon)
3233

3334
(defcustom lsp-dart-dap-extension-version "3.9.1"
3435
"The extension version."
@@ -85,24 +86,36 @@ Required to support 'Inspect Widget'."
8586
:group 'lsp-dart
8687
:type 'string)
8788

89+
(defcustom lsp-dart-dap-flutter-verbose-log nil
90+
"Whether to enable logs from Flutter DAP."
91+
:group 'lsp-dart
92+
:type 'boolean)
8893

8994

9095
;;; Internal
9196

9297
(defconst lsp-dart-dap--devtools-buffer-name "*LSP Dart - DevTools*")
9398
(defconst lsp-dart-dap--pub-list-pacakges-buffer-name "*LSP Dart - Pub list packages*")
9499

100+
(defun lsp-dart-dap-log (msg &rest args)
101+
"Log MSG with ARGS adding lsp-dart-dap prefix."
102+
(lsp-dart-project-log (concat
103+
(propertize "[DAP] "
104+
'face 'font-lock-function-name-face)
105+
msg
106+
args)))
107+
95108
(defun lsp-dart-dap--setup-extension ()
96109
"Setup dart debugger extension to run `lsp-dart-dap-dart-debugger-program`."
97-
(lsp-dart-project-log "Setting up DAP...")
110+
(lsp-dart-dap-log "Setting up debugger...")
98111
(lsp-async-start-process
99112
(lambda ()
100113
(lsp-async-start-process
101-
(lambda () (lsp-dart-project-log "DAP setup done!"))
102-
(lambda (_) (lsp-dart-project-log "Error setting up lsp-dart-dap, check if `npm` is on $PATH"))
114+
(lambda () (lsp-dart-dap-log "Setup done!"))
115+
(lambda (_) (lsp-dart-dap-log "Error setting up DAP, check if `npm` is on $PATH"))
103116
(f-join lsp-dart-dap-debugger-path "extension/node_modules/typescript/bin/tsc")
104117
"--project" (f-join lsp-dart-dap-debugger-path "extension")))
105-
(lambda (_) (lsp-dart-project-log "Error setting up lsp-dart-dap, check if `npm` is on $PATH"))
118+
(lambda (_) (lsp-dart-dap-log "Error setting up DAP, check if `npm` is on $PATH"))
106119
"npm" "install" "--prefix" (f-join lsp-dart-dap-debugger-path "extension")
107120
"--no-package-lock" "--silent" "--no-save"))
108121

@@ -134,8 +147,17 @@ Required to support 'Inspect Widget'."
134147

135148
(defun lsp-dart-dap--flutter-get-or-create-device ()
136149
"Return the device to debug or prompt to start it."
137-
(ht ('id "emulator-5554")
138-
('name "device")))
150+
(-let* ((devices (lsp-dart-flutter-daemon-get-emulators))
151+
(chosen-device (dap--completing-read "Select a device to use: "
152+
devices
153+
(-lambda ((&hash "id" "name" "category" "platformType" platform))
154+
(format "%s - %s" platform (if name name id)))
155+
nil
156+
t))
157+
(emulator (lsp-dart-flutter-daemon-launch chosen-device)))
158+
(ht ('id "emulator-5554")
159+
('name "device"))
160+
))
139161

140162
(defun lsp-dart-dap--populate-flutter-start-file-args (conf)
141163
"Populate CONF with the required arguments for Flutter debug."
@@ -163,6 +185,60 @@ Required to support 'Inspect Widget'."
163185
:flutterPlatform "default"
164186
:name "Flutter"))
165187

188+
(defvar lsp-dart-dap--flutter-progress-reporter nil)
189+
190+
(cl-defmethod dap-handle-event ((_event (eql dart.log)) _session params)
191+
"Handle debugger uris EVENT for SESSION with PARAMS."
192+
(when lsp-dart-dap-flutter-verbose-log
193+
(-let* (((&hash "message") params)
194+
(msg (replace-regexp-in-string (regexp-quote "\n") "" message nil 'literal)))
195+
(lsp-dart-dap-log msg))))
196+
197+
(cl-defmethod dap-handle-event ((_event (eql dart.launching)) _session params)
198+
"Handle debugger uris EVENT for SESSION with PARAMS."
199+
(let ((prefix (concat (propertize "[LSP Dart] "
200+
'face 'font-lock-keyword-face)
201+
(propertize "[DAP] "
202+
'face 'font-lock-function-name-face))))
203+
(setq lsp-dart-dap--flutter-progress-reporter
204+
(make-progress-reporter (concat prefix (gethash "message" params))))))
205+
206+
(cl-defmethod dap-handle-event ((_event (eql dart.launched)) _session _params)
207+
"Handle debugger uris EVENT for SESSION with PARAMS."
208+
(when lsp-dart-dap--flutter-progress-reporter
209+
(progress-reporter-done lsp-dart-dap--flutter-progress-reporter))
210+
(lsp-dart-dap-log "Loading app..."))
211+
212+
(cl-defmethod dap-handle-event ((_event (eql dart.progress)) _session params)
213+
"Handle debugger uris EVENT for SESSION with PARAMS."
214+
(-let (((&hash "message") params)
215+
(prefix (concat (propertize "[LSP Dart] "
216+
'face 'font-lock-keyword-face)
217+
(propertize "[DAP] "
218+
'face 'font-lock-function-name-face))))
219+
(when (and message lsp-dart-dap--flutter-progress-reporter)
220+
(progress-reporter-force-update lsp-dart-dap--flutter-progress-reporter nil (concat prefix message)))))
221+
222+
(cl-defmethod dap-handle-event ((_event (eql dart.flutter.firstFrame)) _session _params)
223+
"Handle debugger uris EVENT for SESSION with PARAMS."
224+
(setq lsp-dart-dap--flutter-progress-reporter nil)
225+
(lsp-dart-dap-log "App ready!"))
226+
227+
(cl-defmethod dap-handle-event ((_event (eql dart.serviceRegistered)) _session _params)
228+
"Handle debugger uris EVENT for SESSION with PARAMS.")
229+
(cl-defmethod dap-handle-event ((_event (eql dart.serviceExtensionAdded)) _session _params)
230+
"Handle debugger uris EVENT for SESSION with PARAMS.")
231+
(cl-defmethod dap-handle-event ((_event (eql dart.flutter.serviceExtensionStateChanged)) _session _params)
232+
"Handle debugger uris EVENT for SESSION with PARAMS.")
233+
(cl-defmethod dap-handle-event ((_event (eql dart.hotRestartRequest)) _session _params)
234+
"Handle debugger uris EVENT for SESSION with PARAMS.")
235+
(cl-defmethod dap-handle-event ((_event (eql dart.hotReloadRequest)) _session _params)
236+
"Handle debugger uris EVENT for SESSION with PARAMS.")
237+
(cl-defmethod dap-handle-event ((_event (eql dart.debugMetrics)) _session _params)
238+
"Handle debugger uris EVENT for SESSION with PARAMS.")
239+
(cl-defmethod dap-handle-event ((_event (eql dart.navigate)) _session _params)
240+
"Handle debugger uris EVENT for SESSION with PARAMS.")
241+
166242
;; DevTools
167243

168244
(cl-defmethod dap-handle-event ((_event (eql dart.debuggerUris)) _session params)
@@ -208,13 +284,13 @@ If URI is not found on buffer, schedule re-check."
208284

209285
(defun lsp-dart-dap--activate-devtools (callback)
210286
"Activate Dart Devtools via pub then call CALLBACK."
211-
(lsp-dart-project-log "Activating DevTools...")
287+
(lsp-dart-dap-log "Activating DevTools...")
212288
(let ((pub (lsp-dart-project-get-pub-command)))
213289
(lsp-async-start-process
214290
(lambda ()
215-
(lsp-dart-project-log "DevTools activated successfully!")
291+
(lsp-dart-dap-log "DevTools activated successfully!")
216292
(funcall callback))
217-
(lambda (_) (lsp-dart-project-log "Could not Activate DevTools. \
293+
(lambda (_) (lsp-dart-dap-log "Could not Activate DevTools. \
218294
Try to activate manually running 'pub global activate devtools'"))
219295
pub "global" "activate" "devtools")))
220296

@@ -275,7 +351,7 @@ If it is already activated or after activated successfully, call CALLBACK."
275351
(when (and session vm-service-uri)
276352
(lsp-dart-dap--start-devtools
277353
(lambda (uri)
278-
(lsp-dart-project-log "Openning DevTools at browser...")
354+
(lsp-dart-dap-log "Openning DevTools at browser...")
279355
(lsp-dart-dap--open-devtools uri vm-service-uri))))))
280356

281357
(provide 'lsp-dart-dap)

lsp-dart-flutter-daemon.el

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
;;; lsp-dart-flutter-daemon.el --- Helper for the Flutter daemon -*- lexical-binding: t; -*-
2+
;;
3+
;; Version: 1.8
4+
;; Keywords: languages, extensions
5+
;; Package-Requires: ((emacs "25.2") (lsp-mode "6.0"))
6+
;; URL: https://github.com/emacs-lsp/lsp-dart.el
7+
;;
8+
;; This program is free software; you can redistribute it and/or modify
9+
;; it under the terms of the GNU General Public License as published by
10+
;; the Free Software Foundation, either version 3 of the License, or
11+
;; (at your option) any later version.
12+
13+
;; This program is distributed in the hope that it will be useful,
14+
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
;; GNU General Public License for more details.
17+
18+
;; You should have received a copy of the GNU General Public License
19+
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
20+
;;
21+
;;; Commentary:
22+
;;
23+
;; Helper for the Flutter daemon
24+
;;
25+
;;; Code:
26+
27+
(require 'comint)
28+
(require 'lsp-mode)
29+
30+
(require 'lsp-dart-project)
31+
32+
(defconst lsp-dart-flutter-daemon-buffer-name "*LSP Dart - Flutter daemon*")
33+
(defconst lsp-dart-flutter-daemon-name "LSP Dart - Flutter daemon")
34+
35+
(defun lsp-dart-flutter-daemon--generate-command-id ()
36+
"Generate a random command id."
37+
(random 10000))
38+
39+
(defun lsp-dart-flutter-daemon--start ()
40+
"Start the Flutter daemon."
41+
(let ((buffer (get-buffer-create lsp-dart-flutter-daemon-buffer-name)))
42+
(make-comint-in-buffer lsp-dart-flutter-daemon-name buffer lsp-dart-project-flutter-command nil "daemon")
43+
(with-current-buffer buffer
44+
(unless (derived-mode-p 'lsp-dart-flutter-daemon-mode)
45+
(lsp-dart-flutter-daemon-mode)))
46+
;; We need to wait the daemon start
47+
(sit-for 1)))
48+
49+
(defun lsp-dart-flutter-daemon--build-command (id method &optional params)
50+
"Build a command from an ID and METHOD.
51+
PARAMS is the optional method params."
52+
(let ((command (ht ("id" id)
53+
("method" method))))
54+
(when params
55+
(ht-set! command "params" params))
56+
(concat "["
57+
(lsp--json-serialize command)
58+
"]\n")))
59+
60+
(defvar lsp-dart-flutter-daemon-response nil)
61+
62+
(defun lsp-dart-flutter-daemon-handle-response (id event-name response)
63+
"Handle RESPONSE and save if it is for ID.
64+
Wait for next response if EVENT-NAME is non null."
65+
(when (string-prefix-p "[" response)
66+
(-let* (((&hash "id" resp-id "result" "event" "params") (lsp--read-json (substring response 1 -2))))
67+
(if event-name
68+
(when (string= event event-name)
69+
(setq lsp-dart-flutter-daemon-response params))
70+
(when (= resp-id id)
71+
(setq lsp-dart-flutter-daemon-response result))))))
72+
73+
(defun lsp-dart-flutter-daemon-running-p ()
74+
"Return non-nil if the Flutter daemon is already running."
75+
(comint-check-proc lsp-dart-flutter-daemon-buffer-name))
76+
77+
(defun lsp-dart-flutter-daemon--send (method &optional params event-name)
78+
"Send a command with METHOD to a Flutter daemon and await for a response.
79+
PARAMS is the optional method args and should be a hash-table.
80+
If EVENT-NAME is non-nil, it will this event to return its value.
81+
Starts the daemon if is not running yet."
82+
(unless (lsp-dart-flutter-daemon-running-p)
83+
(lsp-dart-flutter-daemon--start))
84+
(setq lsp-dart-flutter-daemon-response nil)
85+
(let* ((id (lsp-dart-flutter-daemon--generate-command-id))
86+
(command (lsp-dart-flutter-daemon--build-command id method params)))
87+
(remove-hook 'comint-output-filter-functions (-partial #'lsp-dart-flutter-daemon-handle-response id event-name) t)
88+
(add-hook 'comint-output-filter-functions (-partial #'lsp-dart-flutter-daemon-handle-response id event-name))
89+
(comint-send-string (get-buffer-process lsp-dart-flutter-daemon-buffer-name) command)
90+
(while (not lsp-dart-flutter-daemon-response)
91+
(sit-for 0.1))
92+
lsp-dart-flutter-daemon-response))
93+
94+
(defun lsp-dart-flutter-daemon-get-emulators ()
95+
"Return the available emulators from Flutter daemon."
96+
(lsp-dart-flutter-daemon--send "emulator.getEmulators"))
97+
98+
(defun lsp-dart-flutter-daemon-launch (device)
99+
"Launch emulator for DEVICE and wait for connected state."
100+
(-let* (((&hash "id") device)
101+
(params (ht ('emulatorId id))))
102+
(lsp-dart-flutter-daemon--send "device.enable")
103+
(lsp-dart-flutter-daemon--send "emulator.launch" params "device.added")))
104+
105+
;;;###autoload
106+
(define-derived-mode lsp-dart-flutter-daemon-mode comint-mode lsp-dart-flutter-daemon-name
107+
"Major mode for `lsp-dart-flutter-daemon--start`."
108+
(setq comint-prompt-read-only nil)
109+
(setq comint-process-echoes nil)
110+
(setenv "PATH" (concat (lsp-dart-project-get-flutter-path) ":" (getenv "PATH"))))
111+
112+
(provide 'lsp-dart-flutter-daemon)
113+
;;; lsp-dart-flutter-daemon.el ends here

0 commit comments

Comments
 (0)