python

超轻量级php框架startmvc

使用python模拟命令行终端的示例

更新时间:2020-07-23 22:00:01 作者:startmvc
可以对?显示帮助信息,需要立即获取输入的字符,因此需要用到termios模块另外需要对tab

可以对?显示帮助信息,需要立即获取输入的字符,因此需要用到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 <Ctrl-\>.\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 <Ctrl-\>.\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模拟命令行终端的示例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

python 命令行 终端