diff --git a/cli/src/init.rs b/cli/src/init.rs index 73a355ce..8f1d0f2d 100644 --- a/cli/src/init.rs +++ b/cli/src/init.rs @@ -6,7 +6,7 @@ use std::{ use anyhow::{anyhow, Context, Result}; use heck::{ToKebabCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase}; -use indoc::indoc; +use indoc::{formatdoc, indoc}; use semver::Version; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; @@ -288,9 +288,16 @@ pub fn generate_grammar_files( })?; // Write .gitattributes file - missing_path(repo_path.join(".gitattributes"), |path| { - generate_file(path, GITATTRIBUTES_TEMPLATE, language_name, &generate_opts) - })?; + missing_path_else( + repo_path.join(".gitattributes"), + allow_update, + |path| generate_file(path, GITATTRIBUTES_TEMPLATE, language_name, &generate_opts), + |path| { + let contents = fs::read_to_string(path)?; + write_file(path, contents.replace("bindings/c/* ", "bindings/c/** "))?; + Ok(()) + }, + )?; // Write .editorconfig file missing_path(repo_path.join(".editorconfig"), |path| { @@ -376,10 +383,19 @@ pub fn generate_grammar_files( // Generate C bindings if tree_sitter_config.bindings.c { missing_path(bindings_dir.join("c"), create_dir)?.apply(|path| { - missing_path( - path.join(format!("tree-sitter-{language_name}.h")), - |path| generate_file(path, PARSER_NAME_H_TEMPLATE, language_name, &generate_opts), - )?; + let old_file = &path.join(format!("tree-sitter-{language_name}.h")); + if allow_update && fs::exists(old_file).unwrap_or(false) { + fs::remove_file(old_file)?; + } + missing_path(path.join("tree_sitter"), create_dir)?.apply(|include_path| { + missing_path( + include_path.join(format!("tree-sitter-{language_name}.h")), + |path| { + generate_file(path, PARSER_NAME_H_TEMPLATE, language_name, &generate_opts) + }, + )?; + Ok(()) + })?; missing_path( path.join(format!("tree-sitter-{language_name}.pc.in")), @@ -393,20 +409,50 @@ pub fn generate_grammar_files( }, )?; - missing_path(repo_path.join("Makefile"), |path| { - generate_file(path, MAKEFILE_TEMPLATE, language_name, &generate_opts) - })?; + missing_path_else( + repo_path.join("Makefile"), + allow_update, + |path| { + generate_file(path, MAKEFILE_TEMPLATE, language_name, &generate_opts) + }, + |path| { + let contents = fs::read_to_string(path)?.replace( + "-m644 bindings/c/$(LANGUAGE_NAME).h", + "-m644 bindings/c/tree_sitter/$(LANGUAGE_NAME).h" + ); + write_file(path, contents)?; + Ok(()) + }, + )?; missing_path_else( repo_path.join("CMakeLists.txt"), allow_update, |path| generate_file(path, CMAKELISTS_TXT_TEMPLATE, language_name, &generate_opts), |path| { - let contents = fs::read_to_string(path)?; - let old = "add_custom_target(test"; - if contents.contains(old) { - write_file(path, contents.replace(old, "add_custom_target(ts-test"))?; - } + let mut contents = fs::read_to_string(path)?; + contents = contents + .replace("add_custom_target(test", "add_custom_target(ts-test") + .replace( + &formatdoc! {r#" + install(FILES bindings/c/tree-sitter-{language_name}.h + DESTINATION "${{CMAKE_INSTALL_INCLUDEDIR}}/tree_sitter") + "#}, + indoc! {r#" + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bindings/c/tree_sitter" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + FILES_MATCHING PATTERN "*.h") + "#} + ).replace( + &format!("target_include_directories(tree-sitter-{language_name} PRIVATE src)"), + &formatdoc! {" + target_include_directories(tree-sitter-{language_name} + PRIVATE src + INTERFACE $ + $) + "} + ); + write_file(path, contents)?; Ok(()) }, )?; diff --git a/cli/src/templates/cmakelists.cmake b/cli/src/templates/cmakelists.cmake index 0d53ce5a..e8ba9a6c 100644 --- a/cli/src/templates/cmakelists.cmake +++ b/cli/src/templates/cmakelists.cmake @@ -28,7 +28,10 @@ add_library(tree-sitter-PARSER_NAME src/parser.c) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/scanner.c) target_sources(tree-sitter-PARSER_NAME PRIVATE src/scanner.c) endif() -target_include_directories(tree-sitter-PARSER_NAME PRIVATE src) +target_include_directories(tree-sitter-PARSER_NAME + PRIVATE src + INTERFACE $ + $) target_compile_definitions(tree-sitter-PARSER_NAME PRIVATE $<$:TREE_SITTER_REUSE_ALLOCATOR> @@ -46,8 +49,9 @@ configure_file(bindings/c/tree-sitter-PARSER_NAME.pc.in include(GNUInstallDirs) -install(FILES bindings/c/tree-sitter-PARSER_NAME.h - DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/tree_sitter") +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bindings/c/tree_sitter" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + FILES_MATCHING PATTERN "*.h") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-PARSER_NAME.pc" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig") install(TARGETS tree-sitter-PARSER_NAME diff --git a/cli/src/templates/gitattributes b/cli/src/templates/gitattributes index 7e2cae0c..4d7e4402 100644 --- a/cli/src/templates/gitattributes +++ b/cli/src/templates/gitattributes @@ -6,7 +6,7 @@ src/parser.c linguist-generated src/tree_sitter/* linguist-generated # C bindings -bindings/c/* linguist-generated +bindings/c/** linguist-generated CMakeLists.txt linguist-generated Makefile linguist-generated diff --git a/cli/src/templates/makefile b/cli/src/templates/makefile index 36f00d2b..ddb47821 100644 --- a/cli/src/templates/makefile +++ b/cli/src/templates/makefile @@ -71,7 +71,7 @@ $(PARSER): $(SRC_DIR)/grammar.json install: all install -d '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/PARSER_NAME '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter '$(DESTDIR)$(PCLIBDIR)' '$(DESTDIR)$(LIBDIR)' - install -m644 bindings/c/$(LANGUAGE_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h + install -m644 bindings/c/tree_sitter/$(LANGUAGE_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h install -m644 $(LANGUAGE_NAME).pc '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc install -m644 lib$(LANGUAGE_NAME).a '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a install -m755 lib$(LANGUAGE_NAME).$(SOEXT) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) diff --git a/docs/src/cli/init.md b/docs/src/cli/init.md index 44e6b380..2751b368 100644 --- a/docs/src/cli/init.md +++ b/docs/src/cli/init.md @@ -126,7 +126,7 @@ to be used from different language. Here is a list of these bindings files that - `Makefile` — This file tells [`make`][make] how to compile your language. - `CMakeLists.txt` — This file tells [`cmake`][cmake] how to compile your language. -- `bindings/c/tree-sitter-language.h` — This file provides the C interface of your language. +- `bindings/c/tree_sitter/tree-sitter-language.h` — This file provides the C interface of your language. - `bindings/c/tree-sitter-language.pc` — This file provides [pkg-config][pkg-config] metadata about your language's C library. - `src/tree_sitter/parser.h` — This file provides some basic C definitions that are used in your generated `parser.c` file. - `src/tree_sitter/alloc.h` — This file provides some memory allocation macros that are to be used in your external scanner,