mwxlib 0.97.7__py3-none-any.whl → 0.98.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mwxlib might be problematic. Click here for more details.

mwx/framework.py CHANGED
@@ -1,7 +1,7 @@
1
1
  #! python3
2
2
  """mwxlib framework.
3
3
  """
4
- __version__ = "0.97.7"
4
+ __version__ = "0.98.1"
5
5
  __author__ = "Kazuya O'moto <komoto@jeol.co.jp>"
6
6
 
7
7
  from contextlib import contextmanager
@@ -78,11 +78,12 @@ def postcall(f):
78
78
 
79
79
  @contextmanager
80
80
  def save_focus_excursion():
81
+ """Save window focus excursion."""
81
82
  wnd = wx.Window.FindFocus() # original focus
82
83
  try:
83
84
  yield wnd
84
85
  finally:
85
- if wnd:
86
+ if wnd and wnd.IsShownOnScreen():
86
87
  wnd.SetFocus() # restore focus
87
88
 
88
89
 
mwx/nutshell.py CHANGED
@@ -71,11 +71,296 @@ def ask(f, prompt="Enter value", type=str):
71
71
  return _f
72
72
 
73
73
 
74
+ class AutoCompInterfaceMixin:
75
+ """Auto-complete mode interface.
76
+
77
+ Mode name Mode vars.
78
+ --------------------------------
79
+ [1] history-comp history (an instance variable of the Shell)
80
+ [2] word-comp -
81
+ [3] apropos-comp -
82
+ [4] text-comp fragmwords
83
+ [5] module-comp modules
84
+
85
+ Note:
86
+ This class is mixed-in ``wx.py.editwindow.EditWindow``.
87
+ """
88
+ history = [] # used in history-comp mode
89
+ modules = set() # used in module-comp mode
90
+ fragmwords = set(keyword.kwlist + dir(builtins)) # used in text-comp mode
91
+
92
+ def __init__(self):
93
+ ## cf. sys.modules
94
+ if not self.modules:
95
+ force = wx.GetKeyState(wx.WXK_CONTROL)\
96
+ & wx.GetKeyState(wx.WXK_SHIFT)
97
+ AutoCompInterfaceMixin.modules = set(find_modules(force))
98
+
99
+ def CallTipShow(self, pos, tip, N=11):
100
+ """Show a call tip containing a definition near position pos.
101
+
102
+ (override) Snip the tip of max N lines if it is too long.
103
+ Keep the tip for calltip-click event.
104
+ """
105
+ self._calltips = (pos, tip)
106
+ lines = tip.splitlines()
107
+ if N and len(lines) > N > 0:
108
+ lines[N+1:] = ["\n...(snip) This tips are too long... "
109
+ "Click to show more details."]
110
+ tip = '\n'.join(lines)
111
+ super().CallTipShow(pos, tip)
112
+
113
+ def autoCallTipShow(self, command, insertcalltip=True):
114
+ """Display argument spec and docstring in a popup window."""
115
+ if self.CallTipActive():
116
+ self.CallTipCancel()
117
+
118
+ name, argspec, tip = introspect.getCallTip(command, locals=self.locals)
119
+ if tip:
120
+ dispatcher.send(signal='Shell.calltip', sender=self, calltip=tip)
121
+ p = self.cpos
122
+ if argspec and insertcalltip:
123
+ self.AddText(argspec + ')') # 挿入後のカーソル位置は変化しない
124
+ self.SetSelection(self.cpos, p) # selection back
125
+ if tip:
126
+ ## In case there isn't enough room, only go back to bol fallback.
127
+ tippos = max(self.bol, p - len(name) - 1)
128
+ self.CallTipShow(tippos, tip)
129
+
130
+ def call_helpDoc(self, evt):
131
+ """Show help:str for the selected topic."""
132
+ if self.CallTipActive():
133
+ self.CallTipCancel()
134
+
135
+ text = next(self.gen_text_at_caret(), None)
136
+ if text:
137
+ text = introspect.getRoot(text, terminator='(')
138
+ try:
139
+ obj = self.eval(text)
140
+ self.help(obj)
141
+ except Exception as e:
142
+ self.message("- {} : {!r}".format(e, text))
143
+
144
+ def call_helpTip(self, evt):
145
+ """Show tooltips for the selected topic."""
146
+ if self.CallTipActive():
147
+ self.CallTipCancel()
148
+
149
+ text = next(self.gen_text_at_caret(), None)
150
+ if text:
151
+ p = self.cpos
152
+ self.autoCallTipShow(text,
153
+ p == self.eol and self.get_char(p-1) == '(') # => CallTipShow
154
+
155
+ def on_completion_forward(self, evt):
156
+ if not self.AutoCompActive():
157
+ self.handler('quit', evt)
158
+ return
159
+ self._on_completion(1)
160
+
161
+ def on_completion_backward(self, evt):
162
+ if not self.AutoCompActive():
163
+ self.handler('quit', evt)
164
+ return
165
+ self._on_completion(-1)
166
+
167
+ def _on_completion(self, step=0):
168
+ """Show completion with selection."""
169
+ try:
170
+ N = len(self.__comp_words)
171
+ j = self.__comp_ind + step
172
+ j = 0 if j < 0 else j if j < N else N-1
173
+ word = self.__comp_words[j]
174
+ n = len(self.__comp_hint)
175
+ p = self.cpos
176
+ if not self.SelectedText:
177
+ p, self.anchor, sty = self.get_following_atom(p) # word-right-selection
178
+ self.ReplaceSelection(word[n:]) # Modify (or insert) the selected range
179
+ self.cpos = p # backward selection to the point
180
+ self.__comp_ind = j
181
+ except IndexError:
182
+ self.message("No completion words")
183
+
184
+ def _gen_autocomp(self, j, hint, words, sep=' ', mode=True):
185
+ ## Prepare on_completion_forward/backward
186
+ self.__comp_ind = j
187
+ self.__comp_hint = hint
188
+ self.__comp_words = words
189
+ if not mode:
190
+ self.anchor = self.eolc # selection to eol
191
+ self._on_completion() # show completion always
192
+ elif words:
193
+ self.AutoCompSetSeparator(ord(sep))
194
+ self.AutoCompShow(len(hint), sep.join(words))
195
+
196
+ def _get_words_hint(self):
197
+ cmdl = self.GetTextRange(self.bol, self.cpos)
198
+ text = next(split_words(cmdl, reverse=1), '')
199
+ return text.rpartition('.') # -> text, sep, hint
200
+
201
+ def call_history_comp(self, evt):
202
+ """Called when history-comp mode."""
203
+ if not self.CanEdit():
204
+ self.handler('quit', evt)
205
+ return
206
+
207
+ cmdl = self.GetTextRange(self.bol, self.cpos)
208
+ if cmdl.isspace() or self.bol != self.bolc:
209
+ self.handler('skip', evt) # [tab pressed] => on_indent_line
210
+ return
211
+
212
+ hint = cmdl.strip()
213
+ ls = [x.replace('\n', os.linesep + sys.ps2)
214
+ for x in self.history if x.startswith(hint)] # case-sensitive match
215
+ words = sorted(set(ls), key=ls.index, reverse=0) # keep order, no duplication
216
+
217
+ ## the latest history stacks in the head of the list (time-descending)
218
+ self._gen_autocomp(0, hint, words, mode=False)
219
+ self.message("[history] {} candidates matched"
220
+ " with {!r}".format(len(words), hint))
221
+
222
+ def call_text_autocomp(self, evt):
223
+ """Called when text-comp mode."""
224
+ if not self.CanEdit():
225
+ self.handler('quit', evt)
226
+ return
227
+
228
+ cmdl = self.GetTextRange(self.bol, self.cpos)
229
+ hint = re.search(r"[\w.]*$", cmdl).group(0) # extract the last word
230
+
231
+ ls = [x for x in self.fragmwords if x.startswith(hint)] # case-sensitive match
232
+ words = sorted(ls, key=lambda s:s.upper())
233
+
234
+ self._gen_autocomp(0, hint, words)
235
+ self.message("[text] {} candidates matched"
236
+ " with {!r}".format(len(words), hint))
237
+
238
+ def call_module_autocomp(self, evt, force=False):
239
+ """Called when module-comp mode."""
240
+ if not self.CanEdit():
241
+ self.handler('quit', evt)
242
+ return
243
+
244
+ def _continue(hints):
245
+ if not hints.endswith(' '):
246
+ h = hints.strip()
247
+ if not h.endswith(','):
248
+ lh = h.split(',')[-1].strip() # 'x, y, z|' last hint after ','
249
+ if ' ' not in lh: # 'x, y as|' contains no spaces.
250
+ return lh
251
+
252
+ cmdl = self.GetTextRange(self.bol, self.cpos)
253
+ hint = re.search(r"[\w.]*$", cmdl).group(0) # extract the last word
254
+ try:
255
+ if (m := re.match(r"from\s+([\w.]+)\s+import\s+(.*)", cmdl)):
256
+ text, hints = m.groups()
257
+ if not _continue(hints) and not force:
258
+ self.message("[module]>>> waiting for key input...")
259
+ return
260
+ elif '.' in hints:
261
+ self.message("[module] invalid syntax.")
262
+ return
263
+ try:
264
+ self.message("[module]>>> loading {}...".format(text))
265
+ modules = set(dir(import_module(text)))
266
+ except ImportError as e:
267
+ self.message("\b failed:", e)
268
+ return
269
+ else:
270
+ ## Add unimported module names.
271
+ p = "{}.{}".format(text, hint)
272
+ keys = [x[len(text)+1:] for x in self.modules if x.startswith(p)]
273
+ modules.update(k for k in keys if '.' not in k)
274
+
275
+ elif (m := re.match(r"(import|from)\s+(.*)", cmdl)):
276
+ text, hints = m.groups()
277
+ if not _continue(hints) and not force:
278
+ self.message("[module]>>> waiting for key input...")
279
+ return
280
+ modules = self.modules
281
+ else:
282
+ text, sep, hint = self._get_words_hint()
283
+ obj = self.eval(text)
284
+ modules = set(k for k, v in vars(obj).items() if inspect.ismodule(v))
285
+
286
+ P = re.compile(hint)
287
+ p = re.compile(hint, re.I)
288
+ words = sorted([x for x in modules if p.match(x)], key=lambda s:s.upper())
289
+
290
+ j = next((k for k, w in enumerate(words) if P.match(w)),
291
+ next((k for k, w in enumerate(words) if p.match(w)), -1))
292
+
293
+ self._gen_autocomp(j, hint, words)
294
+ self.message("[module] {} candidates matched"
295
+ " with {!r} in {}".format(len(words), hint, text))
296
+ except re.error as e:
297
+ self.message("- re:miss compilation {!r} : {!r}".format(e, hint))
298
+ except SyntaxError as e:
299
+ self.handler('quit', evt)
300
+ self.message("- {} : {!r}".format(e, text))
301
+ except Exception as e:
302
+ self.message("- {} : {!r}".format(e, text))
303
+
304
+ def call_word_autocomp(self, evt):
305
+ """Called when word-comp mode."""
306
+ if not self.CanEdit():
307
+ self.handler('quit', evt)
308
+ return
309
+ try:
310
+ text, sep, hint = self._get_words_hint()
311
+ obj = self.eval(text)
312
+
313
+ P = re.compile(hint)
314
+ p = re.compile(hint, re.I)
315
+ words = sorted([x for x in dir(obj) if p.match(x)], key=lambda s:s.upper())
316
+
317
+ j = next((k for k, w in enumerate(words) if P.match(w)),
318
+ next((k for k, w in enumerate(words) if p.match(w)), -1))
319
+
320
+ self._gen_autocomp(j, hint, words)
321
+ self.message("[word] {} candidates matched"
322
+ " with {!r} in {}".format(len(words), hint, text))
323
+ except re.error as e:
324
+ self.message("- re:miss compilation {!r} : {!r}".format(e, hint))
325
+ except SyntaxError as e:
326
+ self.handler('quit', evt)
327
+ self.message("- {} : {!r}".format(e, text))
328
+ except Exception as e:
329
+ self.message("- {} : {!r}".format(e, text))
330
+
331
+ def call_apropos_autocomp(self, evt):
332
+ """Called when apropos mode."""
333
+ if not self.CanEdit():
334
+ self.handler('quit', evt)
335
+ return
336
+ try:
337
+ text, sep, hint = self._get_words_hint()
338
+ obj = self.eval(text)
339
+
340
+ P = re.compile(hint)
341
+ p = re.compile(hint, re.I)
342
+ words = sorted([x for x in dir(obj) if p.search(x)], key=lambda s:s.upper())
343
+
344
+ j = next((k for k, w in enumerate(words) if P.match(w)),
345
+ next((k for k, w in enumerate(words) if p.match(w)), -1))
346
+
347
+ self._gen_autocomp(j, hint, words)
348
+ self.message("[apropos] {} candidates matched"
349
+ " with {!r} in {}".format(len(words), hint, text))
350
+ except re.error as e:
351
+ self.message("- re:miss compilation {!r} : {!r}".format(e, hint))
352
+ except SyntaxError as e:
353
+ self.handler('quit', evt)
354
+ self.message("- {} : {!r}".format(e, text))
355
+ except Exception as e:
356
+ self.message("- {} : {!r}".format(e, text))
357
+
358
+
74
359
  class EditorInterface(CtrlInterface):
