mwxlib 0.98.1__py3-none-any.whl → 0.98.6__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/nutshell.py CHANGED
@@ -10,7 +10,6 @@ import traceback
10
10
  import inspect
11
11
  import builtins
12
12
  import operator
13
- import dis
14
13
  import pydoc
15
14
  import keyword
16
15
  import linecache
@@ -102,12 +101,13 @@ class AutoCompInterfaceMixin:
102
101
  (override) Snip the tip of max N lines if it is too long.
103
102
  Keep the tip for calltip-click event.
104
103
  """
105
- self._calltips = (pos, tip)
104
+ self._calltips = [pos, tip, False]
106
105
  lines = tip.splitlines()
107
106
  if N and len(lines) > N > 0:
108
107
  lines[N+1:] = ["\n...(snip) This tips are too long... "
109
108
  "Click to show more details."]
110
109
  tip = '\n'.join(lines)
110
+ self._calltips[-1] = True # snipped (needs to be shown)
111
111
  super().CallTipShow(pos, tip)
112
112
 
113
113
  def autoCallTipShow(self, command, insertcalltip=True):
@@ -142,7 +142,7 @@ class AutoCompInterfaceMixin:
142
142
  self.message("- {} : {!r}".format(e, text))
143
143
 
144
144
  def call_helpTip(self, evt):
145
- """Show tooltips for the selected topic."""
145
+ """Show a calltip for the selected function."""
146
146
  if self.CallTipActive():
147
147
  self.CallTipCancel()
148
148
 
@@ -174,8 +174,11 @@ class AutoCompInterfaceMixin:
174
174
  n = len(self.__comp_hint)
175
175
  p = self.cpos
176
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
177
+ p, q, sty = self.get_following_atom(p) # word-right-selection
178
+ if sty == 'word':
179
+ self.anchor = q
180
+ with self.off_undocollection():
181
+ self.ReplaceSelection(word[n:])
179
182
  self.cpos = p # backward selection to the point
180
183
  self.__comp_ind = j
181
184
  except IndexError:
@@ -264,7 +267,7 @@ class AutoCompInterfaceMixin:
264
267
  self.message("[module]>>> loading {}...".format(text))
265
268
  modules = set(dir(import_module(text)))
266
269
  except ImportError as e:
267
- self.message("\b failed:", e)
270
+ self.message("\b failed.", e)
268
271
  return
269
272
  else:
270
273
  ## Add unimported module names.
@@ -356,7 +359,7 @@ class AutoCompInterfaceMixin:
356
359
  self.message("- {} : {!r}".format(e, text))
357
360
 
358
361
 
359
- class EditorInterface(CtrlInterface):
362
+ class EditorInterface(AutoCompInterfaceMixin, CtrlInterface):
360
363
  """Interface of Python code editor.
361
364
 
362
365
  Note:
@@ -364,6 +367,7 @@ class EditorInterface(CtrlInterface):
364
367
  """
365
368
  def __init__(self):
366
369
  CtrlInterface.__init__(self)
370
+ AutoCompInterfaceMixin.__init__(self)
367
371
 
368
372
  def dispatch(evt):
369
373
  """Fork events to the parent."""
@@ -414,8 +418,8 @@ class EditorInterface(CtrlInterface):
414
418
  'C-S-; pressed' : (0, _F(self.comment_out_line)),
415
419
  'C-: pressed' : (0, _F(self.uncomment_line)),
416
420
  'C-S-: pressed' : (0, _F(self.uncomment_line)),
417
- 'select_line' : (100, self.on_linesel_begin),
418
- 'select_lines' : (100, self.on_linesel_next),
421
+ 'select_line' : (11, self.on_linesel_begin),
422
+ 'select_lines' : (11, self.on_linesel_next),
419
423
  },
420
424
  10 : {
421
425
  'quit' : (0, self.on_itext_exit),
@@ -424,8 +428,8 @@ class EditorInterface(CtrlInterface):
424
428
  'down pressed' : (10, skip),
425
429
  'enter pressed' : (0, self.on_itext_selection),
426
430
  },
427
- 100 : {
428
- '*Ldrag move' : (100, self.on_linesel_motion),
431
+ 11 : {
432
+ '*Ldrag move' : (11, self.on_linesel_motion),
429
433
  'capture_lost' : (0, self.on_linesel_end),
430
434
  'Lbutton released' : (0, self.on_linesel_end),
431
435
  },
@@ -871,22 +875,10 @@ class EditorInterface(CtrlInterface):
871
875
  q = self.cpos
872
876
  return self.GetTextRange(p, q)
873
877
 
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
-
887
878
  ## --------------------------------
888
879
  ## Python syntax and indentation
889
880
  ## --------------------------------
881
+
890
882
  def on_indent_line(self, evt):
891
883
  if self.SelectedText:
892
884
  evt.Skip()
@@ -1191,10 +1183,10 @@ class EditorInterface(CtrlInterface):
1191
1183
  """
