可以对?显示帮助信息,需要立即获取输入的字符,因此需要用到termios模块
另外需要对tab键做处理,当按下tab键时可以进行自动补全
#! /usr/bin/env python
# coding=utf-8
import os
import sys
import tty
import termios
'''
Enter: 13
Back: 127
?: 63
C-h: 8
C-w: 23
Tab: 9
C-u: 21
C-c: 3
C-d: 4
C-\: 28
SPACE: 32
'''
CLI_KEY_CNCR = 13
CLI_KEY_BACK = 127
CLI_KEY_QMARK = 63
CLI_KEY_CTRLH = 8
CLI_KEY_CTRLW = 23
CLI_KEY_TAB = 9
CLI_KEY_CTRLU = 21
CLI_KEY_CTRLC = 3
CLI_KEY_CTRLD = 4
CLI_KEY_QUIT = 28
CLI_KEY_SPACE = 32
CLI_KEY_TABLEN = 4
class CLI(object):
def __init__(self):
self.line = ''
self.line_complete = ''
self.completer_on = False
self.completer_dict = {}
self.completer_dict_keys = self.completer_dict.keys()
self.completer_id = 0
self.completer_cnt = len(self.completer_dict)
def getch(self):
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
def completer_kw_update(self):
self.completer_dict_keys = self.completer_dict.keys()
self.completer_dict_keys.sort()
self.completer_cnt = len(self.completer_dict)
def completer_kw_add(self, key, word):
self.completer_dict[key] = word
self.completer_kw_update()
def completer_kw_clear(self):
self.completer_dict.clear()
self.completer_id_update()
def completer_id_update(self):
self.completer_kw_update()
if self.completer_id < self.completer_cnt - 1:
self.completer_id += 1
else:
self.completer_id = 0
def completer_wd_select(self, word):
if not word:
return ''
cnt = self.completer_cnt
while cnt>0:
completer = self.completer_dict_keys[self.completer_id]
self.completer_id_update()
cnt -= 1
if word == completer[:len(word)]:
return completer[len(word):]
return ''
def printf(self, info=''):
sys.stdout.write(info)
def show_spec_len_str(self, info, maxlen, spacech=' '):
'display a string of the specified length'
maxlen = maxlen
infolen = len(info)
if maxlen < infolen:
maxlen = infolen
while infolen>0:
ch = info[-infolen]
for i in range(self.char_memory_len(ch)):
self.printf(info[i-infolen])
infolen -= self.char_memory_len(ch)
maxlen -= self.char_display_len(ch)
while maxlen>0:
self.printf(spacech)
maxlen -= self.char_display_len(spacech)
def show_help_info(self):
if self.completer_on:
line = self.line_complete
else:
line = self.line
lastwd = ''
show_all = False
if not line or line[-1] == ' ':
show_all = True
else:
lastwd = line.split()[-1]
if self.completer_dict:
maxlen = max([len(info) for info in self.completer_dict])
else:
maxlen = 12
for info in self.completer_dict:
if show_all or lastwd == info[:len(lastwd)]:
self.printf(' ')
self.show_spec_len_str(info, maxlen)
self.printf(' ')
self.printf(self.completer_dict[info])
self.printf('\r\n')
def is_chinese_char(self, ch):
return ord(ch) > 127
def char_display_len(self, ch):
if self.is_chinese_char(ch):
return 2
elif ord(ch) == CLI_KEY_TAB:
return CLI_KEY_TABLEN
else:
return 1
def char_memory_len(self, ch):
if self.is_chinese_char(ch):
return 3
else:
return 1
def rm_last_char(self, line):
lastch = ''
rmlen = 0
if len(line)>0:
lastch = line[-1]
self.printf('\b \b' * self.char_display_len(lastch))
rmlen = self.char_memory_len(lastch)
if len(line) >= rmlen:
line = line[:-(rmlen)]
else:
rmlen = len(line)
line = ''
return rmlen, line
def rm_last_word(self, line):
lastwd = ''
linelen = len(line)
rspacelen = linelen - len(line.rstrip())
if not linelen:
return line
lastwd = line.split()[-1]
backlen = len(lastwd) + rspacelen
rmlen = 0
while backlen>0 and line:
rmlen, line = self.rm_last_char(line)
backlen -= rmlen
return line
def rm_one_line(self, line):
rmlen = 0
while line:
rmlen, line = self.rm_last_char(line)
return line
def do_line_complete_proc(self):
line = self.line
line_complete = self.line_complete
lastwd = ''
self.printf('\r\n')
if self.line_complete:
self.printf(self.line_complete)
else:
self.printf(self.line)
if not line:
return line
lastwd = line.split()[-1]
completer = self.completer_wd_select(lastwd)
if not completer.strip():
self.line_complete = line
return line
backlen = len(line_complete) - len(line)
while backlen>0 and line_complete:
rmlen, line_complete = self.rm_last_char(line_complete)
backlen -= rmlen
self.printf(completer)
line_complete = line + completer
self.line_complete = line_complete
def do_line_complete_end(self):
if self.completer_on:
self.line = self.line_complete
self.line_complete = ''
self.completer_on = False
def get_line(self):
self.line = ''
self.line_complete = ''
self.completer_on = False
while True:
ch = self.getch()
if ch == '\r' or ch == '\n':
self.do_line_complete_end()
self.printf('\r\n')
break
elif ord(ch) == CLI_KEY_BACK or ord(ch) == CLI_KEY_CTRLH:
if self.completer_on:
rmlen, self.line_complete = self.rm_last_char(self.line_complete)
else:
rmlen, self.line = self.rm_last_char(self.line)
self.do_line_complete_end()
elif ord(ch) == CLI_KEY_QMARK:
self.printf('?')
self.printf('\r\n')
self.show_help_info()
if self.completer_on:
self.printf(self.line_complete)
else:
self.printf(self.line)
elif ord(ch) == CLI_KEY_CTRLW:
if self.completer_on:
self.line_complete = self.rm_last_word(self.line_complete)
else:
self.line = self.rm_last_word(self.line)
self.do_line_complete_end()
elif ord(ch) == CLI_KEY_TAB:
self.completer_on = True
self.do_line_complete_proc()
elif ord(ch) == CLI_KEY_CTRLD:
if self.line:
return self.line
else:
return ch
elif ord(ch) == CLI_KEY_QUIT:
self.printf('\r\n Interrupted by .\r\n')
sys.exit()
elif ord(ch) == CLI_KEY_CTRLU:
if self.completer_on:
self.line_complete = self.rm_one_line(self.line_complete)
else:
self.line = self.rm_one_line(self.line)
self.do_line_complete_end()
elif ord(ch) == CLI_KEY_SPACE:
self.printf(ch)
if self.completer_on:
self.line_complete += ch
else:
self.line += ch
else:
self.printf(ch)
self.do_line_complete_end()
self.line += ch
# chinese qmask proc
if ord(ch) == 159 and len(self.line)>= 3 and self.line[-3:] == '\xef\xbc\x9f':
self.printf('\r\n')
self.line = self.line[:-3]
self.show_help_info()
self.printf(self.line)
return self.line
def get_raw_line(self):
self.raw_line = ''
while True:
ch = self.getch()
if ch == '\r' or ch == '\n':
self.printf('\r\n')
break
elif ord(ch) == CLI_KEY_BACK or ord(ch) == CLI_KEY_CTRLH:
rmlen, self.raw_line = self.rm_last_char(self.raw_line)
elif ord(ch) == CLI_KEY_CTRLW:
self.raw_line = self.rm_last_word(self.raw_line)
elif ord(ch) == CLI_KEY_TAB:
self.printf(' ' * self.char_display_len(ch))
self.raw_line += ch
elif ord(ch) == CLI_KEY_CTRLD:
if self.raw_line:
return self.raw_line
else:
return ch
elif ord(ch) == CLI_KEY_QUIT:
self.printf('\r\n Interrupted by .\r\n')
sys.exit()
elif ord(ch) == CLI_KEY_CTRLU:
self.raw_line = self.rm_one_line(self.raw_line)
else:
self.raw_line += ch
self.printf(ch)
return self.raw_line
def test():
cli = CLI()
help_info = {
'hello0': 'say hello 0',
'hello1': 'say hello 1',
'hellohello': 'say hello hello',
'hellohehe': 'say hello hehe',
'hellohi': 'say hello hi',
'你好啊': 'say 你好啊',
'你好吗': 'say 你好吗',
'你好哈': 'say 你好哈',
}
for key in help_info:
cli.completer_kw_add(key, help_info[key])
while True:
line = cli.get_line()
if len(line) == 1 and ord(line[0]) == CLI_KEY_CTRLD:
break
if line == 'quit':
break
print(line)
if __name__ == "__main__":
test()
以上这篇使用python模拟命令行终端的示例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。