75
360
  """Interface of Python code editor.
76
361
 
77
362
  Note:
78
- This class should be mixed-in `wx.stc.StyledTextCtrl`
363
+ This class is mixed-in ``wx.stc.StyledTextCtrl``.
79
364
  """
80
365
  def __init__(self):
81
366
  CtrlInterface.__init__(self)
@@ -538,7 +823,7 @@ class EditorInterface(CtrlInterface):
538
823
  return (self.cpos - lp + len(text.encode()))
539
824
 
540
825
  @property
541
- def caretline(self):
826
+ def line_at_caret(self):
542
827
  """Text of the range (bol, eol) at the caret-line."""
543
828
  return self.GetTextRange(self.bol, self.eol)
544
829
 
@@ -586,6 +871,19 @@ class EditorInterface(CtrlInterface):
586
871
  q = self.cpos
587
872
  return self.GetTextRange(p, q)
588
873
 
874
+ def gen_text_at_caret(self):
875
+ """Generates the selected text,
876
+ otherwise the line or expression at the caret.
877
+ """
878
+ def _gen_text():
879
+ text = self.SelectedText
880
+ if text:
881
+ yield text
882
+ else:
883
+ yield self.line_at_caret
884
+ yield self.expr_at_caret
885
+ return filter(None, _gen_text())
886
+
589
887
  ## --------------------------------
590
888
  ## Python syntax and indentation
591
889
  ## --------------------------------
@@ -604,24 +902,26 @@ class EditorInterface(CtrlInterface):
604
902
  @can_edit
605
903
  def py_indent_line(self):
606
904
  """Indent the current line."""
607
- text = self.caretline # w/ no-prompt
608
- lstr = text.lstrip() # w/ no-indent
609
- p = self.bol + len(text) - len(lstr) # for multi-byte string
905
+ text = self.line_at_caret # w/ no-prompt
906
+ lstr = text.lstrip() # w/ no-indent
907
+ p = self.bol + len(text) - len(lstr)
610
908
  offset = max(0, self.cpos - p)
611
909
  indent = self.py_current_indent() # check current/previous line
612
- self.Replace(self.bol, p, ' '*indent)
613
- self.goto_char(self.bol + indent + offset)
910
+ if indent >= 0:
911
+ self.Replace(self.bol, p, ' '*indent)
912
+ self.goto_char(self.bol + indent + offset)
614
913
 
615
914
  @can_edit
616
915
  def py_outdent_line(self):
617
916
  """Outdent the current line."""
