From 4c51f27b0ae66ce2dab49a794cde7f6283e62e8c Mon Sep 17 00:00:00 2001 From: sammyne Date: Sun, 8 Jun 2025 06:44:30 +0000 Subject: [PATCH] feat(cli): support selecting bindings in init cmd --- crates/cli/src/init.rs | 4 ++- crates/cli/src/main.rs | 21 ++++++++++++-- crates/loader/src/loader.rs | 57 ++++++++++++++++++++++++++++++++++++- 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/crates/cli/src/init.rs b/crates/cli/src/init.rs index d99c046d..e05a2abb 100644 --- a/crates/cli/src/init.rs +++ b/crates/cli/src/init.rs @@ -139,6 +139,7 @@ pub struct JsonConfigOpts { pub email: Option, #[serde(skip_serializing_if = "Option::is_none")] pub url: Option, + pub bindings: Bindings, } impl JsonConfigOpts { @@ -185,7 +186,7 @@ impl JsonConfigOpts { }), namespace: None, }, - bindings: Bindings::default(), + bindings: self.bindings, } } } @@ -206,6 +207,7 @@ impl Default for JsonConfigOpts { author: String::new(), email: None, url: None, + bindings: Bindings::default(), } } } diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index eb5cf0aa..56bbb411 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -8,7 +8,7 @@ use anstyle::{AnsiColor, Color, Style}; use anyhow::{anyhow, Context, Result}; use clap::{crate_authors, Args, Command, FromArgMatches as _, Subcommand, ValueEnum}; use clap_complete::generate; -use dialoguer::{theme::ColorfulTheme, Confirm, FuzzySelect, Input}; +use dialoguer::{theme::ColorfulTheme, Confirm, FuzzySelect, Input, MultiSelect}; use heck::ToUpperCamelCase; use regex::Regex; use semver::Version as SemverVersion; @@ -30,7 +30,7 @@ use tree_sitter_cli::{ }; use tree_sitter_config::Config; use tree_sitter_highlight::Highlighter; -use tree_sitter_loader::{self as loader, TreeSitterJSON}; +use tree_sitter_loader::{self as loader, Bindings, TreeSitterJSON}; use tree_sitter_tags::TagsContext; use url::Url; @@ -682,6 +682,21 @@ impl Init { .map(|e| (!e.trim().is_empty()).then(|| Url::parse(&e).unwrap())) }; + let bindings = || { + let languages = Bindings::default().languages(); + + let enabled = MultiSelect::new() + .with_prompt("Bindings") + .items_checked(&languages) + .interact()? + .into_iter() + .map(|i| languages[i].0); + + let out = Bindings::with_enabled_languages(enabled) + .expect("unexpected unsupported language"); + anyhow::Ok(out) + }; + let choices = [ "name", "camelcase", @@ -696,6 +711,7 @@ impl Init { "author", "email", "url", + "bindings", "exit", ]; @@ -715,6 +731,7 @@ impl Init { "author" => opts.author = author()?, "email" => opts.email = email()?, "url" => opts.url = url()?, + "bindings" => opts.bindings = bindings()?, "exit" => break, _ => unreachable!(), } diff --git a/crates/loader/src/loader.rs b/crates/loader/src/loader.rs index 488a7a8e..9ff556fa 100644 --- a/crates/loader/src/loader.rs +++ b/crates/loader/src/loader.rs @@ -222,7 +222,7 @@ pub struct Links { pub homepage: Option, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone)] #[serde(default)] pub struct Bindings { pub c: bool, @@ -238,6 +238,61 @@ pub struct Bindings { pub zig: bool, } +impl Bindings { + /// return available languages and its default enabled state. + #[must_use] + pub const fn languages(&self) -> [(&'static str, bool); 7] { + [ + ("c", true), + ("go", true), + // Comment out Java and Kotlin until the bindings are actually available. + // ("java", false), + // ("kotlin", false), + ("node", true), + ("python", true), + ("rust", true), + ("swift", true), + ("zig", false), + ] + } + + /// construct Bindings from a language list. If a language isn't supported, its name will be put on the error part. + pub fn with_enabled_languages<'a, I>(languages: I) -> Result + where + I: Iterator, + { + let mut out = Self { + c: false, + go: false, + java: false, + kotlin: false, + node: false, + python: false, + rust: false, + swift: false, + zig: false, + }; + + for v in languages { + match v { + "c" => out.c = true, + "go" => out.go = true, + // Comment out Java and Kotlin until the bindings are actually available. + // "java" => out.java = true, + // "kotlin" => out.kotlin = true, + "node" => out.node = true, + "python" => out.python = true, + "rust" => out.rust = true, + "swift" => out.swift = true, + "zig" => out.zig = true, + unsupported => return Err(unsupported), + } + } + + Ok(out) + } +} + impl Default for Bindings { fn default() -> Self { Self {