diff --git a/CHANGELOG.md b/CHANGELOG.md
index 268deaa..767106a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
+## 0.2.0
+> Released N/A
+
+* Use queries instead (#5)
+
## 0.1.0
> Released Oct 18, 2021
diff --git a/Cask b/Cask
index 46c78ac..34a1acf 100644
--- a/Cask
+++ b/Cask
@@ -5,7 +5,6 @@
(files
"ts-fold.el"
- "ts-fold-parsers.el"
"ts-fold-summary.el"
"ts-fold-indicators.el"
"ts-fold-util.el")
diff --git a/queries/bash/folds.scm b/queries/bash/folds.scm
new file mode 100644
index 0000000..851c67e
--- /dev/null
+++ b/queries/bash/folds.scm
@@ -0,0 +1,8 @@
+[
+ (function_definition)
+ (if_statement)
+ (case_statement)
+ (for_statement)
+ (while_statement)
+ (c_style_for_statement)
+] @fold
diff --git a/queries/beancount/folds.scm b/queries/beancount/folds.scm
new file mode 100644
index 0000000..b65ae01
--- /dev/null
+++ b/queries/beancount/folds.scm
@@ -0,0 +1,4 @@
+[
+ (transaction)
+ (heading)
+] @fold
diff --git a/queries/bibtex/folds.scm b/queries/bibtex/folds.scm
new file mode 100644
index 0000000..3b24d5f
--- /dev/null
+++ b/queries/bibtex/folds.scm
@@ -0,0 +1,3 @@
+[
+ (entry)
+] @fold
diff --git a/queries/c-sharp/folds.scm b/queries/c-sharp/folds.scm
new file mode 100644
index 0000000..3d5a38c
--- /dev/null
+++ b/queries/c-sharp/folds.scm
@@ -0,0 +1,17 @@
+body: [
+ (declaration_list)
+ (switch_body)
+ (enum_member_declaration_list)
+] @fold
+
+accessors: [
+ (accessor_list)
+] @fold
+
+initializer: [
+ (initializer_expression)
+] @fold
+
+(block) @fold
+
+(comment) @comment
diff --git a/queries/c/folds.scm b/queries/c/folds.scm
new file mode 100644
index 0000000..80c3039
--- /dev/null
+++ b/queries/c/folds.scm
@@ -0,0 +1,19 @@
+[
+ (for_statement)
+ (if_statement)
+ (while_statement)
+ (switch_statement)
+ (case_statement)
+ (function_definition)
+ (struct_specifier)
+ (enum_specifier)
+ (comment)
+ (preproc_if)
+ (preproc_elif)
+ (preproc_else)
+ (preproc_ifdef)
+ (initializer_list)
+] @fold
+
+ (compound_statement
+ (compound_statement) @fold)
diff --git a/queries/clojure/folds.scm b/queries/clojure/folds.scm
new file mode 100644
index 0000000..d54daad
--- /dev/null
+++ b/queries/clojure/folds.scm
@@ -0,0 +1 @@
+(source (list_lit) @fold)
diff --git a/queries/cmake/folds.scm b/queries/cmake/folds.scm
new file mode 100644
index 0000000..ed5cc8d
--- /dev/null
+++ b/queries/cmake/folds.scm
@@ -0,0 +1,7 @@
+[
+ (if_condition)
+ (foreach_loop)
+ (while_loop)
+ (function_def)
+ (macro_def)
+] @fold
diff --git a/queries/commonlisp/folds.scm b/queries/commonlisp/folds.scm
new file mode 100644
index 0000000..d54daad
--- /dev/null
+++ b/queries/commonlisp/folds.scm
@@ -0,0 +1 @@
+(source (list_lit) @fold)
diff --git a/queries/cpp/folds.scm b/queries/cpp/folds.scm
new file mode 100644
index 0000000..23d623b
--- /dev/null
+++ b/queries/cpp/folds.scm
@@ -0,0 +1,14 @@
+; inherits: c
+
+[
+ (for_range_loop)
+ (class_specifier)
+ (field_declaration
+ type: (enum_specifier)
+ default_value: (initializer_list))
+ (template_declaration)
+ (namespace_definition)
+ (try_statement)
+ (catch_clause)
+ (lambda_expression)
+] @fold
diff --git a/queries/css/folds.scm b/queries/css/folds.scm
new file mode 100644
index 0000000..9d2995c
--- /dev/null
+++ b/queries/css/folds.scm
@@ -0,0 +1,3 @@
+[
+ (rule_set)
+] @fold
diff --git a/queries/cuda/folds.scm b/queries/cuda/folds.scm
new file mode 100644
index 0000000..b617fdc
--- /dev/null
+++ b/queries/cuda/folds.scm
@@ -0,0 +1 @@
+; inherits: cpp
diff --git a/queries/d/folds.scm b/queries/d/folds.scm
new file mode 100644
index 0000000..be4dee4
--- /dev/null
+++ b/queries/d/folds.scm
@@ -0,0 +1 @@
+(block_statement) @fold
diff --git a/queries/devicetree/folds.scm b/queries/devicetree/folds.scm
new file mode 100644
index 0000000..206c4be
--- /dev/null
+++ b/queries/devicetree/folds.scm
@@ -0,0 +1 @@
+(node) @fold
diff --git a/queries/ecma/folds.scm b/queries/ecma/folds.scm
new file mode 100644
index 0000000..960b247
--- /dev/null
+++ b/queries/ecma/folds.scm
@@ -0,0 +1,21 @@
+[
+ (for_in_statement)
+ (for_statement)
+ (while_statement)
+ (arrow_function)
+ (function)
+ (function_declaration)
+ (class_declaration)
+ (method_definition)
+ (do_statement)
+ (with_statement)
+ (switch_statement)
+ (switch_case)
+ (import_statement)
+ (if_statement)
+ (try_statement)
+ (catch_clause)
+ (object)
+ (generator_function)
+ (generator_function_declaration)
+] @fold
diff --git a/queries/elixir/folds.scm b/queries/elixir/folds.scm
new file mode 100644
index 0000000..b99a6d9
--- /dev/null
+++ b/queries/elixir/folds.scm
@@ -0,0 +1,9 @@
+[
+ (anonymous_function)
+ (arguments)
+ (block)
+ (do_block)
+ (list)
+ (map)
+ (tuple)
+] @fold
diff --git a/queries/fish/folds.scm b/queries/fish/folds.scm
new file mode 100644
index 0000000..6075e2e
--- /dev/null
+++ b/queries/fish/folds.scm
@@ -0,0 +1,8 @@
+[
+ (function_definition)
+ (if_statement)
+ (switch_statement)
+ (for_statement)
+ (while_statement)
+ (begin_statement)
+] @fold
diff --git a/queries/foam/folds.scm b/queries/foam/folds.scm
new file mode 100644
index 0000000..2e499c2
--- /dev/null
+++ b/queries/foam/folds.scm
@@ -0,0 +1,7 @@
+[
+ (comment)
+ (list)
+ (dict_core)
+] @fold
+
+(code (code_body)* @fold)
diff --git a/queries/fortran/folds.scm b/queries/fortran/folds.scm
new file mode 100644
index 0000000..a2edc64
--- /dev/null
+++ b/queries/fortran/folds.scm
@@ -0,0 +1,11 @@
+;; by @oponkork
+[
+ (if_statement)
+ (where_statement)
+ (enum_statement)
+ (do_loop_statement)
+ (derived_type_definition)
+ (function)
+ (subroutine)
+ (interface)
+] @fold
diff --git a/queries/fusion/folds.scm b/queries/fusion/folds.scm
new file mode 100644
index 0000000..179fc16
--- /dev/null
+++ b/queries/fusion/folds.scm
@@ -0,0 +1,6 @@
+[
+ (comment)
+ (block)
+ (afx_comment)
+ (afx_element)
+] @fold
diff --git a/queries/gleam/folds.scm b/queries/gleam/folds.scm
new file mode 100644
index 0000000..ff05eeb
--- /dev/null
+++ b/queries/gleam/folds.scm
@@ -0,0 +1,11 @@
+; Folds
+[
+ (case)
+ (expression_group)
+ (function)
+ (public_function)
+ (anonymous_function)
+ (type_definition)
+ (public_type_definition)
+ (public_opaque_type_definition)
+] @fold
diff --git a/queries/glsl/folds.scm b/queries/glsl/folds.scm
new file mode 100644
index 0000000..a5a5208
--- /dev/null
+++ b/queries/glsl/folds.scm
@@ -0,0 +1 @@
+; inherits: c
diff --git a/queries/go/folds.scm b/queries/go/folds.scm
new file mode 100644
index 0000000..c79d457
--- /dev/null
+++ b/queries/go/folds.scm
@@ -0,0 +1,13 @@
+[
+ (const_declaration)
+ (expression_switch_statement)
+ (for_statement)
+ (func_literal)
+ (function_declaration)
+ (if_statement)
+ (import_declaration)
+ (method_declaration)
+ (type_declaration)
+ (var_declaration)
+] @fold
+
diff --git a/queries/godot_resource/folds.scm b/queries/godot_resource/folds.scm
new file mode 100644
index 0000000..943e062
--- /dev/null
+++ b/queries/godot_resource/folds.scm
@@ -0,0 +1,3 @@
+[
+ (section)
+] @fold
diff --git a/queries/hcl/folds.scm b/queries/hcl/folds.scm
new file mode 100644
index 0000000..cb20b2a
--- /dev/null
+++ b/queries/hcl/folds.scm
@@ -0,0 +1,6 @@
+[
+ (comment)
+ (block)
+ (heredoc_template)
+ (object)
+] @fold
diff --git a/queries/heex/folds.scm b/queries/heex/folds.scm
new file mode 100644
index 0000000..88d4f17
--- /dev/null
+++ b/queries/heex/folds.scm
@@ -0,0 +1,6 @@
+; HEEx tags, components, and slots fold similar to HTML
+[
+ (component)
+ (tag)
+ (slot)
+] @fold
diff --git a/queries/hjson/folds.scm b/queries/hjson/folds.scm
new file mode 100644
index 0000000..4126921
--- /dev/null
+++ b/queries/hjson/folds.scm
@@ -0,0 +1 @@
+; inherits: json
diff --git a/queries/html/folds.scm b/queries/html/folds.scm
new file mode 100644
index 0000000..69b57ea
--- /dev/null
+++ b/queries/html/folds.scm
@@ -0,0 +1,5 @@
+[
+ (element)
+ (style_element)
+ (script_element)
+] @fold
diff --git a/queries/javascript/folds.scm b/queries/javascript/folds.scm
new file mode 100644
index 0000000..b6d9b28
--- /dev/null
+++ b/queries/javascript/folds.scm
@@ -0,0 +1 @@
+; inherits: ecma,jsx
diff --git a/queries/json/folds.scm b/queries/json/folds.scm
new file mode 100644
index 0000000..4c2b9d3
--- /dev/null
+++ b/queries/json/folds.scm
@@ -0,0 +1,5 @@
+[
+ (pair)
+ (object)
+ (array)
+] @fold
diff --git a/queries/jsonc/folds.scm b/queries/jsonc/folds.scm
new file mode 100644
index 0000000..4126921
--- /dev/null
+++ b/queries/jsonc/folds.scm
@@ -0,0 +1 @@
+; inherits: json
diff --git a/queries/jsx/folds.scm b/queries/jsx/folds.scm
new file mode 100644
index 0000000..93c3d9c
--- /dev/null
+++ b/queries/jsx/folds.scm
@@ -0,0 +1 @@
+(jsx_element) @fold
diff --git a/queries/julia/folds.scm b/queries/julia/folds.scm
new file mode 100644
index 0000000..a8cfc94
--- /dev/null
+++ b/queries/julia/folds.scm
@@ -0,0 +1,17 @@
+[
+ (module_definition)
+ (struct_definition)
+ (macro_definition)
+ (function_definition)
+
+ (if_statement)
+ (try_statement)
+ (for_statement)
+ (while_statement)
+ (let_statement)
+ (quote_statement)
+
+ (do_clause)
+ (compound_expression)
+] @fold
+
diff --git a/queries/kotlin/folds.scm b/queries/kotlin/folds.scm
new file mode 100644
index 0000000..768972b
--- /dev/null
+++ b/queries/kotlin/folds.scm
@@ -0,0 +1,17 @@
+[
+ (import_list)
+
+ (when_expression)
+ (control_structure_body)
+
+ (lambda_literal)
+ (function_body)
+ (primary_constructor)
+ (secondary_constructor)
+ (anonymous_initializer)
+
+ (class_body)
+ (enum_class_body)
+
+ (interpolated_expression)
+] @fold
diff --git a/queries/latex/folds.scm b/queries/latex/folds.scm
new file mode 100644
index 0000000..6769b2e
--- /dev/null
+++ b/queries/latex/folds.scm
@@ -0,0 +1,13 @@
+[
+ (chapter)
+ (part)
+ (section)
+ (subsection)
+ (subsubsection)
+ (paragraph)
+ (subparagraph)
+
+ (generic_environment)
+ (comment_environment)
+ (displayed_equation)
+] @fold
diff --git a/queries/ledger/folds.scm b/queries/ledger/folds.scm
new file mode 100644
index 0000000..d807fc3
--- /dev/null
+++ b/queries/ledger/folds.scm
@@ -0,0 +1,3 @@
+[
+ (xact)
+] @fold
diff --git a/queries/lua/folds.scm b/queries/lua/folds.scm
new file mode 100644
index 0000000..d8f0b42
--- /dev/null
+++ b/queries/lua/folds.scm
@@ -0,0 +1,10 @@
+[
+ (do_statement)
+ (while_statement)
+ (repeat_statement)
+ (if_statement)
+ (for_statement)
+ (function_declaration)
+ (function_definition)
+ (table_constructor)
+] @fold
diff --git a/queries/markdown/folds.scm b/queries/markdown/folds.scm
new file mode 100644
index 0000000..f6c34f7
--- /dev/null
+++ b/queries/markdown/folds.scm
@@ -0,0 +1,5 @@
+[
+ (fenced_code_block)
+ (indented_code_block)
+ (list)
+] @fold
diff --git a/queries/ninja/folds.scm b/queries/ninja/folds.scm
new file mode 100644
index 0000000..341a8b8
--- /dev/null
+++ b/queries/ninja/folds.scm
@@ -0,0 +1 @@
+(body) @fold
diff --git a/queries/nix/folds.scm b/queries/nix/folds.scm
new file mode 100644
index 0000000..72050aa
--- /dev/null
+++ b/queries/nix/folds.scm
@@ -0,0 +1,11 @@
+; Nix doesn't really have blocks, so just guess what people might want folds for
+[
+ (if)
+ (with)
+ (let)
+ (function)
+ (attrset)
+ (rec_attrset)
+ (list)
+ (indented_string)
+] @fold
diff --git a/queries/ocaml/folds.scm b/queries/ocaml/folds.scm
new file mode 100644
index 0000000..1d45dbb
--- /dev/null
+++ b/queries/ocaml/folds.scm
@@ -0,0 +1,30 @@
+[
+ (let_binding)
+ (external)
+ (type_binding)
+ (exception_definition)
+ (module_binding)
+ (module_type_definition)
+ (open_module)
+ (include_module)
+ (include_module_type)
+ (class_binding)
+ (class_type_binding)
+ (value_specification)
+ (inheritance_specification)
+ (instance_variable_specification)
+ (method_specification)
+ (inheritance_definition)
+ (instance_variable_definition)
+ (method_definition)
+ (class_initializer)
+ (match_case)
+ (attribute)
+ (item_attribute)
+ (floating_attribute)
+ (extension)
+ (item_extension)
+ (quoted_extension)
+ (quoted_item_extension)
+ (comment)
+] @fold
diff --git a/queries/ocaml_interface/folds.scm b/queries/ocaml_interface/folds.scm
new file mode 100644
index 0000000..6d3dfbc
--- /dev/null
+++ b/queries/ocaml_interface/folds.scm
@@ -0,0 +1 @@
+; inherits: ocaml
diff --git a/queries/pascal/folds.scm b/queries/pascal/folds.scm
new file mode 100644
index 0000000..6db2857
--- /dev/null
+++ b/queries/pascal/folds.scm
@@ -0,0 +1,33 @@
+[
+ (interface)
+ (implementation)
+ (initialization)
+ (finalization)
+
+ (if)
+ (ifElse)
+ (while)
+ (repeat)
+ (for)
+ (foreach)
+ (try)
+ (case)
+ (caseCase)
+ (asm)
+ (with)
+
+ (declVar)
+ (declConst)
+ (declEnum)
+ (declProcRef)
+ (declExports)
+ (declProcRef)
+ (declType)
+ (defProc)
+ (declField)
+ (declProp)
+
+ (comment)
+] @fold
+
+(interface (declProc) @fold)
diff --git a/queries/perl/folds.scm b/queries/perl/folds.scm
new file mode 100644
index 0000000..994d569
--- /dev/null
+++ b/queries/perl/folds.scm
@@ -0,0 +1,12 @@
+[
+ (function_definition)
+ (if_statement)
+ (unless_statement)
+ (while_statement)
+ (until_statement)
+ (for_statement_1)
+ (for_statement_2)
+ (foreach_statement)
+ (standalone_block)
+ (pod_statement)
+] @fold
diff --git a/queries/php/folds.scm b/queries/php/folds.scm
new file mode 100644
index 0000000..3d44782
--- /dev/null
+++ b/queries/php/folds.scm
@@ -0,0 +1,6 @@
+[
+ (class_declaration)
+ (compound_statement)
+ (switch_statement)
+ (case_statement)
+] @fold
diff --git a/queries/query/folds.scm b/queries/query/folds.scm
new file mode 100644
index 0000000..47dd965
--- /dev/null
+++ b/queries/query/folds.scm
@@ -0,0 +1,6 @@
+[
+ (named_node)
+ (predicate)
+ (grouping)
+ (list)
+] @fold
diff --git a/queries/rasi/folds.scm b/queries/rasi/folds.scm
new file mode 100644
index 0000000..1557b83
--- /dev/null
+++ b/queries/rasi/folds.scm
@@ -0,0 +1,5 @@
+[
+ (rule_set)
+ (list_value)
+ (distance_calc)
+ ] @fold
diff --git a/queries/ruby/folds.scm b/queries/ruby/folds.scm
new file mode 100644
index 0000000..3a497b3
--- /dev/null
+++ b/queries/ruby/folds.scm
@@ -0,0 +1,12 @@
+[
+ (method)
+ (singleton_method)
+ (class)
+ (module)
+ (if)
+ (else)
+ (case)
+ (do_block)
+ (singleton_class)
+ (lambda)
+] @fold
diff --git a/queries/rust/folds.scm b/queries/rust/folds.scm
new file mode 100644
index 0000000..d83351c
--- /dev/null
+++ b/queries/rust/folds.scm
@@ -0,0 +1,25 @@
+[(mod_item)
+ (function_item)
+ (struct_item)
+ (trait_item)
+ (enum_item)
+ (impl_item)
+ (type_item)
+ (union_item)
+
+ (use_declaration)
+ (let_declaration)
+
+ (loop_expression)
+ (for_expression)
+ (while_expression)
+ (if_expression)
+ (if_let_expression)
+ (match_expression)
+ (call_expression)
+
+ (macro_definition)
+ (macro_invocation)
+
+ (attribute_item)
+] @fold
diff --git a/queries/scala/folds.scm b/queries/scala/folds.scm
new file mode 100644
index 0000000..e748e86
--- /dev/null
+++ b/queries/scala/folds.scm
@@ -0,0 +1,15 @@
+(call_expression (block) @fold)
+
+[(class_definition)
+ (trait_definition)
+ (object_definition)
+ (function_definition)
+ (val_definition)
+ (import_declaration)
+
+ (while_expression)
+ (do_while_expression)
+ (for_expression)
+ (try_expression)
+ (match_expression)
+] @fold
diff --git a/queries/sparql/folds.scm b/queries/sparql/folds.scm
new file mode 100644
index 0000000..2b93a7b
--- /dev/null
+++ b/queries/sparql/folds.scm
@@ -0,0 +1,26 @@
+[
+ (prologue)
+ (select_query)
+ (construct_query)
+ (describe_query)
+ (ask_query)
+ (values_clause)
+ (load)
+ (clear)
+ (drop)
+ (add)
+ (move)
+ (copy)
+ (create)
+ (insert_data)
+ (delete_data)
+ (delete_where)
+ (modify)
+ (group_graph_pattern)
+ (triples_same_subject)
+ (where_clause)
+ (delete_clause)
+ (insert_clause)
+ (data_block)
+ (blank_node_property_list)
+] @fold
diff --git a/queries/supercollider/folds.scm b/queries/supercollider/folds.scm
new file mode 100644
index 0000000..214247b
--- /dev/null
+++ b/queries/supercollider/folds.scm
@@ -0,0 +1,7 @@
+[
+(function_call)
+(code_block)
+(function_block)
+(control_structure)
+] @fold
+
diff --git a/queries/surface/folds.scm b/queries/surface/folds.scm
new file mode 100644
index 0000000..994f12e
--- /dev/null
+++ b/queries/surface/folds.scm
@@ -0,0 +1,6 @@
+; Surface folds similar to HTML and includes blocks
+[
+ (tag)
+ (component)
+ (block)
+] @fold
diff --git a/queries/svelte/folds.scm b/queries/svelte/folds.scm
new file mode 100644
index 0000000..795c32f
--- /dev/null
+++ b/queries/svelte/folds.scm
@@ -0,0 +1,9 @@
+[
+ (style_element)
+ (script_element)
+ (element)
+ (if_statement)
+ (else_statement)
+ (each_statement)
+ (await_statement)
+] @fold
diff --git a/queries/teal/folds.scm b/queries/teal/folds.scm
new file mode 100644
index 0000000..4583057
--- /dev/null
+++ b/queries/teal/folds.scm
@@ -0,0 +1,13 @@
+[
+(do_statement)
+(numeric_for_statement)
+(generic_for_statement)
+(while_statement)
+(repeat_statement)
+(if_statement)
+(function_statement)
+(record_declaration)
+(enum_declaration)
+(anon_function)
+(table_constructor)
+] @fold
diff --git a/queries/tlaplus/folds.scm b/queries/tlaplus/folds.scm
new file mode 100644
index 0000000..2ca0168
--- /dev/null
+++ b/queries/tlaplus/folds.scm
@@ -0,0 +1,5 @@
+[
+ (extramodular_text)
+ (block_comment)
+ (non_terminal_proof)
+] @fold
diff --git a/queries/toml/folds.scm b/queries/toml/folds.scm
new file mode 100644
index 0000000..a58aae4
--- /dev/null
+++ b/queries/toml/folds.scm
@@ -0,0 +1,5 @@
+[
+ (table)
+ (array)
+ (table_array_element)
+] @fold
diff --git a/queries/tsx/folds.scm b/queries/tsx/folds.scm
new file mode 100644
index 0000000..0739123
--- /dev/null
+++ b/queries/tsx/folds.scm
@@ -0,0 +1 @@
+; inherits: typescript,jsx
diff --git a/queries/turtle/folds.scm b/queries/turtle/folds.scm
new file mode 100644
index 0000000..863e442
--- /dev/null
+++ b/queries/turtle/folds.scm
@@ -0,0 +1,4 @@
+[
+ (statement)
+ (blank_node_property_list)
+] @fold
diff --git a/queries/typescript/folds.scm b/queries/typescript/folds.scm
new file mode 100644
index 0000000..dced30d
--- /dev/null
+++ b/queries/typescript/folds.scm
@@ -0,0 +1,7 @@
+; inherits: ecma
+
+[
+ (interface_declaration)
+ (internal_module)
+ (type_alias_declaration)
+] @fold
diff --git a/queries/verilog/folds.scm b/queries/verilog/folds.scm
new file mode 100644
index 0000000..efc0ac6
--- /dev/null
+++ b/queries/verilog/folds.scm
@@ -0,0 +1,6 @@
+[
+ (seq_block)
+ (function_body_declaration)
+ (task_body_declaration)
+ (generate_block)
+] @fold
diff --git a/queries/vue/folds.scm b/queries/vue/folds.scm
new file mode 100644
index 0000000..314256e
--- /dev/null
+++ b/queries/vue/folds.scm
@@ -0,0 +1,6 @@
+[
+ (element)
+ (template_element)
+ (script_element)
+ (style_element)
+] @fold
diff --git a/queries/yaml/folds.scm b/queries/yaml/folds.scm
new file mode 100644
index 0000000..f82378e
--- /dev/null
+++ b/queries/yaml/folds.scm
@@ -0,0 +1,3 @@
+[
+ (block_node)
+] @fold
diff --git a/queries/yang/folds.scm b/queries/yang/folds.scm
new file mode 100644
index 0000000..adf0eb1
--- /dev/null
+++ b/queries/yang/folds.scm
@@ -0,0 +1,3 @@
+[
+ (block)
+] @fold
diff --git a/queries/zig/folds.scm b/queries/zig/folds.scm
new file mode 100644
index 0000000..9659874
--- /dev/null
+++ b/queries/zig/folds.scm
@@ -0,0 +1,16 @@
+[
+ (Block)
+ (ContainerDecl)
+ (SwitchExpr)
+ (InitList)
+ (AsmExpr)
+ (ErrorSetDecl)
+ (LINESTRING)
+ (
+ [
+ (IfPrefix)
+ (WhilePrefix)
+ (ForPrefix)
+ ]
+ )
+] @fold
diff --git a/ts-fold-indicators.el b/ts-fold-indicators.el
index f286331..dfd5f48 100644
--- a/ts-fold-indicators.el
+++ b/ts-fold-indicators.el
@@ -1,6 +1,6 @@
;;; ts-fold-indicators.el --- Display indicators for folding range -*- lexical-binding: t; -*-
-;; Copyright (C) 2021 Shen, Jen-Chieh
+;; Copyright (C) 2021-2022 Shen, Jen-Chieh
;; Created date 2021-10-04 20:03:12
;; This file is NOT part of GNU Emacs.
@@ -93,6 +93,10 @@
"........" "........" "........" "........" "........"
"........" "........" "........" "........" "........")
+(defun ts-fold--after-command (&rest _)
+ "Function call after interactive commands."
+ (ts-fold-indicators-refresh))
+
;;
;; (@* "Entry" )
;;
@@ -108,12 +112,16 @@
"Enable `ts-fold-indicators' mode."
(if (ts-fold-mode 1) ; Enable `ts-fold-mode' automatically
(progn
+ (dolist (cmd ts-fold-interactive-commands)
+ (advice-add cmd :after #'ts-fold--after-command))
(add-hook 'tree-sitter-after-change-functions #'ts-fold-indicators-refresh nil t)
(add-hook 'after-save-hook #'ts-fold-indicators-refresh nil t))
(ts-fold-indicators-mode -1)))
(defun ts-fold-indicators--disable ()
"Disable `ts-fold-indicators' mode."
+ (dolist (cmd ts-fold-interactive-commands)
+ (advice-remove cmd #'ts-fold--after-command))
(remove-hook 'tree-sitter-after-change-functions #'ts-fold-indicators-refresh t)
(remove-hook 'after-save-hook #'ts-fold-indicators-refresh t)
(ts-fold-indicators--remove-overlays))
@@ -222,8 +230,8 @@ head (first line) of the region."
(defun ts-fold-indicators--get-end-fringe ()
"Return end fringe bitmap according to variable `ts-fold-indicators-fringe'."
(cl-case ts-fold-indicators-fringe
- (left-fringe 'ts-fold-indicators-fr-end-left)
- (right-fringe 'ts-fold-indicators-fr-end-right)
+ (`left-fringe 'ts-fold-indicators-fr-end-left)
+ (`right-fringe 'ts-fold-indicators-fr-end-right)
(t (user-error "Invalid indicators fringe type: %s" ts-fold-indicators-fringe))))
(defun ts-fold-indicators--update-overlays (ov-lst folded)
@@ -255,25 +263,17 @@ head (first line) of the region."
"Create indicators using NODE."
(when-let* ((range (ts-fold--get-fold-range node))
(beg (car range)) (end (cdr range)))
- (let ((folded (ts-fold-overlay-at node)))
- (ts-fold-indicators--create-overlays beg end folded))))
+ (ts-fold-indicators--create-overlays beg end (ts-fold-overlay-at range))))
;;;###autoload
(defun ts-fold-indicators-refresh (&rest _)
"Refresh indicators for all folding range."
(when ts-fold-indicators-mode
(ts-fold--ensure-ts
- (when-let* ((node (tsc-root-node tree-sitter-tree))
- (patterns (seq-mapcat (lambda (type) `(,(list type) @name))
- (alist-get major-mode ts-fold-foldable-node-alist)
- 'vector))
- (query (ignore-errors
- (tsc-make-query tree-sitter-language patterns)))
- (nodes-to-fold (tsc-query-captures query node #'ignore)))
+ (when-let ((nodes-to-fold (ts-fold--get-nodes '(fold comment) nil)))
(ts-fold-indicators--remove-overlays)
(thread-last nodes-to-fold
- (mapcar #'cdr)
- (mapc #'ts-fold-indicators--create))))))
+ (mapc #'ts-fold-indicators--create))))))
(defun ts-fold-indicators--remove-overlays ()
"Remove all indicators overlays."
diff --git a/ts-fold-parsers.el b/ts-fold-parsers.el
deleted file mode 100644
index bd3c0e7..0000000
--- a/ts-fold-parsers.el
+++ /dev/null
@@ -1,218 +0,0 @@
-;;; ts-fold-parsers.el --- Adapter layer to Tree-Sitter -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2021 Shen, Jen-Chieh
-;; Created date 2021-10-04 17:45:48
-
-;; This file is NOT part of GNU Emacs.
-
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program. If not, see .
-
-;;; Commentary:
-;;
-;; Adapter layer to Tree-Sitter
-;;
-;; This isn't a real parser implementation, but records down the rule
-;; in order to let the Tree-Sitter to parse things correctly. Think of
-;; the rule sets!
-;;
-
-;;; Code:
-
-;;
-;; (@* "Externals" )
-;;
-
-(declare-function ts-fold-range-seq "ts-fold.el")
-(declare-function ts-fold-range-line-comment "ts-fold.el")
-(declare-function ts-fold-range-block-comment "ts-fold.el")
-(declare-function ts-fold-range-c-like-comment "ts-fold.el")
-
-(declare-function ts-fold-range-c-preproc-ifdef "ts-fold.el")
-(declare-function ts-fold-range-c-preproc-if "ts-fold.el")
-(declare-function ts-fold-range-c-preproc-elif "ts-fold.el")
-(declare-function ts-fold-range-c-preproc-else "ts-fold.el")
-(declare-function ts-fold-range-html "ts-fold.el")
-(declare-function ts-fold-range-python "ts-fold.el")
-(declare-function ts-fold-range-ruby "ts-fold.el")
-(declare-function ts-fold-range-rust-macro "ts-fold.el")
-
-;;
-;; (@* "Parsers" )
-;;
-
-(defun ts-fold-parsers-agda ()
- "Rule sets for Agda."
- '(()))
-
-(defun ts-fold-parsers-bash ()
- "Rule sets for Bash."
- '((compound_statement . ts-fold-range-seq)
- (expansion . ts-fold-range-seq)
- (comment
- . (lambda (node offset)
- (ts-fold-range-line-comment node offset "#")))))
-
-(defun ts-fold-parsers-c ()
- "Rule sets for C."
- '((compound_statement . ts-fold-range-seq)
- (declaration_list . ts-fold-range-seq)
- (enumerator_list . ts-fold-range-seq)
- (field_declaration_list . ts-fold-range-seq)
- (preproc_if . ts-fold-range-c-preproc-if)
- (preproc_ifdef . ts-fold-range-c-preproc-ifdef)
- (preproc_elif . ts-fold-range-c-preproc-elif)
- (preproc_else . ts-fold-range-c-preproc-else)
- (comment . ts-fold-range-c-like-comment)))
-
-(defun ts-fold-parsers-c++ ()
- "Rule sets for C++."
- (append (ts-fold-parsers-c)))
-
-(defun ts-fold-parsers-csharp ()
- "Rule sets for C#."
- '((block . ts-fold-range-seq)
- (accessor_list . ts-fold-range-seq)
- (enum_member_declaration_list . ts-fold-range-seq)
- (declaration_list . ts-fold-range-seq)
- (switch_body . ts-fold-range-seq)
- (anonymous_object_creation_expression . ts-fold-range-seq)
- (initializer_expression . ts-fold-range-seq)
- ;;(if_directive . ts-fold-range-seq)
- ;;(else_directive . ts-fold-range-seq)
- ;;(elif_directive . ts-fold-range-seq)
- ;;(endif_directive . ts-fold-range-seq)
- ;;(region_directive . ts-fold-range-seq)
- ;;(endregion_directive . ts-fold-range-seq)
- (comment . ts-fold-range-c-like-comment)))
-
-(defun ts-fold-parsers-css ()
- "Rule sets for CSS."
- '((keyframe_block_list . ts-fold-range-seq)
- (block . ts-fold-range-seq)
- (comment . ts-fold-range-c-like-comment)))
-
-(defun ts-fold-parsers-go ()
- "Rule sets for Go."
- '((block . ts-fold-range-seq)
- (comment . ts-fold-range-seq)))
-
-(defun ts-fold-parsers-html ()
- "Rule sets for HTML."
- '((element . ts-fold-range-html)
- (comment . (ts-fold-range-seq 1 -1))))
-
-(defun ts-fold-parsers-java ()
- "Rule sets for Java."
- '((switch_block . ts-fold-range-seq)
- (block . ts-fold-range-seq)
- (element_value_array_initializer . ts-fold-range-seq)
- (module_body . ts-fold-range-seq)
- (enum_body . ts-fold-range-seq)
- (class_body . ts-fold-range-seq)
- (constructor_body . ts-fold-range-seq)
- (annotation_type_body . ts-fold-range-seq)
- (interface_body . ts-fold-range-seq)
- (array_initializer . ts-fold-range-seq)
- (comment . (ts-fold-range-seq 1 -1))))
-
-(defun ts-fold-parsers-javascript ()
- "Rule sets for JavaScript."
- '((export_clause . ts-fold-range-seq)
- (statement_block . ts-fold-range-seq)
- (comment . ts-fold-range-c-like-comment)))
-
-(defun ts-fold-parsers-json ()
- "Rule sets for JSON."
- '((object . ts-fold-range-seq)
- (array . ts-fold-range-seq)))
-
-(defun ts-fold-parsers-nix ()
- "Rule sets for Nix."
- '((attrset . ts-fold-range-seq)
- (interpolation . ts-fold-range-seq)
- (list . ts-fold-range-seq)))
-
-(defun ts-fold-parsers-php ()
- "Rule sets for PHP."
- '((namespace_use_group . ts-fold-range-seq)
- (declaration_list . ts-fold-range-seq)
- (use_list . ts-fold-range-seq)
- (switch_block . ts-fold-range-seq)
- (compound_statement . ts-fold-range-seq)
- (comment
- . (lambda (node offset)
- (if (string-prefix-p "#" (tsc-node-text node))
- (ts-fold-range-line-comment node offset "#")
- (ts-fold-range-c-like-comment node offset))))))
-
-(defun ts-fold-parsers-python ()
- "Rule sets for Python."
- '((function_definition . ts-fold-range-python)
- (class_definition . ts-fold-range-python)
- (list . ts-fold-range-seq)
- (comment
- . (lambda (node offset)
- (ts-fold-range-line-comment node offset "#")))))
-
-(defun ts-fold-parsers-r ()
- "Rule sets for R."
- '((brace_list . ts-fold-range-seq)))
-
-(defun ts-fold-parsers-ruby ()
- "Rule sets for Ruby."
- '((class . ts-fold-range-ruby)
- (method . ts-fold-range-ruby)
- (array . ts-fold-range-seq)
- (comment
- . (lambda (node offset)
- (ts-fold-range-line-comment node offset "#")))))
-
-(defun ts-fold-parsers-rust ()
- "Rule sets for Rust."
- '((declaration_list . ts-fold-range-seq)
- (enum_variant_list . ts-fold-range-seq)
- (field_declaration_list . ts-fold-range-seq)
- (use_list . ts-fold-range-seq)
- (field_initializer_list . ts-fold-range-seq)
- (match_block . ts-fold-range-seq)
- (macro_definition . (ts-fold-range-rust-macro 1 -1))
- (block . ts-fold-range-seq)
- (line_comment . (lambda (node offset)
- (ts-fold-range-line-comment node offset "///")))
- (block_comment . ts-fold-range-block-comment)))
-
-(defun ts-fold-parsers-scala ()
- "Rule sets for Scala."
- '((import_selectors . ts-fold-range-seq)
- (template_body . ts-fold-range-seq)
- (block . ts-fold-range-seq)
- (comment . ts-fold-range-c-like-comment)))
-
-(defun ts-fold-parsers-swift ()
- "Rule sets for Swift."
- '((switch_statement . ts-fold-range-seq)
- (function_declaration . ts-fold-range-seq)
- (enum_declaration . ts-fold-range-seq)
- (struct_declaration . ts-fold-range-seq)
- (class_declaration . ts-fold-range-seq)
- (protocol_declaration . ts-fold-range-seq)
- (extension_declaration . ts-fold-range-seq)
- (comment . ts-fold-range-c-like-comment)))
-
-(defun ts-fold-parsers-typescript ()
- "Rule sets for TypeScript."
- (append (ts-fold-parsers-javascript)))
-
-(provide 'ts-fold-parsers)
-;;; ts-fold-parsers.el ends here
diff --git a/ts-fold-summary.el b/ts-fold-summary.el
index d1ce6b4..4062676 100644
--- a/ts-fold-summary.el
+++ b/ts-fold-summary.el
@@ -1,6 +1,6 @@
;;; ts-fold-summary.el --- Extract summary from fold region -*- lexical-binding: t; -*-
-;; Copyright (C) 2021 Shen, Jen-Chieh
+;; Copyright (C) 2021-2022 Shen, Jen-Chieh
;; Created date 2021-10-04 16:59:22
;; This file is NOT part of GNU Emacs.
@@ -87,9 +87,10 @@ type of content by checking the word boundary's existence."
(defun ts-fold-summary--doc-extract (doc-str sym)
"Default way to extract the doc summary from DOC-STR."
- (let* ((lines (ts-fold-summary--extract-summary doc-str sym)) (summary (nth 0 lines)))
- (when summary (setq summary (string-trim summary)))
- (if (string-empty-p summary) nil summary)))
+ (when-let* ((lines (ts-fold-summary--extract-summary doc-str sym))
+ (summary (nth 0 lines))
+ (summary (string-trim summary)))
+ (unless (string-empty-p summary) summary)))
(defun ts-fold-summary--generic (doc-str sym)
"Generic DOC-STR extraction using SYM."
@@ -183,15 +184,14 @@ type of content by checking the word boundary's existence."
(defun ts-fold-summary--get (doc-str)
"Extract summary from DOC-STR in order to display ontop of the overlay."
- (let ((parser (cdr (ts-fold-summary--parser))) summary)
- (when parser
- (setq summary (funcall parser doc-str))
+ (when-let ((parser (cdr (ts-fold-summary--parser))))
+ (let ((summary (funcall parser doc-str)))
(when (integerp ts-fold-summary-max-length)
(setq summary (ts-fold-summary--keep-length summary)))
(when summary
(setq summary (ts-fold-summary--apply-format summary)
- summary (propertize summary 'face 'ts-fold-replacement-face))))
- summary))
+ summary (propertize summary 'face 'ts-fold-replacement-face)))
+ summary)))
(defcustom ts-fold-summary-parsers-alist
`((actionscript-mode . ts-fold-summary-javadoc)
diff --git a/ts-fold-util.el b/ts-fold-util.el
index e3aa14e..dd8e705 100644
--- a/ts-fold-util.el
+++ b/ts-fold-util.el
@@ -1,6 +1,6 @@
;;; ts-fold-util.el --- Utility module -*- lexical-binding: t; -*-
-;; Copyright (C) 2021 Shen, Jen-Chieh
+;; Copyright (C) 2021-2022 Shen, Jen-Chieh
;; Created date 2021-10-04 20:19:42
;; This file is NOT part of GNU Emacs.
@@ -82,6 +82,11 @@ Optional argument TRIM, see function `ts-fold--get-face'."
;; (@* "Math" )
;;
+
+(defun ts-folde--with-in-range (range)
+ "Return non-nil if point is inside the range."
+ (and (<= (car range) (point)) (<= (point) (cdr range))))
+
(defun ts-fold--in-range-p (in-val in-min in-max)
"Check to see if IN-VAL is between IN-MIN and IN-MAX."
(and (<= in-min in-val) (<= in-val in-max)))
diff --git a/ts-fold.el b/ts-fold.el
index 4dc3ce6..0d1eb27 100644
--- a/ts-fold.el
+++ b/ts-fold.el
@@ -1,7 +1,7 @@
;;; ts-fold.el --- Code folding using tree-sitter -*- lexical-binding: t; -*-
;; Copyright (C) 2021 Junyi Hou
-;; Copyright (C) 2021 Shen, Jen-Chieh
+;; Copyright (C) 2021-2022 Shen, Jen-Chieh
;; Created date 2021-08-11 14:12:37
@@ -9,8 +9,8 @@
;; Shen, Jen-Chieh
;; Description: Code folding using tree-sitter
;; Keyword: folding tree-sitter
-;; Version: 0.1.0
-;; Package-Requires: ((emacs "26.1") (tree-sitter "0.15.1") (s "1.9.0") (fringe-helper "1.0.1"))
+;; Version: 0.2.0
+;; Package-Requires: ((emacs "26.1") (tree-sitter "0.15.1") (s "1.9.0") (fringe-helper "1.0.1") (ht "2.0"))
;; URL: https://github.com/jcs090218/ts-fold
;; This file is NOT part of GNU Emacs.
@@ -38,14 +38,15 @@
;;; Code:
+(require 'cl-lib)
(require 'seq)
(require 'subr-x)
+(require 'ht)
(require 's)
(require 'tree-sitter)
(require 'ts-fold-util)
-(require 'ts-fold-parsers)
(require 'ts-fold-summary)
;;
@@ -54,60 +55,46 @@
(defgroup ts-fold nil
"Code folding using tree-sitter."
- :group 'tree-sitter
- :prefix "ts-fold-")
-
-(defvar ts-fold-foldable-node-alist nil
- "Collect a list of foldable node from variable `ts-fold-range-alist'.
-
-The alist is in form of (major-mode . (foldable-node-type)).")
-
-(defcustom ts-fold-range-alist
- `((agda-mode . ,(ts-fold-parsers-agda))
- (sh-mode . ,(ts-fold-parsers-bash))
- (c-mode . ,(ts-fold-parsers-c))
- (c++-mode . ,(ts-fold-parsers-c++))
- (csharp-mode . ,(ts-fold-parsers-csharp))
- (css-mode . ,(ts-fold-parsers-css))
- (ess-r-mode . ,(ts-fold-parsers-r))
- (go-mode . ,(ts-fold-parsers-go))
- (html-mode . ,(ts-fold-parsers-html))
- (java-mode . ,(ts-fold-parsers-java))
- (javascript-mode . ,(ts-fold-parsers-javascript))
- (js-mode . ,(ts-fold-parsers-javascript))
- (js2-mode . ,(ts-fold-parsers-javascript))
- (js3-mode . ,(ts-fold-parsers-javascript))
- (json-mode . ,(ts-fold-parsers-json))
- (jsonc-mode . ,(ts-fold-parsers-json))
- (nix-mode . ,(ts-fold-parsers-nix))
- (php-mode . ,(ts-fold-parsers-php))
- (python-mode . ,(ts-fold-parsers-python))
- (rjsx-mode . ,(ts-fold-parsers-javascript))
- (ruby-mode . ,(ts-fold-parsers-ruby))
- (rust-mode . ,(ts-fold-parsers-rust))
- (rustic-mode . ,(ts-fold-parsers-rust))
- (scala-mode . ,(ts-fold-parsers-scala))
- (swift-mode . ,(ts-fold-parsers-swift))
- (typescript-mode . ,(ts-fold-parsers-typescript)))
- "An alist of (major-mode . (foldable-node-type . function)).
-
-FUNCTION is used to determine where the beginning and end for FOLDABLE-NODE-TYPE
-in MAJOR-MODE. It should take a single argument (the syntax node with type
-FOLDABLE-NODE-TYPE) and return the buffer positions of the beginning and end of
-the fold in a cons cell. See `ts-fold-range-python' for an example."
- :type '(alist :key-type symbol
- :value-type (alist :key-type symbol :value-type function))
- :set (lambda (symbol value)
- (set-default symbol value)
- (setq ts-fold-foldable-node-alist
- (let (alist)
- (dolist (item ts-fold-range-alist)
- (let ((mode (car item)) nodes)
- (dolist (rule (cdr item)) (push (car rule) nodes))
- (push (cons mode nodes) alist)))
- alist)))
+ :prefix "ts-fold-"
+ :group 'tree-sitter)
+
+(defconst ts-fold--dir (file-name-directory (locate-library "ts-fold.el"))
+ "The directory where the library `ts-fold' is located.")
+
+(defconst ts-fold--queries-dir
+ (file-name-as-directory (concat ts-fold--dir "queries"))
+ "The directory where the `ts-fold' queries is located.")
+
+(defcustom ts-fold-major-mode-language-alist nil
+ "Alist that maps major modes to tree-sitter language names."
+ :type '(alist :key-type symbol :value-type string)
:group 'ts-fold)
+(pcase-dolist
+ (`(,major-mode . ,lang-symbol)
+ (reverse
+ '((sh-mode . "bash")
+ (shell-script-mode . "bash")
+ (c-mode . "c")
+ (csharp-mode . "c-sharp")
+ (c++-mode . "cpp")
+ (go-mode . "go")
+ (html-mode . "html")
+ (java-mode . "java")
+ (javascript-mode . "javascript")
+ (js-mode . "javascript")
+ (js2-mode . "javascript")
+ (js3-mode . "javascript")
+ (julia-mode . "julia")
+ (php-mode . "php")
+ (python-mode . "python")
+ (rjsx-mode . "javascript")
+ (ruby-mode . "ruby")
+ (rust-mode . "rust")
+ (rustic-mode . "rust")
+ (typescript-mode . "typescript"))))
+ (setf (map-elt ts-fold-major-mode-language-alist major-mode) lang-symbol))
+
(defcustom ts-fold-mode-hook nil
"Hook to run when enabling `ts-fold-mode`."
:type 'hook
@@ -128,6 +115,12 @@ the fold in a cons cell. See `ts-fold-range-python' for an example."
"Face used to display fringe contents."
:group 'ts-fold)
+(defvar ts-fold--query-cache (ht-create)
+ "Hashmap of `lang-symbol' and it's query file string.")
+
+(defvar ts-fold-debug nil
+ "Set to non-nil to enable debug mode.")
+
;;
;; (@* "Externals" )
;;
@@ -174,34 +167,125 @@ the fold in a cons cell. See `ts-fold-range-python' for an example."
(lambda () (ts-fold-mode 1)))
;;
-;; (@* "Core" )
+;; (@* "Queries" )
;;
-(defun ts-fold--foldable-node-at-pos (&optional pos)
- "Return the smallest foldable node at POS. If POS is nil, use `point'.
+(defun ts-fold--get-query (language top-level)
+ "Get tree sitter query for LANGUAGE.
+TOP-LEVEL is used to mention if we should load optional inherits."
+ (with-temp-buffer
+ (when-let* ((filename (concat ts-fold--queries-dir language "/folds.scm"))
+ ((file-exists-p filename)))
+ (insert-file-contents filename)
+ (goto-char (point-min))
+ (when-let* ((first-line (thing-at-point 'line t))
+ (first-line-matches
+ (save-match-data
+ (when (string-match "^; *inherits *:? *\\([a-z_,()]+\\) *$"
+ first-line)
+ (match-string 1 first-line)))))
+ (insert
+ (string-join
+ (mapcar (lambda (x)
+ (if (string-prefix-p "(" x)
+ (when top-level
+ (ts-fold--get-query (substring x 1 -1)
+ nil))
+ (ts-fold--get-query x nil)))
+ (split-string first-line-matches ","))
+ "\n")))
+ (buffer-string))))
-Raise `user-error' if no foldable node is found.
+;;
+;; (@* "Core" )
+;;
-This function is borrowed from `tree-sitter-node-at-point'."
- (let* ((pos (or pos (point)))
- (foldable-types (alist-get major-mode ts-fold-foldable-node-alist))
- (root (tsc-root-node tree-sitter-tree))
- (node (tsc-get-descendant-for-position-range root pos pos)))
- (let ((current node) result)
- (while current
- (if (memq (tsc-node-type current) foldable-types)
- (setq result current
- current nil)
- (setq current (tsc-get-parent current))))
- (or result (user-error "No foldable node found at POS")))))
+(defun ts-fold--nodes-before (nodes)
+ "NODES which contain the current after them."
+ (cl-remove-if-not (lambda (x)
+ (< (byte-to-position (cdr (tsc-node-byte-range x))) (point)))
+ nodes))
+
+(defun ts-fold--nodes-within (nodes)
+ "NODES which contain the current point inside them ordered inside out."
+ (let ((byte-pos (position-bytes (point))))
+ (sort (cl-remove-if-not (lambda (x)
+ (and (<= (car (tsc-node-byte-range x)) byte-pos)
+ (< byte-pos (cdr (tsc-node-byte-range x)))))
+ nodes)
+ (lambda (x y)
+ (< (+ (abs (- byte-pos
+ (car (tsc-node-byte-range x))))
+ (abs (- byte-pos
+ (cdr (tsc-node-byte-range x)))))
+ (+ (abs (- byte-pos
+ (car (tsc-node-byte-range y))))
+ (abs (- byte-pos
+ (cdr (tsc-node-byte-range y))))))))))
+
+(defun ts-fold--nodes-after (nodes)
+ "NODES which contain the current point before them ordered top to bottom."
+ (cl-remove-if-not (lambda (x)
+ (> (byte-to-position (car (tsc-node-byte-range x))) (point)))
+ nodes))
+
+(defun ts-fold--get-nodes (group query)
+ "Get a list of viable nodes based on `GROUP' value.
+They will be order with captures with point inside them first then the
+ones that follow. If a `QUERY' alist is provided, we make use of that
+instead of the builtin query set."
+ (let* ((lang-name (alist-get major-mode ts-fold-major-mode-language-alist))
+ (debugging-query (or (ht-get ts-fold--query-cache lang-name)
+ (if query (alist-get major-mode query)
+ (ts-fold--get-query lang-name t))))
+ (root-node (tsc-root-node tree-sitter-tree))
+ (query (tsc-make-query tree-sitter-language debugging-query))
+ (captures (tsc-query-captures query root-node #'tsc--buffer-substring-no-properties))
+ (filtered-captures (cl-remove-if-not (lambda (x)
+ (member (car x) group))
+ captures))
+ (nodes (seq-map #'cdr filtered-captures)))
+ (ht-set ts-fold--query-cache lang-name debugging-query)
+ (when ts-fold-debug (ts-fold-clear-cache))
+ (cl-remove-duplicates
+ nodes
+ :test (lambda (x y)
+ (and (= (car (tsc-node-byte-range x)) (car (tsc-node-byte-range y)))
+ (= (cdr (tsc-node-byte-range x)) (cdr (tsc-node-byte-range y))))))))
+
+(defun ts-fold--get-within-and-after (group count query)
+ "Given a `GROUP' `QUERY' find `COUNT' number of nodes within in and after
+current point."
+ (let* ((nodes (ts-fold--get-nodes group query))
+ (nodes-within (ts-fold--nodes-within nodes))
+ (nodes-after (ts-fold--nodes-after nodes))
+ (filtered-nodes (append nodes-within nodes-after)))
+ (when (> (length filtered-nodes) 0)
+ (cl-subseq filtered-nodes 0 count))))
+
+(defun ts-fold--current-node ()
+ "Return the current foldable node."
+ (ts-fold--get-within-and-after '(fold comment) 1 nil))
+
+(defun ts-fold--range (nodes)
+ "Return the range from NODES."
+ (let* ((range-min (apply #'min
+ (seq-map (lambda (x)
+ (car (tsc-node-byte-range x)))
+ nodes)))
+ (range-max (apply #'max
+ (seq-map (lambda (x)
+ (cdr (tsc-node-byte-range x)))
+ nodes)))
+ (min (cl-callf byte-to-position range-min))
+ (max (cl-callf byte-to-position range-max)))
+ ;; Have to compute min and max like this as we might have nested functions
+ ;; We have to use `cl-callf byte-to-position` ot the positioning might be off for unicode chars
+ (cons (1+ min) (1- max))))
(defun ts-fold--get-fold-range (node)
- "Return the beginning (as buffer position) of fold for NODE."
- (when-let* ((fold-alist (alist-get major-mode ts-fold-range-alist))
- (item (alist-get (tsc-node-type node) fold-alist)))
- (cond ((functionp item) (funcall item node (cons 0 0)))
- ((listp item) (funcall (nth 0 item) node (cons (nth 1 item) (nth 2 item))))
- (t (user-error "Current node is not found in `ts-fold-range-alist' in %s" major-mode)))))
+ "Return fold range."
+ (ts-fold--range (if (listp node) node (list node))))
;;
;; (@* "Overlays" )
@@ -209,32 +293,28 @@ This function is borrowed from `tree-sitter-node-at-point'."
(defun ts-fold--create-overlay (range)
"Create invisible overlay in RANGE."
- (when range
- (let* ((beg (car range)) (end (cdr range)) (ov (make-overlay beg end)))
- (overlay-put ov 'creator 'ts-fold)
- (overlay-put ov 'invisible 'ts-fold)
- (overlay-put ov 'display (or (and ts-fold-summary-show
- (ts-fold-summary--get (buffer-substring beg end)))
- ts-fold-replacement))
- (overlay-put ov 'face 'ts-fold-replacement-face)
- (overlay-put ov 'isearch-open-invisible #'ts-fold--isearch-open))))
+ (let* ((beg (car range)) (end (cdr range)) (ov (make-overlay beg end)))
+ (overlay-put ov 'creator 'ts-fold)
+ (overlay-put ov 'invisible 'ts-fold)
+ (overlay-put ov 'display (or (and ts-fold-summary-show
+ (ts-fold-summary--get (buffer-substring beg end)))
+ ts-fold-replacement))
+ (overlay-put ov 'face 'ts-fold-replacement-face)
+ (overlay-put ov 'isearch-open-invisible #'ts-fold--isearch-open)))
(defun ts-fold--isearch-open (ov)
"Open overlay OV during `isearch' session."
(delete-overlay ov))
-(defun ts-fold-overlay-at (node)
+(defun ts-fold-overlay-at (range)
"Return the ts-fold overlay at NODE if NODE is foldable and folded.
Return nil otherwise."
- (when-let* ((foldable-types (alist-get major-mode ts-fold-foldable-node-alist))
- ((memq (tsc-node-type node) foldable-types))
- (range (ts-fold--get-fold-range node)))
- (thread-last (overlays-in (car range) (cdr range))
- (seq-filter (lambda (ov)
- (and (eq (overlay-get ov 'invisible) 'ts-fold)
- (= (overlay-start ov) (car range))
- (= (overlay-end ov) (cdr range)))))
- car)))
+ (thread-last (overlays-in (car range) (cdr range))
+ (seq-filter (lambda (ov)
+ (and (eq (overlay-get ov 'invisible) 'ts-fold)
+ (= (overlay-start ov) (car range))
+ (= (overlay-end ov) (cdr range)))))
+ car))
;;
;; (@* "Commands" )
@@ -243,23 +323,31 @@ Return nil otherwise."
(defmacro ts-fold--ensure-ts (&rest body)
"Run BODY only if `tree-sitter-mode` is enabled."
(declare (indent 0))
- `(if (bound-and-true-p tree-sitter-mode)
- (progn ,@body)
+ `(if (bound-and-true-p tree-sitter-mode) (progn ,@body)
(user-error "Ignored, tree-sitter-mode is not enable in the current buffer")))
+(defconst ts-fold-interactive-commands
+ '(ts-fold-close
+ ts-fold-open
+ ts-fold-open-recursively
+ ts-fold-close-all
+ ts-fold-open-all
+ ts-fold-toggle)
+ "List of interactive commands.")
+
;;;###autoload
(defun ts-fold-close (&optional node)
"Fold the syntax node at `point` if it is foldable.
-Foldable nodes are defined in `ts-fold-foldable-node-alist' for the
-current `major-mode'. If no foldable NODE is found in point, do nothing."
+Foldable nodes are defined in `ts-fold-groups-alist' for the current
+`major-mode'. If no foldable NODE is found in point, do nothing."
(interactive)
(ts-fold--ensure-ts
- (let ((node (or node (ts-fold--foldable-node-at-pos))))
+ (when-let* ((node (or node (ts-fold--current-node)))
+ (range (ts-fold--get-fold-range node)))
;; make sure I do not create multiple overlays for the same fold
- (when-let* ((ov (ts-fold-overlay-at node)))
- (delete-overlay ov))
- (ts-fold--create-overlay (ts-fold--get-fold-range node)))))
+ (when-let ((ov (ts-fold-overlay-at range))) (delete-overlay ov))
+ (ts-fold--create-overlay range))))
;;;###autoload
(defun ts-fold-open ()
@@ -267,8 +355,9 @@ current `major-mode'. If no foldable NODE is found in point, do nothing."
If the current node is not folded or not foldable, do nothing."
(interactive)
(ts-fold--ensure-ts
- (when-let* ((node (ts-fold--foldable-node-at-pos))
- (ov (ts-fold-overlay-at node)))
+ (when-let* ((node (ts-fold--current-node))
+ (range (ts-fold--get-fold-range node))
+ (ov (ts-fold-overlay-at range)))
(delete-overlay ov))))
;;;###autoload
@@ -276,27 +365,22 @@ If the current node is not folded or not foldable, do nothing."
"Open recursively folded syntax NODE that are contained in the node at point."
(interactive)
(ts-fold--ensure-ts
- (when-let* ((node (ts-fold--foldable-node-at-pos))
- (beg (tsc-node-start-position node))
- (end (tsc-node-end-position node)))
+ (when-let* ((node (ts-fold--current-node))
+ (range (ts-fold--get-fold-range node))
+ (beg (car range))
+ (end (cdr range)))
(thread-last (overlays-in beg end)
- (seq-filter (lambda (ov) (eq (overlay-get ov 'invisible) 'ts-fold)))
- (mapc #'delete-overlay)))))
+ (seq-filter (lambda (ov) (eq (overlay-get ov 'invisible) 'ts-fold)))
+ (mapc #'delete-overlay)))))
;;;###autoload
(defun ts-fold-close-all ()
"Fold all foldable syntax nodes in the buffer."
(interactive)
(ts-fold--ensure-ts
- (let* ((node (tsc-root-node tree-sitter-tree))
- (patterns (seq-mapcat (lambda (type) `(,(list type) @name))
- (alist-get major-mode ts-fold-foldable-node-alist)
- 'vector))
- (query (tsc-make-query tree-sitter-language patterns))
- (nodes-to-fold (tsc-query-captures query node #'ignore)))
+ (when-let ((nodes-to-fold (ts-fold--get-nodes '(fold comment) nil)))
(thread-last nodes-to-fold
- (mapcar #'cdr)
- (mapc #'ts-fold-close)))))
+ (mapc #'ts-fold-close)))))
;;;###autoload
(defun ts-fold-open-all ()
@@ -313,174 +397,16 @@ If the current node is not folded or not foldable, do nothing."
If the current syntax node is not foldable, do nothing."
(interactive)
(ts-fold--ensure-ts
- (if-let* ((node (ts-fold--foldable-node-at-pos (point)))
- (ov (ts-fold-overlay-at node)))
+ (if-let* ((node (ts-fold--current-node))
+ (range (ts-fold--get-fold-range node))
+ (ov (ts-fold-overlay-at range)))
(progn (delete-overlay ov) t)
(ts-fold-close))))
-(defun ts-fold--after-command (&rest _)
- "Function call after interactive commands."
- (ts-fold-indicators-refresh))
-
-(let ((commands '(ts-fold-close
- ts-fold-open
- ts-fold-open-recursively
- ts-fold-close-all
- ts-fold-open-all
- ts-fold-toggle)))
- (dolist (command commands)
- (advice-add command :after #'ts-fold--after-command)))
-
-;;
-;; (@* "Rule Helpers" )
-;;
-
-(defun ts-fold--next-prev-node (node next)
- "Return previous/next sibling node starting from NODE.
-
-If NEXT is non-nil, return next sibling. Otherwirse, return previouse sibling."
- (if next (tsc-get-next-sibling node) (tsc-get-prev-sibling node)))
-
-(defun ts-fold--continuous-node-prefix (node prefix next)
- "Iterate through node starting from NODE and compare node-text to PREFIX;
-then return the last iterated node.
-
-Argument NEXT is a boolean type. If non-nil iterate forward; otherwise iterate
-in backward direction."
- (let ((iter-node node) (last-node node)
- (last-line (car (tsc-node-start-point node))) line text break
- (line-range 1) (last-line-range 1) max-line-range)
- (while (and iter-node (not break))
- (setq text (tsc-node-text iter-node)
- line (car (tsc-node-start-point iter-node))
- line-range (1+ (s-count-matches "\n" text))
- max-line-range (max line-range last-line-range))
- (if (and (ts-fold--in-range-p line (- last-line max-line-range) (+ last-line max-line-range))
- (string-prefix-p prefix text))
- (setq last-node iter-node last-line line
- last-line-range (1+ (s-count-matches "\n" text)))
- (setq break t))
- (setq iter-node (ts-fold--next-prev-node iter-node next)))
- last-node))
-
-(defun ts-fold-range-seq (node offset)
- "Return the fold range in sequence starting from NODE.
-
-Argument OFFSET can be used to tweak the final beginning and end position."
- (let ((beg (1+ (tsc-node-start-position node)))
- (end (1- (tsc-node-end-position node))))
- (ts-fold--cons-add (cons beg end) offset)))
-
-(defun ts-fold-range-line-comment (node offset prefix)
- "Define fold range for line comment.
-
-For arguments NODE and OFFSET, see function `ts-fold-range-seq' for
-more information.
-
-Argument PREFIX is the comment prefix in string."
- (when-let* ((first-node (ts-fold--continuous-node-prefix node prefix nil))
- (last-node (ts-fold--continuous-node-prefix node prefix t))
- (prefix-len (length prefix))
- (beg (+ (tsc-node-start-position first-node) prefix-len))
- (end (tsc-node-end-position last-node)))
- (ts-fold--cons-add (cons beg end) offset)))
-
-(defun ts-fold-range-block-comment (node offset)
- "Define fold range for block comment.
-
-For arguments NODE and OFFSET, see function `ts-fold-range-seq' for
-more information."
- (ts-fold-range-seq node (ts-fold--cons-add '(1 . -1) offset)))
-
-(defun ts-fold-range-c-like-comment (node offset)
- "Define fold range for C-like comemnt."
- (let ((text (tsc-node-text node)))
- (if (and (string-match-p "\n" text) (string-prefix-p "/*" text))
- (ts-fold-range-block-comment node offset)
- (if (string-prefix-p "///" text)
- (ts-fold-range-line-comment node offset "///")
- (ts-fold-range-line-comment node offset "//")))))
-
-;;
-;; (@* "Languages" )
-;;
-
-(defun ts-fold-range-c-preproc-if (node offset)
- "Define fold range for `if' preprocessor."
- (let* ((named-node (tsc-get-child-by-field node :condition))
- (else (tsc-get-child-by-field node :alternative))
- (beg (tsc-node-end-position named-node))
- (end (1- (tsc-node-start-position else))))
- (ts-fold--cons-add (cons beg end) offset)))
-
-(defun ts-fold-range-c-preproc-ifdef (node offset)
- "Define fold range for `ifdef' and `ifndef' preprocessor."
- (when-let* ((named-node (tsc-get-child-by-field node :name))
- (else (tsc-get-child-by-field node :alternative))
- (beg (tsc-node-end-position named-node))
- (end (1- (tsc-node-start-position else))))
- (ts-fold--cons-add (cons beg end) offset)))
-
-(defun ts-fold-range-c-preproc-elif (node offset)
- "Define fold range for `elif' preprocessor."
- (when-let* ((named-node (tsc-get-child-by-field node :condition))
- (else (tsc-get-child-by-field node :alternative))
- (beg (tsc-node-end-position named-node))
- (end (1- (tsc-node-start-position else))))
- (ts-fold--cons-add (cons beg end) offset)))
-
-(defun ts-fold-range-c-preproc-else (node offset)
- "Define fold range for `else' preprocessor."
- (when-let* ((target "#else")
- (len (length target))
- (beg (+ (tsc-node-start-position node) len))
- (end (tsc-node-end-position node)))
- (ts-fold--cons-add (cons beg end) offset)))
-
-(defun ts-fold-range-html (node offset)
- "Define fold range for tag in HTML."
- (let* ((beg (tsc-node-end-position (tsc-get-nth-child node 0)))
- (end-node (tsc-get-nth-child node (1- (tsc-count-children node))))
- (end (tsc-node-start-position end-node)))
- (ts-fold--cons-add (cons beg end) offset)))
-
-(defun ts-fold-range-python (node offset)
- "Define fold range for `function_definition' and `class_definition'.
-
-For arguments NODE and OFFSET, see function `ts-fold-range-seq' for
-more information."
- (when-let* ((named-node (or (tsc-get-child-by-field node :superclasses)
- (tsc-get-child-by-field node :return_type)
- (tsc-get-child-by-field node :parameters)
- (tsc-get-child-by-field node :name)))
- ;; the colon is an anonymous node after return_type or parameters node
- (beg (tsc-node-end-position (tsc-get-next-sibling named-node)))
- (end (tsc-node-end-position node)))
- (ts-fold--cons-add (cons beg end) offset)))
-
-(defun ts-fold-range-ruby (node offset)
- "Define fold range for `method' and `class' in Ruby.
-
-For arguments NODE and OFFSET, see function `ts-fold-range-seq' for
-more information."
- (when-let* ((named-node (or (tsc-get-child-by-field node :superclass)
- (tsc-get-child-by-field node :parameters)
- (tsc-get-child-by-field node :name)))
- (beg (tsc-node-end-position named-node))
- (end (tsc-node-end-position node)))
- (ts-fold--cons-add (cons beg end) offset)))
-
-(defun ts-fold-range-rust-macro (node offset)
- "Return the fold range for `macro_definition' NODE in Rust.
-
-For arguments NODE and OFFSET, see function `ts-fold-range-seq' for
-more information."
- (when-let* ((children (tsc-count-children node))
- (last_bracket (tsc-get-nth-child node (- children 1)))
- (first_bracket (tsc-get-nth-child node 2))
- (beg (tsc-node-start-position first_bracket))
- (end (1+ (tsc-node-start-position last_bracket))))
- (ts-fold--cons-add (cons beg end) offset)))
+(defun ts-fold-clear-cache ()
+ "Clean up the query cache."
+ (interactive)
+ (ht-clear ts-fold--query-cache))
(provide 'ts-fold)
;;; ts-fold.el ends here