618
- text = self.caretline # w/ no-prompt
619
- lstr = text.lstrip() # w/ no-indent
620
- p = self.bol + len(text) - len(lstr) # for multi-byte string
917
+ text = self.line_at_caret # w/ no-prompt
918
+ lstr = text.lstrip() # w/ no-indent
919
+ p = self.bol + len(text) - len(lstr)
621
920
  offset = max(0, self.cpos - p)
622
921
  indent = len(text) - len(lstr) - 4
623
- self.Replace(self.bol, p, ' '*indent)
624
- self.goto_char(self.bol + indent + offset)
922
+ if indent >= 0:
923
+ self.Replace(self.bol, p, ' '*indent)
924
+ self.goto_char(self.bol + indent + offset)
625
925
 
626
926
  def py_current_indent(self):
627
927
  """Calculate indent spaces from previous line."""
@@ -1146,9 +1446,9 @@ class EditorInterface(CtrlInterface):
1146
1446
  self.goto_char(p)
1147
1447
 
1148
1448
  def back_to_indentation(self):
1149
- text = self.caretline # w/ no-prompt
1150
- lstr = text.lstrip() # w/ no-indent
1151
- p = self.bol + len(text) - len(lstr) # for multi-byte string
1449
+ text = self.line_at_caret # w/ no-prompt
1450
+ lstr = text.lstrip() # w/ no-indent
1451
+ p = self.bol + len(text) - len(lstr)
1152
1452
  self.goto_char(p, interactive=True)
1153
1453
  self.ScrollToColumn(0)
1154
1454
 
@@ -1191,13 +1491,11 @@ class EditorInterface(CtrlInterface):
1191
1491
  """Save buffer excursion."""
1192
1492
  try:
1193
1493
  p = self.cpos
1194
- q = self.anchor
1195
1494
  vpos = self.GetScrollPos(wx.VERTICAL)
1196
1495
  hpos = self.GetScrollPos(wx.HORIZONTAL)
1197
1496
  yield
1198
1497
  finally:
1199
1498
  self.GotoPos(p)
1200
- self.SetAnchor(q)
1201
1499
  self.ScrollToLine(vpos)
1202
1500
  self.SetXOffset(hpos)
1203
1501
 
@@ -1336,13 +1634,13 @@ class EditorInterface(CtrlInterface):
1336
1634
  _text, lp = self.CurLine
1337
1635
  for i in range(lp % 4 or 4):
1338
1636
  p = self.cpos
1339
- if self.get_char(p-1) != ' ' or p == self.bol:
1637
+ if p == self.bol or self.get_char(p-1) != ' ':
1340
1638
  break
1341
1639
  self.cpos = p-1
1342
1640
  self.ReplaceSelection('')
1343
1641
 
1344
1642
 
1345
- class Buffer(EditWindow, EditorInterface):
1643
+ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
1346
1644
  """Python code buffer.
1347
1645
 
1348
1646
  Attributes:
@@ -1468,6 +1766,7 @@ class Buffer(EditWindow, EditorInterface):
1468
1766
  def __init__(self, parent, filename=None, **kwargs):
1469
1767
  EditWindow.__init__(self, parent, **kwargs)
1470
1768
  EditorInterface.__init__(self)
1769
+ AutoCompInterfaceMixin.__init__(self)
1471
1770
 
1472
1771
  self.parent = parent
1473
1772
  self.__filename = filename
@@ -1475,7 +1774,7 @@ class Buffer(EditWindow, EditorInterface):
1475
1774
  self.code = None
1476
1775
 
1477
1776
  self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdate) # skip to brace matching
1478
-
1777
+ self.Bind(stc.EVT_STC_CALLTIP_CLICK, self.OnCallTipClick)
1479
1778
  self.Bind(stc.EVT_STC_INDICATOR_CLICK, self.OnIndicatorClick)
1480
1779
 
1481
1780
  self.Bind(stc.EVT_STC_SAVEPOINTLEFT, self.OnSavePointLeft)
@@ -1493,6 +1792,26 @@ class Buffer(EditWindow, EditorInterface):
1493
1792
  evt.Skip()
1494
1793
  self.Bind(wx.EVT_KILL_FOCUS, inactivate)
1495
1794
 
1795
+ def clear(evt):
1796
+ ## """Clear selection and message, no skip."""
1797
+ ## *do not* clear autocomp, so that the event can skip to AutoComp properly.
1798
+ ## if self.AutoCompActive():
1799
+ ## self.AutoCompCancel() # may delete selection
1800
+ if self.CanEdit():
1801
+ self.ReplaceSelection("")
1802
+ self.message("")
1803
+
1804
+ def clear_autocomp(evt):
1805
+ ## """Clear Autocomp, selection, and message."""
1806
+ if self.AutoCompActive():
1807
+ self.AutoCompCancel()
1808
+ if self.CanEdit():
1809
+ self.ReplaceSelection("")
1810
+ self.message("")
1811
+
1812
+ def fork(evt):
1813
+ self.handler.fork(self.handler.current_event, evt)
1814
+
1496
1815
  def dispatch(evt):
1497
1816
  """Fork events to the parent."""
1498
1817
  self.parent.handler(self.handler.current_event, evt)
@@ -1520,6 +1839,64 @@ class Buffer(EditWindow, EditorInterface):
1520
1839
  '* pressed' : (0, skip, dispatch),
1521
1840
  '* released' : (0, skip, dispatch),
1522
1841
  'escape pressed' : (-1, self.on_enter_escmap),
1842
+ 'C-h pressed' : (0, self.call_helpTip),
1843
+ '. pressed' : (2, skip),
1844
+ 'M-. pressed' : (2, self.call_word_autocomp),
1845
+ 'M-/ pressed' : (3, self.call_apropos_autocomp),
1846
+ },
1847
+ 2 : { # word auto completion AS-mode
1848
+ 'quit' : (0, clear_autocomp),
1849
+ '* pressed' : (0, clear_autocomp, fork),
1850
+ 'tab pressed' : (0, clear, skip),
1851
+ 'enter pressed' : (0, clear, skip),
1852
+ 'escape pressed' : (0, clear_autocomp),
1853
+ 'up pressed' : (2, skip, self.on_completion_backward),
1854
+ 'down pressed' : (2, skip, self.on_completion_forward),
1855
+ '*left pressed' : (2, skip),
1856
+ '*left released' : (2, self.call_word_autocomp),
1857
+ '*right pressed' : (2, skip),
1858
+ '*right released' : (2, self.call_word_autocomp),
1859
+ '[a-z0-9_.] pressed' : (2, skip),
1860
+ '[a-z0-9_.] released' : (2, self.call_word_autocomp),
1861
+ 'S-[a-z\\] pressed' : (2, skip),
1862
+ 'S-[a-z\\] released' : (2, self.call_word_autocomp),
1863
+ '\\ released' : (2, self.call_word_autocomp),
1864
+ '*delete pressed' : (2, skip),
1865
+ '*backspace pressed' : (2, skip),
1866
+ '*backspace released' : (2, self.call_word_autocomp),
1867
+ 'C-S-backspace pressed' : (2, ),
1868
+ '*alt pressed' : (2, ),
1869
+ '*ctrl pressed' : (2, ),
1870
+ '*shift pressed' : (2, ),
1871
+ '*[LR]win pressed' : (2, ),
1872
+ '*f[0-9]* pressed' : (2, ),
1873
+ },
1874
+ 3 : { # apropos auto completion AS-mode
1875
+ 'quit' : (0, clear_autocomp),
1876
+ '* pressed' : (0, clear_autocomp, fork),
1877
+ 'tab pressed' : (0, clear, skip),
1878
+ 'enter pressed' : (0, clear, skip),
1879
+ 'escape pressed' : (0, clear_autocomp),
1880
+ 'up pressed' : (3, skip, self.on_completion_backward),
1881
+ 'down pressed' : (3, skip, self.on_completion_forward),
1882
+ '*left pressed' : (3, skip),
1883
+ '*left released' : (3, self.call_apropos_autocomp),
1884
+ '*right pressed' : (3, skip),
1885
+ '*right released' : (3, self.call_apropos_autocomp),
1886
+ '[a-z0-9_.] pressed' : (3, skip),
1887
+ '[a-z0-9_.] released' : (3, self.call_apropos_autocomp),
1888
+ 'S-[a-z\\] pressed' : (3, skip),
1889
+ 'S-[a-z\\] released' : (3, self.call_apropos_autocomp),
1890
+ '\\ released' : (3, self.call_apropos_autocomp),
1891
+ '*delete pressed' : (3, skip),
1892
+ '*backspace pressed' : (3, skip),
1893
+ '*backspace released' : (3, self.call_apropos_autocomp),
1894
+ 'C-S-backspace pressed' : (3, ),
1895
+ '*alt pressed' : (3, ),
1896
+ '*ctrl pressed' : (3, ),
1897
+ '*shift pressed' : (3, ),
1898
+ '*[LR]win pressed' : (3, ),
1899
+ '*f[0-9]* pressed' : (3, ),
1523
1900
  },
1524
1901
  })
1525
1902
 
@@ -1542,6 +1919,12 @@ class Buffer(EditWindow, EditorInterface):
1542
1919
  self.handler('buffer_modified', self)
1543
1920
  evt.Skip()
1544
1921
 
1922
+ def OnCallTipClick(self, evt):
1923
+ if self.CallTipActive():
1924
+ self.CallTipCancel()
1925
+ self.CallTipShow(*self._calltips, N=None)
1926
+ evt.Skip()
1927
+
1545
1928
  def OnIndicatorClick(self, evt):
1546
1929
  if self.SelectedText or not wx.GetKeyState(wx.WXK_CONTROL):
1547
1930
  ## Processing text selection, dragging, or dragging+
@@ -1647,24 +2030,38 @@ class Buffer(EditWindow, EditorInterface):
1647
2030
  ## Python eval / exec
1648
2031
  ## --------------------------------
1649
2032
 
2033
+ @property
2034
+ def locals(self): # internal use only
2035
+ try:
2036
+ return self.parent.parent.current_shell.locals
2037
+ except AttributeError:
2038
+ return None
2039
+
2040
+ @property
2041
+ def globals(self): # internal use only
2042
+ try:
2043
+ return self.parent.parent.current_shell.globals
2044
+ except AttributeError:
2045
+ return None
2046
+
2047
+ def eval(self, text):
2048
+ return eval(text, self.globals, self.locals) # using current shell namespace
2049
+
2050
+ def exec(self, text):
2051
+ exec(text, self.globals, self.locals) # using current shell namespace
2052
+ dispatcher.send(signal='Interpreter.push',
2053
+ sender=self, command=None, more=False)
2054
+
1650
2055
  def py_eval_line(self, globals=None, locals=None):
1651
2056
  if self.CallTipActive():
1652
2057
  self.CallTipCancel()
1653
2058
 
1654
- def _gen_text():
1655
- text = self.SelectedText
1656
- if text:
1657
- yield text
1658
- else:
1659
- yield self.caretline
1660
- yield self.expr_at_caret
1661
-
1662
2059
  status = "No words"
1663
- for text in filter(None, _gen_text()):
2060
+ for text in self.gen_text_at_caret():
1664
2061
  try:
1665
2062
  obj = eval(text, globals, locals)
1666
2063
  except Exception as e:
1667
- status = "- {}: {!r}".format(e, text)
2064
+ status = "- {} : {!r}".format(e, text)
1668
2065
  else:
1669
2066
  self.CallTipShow(self.cpos, pformat(obj))
1670
2067
  self.message(text)
@@ -2182,13 +2579,15 @@ class Interpreter(interpreter.Interpreter):
2182
2579
  (override) Ignore ValueError: no signature found for builtin
2183
2580
  if the unwrapped function is a builtin function.
2184
2581
  """
