##// END OF EJS Templates
Implement __call__ for LA
Ville M. Vainio -
Show More
@@ -1,244 +1,246 b''
1 """Shell mode for IPython.
1 """Shell mode for IPython.
2
2
3 Start ipython in shell mode by invoking "ipython -p sh"
3 Start ipython in shell mode by invoking "ipython -p sh"
4
4
5 (the old version, "ipython -p pysh" still works but this is the more "modern"
5 (the old version, "ipython -p pysh" still works but this is the more "modern"
6 shell mode and is recommended for users who don't care about pysh-mode
6 shell mode and is recommended for users who don't care about pysh-mode
7 compatibility)
7 compatibility)
8 """
8 """
9
9
10 from IPython import ipapi
10 from IPython import ipapi
11 import os,textwrap
11 import os,textwrap
12
12
13 # The import below effectively obsoletes your old-style ipythonrc[.ini],
13 # The import below effectively obsoletes your old-style ipythonrc[.ini],
14 # so consider yourself warned!
14 # so consider yourself warned!
15
15
16 import ipy_defaults
16 import ipy_defaults
17
17
18 def main():
18 def main():
19 ip = ipapi.get()
19 ip = ipapi.get()
20 o = ip.options
20 o = ip.options
21 # autocall to "full" mode (smart mode is default, I like full mode)
21 # autocall to "full" mode (smart mode is default, I like full mode)
22
22
23 o.autocall = 2
23 o.autocall = 2
24
24
25 # Jason Orendorff's path class is handy to have in user namespace
25 # Jason Orendorff's path class is handy to have in user namespace
26 # if you are doing shell-like stuff
26 # if you are doing shell-like stuff
27 try:
27 try:
28 ip.ex("from IPython.external.path import path" )
28 ip.ex("from IPython.external.path import path" )
29 except ImportError:
29 except ImportError:
30 pass
30 pass
31
31
32 # beefed up %env is handy in shell mode
32 # beefed up %env is handy in shell mode
33 import envpersist
33 import envpersist
34
34
35 # To see where mycmd resides (in path/aliases), do %which mycmd
35 # To see where mycmd resides (in path/aliases), do %which mycmd
36 import ipy_which
36 import ipy_which
37
37
38 # tab completers for hg, svn, ...
38 # tab completers for hg, svn, ...
39 import ipy_app_completers
39 import ipy_app_completers
40
40
41 # To make executables foo and bar in mybin usable without PATH change, do:
41 # To make executables foo and bar in mybin usable without PATH change, do:
42 # %rehashdir c:/mybin
42 # %rehashdir c:/mybin
43 # %store foo
43 # %store foo
44 # %store bar
44 # %store bar
45 import ipy_rehashdir
45 import ipy_rehashdir
46 import ipy_signals
46 import ipy_signals
47
47
48 ip.ex('import os')
48 ip.ex('import os')
49 ip.ex("def up(): os.chdir('..')")
49 ip.ex("def up(): os.chdir('..')")
50 ip.user_ns['LA'] = LastArgFinder()
50 ip.user_ns['LA'] = LastArgFinder()
51 # Nice prompt
51 # Nice prompt
52
52
53 o.prompt_in1= r'\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Green|\#> '
53 o.prompt_in1= r'\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Green|\#> '
54 o.prompt_in2= r'\C_Green|\C_LightGreen\D\C_Green> '
54 o.prompt_in2= r'\C_Green|\C_LightGreen\D\C_Green> '
55 o.prompt_out= '<\#> '
55 o.prompt_out= '<\#> '
56
56
57 from IPython import Release
57 from IPython import Release
58
58
59 import sys
59 import sys
60 # Non-chatty banner
60 # Non-chatty banner
61 o.banner = "IPython %s [on Py %s]\n" % (Release.version,sys.version.split(None,1)[0])
61 o.banner = "IPython %s [on Py %s]\n" % (Release.version,sys.version.split(None,1)[0])
62
62
63
63
64 ip.IP.default_option('cd','-q')
64 ip.IP.default_option('cd','-q')
65 ip.IP.default_option('macro', '-r')
65 ip.IP.default_option('macro', '-r')
66 # If you only rarely want to execute the things you %edit...
66 # If you only rarely want to execute the things you %edit...
67 #ip.IP.default_option('edit','-x')
67 #ip.IP.default_option('edit','-x')
68
68
69
69
70 o.prompts_pad_left="1"
70 o.prompts_pad_left="1"
71 # Remove all blank lines in between prompts, like a normal shell.
71 # Remove all blank lines in between prompts, like a normal shell.
72 o.separate_in="0"
72 o.separate_in="0"
73 o.separate_out="0"
73 o.separate_out="0"
74 o.separate_out2="0"
74 o.separate_out2="0"
75
75
76 # now alias all syscommands
76 # now alias all syscommands
77
77
78 db = ip.db
78 db = ip.db
79
79
80 syscmds = db.get("syscmdlist",[] )
80 syscmds = db.get("syscmdlist",[] )
81 if not syscmds:
81 if not syscmds:
82 print textwrap.dedent("""
82 print textwrap.dedent("""
83 System command list not initialized, probably the first run...
83 System command list not initialized, probably the first run...
84 running %rehashx to refresh the command list. Run %rehashx
84 running %rehashx to refresh the command list. Run %rehashx
85 again to refresh command list (after installing new software etc.)
85 again to refresh command list (after installing new software etc.)
86 """)
86 """)
87 ip.magic('rehashx')
87 ip.magic('rehashx')
88 syscmds = db.get("syscmdlist")
88 syscmds = db.get("syscmdlist")
89
89
90 # lowcase aliases on win32 only
90 # lowcase aliases on win32 only
91 if os.name == 'posix':
91 if os.name == 'posix':
92 mapper = lambda s:s
92 mapper = lambda s:s
93 else:
93 else:
94 def mapper(s): return s.lower()
94 def mapper(s): return s.lower()
95
95
96 for cmd in syscmds:
96 for cmd in syscmds:
97 # print "sys",cmd #dbg
97 # print "sys",cmd #dbg
98 noext, ext = os.path.splitext(cmd)
98 noext, ext = os.path.splitext(cmd)
99 key = mapper(noext)
99 key = mapper(noext)
100 if key not in ip.IP.alias_table:
100 if key not in ip.IP.alias_table:
101 ip.defalias(key, cmd)
101 ip.defalias(key, cmd)
102
102
103 # mglob combines 'find', recursion, exclusion... '%mglob?' to learn more
103 # mglob combines 'find', recursion, exclusion... '%mglob?' to learn more
104 ip.load("IPython.external.mglob")
104 ip.load("IPython.external.mglob")
105
105
106 # win32 is crippled w/o cygwin, try to help it a little bit
106 # win32 is crippled w/o cygwin, try to help it a little bit
107 if sys.platform == 'win32':
107 if sys.platform == 'win32':
108 if 'cygwin' in os.environ['PATH'].lower():
108 if 'cygwin' in os.environ['PATH'].lower():
109 # use the colors of cygwin ls (recommended)
109 # use the colors of cygwin ls (recommended)
110 ip.defalias('d', 'ls -F --color=auto')
110 ip.defalias('d', 'ls -F --color=auto')
111 else:
111 else:
112 # get icp, imv, imkdir, igrep, irm,...
112 # get icp, imv, imkdir, igrep, irm,...
113 ip.load('ipy_fsops')
113 ip.load('ipy_fsops')
114
114
115 # and the next best thing to real 'ls -F'
115 # and the next best thing to real 'ls -F'
116 ip.defalias('d','dir /w /og /on')
116 ip.defalias('d','dir /w /og /on')
117
117
118 extend_shell_behavior(ip)
118 extend_shell_behavior(ip)
119
119
120 class LastArgFinder:
120 class LastArgFinder:
121 """ Allow $LA to work as "last argument of previous command, like $! in bash
121 """ Allow $LA to work as "last argument of previous command", like $! in bash
122
122
123 To call this in normal IPython code, do str(LA).
123 To call this in normal IPython code, do LA()
124 """
124 """
125 def __call__(self):
126 return str(self)
125 def __str__(self):
127 def __str__(self):
126 ip = ipapi.get()
128 ip = ipapi.get()
127 for cmd in reversed(ip.IP.input_hist_raw):
129 for cmd in reversed(ip.IP.input_hist_raw):
128 parts = cmd.strip().split()
130 parts = cmd.strip().split()
129 if len(parts) < 2 or parts[-1] == '$LA':
131 if len(parts) < 2 or parts[-1] == '$LA':
130 continue
132 continue
131 return parts[-1]
133 return parts[-1]
132 return ""
134 return ""
133
135
134
136
135
137
136
138
137
139
138 # XXX You do not need to understand the next function!
140 # XXX You do not need to understand the next function!
139 # This should probably be moved out of profile
141 # This should probably be moved out of profile
140
142
141 def extend_shell_behavior(ip):
143 def extend_shell_behavior(ip):
142
144
143 # Instead of making signature a global variable tie it to IPSHELL.
145 # Instead of making signature a global variable tie it to IPSHELL.
144 # In future if it is required to distinguish between different
146 # In future if it is required to distinguish between different
145 # shells we can assign a signature per shell basis
147 # shells we can assign a signature per shell basis
146 ip.IP.__sig__ = 0xa005
148 ip.IP.__sig__ = 0xa005
147 # mark the IPSHELL with this signature
149 # mark the IPSHELL with this signature
148 ip.IP.user_ns['__builtins__'].__dict__['__sig__'] = ip.IP.__sig__
150 ip.IP.user_ns['__builtins__'].__dict__['__sig__'] = ip.IP.__sig__
149
151
150 from IPython.Itpl import ItplNS
152 from IPython.Itpl import ItplNS
151 from IPython.genutils import shell
153 from IPython.genutils import shell
152 # utility to expand user variables via Itpl
154 # utility to expand user variables via Itpl
153 # xxx do something sensible with depth?
155 # xxx do something sensible with depth?
154 ip.IP.var_expand = lambda cmd, lvars=None, depth=2: \
156 ip.IP.var_expand = lambda cmd, lvars=None, depth=2: \
155 str(ItplNS(cmd, ip.IP.user_ns, get_locals()))
157 str(ItplNS(cmd, ip.IP.user_ns, get_locals()))
156
158
157 def get_locals():
159 def get_locals():
158 """ Substituting a variable through Itpl deep inside the IPSHELL stack
160 """ Substituting a variable through Itpl deep inside the IPSHELL stack
159 requires the knowledge of all the variables in scope upto the last
161 requires the knowledge of all the variables in scope upto the last
160 IPSHELL frame. This routine simply merges all the local variables
162 IPSHELL frame. This routine simply merges all the local variables
161 on the IPSHELL stack without worrying about their scope rules
163 on the IPSHELL stack without worrying about their scope rules
162 """
164 """
163 import sys
165 import sys
164 # note lambda expression constitues a function call
166 # note lambda expression constitues a function call
165 # hence fno should be incremented by one
167 # hence fno should be incremented by one
166 getsig = lambda fno: sys._getframe(fno+1).f_globals \
168 getsig = lambda fno: sys._getframe(fno+1).f_globals \
167 ['__builtins__'].__dict__['__sig__']
169 ['__builtins__'].__dict__['__sig__']
168 getlvars = lambda fno: sys._getframe(fno+1).f_locals
170 getlvars = lambda fno: sys._getframe(fno+1).f_locals
169 # trackback until we enter the IPSHELL
171 # trackback until we enter the IPSHELL
170 frame_no = 1
172 frame_no = 1
171 sig = ip.IP.__sig__
173 sig = ip.IP.__sig__
172 fsig = ~sig
174 fsig = ~sig
173 while fsig != sig :
175 while fsig != sig :
174 try:
176 try:
175 fsig = getsig(frame_no)
177 fsig = getsig(frame_no)
176 except (AttributeError, KeyError):
178 except (AttributeError, KeyError):
177 frame_no += 1
179 frame_no += 1
178 except ValueError:
180 except ValueError:
179 # stack is depleted
181 # stack is depleted
180 # call did not originate from IPSHELL
182 # call did not originate from IPSHELL
181 return {}
183 return {}
182 first_frame = frame_no
184 first_frame = frame_no
183 # walk further back until we exit from IPSHELL or deplete stack
185 # walk further back until we exit from IPSHELL or deplete stack
184 try:
186 try:
185 while(sig == getsig(frame_no+1)):
187 while(sig == getsig(frame_no+1)):
186 frame_no += 1
188 frame_no += 1
187 except (AttributeError, KeyError, ValueError):
189 except (AttributeError, KeyError, ValueError):
188 pass
190 pass
189 # merge the locals from top down hence overriding
191 # merge the locals from top down hence overriding
190 # any re-definitions of variables, functions etc.
192 # any re-definitions of variables, functions etc.
191 lvars = {}
193 lvars = {}
192 for fno in range(frame_no, first_frame-1, -1):
194 for fno in range(frame_no, first_frame-1, -1):
193 lvars.update(getlvars(fno))
195 lvars.update(getlvars(fno))
194 #print '\n'*5, first_frame, frame_no, '\n', lvars, '\n'*5 #dbg
196 #print '\n'*5, first_frame, frame_no, '\n', lvars, '\n'*5 #dbg
195 return lvars
197 return lvars
196
198
197 def _runlines(lines):
199 def _runlines(lines):
198 """Run a string of one or more lines of source.
200 """Run a string of one or more lines of source.
199
201
200 This method is capable of running a string containing multiple source
202 This method is capable of running a string containing multiple source
201 lines, as if they had been entered at the IPython prompt. Since it
203 lines, as if they had been entered at the IPython prompt. Since it
202 exposes IPython's processing machinery, the given strings can contain
204 exposes IPython's processing machinery, the given strings can contain
203 magic calls (%magic), special shell access (!cmd), etc."""
205 magic calls (%magic), special shell access (!cmd), etc."""
204
206
205 # We must start with a clean buffer, in case this is run from an
207 # We must start with a clean buffer, in case this is run from an
206 # interactive IPython session (via a magic, for example).
208 # interactive IPython session (via a magic, for example).
207 ip.IP.resetbuffer()
209 ip.IP.resetbuffer()
208 lines = lines.split('\n')
210 lines = lines.split('\n')
209 more = 0
211 more = 0
210 command = ''
212 command = ''
211 for line in lines:
213 for line in lines:
212 # skip blank lines so we don't mess up the prompt counter, but do
214 # skip blank lines so we don't mess up the prompt counter, but do
213 # NOT skip even a blank line if we are in a code block (more is
215 # NOT skip even a blank line if we are in a code block (more is
214 # true)
216 # true)
215 # if command is not empty trim the line
217 # if command is not empty trim the line
216 if command != '' :
218 if command != '' :
217 line = line.strip()
219 line = line.strip()
218 # add the broken line to the command
220 # add the broken line to the command
219 if line and line[-1] == '\\' :
221 if line and line[-1] == '\\' :
220 command += line[0:-1] + ' '
222 command += line[0:-1] + ' '
221 more = True
223 more = True
222 continue
224 continue
223 else :
225 else :
224 # add the last (current) line to the command
226 # add the last (current) line to the command
225 command += line
227 command += line
226 if command or more:
228 if command or more:
227 # push to raw history, so hist line numbers stay in sync
229 # push to raw history, so hist line numbers stay in sync
228 ip.IP.input_hist_raw.append("# " + command + "\n")
230 ip.IP.input_hist_raw.append("# " + command + "\n")
229
231
230 more = ip.IP.push(ip.IP.prefilter(command,more))
232 more = ip.IP.push(ip.IP.prefilter(command,more))
231 command = ''
233 command = ''
232 # IPython's runsource returns None if there was an error
234 # IPython's runsource returns None if there was an error
233 # compiling the code. This allows us to stop processing right
235 # compiling the code. This allows us to stop processing right
234 # away, so the user gets the error message at the right place.
236 # away, so the user gets the error message at the right place.
235 if more is None:
237 if more is None:
236 break
238 break
237 # final newline in case the input didn't have it, so that the code
239 # final newline in case the input didn't have it, so that the code
238 # actually does get executed
240 # actually does get executed
239 if more:
241 if more:
240 ip.IP.push('\n')
242 ip.IP.push('\n')
241
243
242 ip.IP.runlines = _runlines
244 ip.IP.runlines = _runlines
243
245
244 main()
246 main()
General Comments 0
You need to be logged in to leave comments. Login now