Skip to content

Commit 960d06f

Browse files
danielmartinyyoncho
authored andcommittedJan 20, 2019
Add Flow Language Server support (#603)
* Add support for JavaScript Flow LSP This language server is considered an "add-on", that is, it will be enabled simultaneously with another JavaScript/TypeScript server if both are present and the buffer meets the conditions of a Flow source file. The server used is the official one from https://flow.org, which is supposedly the one that will be better supported now and in the future. In order to fine grain the decision of when to enable this server, a new `activation-fn` has been added to the `lsp-client` structure. If present, this function overrides `major-modes` and `remote?`, in case that any of them are also present when registering a new language client. In particular, the new Flow client considers that the file is a Flow file if the following conditions are met: - The major mode is one of js-mode, js2-mode, or flow-js2-mode. - The file resides in a Flow project (there is a .flowconfig file). - The file has a `// @flow` or `/* @flow */` tag. * Update README * Remove redundant lambda
1 parent bb9ca39 commit 960d06f

File tree

3 files changed

+76
-5
lines changed

3 files changed

+76
-5
lines changed
 

‎README.org

+3-2
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,9 @@
106106
| HTML | [[https://github.com/vscode-langservers/vscode-html-languageserver][html]] | Yes | npm install -g vscode-html-languageserver-bin | |
107107
| Haskell | [[https://github.com/haskell/haskell-ide-engine][IDE engine]] | [[https://github.com/emacs-lsp/lsp-haskell][lsp-haskell]] | [[https://github.com/haskell/haskell-ide-engine][IDE engine]] | |
108108
| Java | [[https://github.com/eclipse/eclipse.jdt.ls][Eclipse JDT LS]] | [[https://github.com/emacs-lsp/lsp-java][lsp-java]] | Automatic by [[https://github.com/emacs-lsp/lsp-java][lsp-java]] | Yes |
109-
| Javascript/Typescript | [[https://github.com/theia-ide/typescript-language-server][typescript-language-server]] (recommended) | Yes | npm i -g typescript-language-server | |
110-
| Javascript/Typescript | [[https://github.com/sourcegraph/javascript-typescript-langserver][javascript-typescript-stdio]] | Yes | npm i -g javascript-typescript-langserver | |
109+
| JavaScript/TypeScript | [[https://github.com/theia-ide/typescript-language-server][typescript-language-server]] (recommended) | Yes | npm i -g typescript-language-server | |
110+
| JavaScript/TypeScript | [[https://github.com/sourcegraph/javascript-typescript-langserver][javascript-typescript-stdio]] | Yes | npm i -g javascript-typescript-langserver | |
111+
| JavaScript Flow | [[https://flow.org][flow]] (add-on if working on a Flow file) | Yes | [[https://flow.org][flow]] | |
111112
| Ocaml | [[https://github.com/freebroccolo/ocaml-language-server][ocaml-language-server]] | Yes | [[https://github.com/freebroccolo/ocaml-language-server][ocaml-language-server]] | |
112113
| PHP | [[https://github.com/felixfbecker/php-language-server][php-language-server]] | Yes | [[https://github.com/felixfbecker/php-language-server][php-language-server]] | |
113114
| Python | [[https://github.com/palantir/python-language-server][pyls]] | Yes | pip install 'python-language-server[all]' | Yes |

‎lsp-clients.el

+62
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,68 @@ finding the executable with variable `exec-path'."
143143
:server-id 'ts-ls))
144144

145145

146+
147+
;;; JavaScript Flow
148+
(defcustom lsp-clients-flow-server "flow"
149+
"The Flow executable to use.
150+
Leave as just the executable name to use the default behavior of
151+
finding the executable with variable `exec-path'."
152+
:group 'lsp-flow
153+
:risky t
154+
:type 'file)
155+
156+
(defcustom lsp-clients-flow-server-args '("lsp")
157+
"Extra arguments for starting the Flow language server."
158+
:group 'lsp-flow
159+
:risky t
160+
:type '(repeat string))
161+
162+
(defun lsp-clients-flow-tag-present-p (file-name)
163+
"Checks if the '// @flow' or `/* @flow */' tag is present in
164+
the contents of FILE-NAME."
165+
(with-temp-buffer
166+
(insert-file-contents file-name)
167+
(save-excursion
168+
(goto-char (point-min))
169+
(let (stop found)
170+
(while (not stop)
171+
(when (not (re-search-forward "[^\n[:space:]]" nil t))
172+
(setq stop t))
173+
(if (equal (point) (point-min))
174+
(setq stop t)
175+
(backward-char))
176+
(cond ((or (looking-at "//+[ ]*@flow")
177+
(looking-at "/\\**[ ]*@flow"))
178+
(setq found t)
179+
(setq stop t))
180+
((looking-at "//")
181+
(forward-line))
182+
((looking-at "/\\*")
183+
(when (not (re-search-forward "*/" nil t))
184+
(setq stop t)))
185+
(t (setq stop t))))
186+
found))))
187+
188+
(defun lsp-clients-flow-project-p (file-name)
189+
"Checks if FILE-NAME is part of a Flow project, that is, if
190+
there is a .flowconfig file in the folder hierarchy."
191+
(locate-dominating-file file-name ".flowconfig"))
192+
193+
(defun lsp-clients-flow-activate-p (file-name major-mode)
194+
"Checks if the Flow language server should be enabled for a
195+
particular FILE-NAME and MAJOR-MODE."
196+
(and (member major-mode '(js-mode js2-mode flow-js2-mode))
197+
(lsp-clients-flow-project-p file-name)
198+
(lsp-clients-flow-tag-present-p file-name)))
199+
200+
(lsp-register-client
201+
(make-lsp-client :new-connection (lsp-stdio-connection
202+
(-const `(,lsp-clients-flow-server
203+
,@lsp-clients-flow-server-args)))
204+
:activation-fn 'lsp-clients-flow-activate-p
205+
:add-on? t
206+
:server-id 'flow-ls))
207+
146208
;;; Vue
147209
(defcustom lsp-clients-vue-server "vls"
148210
"The vue-language-server executable to use.

‎lsp-mode.el

+11-3
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,12 @@ INHERIT-INPUT-METHOD will be proxied to `completing-read' without changes."
654654

655655
;; major modes supported by the client.
656656
(major-modes)
657+
;; Function that will be called to decide if this language client
658+
;; should manage a particular buffer. The function will be passed
659+
;; the file name and major mode to inform the decision. Setting
660+
;; `activation-fn' will override `major-modes' and `remote?', if
661+
;; present.
662+
(activation-fn)
657663
;; Break the tie when major-mode is supported by multiple clients.
658664
(priority 0)
659665
;; Unique identifier for
@@ -3453,9 +3459,11 @@ remote machine and vice versa."
34533459
(--when-let (->> lsp-clients
34543460
hash-table-values
34553461
(-filter (-lambda (client)
3456-
(and (-contains? (lsp--client-major-modes client) buffer-major-mode)
3457-
(-some-> client lsp--client-new-connection (plist-get :test?) funcall)
3458-
(eq (---truthy? remote?) (---truthy? (lsp--client-remote? client)))))))
3462+
(and (or
3463+
(-some-> client lsp--client-activation-fn (funcall buffer-file-name buffer-major-mode))
3464+
(and (-contains? (lsp--client-major-modes client) buffer-major-mode)
3465+
(eq (---truthy? remote?) (---truthy? (lsp--client-remote? client)))))
3466+
(-some-> client lsp--client-new-connection (plist-get :test?) funcall)))))
34593467
(-let (((add-on-clients main-clients) (-separate 'lsp--client-add-on? it)))
34603468
;; Pick only one client (with the highest priority) that is not declared as add-on? t.
34613469
(cons (and main-clients (--max-by (> (lsp--client-priority it) (lsp--client-priority other)) main-clients))

0 commit comments

Comments
 (0)