22; ;
33; ; Version: 1.8
44; ; Keywords: languages, extensions
5- ; ; Package-Requires: ((emacs "25.2") (lsp-mode "6.0"))
5+ ; ; Package-Requires: ((emacs "25.2") (lsp-mode "6.0") (dash "2.14.1") )
66; ; URL: https://github.com/emacs-lsp/lsp-dart.el
77; ;
88; ; This program is free software; you can redistribute it and/or modify
2525; ;; Code:
2626
2727(require 'comint )
28+ (require 'dash )
29+ (require 'ht )
2830(require 'lsp-mode )
2931
3032(require 'lsp-dart-project )
3133
3234(defconst lsp-dart-flutter-daemon-buffer-name " *LSP Dart - Flutter daemon*" )
3335(defconst lsp-dart-flutter-daemon-name " LSP Dart - Flutter daemon" )
3436
37+ (defvar lsp-dart-flutter-daemon-current-command nil )
38+ (defvar lsp-dart-flutter-daemon-current-device nil )
39+
40+ (defun lsp-dart-flutter-daemon-log (level msg &rest args )
41+ " Log for LEVEL, MSG with ARGS adding lsp-dart-flutter-daemon prefix."
42+ (lsp-dart-project-log (concat
43+ (propertize (concat " [FLUTTER " (upcase level) " ] " )
44+ 'face 'font-lock-function-name-face )
45+ msg
46+ args)))
47+
3548(defun lsp-dart-flutter-daemon--generate-command-id ()
3649 " Generate a random command id."
3750 (random 10000 ))
@@ -57,50 +70,80 @@ PARAMS is the optional method params."
5770 (lsp--json-serialize command)
5871 " ]\n " )))
5972
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))
73+ (defun lsp-dart-flutter-daemon-raw->response (response )
74+ " Parse raw RESPONSE into a list of responses."
75+ (when (string-prefix-p " [" (string-trim response))
76+ (--> response
77+ string-trim
78+ (replace-regexp-in-string (regexp-quote " \n " ) " " it nil 'literal )
79+ (replace-regexp-in-string (regexp-quote " ][" ) " ]\n [" it nil 'literal )
80+ (split-string it " \n " )
81+ (-map (lambda (el ) (seq-first (lsp--read-json el))) it))))
82+
83+ (defun lsp-dart-flutter-daemon-handle-events (raw-response )
84+ " Handle Flutter daemon events from RAW-RESPONSE."
85+ (-map (-lambda ((&hash " event" " params" (params &as &hash? " level" " message" )))
86+ (when event
87+ (pcase event
88+ (" device.removed" (setq lsp-dart-flutter-daemon-current-device nil ))
89+
90+ (" device.added" (setq lsp-dart-flutter-daemon-current-device params))
91+
92+ (" daemon.logMessage" (lsp-dart-flutter-daemon-log level message)))))
93+ (lsp-dart-flutter-daemon-raw->response raw-response)))
94+
95+ (defun lsp-dart-flutter-daemon-handle-response (raw-response )
96+ " Handle the RAW-RESPONSE from comint output."
97+ (when lsp-dart-flutter-daemon-current-command
98+ (--map
99+ (-let* (((&hash " id" resp-id " result" " event" " params" ) it)
100+ ((&hash " id" " callback" " event-name" ) lsp-dart-flutter-daemon-current-command))
101+ (if event-name
102+ (when (string= event event-name)
103+ (remove-hook 'comint-output-filter-functions #'lsp-dart-flutter-daemon-handle-response )
104+ (funcall callback params))
70105 (when (= resp-id id)
71- (setq lsp-dart-flutter-daemon-response result))))))
106+ (remove-hook 'comint-output-filter-functions #'lsp-dart-flutter-daemon-handle-response )
107+ (if result
108+ (funcall callback result)
109+ (funcall callback)))))
110+ (lsp-dart-flutter-daemon-raw->response raw-response))))
72111
73112(defun lsp-dart-flutter-daemon-running-p ()
74113 " Return non-nil if the Flutter daemon is already running."
75114 (comint-check-proc lsp-dart-flutter-daemon-buffer-name))
76115
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.
116+ (defun lsp-dart-flutter-daemon--send (method callback &optional params event-name )
117+ " Send a command with METHOD to the daemon and call CALLBACK with the response.
79118PARAMS is the optional method args and should be a hash-table.
80119If EVENT-NAME is non-nil, it will this event to return its value.
81120Starts the daemon if is not running yet."
82121 (unless (lsp-dart-flutter-daemon-running-p)
83122 (lsp-dart-flutter-daemon--start))
84- (setq lsp-dart-flutter-daemon-response nil )
85123 (let* ((id (lsp-dart-flutter-daemon--generate-command-id))
86124 (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" )))
125+ (setq lsp-dart-flutter-daemon-current-command (ht (" id" id)
126+ (" callback" callback)
127+ (" event-name" event-name)))
128+ (add-hook 'comint-output-filter-functions #'lsp-dart-flutter-daemon-handle-response )
129+ (comint-send-string (get-buffer-process lsp-dart-flutter-daemon-buffer-name) command)))
130+
131+ (defun lsp-dart-flutter-daemon-get-emulators (callback )
132+ " Call CALLBACK with the available emulators from Flutter daemon."
133+ (lsp-dart-flutter-daemon--send " emulator.getEmulators" callback))
134+
135+ (defun lsp-dart-flutter-daemon-launch (device callback )
136+ " Launch emulator for DEVICE and wait for connected state and call CALLBACK."
137+ (if lsp-dart-flutter-daemon-current-device
138+ (funcall callback lsp-dart-flutter-daemon-current-device)
139+ (-let* (((&hash " id" ) device)
140+ (params (ht (" emulatorId" id))))
141+ (lsp-dart-flutter-daemon--send
142+ " device.enable"
143+ (lambda ()
144+ (remove-hook 'comint-output-filter-functions #'lsp-dart-flutter-daemon-handle-events )
145+ (add-hook 'comint-output-filter-functions #'lsp-dart-flutter-daemon-handle-events )
146+ (lsp-dart-flutter-daemon--send " emulator.launch" callback params " device.added" ))))))
104147
105148;;;### autoload
106149(define-derived-mode lsp-dart-flutter-daemon-mode comint-mode lsp-dart-flutter-daemon-name
0 commit comments