Subject: Re: bug#73404: 30.0.50; [forward/kill/etc]-sexp commands do not behave as expected in tree-sitter modes

From: Juri Linkov <[email-masked]>
Date: Thu, 12 Dec 2024 18:31:04 +0200

> A better idea: instead of 'sexp' in treesit-thing-settings
> define separately 'list' and 'atom', e.g. replace
>
>     (setq-local treesit-thing-settings
>                 `((javascript
>                    (sexp ,(js--regexp-opt-symbol js--treesit-sexp-nodes)))))
>
> with
>
>     (setq-local treesit-thing-settings
>                 `((javascript
>                    (list ,(js--regexp-opt-symbol js--treesit-list-nodes))
>                    (atom ,(js--regexp-opt-symbol js--treesit-atom-nodes)))))

Still the problem is that using the atoms from the tree
doesn't provide backward-compatibility with non-ts modes
and how C-M-f moves on non-list atoms there.

One way would be to extract anonymous text leaf nodes
such as "export" and "const" from

 (export_statement "export" declaration: 
 (lexical_declaration kind: "const"

But still need to check symbol/word syntax to omit such nodes
as "+" from

  (binary_expression left: (identifier) operator: "+"

Therefore to provide backward-compatibility with non-ts modes
in regard to C-M-f navigation, navigation on atoms should follow
the Sword/Ssymbol rules of 'scan_lists' with non-nil 'sexpflag'.

So an atom should be a syntactical entity, not structural.
This means that treesit-forward-sexp should use the 'list' thing
with syntactical atoms.

For example, for 'C-M-f' on

  var p = {
    case: 'zzzz',
    -!-default: 'donkey',
    tee: 'ornery'
  };

in js-ts-mode it would be unexpected to move to

  var p = {
    case: 'zzzz',
    default: 'donkey'-!-,
    tee: 'ornery'
  };

because js-mode moves to

  var p = {
    case: 'zzzz',
    default-!-: 'donkey',
    tee: 'ornery'
  };

But anyway 'list' should be customizable as 'sexp' already is.

OTOH, transpose-sexps should use treesit 'sexp' with more fine-grained
lists that are not suitable for forward-sexp.
(And we have no transpose-lists.)

For example, it's expected for transpose-sexps to transpose
a pair of key:value defined by 'sexp':

  var p = {
    default: 'donkey',
    -!-case: 'zzzz',
    tee: 'ornery'
  };

that will be a big improvement when comparing to js-mode.
This also will close bug#60655.

And if someone want to transpose adjacent atoms (symbols or words),
there is transpose-words.

In summary:
The current implementation in treesit-forward-sexp is more like forward-list.
So let's rename it to treesit-forward-list, then create a new implementation
of treesit-forward-sexp that uses the 'list' thing together with
syntactical atoms.

Another variant is to leave treesit-forward-sexp as is,
and create a new function treesit-forward-sexp-with-list
that uses the 'list' thing.

And anyway let's keep the current implementation
of treesit-transpose-sexps that uses the 'sexp' thing.