##// END OF EJS Templates
check for both $LA and LA() in history crawling
Ville M. Vainio -
Show More
@@ -1,246 +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 121 """ Allow $LA to work as "last argument of previous command", like $! in bash
122 122
123 123 To call this in normal IPython code, do LA()
124 124 """
125 125 def __call__(self):
126 126 return str(self)
127 127 def __str__(self):
128 128 ip = ipapi.get()
129 129 for cmd in reversed(ip.IP.input_hist_raw):
130 130 parts = cmd.strip().split()
131 if len(parts) < 2 or parts[-1] == '$LA':
131 if len(parts) < 2 or parts[-1] in ['$LA', 'LA()']:
132 132 continue
133 133 return parts[-1]
134 134 return ""
135 135
136 136
137 137
138 138
139 139
140 140 # XXX You do not need to understand the next function!
141 141 # This should probably be moved out of profile
142 142
143 143 def extend_shell_behavior(ip):
144 144
145 145 # Instead of making signature a global variable tie it to IPSHELL.
146 146 # In future if it is required to distinguish between different
147 147 # shells we can assign a signature per shell basis
148 148 ip.IP.__sig__ = 0xa005
149 149 # mark the IPSHELL with this signature
150 150 ip.IP.user_ns['__builtins__'].__dict__['__sig__'] = ip.IP.__sig__
151 151
152 152 from IPython.Itpl import ItplNS
153 153 from IPython.genutils import shell
154 154 # utility to expand user variables via Itpl
155 155 # xxx do something sensible with depth?
156 156 ip.IP.var_expand = lambda cmd, lvars=None, depth=2: \
157 157 str(ItplNS(cmd, ip.IP.user_ns, get_locals()))
158 158
159 159 def get_locals():
160 160 """ Substituting a variable through Itpl deep inside the IPSHELL stack
161 161 requires the knowledge of all the variables in scope upto the last
162 162 IPSHELL frame. This routine simply merges all the local variables
163 163 on the IPSHELL stack without worrying about their scope rules
164 164 """
165 165 import sys
166 166 # note lambda expression constitues a function call
167 167 # hence fno should be incremented by one
168 168 getsig = lambda fno: sys._getframe(fno+1).f_globals \
169 169 ['__builtins__'].__dict__['__sig__']
170 170 getlvars = lambda fno: sys._getframe(fno+1).f_locals
171 171 # trackback until we enter the IPSHELL
172 172 frame_no = 1
173 173 sig = ip.IP.__sig__
174 174 fsig = ~sig
175 175 while fsig != sig :
176 176 try:
177 177 fsig = getsig(frame_no)
178 178 except (AttributeError, KeyError):
179 179 frame_no += 1
180 180 except ValueError:
181 181 # stack is depleted
182 182 # call did not originate from IPSHELL
183 183 return {}
184 184 first_frame = frame_no
185 185 # walk further back until we exit from IPSHELL or deplete stack
186 186 try:
187 187 while(sig == getsig(frame_no+1)):
188 188 frame_no += 1
189 189 except (AttributeError, KeyError, ValueError):
190 190 pass
191 191 # merge the locals from top down hence overriding
192 192 # any re-definitions of variables, functions etc.
193 193 lvars = {}
194 194 for fno in range(frame_no, first_frame-1, -1):
195 195 lvars.update(getlvars(fno))
196 196 #print '\n'*5, first_frame, frame_no, '\n', lvars, '\n'*5 #dbg
197 197 return lvars
198 198
199 199 def _runlines(lines):
200 200 """Run a string of one or more lines of source.
201 201
202 202 This method is capable of running a string containing multiple source
203 203 lines, as if they had been entered at the IPython prompt. Since it
204 204 exposes IPython's processing machinery, the given strings can contain
205 205 magic calls (%magic), special shell access (!cmd), etc."""
206 206
207 207 # We must start with a clean buffer, in case this is run from an
208 208 # interactive IPython session (via a magic, for example).
209 209 ip.IP.resetbuffer()
210 210 lines = lines.split('\n')
211 211 more = 0
212 212 command = ''
213 213 for line in lines:
214 214 # skip blank lines so we don't mess up the prompt counter, but do
215 215 # NOT skip even a blank line if we are in a code block (more is
216 216 # true)
217 217 # if command is not empty trim the line
218 218 if command != '' :
219 219 line = line.strip()
220 220 # add the broken line to the command
221 221 if line and line[-1] == '\\' :
222 222 command += line[0:-1] + ' '
223 223 more = True
224 224 continue
225 225 else :
226 226 # add the last (current) line to the command
227 227 command += line
228 228 if command or more:
229 229 # push to raw history, so hist line numbers stay in sync
230 230 ip.IP.input_hist_raw.append("# " + command + "\n")
231 231
232 232 more = ip.IP.push(ip.IP.prefilter(command,more))
233 233 command = ''
234 234 # IPython's runsource returns None if there was an error
235 235 # compiling the code. This allows us to stop processing right
236 236 # away, so the user gets the error message at the right place.
237 237 if more is None:
238 238 break
239 239 # final newline in case the input didn't have it, so that the code
240 240 # actually does get executed
241 241 if more:
242 242 ip.IP.push('\n')
243 243
244 244 ip.IP.runlines = _runlines
245 245
246 246 main()
General Comments 0
You need to be logged in to leave comments. Login now