11'''
2- Windows only. If not windows, start IPython.
3- Advantage over IPython:
2+ Windows only. If not windows, console() calls IPython.embed() .
3+ Advantages over IPython:
44 1. Lighter
55 2. Other threads can still print things when user is inputting commands
6- Issue:
7- If you wanna scroll up, you need to input().
8- Changing global bindings doesn't work. Sorry.
6+ 3. Tab auto-completes your phrase, even under Windows! (I'm proud.)
7+ Issues:
8+ 1. If you wanna scroll up, you need to input().
9+ 2. Reassigning module global variables will not be visible to module native codes. Sorry.
910'''
1011import platform
11- from listen import listen
12+ from interactive import listen , strCommonStart
1213from kernal import Kernal
14+ from graphic_terminal import clearLine
15+ import string
1316
1417CURSOR = '|'
1518
@@ -18,7 +21,7 @@ def console(namespace = {}, prompt = '>>> ', use_input = False, fixer = None):
1821 from IPython import embed
1922 embed ()
2023 return
21- print ('console.console Warning: no support for change in global bindings . ' )
24+ print ('console.console Warning: no support for reassigning module global variables . ' )
2225 history = []
2326 kernal = Kernal (namespace )
2427 next (kernal )
@@ -38,7 +41,8 @@ def console(namespace = {}, prompt = '>>> ', use_input = False, fixer = None):
3841 op = listen (timeout = .5 )
3942 last_len = len (command )
4043 if op == b'\r ' :
41- print (prompt + command .replace ('\x1a ' , '^Z' ) + ' ' )
44+ clearLine ()
45+ print (prompt + command .replace ('\x1a ' , '^Z' ))
4246 break
4347 elif op is None :
4448 cursor_bright = not cursor_bright
@@ -100,18 +104,53 @@ def console(namespace = {}, prompt = '>>> ', use_input = False, fixer = None):
100104 word_ended = True
101105 else :
102106 cursor = len (command )
107+ elif op == b'\t ' :
108+ # auto complete
109+ legal_prefix = string .ascii_letters + string .digits + '_'
110+ reversed_names = []
111+ name_end = cursor
112+ name_start = cursor - 1
113+ while True :
114+ if name_start >= 0 and command [name_start ] in legal_prefix :
115+ name_start -= 1
116+ else :
117+ reversed_names .append (command [name_start + 1 :name_end ])
118+ name_end = name_start
119+ name_start -= 1
120+ if name_start < 0 or command [name_end ] != '.' :
121+ break
122+ keyword = reversed_names .pop (0 )
123+ names = reversed (reversed_names )
124+ to_search = kernal .send ('dir(%s)' % '.' .join (names ))
125+ if len (reversed_names ) == 0 :
126+ # include builtins
127+ to_search += dir (__builtins__ )
128+ next (kernal )
129+ candidates = [x for x in to_search if x .startswith (keyword )]
130+ if len (candidates ) >= 1 :
131+ if len (candidates ) == 1 :
132+ to_become = candidates [0 ]
133+ if len (candidates ) > 1 :
134+ clearLine ()
135+ print ('auto-complete: ' , end = '' )
136+ [print (x , end = '\t ' ) for x in candidates ]
137+ print ()
138+ to_become = strCommonStart (candidates , len (keyword ))
139+ to_insert = to_become [len (keyword ):]
140+ command = command [:cursor ] + to_insert + command [cursor :]
141+ cursor += len (to_insert )
103142 elif op [0 ] in range (1 , 26 ) or op [0 ] in (0 , 224 ):
104143 pass
105144 else :
106145 command = command [:cursor ] + op .decode () + command [cursor :]
107146 cursor += 1
108- padding = max (0 , last_len - len (command )) * 2
109147 if cursor_bright :
110148 cursor_show = CURSOR
111149 else :
112150 cursor_show = '_'
113151 cursed_command = command [:cursor ] + cursor_show + command [cursor :]
114- print (prompt + cursed_command .replace ('\x1a ' , '^Z' ) + ' ' * padding , end = '\r ' )
152+ clearLine ()
153+ print (prompt + cursed_command .replace ('\x1a ' , '^Z' ), end = '\r ' )
115154 if fixer is not None :
116155 command = fixer (command )
117156 if command in ('exit' , 'exit()' , '\x1a ' ):
@@ -123,7 +162,10 @@ def console(namespace = {}, prompt = '>>> ', use_input = False, fixer = None):
123162 if command == '' :
124163 continue
125164 history .append (command )
126- kernal .send (command )
165+ result = kernal .send (command )
166+ next (kernal )
167+ if result is not None :
168+ print (result )
127169
128170if __name__ == '__main__' :
129171 console ({})
0 commit comments