GnuCash c935c2f+
Loading...
Searching...
No Matches
shell.py
1#! /usr/bin/env python3
2#
3# Copyright (c) 2008, Nicolas Rougier
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are met:
8#
9# * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# * Redistributions in binary form must reproduce the above copyright
12# notice, this list of conditions and the following disclaimer in the
13# documentation and/or other materials provided with the distribution.
14# * Neither the name of the University of California, Berkeley nor the
15# names of its contributors may be used to endorse or promote products
16# derived from this software without specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
19# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE FOR ANY
22# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29import os
30import sys
31import re
32import rlcompleter
33import traceback
34import tempfile
35
36if not hasattr(sys, 'ps1'): sys.ps1 = '>>> '
37if not hasattr(sys, 'ps2'): sys.ps2 = '... '
38
39
40class Shell:
41 """ """
42
43 def __init__(self, ns_globals={}, ns_locals={}):
44 """ """
45
46 self.completer = rlcompleter.Completer (ns_globals)
47 self.command = ''
48 self.globals = ns_globals
49 self.locals = ns_locals
50 self.complete_sep = re.compile(r'[\s\{\}\[\]\‍(\‍)]')
51 self.prompt = sys.ps1
52
53
54 def namespace(self):
55 return self.globals
56
57 def is_balanced (self, line):
58 """ Checks line balance for brace, bracket, parentheses and string quote
59
60 This helper function checks for the balance of brace, bracket,
61 parentheses and string quote. Any unbalanced line means to wait until
62 some other lines are fed to the console.
63 """
64
65 s = line
66 s = list(filter(lambda x: x in '()[]{}"\'', s))
67 # s = s.replace ("'''", "'")
68 # s = s.replace ('"""', '"')
69 instring = False
70 brackets = {'(':')', '[':']', '{':'}', '"':'"', '\'':'\''}
71 stack = []
72 while len(s):
73 if not instring:
74 if s[0] in ')]}':
75 if stack and brackets[stack[-1]] == s[0]:
76 del stack[-1]
77 else:
78 return False
79 elif s[0] in '"\'':
80 if stack and brackets[stack[-1]] == s[0]:
81 del stack[-1]
82 instring = False
83 else:
84 stack.append(s[0])
85 instring = True
86 else:
87 stack.append(s[0])
88 else:
89 if s[0] in '"\'' and stack and brackets[stack[-1]] == s[0]:
90 del stack[-1]
91 instring = False
92 s = s[1:]
93 return len(stack) == 0
94
95
96 def complete(self, line):
97 split_line = self.complete_sep.split(line)
98 possibilities = []
99 i = 0
100 c = self.completer.complete (split_line[-1], i)
101 while c:
102 possibilities.append(c)
103 i = i+1
104 c = self.completer.complete (split_line[-1], i)
105 if possibilities:
106 common_prefix = os.path.commonprefix (possibilities)
107 completed = line[:-len(split_line[-1])]+common_prefix
108 else:
109 completed = line
110 return completed, possibilities
111
112
113 def eval (self, console):
114 line = console.last_line()
115 console.write ('\n')
116 if line == '':
117 self.execute (console)
118 self.command = ''
119 self.prompt = sys.ps1
120 console.prompt('prompt')
121 return
122 self.command = self.command + line + '\n'
123 if not self.is_balanced (self.command):
124 self.prompt = sys.ps2
125 console.prompt('prompt')
126 return
127 line = line.rstrip()
128 if len(line) > 0:
129 if line[-1] == ':' or line[-1] == '\\' or line[0] in ' \11':
130 self.prompt = sys.ps2
131 console.prompt('prompt')
132 return
133 self.execute (console)
134 self.command = ''
135 self.prompt = sys.ps1
136 console.prompt('prompt')
137
138
139 def execute (self, console):
140 if not self.command:
141 return
142 try:
143 try:
144 r = eval (self.command, self.globals, self.locals)
145 if r is not None:
146 # System output (if any)
147 while True:
148 try:
149 buf = os.read(console.piperead, 256)
150 except:
151 break
152 else:
153 console.write (buf, 'output')
154 if len(buf) < 256: break
155 # Command output
156 print(repr(r))
157 except SyntaxError:
158 exec(str(self.command), self.globals)
159 except:
160 if hasattr (sys, 'last_type') and sys.last_type == SystemExit:
161 console.quit()
162 elif hasattr (sys, 'exc_type') and sys.exc_type == SystemExit:
163 console.quit()
164 else:
165 try:
166 tb = sys.exc_info()[2]
167 if tb:
168 tb=tb.tb_next
169 traceback.print_exception(sys.exc_info()[0], sys.exc_info()[1], tb)
170 except:
171 sys.stderr, console.stderr = console.stderr, sys.stderr
172 traceback.print_exc()
173
is_balanced(self, line)
Definition shell.py:57
__init__(self, ns_globals={}, ns_locals={})
Definition shell.py:43
execute(self, console)
Definition shell.py:139