From: john muhl via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
To: Andrey Listopadov <andreyorst@gmail.com>
Cc: 66159@debbugs.gnu.org, Eli Zaretskii <eliz@gnu.org>
Subject: bug#66159: 30.0.50; lua-ts-mode semantic indentation problems
Date: Tue, 03 Oct 2023 10:04:56 -0500 [thread overview]
Message-ID: <87ttr73fuz.fsf@pub.pink> (raw)
In-Reply-To: <874jj847dr.fsf@pub.pink>
[-- Attachment #1: Type: text/plain, Size: 92 bytes --]
Whoops. Looks like I forgot to update the patch before sending. This one
should be better.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Various-improvements-in-lus-ts-mode-Bug-66159.patch --]
[-- Type: text/x-patch, Size: 18788 bytes --]
From 4ee42d82557e188537693c3a27b2246ed690c2a6 Mon Sep 17 00:00:00 2001
From: john muhl <jm@pub.pink>
Date: Sat, 23 Sep 2023 10:49:11 -0500
Subject: [PATCH] Various improvements in lus-ts-mode (Bug#66159)
* lisp/progmodes/lua-ts-mode.el (lua-ts--first-child)
(lua-ts--end-indent-offset)
(lua-ts--simple-indent-rules): Improve indentation.
(lua-ts-inferior--write-history)
(lua-ts-inferior-lua): Improve inferior Lua interaction.
(lua-ts-mode-map): Add keymap.
(lua-ts-mode-menu): Add menu.
(lua-ts-mode): Add mode map and improve sexp navigation.
(lua-ts-send-buffer)
(lua-ts-send-file)
(lua-ts-send-line)
(lua-ts-send-region)
(lua-ts-show-process-buffer)
(lua-ts-hide-process-buffer)
(lua-ts-kill-process): New functions.
(lua-ts-mode-hook)
(lua-ts-inferior-prompt-regexp)
(lua-ts-inferior-prompt)
(lua-ts-inferior-prompt-continue)
(lua-ts-inferior-history): New variables.
---
lisp/progmodes/lua-ts-mode.el | 210 ++++++++++++++++--
.../lua-ts-mode-resources/indent.erts | 199 +++++++++++++++++
.../lua-ts-mode-resources/movement.erts | 56 +++++
3 files changed, 441 insertions(+), 24 deletions(-)
diff --git a/lisp/progmodes/lua-ts-mode.el b/lisp/progmodes/lua-ts-mode.el
index 030a3585158..d1930d9f2b1 100644
--- a/lisp/progmodes/lua-ts-mode.el
+++ b/lisp/progmodes/lua-ts-mode.el
@@ -39,7 +39,9 @@
(require 'rx))
(declare-function treesit-node-child-by-field-name "treesit.c")
+(declare-function treesit-node-first-child-for-pos "treesit.c")
(declare-function treesit-node-type "treesit.c")
+(declare-function treesit-node-start "treesit.c")
(declare-function treesit-parser-create "treesit.c")
(declare-function treesit-search-subtree "treesit.c")
@@ -48,6 +50,15 @@ lua-ts
:prefix "lua-ts-"
:group 'languages)
+(defcustom lua-ts-mode-hook nil
+ "Hook run after entering `lua-ts-mode'."
+ :type 'hook
+ :options '(flymake-mode
+ hs-minor-mode
+ outline-minor-mode)
+ :group 'lua-ts
+ :version "30.1")
+
(defcustom lua-ts-indent-offset 4
"Number of spaces for each indentation step in `lua-ts-mode'."
:type 'natnum
@@ -86,9 +97,22 @@ lua-ts-inferior-startfile
:group 'lua-ts
:version "30.1")
-(defcustom lua-ts-inferior-prompt-regexp "^>>?[[:blank:]]"
- "Regular expression matching the prompt of the inferior Lua process."
- :type 'regexp
+(defcustom lua-ts-inferior-prompt ">"
+ "The prompt of the inferior Lua process."
+ :type 'string
+ :group 'lua-ts
+ :version "30.1")
+
+(defcustom lua-ts-inferior-prompt-continue ">>"
+ "The continuation prompt of the inferior Lua process."
+ :type 'string
+ :group 'lua-ts
+ :version "30.1")
+
+(defcustom lua-ts-inferior-history nil
+ "File used to save command history of the inferior Lua process."
+ :type '(choice (const nil) file)
+ :safe 'string-or-null-p
:group 'lua-ts
:version "30.1")
@@ -233,27 +257,65 @@ lua-ts--font-lock-settings
'((ERROR) @font-lock-warning-face))
"Tree-sitter font-lock settings for `lua-ts-mode'.")
+(defun lua-ts--first-child (node _p _b &rest _)
+ "Matches if NODE is the first among its siblings."
+ (= (treesit-node-index node) 1))
+
+(defun lua-ts--end-indent-offset (_n _p _b &rest _)
+ "Calculate indent offset based on `end' count."
+ (let* ((beg (line-beginning-position))
+ (end (line-end-position))
+ (count (count-matches "end" beg end)))
+ (- (* (1- count) lua-ts-indent-offset))))
+
(defvar lua-ts--simple-indent-rules
`((lua
+ ((n-p-gp "end" "function_definition" "arguments")
+ parent 0)
+ ((n-p-gp "end" "function_definition" "parenthesized_expression")
+ parent 0)
+ ((and (n-p-gp "block" "function_definition" "arguments")
+ (lambda (_n parent &rest _)
+ (save-excursion
+ (goto-char (treesit-node-start parent))
+ (backward-char 2)
+ (not (looking-at ")")))))
+ parent lua-ts-indent-offset)
+ ((and (n-p-gp "block" "function_definition" "parenthesized_expression")
+ (lambda (node _p bol &rest _)
+ (equal "assignment_statement"
+ (treesit-node-type
+ (treesit-node-first-child-for-pos node bol)))))
+ parent lua-ts-indent-offset)
((parent-is "chunk") column-0 0)
((node-is "comment_end") column-0 0)
((parent-is "block") parent-bol 0)
((node-is "}") parent-bol 0)
((node-is ")") parent-bol 0)
+ ((node-is "do") standalone-parent 0)
+ ((node-is "then") standalone-parent 0)
((node-is "else_statement") parent-bol 0)
((node-is "elseif_statement") parent-bol 0)
- ((node-is "end") parent-bol 0)
+ ((node-is "end") parent-bol lua-ts--end-indent-offset)
((node-is "until") parent-bol 0)
((parent-is "for_statement") parent-bol lua-ts-indent-offset)
((parent-is "function_declaration") parent-bol lua-ts-indent-offset)
- ((parent-is "function_definition") parent-bol lua-ts-indent-offset)
+ ((parent-is "function_definition") standalone-parent lua-ts-indent-offset)
+ ((parent-is "parenthesized_expression")
+ standalone-parent lua-ts-indent-offset)
((parent-is "if_statement") parent-bol lua-ts-indent-offset)
((parent-is "else_statement") parent-bol lua-ts-indent-offset)
((parent-is "repeat_statement") parent-bol lua-ts-indent-offset)
((parent-is "while_statement") parent-bol lua-ts-indent-offset)
- ((parent-is "table_constructor") parent-bol lua-ts-indent-offset)
- ((parent-is "arguments") parent-bol lua-ts-indent-offset)
- ((parent-is "parameters") parent-bol lua-ts-indent-offset)
+ ((and (parent-is "table_constructor") lua-ts--first-child)
+ parent-bol lua-ts-indent-offset)
+ ((parent-is "table_constructor") (nth-sibling 1) 0)
+ ((and (parent-is "arguments") lua-ts--first-child)
+ parent-bol lua-ts-indent-offset)
+ ((parent-is "arguments") (nth-sibling 1) 0)
+ ((and (parent-is "parameters") lua-ts--first-child)
+ parent-bol lua-ts-indent-offset)
+ ((parent-is "parameters") (nth-sibling 1) 0)
((parent-is "ERROR") no-indent 0))))
(defvar lua-ts--syntax-table
@@ -348,30 +410,128 @@ lua-ts-flymake-luacheck
(process-send-region lua-ts--flymake-process (point-min) (point-max))
(process-send-eof lua-ts--flymake-process))))
+(defun lua-ts-inferior--write-history (process _event)
+ "Write history file for inferior Lua PROCESS."
+ ;; Depending on how the process is killed the buffer may
+ ;; not be around anymore; e.g. `kill-buffer'.
+ (when-let* ((buffer (process-buffer process))
+ ((buffer-live-p buffer)))
+ (with-current-buffer buffer (comint-write-input-ring))))
+
;;;###autoload
(defun lua-ts-inferior-lua ()
"Run a Lua interpreter in an inferior process."
(interactive)
- (let* ((buffer lua-ts-inferior-buffer)
- (name (string-replace "*" "" buffer))
- (program lua-ts-inferior-program)
- (prompt-regexp lua-ts-inferior-prompt-regexp)
- (switches lua-ts-inferior-options)
- (startfile lua-ts-inferior-startfile))
- (unless (comint-check-proc buffer)
- (set-buffer (apply (function make-comint) name program startfile switches))
- (setq-local comint-input-ignoredups t
- comint-prompt-read-only t
- comint-prompt-regexp prompt-regexp
- comint-use-prompt-regexp t))
- (select-window (display-buffer buffer '((display-buffer-reuse-window
- display-buffer-pop-up-frame)
- (reusable-frames . t))))))
+ (unless (comint-check-proc lua-ts-inferior-buffer)
+ (apply #'make-comint-in-buffer
+ (string-replace "*" "" lua-ts-inferior-buffer)
+ lua-ts-inferior-buffer
+ lua-ts-inferior-program
+ lua-ts-inferior-startfile
+ lua-ts-inferior-options)
+ (when lua-ts-inferior-history
+ (set-process-sentinel (get-buffer-process lua-ts-inferior-buffer)
+ 'lua-ts-inferior--write-history))
+ (with-current-buffer lua-ts-inferior-buffer
+ (setq comint-prompt-regexp (rx-to-string `(: bol
+ ,lua-ts-inferior-prompt
+ space)))
+ (setq-local comint-input-ignoredups t)
+ (setq-local comint-input-ring-file-name lua-ts-inferior-history)
+ (setq-local comint-prompt-read-only t)
+ (setq-local comint-use-prompt-regexp t)
+ (comint-read-input-ring t)
+ (add-hook 'comint-preoutput-filter-functions
+ (lambda (string)
+ (if (equal string (concat lua-ts-inferior-prompt-continue " "))
+ string ; Don't mess with continuation prompts.
+ (concat
+ ;; Filter out the extra prompt characters that
+ ;; accumulate in the output when sending regions
+ ;; to the inferior process.
+ (replace-regexp-in-string (rx-to-string
+ `(: bol
+ (* ,lua-ts-inferior-prompt
+ (? ,lua-ts-inferior-prompt)
+ space)
+ (group (* nonl))))
+ "\\1" string)
+ ;; Re-add the prompt for the next line.
+ lua-ts-inferior-prompt " "))))))
+ (select-window (display-buffer lua-ts-inferior-buffer
+ '((display-buffer-reuse-window
+ display-buffer-pop-up-window)
+ (reusable-frames . t))))
+ (get-buffer-process (current-buffer)))
+
+(defun lua-ts-send-buffer ()
+ "Send current buffer to the inferior Lua process."
+ (interactive)
+ (lua-ts-send-region (point-min) (point-max)))
+
+(defun lua-ts-send-file (file)
+ "Send contents of FILE to the inferior Lua process."
+ (interactive "f")
+ (with-temp-buffer
+ (insert-file-contents-literally file)
+ (lua-ts-send-region (point-min) (point-max))))
+
+(defun lua-ts-send-region (beg end)
+ "Send region between BEG and END to the inferior Lua process."
+ (interactive "r")
+ (let ((string (buffer-substring-no-properties beg end))
+ (proc-buffer (lua-ts-inferior-lua)))
+ (comint-send-string proc-buffer "print()") ; Prevent output from
+ (comint-send-string proc-buffer "\n") ; appearing at prompt.
+ (comint-send-string proc-buffer string)
+ (comint-send-string proc-buffer "\n")))
+
+(defun lua-ts-show-process-buffer ()
+ "Show the inferior Lua process buffer."
+ (interactive)
+ (display-buffer lua-ts-inferior-buffer))
+
+(defun lua-ts-hide-process-buffer ()
+ "Hide the inferior Lua process buffer."
+ (interactive)
+ (delete-windows-on lua-ts-inferior-buffer))
+
+(defun lua-ts-kill-process ()
+ "Kill the inferior Lua process."
+ (interactive)
+ (with-current-buffer lua-ts-inferior-buffer
+ (kill-buffer-and-window)))
+
+(defvar lua-ts-mode-map
+ (let ((map (make-sparse-keymap "Lua")))
+ (define-key map "\C-c\C-n" 'lua-ts-inferior-lua)
+ (define-key map "\C-c\C-c" 'lua-ts-send-buffer)
+ (define-key map "\C-c\C-l" 'lua-ts-send-file)
+ (define-key map "\C-c\C-r" 'lua-ts-send-region)
+ map)
+ "Keymap for `lua-ts-mode' buffers.")
+
+(easy-menu-define lua-ts-mode-menu lua-ts-mode-map
+ "Menu bar entry for `lua-ts-mode'."
+ `("Lua"
+ ["Evaluate Buffer" lua-ts-send-buffer]
+ ["Evaluate File" lua-ts-send-file]
+ ["Evaluate Region" lua-ts-send-region]
+ "--"
+ ["Start Process" lua-ts-inferior-lua]
+ ["Show Process Buffer" lua-ts-show-process-buffer]
+ ["Hide Process Buffer" lua-ts-hide-process-buffer]
+ ["Kill Process" lua-ts-kill-process]
+ "--"
+ ["Customize" (lambda () (interactive) (customize-group "lua-ts"))]))
;;;###autoload
(define-derived-mode lua-ts-mode prog-mode "Lua"
- "Major mode for editing Lua files, powered by tree-sitter."
+ "Major mode for editing Lua files, powered by tree-sitter.
+
+\\{lua-ts-mode-map}"
:syntax-table lua-ts--syntax-table
+ (use-local-map lua-ts-mode-map)
(when (treesit-ready-p 'lua)
(treesit-parser-create 'lua)
@@ -415,7 +575,9 @@ lua-ts-mode
"while_statement")))
(sexp ,(rx (or "arguments"
"block"
+ "function_declaration"
"parameters"
+ "parenthesized_expression"
"string"
"table_constructor")))
(text "comment"))))
diff --git a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts
index 040225c8580..c407d3400f8 100644
--- a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts
+++ b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts
@@ -32,6 +32,22 @@ f({
;(function()
return false
)()
+
+function foo (e)
+ if e == nil
+ then return 1000
+ else return e
+ end
+end
+
+function foo (e)
+ if e == nil
+ then
+ return 1000
+ else
+ return e
+ end
+end
=-=
print(
0,
@@ -57,6 +73,22 @@ f({
;(function()
return false
)()
+
+function foo (e)
+ if e == nil
+ then return 1000
+ else return e
+ end
+end
+
+function foo (e)
+ if e == nil
+ then
+ return 1000
+ else
+ return e
+ end
+end
=-=-=
Name: Argument Indent
@@ -77,6 +109,13 @@ cost = 2,
length = 8,
parallelism = 4,
})
+
+fn(1,
+2,
+ 3)
+
+fn(1, 2,
+3)
=-=
function h(
string,
@@ -93,6 +132,13 @@ local p = h(
length = 8,
parallelism = 4,
})
+
+fn(1,
+ 2,
+ 3)
+
+fn(1, 2,
+ 3)
=-=-=
Name: Continuation Indent
@@ -130,10 +176,20 @@ for k, v in pairs({}) do
print(k, v)
end
+for i=1,10
+ do
+ print(i)
+end
+
while n < 10 do
n = n + 1
end
+while n < 10
+ do
+ n = n + 1
+end
+
repeat
z = z * 2
until z > 12
@@ -142,11 +198,154 @@ for k, v in pairs({}) do
print(k, v)
end
+for i=1,10
+do
+ print(i)
+end
+
while n < 10 do
n = n + 1
end
+while n < 10
+do
+ n = n + 1
+end
+
repeat
z = z * 2
until z > 12
=-=-=
+
+Name: Parameter Indent
+
+=-=
+fn(a,
+b)
+
+fn(a, b,
+c)
+
+fn(
+a,
+b
+)
+=-=
+fn(a,
+ b)
+
+fn(a, b,
+ c)
+
+fn(
+ a,
+ b
+)
+=-=-=
+
+Code:
+ (lambda ()
+ (setq indent-tabs-mode nil)
+ (setq lua-ts-indent-offset 4)
+ (lua-ts-mode)
+ (indent-region (point-min) (point-max)))
+
+Name: Table Indent
+
+=-=
+local Recipe = {
+ Floor={up={Floor=true,Wall=true},
+ down={Floor=true,Wall=true},
+ left={Floor=true,Wall=true},
+ right={Floor=true,Wall=true}},
+ Wall={up={Floor=true,Wall=true},
+ down={Floor=true,Wall=true},
+ left={Floor=true,Wall=true},
+ right={Floor=true,Wall=true}},
+ Corridor={up={Corridoor=true},
+ down={Corridoor=true},
+ left={Corridoor=true},
+ right={Corridoor=true}}
+}
+
+local Other = {
+a = 1,
+ b = 2,
+ c = 3,
+}
+=-=
+local Recipe = {
+ Floor={up={Floor=true,Wall=true},
+ down={Floor=true,Wall=true},
+ left={Floor=true,Wall=true},
+ right={Floor=true,Wall=true}},
+ Wall={up={Floor=true,Wall=true},
+ down={Floor=true,Wall=true},
+ left={Floor=true,Wall=true},
+ right={Floor=true,Wall=true}},
+ Corridor={up={Corridoor=true},
+ down={Corridoor=true},
+ left={Corridoor=true},
+ right={Corridoor=true}}
+}
+
+local Other = {
+ a = 1,
+ b = 2,
+ c = 3,
+}
+=-=-=
+
+Name: Single Line End
+
+=-=
+function lowest_entropy_cell(world)
+ local lowest,res=math.huge,nil
+ for y=1,world.height do
+ for x=1,world.width do
+ local cell=world:get(x,y)
+ if cell.is_set then
+ local e=cell_enthropy(cell)
+ trace(e)
+ if e <= lowest then
+ lowest,res=e,{x,y}
+ end end end end
+ return res or {math.random(w.w),math.random(w.h)}
+end
+
+for y=1,world.height do
+ for x=1,world.width do
+ local cell=world:get(x,y)
+ if cell.is_set then
+ local e=cell_enthropy(cell)
+ trace(e)
+ if e <= lowest then
+ lowest,res=e,{x,y}
+ end
+ end end end
+=-=
+function lowest_entropy_cell(world)
+ local lowest,res=math.huge,nil
+ for y=1,world.height do
+ for x=1,world.width do
+ local cell=world:get(x,y)
+ if cell.is_set then
+ local e=cell_enthropy(cell)
+ trace(e)
+ if e <= lowest then
+ lowest,res=e,{x,y}
+ end end end end
+ return res or {math.random(w.w),math.random(w.h)}
+end
+
+for y=1,world.height do
+ for x=1,world.width do
+ local cell=world:get(x,y)
+ if cell.is_set then
+ local e=cell_enthropy(cell)
+ trace(e)
+ if e <= lowest then
+ lowest,res=e,{x,y}
+ end
+end end end
+=-=-=
diff --git a/test/lisp/progmodes/lua-ts-mode-resources/movement.erts b/test/lisp/progmodes/lua-ts-mode-resources/movement.erts
index 770aa23b18d..afebe93de3f 100644
--- a/test/lisp/progmodes/lua-ts-mode-resources/movement.erts
+++ b/test/lisp/progmodes/lua-ts-mode-resources/movement.erts
@@ -481,6 +481,34 @@ local t = { 1,
3 }|
=-=-=
+Name: forward-sexp moves over parenthesized expressions
+
+=-=
+|(function (x) return x + 1 end)(41)
+=-=
+(function (x) return x + 1 end)|(41)
+=-=-=
+
+Name: forward-sexp moves over function declarations
+
+=-=
+|function foo (x)
+ if false then
+ print "foo"
+ elseif true then
+ print "bar"
+ end
+end
+=-=
+function foo (x)
+ if false then
+ print "foo"
+ elseif true then
+ print "bar"
+ end
+end|
+=-=-=
+
Code:
(lambda ()
(lua-ts-mode)
@@ -551,3 +579,31 @@ local t = |{ 1,
2,
3 }
=-=-=
+
+Name: backward-sexp moves over parenthesized expressions
+
+=-=
+(function (x) return x + 1 end)|(41)
+=-=
+|(function (x) return x + 1 end)(41)
+=-=-=
+
+Name: backward-sexp moves over function declarations
+
+=-=
+function foo (x)
+ if false then
+ print "foo"
+ elseif true then
+ print "bar"
+ end
+end|
+=-=
+|function foo (x)
+ if false then
+ print "foo"
+ elseif true then
+ print "bar"
+ end
+end
+=-=-=
--
2.41.0
next prev parent reply other threads:[~2023-10-03 15:04 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-22 19:17 bug#66159: 30.0.50; lua-ts-mode semantic indentation problems Andrey Listopadov
2023-09-22 19:49 ` Eli Zaretskii
2023-09-24 15:06 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-24 15:44 ` Eli Zaretskii
2023-09-24 16:38 ` Andrey Listopadov
2023-09-24 18:20 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-26 19:21 ` Andrey Listopadov
2023-09-27 1:18 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-30 9:59 ` Andrey Listopadov
2023-09-30 13:57 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-03 15:04 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors [this message]
2023-10-03 19:13 ` Andrey Listopadov
2023-09-30 7:52 ` Philip Kaludercic
2023-10-06 19:44 ` bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-07 10:11 ` Mauro Aranda
2023-10-07 16:15 ` Andrey Listopadov
2023-10-07 18:10 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-08 9:43 ` Andrey Listopadov
2023-10-09 3:28 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-17 3:26 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-20 20:40 ` Stefan Kangas
2023-10-22 20:03 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-23 8:11 ` Stefan Kangas
2023-10-21 5:15 ` Andrey
2023-10-21 11:37 ` Andrey
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=87ttr73fuz.fsf@pub.pink \
--to=bug-gnu-emacs@gnu.org \
--cc=66159@debbugs.gnu.org \
--cc=andreyorst@gmail.com \
--cc=eliz@gnu.org \
--cc=jm@pub.pink \
/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).