From db797a140ae068dbd852e2724a5a922f73109d1b Mon Sep 17 00:00:00 2001 From: Gleb Kashkin Date: Mon, 11 Jul 2022 09:27:53 +0000 Subject: [PATCH] console: add line carrying backslash When using interactive console(stdin) instead of `\set delimiter '\'`, slash at the end of the line can be used. Works on both server and client side. Co-authored-by: Olga Arkhangelskaia Closes #4317 Requires #7357 @TarantoolBot document Title: introduce line carrying slash Now we can use multiline commands with lines ending with '\' by default. Works only when console is in lua mode and without a set delimiter. Consider the example: ``` tarantool> a = 10 \ > + 12 --- ... tarantool> a --- - 22 ... ``` --- ...317-console-add-line-carrying-backslash.md | 5 ++ src/box/lua/console.lua | 39 +++++++++++++-- .../gh_4317_console_backslash_test.lua | 50 +++++++++++++++++++ 3 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/gh-4317-console-add-line-carrying-backslash.md create mode 100644 test/app-luatest/gh_4317_console_backslash_test.lua diff --git a/changelogs/unreleased/gh-4317-console-add-line-carrying-backslash.md b/changelogs/unreleased/gh-4317-console-add-line-carrying-backslash.md new file mode 100644 index 000000000000..45283a6dec5b --- /dev/null +++ b/changelogs/unreleased/gh-4317-console-add-line-carrying-backslash.md @@ -0,0 +1,5 @@ +## feature/console + +* Now multiline commands with all lines except last one ending with "\" can + be used instead of `\set delimiter "\"`, is active only without a set + delimiter. Works on both server and client side. diff --git a/src/box/lua/console.lua b/src/box/lua/console.lua index 69d9d992109d..caef971f0e9f 100644 --- a/src/box/lua/console.lua +++ b/src/box/lua/console.lua @@ -587,6 +587,8 @@ local function local_check_lua(buf) return false end +-- Each but the last string of multiline command should end with this string. +local multiline_delim = '\\' -- -- Read command from stdin -- @@ -611,7 +613,11 @@ local function local_read(self) if not lang or lang == 'lua' then -- stop once a complete Lua statement is entered if local_check_lua(buf) then - break + if not line:endswith(multiline_delim) then + break + end + buf = buf:sub(1, -2) + -- Continue reading. end else break @@ -642,9 +648,12 @@ local function local_print(self, output) end -- --- Read command from connected client console.listen() +-- Read a line or a chunk from connected client console.listen(). -- -local function client_read(self) +-- The value is returned without delimiter (if any) and trailing +-- newline character. +-- +local function client_read_line(self) -- -- Byte sequences that come over the network and come from -- the local client console may have a different terminal @@ -665,6 +674,30 @@ local function client_read(self) return buf:sub(1, -#self.delimiter-2) end +-- +-- Read a command from connected client console.listen(). +-- +local function client_read(self) + local buf = "" + while true do + local line = client_read_line(self) + if line == nil then + -- EOF or error. + -- + -- Note: Even if `buf` is not empty, skip unfinished + -- command. + return nil + end + buf = buf .. line + if self.delimiter == "" and line:endswith(multiline_delim) then + buf = buf:sub(1, -2) + else + break + end + end + return buf +end + -- -- Print result to connected client from console.listen() -- diff --git a/test/app-luatest/gh_4317_console_backslash_test.lua b/test/app-luatest/gh_4317_console_backslash_test.lua new file mode 100644 index 000000000000..92c18a893d6e --- /dev/null +++ b/test/app-luatest/gh_4317_console_backslash_test.lua @@ -0,0 +1,50 @@ +local t = require('luatest') +local g = t.group() + +local result_str = [[tarantool> local a = 0 \ + > for i = 1, 10 do + > a = a + i + > end \ + > print(a) +55 +--- +... + +tarantool> ]] + +local TARANTOOL_PATH = arg[-1] + +g.test_using_backslash_on_local_console = function() + local tarantool_command = [[local a = 0 \\\nfor i = 1, 10 do\na = a + i\nend \\\nprint(a)\n]] + + local cmd = ("printf '%s' | %s -i 2>/dev/null"):format(tarantool_command, TARANTOOL_PATH) + local fh = io.popen(cmd, 'r') + + -- Readline on CentOS 7 produces \e[?1034h escape sequence before tarantool> prompt, remove it. + local result = fh:read('*a'):gsub('\x1b%[%?1034h', '') + + fh:close() + t.assert_equals(result, result_str) +end + +g.test_using_backslash_on_remote_console = function() + local console = require('console') + local socket = require('socket') + local log = require('log') + + -- Suppress console log messages. + log.level(4) + local CONSOLE_SOCKET = '/tmp/tarantool-test-using-backslash-on-remote-console.sock' + local EOL = '\n...\n' + console.listen(CONSOLE_SOCKET) + socket.tcp_connect('unix/', CONSOLE_SOCKET) + local tarantool_command = 'local a = 0 \\\nfor i = 1, 10 do\\\n a = a + i \\\n end \\\n return a' + + local client = socket.tcp_connect('unix/', CONSOLE_SOCKET) + client:write(('%s\n'):format(tarantool_command)) + local result = client:read(EOL) + t.assert_str_contains(result, '- 55') + t.assert_not_str_contains(result, 'error') + client:close() + os.remove(CONSOLE_SOCKET) +end