From: Yuan Fu <casouri@gmail.com>
To: Eli Zaretskii <eliz@gnu.org>
Cc: "Clément Pit-Claudel" <cpitclaudel@gmail.com>,
"Stephen Leake" <stephen_leake@stephe-leake.org>,
"Stefan Monnier" <monnier@iro.umontreal.ca>,
emacs-devel@gnu.org
Subject: Re: How to add pseudo vector types
Date: Thu, 29 Jul 2021 10:35:10 -0400 [thread overview]
Message-ID: <E0D4E307-E5FE-4791-A3D5-8DA80CAF0AB7@gmail.com> (raw)
In-Reply-To: <83wnpas1q7.fsf@gnu.org>
[-- Attachment #1: Type: text/plain, Size: 1728 bytes --]
>>
>> That makes sense. However it bring up a problem. Consider such a buffer: XXAAXX. Say lisp narrows to AA and creates a tree-sitter parser. Then lisp widens the buffer, and user inserts B in front of AA. Now the buffer is XXBAAXX. Emacs has two options to convey this change to the tree-sitter parser: 1) it does not, then tree-sitter still thinks the buffer is AA, essentially the portion where tree-sitter sees is pushed forward by one character, 2) it tells tree-sitter the user inserted a character at the beginning, then tree-sitter thinks the buffer is BAA. Which option is correct depends on how does lisp later narrows: if lisp narrows to AA, then option 1 is correct, if lisp narrows to BAA, then option 2 is correct. But how do we know which option is correct before lisp narrows?
>
> We don't need to know. The Lisp program which needs to handle this
> situation will have to figure out what is right in that case, "right"
> in the sense that it produces the desired results after communicating
> the changes to TS.
The difficulty is that what tree-sitter sees must be consistent. If Emacs updates tree-sitter with option 1 and lisp later choose option 2, the content that tree-sitter sees is not consistent. Anyway, I found a way that avoids this issue: the bounds of tree-sitter’s visible region never changes, and the next time when lisp narrows to a different region, we update tree-sitter’s bound to match that of the narrowing. Here is the latest patch. If the code is not entirely straightforward, I’m happy to add more comment to explain it.
I set up a linux machine and tried to debug the crashing problem, but it didn’t crash. Seems the crash only appears on my Mac...
Yuan
[-- Attachment #2: ts.5.patch --]
[-- Type: application/octet-stream, Size: 23721 bytes --]
From 62fc019a7f57119329d53b9b8a3e8b5c1e61b27f Mon Sep 17 00:00:00 2001
From: Yuan Fu <casouri@gmail.com>
Date: Wed, 28 Jul 2021 21:08:43 -0400
Subject: [PATCH] checkpoint 5
- Move define_error out of json.c
- Add narrowing support
---
lisp/tree-sitter.el | 11 +-
src/eval.c | 13 ++
src/json.c | 16 ---
src/lisp.h | 5 +
src/tree_sitter.c | 231 +++++++++++++++++++++++-----------
src/tree_sitter.h | 15 ++-
test/src/tree-sitter-tests.el | 53 ++++++++
7 files changed, 251 insertions(+), 93 deletions(-)
diff --git a/lisp/tree-sitter.el b/lisp/tree-sitter.el
index a6ecb09386..8a887bb406 100644
--- a/lisp/tree-sitter.el
+++ b/lisp/tree-sitter.el
@@ -102,12 +102,13 @@ tree-sitter-font-lock-settings
PATTERN is a tree-sitter query pattern. (See manual for how to
write query patterns.) This pattern should capture nodes with
-either face names or function names. If captured with a face
-name, the node's corresponding text in the buffer is fontified
-with that face; if captured with a function name, the function is
-called with three arguments, BEG END NODE, where BEG and END
+either face symbols or function symbols. If captured with a face
+symbol, the node's corresponding text in the buffer is fontified
+with that face; if captured with a function symbol, the function
+is called with three arguments, BEG END NODE, where BEG and END
marks the span of the corresponding text, and NODE is the node
-itself.")
+itself. If a symbol is both a face and a function, it is treated
+as a face.")
(defun tree-sitter-fontify-region-function (beg end &optional verbose)
"Fontify the region between BEG and END.
diff --git a/src/eval.c b/src/eval.c
index 18faa0b9b1..33c0763f38 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1956,6 +1956,19 @@ signal_error (const char *s, Lisp_Object arg)
xsignal (Qerror, Fcons (build_string (s), arg));
}
+void
+define_error (Lisp_Object name, const char *message, Lisp_Object parent)
+{
+ eassert (SYMBOLP (name));
+ eassert (SYMBOLP (parent));
+ Lisp_Object parent_conditions = Fget (parent, Qerror_conditions);
+ eassert (CONSP (parent_conditions));
+ eassert (!NILP (Fmemq (parent, parent_conditions)));
+ eassert (NILP (Fmemq (name, parent_conditions)));
+ Fput (name, Qerror_conditions, pure_cons (name, parent_conditions));
+ Fput (name, Qerror_message, build_pure_c_string (message));
+}
+
/* Use this for arithmetic overflow, e.g., when an integer result is
too large even for a bignum. */
void
diff --git a/src/json.c b/src/json.c
index 3f1d27ad7f..ff28143a3c 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1098,22 +1098,6 @@ DEFUN ("json-parse-buffer", Fjson_parse_buffer, Sjson_parse_buffer,
return unbind_to (count, lisp);
}
-/* Simplified version of 'define-error' that works with pure
- objects. */
-
-static void
-define_error (Lisp_Object name, const char *message, Lisp_Object parent)
-{
- eassert (SYMBOLP (name));
- eassert (SYMBOLP (parent));
- Lisp_Object parent_conditions = Fget (parent, Qerror_conditions);
- eassert (CONSP (parent_conditions));
- eassert (!NILP (Fmemq (parent, parent_conditions)));
- eassert (NILP (Fmemq (name, parent_conditions)));
- Fput (name, Qerror_conditions, pure_cons (name, parent_conditions));
- Fput (name, Qerror_message, build_pure_c_string (message));
-}
-
void
syms_of_json (void)
{
diff --git a/src/lisp.h b/src/lisp.h
index e439447283..d30509b61a 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -5127,6 +5127,11 @@ maybe_gc (void)
maybe_garbage_collect ();
}
+/* Simplified version of 'define-error' that works with pure
+ objects. */
+void
+define_error (Lisp_Object name, const char *message, Lisp_Object parent);
+
INLINE_HEADER_END
#endif /* EMACS_LISP_H */
diff --git a/src/tree_sitter.c b/src/tree_sitter.c
index e9f8ddc7e3..5e16df7758 100644
--- a/src/tree_sitter.c
+++ b/src/tree_sitter.c
@@ -19,17 +19,8 @@ Copyright (C) 2021 Free Software Foundation, Inc.
#include <config.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
#include "lisp.h"
#include "buffer.h"
-#include "coding.h"
#include "tree_sitter.h"
/* parser.h defines a macro ADVANCE that conflicts with alloc.c. */
@@ -61,6 +52,16 @@ DEFUN ("tree-sitter-node-p",
/*** Parsing functions */
+static inline void
+ts_tree_edit_1 (TSTree *tree, ptrdiff_t start_byte,
+ ptrdiff_t old_end_byte, ptrdiff_t new_end_byte)
+{
+ TSPoint dummy_point = {0, 0};
+ TSInputEdit edit = {start_byte, old_end_byte, new_end_byte,
+ dummy_point, dummy_point, dummy_point};
+ ts_tree_edit (tree, &edit);
+}
+
/* Update each parser's tree after the user made an edit. This
function does not parse the buffer and only updates the tree. (So it
should be very fast.) */
@@ -68,18 +69,38 @@ DEFUN ("tree-sitter-node-p",
ts_record_change (ptrdiff_t start_byte, ptrdiff_t old_end_byte,
ptrdiff_t new_end_byte)
{
+ eassert(start_byte <= old_end_byte);
+ eassert(start_byte <= new_end_byte);
+
Lisp_Object parser_list = Fsymbol_value (Qtree_sitter_parser_list);
- TSPoint dummy_point = {0, 0};
- TSInputEdit edit = {start_byte, old_end_byte, new_end_byte,
- dummy_point, dummy_point, dummy_point};
+
while (!NILP (parser_list))
{
Lisp_Object lisp_parser = Fcar (parser_list);
TSTree *tree = XTS_PARSER (lisp_parser)->tree;
if (tree != NULL)
- ts_tree_edit (tree, &edit);
- XTS_PARSER (lisp_parser)->need_reparse = true;
- parser_list = Fcdr (parser_list);
+ {
+ /* We "clip" the change to between visible_beg and
+ visible_end. It is okay if visible_end ends up larger
+ than BUF_Z, tree-sitter only access buffer text during
+ re-parse, and we will adjust visible_beg/end before
+ re-parse. */
+ ptrdiff_t visible_beg = XTS_PARSER (lisp_parser)->visible_beg;
+ ptrdiff_t visible_end = XTS_PARSER (lisp_parser)->visible_end;
+
+ ptrdiff_t visible_start =
+ max (visible_beg, start_byte) - visible_beg;
+ ptrdiff_t visible_old_end =
+ min (visible_end, old_end_byte) - visible_beg;
+ ptrdiff_t visible_new_end =
+ min (visible_end, new_end_byte) - visible_beg;
+
+ ts_tree_edit_1 (tree, visible_start, visible_old_end,
+ visible_new_end);
+ XTS_PARSER (lisp_parser)->need_reparse = true;
+
+ parser_list = Fcdr (parser_list);
+ }
}
}
@@ -93,16 +114,67 @@ ts_ensure_parsed (Lisp_Object parser)
TSParser *ts_parser = XTS_PARSER (parser)->parser;
TSTree *tree = XTS_PARSER(parser)->tree;
TSInput input = XTS_PARSER (parser)->input;
+ struct buffer *buffer = XTS_PARSER (parser)->buffer;
+
+ /* Before we parse, catch up with the narrowing situation. We
+ change visible_beg and visible_end to match BUF_BEGV_BYTE and
+ BUF_ZV_BYTE, and inform tree-sitter of the change. */
+ ptrdiff_t visible_beg = XTS_PARSER (parser)->visible_beg;
+ ptrdiff_t visible_end = XTS_PARSER (parser)->visible_end;
+ /* Before re-parse, we want to move the visible range of tree-sitter
+ to matched the narrowed range. For example:
+ Move ________|____|__
+ to |____|__________ */
+
+ /* 1. Make sure visible_beg <= BUF_BEGV_BYTE. */
+ if (visible_beg > BUF_BEGV_BYTE (buffer))
+ {
+ /* Tree-sitter sees: insert at the beginning. */
+ ts_tree_edit_1 (tree, 0, 0, visible_beg - BUF_BEGV_BYTE (buffer));
+ visible_beg = BUF_BEGV_BYTE (buffer);
+ }
+ /* 2. Make sure visible_end = BUF_ZV_BYTE. */
+ if (visible_end < BUF_ZV_BYTE (buffer))
+ {
+ /* Tree-sitter sees: insert at the end. */
+ ts_tree_edit_1 (tree, visible_end - visible_beg,
+ visible_end - visible_beg,
+ BUF_ZV_BYTE (buffer) - visible_beg);
+ visible_end = BUF_ZV_BYTE (buffer);
+ }
+ else if (visible_end > BUF_ZV_BYTE (buffer))
+ {
+ /* Tree-sitter sees: delete at the end. */
+ ts_tree_edit_1 (tree, BUF_ZV_BYTE (buffer) - visible_beg,
+ visible_end - visible_beg,
+ BUF_ZV_BYTE (buffer) - visible_beg);
+ visible_end = BUF_ZV_BYTE (buffer);
+ }
+ /* 3. Make sure visible_beg = BUF_BEGV_BYTE. */
+ if (visible_beg < BUF_BEGV_BYTE (buffer))
+ {
+ /* Tree-sitter sees: delete at the beginning. */
+ ts_tree_edit_1 (tree, 0, BUF_BEGV_BYTE (buffer) - visible_beg, 0);
+ visible_beg = BUF_BEGV_BYTE (buffer);
+ }
+ XTS_PARSER (parser)->visible_beg = visible_beg;
+ XTS_PARSER (parser)->visible_end = visible_end;
+
TSTree *new_tree = ts_parser_parse(ts_parser, tree, input);
- /* This should be very rare: it only happens when 1) language is not
- set (impossible in Emacs because the user has to supply a
- language to create a parser), 2) parse canceled due to timeout
- (impossible because we don't set a timeout), 3) parse canceled
- due to cancellation flag (impossible because we don't set the
- flag). (See comments for ts_parser_parse in
+ /* This should be very rare (impossible, really): it only happens
+ when 1) language is not set (impossible in Emacs because the user
+ has to supply a language to create a parser), 2) parse canceled
+ due to timeout (impossible because we don't set a timeout), 3)
+ parse canceled due to cancellation flag (impossible because we
+ don't set the flag). (See comments for ts_parser_parse in
tree_sitter/api.h.) */
if (new_tree == NULL)
- signal_error ("Parse failed", parser);
+ {
+ Lisp_Object buf;
+ XSETBUFFER(buf, buffer);
+ xsignal1 (Qtree_sitter_parse_error, buf);
+ }
+
ts_tree_delete (tree);
XTS_PARSER (parser)->tree = new_tree;
XTS_PARSER (parser)->need_reparse = false;
@@ -110,13 +182,18 @@ ts_ensure_parsed (Lisp_Object parser)
}
/* This is the read function provided to tree-sitter to read from a
- buffer. It reads one character at a time and automatically skip
+ buffer. It reads one character at a time and automatically skips
the gap. */
const char*
-ts_read_buffer (void *buffer, uint32_t byte_index,
+ts_read_buffer (void *parser, uint32_t byte_index,
TSPoint position, uint32_t *bytes_read)
{
- ptrdiff_t byte_pos = byte_index + 1;
+ struct buffer *buffer = ((struct Lisp_TS_Parser *) parser)->buffer;
+ ptrdiff_t visible_beg = ((struct Lisp_TS_Parser *) parser)->visible_beg;
+ ptrdiff_t byte_pos = byte_index + visible_beg;
+ /* We will make sure visible_beg >= BUF_BEG_BYTE before re-parse (in
+ ts_ensure_parsed), so byte_pos will never be smaller than
+ BUF_BEG_BYTE (unless byte_index < 0). */
/* Read one character. Tree-sitter wants us to set bytes_read to 0
if it reads to the end of buffer. It doesn't say what it wants
@@ -126,26 +203,26 @@ ts_read_buffer (void *buffer, uint32_t byte_index,
int len;
/* This function could run from a user command, so it is better to
do nothing instead of raising an error. (It was a pain in the a**
- to read mega-if-conditions in Emacs source, so I write the two
- branches separately, hoping the compiler can merge them.) */
- if (!BUFFER_LIVE_P ((struct buffer *) buffer))
+ to decrypt mega-if-conditions in Emacs source, so I wrote the two
+ branches separately.) */
+ if (!BUFFER_LIVE_P (buffer))
{
beg = "";
len = 0;
}
- // TODO BUF_ZV_BYTE?
- else if (byte_pos >= BUF_Z_BYTE ((struct buffer *) buffer))
+ /* Reached visible end-of-buffer, tell tree-sitter to read no more. */
+ else if (byte_pos >= BUF_ZV_BYTE (buffer))
{
beg = "";
len = 0;
}
+ /* Normal case, read a character. */
else
{
beg = (char *) BUF_BYTE_ADDRESS (buffer, byte_pos);
- len = BYTES_BY_CHAR_HEAD ((int) beg);
+ len = BYTES_BY_CHAR_HEAD ((int) *beg);
}
*bytes_read = (uint32_t) len;
-
return beg;
}
@@ -158,13 +235,16 @@ make_ts_parser (struct buffer *buffer, TSParser *parser,
{
struct Lisp_TS_Parser *lisp_parser
= ALLOCATE_PSEUDOVECTOR (struct Lisp_TS_Parser, name, PVEC_TS_PARSER);
+
lisp_parser->name = name;
lisp_parser->buffer = buffer;
lisp_parser->parser = parser;
lisp_parser->tree = tree;
- TSInput input = {buffer, ts_read_buffer, TSInputEncodingUTF8};
+ TSInput input = {lisp_parser, ts_read_buffer, TSInputEncodingUTF8};
lisp_parser->input = input;
lisp_parser->need_reparse = true;
+ lisp_parser->visible_beg = BUF_BEGV (buffer);
+ lisp_parser->visible_end = BUF_ZV (buffer);
return make_lisp_ptr (lisp_parser, Lisp_Vectorlike);
}
@@ -287,7 +367,7 @@ DEFUN ("tree-sitter-parse-string",
/* See comment in ts_ensure_parsed for possible reasons for a
failure. */
if (tree == NULL)
- signal_error ("Failed to parse STRING", string);
+ xsignal1 (Qtree_sitter_parse_error, string);
TSNode root_node = ts_tree_root_node (tree);
@@ -535,7 +615,9 @@ DEFUN ("tree-sitter-node-first-child-for-byte",
{
CHECK_INTEGER (pos);
- struct buffer *buf = (XTS_PARSER (XTS_NODE (node)->parser)->buffer);
+ struct buffer *buf = XTS_PARSER (XTS_NODE (node)->parser)->buffer;
+ ptrdiff_t visible_beg =
+ XTS_PARSER (XTS_NODE (node)->parser)->visible_beg;
ptrdiff_t byte_pos = XFIXNUM (pos);
if (byte_pos < BUF_BEGV_BYTE (buf) || byte_pos > BUF_ZV_BYTE (buf))
@@ -544,9 +626,10 @@ DEFUN ("tree-sitter-node-first-child-for-byte",
TSNode ts_node = XTS_NODE (node)->node;
TSNode child;
if (NILP (named))
- child = ts_node_first_child_for_byte (ts_node, byte_pos - 1);
+ child = ts_node_first_child_for_byte (ts_node, byte_pos - visible_beg);
else
- child = ts_node_first_named_child_for_byte (ts_node, byte_pos - 1);
+ child = ts_node_first_named_child_for_byte
+ (ts_node, byte_pos - visible_beg);
if (ts_node_is_null(child))
return Qnil;
@@ -566,7 +649,9 @@ DEFUN ("tree-sitter-node-descendant-for-byte-range",
CHECK_INTEGER (beg);
CHECK_INTEGER (end);
- struct buffer *buf = (XTS_PARSER (XTS_NODE (node)->parser)->buffer);
+ struct buffer *buf = XTS_PARSER (XTS_NODE (node)->parser)->buffer;
+ ptrdiff_t visible_beg =
+ XTS_PARSER (XTS_NODE (node)->parser)->visible_beg;
ptrdiff_t byte_beg = XFIXNUM (beg);
ptrdiff_t byte_end = XFIXNUM (end);
@@ -580,10 +665,10 @@ DEFUN ("tree-sitter-node-descendant-for-byte-range",
TSNode child;
if (NILP (named))
child = ts_node_descendant_for_byte_range
- (ts_node, byte_beg - 1 , byte_end - 1);
+ (ts_node, byte_beg - visible_beg , byte_end - visible_beg);
else
child = ts_node_named_descendant_for_byte_range
- (ts_node, byte_beg - 1, byte_end - 1);
+ (ts_node, byte_beg - visible_beg, byte_end - visible_beg);
if (ts_node_is_null(child))
return Qnil;
@@ -593,31 +678,24 @@ DEFUN ("tree-sitter-node-descendant-for-byte-range",
/* Query functions */
-Lisp_Object ts_query_error_to_string (TSQueryError error)
+char*
+ts_query_error_to_string (TSQueryError error)
{
- char *error_name;
switch (error)
{
case TSQueryErrorNone:
- error_name = "none";
- break;
+ return "none";
case TSQueryErrorSyntax:
- error_name = "syntax";
- break;
+ return "syntax";
case TSQueryErrorNodeType:
- error_name = "node type";
- break;
+ return "node type";
case TSQueryErrorField:
- error_name = "field";
- break;
+ return "field";
case TSQueryErrorCapture:
- error_name = "capture";
- break;
+ return "capture";
case TSQueryErrorStructure:
- error_name = "structure";
- break;
+ return "structure";
}
- return make_pure_c_string (error_name, strlen(error_name));
}
DEFUN ("tree-sitter-query-capture",
@@ -634,7 +712,7 @@ DEFUN ("tree-sitter-query-capture",
BEG and END, if _both_ non-nil, specifies the range in which the query
is executed.
-Return nil if the query failed. */)
+Raise an tree-sitter-query-error if PATTERN is malformed. */)
(Lisp_Object node, Lisp_Object pattern,
Lisp_Object beg, Lisp_Object end)
{
@@ -643,47 +721,56 @@ DEFUN ("tree-sitter-query-capture",
TSNode ts_node = XTS_NODE (node)->node;
Lisp_Object lisp_parser = XTS_NODE (node)->parser;
+ ptrdiff_t visible_beg =
+ XTS_PARSER (XTS_NODE (node)->parser)->visible_beg;
const TSLanguage *lang = ts_parser_language
(XTS_PARSER (lisp_parser)->parser);
char *source = SSDATA (pattern);
+
uint32_t error_offset;
- uint32_t error_type;
+ TSQueryError error_type;
TSQuery *query = ts_query_new (lang, source, strlen (source),
&error_offset, &error_type);
TSQueryCursor *cursor = ts_query_cursor_new ();
if (query == NULL)
{
- // FIXME: Signal an error?
- return Qnil;
+ // FIXME: Still crashes, debug when I can get a gdb.
+ xsignal2 (Qtree_sitter_query_error,
+ make_fixnum (error_offset),
+ build_string (ts_query_error_to_string (error_type)));
}
if (!NILP (beg) && !NILP (end))
{
EMACS_INT beg_byte = XFIXNUM (beg);
EMACS_INT end_byte = XFIXNUM (end);
ts_query_cursor_set_byte_range
- (cursor, (uint32_t) beg_byte - 1, (uint32_t) end_byte - 1);
+ (cursor, (uint32_t) beg_byte - visible_beg,
+ (uint32_t) end_byte - visible_beg);
}
ts_query_cursor_exec (cursor, query, ts_node);
TSQueryMatch match;
- TSQueryCapture capture;
+
Lisp_Object result = Qnil;
- Lisp_Object entry;
- Lisp_Object captured_node;
- const char *capture_name;
- uint32_t capture_name_len;
while (ts_query_cursor_next_match (cursor, &match))
{
const TSQueryCapture *captures = match.captures;
for (int idx=0; idx < match.capture_count; idx++)
{
+ TSQueryCapture capture;
+ Lisp_Object captured_node;
+ const char *capture_name;
+ Lisp_Object entry;
+ uint32_t capture_name_len;
+
capture = captures[idx];
captured_node = make_ts_node(lisp_parser, capture.node);
capture_name = ts_query_capture_name_for_id
(query, capture.index, &capture_name_len);
- entry = Fcons (intern_c_string (capture_name),
+ entry = Fcons (intern_c_string_1
+ (capture_name, capture_name_len),
captured_node);
result = Fcons (entry, result);
}
@@ -705,11 +792,15 @@ syms_of_tree_sitter (void)
DEFSYM (Qhas_changes, "has-changes");
DEFSYM (Qhas_error, "has-error");
+ DEFSYM(Qtree_sitter_error, "tree-sitter-error");
DEFSYM (Qtree_sitter_query_error, "tree-sitter-query-error");
- Fput (Qtree_sitter_query_error, Qerror_conditions,
- pure_list (Qtree_sitter_query_error, Qerror));
- Fput (Qtree_sitter_query_error, Qerror_message,
- build_pure_c_string ("Error with query pattern"))
+ DEFSYM (Qtree_sitter_parse_error, "tree-sitter-parse-error")
+ define_error (Qtree_sitter_error, "Generic tree-sitter error", Qerror);
+ define_error (Qtree_sitter_query_error, "Query pattern is malformed",
+ Qtree_sitter_error);
+ define_error (Qtree_sitter_parse_error, "Parse failed",
+ Qtree_sitter_error);
+
DEFSYM (Qtree_sitter_parser_list, "tree-sitter-parser-list");
DEFVAR_LISP ("tree-sitter-parser-list", Vtree_sitter_parser_list,
diff --git a/src/tree_sitter.h b/src/tree_sitter.h
index e9b4a71326..7e0fec0ee9 100644
--- a/src/tree_sitter.h
+++ b/src/tree_sitter.h
@@ -20,8 +20,6 @@ Copyright (C) 2021 Free Software Foundation, Inc.
#ifndef EMACS_TREE_SITTER_H
#define EMACS_TREE_SITTER_H
-#include <sys/types.h>
-
#include "lisp.h"
#include <tree_sitter/api.h>
@@ -33,12 +31,25 @@ #define EMACS_TREE_SITTER_H
struct Lisp_TS_Parser
{
union vectorlike_header header;
+ /* A parser's name is just a convenient tag, see docstring for
+ 'tree-sitter-make-parser', and 'tree-sitter-get-parser'. */
Lisp_Object name;
struct buffer *buffer;
TSParser *parser;
TSTree *tree;
TSInput input;
+ /* Re-parsing an unchanged buffer is not free for tree-sitter, so we
+ only make it re-parse when need_reparse == true. That usually
+ means some change is made in the buffer. But others could set
+ this field to true to force tree-sitter to re-parse. */
bool need_reparse;
+ /* This two positions record the byte position of the "visible
+ region" that tree-sitter sees. Unlike markers, These two
+ positions do not change as the user inserts and deletes text
+ around them. Before re-parse, we move these positions to match
+ BUF_BEGV_BYTE and BUF_ZV_BYTE. */
+ ptrdiff_t visible_beg;
+ ptrdiff_t visible_end;
};
/* A wrapper around a tree-sitter node. */
diff --git a/test/src/tree-sitter-tests.el b/test/src/tree-sitter-tests.el
index c61ad678d2..69104568de 100644
--- a/test/src/tree-sitter-tests.el
+++ b/test/src/tree-sitter-tests.el
@@ -148,5 +148,58 @@ tree-sitter-query-api
(cdr entry))))
(tree-sitter-query-capture root-node pattern)))))))
+(ert-deftest tree-sitter-narrow ()
+ "Tests if narrowing works."
+ (with-temp-buffer
+ (let (parser root-node pattern doc-node object-node pair-node)
+ (progn
+ (insert "xxx[1,{\"name\": \"Bob\"},2,3]xxx")
+ (narrow-to-region (+ (point-min) 3) (- (point-max) 3))
+ (setq parser (tree-sitter-create-parser
+ (current-buffer) (tree-sitter-json)))
+ (setq root-node (tree-sitter-parser-root-node
+ parser)))
+ ;; This test is from the basic test.
+ (should
+ (equal
+ (tree-sitter-node-string
+ (tree-sitter-parser-root-node parser))
+ "(document (array (number) (object (pair key: (string (string_content)) value: (string (string_content)))) (number) (number)))"))
+
+ (widen)
+ (goto-char (point-min))
+ (insert "ooo")
+ (should (equal "oooxxx[1,{\"name\": \"Bob\"},2,3]xxx"
+ (buffer-string)))
+ (delete-region 10 26)
+ (should (equal "oooxxx[1,2,3]xxx"
+ (buffer-string)))
+ (narrow-to-region (+ (point-min) 6) (- (point-max) 3))
+ ;; This test is also from the basic test.
+ (should
+ (equal (tree-sitter-node-string
+ (tree-sitter-parser-root-node parser))
+ "(document (array (number) (number) (number)))"))
+ (widen)
+ (goto-char (point-max))
+ (insert "[1,2]")
+ (should (equal "oooxxx[1,2,3]xxx[1,2]"
+ (buffer-string)))
+ (narrow-to-region (- (point-max) 5) (point-max))
+ (should
+ (equal (tree-sitter-node-string
+ (tree-sitter-parser-root-node parser))
+ "(document (array (number) (number)))"))
+ (widen)
+ (goto-char (point-min))
+ (insert "[1]")
+ (should (equal "[1]oooxxx[1,2,3]xxx[1,2]"
+ (buffer-string)))
+ (narrow-to-region (point-min) (+ (point-min) 3))
+ (should
+ (equal (tree-sitter-node-string
+ (tree-sitter-parser-root-node parser))
+ "(document (array (number)))")))))
+
(provide 'tree-sitter-tests)
;;; tree-sitter-tests.el ends here
--
2.24.3 (Apple Git-128)
next prev parent reply other threads:[~2021-07-29 14:35 UTC|newest]
Thread overview: 370+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-07-14 17:37 How to add pseudo vector types Yuan Fu
2021-07-14 17:44 ` Eli Zaretskii
2021-07-14 17:47 ` Stefan Monnier
2021-07-14 23:48 ` Yuan Fu
2021-07-15 0:26 ` Yuan Fu
2021-07-15 2:48 ` Yuan Fu
2021-07-15 6:39 ` Eli Zaretskii
2021-07-15 13:37 ` Fu Yuan
2021-07-15 14:18 ` Eli Zaretskii
2021-07-15 15:17 ` Yuan Fu
2021-07-15 15:50 ` Eli Zaretskii
2021-07-15 16:19 ` Yuan Fu
2021-07-15 16:26 ` Yuan Fu
2021-07-15 16:50 ` Eli Zaretskii
2021-07-15 16:48 ` Eli Zaretskii
2021-07-15 18:23 ` Yuan Fu
2021-07-16 7:30 ` Eli Zaretskii
2021-07-16 14:27 ` Yuan Fu
2021-07-16 14:33 ` Stefan Monnier
2021-07-16 14:53 ` Yuan Fu
2021-07-16 15:27 ` Eli Zaretskii
2021-07-16 15:51 ` Yuan Fu
2021-07-17 2:05 ` Yuan Fu
2021-07-17 2:23 ` Clément Pit-Claudel
2021-07-17 3:12 ` Yuan Fu
2021-07-17 7:18 ` Eli Zaretskii
2021-07-17 7:16 ` Eli Zaretskii
2021-07-20 20:36 ` Clément Pit-Claudel
2021-07-21 11:26 ` Eli Zaretskii
2021-07-21 13:38 ` Clément Pit-Claudel
2021-07-21 13:51 ` Eli Zaretskii
2021-07-22 4:59 ` Clément Pit-Claudel
2021-07-22 6:38 ` Eli Zaretskii
2021-07-21 16:29 ` Stephen Leake
2021-07-21 16:54 ` Clément Pit-Claudel
2021-07-21 19:43 ` Eli Zaretskii
2021-07-24 2:57 ` Stephen Leake
2021-07-24 3:39 ` Óscar Fuentes
2021-07-24 7:34 ` Eli Zaretskii
2021-07-25 16:49 ` Stephen Leake
2021-07-24 7:06 ` Eli Zaretskii
2021-07-25 17:48 ` Stephen Leake
2021-07-24 3:55 ` Clément Pit-Claudel
2021-07-21 21:54 ` Stephen Leake
2021-07-22 4:40 ` Clément Pit-Claudel
2021-07-17 17:30 ` Stefan Monnier
2021-07-17 17:54 ` Eli Zaretskii
2021-07-24 14:08 ` Stefan Monnier
2021-07-24 14:32 ` Eli Zaretskii
2021-07-24 15:10 ` Stefan Monnier
2021-07-24 15:51 ` Eli Zaretskii
2021-07-19 15:16 ` Yuan Fu
2021-07-22 3:10 ` Yuan Fu
2021-07-22 8:23 ` Eli Zaretskii
2021-07-22 13:47 ` Yuan Fu
2021-07-22 14:11 ` Óscar Fuentes
2021-07-22 17:09 ` Eli Zaretskii
2021-07-22 19:29 ` Óscar Fuentes
2021-07-23 5:21 ` Eli Zaretskii
2021-07-24 9:38 ` Stephen Leake
2021-07-22 17:00 ` Eli Zaretskii
2021-07-22 17:47 ` Yuan Fu
2021-07-22 19:05 ` Eli Zaretskii
2021-07-23 13:25 ` Yuan Fu
2021-07-23 19:10 ` Eli Zaretskii
2021-07-23 20:01 ` Perry E. Metzger
2021-07-24 5:52 ` Eli Zaretskii
2021-07-23 20:22 ` Yuan Fu
2021-07-24 6:00 ` Eli Zaretskii
2021-07-25 18:01 ` Stephen Leake
2021-07-25 19:09 ` Eli Zaretskii
2021-07-26 5:10 ` Stephen Leake
2021-07-26 12:56 ` Eli Zaretskii
2021-07-24 15:04 ` Yuan Fu
2021-07-24 15:48 ` Eli Zaretskii
2021-07-24 17:14 ` Yuan Fu
2021-07-24 17:20 ` Eli Zaretskii
2021-07-24 17:40 ` Yuan Fu
2021-07-24 17:46 ` Eli Zaretskii
2021-07-24 18:06 ` Yuan Fu
2021-07-24 18:21 ` Eli Zaretskii
2021-07-24 18:55 ` Stefan Monnier
2021-07-25 18:44 ` Stephen Leake
2021-07-26 14:38 ` Perry E. Metzger
2021-07-24 16:14 ` Eli Zaretskii
2021-07-24 17:32 ` Yuan Fu
2021-07-24 17:42 ` Eli Zaretskii
2021-07-23 14:07 ` Stefan Monnier
2021-07-23 14:45 ` Yuan Fu
2021-07-23 19:13 ` Eli Zaretskii
2021-07-23 20:28 ` Stefan Monnier
2021-07-24 6:02 ` Eli Zaretskii
2021-07-24 14:19 ` Stefan Monnier
2021-07-24 9:42 ` Stephen Leake
2021-07-24 11:22 ` Eli Zaretskii
2021-07-25 18:21 ` Stephen Leake
2021-07-25 19:03 ` Eli Zaretskii
2021-07-26 16:40 ` Yuan Fu
2021-07-26 16:49 ` Eli Zaretskii
2021-07-26 17:09 ` Yuan Fu
2021-07-26 18:55 ` Eli Zaretskii
2021-07-26 19:06 ` Yuan Fu
2021-07-26 19:19 ` Perry E. Metzger
2021-07-26 19:31 ` Eli Zaretskii
2021-07-26 19:20 ` Eli Zaretskii
2021-07-26 19:45 ` Yuan Fu
2021-07-26 19:57 ` Dmitry Gutov
2021-07-27 6:13 ` Stephen Leake
2021-07-27 14:56 ` Yuan Fu
2021-07-28 3:40 ` Stephen Leake
2021-07-28 16:36 ` Yuan Fu
2021-07-28 16:41 ` Eli Zaretskii
2021-07-29 22:58 ` Stephen Leake
2021-07-30 6:00 ` Eli Zaretskii
2021-07-28 16:43 ` Eli Zaretskii
2021-07-28 17:47 ` Yuan Fu
2021-07-28 17:54 ` Eli Zaretskii
2021-07-28 18:46 ` Yuan Fu
2021-07-28 19:00 ` Eli Zaretskii
2021-07-29 14:35 ` Yuan Fu [this message]
2021-07-29 15:28 ` Eli Zaretskii
2021-07-29 15:57 ` Yuan Fu
2021-07-29 16:21 ` Eli Zaretskii
2021-07-29 16:59 ` Yuan Fu
2021-07-29 17:38 ` Eli Zaretskii
2021-07-29 17:55 ` Yuan Fu
2021-07-29 18:37 ` Eli Zaretskii
2021-07-29 18:57 ` Yuan Fu
2021-07-30 6:47 ` Eli Zaretskii
2021-07-30 14:17 ` Yuan Fu
2021-08-03 10:24 ` Fu Yuan
2021-08-03 11:42 ` Eli Zaretskii
2021-08-03 11:53 ` Fu Yuan
2021-08-03 12:21 ` Eli Zaretskii
2021-08-03 12:50 ` Fu Yuan
2021-08-03 13:03 ` Eli Zaretskii
2021-08-03 13:08 ` Fu Yuan
2021-08-03 11:47 ` Eli Zaretskii
2021-08-03 12:00 ` Fu Yuan
2021-08-03 12:24 ` Eli Zaretskii
2021-08-03 13:00 ` Fu Yuan
2021-08-03 13:28 ` Stefan Monnier
2021-08-03 13:34 ` Eli Zaretskii
2021-08-06 3:22 ` Yuan Fu
2021-08-06 6:37 ` Eli Zaretskii
2021-08-07 5:31 ` Tree-sitter api (Was: Re: How to add pseudo vector types) Fu Yuan
2021-08-07 6:26 ` Eli Zaretskii
2021-08-07 15:47 ` Tree-sitter api Stefan Monnier
2021-08-07 18:40 ` Theodor Thornhill
2021-08-07 19:53 ` Stefan Monnier
2021-08-17 6:18 ` Yuan Fu
2021-08-18 18:27 ` Stephen Leake
2021-08-18 21:30 ` Yuan Fu
2021-08-20 0:12 ` [SPAM UNSURE] " Stephen Leake
2021-08-23 6:51 ` Yuan Fu
2021-08-24 14:59 ` [SPAM UNSURE] " Stephen Leake
2021-08-27 5:18 ` [SPAM UNSURE] " Yuan Fu
2021-08-31 0:48 ` Stephen Leake
2021-08-24 22:51 ` Stefan Monnier
2021-08-22 2:43 ` Yuan Fu
2021-08-22 3:46 ` Yuan Fu
2021-08-22 6:16 ` Eli Zaretskii
2021-08-22 6:15 ` Eli Zaretskii
2021-08-25 0:21 ` Stefan Monnier
2021-08-27 5:45 ` Yuan Fu
2021-09-03 19:16 ` Theodor Thornhill
[not found] ` <AF64EB2C-CCEC-4C98-8FE3-37697BEC9098@gmail.com>
2021-09-04 12:49 ` Tuấn-Anh Nguyễn
2021-09-04 13:04 ` Eli Zaretskii
2021-09-04 14:49 ` Tuấn-Anh Nguyễn
2021-09-04 15:00 ` Eli Zaretskii
2021-09-05 16:34 ` Tuấn-Anh Nguyễn
2021-09-05 16:45 ` Eli Zaretskii
2021-09-04 15:31 ` Yuan Fu
2021-09-05 16:45 ` Tuấn-Anh Nguyễn
2021-09-05 20:19 ` Yuan Fu
2021-09-06 0:03 ` Tuấn-Anh Nguyễn
2021-09-06 0:23 ` Yuan Fu
2021-09-06 5:33 ` Eli Zaretskii
2021-09-07 15:38 ` Tuấn-Anh Nguyễn
2021-09-07 16:16 ` Eli Zaretskii
2021-09-08 3:06 ` Yuan Fu
2021-09-10 2:06 ` Yuan Fu
2021-09-10 6:32 ` Eli Zaretskii
2021-09-10 19:57 ` Yuan Fu
2021-09-11 3:41 ` Tuấn-Anh Nguyễn
2021-09-11 4:11 ` Yuan Fu
2021-09-11 7:23 ` Tuấn-Anh Nguyễn
2021-09-11 19:02 ` Yuan Fu
2021-09-11 5:51 ` Eli Zaretskii
2021-09-11 19:00 ` Yuan Fu
2021-09-11 19:14 ` Eli Zaretskii
2021-09-11 19:17 ` Eli Zaretskii
2021-09-11 20:29 ` Yuan Fu
2021-09-12 5:39 ` Eli Zaretskii
2021-09-13 4:15 ` Yuan Fu
2021-09-13 11:47 ` Eli Zaretskii
2021-09-13 18:01 ` Yuan Fu
2021-09-13 18:07 ` Eli Zaretskii
2021-09-13 18:29 ` Yuan Fu
2021-09-13 18:37 ` Eli Zaretskii
2021-09-14 0:13 ` Yuan Fu
2021-09-14 2:29 ` Eli Zaretskii
2021-09-14 4:27 ` Yuan Fu
2021-09-14 11:29 ` Eli Zaretskii
2021-09-15 0:50 ` Yuan Fu
2021-09-15 6:15 ` Eli Zaretskii
2021-09-15 15:56 ` Yuan Fu
2021-09-15 16:02 ` Eli Zaretskii
2021-09-15 18:19 ` Stefan Monnier
2021-09-15 18:48 ` Eli Zaretskii
2021-09-16 21:46 ` Yuan Fu
2021-09-17 6:06 ` Eli Zaretskii
2021-09-17 6:56 ` Yuan Fu
2021-09-17 7:38 ` Eli Zaretskii
2021-09-17 20:30 ` Yuan Fu
2021-09-18 2:22 ` Tuấn-Anh Nguyễn
2021-09-18 6:38 ` Yuan Fu
2021-09-18 12:33 ` Stephen Leake
2021-09-20 16:48 ` Yuan Fu
2021-09-20 18:48 ` Eli Zaretskii
2021-09-20 19:09 ` John Yates
2021-09-21 22:20 ` Yuan Fu
2021-09-27 4:42 ` Yuan Fu
2021-09-27 5:37 ` Eli Zaretskii
2021-09-27 19:17 ` Stefan Monnier
2021-09-28 5:33 ` Yuan Fu
2021-09-28 7:02 ` Eli Zaretskii
2021-09-28 16:10 ` Yuan Fu
2021-09-28 16:28 ` Eli Zaretskii
2021-12-13 6:54 ` Yuan Fu
2021-12-13 12:56 ` Eli Zaretskii
2021-12-14 7:19 ` Yuan Fu
2021-12-17 0:14 ` Yuan Fu
2021-12-17 7:15 ` Eli Zaretskii
2021-12-18 14:45 ` Philipp
2021-12-18 14:57 ` Eli Zaretskii
2021-12-19 2:51 ` Yuan Fu
2021-12-19 7:11 ` Eli Zaretskii
2021-12-19 7:52 ` Yuan Fu
2021-12-24 10:04 ` Yoav Marco
2021-12-24 10:21 ` Yoav Marco
2021-12-25 8:31 ` Yuan Fu
2021-12-25 10:13 ` Eli Zaretskii
2021-12-26 9:50 ` Yuan Fu
2021-12-26 10:23 ` Eli Zaretskii
2021-12-30 0:59 ` Yuan Fu
2021-12-30 6:35 ` Eli Zaretskii
2022-01-04 18:31 ` Yuan Fu
2022-03-13 6:22 ` Yuan Fu
2022-03-13 6:25 ` Yuan Fu
2022-03-13 7:13 ` Po Lu
2022-03-14 0:23 ` Yuan Fu
2022-03-14 1:10 ` Po Lu
2022-03-14 3:31 ` Eli Zaretskii
2022-03-14 3:43 ` Yuan Fu
2022-03-29 16:40 ` Eli Zaretskii
2022-03-30 0:35 ` Po Lu
2022-03-30 0:49 ` Yuan Fu
2022-03-30 0:51 ` Yuan Fu
2022-03-30 2:13 ` Po Lu
2022-03-30 3:01 ` Yuan Fu
2022-03-30 3:10 ` Vitaly Ankh
2022-03-30 3:24 ` Yuan Fu
2022-03-30 3:39 ` Po Lu
2022-03-30 4:29 ` Yuan Fu
2022-03-30 5:19 ` Phil Sainty
2022-03-30 5:39 ` Phil Sainty
2022-03-30 13:46 ` João Távora
2022-03-30 2:31 ` Eli Zaretskii
2022-03-30 2:59 ` Yuan Fu
2022-03-30 9:04 ` Lars Ingebrigtsen
2022-03-30 11:48 ` Daniel Martín
2022-03-30 15:00 ` [External] : " Drew Adams
2022-03-31 4:27 ` Richard Stallman
2022-03-31 5:36 ` Eli Zaretskii
2022-03-31 11:13 ` Lars Ingebrigtsen
2022-03-31 12:46 ` John Yates
2022-03-31 17:37 ` Phil Sainty
2022-04-01 1:56 ` Po Lu
2022-04-01 6:36 ` Eli Zaretskii
2022-04-01 7:56 ` Po Lu
2022-04-01 10:45 ` Eli Zaretskii
2022-03-31 17:58 ` Stefan Monnier
2022-04-04 10:29 ` Jostein Kjønigsen
2022-03-31 16:23 ` [External] : " Drew Adams
2022-03-31 19:33 ` Filipp Gunbin
2022-03-31 16:35 ` Yuan Fu
2022-03-31 23:00 ` Yuan Fu
2022-03-31 23:53 ` Yuan Fu
2022-04-01 6:20 ` Eli Zaretskii
2022-04-01 16:48 ` Yuan Fu
2022-04-01 17:59 ` Eli Zaretskii
2022-04-02 6:26 ` Yuan Fu
2022-04-04 7:38 ` Robert Pluim
2022-04-04 20:41 ` Yuan Fu
2022-04-20 20:14 ` Theodor Thornhill
2022-04-21 1:36 ` Yuan Fu
2022-04-21 5:48 ` Eli Zaretskii
2022-04-21 11:37 ` Lars Ingebrigtsen
2022-04-21 12:10 ` Theodor Thornhill
2022-04-22 2:54 ` Yuan Fu
2022-04-22 4:58 ` Theodor Thornhill
2022-04-22 7:08 ` Yuan Fu
2022-04-22 8:02 ` Theodor Thornhill
2022-04-22 11:41 ` Theodor Thornhill
2021-12-18 13:39 ` Daniel Martín
2021-12-19 2:48 ` Yuan Fu
2021-09-17 12:11 ` Tuấn-Anh Nguyễn
2021-09-17 13:14 ` Stefan Monnier
2021-09-17 13:39 ` Tuấn-Anh Nguyễn
2021-09-17 17:18 ` Stefan Monnier
2021-09-18 2:16 ` Tuấn-Anh Nguyễn
2021-09-17 12:23 ` Stefan Monnier
2021-09-17 13:03 ` Tuấn-Anh Nguyễn
2021-09-04 15:14 ` Tuấn-Anh Nguyễn
2021-09-04 15:33 ` Eli Zaretskii
2021-09-05 16:48 ` Tuấn-Anh Nguyễn
2021-09-04 15:39 ` Yuan Fu
2021-09-05 21:15 ` Theodor Thornhill
2021-09-05 23:58 ` Yuan Fu
2021-08-08 22:56 ` Yuan Fu
2021-08-08 23:24 ` Stefan Monnier
2021-08-09 0:06 ` Yuan Fu
2021-07-29 23:06 ` How to add pseudo vector types Stephen Leake
2021-07-30 0:35 ` Richard Stallman
2021-07-30 0:46 ` Alexandre Garreau
2021-07-30 6:35 ` Eli Zaretskii
2021-07-29 23:01 ` Stephen Leake
2021-07-26 18:32 ` chad
2021-07-26 18:44 ` Perry E. Metzger
2021-07-26 19:13 ` Eli Zaretskii
2021-07-26 19:09 ` Eli Zaretskii
2021-07-26 19:48 ` chad
2021-07-26 20:05 ` Óscar Fuentes
2021-07-26 21:30 ` Clément Pit-Claudel
2021-07-26 21:46 ` Óscar Fuentes
2021-07-27 14:02 ` Eli Zaretskii
2021-07-27 13:59 ` Eli Zaretskii
2021-07-26 23:40 ` Ergus
2021-07-27 14:49 ` Yuan Fu
2021-07-27 16:50 ` Ergus
2021-07-27 16:59 ` Eli Zaretskii
2021-07-28 3:45 ` Stephen Leake
2021-07-24 9:33 ` Stephen Leake
2021-07-24 22:54 ` Dmitry Gutov
2021-07-20 16:32 ` Stephen Leake
2021-07-20 16:48 ` Eli Zaretskii
2021-07-20 17:38 ` Stefan Monnier
2021-07-20 17:36 ` Stefan Monnier
2021-07-20 18:05 ` Clément Pit-Claudel
2021-07-21 16:02 ` Stephen Leake
2021-07-21 17:16 ` Stefan Monnier
2021-07-20 18:04 ` Clément Pit-Claudel
2021-07-20 18:24 ` Eli Zaretskii
2021-07-21 16:54 ` [SPAM UNSURE] " Stephen Leake
2021-07-21 17:12 ` Clément Pit-Claudel
2021-07-21 19:49 ` Eli Zaretskii
2021-07-22 5:09 ` Clément Pit-Claudel
2021-07-22 6:44 ` Eli Zaretskii
2021-07-22 14:43 ` Clément Pit-Claudel
2021-07-17 6:56 ` Eli Zaretskii
2021-07-20 16:28 ` Stephen Leake
2021-07-20 16:27 ` Stephen Leake
2021-07-20 16:25 ` Stephen Leake
2021-07-20 16:45 ` Eli Zaretskii
2021-07-21 15:49 ` Stephen Leake
2021-07-21 19:37 ` Eli Zaretskii
2021-07-24 2:00 ` Stephen Leake
2021-07-24 6:51 ` Eli Zaretskii
2021-07-25 16:16 ` Stephen Leake
[not found] <casouri/emacs/issues/5@github.com>
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=E0D4E307-E5FE-4791-A3D5-8DA80CAF0AB7@gmail.com \
--to=casouri@gmail.com \
--cc=cpitclaudel@gmail.com \
--cc=eliz@gnu.org \
--cc=emacs-devel@gnu.org \
--cc=monnier@iro.umontreal.ca \
--cc=stephen_leake@stephe-leake.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).