2582
+ ## In 4.2.1, DeprecationWarning was fixed.
2583
+ ## In 4.2.2, ValueError was fixed.
2185
2584
  try:
2186
2585
  return interpreter.Interpreter.getCallTip(self, command, *args, **kwargs)
2187
2586
  except ValueError:
2188
2587
  return interpreter.Interpreter.getCallTip(self) # dummy
2189
2588
 
2190
2589
 
2191
- class Nautilus(Shell, EditorInterface):
2590
+ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
2192
2591
  """Nautilus in the Shell.
2193
2592
 
2194
2593
  Facade objects for accessing the APIs:
@@ -2221,24 +2620,24 @@ class Nautilus(Shell, EditorInterface):
2221
2620
  ``*`` denotes the original syntax defined in wx.py.shell,
2222
2621
  for which, at present version, enabled with USE_MAGIC switch being on.
2223
2622
 
2224
- Autocomp-key bindings::
2623
+ Auto-complete key bindings::
2225
2624
 
2226
2625
  C-up : [0] retrieve previous history
2227
2626
  C-down : [0] retrieve next history
2228
- C-j(J), M-j : [0] call tooltip of eval (for the word selected or focused)
2229
- C-h(H), M-h : [0] call tooltip of help (for the func selected or focused)
2230
- TAB : [1] history-comp-mode
2231
- M-p : [1] retrieve previous history in comp-mode
2232
- M-n : [1] retrieve next history in comp-mode
2233
- M-. : [2] word-comp-mode
2234
- M-/ : [3] apropos-comp-mode
2235
- M-, : [4] text-comp-mode
2236
- M-m : [5] module-comp-mode
2627
+ C-j, M-j : [0] call tooltip of eval (for the word selected or focused)
2628
+ C-h, M-h : [0] call tooltip of help (for the func selected or focused)
2629
+ TAB : [1] history-comp
2630
+ M-p : [1] retrieve previous history in history-comp mode
2631
+ M-n : [1] retrieve next history in history-comp mode
2632
+ M-. : [2] word-comp
2633
+ M-/ : [3] apropos-comp
2634
+ M-, : [4] text-comp
2635
+ M-m : [5] module-comp
2237
2636
 
2238
2637
  Autocomps are incremental when pressed any alnums,
2239
2638
  and decremental when backspace.
2240
2639
 
2241
- Enter-key bindings::
2640
+ Enter key bindings::
2242
2641
 
2243
2642
  C-enter : insert-line-break
2244
2643
  M-enter : duplicate-command
@@ -2332,8 +2731,6 @@ class Nautilus(Shell, EditorInterface):
2332
2731
  def globals(self): # internal use only
2333
2732
  self.interp.globals = self.__target.__dict__
2334
2733
 
2335
- modules = None
2336
-
2337
2734
  ## (override)
2338
2735
  wrap = EditorInterface.wrap
2339
2736
 
@@ -2351,6 +2748,7 @@ class Nautilus(Shell, EditorInterface):
2351
2748
  execStartupScript=execStartupScript, # if True, executes ~/.py
2352
2749
  **kwargs)
2353
2750
  EditorInterface.__init__(self)
2751
+ AutoCompInterfaceMixin.__init__(self)
2354
2752
 
2355
2753
  self.parent = parent #: parent<ShellFrame> is not Parent<AuiNotebook>
2356
2754
  self.target = target
@@ -2359,12 +2757,6 @@ class Nautilus(Shell, EditorInterface):
2359
2757
  wx.py.shell.USE_MAGIC = True
2360
2758
  wx.py.shell.magic = self.magic # called when USE_MAGIC
2361
2759
 
2362
- ## cf. sys.modules
2363
- if not self.modules:
2364
- force = wx.GetKeyState(wx.WXK_CONTROL)\
2365
- & wx.GetKeyState(wx.WXK_SHIFT)
2366
- Nautilus.modules = set(find_modules(force))
2367
-
2368
2760
  self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdate) # skip to brace matching
2369
2761
  self.Bind(stc.EVT_STC_CALLTIP_CLICK, self.OnCallTipClick)
2370
2762
  self.Bind(stc.EVT_STC_START_DRAG, self.OnDrag)
@@ -2469,8 +2861,8 @@ class Nautilus(Shell, EditorInterface):
2469
2861
  'M-j pressed' : (0, self.exec_region),
2470
2862
  'C-S-j pressed' : (0, self.exec_region),
2471
2863
  'C-h pressed' : (0, self.call_helpTip),
2472
- 'M-h pressed' : (0, self.call_helpTip2),
2473
- 'C-S-h pressed' : (0, self.call_helpTip2),
2864
+ 'M-h pressed' : (0, self.call_helpDoc),
2865
+ 'C-S-h pressed' : (0, self.call_helpDoc),
2474
2866
  '. pressed' : (2, self.OnEnterDot),
2475
2867
  'tab pressed' : (1, self.call_history_comp),
2476
2868
  'M-p pressed' : (1, self.call_history_comp),
@@ -2482,7 +2874,7 @@ class Nautilus(Shell, EditorInterface):
2482
2874
  },
2483
2875
  1 : { # history auto completion S-mode
2484
2876
  'quit' : (0, clear),
2485
- 'fork' : (0, self.on_indent_line),
2877
+ 'skip' : (0, self.on_indent_line),
2486
2878
  '* pressed' : (0, fork),
2487
2879
  'enter pressed' : (0, lambda v: self.goto_char(self.eolc)),
2488
2880
  'escape pressed' : (0, clear),
@@ -2490,10 +2882,10 @@ class Nautilus(Shell, EditorInterface):
2490
2882
  'S-left released' : (1, self.call_history_comp),
2491
2883
  'S-right pressed' : (1, skip),
2492
2884
  'S-right released' : (1, self.call_history_comp),
2493
- 'tab pressed' : (1, self.on_completion_forward_history),
2494
- 'S-tab pressed' : (1, self.on_completion_backward_history),
2495
- 'M-p pressed' : (1, self.on_completion_forward_history),
2496
- 'M-n pressed' : (1, self.on_completion_backward_history),
2885
+ 'tab pressed' : (1, _F(self._on_completion, 1)), # 古いヒストリへ進む
2886
+ 'S-tab pressed' : (1, _F(self._on_completion, -1)), # 新しいヒストリへ戻る
2887
+ 'M-p pressed' : (1, _F(self._on_completion, 1)),
2888
+ 'M-n pressed' : (1, _F(self._on_completion, -1)),
2497
2889
  '[a-z0-9_] pressed' : (1, skip),
2498
2890
  '[a-z0-9_] released' : (1, self.call_history_comp),
2499
2891
  'S-[a-z\\] pressed' : (1, skip),
@@ -2509,7 +2901,7 @@ class Nautilus(Shell, EditorInterface):
2509
2901
  'quit' : (0, clear_autocomp),
2510
2902
  '* pressed' : (0, clear_autocomp, fork),
2511
2903
  'tab pressed' : (0, clear, skip),
2512
- 'enter pressed' : (0, clear, fork),
2904
+ 'enter pressed' : (0, clear, skip),
2513
2905
  'escape pressed' : (0, clear_autocomp),
2514
2906
  'up pressed' : (2, skip, self.on_completion_backward),
2515
2907
  'down pressed' : (2, skip, self.on_completion_forward),
@@ -2527,11 +2919,6 @@ class Nautilus(Shell, EditorInterface):
2527
2919
  '*backspace released' : (2, self.call_word_autocomp),
2528
2920
  'C-S-backspace pressed' : (2, ),
2529
2921
  'C-j pressed' : (2, self.eval_line),
2530
- 'M-j pressed' : (2, self.exec_region),
2531
- 'C-S-j pressed' : (2, self.exec_region),
2532
- 'C-h pressed' : (2, self.call_helpTip),
2533
- 'M-h pressed' : (2, self.call_helpTip2),
2534
- 'C-S-h pressed' : (2, self.call_helpTip2),
2535
2922
  '*alt pressed' : (2, ),
2536
2923
  '*ctrl pressed' : (2, ),
2537
2924
  '*shift pressed' : (2, ),
@@ -2542,7 +2929,7 @@ class Nautilus(Shell, EditorInterface):
2542
2929
  'quit' : (0, clear_autocomp),
2543
2930
  '* pressed' : (0, clear_autocomp, fork),
2544
2931
  'tab pressed' : (0, clear, skip),
2545
- 'enter pressed' : (0, clear, fork),
2932
+ 'enter pressed' : (0, clear, skip),
2546
2933
  'escape pressed' : (0, clear_autocomp),
2547
2934
  'up pressed' : (3, skip, self.on_completion_backward),
2548
2935
  'down pressed' : (3, skip, self.on_completion_forward),
@@ -2560,11 +2947,6 @@ class Nautilus(Shell, EditorInterface):
2560
2947
  '*backspace released' : (3, self.call_apropos_autocomp),
2561
2948
  'C-S-backspace pressed' : (3, ),
2562
2949
  'C-j pressed' : (3, self.eval_line),
2563
- 'M-j pressed' : (3, self.exec_region),
2564
- 'C-S-j pressed' : (3, self.exec_region),
2565
- 'C-h pressed' : (3, self.call_helpTip),
2566
- 'M-h pressed' : (3, self.call_helpTip2),
2567
- 'C-S-h pressed' : (3, self.call_helpTip2),
2568
2950
  '*alt pressed' : (3, ),
2569
2951
  '*ctrl pressed' : (3, ),
2570
2952
  '*shift pressed' : (3, ),
@@ -2575,7 +2957,7 @@ class Nautilus(Shell, EditorInterface):
2575
2957
  'quit' : (0, clear_autocomp),
2576
2958
  '* pressed' : (0, clear_autocomp, fork),
2577
2959
  'tab pressed' : (0, clear, skip),
2578
- 'enter pressed' : (0, clear, fork),
2960
+ 'enter pressed' : (0, clear, skip),
2579
2961
  'escape pressed' : (0, clear_autocomp),
2580
2962
  'up pressed' : (4, skip, self.on_completion_backward),
2581
2963
  'down pressed' : (4, skip, self.on_completion_forward),
@@ -2593,11 +2975,6 @@ class Nautilus(Shell, EditorInterface):
2593
2975
  '*backspace released' : (4, self.call_text_autocomp),
2594
2976
  'C-S-backspace pressed' : (4, ),
2595
2977
  'C-j pressed' : (4, self.eval_line),
2596
- 'M-j pressed' : (4, self.exec_region),
2597
- 'C-S-j pressed' : (4, self.exec_region),
2598
- 'C-h pressed' : (4, self.call_helpTip),
2599
- 'M-h pressed' : (4, self.call_helpTip2),
2600
- 'C-S-h pressed' : (4, self.call_helpTip2),
2601
2978
  '*alt pressed' : (4, ),
2602
2979
  '*ctrl pressed' : (4, ),
2603
2980
  '*shift pressed' : (4, ),
@@ -2608,7 +2985,7 @@ class Nautilus(Shell, EditorInterface):
2608
2985
  'quit' : (0, clear_autocomp),
2609
2986
  '* pressed' : (0, clear_autocomp, fork),
2610
2987
  'tab pressed' : (0, clear, skip),
2611
- 'enter pressed' : (0, clear, fork),
2988
+ 'enter pressed' : (0, clear, skip),
2612
2989
  'escape pressed' : (0, clear_autocomp),
2613
2990
  'up pressed' : (5, skip, self.on_completion_backward),
2614
2991
  'down pressed' : (5, skip, self.on_completion_forward),
@@ -2621,7 +2998,7 @@ class Nautilus(Shell, EditorInterface):
2621
2998
  'S-[a-z\\] pressed' : (5, skip),
2622
2999
  'S-[a-z\\] released' : (5, self.call_module_autocomp),
2623
3000
  '\\ released' : (5, self.call_module_autocomp),
2624
- 'M-m released' : (5, _F(self.call_module_autocomp, force=1)),
3001
+ 'M-m pressed' : (5, _F(self.call_module_autocomp, force=1)),
2625
3002
  '*delete pressed' : (5, skip),
2626
3003
  '*backspace pressed' : (5, skip_autocomp),
2627
3004
  '*backspace released' : (5, self.call_module_autocomp),
@@ -2669,9 +3046,9 @@ class Nautilus(Shell, EditorInterface):
2669
3046
  evt.Skip()
2670
3047
 
2671
3048
  def OnCallTipClick(self, evt):
2672
- self.parent.handler('add_help', self.__calltip)
2673
3049
  if self.CallTipActive():
2674
3050
  self.CallTipCancel()
3051
+ self.parent.handler('add_help', self._calltips[1])
2675
3052
  evt.Skip()
2676
3053
 
2677
3054
  def OnDrag(self, evt): #<wx._core.StyledTextEvent>
@@ -2689,7 +3066,7 @@ class Nautilus(Shell, EditorInterface):
2689
3066
  """Called when space pressed."""
2690
3067
  if not self.CanEdit():
2691
3068
  return
2692
- cmdl = self.cmdlc
3069
+ cmdl = self.GetTextRange(self.bol, self.cpos)
2693
3070
  if re.match(r"import\s*", cmdl)\
2694
3071
  or re.match(r"from\s*$", cmdl)\
2695
3072
  or re.match(r"from\s+([\w.]+)\s+import\s*", cmdl):
@@ -2963,22 +3340,18 @@ class Nautilus(Shell, EditorInterface):
2963
3340
  Note:
2964
3341
  Argument `text` is raw output:str with no magic cast.
2965
3342
  """
