From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Theodor Thornhill Newsgroups: gmane.emacs.devel Subject: Re: Plug treesit.el into other emacs constructs Date: Thu, 15 Dec 2022 21:57:31 +0100 Message-ID: <87pmckz8p0.fsf@thornhill.no> References: <87wn6whete.fsf@thornhill.no> <87r0x3gnv5.fsf@thornhill.no> <04BB786A-3ED1-4918-8583-17AA01A1E453@gmail.com> <4E3940CA-67A6-45B7-8785-4E60FDECCDFB@gmail.com> <4315EFC6-7AA8-4A48-845C-9CA8B88034D9@thornhill.no> <87bko521n0.fsf@thornhill.no> <87359h1ybt.fsf@thornhill.no> <871qp01msi.fsf@thornhill.no> <87v8mczb6b.fsf@thornhill.no> <87sfhgz9s8.fsf@thornhill.no> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="11182"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Yuan Fu , emacs-devel@gnu.org, eliz@gnu.org To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Thu Dec 15 21:58:22 2022 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1p5vJ8-0002eO-Gm for ged-emacs-devel@m.gmane-mx.org; Thu, 15 Dec 2022 21:58:22 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1p5vIS-0000Hx-CP; Thu, 15 Dec 2022 15:57:40 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p5vIQ-0000Hn-Cb for emacs-devel@gnu.org; Thu, 15 Dec 2022 15:57:38 -0500 Original-Received: from out2.migadu.com ([2001:41d0:2:aacc::]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p5vIN-0005HV-9a; Thu, 15 Dec 2022 15:57:38 -0500 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=thornhill.no; s=key1; t=1671137852; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=MC6uh4ivLyzXPMTNHKuMW59ICuQNZOTO92whaZYiItg=; b=ykR4iopfgq8SUQGs1t/oSpZ6o8960GIFcB7POduE30GSVP70VEt/1tGqL20mX3TjU3p/q1 iZU7kUF/hG/57SiotlLaALXEc3HdnLfVUbljOTy8FEb82jiEUoaPPF1u14S8OzctnY/6hE busbuM0Hy1hV9Lavu/sRnD84exuPoLgzuAEd131AxQWTOjYI8vlAwdcOAJzYcVDA2NK0xv sGhlkuW+T+liwkAvNiNEgfhc00O3az7eW0dDZcsc2VTVNlZyuhiOhaFBFW74AewC2Sxxab tdy3VjJstoE90IGLmwsFrolNWIjcXvIGaacjAv61Pj1sX4wt+F12+6W6WHuXQQ== In-Reply-To: <87sfhgz9s8.fsf@thornhill.no> X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=2001:41d0:2:aacc::; envelope-from=theo@thornhill.no; helo=out2.migadu.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:301470 Archived-At: --=-=-= Content-Type: text/plain Theodor Thornhill writes: > Theodor Thornhill writes: > >> Stefan Monnier writes: >> >>>> If this code is plugged into transpose-sexps we get this nice behavior: >>> >>> It's a bit different from what SMIE would do, but there's a lot of >>> overlap and when it's different it's arguably better, so sounds good >>> to me. >>> >> >> Great! >> >>>> Now forward/backward-sexp can actually work a little differently, as you >>>> suggest, or we can let it use the same "move over siblings"-semantic. >>>> In that case we don't even need the treesit-sexp-type-regexp variables to >>>> control this, I think. >>>> >>>> What do you think? >>> >>> I'm not sufficiently familiar with the tree-sitter tree to foresee >>> precisely how it would affect `forward/backward-sexp`, but I think you >>> have a good enough understanding to make a good judgment at this >>> point :-) >> >> Great. I'll prepare a patch for this behavior, and we can discuss the >> forward-* commands after that. >> > > What do you think about this? Feel free to try it and let me know if > something is completely wrong :-) Now you can use 'arg' as well. --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-Add-treesit-transpose-sexps.patch >From 0ccb449aee15ba1bdd13e5380e5341733a3c9f99 Mon Sep 17 00:00:00 2001 From: Theodor Thornhill Date: Thu, 15 Dec 2022 21:22:13 +0100 Subject: [PATCH] Add treesit-transpose-sexps We don't really need to rely on forward-sexp to define what to transpose. In tree-sitter we can consider siblings as "balanced expressions", and swap them without doing any movement to calculate where the siblings in question are. * lisp/simple.el: Add requires for treesit. * lisp/simple.el (transpose-sexps): If tree-sitter is available, use treesit-transpose-sexps as the 'special' function. (transpose-subr): Just use tree-sitter when available. * lisp/treesit.el (treesit-transpose-sexps): New function. --- lisp/simple.el | 68 +++++++++++++++++++++++++++---------------------- lisp/treesit.el | 16 ++++++++++++ 2 files changed, 53 insertions(+), 31 deletions(-) diff --git a/lisp/simple.el b/lisp/simple.el index 893a43b03f..d6252ea9e6 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -28,10 +28,12 @@ ;;; Code: -(eval-when-compile (require 'cl-lib)) +(eval-when-compile (require 'cl-lib) + (require 'treesit)) (declare-function widget-convert "wid-edit" (type &rest args)) (declare-function shell-mode "shell" ()) +(declare-function treesit-parser-list "treesit.c") ;;; From compile.el (defvar compilation-current-error) @@ -8453,36 +8455,37 @@ transpose-sexps (transpose-sexps arg nil) (scan-error (user-error "Not between two complete sexps"))) (transpose-subr - (lambda (arg) - ;; Here we should try to simulate the behavior of - ;; (cons (progn (forward-sexp x) (point)) - ;; (progn (forward-sexp (- x)) (point))) - ;; Except that we don't want to rely on the second forward-sexp - ;; putting us back to where we want to be, since forward-sexp-function - ;; might do funny things like infix-precedence. - (if (if (> arg 0) - (looking-at "\\sw\\|\\s_") - (and (not (bobp)) - (save-excursion - (forward-char -1) - (looking-at "\\sw\\|\\s_")))) - ;; Jumping over a symbol. We might be inside it, mind you. - (progn (funcall (if (> arg 0) - 'skip-syntax-backward 'skip-syntax-forward) - "w_") - (cons (save-excursion (forward-sexp arg) (point)) (point))) - ;; Otherwise, we're between sexps. Take a step back before jumping - ;; to make sure we'll obey the same precedence no matter which - ;; direction we're going. - (funcall (if (> arg 0) 'skip-syntax-backward 'skip-syntax-forward) - " .") - (cons (save-excursion (forward-sexp arg) (point)) - (progn (while (or (forward-comment (if (> arg 0) 1 -1)) - (not (zerop (funcall (if (> arg 0) - 'skip-syntax-forward - 'skip-syntax-backward) - "."))))) - (point))))) + (if (treesit-parser-list) #'treesit-transpose-sexps + (lambda (arg) + ;; Here we should try to simulate the behavior of + ;; (cons (progn (forward-sexp x) (point)) + ;; (progn (forward-sexp (- x)) (point))) + ;; Except that we don't want to rely on the second forward-sexp + ;; putting us back to where we want to be, since forward-sexp-function + ;; might do funny things like infix-precedence. + (if (if (> arg 0) + (looking-at "\\sw\\|\\s_") + (and (not (bobp)) + (save-excursion + (forward-char -1) + (looking-at "\\sw\\|\\s_")))) + ;; Jumping over a symbol. We might be inside it, mind you. + (progn (funcall (if (> arg 0) + 'skip-syntax-backward 'skip-syntax-forward) + "w_") + (cons (save-excursion (forward-sexp arg) (point)) (point))) + ;; Otherwise, we're between sexps. Take a step back before jumping + ;; to make sure we'll obey the same precedence no matter which + ;; direction we're going. + (funcall (if (> arg 0) 'skip-syntax-backward 'skip-syntax-forward) + " .") + (cons (save-excursion (forward-sexp arg) (point)) + (progn (while (or (forward-comment (if (> arg 0) 1 -1)) + (not (zerop (funcall (if (> arg 0) + 'skip-syntax-forward + 'skip-syntax-backward) + "."))))) + (point)))))) arg 'special))) (defun transpose-lines (arg) @@ -8521,6 +8524,9 @@ transpose-subr (progn (funcall mover (- x)) (point)))))) pos1 pos2) (cond + ((treesit-parser-list) + (cl-multiple-value-bind (p1 p2) (funcall aux arg) + (transpose-subr-1 p1 p2))) ((= arg 0) (save-excursion (setq pos1 (funcall aux 1)) diff --git a/lisp/treesit.el b/lisp/treesit.el index 913a1d8c5b..016f6d19eb 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -1620,6 +1620,22 @@ treesit--defun-maybe-top-level node) finally return node)))) +(defun treesit-transpose-sexps (&optional arg) + "Tree-sitter `transpose-sexps' function. +Arg is the same as in `transpose-sexps'." + (interactive "*p") + (if-let* ((node (treesit-node-at (point))) + (parent (treesit-node-parent node)) + (index (treesit-node-index node)) + (prev (treesit-node-child parent (1- index))) + (next (treesit-node-child parent (+ arg index)))) + (list (cons (treesit-node-start prev) + (treesit-node-end prev)) + (cons (treesit-node-start next) + (treesit-node-end next))) + ;; Hack to trigger the error message in transpose-subr-1 when we + ;; don't have siblings to swap. + (list (cons 0 1) (cons 0 1)))) (defun treesit-beginning-of-defun (&optional arg) "Tree-sitter `beginning-of-defun' function. ARG is the same as in `beginning-of-defun'." -- 2.34.1 --=-=-=--