##// END OF EJS Templates
pep8, second pass
Barry Wark -
Show More
@@ -2,7 +2,7 b''
2 # -*- test-case-name: IPython.frontend.cocoa.tests.test_cocoa_frontend -*-
2 # -*- test-case-name: IPython.frontend.cocoa.tests.test_cocoa_frontend -*-
3
3
4 """PyObjC classes to provide a Cocoa frontend to the
4 """PyObjC classes to provide a Cocoa frontend to the
5 IPython.kernel.engineservice.EngineService.
5 IPython.kernel.engineservice.IEngineBase.
6
6
7 To add an IPython interpreter to a cocoa app, instantiate an
7 To add an IPython interpreter to a cocoa app, instantiate an
8 IPythonCocoaController in a XIB and connect its textView outlet to an
8 IPythonCocoaController in a XIB and connect its textView outlet to an
@@ -37,7 +37,7 b' from AppKit import NSApplicationWillTerminateNotification, NSBeep,\\'
37 from pprint import saferepr
37 from pprint import saferepr
38
38
39 import IPython
39 import IPython
40 from IPython.kernel.engineservice import EngineService, ThreadedEngineService
40 from IPython.kernel.engineservice import ThreadedEngineService
41 from IPython.frontend.frontendbase import FrontEndBase
41 from IPython.frontend.frontendbase import FrontEndBase
42
42
43 from twisted.internet.threads import blockingCallFromThread
43 from twisted.internet.threads import blockingCallFromThread
@@ -77,7 +77,7 b' class IPythonCocoaController(NSObject, FrontEndBase):'
77 self.lines = {}
77 self.lines = {}
78 self.tabSpaces = 4
78 self.tabSpaces = 4
79 self.tabUsesSpaces = True
79 self.tabUsesSpaces = True
80 self.currentBlockID = self.nextBlockID()
80 self.currentBlockID = self.next_block_ID()
81 self.blockRanges = {} # blockID=>NSRange
81 self.blockRanges = {} # blockID=>NSRange
82
82
83
83
@@ -91,19 +91,21 b' class IPythonCocoaController(NSObject, FrontEndBase):'
91 NSLog('IPython engine started')
91 NSLog('IPython engine started')
92
92
93 # Register for app termination
93 # Register for app termination
94 NSNotificationCenter.defaultCenter().addObserver_selector_name_object_(
94 nc = NSNotificationCenter.defaultCenter()
95 self,
95 nc.addObserver_selector_name_object_(
96 'appWillTerminate:',
96 self,
97 NSApplicationWillTerminateNotification,
97 'appWillTerminate:',
98 None)
98 NSApplicationWillTerminateNotification,
99 None)
99
100
100 self.textView.setDelegate_(self)
101 self.textView.setDelegate_(self)
101 self.textView.enclosingScrollView().setHasVerticalRuler_(True)
102 self.textView.enclosingScrollView().setHasVerticalRuler_(True)
102 self.verticalRulerView = NSRulerView.alloc().initWithScrollView_orientation_(
103 r = NSRulerView.alloc().initWithScrollView_orientation_(
103 self.textView.enclosingScrollView(),
104 self.textView.enclosingScrollView(),
104 NSVerticalRuler)
105 NSVerticalRuler)
106 self.verticalRulerView = r
105 self.verticalRulerView.setClientView_(self.textView)
107 self.verticalRulerView.setClientView_(self.textView)
106 self.startCLIForTextView()
108 self._start_cli_banner()
107
109
108
110
109 def appWillTerminate_(self, notification):
111 def appWillTerminate_(self, notification):
@@ -121,7 +123,8 b' class IPythonCocoaController(NSObject, FrontEndBase):'
121
123
122 Result
124 Result
123 ------
125 ------
124 Deferred result of ipython1.kernel.engineservice.IEngineInteractive.complete
126 Deferred result of
127 IPython.kernel.engineservice.IEngineBase.complete
125 """
128 """
126
129
127 return self.engine.complete(token)
130 return self.engine.complete(token)
@@ -131,31 +134,31 b' class IPythonCocoaController(NSObject, FrontEndBase):'
131 self.waitingForEngine = True
134 self.waitingForEngine = True
132 self.willChangeValueForKey_('commandHistory')
135 self.willChangeValueForKey_('commandHistory')
133 d = super(IPythonCocoaController, self).execute(block, blockID)
136 d = super(IPythonCocoaController, self).execute(block, blockID)
134 d.addBoth(self._engineDone)
137 d.addBoth(self._engine_done)
135 d.addCallback(self._updateUserNS)
138 d.addCallback(self._update_user_ns)
136
139
137 return d
140 return d
138
141
139
142
140 def _engineDone(self, x):
143 def _engine_done(self, x):
141 self.waitingForEngine = False
144 self.waitingForEngine = False
142 self.didChangeValueForKey_('commandHistory')
145 self.didChangeValueForKey_('commandHistory')
143 return x
146 return x
144
147
145 def _updateUserNS(self, result):
148 def _update_user_ns(self, result):
146 """Update self.userNS from self.engine's namespace"""
149 """Update self.userNS from self.engine's namespace"""
147 d = self.engine.keys()
150 d = self.engine.keys()
148 d.addCallback(self._getEngineNamepsaceValuesForKeys)
151 d.addCallback(self._get_engine_namespace_values_for_keys)
149
152
150 return result
153 return result
151
154
152
155
153 def _getEngineNamepsaceValuesForKeys(self, keys):
156 def _get_engine_namespace_values_for_keys(self, keys):
154 d = self.engine.pull(keys)
157 d = self.engine.pull(keys)
155 d.addCallback(self._storeEngineNamespaceValues, keys=keys)
158 d.addCallback(self._store_engine_namespace_values, keys=keys)
156
159
157
160
158 def _storeEngineNamespaceValues(self, values, keys=[]):
161 def _store_engine_namespace_values(self, values, keys=[]):
159 assert(len(values) == len(keys))
162 assert(len(values) == len(keys))
160 self.willChangeValueForKey_('userNS')
163 self.willChangeValueForKey_('userNS')
161 for (k,v) in zip(keys,values):
164 for (k,v) in zip(keys,values):
@@ -163,7 +166,43 b' class IPythonCocoaController(NSObject, FrontEndBase):'
163 self.didChangeValueForKey_('userNS')
166 self.didChangeValueForKey_('userNS')
164
167
165
168
166 def startCLIForTextView(self):
169 def update_cell_prompt(self, result):
170 if(isinstance(result, Failure)):
171 blockID = result.blockID
172 else:
173 blockID = result['blockID']
174
175
176 self.insert_text(self.input_prompt(result=result),
177 textRange=NSMakeRange(self.blockRanges[blockID].location,0),
178 scrollToVisible=False
179 )
180
181 return result
182
183
184 def render_result(self, result):
185 blockID = result['blockID']
186 inputRange = self.blockRanges[blockID]
187 del self.blockRanges[blockID]
188
189 #print inputRange,self.current_block_range()
190 self.insert_text('\n' +
191 self.output_prompt(result) +
192 result.get('display',{}).get('pprint','') +
193 '\n\n',
194 textRange=NSMakeRange(inputRange.location+inputRange.length,
195 0))
196 return result
197
198
199 def render_error(self, failure):
200 self.insert_text('\n\n'+str(failure)+'\n\n')
201 self.start_new_block()
202 return failure
203
204
205 def _start_cli_banner(self):
167 """Print banner"""
206 """Print banner"""
168
207
169 banner = """IPython1 %s -- An enhanced Interactive Python.""" % \
208 banner = """IPython1 %s -- An enhanced Interactive Python.""" % \
@@ -171,14 +210,108 b' class IPythonCocoaController(NSObject, FrontEndBase):'
171
210
172 self.insert_text(banner + '\n\n')
211 self.insert_text(banner + '\n\n')
173
212
174 # NSTextView/IPythonTextView delegate methods
213
214 def start_new_block(self):
215 """"""
216
217 self.currentBlockID = self.next_block_ID()
218
219
220
221 def next_block_ID(self):
222
223 return uuid.uuid4()
224
225 def current_block_range(self):
226 return self.blockRanges.get(self.currentBlockID,
227 NSMakeRange(self.textView.textStorage().length(),
228 0))
229
230 def currentBlock(self):
231 """The current block's text"""
232
233 return self.textForRange(self.current_block_range())
234
235 def textForRange(self, textRange):
236 """textForRange"""
237
238 ts = self.textView.textStorage()
239 return ts.string().substringWithRange_(textRange)
240
241 def currentLine(self):
242 block = self.textForRange(self.current_block_range())
243 block = block.split('\n')
244 return block[-1]
245
246
247 def insert_text(self, string=None, textRange=None, scrollToVisible=True):
248 """Insert text into textView at textRange, updating blockRanges
249 as necessary
250 """
251
252 if(textRange == None):
253 #range for end of text
254 textRange = NSMakeRange(self.textView.textStorage().length(), 0)
255
256 for r in self.blockRanges.itervalues():
257 intersection = NSIntersectionRange(r,textRange)
258 if(intersection.length == 0): #ranges don't intersect
259 if r.location >= textRange.location:
260 r.location += len(string)
261 else: #ranges intersect
262 if(r.location <= textRange.location):
263 assert(intersection.length == textRange.length)
264 r.length += textRange.length
265 else:
266 r.location += intersection.length
267
268 self.textView.replaceCharactersInRange_withString_(
269 textRange, string)
270 self.textView.setSelectedRange_(
271 NSMakeRange(textRange.location+len(string), 0))
272 if(scrollToVisible):
273 self.textView.scrollRangeToVisible_(textRange)
274
275
276
277
278 def replace_current_block_with_string(self, textView, string):
279 textView.replaceCharactersInRange_withString_(
280 self.current_block_range(),
281 string)
282 self.current_block_range().length = len(string)
283 r = NSMakeRange(textView.textStorage().length(), 0)
284 textView.scrollRangeToVisible_(r)
285 textView.setSelectedRange_(r)
286
287
288 def current_indent_string(self):
289 """returns string for indent or None if no indent"""
290
291 if(len(self.currentBlock()) > 0):
292 lines = self.currentBlock().split('\n')
293 currentIndent = len(lines[-1]) - len(lines[-1])
294 if(currentIndent == 0):
295 currentIndent = self.tabSpaces
296
297 if(self.tabUsesSpaces):
298 result = ' ' * currentIndent
299 else:
300 result = '\t' * (currentIndent/self.tabSpaces)
301 else:
302 result = None
303
304 return result
305
306
307 # NSTextView delegate methods...
175 def textView_doCommandBySelector_(self, textView, selector):
308 def textView_doCommandBySelector_(self, textView, selector):
176 assert(textView == self.textView)
309 assert(textView == self.textView)
177 NSLog("textView_doCommandBySelector_: "+selector)
310 NSLog("textView_doCommandBySelector_: "+selector)
178
311
179
312
180 if(selector == 'insertNewline:'):
313 if(selector == 'insertNewline:'):
181 indent = self.currentIndentString()
314 indent = self.current_indent_string()
182 if(indent):
315 if(indent):
183 line = indent + self.currentLine()
316 line = indent + self.currentLine()
184 else:
317 else:
@@ -187,7 +320,7 b' class IPythonCocoaController(NSObject, FrontEndBase):'
187 if(self.is_complete(self.currentBlock())):
320 if(self.is_complete(self.currentBlock())):
188 self.execute(self.currentBlock(),
321 self.execute(self.currentBlock(),
189 blockID=self.currentBlockID)
322 blockID=self.currentBlockID)
190 self.startNewBlock()
323 self.start_new_block()
191
324
192 return True
325 return True
193
326
@@ -196,7 +329,7 b' class IPythonCocoaController(NSObject, FrontEndBase):'
196 elif(selector == 'moveUp:'):
329 elif(selector == 'moveUp:'):
197 prevBlock = self.get_history_previous(self.currentBlock())
330 prevBlock = self.get_history_previous(self.currentBlock())
198 if(prevBlock != None):
331 if(prevBlock != None):
199 self.replaceCurrentBlockWithString(textView, prevBlock)
332 self.replace_current_block_with_string(textView, prevBlock)
200 else:
333 else:
201 NSBeep()
334 NSBeep()
202 return True
335 return True
@@ -204,30 +337,30 b' class IPythonCocoaController(NSObject, FrontEndBase):'
204 elif(selector == 'moveDown:'):
337 elif(selector == 'moveDown:'):
205 nextBlock = self.get_history_next()
338 nextBlock = self.get_history_next()
206 if(nextBlock != None):
339 if(nextBlock != None):
207 self.replaceCurrentBlockWithString(textView, nextBlock)
340 self.replace_current_block_with_string(textView, nextBlock)
208 else:
341 else:
209 NSBeep()
342 NSBeep()
210 return True
343 return True
211
344
212 elif(selector == 'moveToBeginningOfParagraph:'):
345 elif(selector == 'moveToBeginningOfParagraph:'):
213 textView.setSelectedRange_(NSMakeRange(
346 textView.setSelectedRange_(NSMakeRange(
214 self.currentBlockRange().location,
347 self.current_block_range().location,
215 0))
348 0))
216 return True
349 return True
217 elif(selector == 'moveToEndOfParagraph:'):
350 elif(selector == 'moveToEndOfParagraph:'):
218 textView.setSelectedRange_(NSMakeRange(
351 textView.setSelectedRange_(NSMakeRange(
219 self.currentBlockRange().location + \
352 self.current_block_range().location + \
220 self.currentBlockRange().length, 0))
353 self.current_block_range().length, 0))
221 return True
354 return True
222 elif(selector == 'deleteToEndOfParagraph:'):
355 elif(selector == 'deleteToEndOfParagraph:'):
223 if(textView.selectedRange().location <= \
356 if(textView.selectedRange().location <= \
224 self.currentBlockRange().location):
357 self.current_block_range().location):
225 # Intersect the selected range with the current line range
358 # Intersect the selected range with the current line range
226 if(self.currentBlockRange().length < 0):
359 if(self.current_block_range().length < 0):
227 self.blockRanges[self.currentBlockID].length = 0
360 self.blockRanges[self.currentBlockID].length = 0
228
361
229 r = NSIntersectionRange(textView.rangesForUserTextChange()[0],
362 r = NSIntersectionRange(textView.rangesForUserTextChange()[0],
230 self.currentBlockRange())
363 self.current_block_range())
231
364
232 if(r.length > 0): #no intersection
365 if(r.length > 0): #no intersection
233 textView.setSelectedRange_(r)
366 textView.setSelectedRange_(r)
@@ -244,10 +377,10 b' class IPythonCocoaController(NSObject, FrontEndBase):'
244 elif(selector == 'deleteBackward:'):
377 elif(selector == 'deleteBackward:'):
245 #if we're at the beginning of the current block, ignore
378 #if we're at the beginning of the current block, ignore
246 if(textView.selectedRange().location == \
379 if(textView.selectedRange().location == \
247 self.currentBlockRange().location):
380 self.current_block_range().location):
248 return True
381 return True
249 else:
382 else:
250 self.currentBlockRange().length-=1
383 self.current_block_range().length-=1
251 return False
384 return False
252 return False
385 return False
253
386
@@ -266,13 +399,13 b' class IPythonCocoaController(NSObject, FrontEndBase):'
266 for r,s in zip(ranges, replacementStrings):
399 for r,s in zip(ranges, replacementStrings):
267 r = r.rangeValue()
400 r = r.rangeValue()
268 if(textView.textStorage().length() > 0 and
401 if(textView.textStorage().length() > 0 and
269 r.location < self.currentBlockRange().location):
402 r.location < self.current_block_range().location):
270 self.insert_text(s)
403 self.insert_text(s)
271 allow = False
404 allow = False
272
405
273
406
274 self.blockRanges.setdefault(self.currentBlockID,
407 self.blockRanges.setdefault(self.currentBlockID,
275 self.currentBlockRange()).length +=\
408 self.current_block_range()).length +=\
276 len(s)
409 len(s)
277
410
278 return allow
411 return allow
@@ -289,127 +422,4 b' class IPythonCocoaController(NSObject, FrontEndBase):'
289
422
290 return (completions,0)
423 return (completions,0)
291
424
292
293 def startNewBlock(self):
294 """"""
295
296 self.currentBlockID = self.nextBlockID()
297
298
299
300 def nextBlockID(self):
301
302 return uuid.uuid4()
303
304 def currentBlockRange(self):
305 return self.blockRanges.get(self.currentBlockID,
306 NSMakeRange(self.textView.textStorage().length(),
307 0))
308
309 def currentBlock(self):
310 """The current block's text"""
311
312 return self.textForRange(self.currentBlockRange())
313
314 def textForRange(self, textRange):
315 """textForRange"""
316
317 ts = self.textView.textStorage()
318 return ts.string().substringWithRange_(textRange)
319
320 def currentLine(self):
321 block = self.textForRange(self.currentBlockRange())
322 block = block.split('\n')
323 return block[-1]
324
325 def update_cell_prompt(self, result):
326 if(isinstance(result, Failure)):
327 blockID = result.blockID
328 else:
329 blockID = result['blockID']
330
331
332 self.insert_text(self.input_prompt(result=result),
333 textRange=NSMakeRange(self.blockRanges[blockID].location,0),
334 scrollToVisible=False
335 )
336
337 return result
338
339
340 def render_result(self, result):
341 blockID = result['blockID']
342 inputRange = self.blockRanges[blockID]
343 del self.blockRanges[blockID]
344
345 #print inputRange,self.currentBlockRange()
346 self.insert_text('\n' +
347 self.output_prompt(result) +
348 result.get('display',{}).get('pprint','') +
349 '\n\n',
350 textRange=NSMakeRange(inputRange.location+inputRange.length,
351 0))
352 return result
353
354
355 def render_error(self, failure):
356 self.insert_text('\n\n'+str(failure)+'\n\n')
357 self.startNewBlock()
358 return failure
359
360
361 def insert_text(self, string=None, textRange=None, scrollToVisible=True):
362 """Insert text into textView at textRange, updating blockRanges
363 as necessary
364 """
365
366 if(textRange == None):
367 textRange = NSMakeRange(self.textView.textStorage().length(), 0) #range for end of text
368
369 for r in self.blockRanges.itervalues():
370 intersection = NSIntersectionRange(r,textRange)
371 if(intersection.length == 0): #ranges don't intersect
372 if r.location >= textRange.location:
373 r.location += len(string)
374 else: #ranges intersect
375 if(r.location <= textRange.location):
376 assert(intersection.length == textRange.length)
377 r.length += textRange.length
378 else:
379 r.location += intersection.length
380
381 self.textView.replaceCharactersInRange_withString_(textRange, string) #textStorage().string()
382 self.textView.setSelectedRange_(NSMakeRange(textRange.location+len(string), 0))
383 if(scrollToVisible):
384 self.textView.scrollRangeToVisible_(textRange)
385
386
387
388 def replaceCurrentBlockWithString(self, textView, string):
389 textView.replaceCharactersInRange_withString_(self.currentBlockRange(),
390 string)
391 self.currentBlockRange().length = len(string)
392 r = NSMakeRange(textView.textStorage().length(), 0)
393 textView.scrollRangeToVisible_(r)
394 textView.setSelectedRange_(r)
395
396
397 def currentIndentString(self):
398 """returns string for indent or None if no indent"""
399
400 if(len(self.currentBlock()) > 0):
401 lines = self.currentBlock().split('\n')
402 currentIndent = len(lines[-1]) - len(lines[-1])
403 if(currentIndent == 0):
404 currentIndent = self.tabSpaces
405
406 if(self.tabUsesSpaces):
407 result = ' ' * currentIndent
408 else:
409 result = '\t' * (currentIndent/self.tabSpaces)
410 else:
411 result = None
412
413 return result
414
415
425
General Comments 0
You need to be logged in to leave comments. Login now