From c8dbf478083b35a2b0edebb2639b56e9637a2676 Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Wed, 5 Feb 2025 14:09:22 +1030 Subject: [PATCH 1/5] pyln-client: remove unused `doc` variable from plugin. The `doc` variable was being initialised and processed but not used anywhere. Changelog-None Signed-off-by: Nishant Bansal --- contrib/pyln-client/pyln/client/plugin.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/contrib/pyln-client/pyln/client/plugin.py b/contrib/pyln-client/pyln/client/plugin.py index 022a931852a0..19eb59a43de6 100644 --- a/contrib/pyln-client/pyln/client/plugin.py +++ b/contrib/pyln-client/pyln/client/plugin.py @@ -938,16 +938,6 @@ def _getmanifest(self, **kwargs) -> JSONType: 'after': method.after}) continue - doc = inspect.getdoc(method.func) - if not doc: - self.log( - 'RPC method \'{}\' does not have a docstring.'.format( - method.name - ) - ) - doc = "Undocumented RPC method from a plugin." - doc = re.sub('\n+', ' ', doc) - # For compatibility with lightningd prior to 24.08, we must # provide a description. Ignored by 24.08 onwards, description = method.description From 4c958c16666e9a4b91308ff7fb1bac9e2360c980 Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Wed, 5 Feb 2025 15:04:09 +1030 Subject: [PATCH 2/5] pyln-client: use `\n` as line separator in lightning-cli help Changelog-Changed: Interpret \n as the line separator in plugins to enhance the readability of lightning-cli help. Signed-off-by: Nishant Bansal [ Modified to use \n not | --RR ] --- contrib/pyln-client/pyln/client/plugin.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contrib/pyln-client/pyln/client/plugin.py b/contrib/pyln-client/pyln/client/plugin.py index 19eb59a43de6..b55312c16381 100644 --- a/contrib/pyln-client/pyln/client/plugin.py +++ b/contrib/pyln-client/pyln/client/plugin.py @@ -84,7 +84,9 @@ def get_usage(self): args.append("[%s]" % arg) if self.description is not None: - args.append("\n%s" % self.description) + doc = inspect.getdoc(self.func) + doc = re.sub('\n', '\n ', doc) + args.append(" \n %s" % doc) return " ".join(args) From 98d21b83623b57ae0ce14ec5417545abcf0121ca Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 5 Feb 2025 15:05:56 +1030 Subject: [PATCH 3/5] lightningd: insert "raw" (unescaped) help messages from commands. So if they want a \n in usage, they can have it. Signed-off-by: Rusty Russell --- lightningd/jsonrpc.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lightningd/jsonrpc.c b/lightningd/jsonrpc.c index d6c9c4babbbd..1ddf80b67d09 100644 --- a/lightningd/jsonrpc.c +++ b/lightningd/jsonrpc.c @@ -1393,10 +1393,22 @@ static void setup_command_usage(struct lightningd *ld, bool jsonrpc_command_add(struct jsonrpc *rpc, struct json_command *command, const char *usage TAKES) { + struct json_escape *esc; + const char *unescaped; + if (!command_add(rpc, command)) return false; - usage = tal_strdup(command, usage); - strmap_add(&rpc->usagemap, command->name, usage); + + esc = json_escape_string_(tmpctx, usage, strlen(usage)); + unescaped = json_escape_unescape(command, esc); + if (!unescaped) + unescaped = tal_strdup(command, usage); + else { + if (taken(usage)) + tal_free(usage); + } + + strmap_add(&rpc->usagemap, command->name, unescaped); tal_add_destructor2(command, destroy_json_command, rpc); return true; } From 6559654d65f1e730c5988804630c3cc35e0e9fba Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 5 Feb 2025 15:06:47 +1030 Subject: [PATCH 4/5] lightning-cli: use human_readable for help messages (unescapes \n for us). Signed-off-by: Rusty Russell Changelog-Changed: lightning-cli: `help` messages using new-lines is now printed properly, enhancing readability and consistency. --- cli/lightning-cli.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/lightning-cli.c b/cli/lightning-cli.c index c3a25afd14a0..53540a7ccaee 100644 --- a/cli/lightning-cli.c +++ b/cli/lightning-cli.c @@ -197,8 +197,8 @@ static void human_help(char *buffer, const jsmntok_t *result) for (i = 0; i < tal_count(help); i++) { const jsmntok_t *command; command = json_get_member(buffer, help[i], "command"); - printf("%.*s\n\n", - command->end - command->start, buffer + command->start); + human_readable(buffer, command, '\n'); + printf("\n"); } tal_free(help); From 69a42610120365c3f9809de52db47d61380bbbb2 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 5 Feb 2025 15:07:33 +1030 Subject: [PATCH 5/5] pytest: add multiline help test. Signed-off-by: Rusty Russell --- tests/plugins/multiline-help.py | 17 +++++++++++++++++ tests/test_misc.py | 22 ++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100755 tests/plugins/multiline-help.py diff --git a/tests/plugins/multiline-help.py b/tests/plugins/multiline-help.py new file mode 100755 index 000000000000..4b8b3a7f87f4 --- /dev/null +++ b/tests/plugins/multiline-help.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +from pyln.client import Plugin, Millisatoshi + + +plugin = Plugin() + + +@plugin.method("helpme") +def helpme(plugin, msat: Millisatoshi): + """This is a message which consumes multiple lines and thus should + be well-formatted by lightning-cli help + + """ + return {'help': msat} + + +plugin.run() diff --git a/tests/test_misc.py b/tests/test_misc.py index 9e1abd75ae4d..a828885de1bf 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -1148,6 +1148,28 @@ def test_cli(node_factory): assert [l for l in lines if not re.search(r'^help\[[0-9]*\].', l)] == ['format-hint=simple'] +def test_cli_multiline_help(node_factory): + l1 = node_factory.get_node(options={'plugin': os.path.join(os.getcwd(), 'tests/plugins/multiline-help.py')}) + + out = subprocess.check_output(['cli/lightning-cli', + '--network={}'.format(TEST_NETWORK), + '--lightning-dir={}' + .format(l1.daemon.lightning_dir), + 'help']).decode('utf-8') + assert ("helpme msat \n" + " This is a message which consumes multiple lines and thus should\n" + " be well-formatted by lightning-cli help\n" in out) + + out = subprocess.check_output(['cli/lightning-cli', + '--network={}'.format(TEST_NETWORK), + '--lightning-dir={}' + .format(l1.daemon.lightning_dir), + 'help', 'helpme']).decode('utf-8') + assert out == ("helpme msat \n" + " This is a message which consumes multiple lines and thus should\n" + " be well-formatted by lightning-cli help\n") + + def test_cli_commando(node_factory): l1, l2 = node_factory.line_graph(2, fundchannel=False, opts={'log-level': 'io', 'allow-deprecated-apis': True})