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