1192
1184
  n = self.LinesOnScreen() # lines completely visible
1193
1185
  m = n//2 if ln is None else ln % n if ln < n else n # ln[0:n]
1194
- vl = self.calc_vline(self.cline)
1186
+ vl = self._calc_vline(self.cline)
1195
1187
  self.ScrollToLine(vl - m)
1196
1188
 
1197
- def calc_vline(self, line):
1189
+ def _calc_vline(self, line):
1198
1190
  """Virtual line numberin the buffer window."""
1199
1191
  pos = self.PositionFromLine(line)
1200
1192
  w, h = self.PointFromPosition(pos)
@@ -1206,7 +1198,7 @@ class EditorInterface(CtrlInterface):
1206
1198
  """
1207
1199
  n = self.LinesOnScreen() # lines completely visible
1208
1200
  hl = self.FirstVisibleLine
1209
- vl = self.calc_vline(line)
1201
+ vl = self._calc_vline(line)
1210
1202
  if vl < hl:
1211
1203
  self.ScrollToLine(vl)
1212
1204
  elif vl > hl + n - 1:
@@ -1219,7 +1211,7 @@ class EditorInterface(CtrlInterface):
1219
1211
  """
1220
1212
  n = self.LinesOnScreen() # lines completely visible
1221
1213
  hl = self.FirstVisibleLine
1222
- vl = self.calc_vline(line)
1214
+ vl = self._calc_vline(line)
1223
1215
  if not hl + offset < vl < hl + n - 1 - offset:
1224
1216
  self.ScrollToLine(vl - n//2)
1225
1217
 
@@ -1512,16 +1504,6 @@ class EditorInterface(CtrlInterface):
1512
1504
  else:
1513
1505
  self.anchor = q
1514
1506
 
1515
- @contextmanager
1516
- def off_readonly(self):
1517
- """Set buffer to be writable (ReadOnly=False) temporarily."""
1518
- r = self.ReadOnly
1519
- try:
1520
- self.ReadOnly = 0
1521
- yield
1522
- finally:
1523
- self.ReadOnly = r
1524
-
1525
1507
  @contextmanager
1526
1508
  def save_attributes(self, **kwargs):
1527
1509
  """Save buffer attributes (e.g. ReadOnly=False)."""
@@ -1534,6 +1516,14 @@ class EditorInterface(CtrlInterface):
1534
1516
  for k, v in kwargs.items():
1535
1517
  setattr(self, k, v)
1536
1518
 
1519
+ def off_readonly(self):
1520
+ """Disables buffer read-only lock temporarily."""
1521
+ return self.save_attributes(ReadOnly=False)
1522
+
1523
+ def off_undocollection(self):
1524
+ """Disables buffer undo stack temporarily."""
1525
+ return self.save_attributes(UndoCollection=False)
1526
+
1537
1527
  ## --------------------------------
1538
1528
  ## Edit: comment / insert / kill
1539
1529
  ## --------------------------------
@@ -1640,7 +1630,7 @@ class EditorInterface(CtrlInterface):
1640
1630
  self.ReplaceSelection('')
1641
1631
 
1642
1632
 
1643
- class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
1633
+ class Buffer(EditorInterface, EditWindow):
1644
1634
  """Python code buffer.
1645
1635
 
1646
1636
  Attributes:
@@ -1766,7 +1756,6 @@ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
1766
1756
  def __init__(self, parent, filename=None, **kwargs):
1767
1757
  EditWindow.__init__(self, parent, **kwargs)
1768
1758
  EditorInterface.__init__(self)
1769
- AutoCompInterfaceMixin.__init__(self)
1770
1759
 
1771
1760
  self.parent = parent
1772
1761
  self.__filename = filename
@@ -1795,18 +1784,18 @@ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
1795
1784
  def clear(evt):
1796
1785
  ## """Clear selection and message, no skip."""
1797
1786
  ## *do not* clear autocomp, so that the event can skip to AutoComp properly.
1798
- ## if self.AutoCompActive():
1799
- ## self.AutoCompCancel() # may delete selection
1800
1787
  if self.CanEdit():
1801
- self.ReplaceSelection("")
1788
+ with self.off_undocollection():
1789
+ self.ReplaceSelection("")
1802
1790
  self.message("")
1803
1791
 
1804
1792
  def clear_autocomp(evt):
1805
- ## """Clear Autocomp, selection, and message."""
1793
+ ## """Clear autocomp, selection, and message."""
1806
1794
  if self.AutoCompActive():
1807
1795
  self.AutoCompCancel()
1808
1796
  if self.CanEdit():
1809
- self.ReplaceSelection("")
1797
+ with self.off_undocollection():
1798
+ self.ReplaceSelection("")
1810
1799
  self.message("")
1811
1800
 
1812
1801
  def fork(evt):
@@ -1840,7 +1829,7 @@ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
1840
1829
  '* released' : (0, skip, dispatch),
1841
1830
  'escape pressed' : (-1, self.on_enter_escmap),
1842
1831
  'C-h pressed' : (0, self.call_helpTip),
1843
- '. pressed' : (2, skip),
1832
+ '. pressed' : (2, self.OnEnterDot),
1844
1833
  'M-. pressed' : (2, self.call_word_autocomp),
1845
1834
  'M-/ pressed' : (3, self.call_apropos_autocomp),
1846
1835
  },
@@ -1922,7 +1911,9 @@ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
1922
1911
  def OnCallTipClick(self, evt):
1923
1912
  if self.CallTipActive():
1924
1913
  self.CallTipCancel()
1925
- self.CallTipShow(*self._calltips, N=None)
1914
+ pos, tip, more = self._calltips
1915
+ if more:
1916
+ self.CallTipShow(pos, tip, N=None)
1926
1917
  evt.Skip()
1927
1918
 
1928
1919
  def OnIndicatorClick(self, evt):
@@ -1960,6 +1951,14 @@ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
1960
1951
  self.update_caption()
1961
1952
  evt.Skip()
1962
1953
 
1954
+ def OnEnterDot(self, evt):
1955
+ p = self.cpos
1956
+ st = self.get_style(p-1)
1957
+ rst = self.get_style(p)
1958
+ if st not in ('moji', 'word', 'rparen') or rst == 'word':
1959
+ self.handler('quit', evt) # don't enter autocomp
1960
+ evt.Skip()
1961
+
1963
1962
  def on_activated(self, buf):
1964
1963
  """Called when the buffer is activated."""
1965
1964
  self.update_caption()
@@ -2052,6 +2051,22 @@ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
2052
2051
  dispatcher.send(signal='Interpreter.push',
2053
2052
  sender=self, command=None, more=False)
2054
2053
 
2054
+ def gen_text_at_caret(self):
2055
+ """Generates the selected text,
2056
+ otherwise the line or expression at the caret.
2057
+ """
2058
+ def _gen_text():
2059
+ text = self.SelectedText
2060
+ if text:
2061
+ yield text
2062
+ else:
2063
+ yield self.line_at_caret
2064
+ yield self.expr_at_caret
2065
+ return filter(None, _gen_text())
2066
+
2067
+ def eval_line(self):
2068
+ self.py_eval_line(self.globals, self.locals)
2069
+
2055
2070
  def py_eval_line(self, globals=None, locals=None):
2056
2071
  if self.CallTipActive():
2057
2072
  self.CallTipCancel()
@@ -2068,6 +2083,9 @@ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
2068
2083
  return
2069
2084
  self.message(status)
2070
2085
 
2086
+ def exec_region(self):
2087
+ self.py_exec_region(self.globals, self.locals)
2088
+
2071
2089
  def py_exec_region(self, globals=None, locals=None, filename=None):
2072
2090
  if not filename:
2073
2091
  filename = self.filename
@@ -2100,23 +2118,6 @@ class Buffer(AutoCompInterfaceMixin, EditorInterface, EditWindow):
2100
2118
  self.handler('buffer_region_executed', self)
2101
2119
  self.message("Evaluated {!r} successfully.".format(filename))
2102
2120
  self.AnnotationClearAll()
2103
-
2104
- def py_get_region(self, line):
2105
- """Line numbers of code head and tail containing the line.
2106
-
2107
- Requires a code object.
2108
- If the code doesn't exist, return the folding region.
2109
- """
2110
- if not self.code:
2111
- return self.get_region(line)
2112
- lc, le = 0, self.LineCount
2113
- linestarts = list(dis.findlinestarts(self.code))
2114
- for i, ln in reversed(linestarts):
2115
- if line >= ln-1:
2116
- lc = ln-1
2117
- break
2118
- le = ln-1
2119
- return lc, le
2120
2121
 
2121
2122
 
2122
2123
  class EditorBook(AuiNotebook, CtrlInterface):
@@ -2402,7 +2403,7 @@ class EditorBook(AuiNotebook, CtrlInterface):
2402
2403
  return True
2403
2404
  return False
2404
2405
  except Exception as e:
2405
- self.post_message(f"Failed to load {filename!r}:", e)
2406
+ self.post_message(f"Failed to load {filename!r}.", e)
2406
2407
  self.delete_buffer(buf)
2407
2408
  return False
2408
2409
 
@@ -2410,6 +2411,7 @@ class EditorBook(AuiNotebook, CtrlInterface):
2410
2411
  """Open the specified file."""
2411
2412
  if not filename:
2412
2413
  with wx.FileDialog(self, "Open buffer",
2414
+ defaultDir=os.path.dirname(self.buffer.filename),
2413
2415
  wildcard='|'.join(self.wildcards),
2414
2416
  style=wx.FD_OPEN|wx.FD_MULTIPLE) as dlg:
2415
2417
  if dlg.ShowModal() == wx.ID_OK:
@@ -2444,7 +2446,7 @@ class EditorBook(AuiNotebook, CtrlInterface):
2444
2446
  return True
2445
2447
  return False
2446
2448
  except Exception as e:
2447
- self.post_message(f"Failed to save {filename!r}:", e)
2449
+ self.post_message(f"Failed to save {filename!r}.", e)
2448
2450
  return False
2449
2451
 
2450
2452
  def load_buffer(self, buf=None):
@@ -2477,6 +2479,7 @@ class EditorBook(AuiNotebook, CtrlInterface):
2477
2479
  """Confirm the saveas with the dialog."""
2478
2480
  buf = buf or self.buffer
2479
2481
  with wx.FileDialog(self, "Save buffer as",
2482
+ defaultDir=os.path.dirname(self.buffer.filename),
2480
2483
  defaultFile=re.sub(r'[\/:*?"<>|]', '_', buf.name),
2481
2484
  wildcard='|'.join(self.wildcards),
2482
2485
  style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dlg:
@@ -2519,11 +2522,10 @@ class EditorBook(AuiNotebook, CtrlInterface):
2519
2522
  class Interpreter(interpreter.Interpreter):
2520
2523
  """Interpreter based on code.InteractiveInterpreter.
2521
2524
  """
2522
- def __init__(self, *args, **kwargs):
2523
- parent = kwargs.pop('interpShell')
2525
+ def __init__(self, interpShell, *args, **kwargs):
2524
2526
  interpreter.Interpreter.__init__(self, *args, **kwargs)
2525
2527
 
2526
- self.parent = parent
2528
+ self.parent = interpShell
2527
2529
  self.globals = self.locals
2528
2530
 
2529
2531
  def runcode(self, code):
@@ -2587,7 +2589,7 @@ class Interpreter(interpreter.Interpreter):
2587
2589
  return interpreter.Interpreter.getCallTip(self) # dummy
2588
2590
 
2589
2591
 
2590
- class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
2592
+ class Nautilus(EditorInterface, Shell):
2591
2593
  """Nautilus in the Shell.
2592
2594
 
2593
2595
  Facade objects for accessing the APIs:
@@ -2624,8 +2626,8 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
2624
2626
 
2625
2627
  C-up : [0] retrieve previous history
2626
2628
  C-down : [0] retrieve next history
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
+ C-j, M-j : [0] tooltip of eval (for the selected or focused word)
2630
+ C-h, M-h : [0] calltip of help (for the selected or focused func)
2629
2631
  TAB : [1] history-comp
2630
2632
  M-p : [1] retrieve previous history in history-comp mode
2631
2633
  M-n : [1] retrieve next history in history-comp mode
@@ -2697,7 +2699,9 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
2697
2699
  raise TypeError("primitive objects cannot be targeted")
2698
2700
 
2699
2701
  self.__target = obj
2700
- self.interp.locals = obj.__dict__
2702
+ self.locals = obj.__dict__
2703
+ self.globals = obj.__dict__
2704
+ self.globals.update(self.__globals)
2701
2705
  try:
2702
2706
  obj.self = obj
2703
2707
  obj.this = inspect.getmodule(obj)
@@ -2730,9 +2734,9 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
2730
2734
  @globals.deleter
2731
2735
  def globals(self): # internal use only
2732
2736
  self.interp.globals = self.__target.__dict__
2737
+ self.interp.globals.update(self.__globals)
2733
2738
 
2734
- ## (override)
2735
- wrap = EditorInterface.wrap
2739
+ __globals = {}
2736
2740
 
2737
2741
  def __init__(self, parent, target, name="root",
2738
2742
  introText=None,
@@ -2741,14 +2745,13 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
2741
2745
  **kwargs):
2742
2746
  Shell.__init__(self, parent,
2743
2747
  locals=target.__dict__,
2744
- interpShell=self,
2748
+ interpShell=self, # **kwds of InterpClass
2745
2749
  InterpClass=Interpreter,
2746
2750
  introText=introText,
2747
2751
  startupScript=startupScript,
2748
- execStartupScript=execStartupScript, # if True, executes ~/.py
2752
+ execStartupScript=execStartupScript, # executes ~/.py
2749
2753
  **kwargs)
2750
2754
  EditorInterface.__init__(self)
2751
- AutoCompInterfaceMixin.__init__(self)
2752
2755
 
2753
2756
  self.parent = parent #: parent<ShellFrame> is not Parent<AuiNotebook>
2754
2757
  self.target = target
@@ -2780,28 +2783,20 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
2780
2783
  def clear(evt):
2781
2784
  ## """Clear selection and message, no skip."""
2782
2785
  ## *do not* clear autocomp, so that the event can skip to AutoComp properly.
2783
- ## if self.AutoCompActive():
2784
- ## self.AutoCompCancel() # may delete selection
2785
2786
  if self.CanEdit():
2786
- self.ReplaceSelection("")
2787
+ with self.off_undocollection():
2788
+ self.ReplaceSelection("")
2787
2789
  self.message("")
2788
2790
 
2789
2791
  def clear_autocomp(evt):
2790
- ## """Clear Autocomp, selection, and message."""
2792
+ ## """Clear autocomp, selection, and message."""
2791
2793
  if self.AutoCompActive():
2792
2794
  self.AutoCompCancel()
2793
2795
  if self.CanEdit():
2794
- self.ReplaceSelection("")
2796
+ with self.off_undocollection():
2797
+ self.ReplaceSelection("")
2795
2798
  self.message("")
2796
2799
 
2797
- def skip_autocomp(evt):
2798
- ## """Don't eat backward prompt whitespace."""
2799
- ## Prevent autocomp from eating prompts.
2800
- ## Quit to avoid backspace over the last non-continuation prompt.
2801
- if self.cpos == self.bolc:
2802
- self.handler('quit', evt)
2803
- evt.Skip()
2804
-
2805
2800
  def fork(evt):
2806
2801
  self.handler.fork(self.handler.current_event, evt)
2807
2802
 
@@ -2844,7 +2839,6 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
2844
2839
  'C-enter pressed' : (0, _F(self.insertLineBreak)),
2845
2840
  'C-S-enter pressed' : (0, _F(self.insertLineBreak)),
2846
2841
  '*enter pressed' : (0, ), # -> OnShowCompHistory 無効
2847
- 'left pressed' : (0, self.OnBackspace),
2848
2842
  'C-[ pressed' : (0, _F(self.goto_previous_mark_arrow)),
2849
2843
  'C-S-[ pressed' : (0, _F(self.goto_previous_mark_arrow, selection=1)),
2850
2844
  'C-] pressed' : (0, _F(self.goto_next_mark_arrow)),
@@ -2859,10 +2853,8 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
2859
2853
  'C-S-insert pressed' : (0, _F(self.Paste, rectangle=1)),
2860
2854
  'C-j pressed' : (0, self.eval_line),
2861
2855
  'M-j pressed' : (0, self.exec_region),
2862
- 'C-S-j pressed' : (0, self.exec_region),
2863
2856
  'C-h pressed' : (0, self.call_helpTip),
2864
2857
  'M-h pressed' : (0, self.call_helpDoc),
2865
- 'C-S-h pressed' : (0, self.call_helpDoc),
2866
2858
  '. pressed' : (2, self.OnEnterDot),
2867
2859
  'tab pressed' : (1, self.call_history_comp),
2868
2860
  'M-p pressed' : (1, self.call_history_comp),
@@ -2915,7 +2907,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
2915
2907
  'S-[a-z\\] released' : (2, self.call_word_autocomp),
2916
2908
  '\\ released' : (2, self.call_word_autocomp),
2917
2909
  '*delete pressed' : (2, skip),
2918
- '*backspace pressed' : (2, skip_autocomp),
2910
+ '*backspace pressed' : (2, self.OnBackspace),
2919
2911
  '*backspace released' : (2, self.call_word_autocomp),
2920
2912
  'C-S-backspace pressed' : (2, ),
2921
2913
  'C-j pressed' : (2, self.eval_line),
@@ -2943,7 +2935,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
2943
2935
  'S-[a-z\\] released' : (3, self.call_apropos_autocomp),
2944
2936
  '\\ released' : (3, self.call_apropos_autocomp),
2945
2937
  '*delete pressed' : (3, skip),
2946
- '*backspace pressed' : (3, skip_autocomp),
2938
+ '*backspace pressed' : (3, self.OnBackspace),
2947
2939
  '*backspace released' : (3, self.call_apropos_autocomp),
2948
2940
  'C-S-backspace pressed' : (3, ),
2949
2941
  'C-j pressed' : (3, self.eval_line),
@@ -2971,7 +2963,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
2971
2963
  'S-[a-z\\] released' : (4, self.call_text_autocomp),
2972
2964
  '\\ released' : (4, self.call_text_autocomp),
2973
2965
  '*delete pressed' : (4, skip),
2974
- '*backspace pressed' : (4, skip_autocomp),
2966
+ '*backspace pressed' : (4, self.OnBackspace),
2975
2967
  '*backspace released' : (4, self.call_text_autocomp),
2976
2968
  'C-S-backspace pressed' : (4, ),
2977
2969
  'C-j pressed' : (4, self.eval_line),
@@ -3000,7 +2992,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
3000
2992
  '\\ released' : (5, self.call_module_autocomp),
3001
2993
  'M-m pressed' : (5, _F(self.call_module_autocomp, force=1)),
3002
2994
  '*delete pressed' : (5, skip),
3003
- '*backspace pressed' : (5, skip_autocomp),
2995
+ '*backspace pressed' : (5, self.OnBackspace),
3004
2996
  '*backspace released' : (5, self.call_module_autocomp),
3005
2997
  'C-S-backspace pressed' : (5, ),
3006
2998
  '*alt pressed' : (5, ),
@@ -3076,12 +3068,11 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
3076
3068
  evt.Skip()
3077
3069
 
3078
3070
  def OnBackspace(self, evt):
3079
- """Called when backspace (or left key) pressed.
3080
- Backspace-guard from Autocomp eating over a prompt whitespace
3071
+ """Called when backspace pressed.
3072
+ Backspace-guard from autocomp eating over a prompt whitespace.
3081
3073
  """
3082
3074
  if self.cpos == self.bolc:
3083
- ## do not skip to prevent autocomp eats prompt,
3084
- ## so not to backspace over the latest non-continuation prompt
3075
+ self.handler('quit', evt) # don't eat backward prompt
3085
3076
  return
3086
3077
  evt.Skip()
3087
3078
 
@@ -3153,7 +3144,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
3153
3144
  self.ReplaceSelection('self')
3154
3145
  elif st not in ('moji', 'word', 'rparen') or rst == 'word':
3155
3146
  self.handler('quit', evt) # don't enter autocomp
3156
- self.ReplaceSelection('.') # just write down a dot.
3147
+ evt.Skip()
3157
3148
 
3158
3149
  def on_enter_escmap(self, evt):
3159
3150
  self.__caret_mode = self.CaretPeriod
@@ -3203,7 +3194,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
3203
3194
  def magic(self, cmd):
3204
3195
  """Called before command pushed.
3205
3196
 
3206
- (override) disable old magic: `f x --> f(x)`
3197
+ (override) Disable old magic: `f x --> f(x)`.
3207
3198
  """
3208
3199
  if cmd:
3209
3200
  if cmd[0:2] == '??': cmd = 'help({})'.format(cmd[2:])
@@ -3461,7 +3452,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
3461
3452
  (override) Add globals when executing su:startupScript.
3462
3453
  Fix history point.
3463
3454
  """
3464
- ## self.globals = self.locals
3455
+ keys = set(self.locals.keys()) # check for locals map changes
3465
3456
  self.promptPosEnd = self.TextLength # fix history point
3466
3457
  if su and os.path.isfile(su):
3467
3458
  self.push("print('Startup script executed:', {0!r})\n".format(su))
@@ -3471,6 +3462,7 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
3471
3462
  else:
3472
3463
  self.push("")
3473
3464
  self.interp.startupScript = None
3465
+ self.__globals = {k: self.locals[k] for k in (self.locals.keys() - keys)}
3474
3466
 
3475
3467
  def Paste(self, rectangle=False):
3476
3468
  """Replace selection with clipboard contents.
@@ -3616,9 +3608,22 @@ class Nautilus(AutoCompInterfaceMixin, EditorInterface, Shell):
3616
3608
  self.cpos, self.anchor = self.anchor, self.cpos
3617
3609
  self.EnsureCaretVisible()
3618
3610
 
3619
- def eval_line(self, evt):
3620
- """Evaluate the selected word or line.
3611
+ def gen_text_at_caret(self):
3612
+ """Generates the selected text,
3613
+ otherwise the line or expression at the caret.
3614
+ (override) Generates command line (that starts with a prompt).
3621
3615
  """
3616
+ def _gen_text():
3617
+ text = self.SelectedText
3618
+ if text:
3619
+ yield text
3620
+ else:
3621
+ yield self.getCommand() # self.line_at_caret
3622
+ yield self.expr_at_caret
3623
+ return filter(None, _gen_text())
3624
+
3625
+ def eval_line(self, evt):
3626
+ """Evaluate the selected word or line."""
3622
3627
  if self.CallTipActive():
3623
3628
  self.CallTipCancel()
3624
3629
 
@@ -122,7 +122,7 @@ class Plugin(Layer):
122
122
  (1, "&Load file", Icon('open'),
123
123
  lambda v: self.load_media()),
124
124
 
125
- (2, "&Snapshot", Icon('clock'),
125
+ (2, "&Snapshot", Icon('clip'),
126
126
  lambda v: self.snapshot(),
127
127
  lambda v: v.Enable(self._path is not None)),
128
128
  (),
@@ -175,7 +175,7 @@ class Plugin(Layer):
175
175
  def load_media(self, path=None):
176
176
  if path is None:
177
177
  with wx.FileDialog(self, "Choose a media file",
178
- style=wx.FD_OPEN|wx.FD_CHANGE_DIR|wx.FD_FILE_MUST_EXIST) as dlg:
178
+ style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST) as dlg:
179
179
  if dlg.ShowModal() != wx.ID_OK:
180
180
  return None
181
181
  path = dlg.Path
mwx/utilus.py CHANGED
@@ -886,7 +886,7 @@ class FSM(dict):
886
886
  return False
887
887
 
888
888
 
889
- class TreeList(object):
889
+ class TreeList:
890
890
  """Interface class for tree list control.
891
891
 
892
892
  >>> list[item:(key,value)]