2966
- ln = self.cmdline_region[0]
3343
+ ln = self.LineFromPosition(self.bolc)
2967
3344
  err = re.findall(py_error_re, text, re.M)
2968
3345
  self.add_marker(ln, 1 if not err else 2) # 1:white-arrow 2:red-arrow
2969
3346
  return (not err)
2970
3347
 
2971
3348
  def on_interp_error(self, e):
2972
- self.pointer = self.cmdline_region[0] + e.lineno - 1
3349
+ ln = self.LineFromPosition(self.bolc)
3350
+ self.pointer = ln + e.lineno - 1
2973
3351
 
2974
3352
  ## --------------------------------
2975
3353
  ## Attributes of the shell
2976
3354
  ## --------------------------------
2977
- fragmwords = set(keyword.kwlist + dir(builtins)) # to be used in text-comp
2978
-
2979
- ## shell.history is an instance variable of the Shell.
2980
- ## If del shell.history, the history of the class variable is used
2981
- history = []
2982
3355
 
2983
3356
  @property
2984
3357
  def bolc(self):
@@ -3000,37 +3373,20 @@ class Nautilus(Shell, EditorInterface):
3000
3373
  break
3001
3374
  return self.cpos - lp
3002
3375
 
3003
- @property
3004
- def cmdlc(self):
3005
- """Cull command-line (excluding ps1:prompt)."""
3006
- return self.GetTextRange(self.bol, self.cpos)
3007
-
3008
3376
  @property
