Improve input speed for tmux integration
Performance issue
- iTerm2 version: 3.4.14
- OS version: 12.1 (21C52)
Detailed steps to reproduce the problem
- run
tmux -CC
- open
vim
- paste a huge text
What happened
The input speed is very slow while using tmux integration, since 1 single byte will turn into 5 bytes.
e.g. Pasting /bin/bash
will turn into send-keys -t "%12" 0x2f 0x62 0x69 0x6e 0x2f 0x62 0x61 0x73 0x68
What should have happened
Don't convert every byte to hex unless necessary.
e.g. Pasting /bin/bash
should be turned into send -l -t %12 /bin/bash
About tmux send-keys
-
Online manual https://man7.org/linux/man-pages/man1/tmux.1.html
-
tmux 3.0a
send-keys [-HlMRX] [-N repeat-count] [-t target-pane] key ...
(alias: send)
Send a key or keys to a window. Each argument key is the name of the key (such as ‘C-a’ or ‘NPage’) to send; if the string is not recognised as a key, it is sent as a series of characters. All arguments are sent sequentially from first to last.
The -l flag disables key name lookup and processes the keys as literal UTF-8 characters. The -H flag expects each key to be a hexadecimal number for an ASCII character.
The -R flag causes the terminal state to be reset.
-M passes through a mouse event (only valid if bound to a mouse key binding, see MOUSE SUPPORT).
-X is used to send a command into copy mode - see the WINDOWS AND PANES section. -N specifies a repeat count.
- tmux 1.8
send-keys [-lR] [-t target-pane] key ...
(alias: send)
Send a key or keys to a window. Each argument key is the name of the key (such as ‘C-a’ or ‘npage’ ) to send; if the string is not recognised as a key, it is sent as a series of characters. The -l flag disables key name lookup and sends the keys literally. All arguments are sent sequentially from first to last. The -R flag causes the terminal state to be reset.
Test tmux send-keys
Test send-keys source code
- echo.py
#!/usr/bin/env python3
import sys
length = int(sys.argv[1])
data = sys.stdin.buffer.read(length)
print(' '.join([str(hex(c)) for c in data]))
- test.py
#!/usr/bin/env python3
import os
import sys
import select
import subprocess
p = subprocess.Popen(['tmux', '-C'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
def read_output():
output = []
while True:
r, w, x = select.select([p.stdout], [], [], 0.2)
if not r:
break
s = p.stdout.readline().decode('utf8')
print(s, end='')
if s.startswith('%output'):
output.append(s)
return output
def send_input(cmd):
print("\n%s\n" % cmd)
p.stdin.write(('%s\n' % cmd).encode('utf8'))
p.stdin.flush()
pane = read_output()[0].split()[1]
data = ''
for i in range(0x21, 0x7f):
if chr(i) in "\"#';\\{}":
continue
data += chr(i)
expect = ' '.join([str(hex(ord(c))) for c in data])
print('\nEXPECT: %s' % expect)
send_input('send -lt %s "./echo.py %d"' % (pane, len(data)))
read_output()
send_input('send -t %s 0xA' % pane)
read_output()
send_input('send -lt %s %s' % (pane, data))
read_output()
send_input('send -t %s 0xA' % pane)
result = read_output()
p.terminate()
for s in result:
if expect in s:
print('\nTEST SUCCESS')
Test success on tmux 1.8, 2.1, 2.6, 3.0a
root@5a2eeccac6dc:~# ./test.py
%begin 1642585499 240 0
%end 1642585499 240 0
%window-pane-changed @1 %1
%window-add @1
%session-window-changed $1 @1
%sessions-changed
%session-changed $1 1
%output %1 root@5a2eeccac6dc:~#
EXPECT: 0x21 0x24 0x25 0x26 0x28 0x29 0x2a 0x2b 0x2c 0x2d 0x2e 0x2f 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3a 0x3c 0x3d 0x3e 0x3f 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x4b 0x4c 0x4d 0x4e 0x4f 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5a 0x5b 0x5d 0x5e 0x5f 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6a 0x6b 0x6c 0x6d 0x6e 0x6f 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7a 0x7c 0x7e
send -lt %1 "./echo.py 87"
%begin 1642585499 247 1
%end 1642585499 247 1
%output %1 ./echo.py 87
send -t %1 0xA
%begin 1642585499 248 1
%end 1642585499 248 1
%output %1 \015\012
send -lt %1 !$%&()*+,-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz|~
%window-renamed @1 python3
%begin 1642585499 250 1
%end 1642585499 250 1
%output %1 !$%&()*+,-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz|~
send -t %1 0xA
%begin 1642585500 251 1
%end 1642585500 251 1
%output %1 \015\012
%output %1 0x21 0x24 0x25 0x26 0x28 0x29 0x2a 0x2b 0x2c 0x2d 0x2e 0x2f 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3a 0x3c 0x3d 0x3e 0x3f 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x4b 0x4c 0x4d 0x4e 0x4f 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5a 0x5b 0x5d 0x5e 0x5f 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x6a 0x6b 0x6c 0x6d 0x6e 0x6f 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7a 0x7c 0x7e\015\012
%output %1 root@5a2eeccac6dc:~#
TEST SUCCESS
Suggestion
Most visible characters can be sent directly. Please don't convert them into hex.
Edited by Lonny Wong