wxPython 4.3.2__cp315-cp315-win_amd64.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.
Files changed (472) hide show
  1. wx/WebView2Loader.dll +0 -0
  2. wx/__init__.py +22 -0
  3. wx/__init__.pyi +10 -0
  4. wx/__version__.py +9 -0
  5. wx/__version__.pyi +15 -0
  6. wx/_adv.cp315-win_amd64.pyd +0 -0
  7. wx/_aui.cp315-win_amd64.pyd +0 -0
  8. wx/_core.cp315-win_amd64.pyd +0 -0
  9. wx/_dataview.cp315-win_amd64.pyd +0 -0
  10. wx/_glcanvas.cp315-win_amd64.pyd +0 -0
  11. wx/_grid.cp315-win_amd64.pyd +0 -0
  12. wx/_html.cp315-win_amd64.pyd +0 -0
  13. wx/_html2.cp315-win_amd64.pyd +0 -0
  14. wx/_media.cp315-win_amd64.pyd +0 -0
  15. wx/_msw.cp315-win_amd64.pyd +0 -0
  16. wx/_propgrid.cp315-win_amd64.pyd +0 -0
  17. wx/_ribbon.cp315-win_amd64.pyd +0 -0
  18. wx/_richtext.cp315-win_amd64.pyd +0 -0
  19. wx/_stc.cp315-win_amd64.pyd +0 -0
  20. wx/_xml.cp315-win_amd64.pyd +0 -0
  21. wx/_xrc.cp315-win_amd64.pyd +0 -0
  22. wx/adv.py +127 -0
  23. wx/adv.pyi +5931 -0
  24. wx/aui.py +70 -0
  25. wx/aui.pyi +4805 -0
  26. wx/core.py +3417 -0
  27. wx/core.pyi +62949 -0
  28. wx/dataview.py +176 -0
  29. wx/dataview.pyi +3828 -0
  30. wx/gizmos.py +18 -0
  31. wx/glcanvas.py +13 -0
  32. wx/glcanvas.pyi +544 -0
  33. wx/grid.py +237 -0
  34. wx/grid.pyi +5678 -0
  35. wx/html.py +38 -0
  36. wx/html.pyi +3283 -0
  37. wx/html2.py +46 -0
  38. wx/html2.pyi +1301 -0
  39. wx/include/wxPython/sip.h +1938 -0
  40. wx/include/wxPython/wxpy_api.h +418 -0
  41. wx/lib/CDate.py +201 -0
  42. wx/lib/ClickableHtmlWindow.py +57 -0
  43. wx/lib/__init__.py +0 -0
  44. wx/lib/activex.py +178 -0
  45. wx/lib/activexwrapper.py +153 -0
  46. wx/lib/agw/__init__.py +128 -0
  47. wx/lib/agw/advancedsplash.py +563 -0
  48. wx/lib/agw/aquabutton.py +1127 -0
  49. wx/lib/agw/artmanager.py +2110 -0
  50. wx/lib/agw/aui/__init__.py +295 -0
  51. wx/lib/agw/aui/aui_constants.py +2616 -0
  52. wx/lib/agw/aui/aui_switcherdialog.py +1232 -0
  53. wx/lib/agw/aui/aui_utilities.py +648 -0
  54. wx/lib/agw/aui/auibar.py +4045 -0
  55. wx/lib/agw/aui/auibook.py +6288 -0
  56. wx/lib/agw/aui/dockart.py +1198 -0
  57. wx/lib/agw/aui/framemanager.py +10485 -0
  58. wx/lib/agw/aui/tabart.py +2749 -0
  59. wx/lib/agw/aui/tabmdi.py +679 -0
  60. wx/lib/agw/balloontip.py +1157 -0
  61. wx/lib/agw/buttonpanel.py +2787 -0
  62. wx/lib/agw/cubecolourdialog.py +3529 -0
  63. wx/lib/agw/customtreectrl.py +9908 -0
  64. wx/lib/agw/data/ShortcutEditor_1.png +0 -0
  65. wx/lib/agw/data/ShortcutEditor_1_thumb.png +0 -0
  66. wx/lib/agw/data/ShortcutEditor_2.png +0 -0
  67. wx/lib/agw/data/ShortcutEditor_2_thumb.png +0 -0
  68. wx/lib/agw/data/ShortcutEditor_3.png +0 -0
  69. wx/lib/agw/data/ShortcutEditor_3_thumb.png +0 -0
  70. wx/lib/agw/data/ShortcutEditor_4.png +0 -0
  71. wx/lib/agw/data/ShortcutEditor_4_thumb.png +0 -0
  72. wx/lib/agw/data/default_help_text.html +105 -0
  73. wx/lib/agw/flatmenu.py +7392 -0
  74. wx/lib/agw/flatnotebook.py +6669 -0
  75. wx/lib/agw/floatspin.py +1820 -0
  76. wx/lib/agw/fmcustomizedlg.py +535 -0
  77. wx/lib/agw/fmresources.py +407 -0
  78. wx/lib/agw/foldpanelbar.py +2282 -0
  79. wx/lib/agw/fourwaysplitter.py +1130 -0
  80. wx/lib/agw/genericmessagedialog.py +1549 -0
  81. wx/lib/agw/gradientbutton.py +731 -0
  82. wx/lib/agw/hyperlink.py +664 -0
  83. wx/lib/agw/hypertreelist.py +5756 -0
  84. wx/lib/agw/infobar.py +885 -0
  85. wx/lib/agw/knobctrl.py +944 -0
  86. wx/lib/agw/labelbook.py +3028 -0
  87. wx/lib/agw/multidirdialog.py +581 -0
  88. wx/lib/agw/peakmeter.py +1028 -0
  89. wx/lib/agw/persist/__init__.py +188 -0
  90. wx/lib/agw/persist/persist_constants.py +283 -0
  91. wx/lib/agw/persist/persist_handlers.py +2614 -0
  92. wx/lib/agw/persist/persistencemanager.py +863 -0
  93. wx/lib/agw/piectrl.py +1082 -0
  94. wx/lib/agw/pybusyinfo.py +399 -0
  95. wx/lib/agw/pycollapsiblepane.py +940 -0
  96. wx/lib/agw/pygauge.py +570 -0
  97. wx/lib/agw/pyprogress.py +916 -0
  98. wx/lib/agw/ribbon/__init__.py +198 -0
  99. wx/lib/agw/ribbon/art.py +219 -0
  100. wx/lib/agw/ribbon/art_aui.py +1283 -0
  101. wx/lib/agw/ribbon/art_default.py +81 -0
  102. wx/lib/agw/ribbon/art_internal.py +248 -0
  103. wx/lib/agw/ribbon/art_msw.py +2735 -0
  104. wx/lib/agw/ribbon/art_osx.py +52 -0
  105. wx/lib/agw/ribbon/bar.py +1259 -0
  106. wx/lib/agw/ribbon/buttonbar.py +1317 -0
  107. wx/lib/agw/ribbon/control.py +205 -0
  108. wx/lib/agw/ribbon/gallery.py +973 -0
  109. wx/lib/agw/ribbon/page.py +946 -0
  110. wx/lib/agw/ribbon/panel.py +1170 -0
  111. wx/lib/agw/ribbon/toolbar.py +1441 -0
  112. wx/lib/agw/rulerctrl.py +1885 -0
  113. wx/lib/agw/scrolledthumbnail.py +2116 -0
  114. wx/lib/agw/shapedbutton.py +1809 -0
  115. wx/lib/agw/shortcuteditor.py +2642 -0
  116. wx/lib/agw/speedmeter.py +1800 -0
  117. wx/lib/agw/supertooltip.py +1443 -0
  118. wx/lib/agw/thumbnailctrl.py +529 -0
  119. wx/lib/agw/toasterbox.py +1327 -0
  120. wx/lib/agw/ultimatelistctrl.py +13671 -0
  121. wx/lib/agw/xlsgrid.py +2111 -0
  122. wx/lib/agw/zoombar.py +1336 -0
  123. wx/lib/analogclock/__init__.py +140 -0
  124. wx/lib/analogclock/analogclock.py +630 -0
  125. wx/lib/analogclock/helpers.py +986 -0
  126. wx/lib/analogclock/lib_setup/__init__.py +0 -0
  127. wx/lib/analogclock/lib_setup/buttontreectrlpanel.py +297 -0
  128. wx/lib/analogclock/lib_setup/fontselect.py +57 -0
  129. wx/lib/analogclock/setup.py +490 -0
  130. wx/lib/analogclock/styles.py +47 -0
  131. wx/lib/anchors.py +103 -0
  132. wx/lib/art/__init__.py +4 -0
  133. wx/lib/art/flagart.py +1583 -0
  134. wx/lib/art/img2pyartprov.py +56 -0
  135. wx/lib/busy.py +152 -0
  136. wx/lib/buttons.py +1140 -0
  137. wx/lib/calendar.py +1596 -0
  138. wx/lib/checkbox.py +837 -0
  139. wx/lib/colourchooser/__init__.py +36 -0
  140. wx/lib/colourchooser/canvas.py +145 -0
  141. wx/lib/colourchooser/intl.py +24 -0
  142. wx/lib/colourchooser/pycolourbox.py +89 -0
  143. wx/lib/colourchooser/pycolourchooser.py +626 -0
  144. wx/lib/colourchooser/pycolourslider.py +98 -0
  145. wx/lib/colourchooser/pypalette.py +208 -0
  146. wx/lib/colourdb.py +740 -0
  147. wx/lib/colourselect.py +385 -0
  148. wx/lib/colourutils.py +118 -0
  149. wx/lib/combotreebox.py +944 -0
  150. wx/lib/delayedresult.py +420 -0
  151. wx/lib/dialogs.py +510 -0
  152. wx/lib/docview.py +3210 -0
  153. wx/lib/dragscroller.py +79 -0
  154. wx/lib/editor/README.txt +77 -0
  155. wx/lib/editor/__init__.py +24 -0
  156. wx/lib/editor/editor.py +974 -0
  157. wx/lib/editor/images.py +15 -0
  158. wx/lib/editor/selection.py +44 -0
  159. wx/lib/embeddedimage.py +76 -0
  160. wx/lib/eventStack.py +136 -0
  161. wx/lib/eventwatcher.py +440 -0
  162. wx/lib/evtmgr.py +521 -0
  163. wx/lib/expando.py +393 -0
  164. wx/lib/fancytext.py +494 -0
  165. wx/lib/filebrowsebutton.py +461 -0
  166. wx/lib/flashwin.py +262 -0
  167. wx/lib/flashwin_old.py +651 -0
  168. wx/lib/floatcanvas/FCEvents.py +53 -0
  169. wx/lib/floatcanvas/FCObjects.py +2910 -0
  170. wx/lib/floatcanvas/FloatCanvas.py +1025 -0
  171. wx/lib/floatcanvas/GUIMode.py +396 -0
  172. wx/lib/floatcanvas/NavCanvas.py +162 -0
  173. wx/lib/floatcanvas/Resources.py +319 -0
  174. wx/lib/floatcanvas/ScreenShot.py +1788 -0
  175. wx/lib/floatcanvas/Utilities/BBox.py +313 -0
  176. wx/lib/floatcanvas/Utilities/Colors.py +137 -0
  177. wx/lib/floatcanvas/Utilities/GUI.py +91 -0
  178. wx/lib/floatcanvas/Utilities/__init__.py +7 -0
  179. wx/lib/floatcanvas/__init__.py +124 -0
  180. wx/lib/foldmenu.py +89 -0
  181. wx/lib/gestures.py +310 -0
  182. wx/lib/gizmos/__init__.py +18 -0
  183. wx/lib/gizmos/dynamicsash.py +1202 -0
  184. wx/lib/gizmos/ledctrl.py +299 -0
  185. wx/lib/gizmos/treelistctrl.py +87 -0
  186. wx/lib/graphics.py +1942 -0
  187. wx/lib/gridmovers.py +516 -0
  188. wx/lib/iewin.py +249 -0
  189. wx/lib/iewin_old.py +894 -0
  190. wx/lib/imagebrowser.py +853 -0
  191. wx/lib/imageutils.py +163 -0
  192. wx/lib/infoframe.py +490 -0
  193. wx/lib/inspection.py +1254 -0
  194. wx/lib/intctrl.py +990 -0
  195. wx/lib/itemspicker.py +256 -0
  196. wx/lib/langlistctrl.py +480 -0
  197. wx/lib/layoutf.py +271 -0
  198. wx/lib/masked/__init__.py +27 -0
  199. wx/lib/masked/combobox.py +839 -0
  200. wx/lib/masked/ctrl.py +108 -0
  201. wx/lib/masked/ipaddrctrl.py +241 -0
  202. wx/lib/masked/maskededit.py +7262 -0
  203. wx/lib/masked/numctrl.py +2000 -0
  204. wx/lib/masked/textctrl.py +465 -0
  205. wx/lib/masked/timectrl.py +1465 -0
  206. wx/lib/mixins/__init__.py +17 -0
  207. wx/lib/mixins/grid.py +47 -0
  208. wx/lib/mixins/gridlabelrenderer.py +277 -0
  209. wx/lib/mixins/imagelist.py +77 -0
  210. wx/lib/mixins/inspection.py +184 -0
  211. wx/lib/mixins/listctrl.py +893 -0
  212. wx/lib/mixins/rubberband.py +403 -0
  213. wx/lib/mixins/treemixin.py +678 -0
  214. wx/lib/msgpanel.py +95 -0
  215. wx/lib/multisash.py +746 -0
  216. wx/lib/myole4ax.idl +178 -0
  217. wx/lib/myole4ax.tlb +0 -0
  218. wx/lib/newevent.py +229 -0
  219. wx/lib/newevent.pyi +25 -0
  220. wx/lib/nvdlg.py +156 -0
  221. wx/lib/ogl/__init__.py +13 -0
  222. wx/lib/ogl/basic.py +3989 -0
  223. wx/lib/ogl/bmpshape.py +86 -0
  224. wx/lib/ogl/canvas.py +467 -0
  225. wx/lib/ogl/composit.py +1576 -0
  226. wx/lib/ogl/diagram.py +230 -0
  227. wx/lib/ogl/divided.py +482 -0
  228. wx/lib/ogl/drawn.py +898 -0
  229. wx/lib/ogl/lines.py +1809 -0
  230. wx/lib/ogl/oglmisc.py +607 -0
  231. wx/lib/pdfviewer/__init__.py +113 -0
  232. wx/lib/pdfviewer/bitmaps/ArrowLeft.png +0 -0
  233. wx/lib/pdfviewer/bitmaps/ArrowRight.png +0 -0
  234. wx/lib/pdfviewer/bitmaps/DirectionH.png +0 -0
  235. wx/lib/pdfviewer/bitmaps/DirectionV.png +0 -0
  236. wx/lib/pdfviewer/bitmaps/PlayerFirst.png +0 -0
  237. wx/lib/pdfviewer/bitmaps/PlayerLast.png +0 -0
  238. wx/lib/pdfviewer/bitmaps/PlayerNext.png +0 -0
  239. wx/lib/pdfviewer/bitmaps/PlayerPrev.png +0 -0
  240. wx/lib/pdfviewer/bitmaps/Printer.png +0 -0
  241. wx/lib/pdfviewer/bitmaps/ReadMe.txt +28 -0
  242. wx/lib/pdfviewer/bitmaps/Save.png +0 -0
  243. wx/lib/pdfviewer/bitmaps/ZoomIn.png +0 -0
  244. wx/lib/pdfviewer/bitmaps/ZoomOut.png +0 -0
  245. wx/lib/pdfviewer/bitmaps/encode_bitmaps.py +37 -0
  246. wx/lib/pdfviewer/buttonpanel.py +285 -0
  247. wx/lib/pdfviewer/images.py +240 -0
  248. wx/lib/pdfviewer/viewer.py +1118 -0
  249. wx/lib/pdfwin.py +295 -0
  250. wx/lib/pdfwin_old.py +789 -0
  251. wx/lib/platebtn.py +789 -0
  252. wx/lib/plot/CHANGELOG.md +150 -0
  253. wx/lib/plot/README.md +16 -0
  254. wx/lib/plot/__init__.py +46 -0
  255. wx/lib/plot/__main__.py +5 -0
  256. wx/lib/plot/examples/__init__.py +0 -0
  257. wx/lib/plot/examples/demo.py +1010 -0
  258. wx/lib/plot/examples/simple_example.py +56 -0
  259. wx/lib/plot/plotcanvas.py +2985 -0
  260. wx/lib/plot/polyobjects.py +1524 -0
  261. wx/lib/plot/utils.py +334 -0
  262. wx/lib/popupctl.py +251 -0
  263. wx/lib/printout.py +1155 -0
  264. wx/lib/progressindicator.py +151 -0
  265. wx/lib/pubsub/LICENSE_BSD_Simple.txt +23 -0
  266. wx/lib/pubsub/README_WxPython.txt +22 -0
  267. wx/lib/pubsub/RELEASE_NOTES.txt +71 -0
  268. wx/lib/pubsub/__init__.py +25 -0
  269. wx/lib/pubsub/core/__init__.py +92 -0
  270. wx/lib/pubsub/core/arg1/__init__.py +16 -0
  271. wx/lib/pubsub/core/arg1/listenerimpl.py +97 -0
  272. wx/lib/pubsub/core/arg1/publisher.py +40 -0
  273. wx/lib/pubsub/core/arg1/publishermixin.py +34 -0
  274. wx/lib/pubsub/core/arg1/topicargspecimpl.py +66 -0
  275. wx/lib/pubsub/core/arg1/topicmgrimpl.py +19 -0
  276. wx/lib/pubsub/core/callables.py +198 -0
  277. wx/lib/pubsub/core/imp2.py +62 -0
  278. wx/lib/pubsub/core/itopicdefnprovider.py +0 -0
  279. wx/lib/pubsub/core/kwargs/__init__.py +16 -0
  280. wx/lib/pubsub/core/kwargs/datamsg.py +27 -0
  281. wx/lib/pubsub/core/kwargs/listenerimpl.py +93 -0
  282. wx/lib/pubsub/core/kwargs/publisher.py +77 -0
  283. wx/lib/pubsub/core/kwargs/publishermixin.py +65 -0
  284. wx/lib/pubsub/core/kwargs/topicargspecimpl.py +216 -0
  285. wx/lib/pubsub/core/kwargs/topicmgrimpl.py +13 -0
  286. wx/lib/pubsub/core/listener.py +40 -0
  287. wx/lib/pubsub/core/listenerbase.py +185 -0
  288. wx/lib/pubsub/core/notificationmgr.py +185 -0
  289. wx/lib/pubsub/core/publisherbase.py +189 -0
  290. wx/lib/pubsub/core/topicargspec.py +77 -0
  291. wx/lib/pubsub/core/topicdefnprovider.py +631 -0
  292. wx/lib/pubsub/core/topicexc.py +72 -0
  293. wx/lib/pubsub/core/topicmgr.py +454 -0
  294. wx/lib/pubsub/core/topicobj.py +472 -0
  295. wx/lib/pubsub/core/topictreetraverser.py +143 -0
  296. wx/lib/pubsub/core/topicutils.py +119 -0
  297. wx/lib/pubsub/core/treeconfig.py +21 -0
  298. wx/lib/pubsub/core/validatedefnargs.py +29 -0
  299. wx/lib/pubsub/core/weakmethod.py +102 -0
  300. wx/lib/pubsub/policies.py +24 -0
  301. wx/lib/pubsub/pub.py +199 -0
  302. wx/lib/pubsub/setuparg1.py +47 -0
  303. wx/lib/pubsub/setupkwargs.py +29 -0
  304. wx/lib/pubsub/utils/__init__.py +27 -0
  305. wx/lib/pubsub/utils/exchandling.py +100 -0
  306. wx/lib/pubsub/utils/misc.py +99 -0
  307. wx/lib/pubsub/utils/notification.py +331 -0
  308. wx/lib/pubsub/utils/topictreeprinter.py +195 -0
  309. wx/lib/pubsub/utils/xmltopicdefnprovider.py +286 -0
  310. wx/lib/pydocview.py +3300 -0
  311. wx/lib/rcsizer.py +227 -0
  312. wx/lib/resizewidget.py +357 -0
  313. wx/lib/scrolledpanel.py +243 -0
  314. wx/lib/sheet.py +350 -0
  315. wx/lib/sized_controls.py +691 -0
  316. wx/lib/softwareupdate.py +355 -0
  317. wx/lib/splitter.py +925 -0
  318. wx/lib/statbmp.py +199 -0
  319. wx/lib/stattext.py +321 -0
  320. wx/lib/throbber.py +424 -0
  321. wx/lib/ticker.py +306 -0
  322. wx/lib/ticker_xrc.py +48 -0
  323. wx/lib/utils.py +89 -0
  324. wx/lib/wordwrap.py +97 -0
  325. wx/lib/wxcairo/__init__.py +139 -0
  326. wx/lib/wxcairo/wx_cairocffi.py +200 -0
  327. wx/lib/wxcairo/wx_pycairo.py +455 -0
  328. wx/lib/wxpTag.py +274 -0
  329. wx/libcairo-2.dll +0 -0
  330. wx/locale/af/LC_MESSAGES/wxstd.mo +0 -0
  331. wx/locale/an/LC_MESSAGES/wxstd.mo +0 -0
  332. wx/locale/ar/LC_MESSAGES/wxstd.mo +0 -0
  333. wx/locale/ca/LC_MESSAGES/wxstd.mo +0 -0
  334. wx/locale/ca@valencia/LC_MESSAGES/wxstd.mo +0 -0
  335. wx/locale/co/LC_MESSAGES/wxstd.mo +0 -0
  336. wx/locale/cs/LC_MESSAGES/wxstd.mo +0 -0
  337. wx/locale/da/LC_MESSAGES/wxstd.mo +0 -0
  338. wx/locale/de/LC_MESSAGES/wxstd.mo +0 -0
  339. wx/locale/el/LC_MESSAGES/wxstd.mo +0 -0
  340. wx/locale/es/LC_MESSAGES/wxstd.mo +0 -0
  341. wx/locale/eu/LC_MESSAGES/wxstd.mo +0 -0
  342. wx/locale/fa_IR/LC_MESSAGES/wxstd.mo +0 -0
  343. wx/locale/fi/LC_MESSAGES/wxstd.mo +0 -0
  344. wx/locale/fr/LC_MESSAGES/wxstd.mo +0 -0
  345. wx/locale/gl_ES/LC_MESSAGES/wxstd.mo +0 -0
  346. wx/locale/hi/LC_MESSAGES/wxstd.mo +0 -0
  347. wx/locale/hr/LC_MESSAGES/wxstd.mo +0 -0
  348. wx/locale/hu/LC_MESSAGES/wxstd.mo +0 -0
  349. wx/locale/id/LC_MESSAGES/wxstd.mo +0 -0
  350. wx/locale/it/LC_MESSAGES/wxstd.mo +0 -0
  351. wx/locale/ja/LC_MESSAGES/wxstd.mo +0 -0
  352. wx/locale/ka/LC_MESSAGES/wxstd.mo +0 -0
  353. wx/locale/ko_KR/LC_MESSAGES/wxstd.mo +0 -0
  354. wx/locale/lt/LC_MESSAGES/wxstd.mo +0 -0
  355. wx/locale/lv/LC_MESSAGES/wxstd.mo +0 -0
  356. wx/locale/ms/LC_MESSAGES/wxstd.mo +0 -0
  357. wx/locale/nb/LC_MESSAGES/wxstd.mo +0 -0
  358. wx/locale/ne/LC_MESSAGES/wxstd.mo +0 -0
  359. wx/locale/nl/LC_MESSAGES/wxstd.mo +0 -0
  360. wx/locale/pl/LC_MESSAGES/wxstd.mo +0 -0
  361. wx/locale/pt/LC_MESSAGES/wxstd.mo +0 -0
  362. wx/locale/pt_BR/LC_MESSAGES/wxstd.mo +0 -0
  363. wx/locale/ro/LC_MESSAGES/wxstd.mo +0 -0
  364. wx/locale/ru/LC_MESSAGES/wxstd.mo +0 -0
  365. wx/locale/sk/LC_MESSAGES/wxstd.mo +0 -0
  366. wx/locale/sl/LC_MESSAGES/wxstd.mo +0 -0
  367. wx/locale/sq/LC_MESSAGES/wxstd.mo +0 -0
  368. wx/locale/sr/LC_MESSAGES/wxstd.mo +0 -0
  369. wx/locale/sv/LC_MESSAGES/wxstd.mo +0 -0
  370. wx/locale/ta/LC_MESSAGES/wxstd.mo +0 -0
  371. wx/locale/tr/LC_MESSAGES/wxstd.mo +0 -0
  372. wx/locale/uk/LC_MESSAGES/wxstd.mo +0 -0
  373. wx/locale/vi/LC_MESSAGES/wxstd.mo +0 -0
  374. wx/locale/zh_CN/LC_MESSAGES/wxstd.mo +0 -0
  375. wx/locale/zh_TW/LC_MESSAGES/wxstd.mo +0 -0
  376. wx/media.py +30 -0
  377. wx/media.pyi +272 -0
  378. wx/msw.py +16 -0
  379. wx/msw.pyi +91 -0
  380. wx/propgrid.py +498 -0
  381. wx/propgrid.pyi +7427 -0
  382. wx/py/CHANGES.txt +796 -0
  383. wx/py/Py.ico +0 -0
  384. wx/py/PyAlaCarte.py +34 -0
  385. wx/py/PyAlaMode.py +34 -0
  386. wx/py/PyAlaModeTest.py +33 -0
  387. wx/py/PyCrust.ico +0 -0
  388. wx/py/PyCrust.py +78 -0
  389. wx/py/PyCrust_16.png +0 -0
  390. wx/py/PyCrust_32.png +0 -0
  391. wx/py/PyFilling.py +35 -0
  392. wx/py/PyShell.py +78 -0
  393. wx/py/PySlices.ico +0 -0
  394. wx/py/PySlices.py +98 -0
  395. wx/py/PySlicesShell.py +94 -0
  396. wx/py/PySlices_16.png +0 -0
  397. wx/py/PySlices_32.png +0 -0
  398. wx/py/PyWrap.py +52 -0
  399. wx/py/README.txt +77 -0
  400. wx/py/__init__.py +20 -0
  401. wx/py/buffer.py +136 -0
  402. wx/py/crust.py +403 -0
  403. wx/py/crustslices.py +403 -0
  404. wx/py/dispatcher.py +259 -0
  405. wx/py/document.py +37 -0
  406. wx/py/editor.py +844 -0
  407. wx/py/editwindow.py +316 -0
  408. wx/py/filling.py +358 -0
  409. wx/py/frame.py +976 -0
  410. wx/py/images.py +212 -0
  411. wx/py/interpreter.py +161 -0
  412. wx/py/introspect.py +402 -0
  413. wx/py/magic.py +98 -0
  414. wx/py/parse.py +134 -0
  415. wx/py/path.py +36 -0
  416. wx/py/pseudo.py +99 -0
  417. wx/py/shell.py +1579 -0
  418. wx/py/sliceshell.py +3805 -0
  419. wx/py/tests/test_interpreter.py +71 -0
  420. wx/py/tests/test_introspect.py +810 -0
  421. wx/py/tests/test_pseudo.py +70 -0
  422. wx/py/tests/test_version.py +36 -0
  423. wx/py/tests/testall.py +22 -0
  424. wx/py/version.py +7 -0
  425. wx/py.typed +0 -0
  426. wx/ribbon.py +48 -0
  427. wx/ribbon.pyi +3099 -0
  428. wx/richtext.py +141 -0
  429. wx/richtext.pyi +13581 -0
  430. wx/siplib.cp315-win_amd64.pyd +0 -0
  431. wx/siplib.pyi +19 -0
  432. wx/stc.py +59 -0
  433. wx/stc.pyi +9918 -0
  434. wx/svg/__init__.py +363 -0
  435. wx/svg/_nanosvg.cp315-win_amd64.pyd +0 -0
  436. wx/tools/__init__.py +18 -0
  437. wx/tools/dbg.py +268 -0
  438. wx/tools/genaxmodule.py +50 -0
  439. wx/tools/helpviewer.py +92 -0
  440. wx/tools/img2img.py +85 -0
  441. wx/tools/img2png.py +54 -0
  442. wx/tools/img2py.py +306 -0
  443. wx/tools/img2xpm.py +54 -0
  444. wx/tools/pywxrc.py +951 -0
  445. wx/tools/wxget.py +254 -0
  446. wx/tools/wxget_docs_demo.py +183 -0
  447. wx/wxbase334u_net_vc140_x64.dll +0 -0
  448. wx/wxbase334u_vc140_x64.dll +0 -0
  449. wx/wxbase334u_xml_vc140_x64.dll +0 -0
  450. wx/wxmsw334u_adv_vc140_x64.dll +0 -0
  451. wx/wxmsw334u_aui_vc140_x64.dll +0 -0
  452. wx/wxmsw334u_core_vc140_x64.dll +0 -0
  453. wx/wxmsw334u_gl_vc140_x64.dll +0 -0
  454. wx/wxmsw334u_html_vc140_x64.dll +0 -0
  455. wx/wxmsw334u_media_vc140_x64.dll +0 -0
  456. wx/wxmsw334u_propgrid_vc140_x64.dll +0 -0
  457. wx/wxmsw334u_qa_vc140_x64.dll +0 -0
  458. wx/wxmsw334u_ribbon_vc140_x64.dll +0 -0
  459. wx/wxmsw334u_richtext_vc140_x64.dll +0 -0
  460. wx/wxmsw334u_stc_vc140_x64.dll +0 -0
  461. wx/wxmsw334u_webview_vc140_x64.dll +0 -0
  462. wx/wxmsw334u_xrc_vc140_x64.dll +0 -0
  463. wx/xml.py +18 -0
  464. wx/xml.pyi +728 -0
  465. wx/xrc.py +68 -0
  466. wx/xrc.pyi +896 -0
  467. wxpython-4.3.2.dist-info/METADATA +71 -0
  468. wxpython-4.3.2.dist-info/RECORD +472 -0
  469. wxpython-4.3.2.dist-info/WHEEL +5 -0
  470. wxpython-4.3.2.dist-info/entry_points.txt +13 -0
  471. wxpython-4.3.2.dist-info/licenses/LICENSE.txt +610 -0
  472. wxpython-4.3.2.dist-info/top_level.txt +1 -0