3009
3377
  def cmdline(self):
3010
- """Full command-(multi-)line (excluding ps1:prompt)."""
3378
+ """Full multi-line command in the current prompt."""
3011
3379
  return self.GetTextRange(self.bolc, self.eolc)
3012
3380
 
3013
- @property
3014
- def cmdline_region(self):
3015
- lc = self.LineFromPosition(self.bolc)
3016
- le = self.LineCount
3017
- return lc, le
3018
-
3019
3381
  ## cf. getCommand() -> caret-line that starts with a prompt
3020
3382
  ## cf. getMultilineCommand() -> caret-multi-line that starts with a prompt
3021
3383
  ## [BUG 4.1.1] Don't use for current prompt --> Fixed in 4.2.0.
3022
3384
 
3023
- @property
3024
- def Command(self):
3025
- """Extract a command from the editor."""
3026
- return self.getCommand(rstrip=False)
3027
-
3028
- @property
3029
- def MultilineCommand(self):
3030
- """Extract a multi-line command from the editor.
3385
+ def getMultilineCommand(self):
3386
+ """Extract a multi-line command which starts with a prompt.
3031
3387
 
3032
- Similar to getMultilineCommand(), but does not exclude
3033
- a trailing ps2 + blank command.
3388
+ (override) Don't remove trailing ps2 + spaces.
3389
+ Don't invoke ``GotoLine``.
3034
3390
  """
3035
3391
  region = self.get_region(self.cline)
3036
3392
  if region:
@@ -3086,13 +3442,13 @@ class Nautilus(Shell, EditorInterface):
3086
3442
  output = self.GetTextRange(self.__eolc_mark, self.eolc)
3087
3443
 
3088
3444
  input = self.regulate_cmd(input)
3089
- Shell.addHistory(self, input)
3445
+ Shell.addHistory(self, input) # => self.history
3090
3446
 
3091
3447
  noerr = self.on_text_output(output)
3092
3448
  if noerr:
3093
3449
  words = re.findall(r"\b[a-zA-Z_][\w.]+", input + output)
3094
3450
  self.fragmwords |= set(words)
3095
- command = self.fixLineEndings(command)
3451
+ command = self.fixLineEndings(command)
3096
3452
  self.parent.handler('add_log', command + os.linesep, noerr)
3097
3453
  except AttributeError:
3098
3454
  ## execStartupScript 実行時は出力先 (owner) が存在しない
@@ -3254,30 +3610,11 @@ class Nautilus(Shell, EditorInterface):
3254
3610
  def autoCallTipShow(self, command, insertcalltip=True, forceCallTip=False):
3255
3611
  """Display argument spec and docstring in a popup window.
3256
3612
 
3257
- (override) Swap anchors to not scroll to the end of the line,
3258
- and display a long hint at the insertion position.
3613
+ (override) Swap anchors to not scroll to the end of the line.
3259
3614
  """
3260
- vpos = self.GetScrollPos(wx.VERTICAL)
3261
- hpos = self.GetScrollPos(wx.HORIZONTAL)
3262
3615
  Shell.autoCallTipShow(self, command, insertcalltip, forceCallTip)
3263
3616
  self.cpos, self.anchor = self.anchor, self.cpos
3264
- ## self.EnsureCaretVisible()
3265
- self.ScrollToLine(vpos)
3266
- self.SetXOffset(hpos)
3267
-
3268
- def CallTipShow(self, pos, tip, N=11):
3269
- """Show a call tip containing a definition near position pos.
3270
-
3271
- (override) Snip the tip of max N lines if it is too long.
3272
- Keep the tip for calltip-click event.
3273
- """
3274
- self.__calltip = tip
3275
- lines = tip.splitlines()
3276
- if len(lines) > N:
3277
- lines[N+1:] = ["\n...(snip) This tips are too long... "
3278
- "Click to show more details."
3279
- ]
3280
- Shell.CallTipShow(self, pos, '\n'.join(lines))
3617
+ self.EnsureCaretVisible()
3281
3618
 
3282
3619
  def eval_line(self, evt):
3283
3620
  """Evaluate the selected word or line.
@@ -3285,24 +3622,15 @@ class Nautilus(Shell, EditorInterface):
3285
3622
  if self.CallTipActive():
3286
3623
  self.CallTipCancel()
3287
3624
 
3288
- def _gen_text():
3289
- text = self.SelectedText
3290
- if text:
3291
- yield text
3292
- else:
3293
- yield self.Command
3294
- yield self.expr_at_caret
3295
- yield self.MultilineCommand
3296
-
3297
3625
  status = "No words"
3298
- for text in filter(None, _gen_text()):
3626
+ for text in self.gen_text_at_caret():
3299
3627
  tokens = split_words(text)
3300
3628
  try:
3301
3629
  cmd = self.magic_interpret(tokens)
3302
3630
  cmd = self.regulate_cmd(cmd)
3303
3631
  obj = self.eval(cmd)
3304
3632
  except Exception as e:
3305
- status = "- {}: {!r}".format(e, text)
3633
+ status = "- {} : {!r}".format(e, text)
3306
3634
  else:
3307
3635
  self.CallTipShow(self.cpos, pformat(obj))
3308
3636
  self.message(cmd)
@@ -3315,7 +3643,7 @@ class Nautilus(Shell, EditorInterface):
3315
3643
  self.CallTipCancel()
3316
3644
 
3317
3645
  filename = "<input>"
