Detailed changes
@@ -8549,6 +8549,15 @@ dependencies = [
"tree-sitter",
]
+[[package]]
+name = "tree-sitter-purescript"
+version = "1.0.0"
+source = "git+https://github.com/ivanmoreau/tree-sitter-purescript?rev=a37140f0c7034977b90faa73c94fcb8a5e45ed08#a37140f0c7034977b90faa73c94fcb8a5e45ed08"
+dependencies = [
+ "cc",
+ "tree-sitter",
+]
+
[[package]]
name = "tree-sitter-python"
version = "0.20.4"
@@ -9739,6 +9748,7 @@ dependencies = [
"tree-sitter-nix",
"tree-sitter-nu",
"tree-sitter-php",
+ "tree-sitter-purescript",
"tree-sitter-python",
"tree-sitter-racket",
"tree-sitter-ruby",
@@ -148,6 +148,7 @@ tree-sitter-json = { git = "https://github.com/tree-sitter/tree-sitter-json", re
tree-sitter-rust = "0.20.3"
tree-sitter-markdown = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "330ecab87a3e3a7211ac69bbadc19eabecdb1cca" }
tree-sitter-php = "0.21.1"
+tree-sitter-purescript = { git = "https://github.com/ivanmoreau/tree-sitter-purescript", rev = "a37140f0c7034977b90faa73c94fcb8a5e45ed08" }
tree-sitter-python = "0.20.2"
tree-sitter-toml = { git = "https://github.com/tree-sitter/tree-sitter-toml", rev = "342d9be207c2dba869b9967124c679b5e6fd0ebe" }
tree-sitter-typescript = { git = "https://github.com/tree-sitter/tree-sitter-typescript", rev = "5d20856f34315b068c41edaee2ac8a100081d259" }
@@ -134,6 +134,7 @@ tree-sitter-ruby.workspace = true
tree-sitter-haskell.workspace = true
tree-sitter-html.workspace = true
tree-sitter-php.workspace = true
+tree-sitter-purescript.workspace = true
tree-sitter-scheme.workspace = true
tree-sitter-svelte.workspace = true
tree-sitter-racket.workspace = true
@@ -23,6 +23,7 @@ mod language_plugin;
mod lua;
mod nu;
mod php;
+mod purescript;
mod python;
mod ruby;
mod rust;
@@ -258,6 +259,13 @@ pub fn init(
],
);
+ language(
+ "purescript",
+ tree_sitter_purescript::language(),
+ vec![Arc::new(purescript::PurescriptLspAdapter::new(
+ node_runtime.clone(),
+ ))],
+ );
language("elm", tree_sitter_elm::language(), vec![]);
language("glsl", tree_sitter_glsl::language(), vec![]);
language("nix", tree_sitter_nix::language(), vec![]);
@@ -0,0 +1,139 @@
+use anyhow::{anyhow, Result};
+use async_trait::async_trait;
+use collections::HashMap;
+use futures::StreamExt;
+use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
+use lsp::LanguageServerBinary;
+use node_runtime::NodeRuntime;
+use serde_json::json;
+use smol::fs;
+use std::{
+ any::Any,
+ ffi::OsString,
+ path::{Path, PathBuf},
+ sync::Arc,
+};
+use util::{async_maybe, ResultExt};
+
+const SERVER_PATH: &'static str = "node_modules/.bin/purescript-language-server";
+
+fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
+ vec![server_path.into(), "--stdio".into()]
+}
+
+pub struct PurescriptLspAdapter {
+ node: Arc<dyn NodeRuntime>,
+}
+
+impl PurescriptLspAdapter {
+ pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
+ Self { node }
+ }
+}
+
+#[async_trait]
+impl LspAdapter for PurescriptLspAdapter {
+ fn name(&self) -> LanguageServerName {
+ LanguageServerName("purescript-language-server".into())
+ }
+
+ fn short_name(&self) -> &'static str {
+ "purescript"
+ }
+
+ async fn fetch_latest_server_version(
+ &self,
+ _: &dyn LspAdapterDelegate,
+ ) -> Result<Box<dyn 'static + Send + Any>> {
+ Ok(Box::new(
+ self.node
+ .npm_package_latest_version("purescript-language-server")
+ .await?,
+ ) as Box<_>)
+ }
+
+ async fn fetch_server_binary(
+ &self,
+ version: Box<dyn 'static + Send + Any>,
+ container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Result<LanguageServerBinary> {
+ let version = version.downcast::<String>().unwrap();
+ let server_path = container_dir.join(SERVER_PATH);
+
+ if fs::metadata(&server_path).await.is_err() {
+ self.node
+ .npm_install_packages(
+ &container_dir,
+ &[("purescript-language-server", version.as_str())],
+ )
+ .await?;
+ }
+
+ Ok(LanguageServerBinary {
+ path: self.node.binary_path().await?,
+ arguments: server_binary_arguments(&server_path),
+ })
+ }
+
+ async fn cached_server_binary(
+ &self,
+ container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary> {
+ get_cached_server_binary(container_dir, &*self.node).await
+ }
+
+ async fn installation_test_binary(
+ &self,
+ container_dir: PathBuf,
+ ) -> Option<LanguageServerBinary> {
+ get_cached_server_binary(container_dir, &*self.node).await
+ }
+
+ fn initialization_options(&self) -> Option<serde_json::Value> {
+ Some(json!({
+ "purescript": {
+ "addSpagoSources": true
+ }
+ }))
+ }
+
+ fn language_ids(&self) -> HashMap<String, String> {
+ [("PureScript".into(), "purescript".into())]
+ .into_iter()
+ .collect()
+ }
+}
+
+async fn get_cached_server_binary(
+ container_dir: PathBuf,
+ node: &dyn NodeRuntime,
+) -> Option<LanguageServerBinary> {
+ async_maybe!({
+ let mut last_version_dir = None;
+ let mut entries = fs::read_dir(&container_dir).await?;
+ while let Some(entry) = entries.next().await {
+ let entry = entry?;
+ if entry.file_type().await?.is_dir() {
+ last_version_dir = Some(entry.path());
+ }
+ }
+
+ let last_version_dir = last_version_dir.ok_or_else(|| anyhow!("no cached binary"))?;
+ let server_path = last_version_dir.join(SERVER_PATH);
+ if server_path.exists() {
+ Ok(LanguageServerBinary {
+ path: node.binary_path().await?,
+ arguments: server_binary_arguments(&server_path),
+ })
+ } else {
+ Err(anyhow!(
+ "missing executable in directory {:?}",
+ last_version_dir
+ ))
+ }
+ })
+ .await
+ .log_err()
+}
@@ -0,0 +1,3 @@
+("(" @open ")" @close)
+("[" @open "]" @close)
+("{" @open "}" @close)
@@ -0,0 +1,13 @@
+name = "PureScript"
+path_suffixes = ["purs"]
+autoclose_before = ",=)}]"
+line_comment = "-- "
+block_comment = ["{- ", " -}"]
+brackets = [
+ { start = "{", end = "}", close = true, newline = true },
+ { start = "[", end = "]", close = true, newline = true },
+ { start = "(", end = ")", close = true, newline = true },
+ { start = "\"", end = "\"", close = true, newline = false },
+ { start = "'", end = "'", close = true, newline = false },
+ { start = "`", end = "`", close = true, newline = false },
+]
@@ -0,0 +1,144 @@
+;; Copyright 2022 nvim-treesitter
+;;
+;; Licensed under the Apache License, Version 2.0 (the "License");
+;; you may not use this file except in compliance with the License.
+;; You may obtain a copy of the License at
+;;
+;; http://www.apache.org/licenses/LICENSE-2.0
+;;
+;; Unless required by applicable law or agreed to in writing, software
+;; distributed under the License is distributed on an "AS IS" BASIS,
+;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;; See the License for the specific language governing permissions and
+;; limitations under the License.
+
+;; ----------------------------------------------------------------------------
+;; Literals and comments
+
+(integer) @number
+(exp_negation) @number
+(exp_literal (number)) @float
+(char) @character
+[
+ (string)
+ (triple_quote_string)
+] @string
+
+(comment) @comment
+
+
+;; ----------------------------------------------------------------------------
+;; Punctuation
+
+[
+ "("
+ ")"
+ "{"
+ "}"
+ "["
+ "]"
+] @punctuation.bracket
+
+[
+ (comma)
+ ";"
+] @punctuation.delimiter
+
+
+;; ----------------------------------------------------------------------------
+;; Keywords, operators, includes
+
+[
+ "forall"
+ "โ"
+] @keyword
+
+;; (pragma) @constant
+
+[
+ "if"
+ "then"
+ "else"
+ "case"
+ "of"
+] @keyword
+
+[
+ "import"
+ "module"
+] @keyword
+
+[
+ (operator)
+ (constructor_operator)
+ (type_operator)
+ (qualified_module) ; grabs the `.` (dot), ex: import System.IO
+ (all_names)
+ (wildcard)
+ "="
+ "|"
+ "::"
+ "=>"
+ "->"
+ "<-"
+ "\\"
+ "`"
+ "@"
+ "โท"
+ "โ"
+ "<="
+ "โ"
+ "โ"
+ "โ"
+] @operator
+
+(module) @title
+
+[
+ (where)
+ "let"
+ "in"
+ "class"
+ "instance"
+ "derive"
+ "foreign"
+ "data"
+ "newtype"
+ "type"
+ "as"
+ "hiding"
+ "do"
+ "ado"
+ "infix"
+ "infixl"
+ "infixr"
+] @keyword
+
+
+;; ----------------------------------------------------------------------------
+;; Functions and variables
+
+(variable) @variable
+(pat_wildcard) @variable
+
+(signature name: (variable) @type)
+(function
+ name: (variable) @function
+ patterns: (patterns))
+
+
+(exp_infix (exp_name) @function (#set! "priority" 101))
+(exp_apply . (exp_name (variable) @function))
+(exp_apply . (exp_name (qualified_variable (variable) @function)))
+
+
+;; ----------------------------------------------------------------------------
+;; Types
+
+(type) @type
+(type_variable) @type
+
+(constructor) @constructor
+
+; True or False
+((constructor) @_bool (#match? @_bool "(True|False)")) @boolean
@@ -0,0 +1,3 @@
+(_ "[" "]" @end) @indent
+(_ "{" "}" @end) @indent
+(_ "(" ")" @end) @indent