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