3318
- text = self.MultilineCommand
3646
+ text = self.getMultilineCommand()
3319
3647
  if text:
3320
3648
  tokens = split_words(text)
3321
3649
  try:
@@ -3337,253 +3665,3 @@ class Nautilus(Shell, EditorInterface):
3337
3665
  self.message("Evaluated {!r} successfully.".format(filename))
3338
3666
  else:
3339
3667
  self.message("No region")
3340
-
3341
- def call_helpTip2(self, evt):
3342
- """Show help:str for the selected topic."""
3343
- if self.CallTipActive():
3344
- self.CallTipCancel()
3345
-
3346
- text = self.SelectedText or self.Command or self.expr_at_caret
3347
- if text:
3348
- text = introspect.getRoot(text, terminator='(')
3349
- try:
3350
- obj = self.eval(text)
3351
- self.help(obj)
3352
- except Exception as e:
3353
- self.message("- {} : {!r}".format(e, text))
3354
-
3355
- def call_helpTip(self, evt):
3356
- """Show tooltips for the selected topic."""
3357
- if self.CallTipActive():
3358
- self.CallTipCancel()
3359
-
3360
- text = self.SelectedText or self.Command or self.expr_at_caret
3361
- if text:
3362
- try:
3363
- p = self.cpos
3364
- c = self.get_char(p-1)
3365
- self.autoCallTipShow(text,
3366
- c == '(' and p == self.eol) # => CallTipShow
3367
- except Exception as e:
3368
- self.message("- {} : {!r}".format(e, text))
3369
-
3370
- def on_completion_forward(self, evt):
3371
- if self.AutoCompActive():
3372
- self.on_completion(evt, 1)
3373
- else:
3374
- self.handler('quit', evt)
3375
-
3376
- def on_completion_backward(self, evt):
3377
- if self.AutoCompActive():
3378
- self.on_completion(evt, -1)
3379
- else:
3380
- self.handler('quit', evt)
3381
-
3382
- def on_completion_forward_history(self, evt):
3383
- self.on_completion(evt, 1) # 古いヒストリへ進む
3384
-
3385
- def on_completion_backward_history(self, evt):
3386
- self.on_completion(evt, -1) # 新しいヒストリへ戻る
3387
-
3388
- def on_completion(self, evt, step=0):
3389
- """Show completion with selection."""
3390
- try:
3391
- N = len(self.__comp_words)
3392
- j = self.__comp_ind + step
3393
- j = 0 if j < 0 else j if j < N else N-1
3394
- word = self.__comp_words[j]
3395
- n = len(self.__comp_hint)
3396
- p = self.cpos
3397
- if not self.SelectedText:
3398
- p, self.anchor, sty = self.get_following_atom(p) # word-right-selection
3399
- self.ReplaceSelection(word[n:]) # Modify (or insert) the selected range
3400
- self.cpos = p # backward selection to the point
3401
- self.__comp_ind = j
3402
- except IndexError:
3403
- self.message("No completion words")
3404
-
3405
- def _gen_autocomp(self, j, hint, words, sep=' '):
3406
- """Call AutoCompShow for the specified words and sep."""
3407
- ## Prepare on_completion_forward/backward
3408
- self.__comp_ind = j
3409
- self.__comp_hint = hint
3410
- self.__comp_words = words
3411
- if words:
3412
- self.AutoCompSetSeparator(ord(sep))
3413
- self.AutoCompShow(len(hint), sep.join(words))
3414
-
3415
- @staticmethod
3416
- def _get_last_hint(cmdl):
3417
- return re.search(r"[\w.]*$", cmdl).group(0) # or ''
3418
-
3419
- @staticmethod
3420
- def _get_words_hint(cmdl):
3421
- text = next(split_words(cmdl, reverse=1), '')
3422
- return text.rpartition('.') # -> text, sep, hint
3423
-
3424
- def call_history_comp(self, evt):
3425
- """Called when history-comp mode."""
3426
- if not self.CanEdit():
3427
- self.handler('quit', evt)
3428
- return
3429
- try:
3430
- cmdl = self.cmdlc
3431
- if cmdl.isspace() or self.bol != self.bolc:
3432
- self.handler('fork', evt) # fork [tab pressed] => on_indent_line
3433
- return
3434
-
3435
- hint = cmdl.strip()
3436
- ls = [x.replace('\n', os.linesep + sys.ps2)
3437
- for x in self.history if x.startswith(hint)] # case-sensitive match
3438
- words = sorted(set(ls), key=ls.index, reverse=0) # keep order, no duplication
3439
-
3440
- self.__comp_ind = 0
3441
- self.__comp_hint = hint
3442
- self.__comp_words = words
3443
-
3444
- self.anchor = self.eolc # selection to eol
3445
- self.on_completion(evt) # show completion always
3446
-
3447
- ## the latest history stacks in the head of the list (time-descending)
3448
- self.message("[history] {} candidates matched"
3449
- " with {!r}".format(len(words), hint))
3450
- except Exception:
3451
- raise
3452
-
3453
- def call_text_autocomp(self, evt):
3454
- """Called when text-comp mode."""
3455
- if not self.CanEdit():
3456
- self.handler('quit', evt)
3457
- return
3458
- try:
3459
- cmdl = self.cmdlc
3460
- hint = self._get_last_hint(cmdl)
3461
-
3462
- ls = [x for x in self.fragmwords if x.startswith(hint)] # case-sensitive match
3463
- words = sorted(ls, key=lambda s:s.upper())
3464
-
3465
- self._gen_autocomp(0, hint, words)
3466
- self.message("[text] {} candidates matched"
3467
- " with {!r}".format(len(words), hint))
3468
- except Exception:
3469
- raise
3470
-
3471
- def call_module_autocomp(self, evt, force=False):
3472
- """Called when module-comp mode."""
3473
- if not self.CanEdit():
3474
- self.handler('quit', evt)
3475
- return
3476
-
3477
- def _continue(hints):
3478
- if not hints.endswith(' '):
3479
- h = hints.strip()
3480
- if not h.endswith(','):
3481
- lh = h.split(',')[-1].strip() # 'x, y, z|' last hint after ','
3482
- if ' ' not in lh: # 'x, y as|' contains no spaces.
3483
- return lh
3484
- try:
3485
- cmdl = self.cmdlc
3486
- hint = self._get_last_hint(cmdl)
3487
-
3488
- if (m := re.match(r"from\s+([\w.]+)\s+import\s+(.*)", cmdl)):
3489
- text, hints = m.groups()
3490
- if not _continue(hints) and not force:
3491
- self.message("[module]>>> waiting for key input...")
3492
- return
3493
- elif hints.endswith('.'):
3494
- self.message("[module] invalid import syntax.")
3495
- return
3496
- if text not in sys.modules:
3497
- self.message("[module]>>> loading {}...".format(text))
3498
- try:
3499
- modules = set(dir(import_module(text)))
3500
- except ImportError as e:
3501
- self.message("\b failed:", e)
3502
- return
3503
- ## Add unimported module names.
3504
- p = "{}.{}".format(text, hint)
3505
- keys = [x[len(text)+1:] for x in self.modules if x.startswith(p)]
3506
- modules.update(k for k in keys if '.' not in k)
3507
-
3508
- elif (m := re.match(r"(import|from)\s+(.*)", cmdl)):
3509
- text, hints = m.groups()
3510
- if not _continue(hints) and not force:
3511
- self.message("[module]>>> waiting for key input...")
3512
- return
3513
- modules = self.modules
3514
- else:
3515
- text, sep, hint = self._get_words_hint(cmdl)
3516
- obj = self.eval(text)
3517
- modules = set(k for k, v in vars(obj).items() if inspect.ismodule(v))
3518
-
3519
- P = re.compile(hint)
3520
- p = re.compile(hint, re.I)
3521
- words = sorted([x for x in modules if p.match(x)], key=lambda s:s.upper())
3522
-
3523
- j = next((k for k, w in enumerate(words) if P.match(w)),
3524
- next((k for k, w in enumerate(words) if p.match(w)), -1))
3525
-
3526
- self._gen_autocomp(j, hint, words)
3527
- self.message("[module] {} candidates matched"
3528
- " with {!r} in {}".format(len(words), hint, text))
3529
- except re.error as e:
3530
- self.message("- re:miss compilation {!r} : {!r}".format(e, hint))
3531
- except SyntaxError as e:
3532
- self.handler('quit', evt)
3533
- self.message("- {} : {!r}".format(e, text))
3534
- except Exception as e:
3535
- self.message("- {} : {!r}".format(e, text))
3536
-
3537
- def call_word_autocomp(self, evt):
3538
- """Called when word-comp mode."""
3539
- if not self.CanEdit():
3540
- self.handler('quit', evt)
3541
- return
3542
- try:
3543
- text, sep, hint = self._get_words_hint(self.cmdlc)
3544
- obj = self.eval(text)
3545
-
3546
- P = re.compile(hint)
3547
- p = re.compile(hint, re.I)
3548
- words = sorted([x for x in dir(obj) if p.match(x)], key=lambda s:s.upper())
3549
-
3550
- j = next((k for k, w in enumerate(words) if P.match(w)),
3551
- next((k for k, w in enumerate(words) if p.match(w)), -1))
3552
-
3553
- self._gen_autocomp(j, hint, words)
3554
- self.message("[word] {} candidates matched"
3555
- " with {!r} in {}".format(len(words), hint, text))
3556
- except re.error as e:
3557
- self.message("- re:miss compilation {!r} : {!r}".format(e, hint))
3558
- except SyntaxError as e:
3559
- self.handler('quit', evt)
3560
- self.message("- {} : {!r}".format(e, text))
3561
- except Exception as e:
3562
- self.message("- {} : {!r}".format(e, text))
3563
-
3564
- def call_apropos_autocomp(self, evt):
3565
- """Called when apropos mode."""
3566
- if not self.CanEdit():
3567
- self.handler('quit', evt)
3568
- return
3569
- try:
3570
- text, sep, hint = self._get_words_hint(self.cmdlc)
3571
- obj = self.eval(text)
3572
-
3573
- P = re.compile(hint)
3574
- p = re.compile(hint, re.I)
3575
- words = sorted([x for x in dir(obj) if p.search(x)], key=lambda s:s.upper())
3576
-
3577
- j = next((k for k, w in enumerate(words) if P.match(w)),
3578
- next((k for k, w in enumerate(words) if p.match(w)), -1))
3579
-
3580
- self._gen_autocomp(j, hint, words)
3581
- self.message("[apropos] {} candidates matched"
3582
- " with {!r} in {}".format(len(words), hint, text))
3583
- except re.error as e:
3584
- self.message("- re:miss compilation {!r} : {!r}".format(e, hint))
3585
- except SyntaxError as e:
3586
- self.handler('quit', evt)
3587
- self.message("- {} : {!r}".format(e, text))
3588
- except Exception as e:
3589
- self.message("- {} : {!r}".format(e, text))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mwxlib
3
- Version: 0.97.7
3
+ Version: 0.98.1
4
4
  Summary: A wrapper of matplotlib and wxPython (phoenix)