wx/py/sliceshell.py ADDED
@@ -0,0 +1,3805 @@
1
+ #----------------------------------------------------------------------
2
+ # Name: sliceshell.py
3
+ # Author: David N. Mashburn, Patrick K. O'Brien
4
+ # Tags: phoenix-port
5
+ #----------------------------------------------------------------------
6
+ """Slices is an interactive text control in which a user types in
7
+ commands to be sent to the interpreter. This particular shell is
8
+ based on wxPython's wxStyledTextCtrl.
9
+
10
+ Sponsored by Orbtech - Your source for Python programming expertise.
11
+ Slices is a version of shell modified by David Mashburn."""
12
+
13
+ __author__ = "David N. Mashburn <david.n.mashburn@gmail.com> / "
14
+ __author__ += "Patrick K. O'Brien <pobrien@orbtech.com>"
15
+
16
+ import wx
17
+ from wx import stc
18
+
19
+ import keyword
20
+ import os
21
+ import sys
22
+ import time
23
+ from functools import cmp_to_key
24
+
25
+ from .buffer import Buffer
26
+ from . import dispatcher
27
+ from . import editor
28
+ from . import editwindow
29
+ from . import document
30
+ from . import frame
31
+ from .pseudo import PseudoFileIn
32
+ from .pseudo import PseudoFileOut
33
+ from .pseudo import PseudoFileErr
34
+ from .version import VERSION
35
+ from .magic import magic
36
+ from .parse import testForContinuations
37
+ from .path import ls,cd,pwd,sx
38
+
39
+
40
+ sys.ps3 = '<-- ' # Input prompt.
41
+ USE_MAGIC=True
42
+ # Force updates from long-running commands after this many seconds
43
+ PRINT_UPDATE_MAX_TIME=2
44
+
45
+ NAVKEYS = (wx.WXK_HOME, wx.WXK_END, wx.WXK_LEFT, wx.WXK_RIGHT,
46
+ wx.WXK_UP, wx.WXK_DOWN, wx.WXK_PAGEUP, wx.WXK_PAGEDOWN)
47
+
48
+ GROUPING_SELECTING=0
49
+ IO_SELECTING = 1
50
+
51
+ GROUPING_START = 2
52
+ GROUPING_START_FOLDED = 3
53
+ GROUPING_MIDDLE = 4
54
+ GROUPING_END = 5
55
+ INPUT_START = 6
56
+ INPUT_START_FOLDED = 7
57
+ INPUT_MIDDLE = 8
58
+ INPUT_END = 9
59
+ OUTPUT_START = 10
60
+ OUTPUT_START_FOLDED = 11
61
+ OUTPUT_MIDDLE = 12
62
+ OUTPUT_END = 13
63
+
64
+ OUTPUT_BG = 14
65
+ READLINE_BG = 15
66
+ INPUT_READLINE = 16
67
+
68
+ # Could add C integration right into the markers...
69
+ # Non-editable file marker for auto-loaded files...
70
+ # Weave VariableInput = 15
71
+ # Weave C code = 16
72
+ # C code = 17 (only for use with Pyrex)
73
+ # Pyrex / Cython code = 18
74
+
75
+ GROUPING_MASK = ( 1<<GROUPING_START | 1<<GROUPING_START_FOLDED |
76
+ 1<<GROUPING_MIDDLE | 1<<GROUPING_END )
77
+
78
+ INPUT_MASK = ( 1<<INPUT_START | 1<<INPUT_START_FOLDED |
79
+ 1<<INPUT_MIDDLE | 1<<INPUT_END )
80
+ OUTPUT_MASK = ( 1<<OUTPUT_START | 1<<OUTPUT_START_FOLDED |
81
+ 1<<OUTPUT_MIDDLE | 1<<OUTPUT_END )
82
+ IO_MASK = ( INPUT_MASK | OUTPUT_MASK )
83
+
84
+ IO_START_MASK = ( 1<<INPUT_START | 1<<OUTPUT_START )
85
+ IO_START_FOLDED_MASK = ( 1<<INPUT_START_FOLDED | 1<<OUTPUT_START_FOLDED )
86
+ IO_ANY_START_MASK = ( 1<<INPUT_START | 1<<OUTPUT_START |
87
+ 1<<INPUT_START_FOLDED | 1<<OUTPUT_START_FOLDED )
88
+ IO_MIDDLE_MASK = ( 1<<INPUT_MIDDLE | 1<<OUTPUT_MIDDLE )
89
+ IO_END_MASK = ( 1<<INPUT_END | 1<<OUTPUT_END )
90
+
91
+ usrBinEnvPythonText = '#!/usr/bin/env python\n'
92
+ pyslicesFormatHeaderText = ['#PySlices Save Format Version 1.1 (PySlices v0.9.7.8 and later)\n',
93
+ '#PySlices Save Format Version 1.2 (PySlices v0.9.8 and later)\n']
94
+ groupingStartText = '#PySlices Marker Information -- Begin Grouping Slice\n'
95
+ inputStartText = '#PySlices Marker Information -- Begin Input Slice\n'
96
+ outputStartText = '#PySlices Marker Information -- Begin Output Slice\n'
97
+
98
+ tutorialText = """
99
+
100
+ Tutorial!!!
101
+ ------------------------------------------------------------------------
102
+ PySlices is the newest member of the Py suite!
103
+ It is a modified version of PyCrust that supports multi-line commands.
104
+
105
+ Input and output are contained in "Slices" shown as markers in the left margin.
106
+ Input Slices have RED margins (active, editable).
107
+ Output Slices have BLUE margins (frozen, not editable).
108
+
109
+ Commands in slices can be on more than one line, as with Sage or Mathematica.
110
+ For example, the command:
111
+ a=1
112
+ b=2
113
+ print(a+b)
114
+ will all run in sequence, much like a script.
115
+ Try running the above Input Slice by clicking somewhere in its text and
116
+ using Ctrl-Return, Shift-Return, or Numpad Enter to execute.
117
+ Previous commands (Old Slices) can be re-edited and run again in place.
118
+
119
+ Slices can also be:
120
+ * selceted (click on the margin, Shift-click for multiple selection)
121
+ * folded (click the margin twice)
122
+ * selected and deleted (hit delete while selected)
123
+ * divided (Ctrl-D)
124
+ * merged (Ctrl-M while selecting adjacent, like-colored slices)
125
+
126
+ Try deleting the slice above this one by clicking on the red margin.
127
+
128
+ If you want a more traditional shell feel, try enabling "Shell Mode" in
129
+ "Options->Settings->Shell Mode" (or try PyCrust).
130
+ In Shell Mode, two returns in a row executes the command, and
131
+ Ctrl-Return and Shift-Return always print newlines.
132
+
133
+ Saving and opening "sessions" is now supported! This is a little
134
+ different to other shells where the history is saved. With PySlices,
135
+ the whole document is saved in a simple text format!
136
+
137
+ To disable this Tutorial on startup, uncheck it in the menu at:
138
+ "Options->Startup->Show PySlices tutorial"
139
+
140
+ PySlices may not be the best thing since sliced bread, but
141
+ I hope it makes using Python a little bit sweeter!
142
+ """
143
+
144
+ class SlicesShellFrame(frame.Frame, frame.ShellFrameMixin):
145
+ """Frame containing the sliceshell component."""
146
+
147
+ name = 'SlicesShell Frame'
148
+
149
+ def __init__(self, parent=None, id=-1, title='PySlicesShell',
150
+ pos=wx.DefaultPosition, size=wx.DefaultSize,
151
+ style=wx.DEFAULT_FRAME_STYLE, locals=None,
152
+ InterpClass=None,
153
+ config=None, dataDir=None, filename=None,
154
+ *args, **kwds):
155
+ """Create SlicesShellFrame instance."""
156
+ frame.Frame.__init__(self, parent, id, title, pos, size, style,shellName='PySlices')
157
+ frame.ShellFrameMixin.__init__(self, config, dataDir)
158
+
159
+ if size == wx.DefaultSize:
160
+ self.SetSize((750, 525))
161
+
162
+ intro = 'PySlices %s - The Flakiest Python Shell... Cut Up!' % VERSION
163
+ self.SetStatusText(intro.replace('\n', ', '))
164
+ self.sliceshell = SlicesShell(parent=self, id=-1, introText=intro,
165
+ locals=locals, InterpClass=InterpClass,
166
+ startupScript=self.startupScript,
167
+ execStartupScript=self.execStartupScript,
168
+ showPySlicesTutorial=self.showPySlicesTutorial,
169
+ enableShellMode=self.enableShellMode,
170
+ hideFoldingMargin=self.hideFoldingMargin,
171
+ *args, **kwds)
172
+ self.shell = self.sliceshell
173
+ self.buffer = self.sliceshell.buffer
174
+
175
+ # Override the shell so that status messages go to the status bar.
176
+ self.sliceshell.setStatusText = self.SetStatusText
177
+
178
+ self.sliceshell.SetFocus()
179
+ self.LoadSettings()
180
+
181
+ self.currentDirectory = os.path.expanduser('~')
182
+
183
+ if filename!=None:
184
+ self.bufferOpen(filename)
185
+
186
+ self.Bind(wx.EVT_IDLE, self.OnIdle)
187
+
188
+
189
+ def OnClose(self, event):
190
+ """Event handler for closing."""
191
+ self.bufferClose()
192
+ # This isn't working the way I want, but I'll leave it for now.
193
+ #if self.sliceshell.waiting:
194
+ # if event.CanVeto():
195
+ # event.Veto(True)
196
+ #else:
197
+ # # TODO: Add check for saving
198
+ # self.SaveSettings()
199
+ # self.sliceshell.destroy()
200
+ # self.Destroy()
201
+
202
+ def OnAbout(self, event):
203
+ """Display an About window."""
204
+ title = 'About PySliceShell'
205
+ text = 'PySliceShell %s\n\n' % VERSION + \
206
+ 'Yet another Python shell, only flakier.\n\n' + \
207
+ 'Half-baked by Patrick K. O\'Brien,\n' + \
208
+ 'the other half is still in the oven.\n\n' + \
209
+ 'Platform: %s\n' % sys.platform + \
210
+ 'Python Version: %s\n' % sys.version.split()[0] + \
211
+ 'wxPython Version: %s\n' % wx.VERSION_STRING + \
212
+ ('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:]))
213
+ dialog = wx.MessageDialog(self, text, title,
214
+ wx.OK | wx.ICON_INFORMATION)
215
+ dialog.ShowModal()
216
+ dialog.Destroy()
217
+
218
+
219
+ def OnHelp(self, event):
220
+ """Show a help dialog."""
221
+ frame.ShellFrameMixin.OnHelp(self, event)
222
+
223
+
224
+ def LoadSettings(self):
225
+ if self.config is not None:
226
+ frame.ShellFrameMixin.LoadSettings(self)
227
+ frame.Frame.LoadSettings(self, self.config)
228
+ self.sliceshell.LoadSettings(self.config)
229
+
230
+ def SaveSettings(self, force=False):
231
+ if self.config is not None:
232
+ frame.ShellFrameMixin.SaveSettings(self,force)
233
+ if self.autoSaveSettings or force:
234
+ frame.Frame.SaveSettings(self, self.config)
235
+ self.sliceshell.SaveSettings(self.config)
236
+
237
+ def DoSaveSettings(self):
238
+ if self.config is not None:
239
+ self.SaveSettings(force=True)
240
+ self.config.Flush()
241
+
242
+ def OnEnableShellMode(self,event):
243
+ """Change between Slices Mode and Shell Mode"""
244
+ frame.Frame.OnEnableShellMode(self,event)
245
+ self.sliceshell.ToggleShellMode(self.enableShellMode)
246
+
247
+ def OnHideFoldingMargin(self,event):
248
+ """Change between Slices Mode and Shell Mode"""
249
+ frame.Frame.OnHideFoldingMargin(self,event)
250
+ self.sliceshell.ToggleFoldingMargin(self.hideFoldingMargin)
251
+ # Copied Straight from crustslices.py (update both with any changes...)
252
+ # Stolen Straight from editor.EditorFrame
253
+ # Modified a little... :)
254
+ # ||
255
+ # \/
256
+ def OnIdle(self, event):
257
+ """Event handler for idle time."""
258
+ self._updateTitle()
259
+ event.Skip()
260
+
261
+ def _updateTitle(self):
262
+ """Show current title information."""
263
+ title = self.GetTitle()
264
+ if self.bufferHasChanged():
265
+ if title.startswith('* '):
266
+ pass
267
+ else:
268
+ self.SetTitle('* ' + title)
269
+ else:
270
+ if title.startswith('* '):
271
+ self.SetTitle(title[2:])
272
+
273
+ def hasBuffer(self):
274
+ """Return True if there is a current buffer."""
275
+ if self.buffer:
276
+ return True
277
+ else:
278
+ return False
279
+
280
+ def bufferClose(self):
281
+ """Close buffer."""
282
+ if self.buffer.hasChanged():
283
+ cancel = self.bufferSuggestSave()
284
+ if cancel:
285
+ #event.Veto()
286
+ return cancel
287
+ self.SaveSettings()
288
+ self.sliceshell.destroy()
289
+ self.bufferDestroy()
290
+ self.Destroy()
291
+
292
+ return False
293
+
294
+ def bufferCreate(self, filename=None):
295
+ """Create new buffer."""
296
+ self.bufferDestroy()
297
+ buffer = Buffer()
298
+ self.panel = panel = wx.Panel(parent=self, id=-1)
299
+ panel.Bind (wx.EVT_ERASE_BACKGROUND, lambda x: x)
300
+ editor = Editor(parent=panel)
301
+ panel.editor = editor
302
+ sizer = wx.BoxSizer(wx.VERTICAL)
303
+ sizer.Add(editor.window, 1, wx.EXPAND)
304
+ panel.SetSizer(sizer)
305
+ panel.SetAutoLayout(True)
306
+ sizer.Layout()
307
+ buffer.addEditor(editor)
308
+ buffer.open(filename)
309
+ self.setEditor(editor)
310
+ self.editor.setFocus()
311
+ self.SendSizeEvent()
312
+
313
+
314
+ def bufferDestroy(self):
315
+ """Destroy the current buffer."""
316
+ if self.buffer:
317
+ self.editor = None
318
+ self.buffer = None
319
+
320
+
321
+ def bufferHasChanged(self):
322
+ """Return True if buffer has changed since last save."""
323
+ if self.buffer:
324
+ return self.buffer.hasChanged()
325
+ else:
326
+ return False
327
+
328
+ def bufferNew(self):
329
+ """Create new buffer."""
330
+ cancel = self.bufferSuggestSave()
331
+ if cancel:
332
+ return cancel
333
+ #self.bufferCreate()
334
+ self.clear()
335
+ self.SetTitle( 'PySlices')
336
+ self.sliceshell.NeedsCheckForSave=False
337
+ self.sliceshell.SetSavePoint()
338
+ self.buffer.doc = document.Document()
339
+ self.buffer.name = 'This shell'
340
+ self.buffer.modulename = self.buffer.doc.filebase
341
+ cancel = False
342
+ return cancel
343
+
344
+ def bufferOpen(self,file=None):
345
+ """Open file in buffer."""
346
+ if self.bufferHasChanged():
347
+ cancel = self.bufferSuggestSave()
348
+ if cancel:
349
+ return cancel
350
+
351
+ if file==None:
352
+ file=wx.FileSelector('Open a PySlices File',
353
+ wildcard='*.pyslices',
354
+ default_path=self.currentDirectory)
355
+ if file!=None and file!=u'':
356
+ with open(file,'r') as fid:
357
+ self.sliceshell.LoadPySlicesFile(fid)
358
+
359
+ self.currentDirectory = os.path.split(file)[0]
360
+ self.SetTitle( os.path.split(file)[1] + ' - PySlices')
361
+ self.sliceshell.NeedsCheckForSave=False
362
+ self.sliceshell.SetSavePoint()
363
+ self.buffer.doc = document.Document(file)
364
+ self.buffer.name = self.buffer.doc.filename
365
+ self.buffer.modulename = self.buffer.doc.filebase
366
+ self.sliceshell.ScrollToLine(0)
367
+ return
368
+
369
+ ## def bufferPrint(self):
370
+ ## """Print buffer."""
371
+ ## pass
372
+
373
+ ## def bufferRevert(self):
374
+ ## """Revert buffer to version of file on disk."""
375
+ ## pass
376
+
377
+ # was self.buffer.save(self): # """Save buffer."""
378
+ def simpleSave(self,confirmed=False):
379
+ filepath = self.buffer.doc.filepath
380
+ self.buffer.confirmed = confirmed
381
+ if not filepath:
382
+ return # XXX Get filename
383
+ if not os.path.exists(filepath):
384
+ self.buffer.confirmed = True
385
+ if not self.buffer.confirmed:
386
+ self.buffer.confirmed = self.buffer.overwriteConfirm(filepath)
387
+ if self.buffer.confirmed:
388
+ with open(filepath, 'wb') as fid:
389
+ self.sliceshell.SavePySlicesFile(fid)
390
+
391
+ self.sliceshell.SetSavePoint()
392
+ self.SetTitle( os.path.split(filepath)[1] + ' - PySlices')
393
+ self.sliceshell.NeedsCheckForSave=False
394
+
395
+ def bufferSave(self):
396
+ """Save buffer to its file."""
397
+ if self.buffer.doc.filepath:
398
+ # self.buffer.save()
399
+ self.simpleSave(confirmed=True)
400
+ cancel = False
401
+ else:
402
+ cancel = self.bufferSaveAs()
403
+ return cancel
404
+
405
+ def bufferSaveAs(self):
406
+ """Save buffer to a new filename."""
407
+ if self.bufferHasChanged() and self.buffer.doc.filepath:
408
+ cancel = self.bufferSuggestSave()
409
+ if cancel:
410
+ return cancel
411
+ filedir = ''
412
+ if self.buffer and self.buffer.doc.filedir:
413
+ filedir = self.buffer.doc.filedir
414
+ result = editor.saveSingle(title='Save PySlices File',directory=filedir,
415
+ wildcard='PySlices Files (*.pyslices)|*.pyslices')
416
+ if result.path not in ['',None]:
417
+ if result.path[-9:]!=".pyslices":
418
+ result.path+=".pyslices"
419
+
420
+ self.buffer.doc = document.Document(result.path)
421
+ self.buffer.name = self.buffer.doc.filename
422
+ self.buffer.modulename = self.buffer.doc.filebase
423
+ self.simpleSave(confirmed=True) # allow overwrite
424
+ cancel = False
425
+ else:
426
+ cancel = True
427
+ return cancel
428
+
429
+ def bufferSaveACopy(self):
430
+ """Save buffer to a new filename."""
431
+ filedir = ''
432
+ if self.buffer and self.buffer.doc.filedir:
433
+ filedir = self.buffer.doc.filedir
434
+ result = editor.saveSingle(title='Save a Copy of PySlices File',directory=filedir,
435
+ wildcard='PySlices Files (*.pyslices)|*.pyslices')
436
+
437
+ if result.path not in ['',None]:
438
+ if result.path[-9:]!=".pyslices":
439
+ result.path+=".pyslices"
440
+
441
+ # if not os.path.exists(result.path):
442
+ # Allow overwrite...
443
+ with open(result.path, 'wb') as fid:
444
+ self.sliceshell.SavePySlicesFile(fid)
445
+
446
+ cancel = False
447
+ else:
448
+ cancel = True
449
+ return cancel
450
+
451
+ def bufferSuggestSave(self):
452
+ """Suggest saving changes. Return True if user selected Cancel."""
453
+ result = editor.messageDialog(parent=None,
454
+ message='%s has changed.\n'
455
+ 'Would you like to save it first'
456
+ '?' % self.buffer.name,
457
+ title='Save current file?',
458
+ style=wx.YES_NO | wx.CANCEL | wx.NO_DEFAULT |
459
+ wx.CENTRE | wx.ICON_QUESTION )
460
+ if result.positive:
461
+ cancel = self.bufferSave()
462
+ else:
463
+ cancel = result.text == 'Cancel'
464
+ return cancel
465
+
466
+ def updateNamespace(self):
467
+ """Update the buffer namespace for autocompletion and calltips."""
468
+ if self.buffer.updateNamespace():
469
+ self.SetStatusText('Namespace updated')
470
+ else:
471
+ self.SetStatusText('Error executing, unable to update namespace')
472
+
473
+
474
+
475
+ # TODO : Update the help text
476
+ HELP_TEXT = """\
477
+ * Key bindings:
478
+ Home Go to the beginning of the line.
479
+ End Go to the end of the line.
480
+ Shift+Home Select to the beginning of the line.
481
+ Shift+End Select to the end of the line.
482
+ Ctrl-Home Jump to the beginning of the slice;
483
+ If already there, jump to beginning of previous slice
484
+ Ctrl-End Jump to the end of the slice;
485
+ If already there, jump to end of next slice
486
+ Ctrl-PageUp Jump to the beginning of the shell
487
+ Ctrl-PageDown Jump to the end of the shell
488
+ Ctrl+C Copy selected text, removing prompts.
489
+ Ctrl+Shift+C Copy selected text, retaining prompts.
490
+ Alt+C Copy to the clipboard, including prefixed prompts.
491
+ Ctrl+X Cut selected text.
492
+ Ctrl+V Paste from clipboard.
493
+ Ctrl+Shift+V Paste and run multiple commands from clipboard.
494
+ Ctrl+Up Arrow Retrieve Previous History item.
495
+ Alt+P Retrieve Previous History item.
496
+ Ctrl+Down Arrow Retrieve Next History item.
497
+ Alt+N Retrieve Next History item.
498
+ Shift+Up Arrow Insert Previous History item.
499
+ Shift+Down Arrow Insert Next History item.
500
+ F8 Command-completion of History item.
501
+ (Type a few characters of a previous command and press F8.)
502
+ Ctrl+] Increase font size.
503
+ Ctrl+[ Decrease font size.
504
+ Ctrl+= Default font size.
505
+
506
+ Ctrl-Space Show Auto Completion.
507
+ Ctrl-Shift-Space Show Call Tip.
508
+ Ctrl-Shift-H Complete Text from History.
509
+
510
+ Ctrl+F Search
511
+ Ctrl+G Search next
512
+ F12 on/off "free-edit" mode
513
+ For testing only -- This does not preserve markers!
514
+
515
+ In "Slices Mode":
516
+ Return Insert new line
517
+ Enter (Numpad) Run command in slice
518
+ Ctrl+Return ""
519
+ Shift+Return ""
520
+
521
+ In "Shell Mode":
522
+ Return or Enter Insert a new line
523
+ Ctrl+Return ""
524
+ Shift+Return ""
525
+ 2 Returns in a row Run command in slice
526
+ """
527
+
528
+ class SlicesShellFacade:
529
+ """Simplified interface to all shell-related functionality.
530
+
531
+ This is a semi-transparent facade, in that all attributes of other
532
+ are accessible, even though only some are visible to the user."""
533
+
534
+ name = 'SlicesShell Interface'
535
+
536
+ def __init__(self, other):
537
+ """Create a SlicesShellFacade instance."""
538
+ d = self.__dict__
539
+ d['other'] = other
540
+ d['helpText'] = HELP_TEXT
541
+
542
+ def help(self):
543
+ """Display some useful information about how to use the slices shell."""
544
+ self.write(self.helpText,type='Output')
545
+
546
+ def __getattr__(self, name):
547
+ if hasattr(self.other, name):
548
+ return getattr(self.other, name)
549
+ else:
550
+ raise AttributeError(name)
551
+
552
+ def __setattr__(self, name, value):
553
+ if name in self.__dict__:
554
+ self.__dict__[name] = value
555
+ elif hasattr(self.other, name):
556
+ setattr(self.other, name, value)
557
+ else:
558
+ raise AttributeError(name)
559
+
560
+ def _getAttributeNames(self):
561
+ """Return list of magic attributes to extend introspection."""
562
+ list = [
563
+ 'about',
564
+ 'ask',
565
+ 'autoCallTip',
566
+ 'autoComplete',
567
+ 'autoCompleteAutoHide',
568
+ 'autoCompleteCaseInsensitive',
569
+ 'autoCompleteIncludeDouble',
570
+ 'autoCompleteIncludeMagic',
571
+ 'autoCompleteIncludeSingle',
572
+ 'callTipInsert',
573
+ 'clear',
574
+ 'pause',
575
+ 'prompt',
576
+ 'quit',
577
+ 'redirectStderr',
578
+ 'redirectStdin',
579
+ 'redirectStdout',
580
+ 'run',
581
+ 'runfile',
582
+ 'wrap',
583
+ 'zoom',
584
+ ]
585
+ list.sort()
586
+ return list
587
+
588
+ DISPLAY_TEXT="""
589
+ Author: %r
590
+ Py Version: %s
591
+ Python Version: %s
592
+ wxPython Version: %s
593
+ wxPython PlatformInfo: %s
594
+ Platform: %s"""
595
+
596
+ class SlicesShell(editwindow.EditWindow):
597
+ """Notebook Shell based on StyledTextCtrl."""
598
+
599
+ name = 'SlicesShell'
600
+
601
+ def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
602
+ size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
603
+ introText='', locals=None, InterpClass=None,
604
+ startupScript=None, execStartupScript=True,
605
+ showPySlicesTutorial=True,enableShellMode=False,
606
+ useStockId=True,
607
+ hideFoldingMargin=False, *args, **kwds):
608
+ """Create Shell instance."""
609
+ editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
610
+ self.wrap()
611
+ if locals is None:
612
+ import __main__
613
+ locals = __main__.__dict__
614
+
615
+ # Grab these so they can be restored by self.redirect* methods.
616
+ self.stdin = sys.stdin
617
+ self.stdout = sys.stdout
618
+ self.stderr = sys.stderr
619
+
620
+ # Import a default interpreter class if one isn't provided.
621
+ if InterpClass is None:
622
+ from .interpreter import Interpreter
623
+ else:
624
+ Interpreter = InterpClass
625
+
626
+ # Create a replacement for stdin.
627
+ self.reader = PseudoFileIn(self.readline, self.readlines)
628
+ self.reader.input = ''
629
+ self.reader.isreading = False
630
+
631
+ # Set up the interpreter.
632
+ self.interp = Interpreter(locals=locals,
633
+ rawin=self.raw_input,
634
+ stdin=self.reader,
635
+ stdout=PseudoFileOut(self.writeOut),
636
+ stderr=PseudoFileErr(self.writeErr),
637
+ *args, **kwds)
638
+
639
+ # Set up the buffer.
640
+ self.buffer = Buffer()
641
+ self.id = self.GetId()
642
+ self.buffer.addEditor(self)
643
+ self.buffer.name='This shell'
644
+ self.NeedsCheckForSave=False
645
+
646
+ # Find out for which keycodes the interpreter will autocomplete.
647
+ self.autoCompleteKeys = self.interp.getAutoCompleteKeys()
648
+
649
+ # Keep track of the last non-continuation prompt positions.
650
+ # Removed all references to these... solved a lot of odd bugs...
651
+ # self.promptPosStart = 0
652
+ # self.promptPosEnd = 0
653
+
654
+ # Keep track of multi-line commands.
655
+ self.more = False
656
+
657
+ # Use Margins to track input / output / slice number
658
+ self.margins = True
659
+
660
+ # For use with forced updates during long-running scripts
661
+ self.lastUpdate=None
662
+
663
+ if self.margins:
664
+ # margin 1 is already defined for the line numbers
665
+ # may eventually change it back to 0 like it ought to be...
666
+ self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
667
+ self.SetMarginType(3, stc.STC_MARGIN_SYMBOL)
668
+ self.SetMarginType(4, stc.STC_MARGIN_SYMBOL)
669
+ self.SetMarginWidth(2, 22)
670
+ self.SetMarginWidth(3, 22)
671
+ self.SetMarginWidth(4, 12)
672
+ self.SetMarginSensitive(2,True)
673
+ self.SetMarginSensitive(3,True)
674
+ self.SetMarginSensitive(4,True)
675
+ self.SetProperty("fold", "1")
676
+ # tabs are bad, use spaces
677
+ self.SetProperty("tab.timmy.whinge.level", "4")
678
+ self.SetMargins(0,0)
679
+
680
+
681
+ self.SetMarginMask(2, GROUPING_MASK | 1<<GROUPING_SELECTING )
682
+ # Display Markers -24...
683
+ self.SetMarginMask(3, IO_MASK | 1<<IO_SELECTING | 1<<READLINE_BG | 1<<INPUT_READLINE )
684
+ self.SetMarginMask(4, stc.STC_MASK_FOLDERS)
685
+ # Set the mask for the line markers, too...
686
+ self.SetMarginMask(1, 0)
687
+
688
+ if hideFoldingMargin:
689
+ self.SetMarginWidth(4, 0)
690
+ self.hideFoldingMargin=hideFoldingMargin
691
+
692
+ sel_color="#E0E0E0"
693
+ grouping_color="black"
694
+ input_color="red"
695
+ output_color="blue"
696
+
697
+ self.MarkerDefine(GROUPING_SELECTING, stc.STC_MARK_FULLRECT,
698
+ sel_color, sel_color)
699
+ self.MarkerDefine(IO_SELECTING, stc.STC_MARK_FULLRECT,
700
+ sel_color, sel_color)
701
+
702
+ self.MarkerDefine(GROUPING_START, stc.STC_MARK_BOXMINUS,
703
+ "white", grouping_color)
704
+ self.MarkerDefine(GROUPING_START_FOLDED, stc.STC_MARK_BOXPLUS,
705
+ "white", grouping_color)
706
+ self.MarkerDefine(GROUPING_MIDDLE, stc.STC_MARK_VLINE,
707
+ "white", grouping_color)
708
+ self.MarkerDefine(GROUPING_END, stc.STC_MARK_LCORNER,
709
+ "white", grouping_color)
710
+
711
+ self.MarkerDefine(READLINE_BG, stc.STC_MARK_FULLRECT,
712
+ wx.Colour(191,191,191), wx.Colour(191,191,191))
713
+ self.MarkerDefine(INPUT_READLINE, stc.STC_MARK_CHARACTER+ord('<'),
714
+ input_color, wx.Colour(191,191,191))
715
+
716
+ if enableShellMode:
717
+ self.mode='ShellMode'
718
+ else:
719
+ self.mode='SlicesMode'
720
+
721
+ self.execOnNextReturn=False
722
+ if self.mode=='SlicesMode':
723
+ self.MarkerDefine(INPUT_START, stc.STC_MARK_BOXMINUS,
724
+ "white", input_color)
725
+ self.MarkerDefine(INPUT_START_FOLDED, stc.STC_MARK_BOXPLUS,
726
+ "white", input_color)
727
+ self.MarkerDefine(INPUT_MIDDLE, stc.STC_MARK_VLINE,
728
+ "white", input_color)
729
+ self.MarkerDefine(INPUT_END, stc.STC_MARK_LCORNER,
730
+ "white", input_color)
731
+ elif self.mode=='ShellMode':
732
+ self.MarkerDefine(INPUT_START, stc.STC_MARK_ARROWS,
733
+ input_color, "white")
734
+ self.MarkerDefine(INPUT_START_FOLDED, stc.STC_MARK_BOXPLUS,
735
+ "white", input_color)
736
+ self.MarkerDefine(INPUT_MIDDLE, stc.STC_MARK_DOTDOTDOT,
737
+ input_color, "white")
738
+ self.MarkerDefine(INPUT_END, stc.STC_MARK_DOTDOTDOT,
739
+ input_color, "white")
740
+
741
+ self.MarkerDefine(OUTPUT_START, stc.STC_MARK_BOXMINUS,
742
+ "white", output_color)
743
+ self.MarkerDefine(OUTPUT_START_FOLDED, stc.STC_MARK_BOXPLUS,
744
+ "white", output_color)
745
+ self.MarkerDefine(OUTPUT_MIDDLE, stc.STC_MARK_VLINE,
746
+ "white", output_color)
747
+ self.MarkerDefine(OUTPUT_END, stc.STC_MARK_LCORNER,
748
+ "white", output_color)
749
+
750
+ self.MarkerDefine(OUTPUT_BG, stc.STC_MARK_BACKGROUND,
751
+ "white", wx.Colour(242,242,255))
752
+
753
+ # Markers for folding margin...
754
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS,
755
+ "white", "#808080")
756
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS,
757
+ "white", "#808080")
758
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE,
759
+ "white", "#808080")
760
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER,
761
+ "white", "#808080")
762
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED,
763
+ "white", "#808080")
764
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED,
765
+ "white", "#808080")
766
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER,
767
+ "white", "#808080")
768
+
769
+ # Create the command history. Commands are added into the
770
+ # front of the list (ie. at index 0) as they are entered.
771
+ # self.historyIndex is the current position in the history; it
772
+ # gets incremented as you retrieve the previous command,
773
+ # decremented as you retrieve the next, and reset when you hit
774
+ # Enter. self.historyIndex == -1 means you're on the current
775
+ # command, not in the history.
776
+ self.history = []
777
+ self.historyIndex = -1
778
+
779
+ #DNM -- disable these markers...
780
+ #seb add mode for "free edit"
781
+ self.noteMode = 0
782
+ #self.MarkerDefine(0,stc.STC_MARK_ROUNDRECT) # marker for hidden
783
+ self.searchTxt = ""
784
+
785
+ # Assign handlers for keyboard events.
786
+ self.Bind(wx.EVT_CHAR, self.OnChar)
787
+ self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
788
+
789
+ self.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
790
+ # TODO : Add a general functions to handle mouse clicks in the
791
+ # TODO: STC window whose sole purpose is to make it so
792
+ # TODO: that margin selection becomes unselected...
793
+
794
+ # Assign handler for the context menu
795
+ self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
796
+ self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI)
797
+
798
+ # add the option to not use the stock IDs; otherwise the context menu
799
+ # may not work on Mac without adding the proper IDs to the menu bar
800
+ if useStockId:
801
+ self.ID_CUT = wx.ID_CUT
802
+ self.ID_COPY = wx.ID_COPY
803
+ self.ID_PASTE = wx.ID_PASTE
804
+ self.ID_SELECTALL = wx.ID_SELECTALL
805
+ self.ID_CLEAR = wx.ID_CLEAR
806
+ self.ID_UNDO = wx.ID_UNDO
807
+ self.ID_REDO = wx.ID_REDO
808
+ else:
809
+ self.ID_CUT = wx.NewIdRef()
810
+ self.ID_COPY = wx.NewIdRef()
811
+ self.ID_PASTE = wx.NewIdRef()
812
+ self.ID_SELECTALL = wx.NewIdRef()
813
+ self.ID_CLEAR = wx.NewIdRef()
814
+ self.ID_UNDO = wx.NewIdRef()
815
+ self.ID_REDO = wx.NewIdRef()
816
+
817
+ # Assign handlers for edit events
818
+ self.Bind(wx.EVT_MENU, lambda evt: self.Cut(), id=self.ID_CUT)
819
+ self.Bind(wx.EVT_MENU, lambda evt: self.Copy(), id=self.ID_COPY)
820
+ self.Bind(wx.EVT_MENU, lambda evt: self.CopyWithPrompts(), id=frame.ID_COPY_PLUS)
821
+ self.Bind(wx.EVT_MENU, lambda evt: self.Paste(), id=self.ID_PASTE)
822
+ self.Bind(wx.EVT_MENU, lambda evt: self.PasteAndRun(), id=frame.ID_PASTE_PLUS)
823
+ self.Bind(wx.EVT_MENU, lambda evt: self.SelectAll(), id=self.ID_SELECTALL)
824
+ self.Bind(wx.EVT_MENU, lambda evt: self.Clear(), id=self.ID_CLEAR)
825
+ self.Bind(wx.EVT_MENU, lambda evt: self.Undo(), id=self.ID_UNDO)
826
+ self.Bind(wx.EVT_MENU, lambda evt: self.Redo(), id=self.ID_REDO)
827
+
828
+ # Assign handler for idle time.
829
+ self.waiting = False
830
+ self.Bind(wx.EVT_IDLE, self.OnIdle)
831
+
832
+ # Display the introductory banner information.
833
+ self.showIntro(introText)
834
+
835
+ outStart,outEnd,inStart,inMiddle,inEnd = [[],[],[],[],[]]
836
+
837
+ # Make "executed startup script move to the top..."
838
+ if showPySlicesTutorial:
839
+ self.write(tutorialText,'Output')
840
+ tutStart=5
841
+ testStart=16
842
+ outStart=[tutStart,testStart+3]
843
+ outEnd=[tutStart-1,testStart-1]
844
+ inStart=[testStart]
845
+ inMiddle=[testStart+1]
846
+ inEnd=[testStart+2]
847
+
848
+ # Assign some pseudo keywords to the interpreter's namespace.
849
+ self.setBuiltinKeywords()
850
+
851
+ # Add 'shell' to the interpreter's local namespace.
852
+ self.setLocalShell()
853
+
854
+ # Do this last so the user has complete control over their
855
+ # environment. They can override anything they want.
856
+ if execStartupScript:
857
+ if startupScript is None:
858
+ startupScript = os.environ.get('PYTHONSTARTUP')
859
+ self.execStartupScript(startupScript)
860
+ else:
861
+ self.prompt()
862
+
863
+ outStart+=[0]
864
+ outEnd+=[self.GetLineCount()-2]
865
+ inStart+=[self.GetLineCount()-1]
866
+ # Set all the line markers to the proper initial states...
867
+ for i in range(self.GetLineCount()):
868
+ self.clearGroupingMarkers(i)
869
+ self.clearIOMarkers(i)
870
+ if i in outStart:
871
+ self.MarkerAdd(i,GROUPING_START)
872
+ self.MarkerAdd(i,OUTPUT_START)
873
+ # Background color is confusing for tutorial... skip it!
874
+ #self.MarkerAdd(i,OUTPUT_BG)
875
+ elif i in outEnd:
876
+ self.MarkerAdd(i,GROUPING_END)
877
+ self.MarkerAdd(i,OUTPUT_END)
878
+ #self.MarkerAdd(i,OUTPUT_BG)
879
+ elif i in inStart:
880
+ self.MarkerAdd(i,GROUPING_START)
881
+ self.MarkerAdd(i,INPUT_START)
882
+ elif i in inMiddle:
883
+ self.MarkerAdd(i,GROUPING_MIDDLE)
884
+ self.MarkerAdd(i,INPUT_MIDDLE)
885
+ elif i in inEnd:
886
+ self.MarkerAdd(i,GROUPING_END)
887
+ self.MarkerAdd(i,INPUT_END)
888
+ else:
889
+ self.MarkerAdd(i,GROUPING_MIDDLE)
890
+ self.MarkerAdd(i,OUTPUT_MIDDLE)
891
+ #self.MarkerAdd(i,OUTPUT_BG)
892
+
893
+ self.SliceSelection=False
894
+ self.runningSlice=None
895
+
896
+ ## NOTE: See note at bottom of this file...
897
+ ## #seb: File drag and drop
898
+ ## self.SetDropTarget( FileDropTarget(self) )
899
+
900
+ #ADD UNDO
901
+ # Everywhere "ADD UNDO" appears, there is new code to handle markers
902
+ self.EmptyUndoBuffer()
903
+
904
+ wx.CallAfter(self.ScrollToLine, 0)
905
+
906
+ def ToggleShellMode(self,enableShellMode=None):
907
+ if enableShellMode==None:
908
+ if self.mode=='ShellMode': self.mode='SlicesMode'
909
+ elif self.mode=='SlicesMode': self.mode='ShellMode'
910
+ elif enableShellMode:
911
+ self.mode='ShellMode'
912
+ else:
913
+ self.mode='SlicesMode'
914
+
915
+ input_color="red"
916
+ if self.mode=='SlicesMode':
917
+ self.MarkerDefine(INPUT_START, stc.STC_MARK_BOXMINUS,
918
+ "white", input_color)
919
+ self.MarkerDefine(INPUT_START_FOLDED, stc.STC_MARK_BOXPLUS,
920
+ "white", input_color)
921
+ self.MarkerDefine(INPUT_MIDDLE, stc.STC_MARK_VLINE,
922
+ "white", input_color)
923
+ self.MarkerDefine(INPUT_END, stc.STC_MARK_LCORNER,
924
+ "white", input_color)
925
+ elif self.mode=='ShellMode':
926
+ self.MarkerDefine(INPUT_START, stc.STC_MARK_ARROWS,
927
+ input_color, "white")
928
+ self.MarkerDefine(INPUT_START_FOLDED, stc.STC_MARK_BOXPLUS,
929
+ "white", input_color)
930
+ self.MarkerDefine(INPUT_MIDDLE, stc.STC_MARK_DOTDOTDOT,
931
+ input_color, "white")
932
+ self.MarkerDefine(INPUT_END, stc.STC_MARK_DOTDOTDOT,
933
+ input_color, "white")
934
+
935
+ def ToggleFoldingMargin(self,hideFoldingMargin=None):
936
+ if hideFoldingMargin==None:
937
+ self.hideFoldingMargin = not self.hideFoldingMargin
938
+ else:
939
+ self.hideFoldingMargin = hideFoldingMargin
940
+
941
+ if self.hideFoldingMargin:
942
+ self.SetMarginWidth(4, 0)
943
+ else:
944
+ self.SetMarginWidth(4, 12)
945
+
946
+ def clearHistory(self):
947
+ self.history = []
948
+ self.historyIndex = -1
949
+ dispatcher.send(signal="SlicesShell.clearHistory")
950
+
951
+
952
+ def destroy(self):
953
+ del self.interp
954
+
955
+ def setFocus(self):
956
+ """Set focus to the slices shell."""
957
+ self.SetFocus()
958
+
959
+ def OnIdle(self, event):
960
+ """Free the CPU to do other things."""
961
+ if self.waiting:
962
+ time.sleep(0.05)
963
+ event.Skip()
964
+
965
+ def showIntro(self, text=''):
966
+ """Display introductory text in the slices shell."""
967
+ if text:
968
+ self.write(text,type='Output')
969
+ try:
970
+ if self.interp.introText:
971
+ if text and not text.endswith(os.linesep):
972
+ self.write(os.linesep,type='Output')
973
+ self.write(self.interp.introText,type='Output')
974
+ except AttributeError:
975
+ pass
976
+
977
+ def setBuiltinKeywords(self):
978
+ """Create pseudo keywords as part of builtins.
979
+
980
+ This sets "close", "exit" and "quit" to a helpful string.
981
+ """
982
+ import builtins
983
+ builtins.close = builtins.exit = builtins.quit = \
984
+ 'Click on the close button to leave the application.'
985
+ builtins.cd = cd
986
+ builtins.ls = ls
987
+ builtins.pwd = pwd
988
+ builtins.sx = sx
989
+
990
+
991
+ def quit(self):
992
+ """Quit the application."""
993
+ # XXX Good enough for now but later we want to send a close event.
994
+ # In the close event handler we can make sure they want to
995
+ # quit. Other applications, like PythonCard, may choose to
996
+ # hide rather than quit so we should just post the event and
997
+ # let the surrounding app decide what it wants to do.
998
+ self.write('Click on the close button to leave the application.',
999
+ type='Output')
1000
+
1001
+
1002
+ def setLocalShell(self):
1003
+ """Add 'slicesshell' to locals as reference to ShellFacade instance."""
1004
+ self.interp.locals['slicesshell'] = SlicesShellFacade(other=self)
1005
+
1006
+
1007
+ def execStartupScript(self, startupScript):
1008
+ """Execute the user's PYTHONSTARTUP script if they have one."""
1009
+ if startupScript and os.path.isfile(startupScript):
1010
+ text = 'Startup script executed: ' + startupScript
1011
+ self.push('print(%r)' % text)
1012
+ self.push('with open(%r, "r") as f:\n'
1013
+ ' exec(f.read())\n' % (startupScript))
1014
+ self.interp.startupScript = startupScript
1015
+ else:
1016
+ self.push('')
1017
+
1018
+
1019
+ def about(self):
1020
+ """Display information about Py."""
1021
+ text = DISPLAY_TEXT % \
1022
+ (__author__, VERSION,
1023
+ sys.version.split()[0], wx.VERSION_STRING, str(wx.PlatformInfo),
1024
+ sys.platform)
1025
+ self.write(text.strip(),type='Output')
1026
+
1027
+ def BreakTextIntoCommands(self,text):
1028
+ """Turn a text block into multiple multi-line commands."""
1029
+
1030
+ #text = text.lstrip() # This should not be done!
1031
+ text = self.fixLineEndings(text)
1032
+ text = self.lstripPrompt(text)
1033
+ text = text.replace(os.linesep, '\n')
1034
+ lines = text.split('\n')
1035
+
1036
+ continuations = testForContinuations(text)
1037
+
1038
+ if len(continuations)==2: # Error case...
1039
+ return None,continuations[1]
1040
+ elif len(continuations)==4:
1041
+ stringContinuationList,indentationBlockList, \
1042
+ lineContinuationList,parentheticalContinuationList = continuations
1043
+
1044
+ commands = []
1045
+ command = ''
1046
+ for j,line in enumerate(lines):
1047
+ lstrip = line.lstrip()
1048
+
1049
+ # Get the first alnum word:
1050
+ first_word=[]
1051
+ for i in lstrip:
1052
+ if i.isalnum():
1053
+ first_word.append(i)
1054
+ else:
1055
+ break
1056
+ first_word = ''.join(first_word)
1057
+
1058
+ # Continue the command if it is blank, has indentation,
1059
+ # starts with else, elif,except, or finally
1060
+ # or previous line had a line continuation \
1061
+
1062
+ if j==0:
1063
+ stringCont = False
1064
+ lineCont=False
1065
+ else:
1066
+ stringCont = stringContinuationList[j-1]
1067
+ lineCont = lineContinuationList[j-1]
1068
+
1069
+ if line.strip() == '' or lstrip != line or \
1070
+ first_word in ['else','elif','except','finally'] or \
1071
+ stringCont or lineCont:
1072
+ # Multiline command. Add to the command.
1073
+ command += '\n'
1074
+ command += line
1075
+ else:
1076
+ # New command.
1077
+ if command:
1078
+ # Add the previous command to the list.
1079
+ commands.append(command)
1080
+ # Start a new command, which may be multiline.
1081
+ command = line
1082
+
1083
+ commands.append(command)
1084
+
1085
+ return commands
1086
+
1087
+ def MarkerSet(self,line,markerBitsSet):
1088
+ """MarkerSet is the Set command for MarkerGet"""
1089
+ markerBits=self.MarkerGet(line)
1090
+
1091
+ numMarkers=14
1092
+ for i in range(numMarkers):
1093
+ if (markerBitsSet & (1<<i)) and not (markerBits & (1<<i)):
1094
+ self.MarkerAdd(line,i)
1095
+ elif not (markerBitsSet & (1<<i)) and (markerBits & (1<<i)):
1096
+ self.MarkerDelete(line,i)
1097
+ def GetGroupingSlice(self,line_num=None):
1098
+ """Get the start/stop lines for the slice based on any line in the slice"""
1099
+ if line_num==None:
1100
+ line_num=self.GetCurrentLine()
1101
+
1102
+ num_lines=self.GetLineCount()
1103
+
1104
+ for i in range(line_num,-1,-1):
1105
+ if self.MarkerGet(i) & (1<<GROUPING_START | 1<<GROUPING_START_FOLDED):
1106
+ break
1107
+ start_line=i
1108
+
1109
+ addition=0
1110
+
1111
+ for i in range(line_num,num_lines):
1112
+ if self.MarkerGet(i) & 1<<GROUPING_END:
1113
+ break
1114
+ elif (i>line_num) and ( self.MarkerGet(i)
1115
+ & (1<<GROUPING_START | 1<<GROUPING_START_FOLDED) ):
1116
+ addition=-1
1117
+ break # the solo case...
1118
+ stop_line=i+addition
1119
+
1120
+ return start_line,stop_line
1121
+
1122
+ def GetIOSlice(self,line_num=None):
1123
+ """Get the start/stop lines for the slice based on any line in the slice"""
1124
+ if line_num==None:
1125
+ line_num=self.GetCurrentLine()
1126
+
1127
+ num_lines=self.GetLineCount()
1128
+
1129
+ for i in range(line_num,-1,-1):
1130
+ if self.MarkerGet(i) & IO_ANY_START_MASK:
1131
+ break
1132
+ start_line=i
1133
+
1134
+ addition=0
1135
+
1136
+ for i in range(line_num,num_lines):
1137
+ if self.MarkerGet(i) & IO_END_MASK:
1138
+ break
1139
+ elif (i>line_num) and (self.MarkerGet(i) & IO_ANY_START_MASK):
1140
+ addition=-1
1141
+ break # the solo case...
1142
+ stop_line=i+addition
1143
+
1144
+ return start_line,stop_line
1145
+
1146
+ def FoldGroupingSlice(self,line_num=None):
1147
+ if line_num==None:
1148
+ line_num=self.GetCurrentLine()
1149
+
1150
+ start,end=self.GetGroupingSlice(line_num)
1151
+ self.HideLines(start+1,end)
1152
+ marker=self.MarkerGet(start)
1153
+ self.clearGroupingMarkers(start)
1154
+ self.MarkerAdd(start,GROUPING_START_FOLDED)
1155
+ self.clearIOMarkers(start)
1156
+ if marker & ( 1<<INPUT_START | 1<<INPUT_START_FOLDED ):
1157
+ self.MarkerAdd(start,INPUT_START_FOLDED)
1158
+ elif marker & ( 1<<OUTPUT_START | 1<<OUTPUT_START_FOLDED ):
1159
+ self.MarkerAdd(start,OUTPUT_START_FOLDED)
1160
+ self.MarkerAdd(start,OUTPUT_BG)
1161
+ else:
1162
+ pass #print('Bad Markers!!!')
1163
+ def FoldIOSlice(self,line_num=None):
1164
+ if line_num==None:
1165
+ line_num=self.GetCurrentLine()
1166
+
1167
+ start,end=self.GetIOSlice(line_num)
1168
+ self.HideLines(start+1,end)
1169
+ marker=self.MarkerGet(start)
1170
+ if (self.MarkerGet(start) & \
1171
+ (1<<GROUPING_START | 1<<GROUPING_START_FOLDED )) and \
1172
+ (self.MarkerGet(end) & 1<<GROUPING_END):
1173
+ self.clearGroupingMarkers(start)
1174
+ self.MarkerAdd(start,GROUPING_START_FOLDED)
1175
+ self.clearIOMarkers(start)
1176
+ if marker & ( 1<<INPUT_START | 1<<INPUT_START_FOLDED ):
1177
+ self.MarkerAdd(start,INPUT_START_FOLDED)
1178
+ elif marker & ( 1<<OUTPUT_START | 1<<OUTPUT_START_FOLDED ):
1179
+ self.MarkerAdd(start,OUTPUT_START_FOLDED)
1180
+ self.MarkerAdd(start,OUTPUT_BG)
1181
+ else:
1182
+ pass #print('Bad Markers!!!')
1183
+ def UnFoldGroupingSlice(self,line_num=None):
1184
+ if line_num==None:
1185
+ line_num=self.GetCurrentLine()
1186
+
1187
+ start,end=self.GetGroupingSlice(line_num)
1188
+ self.ShowLines(start+1,end)
1189
+ self.clearGroupingMarkers(start)
1190
+ self.MarkerAdd(start,GROUPING_START)
1191
+ for i in range(start,end):
1192
+ marker=self.MarkerGet(i)
1193
+ if marker & (1<<INPUT_START | 1<<INPUT_START_FOLDED):
1194
+ self.clearIOMarkers(i)
1195
+ self.MarkerAdd(i,INPUT_START)
1196
+ elif marker & (1<<OUTPUT_START | 1<<OUTPUT_START_FOLDED):
1197
+ self.clearIOMarkers(i)
1198
+ self.MarkerAdd(i,OUTPUT_START)
1199
+ self.MarkerAdd(i,OUTPUT_BG)
1200
+
1201
+ def UnFoldIOSlice(self,line_num=None):
1202
+ if line_num==None:
1203
+ line_num=self.GetCurrentLine()
1204
+
1205
+ start,end=self.GetIOSlice(line_num)
1206
+ self.ShowLines(start+1,end)
1207
+ marker=self.MarkerGet(start)
1208
+ if (self.MarkerGet(start) & \
1209
+ (1<<GROUPING_START | 1<<GROUPING_START_FOLDED )) and \
1210
+ (self.MarkerGet(end) & 1<<GROUPING_END):
1211
+ self.clearGroupingMarkers(start)
1212
+ self.MarkerAdd(start,GROUPING_START)
1213
+ self.clearIOMarkers(start)
1214
+ if marker & 1<<INPUT_START_FOLDED:
1215
+ self.MarkerAdd(start,INPUT_START)
1216
+ elif marker & 1<<OUTPUT_START_FOLDED:
1217
+ self.MarkerAdd(start,OUTPUT_START)
1218
+ self.MarkerAdd(start,OUTPUT_BG)
1219
+
1220
+ def DeleteOutputSlicesAfter(self,line_num=None):
1221
+ """Delete all outputs after an input"""
1222
+ if line_num==None:
1223
+ line_num=self.GetCurrentLine()
1224
+
1225
+ num_lines=self.GetLineCount()
1226
+
1227
+ if self.MarkerGet(line_num) & OUTPUT_MASK:
1228
+ #print('You can only run "DeleteOutputSlicesAfter" from an Input slice!')
1229
+ return
1230
+
1231
+ startIn,endIn=self.GetIOSlice(line_num)
1232
+ startGrouping,endGrouping=self.GetGroupingSlice(line_num)
1233
+
1234
+ if endIn<endGrouping:
1235
+ self.SetSelection(self.PositionFromLine(endIn+1),
1236
+ self.PositionFromLine(endGrouping+1))
1237
+ self.ReplaceSelection('',sliceDeletion=True)
1238
+
1239
+ new_pos=self.GetLineEndPosition(line_num)
1240
+ self.SetCurrentPos(new_pos)
1241
+ self.SetSelection(new_pos,new_pos)
1242
+
1243
+ def SplitSlice(self,line_num=None):
1244
+ if line_num==None:
1245
+ line_num=self.GetCurrentLine()
1246
+
1247
+ start_num,end_num=self.GetIOSlice(line_num)
1248
+
1249
+ if self.MarkerGet(line_num) & INPUT_MASK:
1250
+ type='Input'
1251
+ start=INPUT_START
1252
+ end=INPUT_END
1253
+ splitGrouping=True
1254
+ elif self.MarkerGet(line_num) & OUTPUT_MASK:
1255
+ type='Output'
1256
+ start=OUTPUT_START
1257
+ end=OUTPUT_END
1258
+ splitGrouping=False
1259
+
1260
+ if start_num==end_num:
1261
+ return # Can't split one line!
1262
+ elif start_num==line_num:
1263
+ self.clearIOMarkers(line_num+1)
1264
+ self.MarkerAdd(line_num+1,start)
1265
+ if type=='Output': self.MarkerAdd(line_num+1,OUTPUT_BG)
1266
+ if splitGrouping:
1267
+ self.clearGroupingMarkers(line_num+1)
1268
+ self.MarkerAdd(line_num+1,GROUPING_START)
1269
+ else:
1270
+ self.clearIOMarkers(line_num)
1271
+ self.MarkerAdd(line_num,start)
1272
+ if type=='Output': self.MarkerAdd(line_num,OUTPUT_BG)
1273
+ if splitGrouping:
1274
+ self.clearGroupingMarkers(line_num)
1275
+ self.MarkerAdd(line_num,GROUPING_START)
1276
+ if line_num-1>start_num:
1277
+ self.clearIOMarkers(line_num-1)
1278
+ self.MarkerAdd(line_num-1,end)
1279
+ if type=='Output': self.MarkerAdd(line_num-1,OUTPUT_BG)
1280
+ if splitGrouping:
1281
+ self.clearGroupingMarkers(line_num-1)
1282
+ self.MarkerAdd(line_num-1,GROUPING_END)
1283
+
1284
+ def BackspaceWMarkers(self,force=False):
1285
+ # Warning: This is not good at checking for bad markers!
1286
+ c_before=self.GetCharAt(self.GetCurrentPos() - 1)
1287
+ c_after=self.GetCharAt(self.GetCurrentPos())
1288
+
1289
+ if c_before==0:
1290
+ # Disallow deleting the first line or it will destroy the markers...
1291
+ return False
1292
+ elif c_before in (ord('\n'),ord('\r')):
1293
+ line_num=self.GetCurrentLine()
1294
+
1295
+ marker=self.MarkerGet(line_num)
1296
+ marker_before=self.MarkerGet(line_num-1)
1297
+ marker_after=self.MarkerGet(line_num+1)
1298
+ if marker_before & ( 1<<GROUPING_END ) :
1299
+ return False # Disallow deleting lines between slices...
1300
+ elif marker & ( 1<<GROUPING_START | 1<<GROUPING_START_FOLDED ) :
1301
+ return False # Disallow deleting lines between slices...
1302
+ else:
1303
+ if marker_before & ( 1<<GROUPING_START | 1<<GROUPING_START_FOLDED ) :
1304
+ self.clearGroupingMarkers(line_num)
1305
+ elif marker & ( 1<<GROUPING_END ) :
1306
+ self.clearGroupingMarkers(line_num-1)
1307
+
1308
+ if (marker_before & 1<<INPUT_END) and force:
1309
+ # Special case for use in processLine
1310
+ self.clearIOMarkers(line_num)
1311
+ elif marker_before & (1<<INPUT_END | 1<<OUTPUT_END):
1312
+ return False # Disallow deleting lines between slices...
1313
+ elif marker & ( 1<<INPUT_START | 1<<INPUT_START_FOLDED ) :
1314
+ return False # Disallow deleting lines between slices...
1315
+ else:
1316
+ if marker_before & (1<<INPUT_START | 1<<INPUT_START_FOLDED |
1317
+ 1<<OUTPUT_START | 1<<OUTPUT_START_FOLDED):
1318
+ self.clearIOMarkers(line_num)
1319
+ elif marker & ( 1<<INPUT_END | 1<<OUTPUT_END ) :
1320
+ self.clearIOMarkers(line_num-1)
1321
+
1322
+ return True # If everything went well, return True and do the delete...
1323
+
1324
+ def ForwardDeleteWMarkers(self):
1325
+ c_before=self.GetCharAt(self.GetCurrentPos() - 1)
1326
+ c_after=self.GetCharAt(self.GetCurrentPos())
1327
+ if c_after==0:
1328
+ # Disallow deleting the first line or it will destroy the markers...
1329
+ return False
1330
+ elif c_after in (ord('\n'),ord('\r')):
1331
+ line_num=self.GetCurrentLine()
1332
+
1333
+ marker=self.MarkerGet(line_num)
1334
+ marker_before=self.MarkerGet(line_num-1)
1335
+ marker_after=self.MarkerGet(line_num+1)
1336
+ if marker & ( 1<<GROUPING_END ) :
1337
+ return False # Disallow deleting lines between slices...
1338
+ elif marker_after & ( 1<<GROUPING_START | 1<<GROUPING_START_FOLDED ) :
1339
+ return False # Disallow deleting lines between slices...
1340
+ else:
1341
+ if marker & ( 1<<GROUPING_START | 1<<GROUPING_START_FOLDED ) :
1342
+ self.clearGroupingMarkers(line_num+1)
1343
+ elif marker_after & ( 1<<GROUPING_END ) :
1344
+ self.clearGroupingMarkers(line_num)
1345
+
1346
+ if marker & ( 1<<INPUT_END | 1<<OUTPUT_END ) :
1347
+ return False # Disallow deleting lines between slices...
1348
+ elif marker_after & ( 1<<INPUT_START | 1<<INPUT_START_FOLDED ) :
1349
+ return False # Disallow deleting lines between slices...
1350
+ else:
1351
+ if marker & (1<<INPUT_START | 1<<INPUT_START_FOLDED |
1352
+ 1<<OUTPUT_START | 1<<OUTPUT_START_FOLDED) :
1353
+ self.clearIOMarkers(line_num+1)
1354
+ elif marker_after & ( 1<<INPUT_END | 1<<OUTPUT_END ) :
1355
+ self.clearIOMarkers(line_num)
1356
+
1357
+ return True
1358
+
1359
+ def GetIOSelection(self):
1360
+ started=False
1361
+ start=0
1362
+ end=self.GetLineCount()-1
1363
+ type=None
1364
+ for i in range(self.GetLineCount()):
1365
+ if self.MarkerGet(i) & 1<<IO_SELECTING:
1366
+ if started==False:
1367
+ start=i
1368
+ if self.MarkerGet(i) & INPUT_MASK:
1369
+ type='input'
1370
+ elif self.MarkerGet(i) & OUTPUT_MASK:
1371
+ type='output'
1372
+ else:
1373
+ if self.MarkerGet(i) & INPUT_MASK:
1374
+ if type=='output':
1375
+ end=i-1
1376
+ break
1377
+ elif self.MarkerGet(i) & OUTPUT_MASK:
1378
+ if type=='input':
1379
+ end=i-1
1380
+ break
1381
+ started=True
1382
+ elif started==True:
1383
+ end=i-1
1384
+ break
1385
+
1386
+ if started==False:
1387
+ #print('No Selection!!')
1388
+ self.SliceSelection=False
1389
+
1390
+ return start,end
1391
+
1392
+ def MergeAdjacentSlices(self):
1393
+ """This function merges all adjacent selected slices.\n""" + \
1394
+ """Right now, only IO Merging is allowed."""
1395
+ started=False
1396
+ start=0
1397
+ end=self.GetLineCount()-1
1398
+ type=None
1399
+ for i in range(self.GetLineCount()):
1400
+ if self.MarkerGet(i) & 1<<IO_SELECTING:
1401
+ if started==False:
1402
+ start=i
1403
+ if self.MarkerGet(i) & INPUT_MASK:
1404
+ type='input'
1405
+ elif self.MarkerGet(i) & OUTPUT_MASK:
1406
+ type='output'
1407
+ else:
1408
+ if self.MarkerGet(i) & INPUT_MASK:
1409
+ if type=='output':
1410
+ end=i-1
1411
+ break
1412
+ else:
1413
+ self.clearIOMarkers(i)
1414
+ self.clearGroupingMarkers(i)
1415
+ self.MarkerAdd(i,INPUT_MIDDLE)
1416
+ self.MarkerAdd(i,GROUPING_MIDDLE)
1417
+ elif self.MarkerGet(i) & OUTPUT_MASK:
1418
+ if type=='input':
1419
+ end=i-1
1420
+ break
1421
+ else:
1422
+ self.clearIOMarkers(i)
1423
+ self.clearGroupingMarkers(i)
1424
+ self.MarkerAdd(i,OUTPUT_MIDDLE)
1425
+ self.MarkerAdd(i,OUTPUT_BG)
1426
+ self.MarkerAdd(i,GROUPING_MIDDLE)
1427
+ started=True
1428
+ elif started==True:
1429
+ end=i-1
1430
+ break
1431
+
1432
+ if started and end!=start:
1433
+ self.clearIOMarkers(end)
1434
+ self.clearGroupingMarkers(end)
1435
+ if type=='input':
1436
+ self.MarkerAdd(end,INPUT_END)
1437
+ if end+1<self.GetLineCount():
1438
+ if self.MarkerGet(end+1) & OUTPUT_MASK:
1439
+ self.MarkerAdd(end,GROUPING_MIDDLE)
1440
+ else:
1441
+ self.MarkerAdd(end,GROUPING_END)
1442
+ else:
1443
+ self.MarkerAdd(end,GROUPING_END)
1444
+ else:
1445
+ if self.MarkerGet(start) & 1<<GROUPING_END:
1446
+ self.clearGroupingMarkers(start)
1447
+ self.MarkerAdd(start,GROUPING_MIDDLE)
1448
+ self.MarkerAdd(end,OUTPUT_END)
1449
+ self.MarkerAdd(end,OUTPUT_BG)
1450
+ self.MarkerAdd(end,GROUPING_END)
1451
+
1452
+
1453
+ def SliceSelectionDelete(self):
1454
+ """Deletion of any selected and possibly discontinuous slices."""
1455
+ if not self.SliceSelection:
1456
+ return
1457
+
1458
+ # collect the line numbers to be deleted...
1459
+ selectedSlices=[]
1460
+ start,end=None,None
1461
+ for i in range(self.GetLineCount()):
1462
+ if self.MarkerGet(i) & (1<<GROUPING_SELECTING | 1<<IO_SELECTING):
1463
+ if start==None:
1464
+ start=i
1465
+ end=i
1466
+ elif start!=None:
1467
+ selectedSlices.append([start,end])
1468
+ start,end=None,None
1469
+ if start!=None:
1470
+ selectedSlices.append([start,end])
1471
+
1472
+ # Unselect everything
1473
+ self.MarginUnselectAll()
1474
+ self.SliceSelection=False
1475
+
1476
+ # Going in reverse, delete the selections, fixing the markers as we go...
1477
+ for i in range(len(selectedSlices)-1,-1,-1):
1478
+ self.SetSelection(self.PositionFromLine(selectedSlices[i][0]),
1479
+ self.GetLineEndPosition(selectedSlices[i][1])+1)
1480
+
1481
+ markerNext = self.MarkerGet(selectedSlices[i][1]+1)
1482
+
1483
+ self.ReplaceSelection('',sliceDeletion=True)
1484
+
1485
+ cur_line=self.GetCurrentLine()
1486
+
1487
+ # If we've made a mess of the grouping markers, clean it up...
1488
+ if ((self.MarkerGet(cur_line-1) & 1<<GROUPING_END) and
1489
+ (self.MarkerGet(cur_line) & ( 1<<GROUPING_MIDDLE | 1<<GROUPING_END ) )):
1490
+ self.clearGroupingMarkers(cur_line)
1491
+ self.MarkerAdd(cur_line,GROUPING_START)
1492
+ elif (( self.MarkerGet(cur_line-1) & 1<<GROUPING_MIDDLE ) and
1493
+ ( self.MarkerGet(cur_line) &
1494
+ ( 1<<GROUPING_START | 1<<GROUPING_START_FOLDED ) )):
1495
+ self.clearGroupingMarkers(cur_line-1)
1496
+ self.MarkerAdd(cur_line-1,GROUPING_END)
1497
+
1498
+ if markerNext & 1<<OUTPUT_START:
1499
+ self.clearIOMarkers(cur_line)
1500
+ self.MarkerAdd(cur_line,OUTPUT_START)
1501
+ self.MarkerAdd(cur_line,OUTPUT_BG)
1502
+ elif markerNext & 1<<OUTPUT_START_FOLDED:
1503
+ self.clearIOMarkers(cur_line)
1504
+ self.MarkerAdd(cur_line,OUTPUT_START_FOLDED)
1505
+ self.MarkerAdd(cur_line,OUTPUT_BG)
1506
+
1507
+ return
1508
+
1509
+ def OnChar(self, event):
1510
+ """Keypress event handler.
1511
+
1512
+ Only receives an event if OnKeyDown calls event.Skip() for the
1513
+ corresponding event."""
1514
+
1515
+ if self.noteMode:
1516
+ event.Skip()
1517
+ return
1518
+
1519
+ # Prevent modification of output slices
1520
+ if not self.CanEdit():
1521
+ return
1522
+ key = event.GetKeyCode()
1523
+ currpos = self.GetCurrentPos()
1524
+ stoppos = self.PositionFromLine(self.GetCurrentLine())
1525
+
1526
+ # Return (Enter) needs to be ignored in this handler.
1527
+ if key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
1528
+ pass
1529
+ elif key in self.autoCompleteKeys:
1530
+ # Usually the dot (period) key activates auto completion.
1531
+ # Get the command between the prompt and the cursor. Add
1532
+ # the autocomplete character to the end of the command.
1533
+ if self.AutoCompActive():
1534
+ self.AutoCompCancel()
1535
+ command = self.GetTextRange(stoppos, currpos) + chr(key)
1536
+
1537
+ # write with undo wrapper...
1538
+ cpos=self.GetCurrentPos()
1539
+ s=chr(key)
1540
+ #ADD UNDO
1541
+ self.UpdateUndoHistoryBefore('insert',s,cpos,cpos+len(s),
1542
+ forceNewAction=False)
1543
+ self.write(s,type='Input')
1544
+ self.UpdateUndoHistoryAfter()
1545
+
1546
+ if self.autoComplete:
1547
+ self.autoCompleteShow(command)
1548
+ elif key == ord('('):
1549
+ # The left paren activates a call tip and cancels an
1550
+ # active auto completion.
1551
+ if self.AutoCompActive():
1552
+ self.AutoCompCancel()
1553
+ # Get the command between the prompt and the cursor. Add
1554
+ # the '(' to the end of the command.
1555
+ self.ReplaceSelection('')
1556
+ command = self.GetTextRange(stoppos, currpos) + '('
1557
+
1558
+ # write with undo wrapper...
1559
+ cpos=self.GetCurrentPos()
1560
+ s='('
1561
+ self.UpdateUndoHistoryBefore('insert',s,cpos,cpos+len(s),
1562
+ forceNewAction=True)
1563
+ self.undoHistory[self.undoIndex]['allowsAppend']=True
1564
+ self.write(s,type='Input')
1565
+ self.UpdateUndoHistoryAfter()
1566
+
1567
+ self.autoCallTipShow(command,
1568
+ self.GetCurrentPos() == self.GetTextLength())
1569
+ else:
1570
+ # Allow the normal event handling to take place.
1571
+ # Use undo wrapper
1572
+ cpos=self.GetCurrentPos()
1573
+ try:
1574
+ s=chr(key)
1575
+ self.UpdateUndoHistoryBefore('insert',s,cpos,cpos+len(s))
1576
+ event.Skip()
1577
+ self.UpdateUndoHistoryAfter()
1578
+ except:
1579
+ event.Skip()
1580
+
1581
+ def AutoCompActiveCallback(self):
1582
+ numChars=self.GetTextLength()-self.TotalLengthForAutoCompActiveCallback
1583
+ if numChars==0:
1584
+ self.undoIndex-=1
1585
+ del(self.undoHistory[-1])
1586
+ else:
1587
+ uH=self.undoHistory
1588
+ uI=self.undoIndex
1589
+ cpos=uH[uI]['posStart']
1590
+ s=''.join([chr(self.GetCharAt(cpos+i)) for i in range(numChars)])
1591
+ s.replace(os.linesep,'\n')
1592
+ self.undoHistory[self.undoIndex]['charList'] = s
1593
+ self.undoHistory[self.undoIndex]['posEnd'] = cpos + numChars
1594
+ self.undoHistory[self.undoIndex]['numLines'] = len(s.split('\n'))
1595
+ self.UpdateUndoHistoryAfter()
1596
+
1597
+ def OnKeyDown(self, event):
1598
+ """Key down event handler."""
1599
+
1600
+ key = event.GetKeyCode()
1601
+ # If the auto-complete window is up let it do its thing.
1602
+ if self.AutoCompActive():
1603
+ if key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
1604
+ cpos=self.GetCurrentPos()
1605
+ self.UpdateUndoHistoryBefore('insert','dummy',cpos,cpos+5,
1606
+ forceNewAction=True)
1607
+ self.undoHistory[self.undoIndex]['allowsAppend'] = True
1608
+ self.TotalLengthForAutoCompActiveCallback=self.GetTextLength()
1609
+ event.Skip()
1610
+ wx.CallAfter(self.AutoCompActiveCallback)
1611
+ if key in [wx.WXK_DELETE,wx.WXK_BACK]:
1612
+ self.AutoCompCancel()
1613
+ else:
1614
+ event.Skip()
1615
+ return
1616
+
1617
+ #DNM
1618
+ # Prevent modification of output slices
1619
+ controlDown = event.ControlDown()
1620
+ altDown = event.AltDown()
1621
+ shiftDown = event.ShiftDown()
1622
+ currpos = self.GetCurrentPos()
1623
+ endpos = self.GetTextLength()
1624
+ selecting = self.GetSelectionStart() != self.GetSelectionEnd()
1625
+
1626
+ if key == wx.WXK_F12: #seb
1627
+ if self.noteMode:
1628
+ # self.promptPosStart not used anyway - or ?
1629
+ ## # We don't need to do this any more!
1630
+ ## self.promptPosEnd = self.PositionFromLine(self.GetLineCount()-1 ) +
1631
+ ## len(str(sys.ps1))
1632
+ ## self.GotoLine(self.GetLineCount())
1633
+ ## self.GotoPos(self.promptPosEnd)
1634
+ ## self.prompt() #make sure we have a prompt
1635
+ self.SetCaretForeground("black")
1636
+ self.SetCaretWidth(1) #default
1637
+ self.SetCaretPeriod(500) #default
1638
+ else:
1639
+ self.SetCaretForeground("red")
1640
+ self.SetCaretWidth(4)
1641
+ self.SetCaretPeriod(0) #steady
1642
+
1643
+ self.noteMode = not self.noteMode
1644
+ return
1645
+ if self.noteMode:
1646
+ event.Skip()
1647
+ return
1648
+
1649
+ doLineBreak=False
1650
+ doSubmitCommand=False
1651
+ doPass=False
1652
+ # Return is used to insert a line break.
1653
+ # In Shell Mode, hit Return or Enter twice to submit a command
1654
+ if ((not controlDown and not shiftDown and not altDown) and
1655
+ key in [wx.WXK_RETURN,]):
1656
+ if self.mode=='SlicesMode':
1657
+ doLineBreak=True
1658
+ elif self.mode=='ShellMode':
1659
+ startLine,endLine = self.GetIOSlice()
1660
+ startpos = self.PositionFromLine(startLine)
1661
+ endpos = self.GetLineEndPosition(endLine)
1662
+ command = self.GetTextRange(startpos, endpos)
1663
+ strCont,indentBlock,lineCont,parenCont = testForContinuations(command,ignoreErrors=True)
1664
+
1665
+ lastLine = command.split('\n')[-1]
1666
+ if lastLine.lstrip()=='': # all whitespace...
1667
+ stillIndented=False
1668
+ elif lastLine[0]==' ':
1669
+ stillIndented=True
1670
+ else:
1671
+ stillIndented=False
1672
+
1673
+ if strCont[-1] or indentBlock[-1] or lineCont[-1] or \
1674
+ parenCont[-1]:
1675
+ doLineBreak=True
1676
+ elif stillIndented:
1677
+ new_pos=self.GetLineEndPosition(endLine)
1678
+ self.SetCurrentPos(new_pos)
1679
+ self.SetSelection(new_pos,new_pos)
1680
+ doLineBreak=True
1681
+ elif self.GetCurrentLine()!=endLine:
1682
+ new_pos=self.GetLineEndPosition(endLine)
1683
+ self.SetCurrentPos(new_pos)
1684
+ self.SetSelection(new_pos,new_pos)
1685
+ doPass = True
1686
+ else:
1687
+ doSubmitCommand=True
1688
+ # Enter (Shift/Ctrl + Enter/Return) submits a command to the interpreter.
1689
+ # In Shell Mode, hit Return or Enter twice to submit a command
1690
+ elif ( key in [wx.WXK_NUMPAD_ENTER,] or
1691
+ ( (shiftDown or controlDown) and key in [wx.WXK_RETURN,
1692
+ wx.WXK_NUMPAD_ENTER] ) ):
1693
+ if self.mode=='SlicesMode':
1694
+ doSubmitCommand=True
1695
+ elif self.mode=='ShellMode':
1696
+ doLineBreak=True
1697
+
1698
+ #Only relevant in ShellMode...
1699
+
1700
+ if doPass:
1701
+ pass
1702
+ elif doLineBreak or doSubmitCommand:
1703
+ if self.CallTipActive():
1704
+ self.CallTipCancel()
1705
+ elif self.SliceSelection:
1706
+ for i in range(self.GetLineCount()):
1707
+ if self.MarkerGet(i) & 1<<GROUPING_SELECTING:
1708
+ self.DoMarginClick(i, 2, shiftDown, controlDown)
1709
+ break
1710
+ elif self.MarkerGet(i) & 1<<IO_SELECTING:
1711
+ self.DoMarginClick(i, 3, shiftDown, controlDown)
1712
+ break
1713
+ elif doLineBreak:
1714
+ self.insertLineBreak()
1715
+ #Only relevant in ShellMode...
1716
+ elif doSubmitCommand:
1717
+ self.DeleteOutputSlicesAfter()
1718
+ self.processLine()
1719
+
1720
+ # Let Ctrl-Alt-* get handled normally.
1721
+ elif controlDown and altDown:
1722
+ event.Skip()
1723
+
1724
+ # Clear the current, unexecuted command.
1725
+ elif key == wx.WXK_ESCAPE:
1726
+ if self.CallTipActive():
1727
+ event.Skip()
1728
+ # Clear the current command
1729
+ elif key == wx.WXK_BACK and controlDown and shiftDown:
1730
+ self.clearCommand()
1731
+
1732
+ # Increase font size.
1733
+ elif controlDown and key in (ord(']'), wx.WXK_NUMPAD_ADD):
1734
+ dispatcher.send(signal='FontIncrease')
1735
+
1736
+ # Decrease font size.
1737
+ elif controlDown and key in (ord('['), wx.WXK_NUMPAD_SUBTRACT):
1738
+ dispatcher.send(signal='FontDecrease')
1739
+
1740
+ # Default font size.
1741
+ elif controlDown and key in (ord('='), wx.WXK_NUMPAD_DIVIDE):
1742
+ dispatcher.send(signal='FontDefault')
1743
+
1744
+ # Cut to the clipboard.
1745
+ elif (controlDown and key in (ord('X'), ord('x'))) \
1746
+ or (shiftDown and key == wx.WXK_DELETE):
1747
+ self.Cut()
1748
+
1749
+ # Copy to the clipboard.
1750
+ elif controlDown and not shiftDown \
1751
+ and key in (ord('C'), ord('c'), wx.WXK_INSERT):
1752
+ self.Copy()
1753
+
1754
+ # Copy to the clipboard, including prompts.
1755
+ elif controlDown and shiftDown \
1756
+ and key in (ord('C'), ord('c'), wx.WXK_INSERT):
1757
+ self.CopyWithPrompts()
1758
+
1759
+ # Copy to the clipboard, including prefixed prompts.
1760
+ elif altDown and not controlDown \
1761
+ and key in (ord('C'), ord('c'), wx.WXK_INSERT):
1762
+ self.CopyWithPromptsPrefixed()
1763
+
1764
+ # Home needs to be aware of the prompt.
1765
+ elif controlDown and key == wx.WXK_HOME:
1766
+ # Go to the beginning of the IO Slice
1767
+ curLine = self.GetCurrentLine()
1768
+ IOstart = self.GetIOSlice(curLine)[0]
1769
+ home = self.PositionFromLine(IOstart)
1770
+ if currpos == home and \
1771
+ IOstart > 0:
1772
+ home = self.PositionFromLine(self.GetIOSlice(curLine-1)[0])
1773
+ self.SetCurrentPos(home)
1774
+ if not selecting and not shiftDown:
1775
+ self.SetAnchor(home)
1776
+ self.EnsureCaretVisible()
1777
+
1778
+ elif controlDown and key == wx.WXK_END:
1779
+ curLine = self.GetCurrentLine()
1780
+ IOend = self.GetIOSlice(curLine)[1]
1781
+ end = self.GetLineEndPosition(IOend)
1782
+ if currpos == end and \
1783
+ IOend < self.GetLineCount()-1:
1784
+ end = self.GetLineEndPosition(self.GetIOSlice(curLine+1)[1])
1785
+ self.SetCurrentPos(end)
1786
+ if not selecting and not shiftDown:
1787
+ self.SetAnchor(end)
1788
+ self.EnsureCaretVisible()
1789
+
1790
+ elif controlDown and key == wx.WXK_PAGEUP:
1791
+ pos=0
1792
+ if currpos > pos:
1793
+ self.SetCurrentPos(pos)
1794
+ if not selecting and not shiftDown:
1795
+ self.SetAnchor(pos)
1796
+ self.EnsureCaretVisible()
1797
+
1798
+ elif controlDown and key == wx.WXK_PAGEDOWN:
1799
+ pos = self.GetLineEndPosition(self.GetLineCount()-1)
1800
+ if currpos < pos:
1801
+ self.SetCurrentPos(pos)
1802
+ if not selecting and not shiftDown:
1803
+ self.SetAnchor(pos)
1804
+ self.EnsureCaretVisible()
1805
+
1806
+ elif selecting and key not in NAVKEYS and not self.CanEdit():
1807
+ pass
1808
+
1809
+ # Paste from the clipboard.
1810
+ elif (controlDown and not shiftDown and key in (ord('V'), ord('v'))) \
1811
+ or (shiftDown and not controlDown and key == wx.WXK_INSERT):
1812
+ self.Paste()
1813
+
1814
+ # Paste from the clipboard, run commands.
1815
+ elif controlDown and shiftDown and \
1816
+ key in (ord('V'), ord('v')) and self.CanEdit():
1817
+ self.PasteAndRun()
1818
+
1819
+ # Replace with the previous command from the history buffer.
1820
+ elif (controlDown and not shiftDown and key == wx.WXK_UP) \
1821
+ or (altDown and key in (ord('P'), ord('p'))) and self.CanEdit():
1822
+ self.OnHistoryReplace(step=+1)
1823
+
1824
+ # Replace with the next command from the history buffer.
1825
+ elif (controlDown and not shiftDown and key == wx.WXK_DOWN) \
1826
+ or (altDown and key in (ord('N'), ord('n'))) and self.CanEdit():
1827
+ self.OnHistoryReplace(step=-1)
1828
+
1829
+ # Insert the previous command from the history buffer.
1830
+ elif (controlDown and shiftDown and key == wx.WXK_UP) and \
1831
+ self.CanEdit():
1832
+ self.OnHistoryInsert(step=+1)
1833
+
1834
+ # Insert the next command from the history buffer.
1835
+ elif (controlDown and shiftDown and key == wx.WXK_DOWN) and \
1836
+ self.CanEdit():
1837
+ self.OnHistoryInsert(step=-1)
1838
+
1839
+ # Ctrl-Space shows Auto Completion
1840
+ # Ctrl-Shift-Space shows CallTips
1841
+ elif controlDown and key == wx.WXK_SPACE:
1842
+ self.OnCallTipAutoCompleteManually(shiftDown)
1843
+
1844
+ # Ctrl+Shift+H is used to complete Text (from already typed words)
1845
+ elif controlDown and shiftDown and key in [ord('H')]:
1846
+ self.OnShowCompHistory()
1847
+
1848
+ # Search up the history for the text in front of the cursor.
1849
+ elif key == wx.WXK_F8:
1850
+ self.OnHistorySearch()
1851
+
1852
+ # Don't backspace over the latest non-continuation prompt.
1853
+ elif key == wx.WXK_BACK:
1854
+ if self.SliceSelection:
1855
+ self.SliceSelectionDelete()
1856
+ wx.CallAfter(self.RestoreFirstMarker)
1857
+ elif selecting and self.CanEdit():
1858
+ self.ReplaceSelection('')
1859
+ #event.Skip()
1860
+ elif self.CanEdit():
1861
+ doDelete=True
1862
+ cur_line=self.GetCurrentLine()
1863
+ if not cur_line==0 and \
1864
+ self.GetCurrentPos()==self.PositionFromLine(cur_line):
1865
+ if self.MarkerGet(cur_line-1) & OUTPUT_MASK:
1866
+ doDelete=False
1867
+
1868
+ if doDelete:
1869
+ cpos=self.GetCurrentPos()
1870
+ s=chr(self.GetCharAt(cpos-1))
1871
+ self.UpdateUndoHistoryBefore('delete',s,cpos-1,cpos)
1872
+ if self.BackspaceWMarkers():
1873
+ event.Skip()
1874
+
1875
+ wx.CallAfter(self.RestoreFirstMarker)
1876
+
1877
+ elif key == wx.WXK_DELETE:
1878
+ if self.SliceSelection:
1879
+ self.SliceSelectionDelete()
1880
+ wx.CallAfter(self.RestoreFirstMarker)
1881
+ elif selecting and self.CanEdit():
1882
+ self.ReplaceSelection('')
1883
+ #event.Skip()
1884
+ elif self.CanEdit():
1885
+ doDelete=True
1886
+ cur_line=self.GetCurrentLine()
1887
+ if not cur_line==self.GetLineCount()-1 and \
1888
+ self.GetCurrentPos()==self.GetLineEndPosition(cur_line):
1889
+ if self.MarkerGet(cur_line+1) & OUTPUT_MASK:
1890
+ doDelete=False
1891
+
1892
+ if doDelete:
1893
+ cpos=self.GetCurrentPos()
1894
+ s=chr(self.GetCharAt(cpos))
1895
+ self.UpdateUndoHistoryBefore('delete',s,cpos,cpos+1)
1896
+ if self.ForwardDeleteWMarkers():
1897
+ event.Skip()
1898
+
1899
+ wx.CallAfter(self.RestoreFirstMarker)
1900
+
1901
+ # Only allow these keys after the latest prompt.
1902
+ elif key == wx.WXK_TAB and self.CanEdit():
1903
+ # use the same mechanism as with autocmplete...
1904
+ cpos=self.GetCurrentPos()
1905
+ self.UpdateUndoHistoryBefore('insert','dummy',cpos,cpos+5,
1906
+ forceNewAction=True)
1907
+ self.undoHistory[self.undoIndex]['allowsAppend'] = True
1908
+ self.TotalLengthForAutoCompActiveCallback=self.GetTextLength()
1909
+ event.Skip()
1910
+ wx.CallAfter(self.AutoCompActiveCallback)
1911
+
1912
+ # Don't toggle between insert mode and overwrite mode.
1913
+ elif key == wx.WXK_INSERT:
1914
+ pass
1915
+
1916
+ # Don't allow line deletion.
1917
+ #elif controlDown and key in (ord('L'), ord('l')):
1918
+ # TODO : Allow line deletion eventually ??
1919
+ #event.Skip()
1920
+ # pass
1921
+
1922
+ # Don't allow line transposition.
1923
+ # Toggle Shell Mode / Slices Mode
1924
+ elif controlDown and key in (ord('T'), ord('t')):
1925
+ self.ToggleShellMode()
1926
+
1927
+ #Open and Save now work when using CrustSlicesFrames
1928
+ elif controlDown and key in (ord('L'), ord('l')):
1929
+ #print('Load it')
1930
+ file = wx.FileSelector("Load File As New Slice")
1931
+ if file != u'':
1932
+ with open(file,'r') as fid:
1933
+ self.LoadPyFileAsSlice(fid)
1934
+
1935
+ elif controlDown and key in (ord('D'), ord('d')):
1936
+ #Disallow line duplication in favor of divide slices
1937
+ if self.MarkerGet(self.GetCurrentLine()) & INPUT_MASK:
1938
+ #ADD UNDO
1939
+ cpos=self.GetCurrentPos()
1940
+ start,end = map(self.PositionFromLine,
1941
+ self.GetGroupingSlice(self.LineFromPosition(cpos)))
1942
+ self.UpdateUndoHistoryBefore('marker','',start,end,
1943
+ forceNewAction=True)
1944
+ self.SplitSlice()
1945
+ # Turn off selecting
1946
+ self.SetSelection(cpos,cpos)
1947
+ self.ReplaceSelection('')
1948
+ self.UpdateUndoHistoryAfter()
1949
+
1950
+ elif controlDown and key in (ord('M'), ord('m')):
1951
+ #ADD UNDO
1952
+ if self.SliceSelection:
1953
+ cpos=self.GetCurrentPos()
1954
+ ioSel=self.GetIOSelection()
1955
+ if self.SliceSelection:
1956
+ start,end = map(self.PositionFromLine,ioSel)
1957
+ self.UpdateUndoHistoryBefore('marker','',start,end,
1958
+ forceNewAction=True)
1959
+ self.MergeAdjacentSlices()
1960
+ # Turn off selecting
1961
+ self.SetSelection(cpos,cpos)
1962
+ self.ReplaceSelection('')
1963
+ self.UpdateUndoHistoryAfter()
1964
+
1965
+
1966
+ # Change arrow keys to allow margin behaviors...
1967
+ elif self.SliceSelection and \
1968
+ key in [wx.WXK_UP,wx.WXK_DOWN,wx.WXK_RIGHT,wx.WXK_LEFT]:
1969
+ # TODO : This is useful, but not optimal!
1970
+ if key==wx.WXK_UP:
1971
+ for i in range(self.GetLineCount()):
1972
+ if self.MarkerGet(i) & 1<<GROUPING_SELECTING:
1973
+ if i>0: #Grouping
1974
+ self.DoMarginClick(i-1, 2, shiftDown, controlDown)
1975
+ break
1976
+ elif self.MarkerGet(i) & 1<<IO_SELECTING:
1977
+ if i>0: #IO
1978
+ self.DoMarginClick(i-1, 3, shiftDown, controlDown)
1979
+ break
1980
+ elif key==wx.WXK_DOWN:
1981
+ for i in range(self.GetLineCount()-1,-1,-1):
1982
+ if self.MarkerGet(i) & 1<<GROUPING_SELECTING:
1983
+ if i<self.GetLineCount()-1: #Grouping
1984
+ self.DoMarginClick(i+1, 2, shiftDown, controlDown)
1985
+ break
1986
+ elif self.MarkerGet(i) & 1<<IO_SELECTING:
1987
+ if i<self.GetLineCount()-1: #IO
1988
+ self.DoMarginClick(i+1, 3, shiftDown, controlDown)
1989
+ break
1990
+ elif key==wx.WXK_RIGHT:
1991
+ for i in range(self.GetLineCount()):
1992
+ if self.MarkerGet(i) & 1<<GROUPING_SELECTING:
1993
+ self.DoMarginClick(i, 3, shiftDown, controlDown)
1994
+ break
1995
+ elif self.MarkerGet(i) & 1<<IO_SELECTING:
1996
+ self.MarginUnselectAll()
1997
+ # Go to the beginning of the IO Slice
1998
+ self.SetCurrentPos(self.PositionFromLine(i))
1999
+ if not selecting and not shiftDown:
2000
+ self.SetAnchor(self.PositionFromLine(i))
2001
+ self.EnsureCaretVisible()
2002
+ break
2003
+ elif key==wx.WXK_LEFT:
2004
+ for i in range(self.GetLineCount()):
2005
+ if self.MarkerGet(i) & 1<<GROUPING_SELECTING:
2006
+ break
2007
+ elif self.MarkerGet(i) & 1<<IO_SELECTING:
2008
+ self.DoMarginClick(i, 2, shiftDown, controlDown)
2009
+ break
2010
+ # Basic navigation keys should work anywhere.
2011
+ elif key in NAVKEYS:
2012
+ event.Skip()
2013
+ # Protect the readonly portion of the slices shell.
2014
+ elif not self.CanEdit():
2015
+ pass
2016
+ else:
2017
+ # Check to see if we're selecting
2018
+ if self.GetSelectionEnd()>self.GetSelectionStart():
2019
+ # Check to see if a normal input took place
2020
+ if not controlDown and not altDown and key<256:
2021
+ self.ReplaceSelection('') # This seems to work...
2022
+ event.Skip()
2023
+
2024
+ if self.SliceSelection:
2025
+ if key not in [wx.WXK_UP,wx.WXK_DOWN,wx.WXK_RIGHT,wx.WXK_LEFT,
2026
+ wx.WXK_ALT,wx.WXK_COMMAND,wx.WXK_CONTROL,wx.WXK_SHIFT]:
2027
+ self.MarginUnselectAll()
2028
+
2029
+
2030
+ def MarginSelectAll(self):
2031
+ num_lines=self.GetLineCount()
2032
+ for i in range(num_lines):
2033
+ self.MarkerAdd(i,GROUPING_SELECTING)
2034
+ self.MarkerDelete(i,IO_SELECTING)
2035
+
2036
+ def MarginUnselectAll(self):
2037
+ num_lines=self.GetLineCount()
2038
+ for i in range(num_lines):
2039
+ self.MarkerDelete(i,IO_SELECTING)
2040
+ self.MarkerDelete(i,GROUPING_SELECTING)
2041
+ self.SliceSelection=False
2042
+
2043
+ def DoMarginClick(self, lineClicked, margin, shiftDown, controlDown):
2044
+ num_lines=self.GetLineCount()
2045
+
2046
+ if margin==1:
2047
+ pass # these events are not sent right now...
2048
+ if margin==2:
2049
+ self.SliceSelection=True
2050
+ start,end=self.GetGroupingSlice(lineClicked)
2051
+ startPos=self.PositionFromLine(start)
2052
+ self.SetCurrentPos(startPos)
2053
+ self.SetSelection(startPos,startPos)
2054
+ start_marker=self.MarkerGet(start)
2055
+ if self.MarkerGet(lineClicked) & 1<<GROUPING_SELECTING:
2056
+ toggle=self.MarkerDelete
2057
+ if not shiftDown:
2058
+ if start_marker & 1<<GROUPING_START:
2059
+ self.FoldGroupingSlice(lineClicked)
2060
+ elif start_marker & 1<<GROUPING_START_FOLDED:
2061
+ self.UnFoldGroupingSlice(lineClicked)
2062
+ else:
2063
+ toggle=self.MarkerAdd
2064
+
2065
+ if not shiftDown:
2066
+ self.MarginUnselectAll()
2067
+
2068
+ for i in range(start,end+1):
2069
+ toggle(i,GROUPING_SELECTING)
2070
+ elif margin==3:
2071
+ self.SliceSelection=True
2072
+ start,end=self.GetIOSlice(lineClicked)
2073
+ startPos=self.PositionFromLine(start)
2074
+ self.SetCurrentPos(startPos)
2075
+ self.SetSelection(startPos,startPos)
2076
+ start_marker=self.MarkerGet(start)
2077
+ if self.MarkerGet(lineClicked) & 1<<IO_SELECTING:
2078
+ toggle=self.MarkerDelete
2079
+ if not shiftDown:
2080
+ if start_marker & IO_START_MASK:
2081
+ self.FoldIOSlice(lineClicked)
2082
+ elif start_marker & IO_START_FOLDED_MASK:
2083
+ self.UnFoldIOSlice(lineClicked)
2084
+ else:
2085
+ toggle=self.MarkerAdd
2086
+
2087
+ if not shiftDown:
2088
+ self.MarginUnselectAll()
2089
+
2090
+ for i in range(start,end+1):
2091
+ toggle(i,IO_SELECTING)
2092
+
2093
+ #print(start, end)
2094
+
2095
+ elif margin==4:
2096
+ # TODO : Folding ??
2097
+ if 1:#self.MarkerGet(lineClicked) & ( 1<<7 | 1<<8 ):
2098
+ if shiftDown:
2099
+ self.SetFoldExpanded(lineClicked, True)
2100
+ self.Expand(lineClicked, True, True, 1)
2101
+ elif controlDown:
2102
+ if self.GetFoldExpanded(lineClicked):
2103
+ self.SetFoldExpanded(lineClicked, False)
2104
+ self.Expand(lineClicked, False, True, 0)
2105
+ else:
2106
+ self.SetFoldExpanded(lineClicked, True)
2107
+ self.Expand(lineClicked, True, True, 100)
2108
+ else:
2109
+ self.ToggleFold(lineClicked)
2110
+ else:
2111
+ self.MarginUnselectAll()
2112
+ if margin in [2,3]:
2113
+ if toggle==self.MarkerDelete and not shiftDown:
2114
+ self.SliceSelection=False
2115
+ else:
2116
+ self.SliceSelection=True
2117
+
2118
+ def OnMarginClick(self, evt):
2119
+
2120
+ # fold and unfold as neededNAVKEYS
2121
+ lineClicked = self.LineFromPosition(evt.GetPosition())
2122
+ self.DoMarginClick(lineClicked,evt.GetMargin(),evt.GetShift(),evt.GetControl())
2123
+ evt.Skip()
2124
+
2125
+ def OnShowCompHistory(self):
2126
+ """Show possible autocompletion Words from already typed words."""
2127
+
2128
+ #copy from history
2129
+ his = self.history[:]
2130
+
2131
+ #put together in one string
2132
+ joined = " ".join (his)
2133
+ import re
2134
+
2135
+ #sort out only "good" words
2136
+ newlist = re.split(r"[ \.\[\]=}(\)\,0-9\"]", joined)
2137
+
2138
+ #length > 1 (mix out "trash")
2139
+ thlist = []
2140
+ for i in newlist:
2141
+ if len (i) > 1:
2142
+ thlist.append (i)
2143
+
2144
+ #unique (no duplicate words
2145
+ #oneliner from german python forum => unique list
2146
+ unlist = [thlist[i] for i in xrange(len(thlist)) if thlist[i] not in thlist[:i]]
2147
+
2148
+ #sort lowercase
2149
+ unlist.sort(key=cmp_to_key(lambda a, b: cmp(a.lower(), b.lower())))
2150
+
2151
+ #this is more convenient, isn't it?
2152
+ self.AutoCompSetIgnoreCase(True)
2153
+
2154
+ #join again together in a string
2155
+ stringlist = " ".join(unlist)
2156
+
2157
+ #pos von 0 noch ausrechnen
2158
+
2159
+ #how big is the offset?
2160
+ cpos = self.GetCurrentPos() - 1
2161
+ while chr (self.GetCharAt (cpos)).isalnum():
2162
+ cpos -= 1
2163
+
2164
+ #the most important part
2165
+ self.AutoCompShow(self.GetCurrentPos() - cpos -1, stringlist)
2166
+
2167
+ def ReplaceSelection(self,text,sliceDeletion=False,*args,**kwds):
2168
+ startIO,endIO=self.GetIOSlice()
2169
+ startGrouping,endGrouping=self.GetGroupingSlice()
2170
+ startSel = self.LineFromPosition(self.GetSelectionStart())
2171
+ endSel = self.LineFromPosition(self.GetSelectionEnd())
2172
+
2173
+ #ADD UNDO
2174
+ cpos=self.GetSelectionStart()
2175
+ s=self.GetSelectedText()
2176
+ if s!='':
2177
+ self.UpdateUndoHistoryBefore('delete',s,cpos,cpos+len(s),
2178
+ forceNewAction=True)
2179
+ editwindow.EditWindow.ReplaceSelection(self,'',*args,**kwds)
2180
+ if s!='' and not sliceDeletion:
2181
+ self.UpdateUndoHistoryAfter()
2182
+
2183
+ if endSel-startSel>0 and not sliceDeletion:
2184
+ if endSel==endIO and startIO!=self.GetCurrentLine():
2185
+ self.clearIOMarkers()
2186
+ self.MarkerAdd(self.GetCurrentLine(),INPUT_END)
2187
+
2188
+ if endSel==endGrouping and startGrouping!=self.GetCurrentLine():
2189
+ self.clearGroupingMarkers()
2190
+ self.MarkerAdd(self.GetCurrentLine(),GROUPING_END)
2191
+
2192
+ cpos=self.GetSelectionStart()
2193
+ s=text
2194
+ if s!='':
2195
+ self.UpdateUndoHistoryBefore('insert',s,cpos,cpos+len(s),
2196
+ forceNewAction=True)
2197
+ self.write(text)
2198
+ self.UpdateUndoHistoryAfter()
2199
+
2200
+ self.ensureSingleGroupingMarker()
2201
+ self.ensureSingleIOMarker()
2202
+
2203
+
2204
+ def clearCommand(self):
2205
+ """Delete the current, unexecuted command."""
2206
+ if not self.CanEdit():
2207
+ return
2208
+ start,end=self.GetIOSlice()
2209
+ startpos = self.PositionFromLine(start)
2210
+ endpos = self.GetLineEndPosition(end)
2211
+ self.SetSelection(startpos, endpos)
2212
+ self.ReplaceSelection('')
2213
+ self.more = False
2214
+
2215
+ def OnHistoryReplace(self, step):
2216
+ """Replace with the previous/next command from the history buffer."""
2217
+ if not self.CanEdit():
2218
+ return
2219
+ self.clearCommand()
2220
+ self.replaceFromHistory(step)
2221
+
2222
+ def replaceFromHistory(self, step):
2223
+ """Replace selection with command from the history buffer."""
2224
+ if not self.CanEdit():
2225
+ return
2226
+ self.ReplaceSelection('')
2227
+ newindex = self.historyIndex + step
2228
+ if -1 <= newindex <= len(self.history):
2229
+ self.historyIndex = newindex
2230
+ if 0 <= newindex <= len(self.history)-1:
2231
+ command = self.history[self.historyIndex]
2232
+ command = command.replace('\n', os.linesep)# + ps2)
2233
+ self.ReplaceSelection(command)
2234
+
2235
+ def OnHistoryInsert(self, step):
2236
+ """Insert the previous/next command from the history buffer."""
2237
+ if not self.CanEdit():
2238
+ return
2239
+ startpos = self.GetCurrentPos()
2240
+ self.replaceFromHistory(step)
2241
+ endpos = self.GetCurrentPos()
2242
+ self.SetSelection(endpos, startpos)
2243
+
2244
+ # TODO: Fix Me!
2245
+ def OnHistorySearch(self):
2246
+ """Search up the history buffer for the text in front of the cursor."""
2247
+ if not self.CanEdit():
2248
+ return
2249
+ startpos = self.GetCurrentPos()
2250
+ # The text up to the cursor is what we search for.
2251
+ numCharsAfterCursor = self.GetTextLength() - startpos
2252
+ searchText = self.getCommand(rstrip=False)
2253
+ #print('history search', startpos, numCharsAfterCursor, searchText)
2254
+ if numCharsAfterCursor > 0:
2255
+ searchText = searchText[:-numCharsAfterCursor]
2256
+ if not searchText:
2257
+ return
2258
+ # Search upwards from the current history position and loop
2259
+ # back to the beginning if we don't find anything.
2260
+ if (self.historyIndex <= -1) \
2261
+ or (self.historyIndex >= len(self.history)-2):
2262
+ searchOrder = range(len(self.history))
2263
+ else:
2264
+ ls = list(range(len(self.history)))
2265
+ searchOrder = ls[self.historyIndex+1:] + ls[:self.historyIndex]
2266
+ for i in searchOrder:
2267
+ command = self.history[i]
2268
+ if command[:len(searchText)] == searchText:
2269
+ # Replace the current selection with the one we found.
2270
+ self.ReplaceSelection(command[len(searchText):])
2271
+ endpos = self.GetCurrentPos()
2272
+ self.SetSelection(endpos, startpos)
2273
+ # We've now warped into middle of the history.
2274
+ self.historyIndex = i
2275
+ break
2276
+
2277
+ def setStatusText(self, text):
2278
+ """Display status information."""
2279
+
2280
+ # This method will likely be replaced by the enclosing app to
2281
+ # do something more interesting, like write to a status bar.
2282
+ print(text)
2283
+
2284
+ def insertLineBreak(self):
2285
+ """Insert a new line break."""
2286
+ if not self.CanEdit():
2287
+ return
2288
+ elif self.reader.isreading:
2289
+ self.processLine()
2290
+ return
2291
+
2292
+
2293
+ # write with undo wrapper...
2294
+ cpos=self.GetCurrentPos()
2295
+ s=os.linesep
2296
+ self.UpdateUndoHistoryBefore('insert',s,cpos,cpos+1)
2297
+ self.write(s,type='Input')
2298
+ self.UpdateUndoHistoryAfter()
2299
+
2300
+ self.more = True
2301
+ self.prompt()
2302
+
2303
+ def processLine(self):
2304
+ """Process the line of text at which the user hit Enter or Shift+RETURN."""
2305
+ # The user hit ENTER (Shift+RETURN) (Shift+ENTER) and we need to
2306
+ # decide what to do. They could be sitting on any line in the slices shell.
2307
+ thepos = self.GetCurrentPos()
2308
+ cur_line = self.GetCurrentLine()
2309
+ marker=self.MarkerGet(cur_line)
2310
+ if marker & INPUT_MASK:
2311
+ pass
2312
+ elif marker & OUTPUT_MASK:
2313
+ return
2314
+ else:
2315
+ pass #print('BLANK LINE!!')
2316
+
2317
+ startline,endline=self.GetIOSlice(cur_line)
2318
+
2319
+ if startline==0:
2320
+ startpos=0
2321
+ else:
2322
+ startpos=self.PositionFromLine(startline)
2323
+
2324
+ endpos=self.GetLineEndPosition(endline)
2325
+
2326
+ # If they hit ENTER inside the current command, execute the command.
2327
+ if self.CanEdit():
2328
+ self.SetCurrentPos(endpos)
2329
+ self.interp.more = False
2330
+ command = self.GetTextRange(startpos, endpos)
2331
+ lines = command.split(os.linesep)
2332
+ lines = [line.rstrip() for line in lines]
2333
+ command = '\n'.join(lines)
2334
+ if self.reader.isreading:
2335
+ if not command:
2336
+ # Match the behavior of the standard Python shell
2337
+ # when the user hits return without entering a value.
2338
+ command = '\n'
2339
+ self.reader.input = command
2340
+ self.write(os.linesep,'Input')
2341
+ self.MarkerSet(self.GetCurrentLine(),READLINE_BG)
2342
+ self.MarkerSet(self.GetCurrentLine(),INPUT_READLINE)
2343
+ else:
2344
+ self.runningSlice = (startline,endline)
2345
+ self.push(command,useMultiCommand=True)
2346
+ #print('command: %s'%command)
2347
+ wx.CallLater(1, self.EnsureCaretVisible)
2348
+ self.runningSlice=None
2349
+
2350
+ skip=self.BackspaceWMarkers(force=True)
2351
+ if skip:
2352
+ self.DeleteBack()
2353
+
2354
+ if self.GetCurrentLine()==self.GetLineCount()-1:
2355
+ self.write(os.linesep,type='Input')
2356
+ cpos=self.GetCurrentLine()
2357
+ if self.MarkerGet(cpos-1) & OUTPUT_MASK:
2358
+ self.MarkerAdd(cpos-1,OUTPUT_BG)
2359
+ self.SplitSlice()
2360
+ else:
2361
+ cur_line=self.GetCurrentLine()
2362
+ new_pos=self.GetLineEndPosition(cur_line+1)
2363
+ self.SetSelection(new_pos,new_pos)
2364
+ self.SetCurrentPos(new_pos)
2365
+
2366
+ self.EmptyUndoBuffer()
2367
+ self.NeedsCheckForSave=True
2368
+ if self.hasSyntaxError:
2369
+ pos=self.GetLineEndPosition(self.syntaxErrorRealLine)
2370
+ self.SetCurrentPos(pos)
2371
+ self.SetSelection(pos,pos)
2372
+
2373
+ # Not Used!!
2374
+ def getMultilineCommand(self, rstrip=True):
2375
+ """Extract a multi-line command from the editor.
2376
+
2377
+ The command may not necessarily be valid Python syntax."""
2378
+ # DNM
2379
+ # XXX Need to extract real prompts here. Need to keep track of
2380
+ # the prompt every time a command is issued.
2381
+ text = self.GetCurLine()[0]
2382
+ line = self.GetCurrentLine()
2383
+ # Add Marker testing here...
2384
+ while text == '' and line > 0: # Need to add markers handling...
2385
+ line -= 1
2386
+ self.GotoLine(line)
2387
+ text = self.GetCurLine()[0]
2388
+ if text=='':
2389
+ line = self.GetCurrentLine()
2390
+ self.GotoLine(line)
2391
+ startpos = self.GetCurrentPos()
2392
+ line += 1
2393
+ self.GotoLine(line)
2394
+ while self.GetCurLine()[0]=='':
2395
+ line += 1
2396
+ self.GotoLine(line)
2397
+ stoppos = self.GetCurrentPos()
2398
+ command = self.GetTextRange(startpos, stoppos)
2399
+ command = command.replace(os.linesep, '\n')
2400
+ command = command.rstrip()
2401
+ command = command.replace('\n', os.linesep)
2402
+ else:
2403
+ command = ''
2404
+ if rstrip:
2405
+ command = command.rstrip()
2406
+ return command
2407
+
2408
+ def getCommand(self, text=None, rstrip=True):
2409
+ """Extract a command from text which may include a shell prompt.
2410
+
2411
+ The command may not necessarily be valid Python syntax."""
2412
+ if not text:
2413
+ text = self.GetCurLine()[0]
2414
+ # Strip the prompt off the front leaving just the command.
2415
+ command = self.lstripPrompt(text)
2416
+ # Change this -- Nothing has prompts!
2417
+ #if command == text:
2418
+ # command = '' # Real commands have prompts.
2419
+ if rstrip:
2420
+ command = command.rstrip()
2421
+ return command
2422
+
2423
+ def lstripPrompt(self, text):
2424
+ """Return text without a leading prompt."""
2425
+ ps1 = str(sys.ps1)
2426
+ ps1size = len(ps1)
2427
+ ps2 = str(sys.ps2)
2428
+ ps2size = len(ps2)
2429
+ # Strip the prompt off the front of text.
2430
+ if text[:ps1size] == ps1:
2431
+ text = text[ps1size:]
2432
+ elif text[:ps2size] == ps2:
2433
+ text = text[ps2size:]
2434
+ return text
2435
+
2436
+ def push(self, command, silent = False,useMultiCommand=False):
2437
+ """Send command to the interpreter for execution."""
2438
+ if not silent:
2439
+ self.write(os.linesep,type='Output')
2440
+ # TODO : What other magic might we insert here?
2441
+ # TODO : Is there a good reason not to include magic?
2442
+ if USE_MAGIC:
2443
+ command=magic(command)
2444
+
2445
+ # Allows multi-component commands...
2446
+ self.hasSyntaxError=False
2447
+ if useMultiCommand:
2448
+ result = self.BreakTextIntoCommands(command)
2449
+ if result[0] is None:
2450
+ commands=[command]
2451
+ self.hasSyntaxError=True
2452
+ syntaxErrorLine=result[1]+1
2453
+ self.syntaxErrorRealLine = self.GetCurrentLine()+result[1]-len(command.split('\n'))
2454
+ else:
2455
+ commands=result
2456
+ else:
2457
+ commands=[command]
2458
+
2459
+ busy = wx.BusyCursor()
2460
+ self.waiting = True
2461
+ self.lastUpdate=None
2462
+
2463
+ for i in commands:
2464
+ if self.hasSyntaxError:
2465
+ lineno=syntaxErrorLine
2466
+ offset=0 # not sure how to easily recover this information...
2467
+ self.write(' File "<input>", line '+str(lineno)+'\n '+i.split('\n')[lineno-1]+'\n'+' '*offset+' ^\nSyntaxError: invalid syntax\n','Error')
2468
+ else:
2469
+ self.more = self.interp.push(i+'\n')
2470
+ # (the \n stops many things from bouncing at the interpreter)
2471
+ # I could do the following, but I don't really like it!
2472
+ #if useMultiCommand:
2473
+ # self.SplitSlice()
2474
+ self.lastUpdate=None
2475
+
2476
+ if not silent:
2477
+ self.MarkerAdd(self.GetIOSlice()[0],OUTPUT_BG)
2478
+
2479
+ self.waiting = False
2480
+ del busy
2481
+ if not self.more: # could loop-add to history, too, but I don't like it!
2482
+ self.addHistory(command.rstrip())
2483
+
2484
+ if not silent:
2485
+ self.prompt()
2486
+
2487
+ def addHistory(self, command):
2488
+ """Add command to the command history."""
2489
+ # Reset the history position.
2490
+ self.historyIndex = -1
2491
+ # Insert this command into the history, unless it's a blank
2492
+ # line or the same as the last command.
2493
+ if command!='' and ( len(self.history)==0 or command!=self.history[0] ):
2494
+ self.history.insert(0, command)
2495
+ dispatcher.send(signal="SlicesShell.addHistory", command=command)
2496
+
2497
+ def clearGroupingMarkers(self,line_num=None):
2498
+ if line_num==None:
2499
+ line_num=self.GetCurrentLine()
2500
+ self.MarkerDelete(line_num,GROUPING_START)
2501
+ self.MarkerDelete(line_num,GROUPING_START_FOLDED)
2502
+ self.MarkerDelete(line_num,GROUPING_MIDDLE)
2503
+ self.MarkerDelete(line_num,GROUPING_END)
2504
+ def clearIOMarkers(self,line_num=None):
2505
+ if line_num==None:
2506
+ line_num=self.GetCurrentLine()
2507
+ self.MarkerDelete(line_num,INPUT_START)
2508
+ self.MarkerDelete(line_num,INPUT_START_FOLDED)
2509
+ self.MarkerDelete(line_num,INPUT_MIDDLE)
2510
+ self.MarkerDelete(line_num,INPUT_END)
2511
+ self.MarkerDelete(line_num,OUTPUT_START)
2512
+ self.MarkerDelete(line_num,OUTPUT_START_FOLDED)
2513
+ self.MarkerDelete(line_num,OUTPUT_MIDDLE)
2514
+ self.MarkerDelete(line_num,OUTPUT_END)
2515
+ self.MarkerDelete(line_num,OUTPUT_BG)
2516
+ self.MarkerDelete(line_num,READLINE_BG)
2517
+ self.MarkerDelete(line_num,INPUT_READLINE)
2518
+ def ensureSingleGroupingMarker(self,line_num=None):
2519
+ if line_num==None:
2520
+ line_num=self.GetCurrentLine()
2521
+ marker=self.MarkerGet(line_num)
2522
+ if marker & 1<<GROUPING_START:
2523
+ self.MarkerDelete(line_num,GROUPING_START_FOLDED)
2524
+ self.MarkerDelete(line_num,GROUPING_MIDDLE)
2525
+ self.MarkerDelete(line_num,GROUPING_END)
2526
+ elif marker & 1<<GROUPING_START_FOLDED:
2527
+ self.MarkerDelete(line_num,GROUPING_MIDDLE)
2528
+ self.MarkerDelete(line_num,GROUPING_END)
2529
+ elif marker & 1<<GROUPING_MIDDLE:
2530
+ self.MarkerDelete(line_num,GROUPING_END)
2531
+ elif marker & 1<<GROUPING_END:
2532
+ pass
2533
+ else:
2534
+ #print('ERROR! NO GROUPING MARKERS!')
2535
+ return 1 # Blank marker
2536
+
2537
+ return 0
2538
+
2539
+ def ensureSingleIOMarker(self,line_num=None):
2540
+ if line_num==None:
2541
+ line_num=self.GetCurrentLine()
2542
+ marker=self.MarkerGet(line_num)
2543
+ if marker & INPUT_MASK:
2544
+ self.MarkerDelete(line_num,OUTPUT_START)
2545
+ self.MarkerDelete(line_num,OUTPUT_START_FOLDED)
2546
+ self.MarkerDelete(line_num,OUTPUT_MIDDLE)
2547
+ self.MarkerDelete(line_num,OUTPUT_END)
2548
+ self.MarkerDelete(line_num,OUTPUT_BG)
2549
+ [start,start_folded] = [INPUT_START,INPUT_START_FOLDED]
2550
+ [middle,end] = [INPUT_MIDDLE,INPUT_END]
2551
+ elif marker & OUTPUT_MASK:
2552
+ self.MarkerDelete(line_num,INPUT_START)
2553
+ self.MarkerDelete(line_num,INPUT_START_FOLDED)
2554
+ self.MarkerDelete(line_num,INPUT_MIDDLE)
2555
+ self.MarkerDelete(line_num,INPUT_END)
2556
+ [start,start_folded] = [OUTPUT_START,OUTPUT_START_FOLDED]
2557
+ [middle,end] = [OUTPUT_MIDDLE,OUTPUT_END]
2558
+ else:
2559
+ #print('ERROR! NO IO MARKERS!')
2560
+ return 1 # Blank marker
2561
+
2562
+ if marker & 1<<start:
2563
+ self.MarkerDelete(line_num,start_folded)
2564
+ self.MarkerDelete(line_num,middle)
2565
+ self.MarkerDelete(line_num,end)
2566
+ elif marker & 1<<start_folded:
2567
+ self.MarkerDelete(line_num,middle)
2568
+ self.MarkerDelete(line_num,end)
2569
+ elif marker & 1<<middle:
2570
+ self.MarkerDelete(line_num,end)
2571
+ elif marker & 1<<end:
2572
+ pass
2573
+
2574
+ return 0
2575
+
2576
+ def RestoreFirstMarker(self):
2577
+ first_marker=self.MarkerGet(0)
2578
+ self.clearGroupingMarkers(0)
2579
+ self.clearIOMarkers(0)
2580
+
2581
+ if first_marker & 1<<GROUPING_START :
2582
+ self.MarkerAdd(0,GROUPING_START)
2583
+ elif first_marker & 1<<GROUPING_START_FOLDED :
2584
+ self.MarkerAdd(0,GROUPING_START_FOLDED)
2585
+ else:
2586
+ self.MarkerAdd(0,GROUPING_START)
2587
+
2588
+ if first_marker & 1<<INPUT_START :
2589
+ self.MarkerAdd(0,INPUT_START)
2590
+ elif first_marker & 1<<INPUT_START_FOLDED :
2591
+ self.MarkerAdd(0,INPUT_START_FOLDED)
2592
+ elif first_marker & 1<<OUTPUT_START :
2593
+ self.MarkerAdd(0,OUTPUT_START)
2594
+ #self.MarkerAdd(0,OUTPUT_BG) # More harm than good??
2595
+ elif first_marker & 1<<OUTPUT_START_FOLDED :
2596
+ self.MarkerAdd(0,OUTPUT_START_FOLDED)
2597
+ #self.MarkerAdd(0,OUTPUT_BG) # More harm than good??
2598
+ else:
2599
+ self.MarkerAdd(0,INPUT_START)
2600
+
2601
+ if self.doHistUpdate:
2602
+ self.UpdateUndoHistoryAfter()
2603
+
2604
+ def IsAllowedPair(self,m1,m2):
2605
+ """This testing function ensures that two adjacent markers are valid"""
2606
+ i_s = 1<<INPUT_START | 1<<INPUT_START_FOLDED
2607
+ o_s = 1<<OUTPUT_START | 1<<OUTPUT_START_FOLDED
2608
+ g_s = 1<<GROUPING_START | 1<<GROUPING_START_FOLDED
2609
+ i_m,o_m,g_m = 1<<INPUT_MIDDLE, 1<<OUTPUT_MIDDLE, 1<<GROUPING_MIDDLE
2610
+ i_e,o_e,g_e = 1<<INPUT_END, 1<<OUTPUT_END, 1<<GROUPING_END
2611
+
2612
+ if (m1 & i_s) and (m1 & g_s): #1
2613
+ if (m2 & i_s) and (m2 & g_s): return True #1
2614
+ elif (m2 & i_m) and (m2 & g_m): return True #2
2615
+ elif (m2 & i_e) and (m2 & g_m): return True #3
2616
+ elif (m2 & i_e) and (m2 & g_e): return True #4
2617
+ elif (m2 & o_s) and (m2 & g_s): return False #5
2618
+ elif (m2 & o_s) and (m2 & g_m): return True #6
2619
+ elif (m2 & o_s) and (m2 & g_e): return True #7
2620
+ elif (m2 & o_m) and (m2 & g_m): return False #8
2621
+ elif (m2 & o_e) and (m2 & g_e): return False #9
2622
+ else: return False
2623
+ elif (m1 & i_m) and (m1 & g_m): #2
2624
+ if (m2 & i_m) and (m2 & g_m): return True #2
2625
+ elif (m2 & i_e) and (m2 & g_m): return True #3
2626
+ elif (m2 & i_e) and (m2 & g_e): return True #4
2627
+ else: return False
2628
+ elif (m1 & i_e) and (m1 & g_m): #3
2629
+ if (m2 & o_s) and (m2 & g_m): return True #6
2630
+ elif (m2 & o_s) and (m2 & g_e): return True #7
2631
+ else: return False
2632
+ elif (m1 & i_e) and (m1 & g_e): #4
2633
+ if (m2 & i_s) and (m2 & g_s): return True #1
2634
+ elif (m2 & o_s) and (m2 & g_s): return True #5
2635
+ else: return False
2636
+ elif (m1 & o_s) and (m1 & g_s): #5
2637
+ if (m2 & i_s) and (m2 & g_s): return True #1
2638
+ elif (m2 & i_m) and (m2 & g_m): return False #2
2639
+ elif (m2 & i_e) and (m2 & g_m): return False #3
2640
+ elif (m2 & i_e) and (m2 & g_e): return False #4
2641
+ elif (m2 & o_s) and (m2 & g_s): return True #5
2642
+ elif (m2 & o_s) and (m2 & g_m): return False #6
2643
+ elif (m2 & o_s) and (m2 & g_e): return False #7
2644
+ elif (m2 & o_m) and (m2 & g_m): return True #8
2645
+ elif (m2 & o_e) and (m2 & g_e): return True #9
2646
+ else: return False
2647
+ elif (m1 & o_s) and (m1 & g_m): #6
2648
+ if (m2 & o_m) and (m2 & g_m): return True #8
2649
+ elif (m2 & o_e) and (m2 & g_e): return True #9
2650
+ else: return False
2651
+ elif (m1 & o_s) and (m1 & g_e): #7
2652
+ if (m2 & i_s) and (m2 & g_s): return True #1
2653
+ elif (m2 & o_s) and (m2 & g_s): return True #5
2654
+ else: return False
2655
+ elif (m1 & o_m) and (m1 & g_m): #8
2656
+ if (m2 & o_m) and (m2 & g_m): return True #8
2657
+ elif (m2 & o_e) and (m2 & g_e): return True #9
2658
+ else: return False
2659
+ elif (m1 & o_e) and (m1 & g_e): #9
2660
+ if (m2 & i_s) and (m2 & g_s): return True #1
2661
+ elif (m2 & o_s) and (m2 & g_s): return True #5
2662
+ else: return False
2663
+ else:
2664
+ return False
2665
+
2666
+
2667
+ def CleanAllMarkers(self):
2668
+ self.RestoreFirstMarker()
2669
+ first_marker=self.MarkerGet(0)
2670
+ last_line_num=self.GetLineCount()-1
2671
+
2672
+ for i in range(1,last_line_num):
2673
+ self.ensureSingleGroupingMarker(i)
2674
+ self.ensureSingleIOMarker(i)
2675
+
2676
+ previous_marker=self.MarkerGet(i-1)
2677
+ marker=self.MarkerGet(i)
2678
+
2679
+ if not self.IsAllowedPair(previous_marker,marker):
2680
+ pass # FIX MARKER!!
2681
+ # FIX ME
2682
+
2683
+ def write(self, text,type='Input',silent=False):
2684
+ """Display text in the slices shell.
2685
+
2686
+ Replace line endings with OS-specific endings."""
2687
+ text = self.fixLineEndings(text)
2688
+ split=text.split(os.linesep)
2689
+ self.AddText(text)
2690
+
2691
+ # This part handles all the marker stuff that accompanies
2692
+ # adding or removing new lines of text...
2693
+ # Get the total number of lines in the Document == last line number
2694
+ last_line_num=self.GetLineCount()-1
2695
+ # Get the line number we ended on in the write
2696
+ end_line_num=self.GetCurrentLine()
2697
+ # Get the number of returns we are using == number of lines we pasted -1
2698
+ num_new_lines=text.count(os.linesep)
2699
+ # So if num_new_lines==0, start_line_num and end_line_num are the same
2700
+ start_line_num=end_line_num-num_new_lines+1
2701
+
2702
+ # This is a little unnecessary because there will always
2703
+ # be a line before if we just inserted a newline!
2704
+ if start_line_num == 0:
2705
+ previous_line_num=None
2706
+ else:
2707
+ previous_line_num=start_line_num-1
2708
+
2709
+ #However, this is very important...
2710
+ if end_line_num == last_line_num:
2711
+ next_line_num=None
2712
+ else:
2713
+ next_line_num=end_line_num+1
2714
+
2715
+ if type=='Input':
2716
+ start = INPUT_START
2717
+ start_folded = INPUT_START_FOLDED
2718
+ middle = INPUT_MIDDLE
2719
+ end = INPUT_END
2720
+ # preparation for more io types...
2721
+ opposite_start_mask = 1<<OUTPUT_START
2722
+ opposite_start_folded_mask = 1<<OUTPUT_START_FOLDED
2723
+ opposite_middle_mask = 1<<OUTPUT_MIDDLE # To test for bad writes...
2724
+ opposite_end_mask = 1<<OUTPUT_END # To test for bad writes...
2725
+ elif type in ['Output','Error']:
2726
+ #self.MarkerAdd(start_line_num,GROUPING_START_FOLDED)
2727
+ start=OUTPUT_START
2728
+ start_folded=OUTPUT_START_FOLDED
2729
+ middle=OUTPUT_MIDDLE
2730
+ end=OUTPUT_END
2731
+ # preparation for more io types...
2732
+ opposite_start_mask = 1<<INPUT_START
2733
+ opposite_start_folded_mask = 1<<INPUT_START_FOLDED
2734
+ opposite_middle_mask = 1<<INPUT_MIDDLE # To test for bad writes...
2735
+ opposite_end_mask = 1<<INPUT_END # To test for bad writes...
2736
+
2737
+ if num_new_lines>0: #Do nothing if typing within a line...
2738
+ # Update the Grouping Markers
2739
+ # For the previous line and the start_line
2740
+ # Test to make sure we can write ... but not here ...
2741
+ # test this before we call write or before we add text...
2742
+ # So we assume it already obeys the rules
2743
+
2744
+ badMarkers=False
2745
+ fixIOEnd=True
2746
+
2747
+ if previous_line_num==None:
2748
+ # This is an impossible case, here just for completeness...
2749
+ self.clearGroupingMarkers(start_line_num)
2750
+ self.MarkerAdd(start_line_num,GROUPING_START)
2751
+
2752
+ self.clearIOMarkers(start_line_num)
2753
+ self.MarkerAdd(start_line_num,start)
2754
+ if type in ['Output','Error']: self.MarkerAdd(start_line_num,OUTPUT_BG)
2755
+ else:
2756
+ previous_marker=self.MarkerGet(previous_line_num)
2757
+ if previous_marker & opposite_middle_mask:
2758
+ badMarkers=True
2759
+
2760
+ if next_line_num==None:
2761
+ self.MarkerAdd(end_line_num,GROUPING_END)
2762
+ self.MarkerAdd(end_line_num,end)
2763
+ if type in ['Output','Error']: self.MarkerAdd(end_line_num,OUTPUT_BG)
2764
+ fixEndMarkers=False
2765
+ # May be overwritten below if start_line_num==end_line_num...
2766
+ else:
2767
+ next_marker=self.MarkerGet(next_line_num)
2768
+ fixEndMarkers=True
2769
+ if next_marker & ( opposite_middle_mask | opposite_end_mask ):
2770
+ badMarkers=True
2771
+
2772
+ if not badMarkers:
2773
+ # ensure previous_line only has one marker & turn end into middle
2774
+ if previous_line_num!=None:
2775
+ # Adjust previous line appropriately, ensure only one marker
2776
+ # Only print errors if we are on input!
2777
+ blank=False
2778
+ blank=blank or self.ensureSingleGroupingMarker(previous_line_num)
2779
+ blank=blank or self.ensureSingleIOMarker(previous_line_num)
2780
+
2781
+ if blank:
2782
+ #if type=='Input' and not silent: print('BLANK LINE!' # BAD CASE)
2783
+ pass
2784
+
2785
+ if previous_marker & 1<<GROUPING_END :
2786
+ # Make GROUPING slice continue unless we hit
2787
+ # an output end and are starting a new input...
2788
+ if (previous_marker & OUTPUT_MASK) and type=='Input':
2789
+ pass
2790
+ else:
2791
+ self.MarkerDelete(previous_line_num,GROUPING_END)
2792
+ # ONLY CHANGING CASE
2793
+ self.MarkerAdd(previous_line_num,GROUPING_MIDDLE)
2794
+
2795
+ if previous_marker & 1<<end :
2796
+ self.MarkerDelete(previous_line_num,end)
2797
+ self.MarkerAdd(previous_line_num,middle) # ONLY CHANGING CASE
2798
+ if type in ['Output','Error']: self.MarkerAdd(previous_line_num,OUTPUT_BG)
2799
+ elif previous_marker & opposite_middle_mask :
2800
+ # BAD CASE
2801
+ if type=='Input' and not silent:
2802
+ #print('Should have been a bad marker!')
2803
+ pass
2804
+
2805
+ # We can only add input to an input slice
2806
+ # And can only add output to an output slice
2807
+
2808
+ if previous_marker & ( opposite_start_mask |
2809
+ opposite_start_folded_mask |
2810
+ opposite_end_mask ):
2811
+ if type=='Input':
2812
+ self.clearGroupingMarkers(start_line_num)
2813
+ self.MarkerAdd(start_line_num,GROUPING_START)
2814
+ if start_line_num==end_line_num:
2815
+ fixEndMarkers=False
2816
+ else:
2817
+ if start_line_num==end_line_num:
2818
+ fixIOEnd=False
2819
+ self.clearIOMarkers(start_line_num)
2820
+ self.MarkerAdd(start_line_num,start)
2821
+ if type in ['Output','Error']: self.MarkerAdd(start_line_num,OUTPUT_BG)
2822
+ else:
2823
+ if next_line_num!=None:
2824
+ self.clearGroupingMarkers(start_line_num)
2825
+ self.clearIOMarkers(start_line_num)
2826
+ self.MarkerAdd(start_line_num,GROUPING_MIDDLE)
2827
+ self.MarkerAdd(start_line_num,middle)
2828
+ if type in ['Output','Error']: self.MarkerAdd(start_line_num,OUTPUT_BG)
2829
+ # This may be overwritten if start_line_num==end_line_num
2830
+
2831
+ # Take care of all the middle lines...
2832
+ # Does nothing for only one line...
2833
+ for i in range(start_line_num,end_line_num):
2834
+ self.clearGroupingMarkers(i)
2835
+ self.MarkerAdd(i,GROUPING_MIDDLE)
2836
+
2837
+ self.clearIOMarkers(i)
2838
+ self.MarkerAdd(i,middle)
2839
+ if type in ['Output','Error']: self.MarkerAdd(i,OUTPUT_BG)
2840
+
2841
+ if fixEndMarkers:
2842
+ # Take care of the end_line if we haven't already done so...
2843
+ blank=False
2844
+ blank=blank or self.ensureSingleGroupingMarker(next_line_num)
2845
+ blank=blank or self.ensureSingleIOMarker(next_line_num)
2846
+
2847
+ if blank:
2848
+ if type=='Input' and not silent:
2849
+ #print('BLANK LINE!' # BAD CASE)
2850
+ pass
2851
+
2852
+ self.clearGroupingMarkers(end_line_num)
2853
+ if fixIOEnd:
2854
+ self.clearIOMarkers(end_line_num)
2855
+
2856
+ if next_marker & ( 1<<GROUPING_START | 1<<GROUPING_START_FOLDED ) :
2857
+ self.MarkerAdd(end_line_num,GROUPING_END)
2858
+ elif next_marker & ( 1<<GROUPING_MIDDLE | 1<<GROUPING_END ) :
2859
+ self.MarkerAdd(end_line_num,GROUPING_MIDDLE)
2860
+
2861
+ if fixIOEnd:
2862
+ if next_marker & ( 1<<start | 1<<start_folded ) :
2863
+ self.MarkerAdd(end_line_num,end)
2864
+ if type in ['Output','Error']: self.MarkerAdd(end_line_num,OUTPUT_BG)
2865
+ elif next_marker & ( 1<<middle | 1<<end ) :
2866
+ self.MarkerAdd(end_line_num,middle)
2867
+ if type in ['Output','Error']: self.MarkerAdd(end_line_num,OUTPUT_BG)
2868
+ elif next_marker & ( opposite_start_mask |
2869
+ opposite_start_folded_mask ):
2870
+ self.MarkerAdd(end_line_num,end)
2871
+ if type in ['Output','Error']: self.MarkerAdd(end_line_num,OUTPUT_BG)
2872
+ else:
2873
+ self.MarkerAdd(end_line_num,start_folded)
2874
+ if type in ['Output','Error']: self.MarkerAdd(end_line_num,OUTPUT_BG)
2875
+ if type=='Input' and not silent:
2876
+ #print('BAD MARKERS!')
2877
+ pass
2878
+ else:
2879
+ if type=='Input' and not silent:
2880
+ #print('BAD MARKERS!!!')
2881
+ pass
2882
+
2883
+ self.EnsureCaretVisible()
2884
+
2885
+ if self.waiting:
2886
+ if self.lastUpdate==None:
2887
+ self.lastUpdate=time.time()
2888
+ if time.time()-self.lastUpdate > PRINT_UPDATE_MAX_TIME:
2889
+ self.Update()
2890
+ self.lastUpdate=time.time()
2891
+
2892
+ def fixLineEndings(self, text):
2893
+ """Return text with line endings replaced by OS-specific endings."""
2894
+ lines = text.split('\r\n')
2895
+ for l in range(len(lines)):
2896
+ chunks = lines[l].split('\r')
2897
+ for c in range(len(chunks)):
2898
+ chunks[c] = os.linesep.join(chunks[c].split('\n'))
2899
+ lines[l] = os.linesep.join(chunks)
2900
+ text = os.linesep.join(lines)
2901
+ return text
2902
+
2903
+ def prompt(self): # Autoindent added!!!
2904
+ """Display proper prompt for the context: ps1, ps2 or ps3.
2905
+
2906
+ If this is a continuation line, autoindent as necessary."""
2907
+ # TODO : How much of this can I do away with now without prompts??
2908
+
2909
+ isreading = self.reader.isreading
2910
+
2911
+ skip = True
2912
+ if isreading:
2913
+ prompt = str(sys.ps3)
2914
+ elif self.more:
2915
+ prompt = str(sys.ps2)
2916
+ else:
2917
+ prompt = str(sys.ps1)
2918
+ pos = self.GetCurLine()[1]
2919
+ if pos > 0:
2920
+ if isreading:
2921
+ skip = True
2922
+ else:
2923
+ self.write(os.linesep,type='Input')
2924
+ if not self.more:
2925
+ # Not needed anymore! # self.promptPosStart = self.GetCurrentPos()
2926
+ pass
2927
+ if not skip:
2928
+ self.write(prompt,type='Input')
2929
+ if not self.more:
2930
+ # Not needed anymore! # self.promptPosEnd = self.GetCurrentPos()
2931
+ # Clear the undo history after running a command.
2932
+ self.EmptyUndoBuffer()
2933
+
2934
+ #DNM/CP
2935
+ # Autoindent magic
2936
+ # Match the indent of the line above
2937
+ # UNLESS the line above ends in a colon...then add four spaces
2938
+ # (after valid keywords (if, else, etc...) only)
2939
+ if self.more:
2940
+ line_num=self.GetCurrentLine()
2941
+ currentLine=self.GetLine(line_num)
2942
+ previousLine=self.GetLine(line_num-1)
2943
+ pstrip=previousLine.strip()
2944
+ lstrip=previousLine.lstrip()
2945
+
2946
+ if pstrip == '':
2947
+ # because it is all whitespace!
2948
+ indent=previousLine.strip('\n').strip('\r')
2949
+ else:
2950
+ indent=previousLine[:(len(previousLine)-len(lstrip))]
2951
+ if testForContinuations(previousLine,ignoreErrors=True)[1][0]:
2952
+ indent+=' '*4
2953
+
2954
+ #ADD UNDO
2955
+ cpos=self.GetCurrentPos()
2956
+ s=indent
2957
+ self.UpdateUndoHistoryBefore('insert',s,cpos,cpos+len(s))
2958
+ self.write(s,type='Input')
2959
+ self.UpdateUndoHistoryAfter()
2960
+
2961
+
2962
+ self.EnsureCaretVisible()
2963
+ self.ScrollToColumn(0)
2964
+
2965
+ def readline(self):
2966
+ """Replacement for stdin.readline()."""
2967
+ input = ''
2968
+ reader = self.reader
2969
+ reader.isreading = True
2970
+ self.prompt()
2971
+
2972
+ # Ensure that we get a new line and that it's got an input marker...
2973
+ # Also need to temporarily block any other action...
2974
+ cLine = self.GetCurrentLine()
2975
+ self.clearIOMarkers(cLine)
2976
+ self.MarkerAdd(cLine,INPUT_START)
2977
+ self.MarkerAdd(cLine,READLINE_BG)
2978
+ self.MarkerAdd(cLine,INPUT_READLINE)
2979
+
2980
+ try:
2981
+ while not reader.input:
2982
+ wx.GetApp().Yield(onlyIfNeeded=True)
2983
+ input = reader.input
2984
+ finally:
2985
+ start,end = self.GetIOSlice()
2986
+ start = self.runningSlice[1] + 1
2987
+ for i in range(start,end+1):
2988
+ self.clearIOMarkers(i)
2989
+ self.clearGroupingMarkers(i)
2990
+ self.MarkerAdd(i,OUTPUT_BG)
2991
+ if i == start: self.MarkerAdd(i,OUTPUT_START)
2992
+ elif i==end: self.MarkerAdd(i,OUTPUT_END)
2993
+ else: self.MarkerAdd(i,OUTPUT_MIDDLE)
2994
+
2995
+ if i==end: self.MarkerAdd(i,GROUPING_END)
2996
+ else: self.MarkerAdd(i,GROUPING_MIDDLE)
2997
+ reader.input = ''
2998
+ reader.isreading = False
2999
+ input = str(input) # In case of Unicode.
3000
+ return input
3001
+
3002
+ def readlines(self):
3003
+ """Replacement for stdin.readlines()."""
3004
+ lines = []
3005
+ while lines[-1:] != ['\n']:
3006
+ lines.append(self.readline())
3007
+ return lines
3008
+
3009
+ def raw_input(self, prompt=''):
3010
+ """Return string based on user input."""
3011
+ if prompt:
3012
+ self.write(prompt,type='Output')
3013
+ return self.readline()
3014
+
3015
+ def ask(self, prompt='Please enter your response:'):
3016
+ """Get response from the user using a dialog box."""
3017
+ dialog = wx.TextEntryDialog(None, prompt,
3018
+ 'Input Dialog (Raw)', '')
3019
+ try:
3020
+ if dialog.ShowModal() == wx.ID_OK:
3021
+ text = dialog.GetValue()
3022
+ return text
3023
+ finally:
3024
+ dialog.Destroy()
3025
+ return ''
3026
+
3027
+ def pause(self):
3028
+ """Halt execution pending a response from the user."""
3029
+ self.ask('Press enter to continue:')
3030
+
3031
+ def clear(self):
3032
+ """Delete all text from the slices shell."""
3033
+ self.ClearAll()
3034
+ self.MarkerAdd(0,GROUPING_START)
3035
+ self.MarkerAdd(0,INPUT_START)
3036
+
3037
+ def run(self, command, prompt=True, verbose=True):
3038
+ """Execute command as if it was typed in directly.
3039
+ >>> shell.run('print("this")')
3040
+ >>> print("this")
3041
+ this
3042
+ >>>
3043
+ """
3044
+ # Go to the very bottom of the text.
3045
+ endpos = self.GetTextLength()
3046
+ self.SetCurrentPos(endpos)
3047
+ command = command.rstrip()
3048
+ if prompt: self.prompt()
3049
+ if verbose: self.write(command,type='Input')
3050
+ self.push(command)
3051
+
3052
+ # TODO : Will have to fix this to handle other kinds of errors mentioned before...
3053
+ def runfile(self, filename):
3054
+ """Execute all commands in file as if they were typed into the shell."""
3055
+ self.prompt()
3056
+ with open(filename) as file_:
3057
+ for command in file_:
3058
+ if command[:6] == 'shell.':
3059
+ # Run shell methods silently.
3060
+ self.run(command, prompt=False, verbose=False)
3061
+ else:
3062
+ self.run(command, prompt=False, verbose=True)
3063
+
3064
+ def autoCompleteShow(self, command, offset = 0):
3065
+ """Display auto-completion popup list."""
3066
+ self.AutoCompSetAutoHide(self.autoCompleteAutoHide)
3067
+ self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
3068
+ list = self.interp.getAutoCompleteList(command,
3069
+ includeMagic=self.autoCompleteIncludeMagic,
3070
+ includeSingle=self.autoCompleteIncludeSingle,
3071
+ includeDouble=self.autoCompleteIncludeDouble)
3072
+ if list:
3073
+ options = ' '.join(list)
3074
+ #offset = 0
3075
+ self.AutoCompShow(offset, options)
3076
+
3077
+ def autoCallTipShow(self, command, insertcalltip = True, forceCallTip = False):
3078
+ """Display argument spec and docstring in a popup window."""
3079
+ if self.CallTipActive():
3080
+ self.CallTipCancel()
3081
+ (name, argspec, tip) = self.interp.getCallTip(command)
3082
+ if tip:
3083
+ dispatcher.send(signal='SlicesShell.calltip', sender=self, calltip=tip)
3084
+ if not self.autoCallTip and not forceCallTip:
3085
+ return
3086
+ startpos = self.GetCurrentPos()
3087
+ if argspec and insertcalltip and self.callTipInsert:
3088
+ # write with undo history...
3089
+ cpos=self.GetCurrentPos()
3090
+ s=argspec + ')'
3091
+ self.UpdateUndoHistoryBefore('insert',s,cpos,cpos+len(s))
3092
+ self.write(s,type='Input')
3093
+ self.UpdateUndoHistoryAfter()
3094
+
3095
+ endpos = self.GetCurrentPos()
3096
+ self.SetSelection(startpos, endpos)
3097
+ if tip:
3098
+ tippos = startpos - (len(name) + 1)
3099
+ fallback = startpos - self.GetColumn(startpos)
3100
+ # In case there isn't enough room, only go back to the fallback.
3101
+ tippos = max(tippos, fallback)
3102
+ self.CallTipShow(tippos, tip)
3103
+
3104
+ def OnCallTipAutoCompleteManually (self, shiftDown):
3105
+ """AutoComplete and Calltips manually."""
3106
+ if self.AutoCompActive():
3107
+ self.AutoCompCancel()
3108
+ currpos = self.GetCurrentPos()
3109
+ stoppos = self.PositionFromLine(self.GetIOSlice()[0])
3110
+
3111
+ cpos = currpos
3112
+ #go back until '.' is found
3113
+ pointavailpos = -1
3114
+ while cpos >= stoppos:
3115
+ if self.GetCharAt(cpos) == ord ('.'):
3116
+ pointavailpos = cpos
3117
+ break
3118
+ cpos -= 1
3119
+
3120
+ #word from non whitespace until '.'
3121
+ if pointavailpos != -1:
3122
+ #look backward for first whitespace char
3123
+ textbehind = self.GetTextRange (pointavailpos + 1, currpos)
3124
+ pointavailpos += 1
3125
+
3126
+ if not shiftDown:
3127
+ #call AutoComplete
3128
+ stoppos = self.PositionFromLine(self.GetIOSlice()[0])
3129
+ textbefore = self.GetTextRange(stoppos, pointavailpos)
3130
+ self.autoCompleteShow(textbefore, len (textbehind))
3131
+ else:
3132
+ #call CallTips
3133
+ cpos = pointavailpos
3134
+ begpos = -1
3135
+ while cpos > stoppos:
3136
+ if chr(self.GetCharAt(cpos)).isspace():
3137
+ begpos = cpos
3138
+ break
3139
+ cpos -= 1
3140
+ if begpos == -1:
3141
+ begpos = cpos
3142
+ ctips = self.GetTextRange (begpos, currpos)
3143
+ ctindex = ctips.find ('(')
3144
+ if ctindex != -1 and not self.CallTipActive():
3145
+ #insert calltip, if current pos is '(', otherwise show it only
3146
+ self.autoCallTipShow( ctips[:ctindex + 1],
3147
+ self.GetCharAt(currpos - 1) == ord('(') and
3148
+ self.GetCurrentPos() == self.GetTextLength(),
3149
+ True )
3150
+
3151
+
3152
+ def writeOut(self, text):
3153
+ """Replacement for stdout."""
3154
+ self.write(text,type='Output')
3155
+ # TODO : FLUSH?? How to make this update real-time...
3156
+
3157
+ def writeErr(self, text):
3158
+ """Replacement for stderr."""
3159
+ self.write(text,type='Error')
3160
+
3161
+ def redirectStdin(self, redirect=True):
3162
+ """If redirect is true then sys.stdin will come from the shell."""
3163
+ if redirect:
3164
+ sys.stdin = self.reader
3165
+ else:
3166
+ sys.stdin = self.stdin
3167
+
3168
+ def redirectStdout(self, redirect=True):
3169
+ """If redirect is true then sys.stdout will go to the shell."""
3170
+ if redirect:
3171
+ sys.stdout = PseudoFileOut(self.writeOut)
3172
+ else:
3173
+ sys.stdout = self.stdout
3174
+
3175
+ def redirectStderr(self, redirect=True):
3176
+ """If redirect is true then sys.stderr will go to the shell."""
3177
+ if redirect:
3178
+ sys.stderr = PseudoFileErr(self.writeErr)
3179
+ else:
3180
+ sys.stderr = self.stderr
3181
+
3182
+ # Take a spashot of the WHOLE grouping slice (or slices)
3183
+ # The argument s is either what got added or deleted
3184
+ def UpdateUndoHistoryBefore(self,actionType,s,posStart,posEnd,
3185
+ forceNewAction=False):
3186
+ uH=self.undoHistory
3187
+ uI=self.undoIndex
3188
+
3189
+ s=s.replace(os.linesep,'\n')
3190
+ startLine=self.LineFromPosition(posStart)
3191
+
3192
+ if actionType=='marker':
3193
+ numLines = self.LineFromPosition(posEnd) - startLine
3194
+ else:
3195
+ numLines=s.count('\n')
3196
+
3197
+ makeNewAction=forceNewAction
3198
+
3199
+ if forceNewAction:
3200
+ makeNewAction=True
3201
+ elif self.undoIndex==-1:
3202
+ makeNewAction=True
3203
+ elif not uH[uI]['allowsAppend']:
3204
+ makeNewAction=True
3205
+ elif actionType!=uH[uI]['actionType']:
3206
+ makeNewAction=True
3207
+ elif actionType=='insert':
3208
+ if posStart!=uH[uI]['posEnd']:
3209
+ makeNewAction=True
3210
+ else: # This is a continuation of the previous insert
3211
+ uH[uI]['charList'] = uH[uI]['charList']+s
3212
+ uH[uI]['posEnd'] = posEnd # posStart cannot move
3213
+ uH[uI]['numLines'] = uH[uI]['numLines']+numLines
3214
+ elif actionType=='delete':
3215
+ # This is a forward continuation of the previous delete
3216
+ if posStart==uH[uI]['posStart']:
3217
+ uH[uI]['charList'] = uH[uI]['charList']+s
3218
+ uH[uI]['posEnd'] = posEnd
3219
+ uH[uI]['numLines'] = uH[uI]['numLines']+numLines
3220
+ # This is a backward continuation of the previous delete
3221
+ elif posEnd==uH[uI]['posStart']:
3222
+ uH[uI]['charList'] = s+uH[uI]['charList']
3223
+ uH[uI]['posStart'] = posStart
3224
+ uH[uI]['startLine'] = startLine
3225
+ uH[uI]['numLines'] = uH[uI]['numLines']+numLines
3226
+ else:
3227
+ makeNewAction=True
3228
+
3229
+ elif actionType=='marker':
3230
+ makeNewAction=True
3231
+ else:
3232
+ pass #print('Unsupported Action Type!!')
3233
+
3234
+ if makeNewAction:
3235
+ del(self.undoHistory[uI+1:]) # remove actions after undoIndex
3236
+
3237
+ uH.append({
3238
+ 'actionType' : actionType, # Action type ('insert','delete','marker')
3239
+ 'allowsAppend': not forceNewAction, # Can action be joined with others?
3240
+ 'charList' : s, # Character list
3241
+ 'posStart' : posStart, # Cursor poition at the start of the action
3242
+ 'posEnd' : posEnd, # Cursor position at the end of the action
3243
+ 'startLine' : startLine, # Start line number,
3244
+ 'numLines' : numLines, # Number of newlines involved
3245
+ 'mBStart' : None, # Starting line for markers BEFORE action
3246
+ 'mAStart' : None, # Starting line for markers AFTER action
3247
+ 'markersBefore' : None, # [markers BEFORE action]
3248
+ 'markersAfter' : None # [markers AFTER action]
3249
+ })
3250
+
3251
+ self.undoIndex+=1
3252
+
3253
+ # Only update the before when starting a new action
3254
+ start = startLine
3255
+ if actionType=='insert':
3256
+ end = start
3257
+ else:
3258
+ end = start + numLines
3259
+
3260
+ # Update Marker Info
3261
+ newStart=self.GetGroupingSlice(start)[0]
3262
+ newEnd=self.GetGroupingSlice(end)[1]
3263
+ self.undoHistory[self.undoIndex]['markersBefore'] = \
3264
+ [self.MarkerGet(i) for i in range(newStart,newEnd+1)]
3265
+ self.undoHistory[self.undoIndex]['mBStart']=newStart
3266
+
3267
+ self.doHistUpdate=True
3268
+
3269
+ def UpdateUndoHistoryAfter(self): # s is either what got added or deleted
3270
+ start = self.undoHistory[self.undoIndex]['startLine']
3271
+ if self.undoHistory[self.undoIndex]['actionType']=='delete':
3272
+ end = start
3273
+ else:
3274
+ end = start + self.undoHistory[self.undoIndex]['numLines']
3275
+
3276
+ newStart=min(self.GetGroupingSlice(start)[0]-1, 0)
3277
+ newEnd=max(self.GetGroupingSlice(end)[1]+1, self.GetLineCount()-1)
3278
+ self.undoHistory[self.undoIndex]['markersAfter'] = \
3279
+ [self.MarkerGet(i) for i in range(newStart,newEnd+1)]
3280
+ self.undoHistory[self.undoIndex]['mAStart']=newStart
3281
+
3282
+ self.doHistUpdate=False
3283
+
3284
+ def Undo(self):
3285
+ #ADD UNDO
3286
+ #Skip undo if there are no actions...
3287
+ if self.undoIndex==-1:
3288
+ return
3289
+
3290
+ uHI=self.undoHistory[self.undoIndex]
3291
+
3292
+ if uHI['actionType'] in ['insert','delete']:
3293
+ # This will perform the opposite of the action given
3294
+ editwindow.EditWindow.Undo(self)
3295
+ elif uHI['actionType']=='marker': # No text changed, don't pass to STC
3296
+ pass
3297
+ else:
3298
+ #print('Unsupported actionType in undoHistory!!')
3299
+ return
3300
+
3301
+ numLines=len(uHI['markersBefore'])
3302
+ for i in range(numLines):
3303
+ self.MarkerSet( uHI['mBStart']+i , uHI['markersBefore'][i] )
3304
+
3305
+ self.undoIndex-=1
3306
+
3307
+ def Redo(self):
3308
+ #ADD UNDO
3309
+ # First check to see if there are any redo operations available
3310
+ # Note that for redo, undoIndex=-1 is a valid input
3311
+ if self.undoIndex >= len(self.undoHistory)-1:
3312
+ return
3313
+ self.undoIndex+=1
3314
+ uHI=self.undoHistory[self.undoIndex]
3315
+
3316
+ if uHI['actionType'] in ['insert','delete']:
3317
+ # This will re-perform the given action
3318
+ editwindow.EditWindow.Redo(self)
3319
+ elif uHI['actionType']=='marker': # No text changed, don't pass to STC
3320
+ pass
3321
+ else:
3322
+ #print('Unsupported actionType in undoHistory!!')
3323
+ return
3324
+
3325
+ numLines=len(uHI['markersAfter'])
3326
+ for i in range(numLines):
3327
+ self.MarkerSet( uHI['mAStart']+i , uHI['markersAfter'][i] )
3328
+
3329
+ def EmptyUndoBuffer(self):
3330
+ editwindow.EditWindow.EmptyUndoBuffer(self)
3331
+ self.undoIndex=-1
3332
+ self.undoHistory=[]
3333
+ self.doHistUpdate=False
3334
+
3335
+ def CanCut(self):
3336
+ return self.CanEdit() and \
3337
+ (self.GetSelectionStart() != self.GetSelectionEnd())
3338
+
3339
+ def CanPaste(self):
3340
+ """Return true if a paste should succeed."""
3341
+ if self.CanEdit() and editwindow.EditWindow.CanPaste(self):
3342
+ return True
3343
+ else:
3344
+ return False
3345
+
3346
+ def CanEdit(self):
3347
+ """Return true if editing should succeed."""
3348
+ marker=self.MarkerGet(self.GetCurrentLine())
3349
+
3350
+ if marker & OUTPUT_MASK:
3351
+ return False
3352
+ elif marker & INPUT_MASK:
3353
+ if self.reader.isreading and not \
3354
+ (self.MarkerGet(self.GetCurrentLine()) & 1<<INPUT_READLINE ):
3355
+ return False
3356
+ start,end=self.GetIOSlice()
3357
+ sliceStartPos=self.PositionFromLine(start)
3358
+ sliceEndPos=self.GetLineEndPosition(end)
3359
+ """Return true if text is selected and can be cut."""
3360
+ if self.GetSelectionStart() == self.GetSelectionEnd():
3361
+ return True
3362
+ elif self.GetSelectionStart() != self.GetSelectionEnd() \
3363
+ and self.GetSelectionStart() >= sliceStartPos \
3364
+ and self.GetSelectionEnd() >= sliceStartPos \
3365
+ and self.GetSelectionStart() <= sliceEndPos \
3366
+ and self.GetSelectionEnd() <= sliceEndPos:
3367
+ return True
3368
+ return False
3369
+
3370
+ def Cut(self):
3371
+ """Remove selection and place it on the clipboard."""
3372
+ if self.CanCut() and self.CanCopy():
3373
+ if self.AutoCompActive():
3374
+ self.AutoCompCancel()
3375
+ if self.CallTipActive():
3376
+ self.CallTipCancel()
3377
+ self.Copy()
3378
+ self.ReplaceSelection('')
3379
+
3380
+ def Copy(self):
3381
+ """Copy selection and place it on the clipboard."""
3382
+ if self.CanCopy():
3383
+ ps1 = str(sys.ps1)
3384
+ ps2 = str(sys.ps2)
3385
+ command = self.GetSelectedText()
3386
+ command = command.replace(os.linesep + ps2, os.linesep)
3387
+ command = command.replace(os.linesep + ps1, os.linesep)
3388
+ command = self.lstripPrompt(text=command)
3389
+ data = wx.TextDataObject(command)
3390
+ self._clip(data)
3391
+
3392
+ def CopyWithPrompts(self):
3393
+ """Copy selection, including prompts, and place it on the clipboard."""
3394
+ if self.CanCopy():
3395
+ command = self.GetSelectedText()
3396
+ data = wx.TextDataObject(command)
3397
+ self._clip(data)
3398
+
3399
+ def CopyWithPromptsPrefixed(self):
3400
+ """Copy selection, including prompts prefixed with four
3401
+ spaces, and place it on the clipboard."""
3402
+ if self.CanCopy():
3403
+ command = self.GetSelectedText()
3404
+ spaces = ' ' * 4
3405
+ command = spaces + command.replace(os.linesep,
3406
+ os.linesep + spaces)
3407
+ data = wx.TextDataObject(command)
3408
+ self._clip(data)
3409
+
3410
+ def _clip(self, data):
3411
+ if wx.TheClipboard.Open():
3412
+ wx.TheClipboard.UsePrimarySelection(False)
3413
+ wx.TheClipboard.SetData(data)
3414
+ wx.TheClipboard.Flush()
3415
+ wx.TheClipboard.Close()
3416
+
3417
+ def Paste(self):
3418
+ """Replace selection with clipboard contents."""
3419
+
3420
+ #ADD UNDO
3421
+ if self.CanPaste() and wx.TheClipboard.Open():
3422
+ ps2 = str(sys.ps2)
3423
+ if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_UNICODETEXT)):
3424
+ data = wx.TextDataObject()
3425
+ if wx.TheClipboard.GetData(data):
3426
+ self.ReplaceSelection('')
3427
+ command = data.GetText()
3428
+ command = command.rstrip()
3429
+ command = self.fixLineEndings(command)
3430
+ command = self.lstripPrompt(text=command)
3431
+ # TODO : This is still useful... Add it back other places?
3432
+ command = command.replace(os.linesep + ps2, '\n')
3433
+ command = command.replace(os.linesep, '\n')
3434
+ #DNM--Don't use '... '
3435
+ command = command.replace('\n', os.linesep)# + ps2)
3436
+
3437
+ cpos=self.GetCurrentPos()
3438
+ s=command
3439
+ self.UpdateUndoHistoryBefore('insert', s, cpos,
3440
+ cpos+len(s), forceNewAction=True)
3441
+ self.write(s,type='Input')
3442
+ self.UpdateUndoHistoryAfter()
3443
+
3444
+ # Makes paste -> type -> undo consistent with other STC apps
3445
+ self.ReplaceSelection('')
3446
+ wx.TheClipboard.Close()
3447
+
3448
+
3449
+ def PasteAndRun(self):
3450
+ """Replace selection with clipboard contents, run commands."""
3451
+ text = ''
3452
+ if wx.TheClipboard.Open():
3453
+ if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_UNICODETEXT)):
3454
+ data = wx.TextDataObject()
3455
+ if wx.TheClipboard.GetData(data):
3456
+ text = data.GetText()
3457
+ wx.TheClipboard.Close()
3458
+ if text:
3459
+ self.Execute(text)
3460
+
3461
+
3462
+ def Execute(self, text):
3463
+ """Replace selection with text and run commands."""
3464
+ start,end=self.GetIOSlice()
3465
+ startpos=self.PositionFromLine(start)
3466
+ endpos=self.GetLineEndPosition(end)
3467
+
3468
+ self.SetCurrentPos(endpos)
3469
+ self.SetSelection(startpos, endpos)
3470
+ self.ReplaceSelection('')
3471
+
3472
+ hasSyntaxError=False
3473
+ result = self.BreakTextIntoCommands(command)
3474
+ if result[0] is None:
3475
+ commands=[command]
3476
+ hasSyntaxError=True
3477
+ else:
3478
+ commands=result
3479
+
3480
+ for command in commands:
3481
+ command = command.replace('\n', os.linesep)
3482
+ self.write(command)
3483
+ self.processLine()
3484
+
3485
+ def wrap(self, wrap=True):
3486
+ """Sets whether text is word wrapped."""
3487
+ try:
3488
+ self.SetWrapMode(wrap)
3489
+ except AttributeError:
3490
+ return 'Wrapping is not available in this version.'
3491
+
3492
+ def zoom(self, points=0):
3493
+ """Set the zoom level.
3494
+
3495
+ This number of points is added to the size of all fonts. It
3496
+ may be positive to magnify or negative to reduce."""
3497
+ self.SetZoom(points)
3498
+
3499
+ def LoadSettings(self, config):
3500
+ self.autoComplete = \
3501
+ config.ReadBool('Options/AutoComplete', True)
3502
+ self.autoCompleteIncludeMagic = \
3503
+ config.ReadBool('Options/AutoCompleteIncludeMagic', True)
3504
+ self.autoCompleteIncludeSingle = \
3505
+ config.ReadBool('Options/AutoCompleteIncludeSingle', True)
3506
+ self.autoCompleteIncludeDouble = \
3507
+ config.ReadBool('Options/AutoCompleteIncludeDouble', True)
3508
+ self.autoCallTip = \
3509
+ config.ReadBool('Options/AutoCallTip', True)
3510
+ self.callTipInsert = \
3511
+ config.ReadBool('Options/CallTipInsert', True)
3512
+
3513
+ self.SetWrapMode(config.ReadBool('View/WrapMode', True))
3514
+
3515
+ self.lineNumbers = \
3516
+ config.ReadBool('View/ShowLineNumbers', True)
3517
+ self.setDisplayLineNumbers (self.lineNumbers)
3518
+ zoom = config.ReadInt('View/Zoom/Shell', -99)
3519
+ if zoom != -99:
3520
+ self.SetZoom(zoom)
3521
+
3522
+
3523
+
3524
+ def SaveSettings(self, config):
3525
+ config.WriteBool('Options/AutoComplete', self.autoComplete)
3526
+ config.WriteBool('Options/AutoCompleteIncludeMagic',
3527
+ self.autoCompleteIncludeMagic)
3528
+ config.WriteBool('Options/AutoCompleteIncludeSingle',
3529
+ self.autoCompleteIncludeSingle)
3530
+ config.WriteBool('Options/AutoCompleteIncludeDouble',
3531
+ self.autoCompleteIncludeDouble)
3532
+ config.WriteBool('Options/AutoCallTip', self.autoCallTip)
3533
+ config.WriteBool('Options/CallTipInsert', self.callTipInsert)
3534
+ config.WriteBool('View/WrapMode', self.GetWrapMode())
3535
+ config.WriteBool('View/ShowLineNumbers', self.lineNumbers)
3536
+ config.WriteInt('View/Zoom/Shell', self.GetZoom())
3537
+
3538
+ def GetContextMenu(self):
3539
+ """
3540
+ Create and return a context menu for the slices shell.
3541
+ This is used instead of the scintilla default menu
3542
+ in order to correctly respect our immutable buffer.
3543
+ """
3544
+ menu = wx.Menu()
3545
+ menu.Append(self.ID_UNDO, "Undo")
3546
+ menu.Append(self.ID_REDO, "Redo")
3547
+
3548
+ menu.AppendSeparator()
3549
+
3550
+ menu.Append(self.ID_CUT, "Cut")
3551
+ menu.Append(self.ID_COPY, "Copy")
3552
+ menu.Append(frame.ID_COPY_PLUS, "Copy With Prompts")
3553
+ menu.Append(self.ID_PASTE, "Paste")
3554
+ menu.Append(frame.ID_PASTE_PLUS, "Paste And Run")
3555
+ menu.Append(self.ID_CLEAR, "Clear")
3556
+
3557
+ menu.AppendSeparator()
3558
+
3559
+ menu.Append(self.ID_SELECTALL, "Select All")
3560
+ return menu
3561
+
3562
+ def OnContextMenu(self, evt):
3563
+ menu = self.GetContextMenu()
3564
+ self.PopupMenu(menu)
3565
+
3566
+ def OnUpdateUI(self, evt):
3567
+ id = evt.Id
3568
+ if id in (self.ID_CUT, self.ID_CLEAR):
3569
+ evt.Enable(self.CanCut())
3570
+ elif id in (self.ID_COPY, frame.ID_COPY_PLUS):
3571
+ evt.Enable(self.CanCopy())
3572
+ elif id in (self.ID_PASTE, frame.ID_PASTE_PLUS):
3573
+ evt.Enable(self.CanPaste())
3574
+ elif id == self.ID_UNDO:
3575
+ evt.Enable(self.CanUndo())
3576
+ elif id == self.ID_REDO:
3577
+ evt.Enable(self.CanRedo())
3578
+
3579
+ def LoadPySlicesFile(self,fid):
3580
+ invalidFileString = 'Not a valid input format'
3581
+ lineCount=0
3582
+ groupingStartLines=[0]
3583
+ ioStartLines=[0]
3584
+ ioStartTypes=[]
3585
+ removeComment=False
3586
+
3587
+ # Read the initial three (or four) lines that have version and marker information
3588
+ line=fid.readline()
3589
+ if line == usrBinEnvPythonText:
3590
+ line=fid.readline() # Add the option to place #!/usr/bin/env python at the top
3591
+ if line not in pyslicesFormatHeaderText: print(invalidFileString); return
3592
+ line=fid.readline()
3593
+ if line != groupingStartText: print(invalidFileString); return
3594
+ line=fid.readline()
3595
+ if line == inputStartText: ioStartTypes.append('input');removeComment=False
3596
+ elif line == outputStartText: ioStartTypes.append('output');removeComment=True
3597
+ else: print(invalidFileString); return
3598
+
3599
+ self.ClearAll()
3600
+
3601
+ # Write the file's text to the text area
3602
+ # Capture Marker information to
3603
+ for i in fid:
3604
+ if i==groupingStartText:
3605
+ groupingStartLines.append(lineCount)
3606
+ elif i==inputStartText:
3607
+ ioStartLines.append(lineCount)
3608
+ ioStartTypes.append('input')
3609
+ removeComment=False
3610
+ elif i==outputStartText:
3611
+ ioStartLines.append(lineCount)
3612
+ ioStartTypes.append('output')
3613
+ removeComment=True
3614
+ else:
3615
+ if removeComment: w=i[1:].replace(os.linesep,'\n')
3616
+ else: w=i.replace(os.linesep,'\n')
3617
+ self.write(w,'Input',silent=True)
3618
+ lineCount+=1
3619
+
3620
+ if w[-1]=='\n':
3621
+ lineCount+=1
3622
+
3623
+ for i in range(lineCount+1):
3624
+ self.clearGroupingMarkers(i)
3625
+ self.clearIOMarkers(i)
3626
+
3627
+ doMiddle=False
3628
+ doEnd=False
3629
+ if groupingStartLines!=[]:
3630
+ if i == groupingStartLines[0]:
3631
+ self.MarkerAdd(i,GROUPING_START)
3632
+ del groupingStartLines[0]
3633
+ elif i+1 == groupingStartLines[0]:
3634
+ doEnd=True
3635
+ else:
3636
+ doMiddle=True
3637
+ elif i==lineCount-1:
3638
+ doEnd=True
3639
+ else:
3640
+ doMiddle=True
3641
+
3642
+ if doMiddle:
3643
+ self.MarkerAdd(i,GROUPING_MIDDLE)
3644
+ elif doEnd:
3645
+ self.MarkerAdd(i,GROUPING_END)
3646
+
3647
+ doMiddle=False
3648
+ doEnd=False
3649
+ if ioStartLines!=[]:
3650
+ if i == ioStartLines[0]:
3651
+ # Delete the old ioStartTypes (keep the current copy for later use)
3652
+ if i>0: del ioStartTypes[0]
3653
+
3654
+ if ioStartTypes[0]=='input':
3655
+ self.MarkerAdd(i,INPUT_START)
3656
+ elif ioStartTypes[0]=='output':
3657
+ self.MarkerAdd(i,OUTPUT_START)
3658
+ self.MarkerAdd(i,OUTPUT_BG)
3659
+ else:
3660
+ #print('Invalid Type!')
3661
+ return
3662
+
3663
+ # Only delete markers we are totally finished with...
3664
+ # Keep one more "StartTypes" than "StartLines"
3665
+ del ioStartLines[0]
3666
+ elif i+1 == ioStartLines[0]:
3667
+ doEnd=True
3668
+ else:
3669
+ doMiddle=True
3670
+ elif i==lineCount-1:
3671
+ doEnd=True
3672
+ else:
3673
+ doMiddle=True
3674
+
3675
+ if doMiddle:
3676
+ if ioStartTypes[0]=='input':
3677
+ self.MarkerAdd(i,INPUT_MIDDLE)
3678
+ elif ioStartTypes[0]=='output':
3679
+ self.MarkerAdd(i,OUTPUT_MIDDLE)
3680
+ self.MarkerAdd(i,OUTPUT_BG)
3681
+ else:
3682
+ #print('Invalid Type!')
3683
+ return
3684
+ elif doEnd:
3685
+ if ioStartTypes[0]=='input':
3686
+ self.MarkerAdd(i,INPUT_END)
3687
+ elif ioStartTypes[0]=='output':
3688
+ self.MarkerAdd(i,OUTPUT_END)
3689
+ self.MarkerAdd(i,OUTPUT_BG)
3690
+ else:
3691
+ #print('Invalid Type!')
3692
+ return
3693
+
3694
+ self.EmptyUndoBuffer() # maybe not?
3695
+
3696
+
3697
+ def SavePySlicesFile(self,fid):
3698
+ addComment=False
3699
+
3700
+ def fid_write(s):
3701
+ fid.write(s.replace('\r\n', '\n')
3702
+ .replace('\n', os.linesep)
3703
+ .encode('utf-8'))
3704
+
3705
+ fid_write(usrBinEnvPythonText)
3706
+ fid_write(pyslicesFormatHeaderText[-1])
3707
+ for i in range(self.GetLineCount()):
3708
+ markers=self.MarkerGet(i)
3709
+ if markers & ( 1<<GROUPING_START | 1<<GROUPING_START_FOLDED ):
3710
+ fid_write(groupingStartText)
3711
+ if markers & ( 1<<INPUT_START | 1<<INPUT_START_FOLDED ):
3712
+ fid_write(inputStartText)
3713
+ addComment=False
3714
+ if markers & ( 1<<OUTPUT_START | 1<<OUTPUT_START_FOLDED ):
3715
+ fid_write(outputStartText)
3716
+ addComment=True
3717
+ if addComment:
3718
+ fid_write(u'#')
3719
+
3720
+ fid_write(self.GetLine(i))
3721
+
3722
+ # FIX ME!!
3723
+ def LoadPyFileAsSlice(self,fid):
3724
+ curpos=self.GetCurrentPos()
3725
+ start,end = self.GetGroupingSlice()
3726
+
3727
+ endpos=self.GetLineEndPosition(end)
3728
+ self.SetCurrentPos(endpos)
3729
+ self.SetSelection(endpos, endpos)
3730
+
3731
+ text='\n'+fid.read()
3732
+ self.write(text,'Input')
3733
+ newpos=self.GetCurrentPos()
3734
+
3735
+ self.SetCurrentPos(curpos)
3736
+ self.SetSelection(curpos,curpos)
3737
+ self.SplitSlice()
3738
+ #self.SetCurrentPos(newpos)
3739
+ #self.SetSelection(newpos,newpos)
3740
+
3741
+ def hasChanged(self):
3742
+ """Return True if contents have changed."""
3743
+ return self.GetModify() or self.NeedsCheckForSave
3744
+
3745
+
3746
+
3747
+ ## NOTE: The DnD of file names is disabled until we can figure out how
3748
+ ## best to still allow DnD of text.
3749
+
3750
+ ## #seb : File drag and drop
3751
+ ## class FileDropTarget(wx.FileDropTarget):
3752
+ ## def __init__(self, obj):
3753
+ ## wx.FileDropTarget.__init__(self)
3754
+ ## self.obj = obj
3755
+ ## def OnDropFiles(self, x, y, filenames):
3756
+ ## if len(filenames) == 1:
3757
+ ## txt = 'r\"%s\"' % filenames[0]
3758
+ ## else:
3759
+ ## txt = '( '
3760
+ ## for f in filenames:
3761
+ ## txt += 'r\"%s\" , ' % f
3762
+ ## txt += ')'
3763
+ ## self.obj.AppendText(txt)
3764
+ ## pos = self.obj.GetCurrentPos()
3765
+ ## self.obj.SetCurrentPos( pos )
3766
+ ## self.obj.SetSelection( pos, pos )
3767
+
3768
+
3769
+
3770
+ ## class TextAndFileDropTarget(wx.DropTarget):
3771
+ ## def __init__(self, sliceshell):
3772
+ ## wx.DropTarget.__init__(self)
3773
+ ## self.sliceshell = sliceshell
3774
+ ## self.compdo = wx.DataObjectComposite()
3775
+ ## self.textdo = wx.TextDataObject()
3776
+ ## self.filedo = wx.FileDataObject()
3777
+ ## self.compdo.Add(self.textdo)
3778
+ ## self.compdo.Add(self.filedo, True)
3779
+
3780
+ ## self.SetDataObject(self.compdo)
3781
+
3782
+ ## def OnDrop(self, x, y):
3783
+ ## return True
3784
+
3785
+ ## def OnData(self, x, y, result):
3786
+ ## self.GetData()
3787
+ ## if self.textdo.GetTextLength() > 1:
3788
+ ## text = self.textdo.GetText()
3789
+ ## # *** Do something with the dragged text here...
3790
+ ## self.textdo.SetText('')
3791
+ ## else:
3792
+ ## filenames = str(self.filename.GetFilenames())
3793
+ ## if len(filenames) == 1:
3794
+ ## txt = 'r\"%s\"' % filenames[0]
3795
+ ## else:
3796
+ ## txt = '( '
3797
+ ## for f in filenames:
3798
+ ## txt += 'r\"%s\" , ' % f
3799
+ ## txt += ')'
3800
+ ## self.sliceshell.AppendText(txt)
3801
+ ## pos = self.sliceshell.GetCurrentPos()
3802
+ ## self.sliceshell.SetCurrentPos( pos )
3803
+ ## self.sliceshell.SetSelection( pos, pos )
3804
+
3805
+ ## return result