5
5
  Home-page: https://github.com/komoto48g/mwxlib
6
6
  Author: Kazuya O'moto
@@ -1,14 +1,14 @@
1
1
  mwx/__init__.py,sha256=nN62CGTWjME7Zz2h-jIRB8MxwuErIkHPGrlBzydkF0o,643
2
2
  mwx/bookshelf.py,sha256=Y4xI2SrEO22DrI1hyyfFx7DfFZA8znOzX9RWMPsA2BE,5137
3
3
  mwx/controls.py,sha256=K4GJB81TXv5q0faTELQgbUmtMQBRIM9yINJdTI0xA3g,47556
4
- mwx/framework.py,sha256=muvp-MrmS8TGwpRx7S18X2u-nhS9YumUHA1K_MRKCwA,75443
4
+ mwx/framework.py,sha256=xSh2cxTyg6SHU3jh9cGTaiC2u7teJPJwRuFrmEfSXiQ,75509
5
5
  mwx/graphman.py,sha256=Cyhl_Da_HGBfk721gu1r5iwSH9L3yPEG8Fzmc2gx-EU,70462
6
6
  mwx/images.py,sha256=_-Eh3xF7Khu42ivkYp97NXIzSNGbjcidqtWjZQFGtqE,47827
7
7
  mwx/matplot2.py,sha256=xCJ_ZzdDEWmzctpPaOrzTnwXyHINP4nfFHweoTZa6ug,32899
8
8
  mwx/matplot2g.py,sha256=wiZFDFuQe3ax71fmyeR_9hvAmgT-4nVfZ30UByv8Nv8,64379
9
9
  mwx/matplot2lg.py,sha256=JRWjWnLJUytbSq6wxs4P0gbVUr3xoLSF6Wwqd5V_pJI,27404
10
10
  mwx/mgplt.py,sha256=ITzxA97yDwr_35BUk5OqnyskSuKVDbpf2AQCKY1jHTI,5671
11
- mwx/nutshell.py,sha256=Zwlh_1zFRCmlTBFsw_0xHBLsofKSmzd8K62cWBov1FQ,137580
11
+ mwx/nutshell.py,sha256=nTEKmJ0CMqkVtbmIlDHvZDpkUjefgL6QbxMZKwbZpIk,141553
12
12
  mwx/utilus.py,sha256=mmqB4P_3mTi7SrFleMiN1599Jm0Us0XKnNA6v2xglSs,37333
13
13
  mwx/wxmon.py,sha256=f3V24EF7kdMlYF7usLYK9QE5KU6fSu0jVqsvwAiA-Ag,12647
14
14
  mwx/wxpdb.py,sha256=lLowkkAgMhPFHAfklD7wZHq0qbSMjRxnBFtSajmVgME,19133
@@ -21,8 +21,8 @@ mwx/plugins/frame_listview.py,sha256=hbApzZWa9-BmQthu7uZBlBbGbtf4iJ_prO8IhxoGMs8
21
21
  mwx/plugins/line_profile.py,sha256=--9NIc3x5EfRB3L59JvD7rzENQHyiYfu7wWJo6AuMkA,820
22
22
  mwx/py/__init__.py,sha256=xykgfOytOwNuvXsfkLoumFZSTN-iBsHOjczYXngjmUE,12
23
23
  mwx/py/filling.py,sha256=fumUG1F5M9TL-Dfqni4G85uk7TmvnUunTbdcPDV0vfo,16857
24
- mwxlib-0.97.7.dist-info/LICENSE,sha256=PGtRKCaTkmUDlBQwpptJAxJtdqxIUtAmdBsaT9nUVkA,1091
25
- mwxlib-0.97.7.dist-info/METADATA,sha256=ITXJ8FrL_C8Zp4tjs-dwINs4TrpykIZxNe-hot0NIP0,1880
26
- mwxlib-0.97.7.dist-info/WHEEL,sha256=Wyh-_nZ0DJYolHNn1_hMa4lM7uDedD_RGVwbmTjyItk,91
27
- mwxlib-0.97.7.dist-info/top_level.txt,sha256=SI1Mh118AstnUFGPNq5aMNKiAnVNmZk1S9Ij-OwAEpY,4
28
- mwxlib-0.97.7.dist-info/RECORD,,
24
+ mwxlib-0.98.1.dist-info/LICENSE,sha256=PGtRKCaTkmUDlBQwpptJAxJtdqxIUtAmdBsaT9nUVkA,1091
25
+ mwxlib-0.98.1.dist-info/METADATA,sha256=XcUcwip9zlP_OGddgjt4s8fHdRvz7pGU-y1NS1t4kXg,1880
26
+ mwxlib-0.98.1.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
27
+ mwxlib-0.98.1.dist-info/top_level.txt,sha256=SI1Mh118AstnUFGPNq5aMNKiAnVNmZk1S9Ij-OwAEpY,4
28
+ mwxlib-0.98.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (71.1.0)
2
+ Generator: setuptools (72.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5