<?xml version="1.0" encoding="utf-8"?>
<!-- Created by Leo: http://leoeditor.com/leo_toc.html -->
<leo_file xmlns:leo="http://leoeditor.com/namespaces/leo-python-editor/1.1" >
<leo_header file_format="2"/>
<globals/>
<preferences/>
<find_panel_settings/>
<vnodes>
<v t="ekr.20070615131954"><vh>Startup</vh>
<v t="ekr.20150302053516.3"><vh>@settings</vh>
<v t="mhw.20181210131101.1"><vh>@bool put-expansion-bits-in-leo-files = False</vh></v>
</v>
<v t="ekr.20070427110751"><vh>@chapters</vh></v>
<v t="ekr.20141116105945.2"><vh>@persistence</vh>
<v t="ekr.20141116105945.3"><vh>@data:@auto create-leobat.bat</vh>
<v t="ekr.20141116105945.4"><vh>@gnxs</vh></v>
</v>
<v t="ekr.20161206070406.1"><vh>@data:@auto-md ../doc/c2py.md</vh>
<v t="ekr.20161206090903.1"><vh>@gnxs</vh></v>
</v>
<v t="maphew.20190209160547.1"><vh>@data:@auto build-leo.bat</vh>
<v t="lkj.20190712002811.1"><vh>@gnxs</vh></v>
</v>
</v>
</v>
<v t="ekr.20061008055616"><vh>Scripts</vh>
<v t="ekr.20110914030246.2405"><vh>@file gen_blender_docs.py</vh></v>
<v t="ekr.20051110111150" descendentVnodeUnknownAttributes="7d71005806000000302e382e323371017d710258120000007273745f687474705f61747472696275746571035d71042858460000003c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d333922206e616d653d22687474702d6e6f64652d6d61726b65722d3339223e710558040000003c2f613e71065d71072858340000003c64697620636c6173733d2273656374696f6e222069643d2272756e6e696e672d6c656f2d696e2d62617463682d6d6f6465223e710858060000003c2f6469763e71095d710a28583f0000003c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710b58060000003c2f6469763e710c5d710d2858060000003c626f64793e710e58070000003c2f626f64793e710f5d71102858430000003c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e711158070000003c2f68746d6c3e71124e6565656558070000003c2f6469763e0a7113583e0000003c64697620636c6173733d2273656374696f6e222069643d2266756e6374696f6e732d646566696e65642d696e2d6c656f676c6f62616c732d7079223e0a7114587e0000003c68313e3c6120636c6173733d22746f632d6261636b7265662220687265663d22236964323022206e616d653d2266756e6374696f6e732d646566696e65642d696e2d6c656f676c6f62616c732d7079223e46756e6374696f6e7320646566696e656420696e206c656f476c6f62616c732e70793c2f613e3c2f68313e0a71156573732e"><vh>@file leoScripts.txt</vh></v>
<v t="mhw-debug-1081.20190310203401.1"><vh>Windows-only scripts</vh>
<v t="maphew.20130613230258.2801"><vh>@file elevate.py</vh></v>
<v t="maphew.20130809155103.2863"><vh>@auto build-leo.bat</vh></v>
</v>
</v>
<v t="ekr.20111017085134.16069"><vh>@ignore @button nodes</vh>
<v t="ekr.20111017085134.16072"><vh>@button check-dirty</vh></v>
<v t="ekr.20150508132450.1"><vh>@button create decorators</vh>
<v t="ekr.20150508132450.2"><vh>create_d</vh></v>
<v t="ekr.20150508132450.3"><vh>create_decorator</vh></v>
<v t="ekr.20150508132450.4"><vh>create_decorators</vh></v>
<v t="ekr.20150508132450.5"><vh>create_fixups</vh></v>
<v t="ekr.20150508132450.6"><vh>find_class</vh></v>
<v t="ekr.20150508132450.7"><vh>find_next_clone</vh></v>
<v t="ekr.20150508132450.8"><vh>munge_lines</vh></v>
<v t="ekr.20150508132450.9"><vh>run</vh></v>
</v>
<v t="ekr.20111017085134.16070"><vh>@button jython</vh></v>
<v t="ekr.20111017085134.16074"><vh>@button Lines Down</vh>
<v t="ekr.20111017085134.16075"><vh>moveLinesDown</vh></v>
</v>
<v t="ekr.20111017085134.16076"><vh>@button Lines Up</vh>
<v t="ekr.20111017085134.16077"><vh>moveLinesUp</vh></v>
</v>
<v t="ekr.20111017085134.16078"><vh>@button lispCall @key=alt+6</vh>
<v t="ekr.20111017085134.16079"><vh>ctor</vh></v>
<v t="ekr.20111017085134.16080"><vh>run &amp; helpers</vh>
<v t="ekr.20111017085134.16081"><vh>findCalls</vh></v>
<v t="ekr.20111017085134.16082"><vh>findDefs</vh></v>
<v t="ekr.20111017085134.16083"><vh>stripComments</vh></v>
<v t="ekr.20111017085134.16084"><vh>stripLispIds</vh></v>
<v t="ekr.20111017085134.16085"><vh>stripStrings</vh></v>
</v>
<v t="ekr.20111017085134.16086"><vh>class token</vh></v>
<v t="ekr.20111017085134.16087"><vh>choose</vh></v>
<v t="ekr.20111017085134.16088"><vh>dumpList</vh></v>
<v t="ekr.20111017085134.16089"><vh>Parsing...</vh>
<v t="ekr.20111017085134.16090"><vh>parse</vh></v>
<v t="ekr.20111017085134.16091"><vh>scan &amp; helpers</vh>
<v t="ekr.20111017085134.16092"><vh>skipComment</vh></v>
<v t="ekr.20111017085134.16093"><vh>skipId</vh></v>
<v t="ekr.20111017085134.16094"><vh>skipString</vh></v>
</v>
<v t="ekr.20111017085134.16095"><vh>scanForest</vh></v>
</v>
<v t="ekr.20111017085134.16096"><vh>Code generators...</vh>
<v t="ekr.20111017085134.16097"><vh>gen</vh></v>
<v t="ekr.20111017085134.16098"><vh>gen_token</vh></v>
<v t="ekr.20111017085134.16099"><vh>gen_block &amp; helper</vh>
<v t="ekr.20111017085134.16100"><vh>gen_block_id</vh></v>
</v>
<v t="ekr.20111017085134.16101"><vh>gen_call &amp; helper</vh>
<v t="ekr.20111017085134.16102"><vh>gen_arg</vh></v>
</v>
<v t="ekr.20111017085134.16103"><vh>gen_def</vh></v>
<v t="ekr.20111017085134.16104"><vh>gen_if &amp; helpers</vh>
<v t="ekr.20111017085134.16105"><vh>gen_then</vh></v>
</v>
<v t="ekr.20111017085134.16106"><vh>gen_expr</vh></v>
<v t="ekr.20111017085134.16107"><vh>gen_let &amp; helper</vh>
<v t="ekr.20111017085134.16108"><vh>gen_let_bindings</vh></v>
</v>
<v t="ekr.20111017085134.16109"><vh>put...</vh>
<v t="ekr.20111017085134.16110"><vh>put</vh></v>
<v t="ekr.20111017085134.16111"><vh>put_token</vh></v>
<v t="ekr.20111017085134.16112"><vh>put_code &amp; put_code_line</vh></v>
<v t="ekr.20111017085134.16113"><vh>put_code_token</vh></v>
</v>
</v>
</v>
<v t="ekr.20160123185308.1"><vh>@button make_stub_files script</vh>
<v t="ekr.20160123185308.2"><vh>class MakeStubFile</vh>
<v t="ekr.20160123185308.3"><vh>msf.ctors &amp; helpers</vh>
<v t="ekr.20160123185308.4"><vh>msf.make_types_dict</vh></v>
<v t="ekr.20160123185308.5"><vh>msf.scan_types_data</vh></v>
</v>
<v t="ekr.20160123185308.6"><vh>msf.make_stub_file</vh></v>
<v t="ekr.20160123185308.7"><vh>msf.run</vh></v>
</v>
<v t="ekr.20160123185308.8"><vh>class AstFormatter</vh>
<v t="ekr.20160123185308.9"><vh> f.Entries</vh>
<v t="ekr.20160123185308.10"><vh>f.format</vh></v>
<v t="ekr.20160123185308.11"><vh>f.visit</vh></v>
</v>
<v t="ekr.20160123185308.12"><vh>f.Contexts</vh>
<v t="ekr.20160123185308.13"><vh>f.ClassDef</vh></v>
<v t="ekr.20160123185308.14"><vh>f.FunctionDef</vh></v>
<v t="ekr.20160123185308.15"><vh>f.Interactive</vh></v>
<v t="ekr.20160123185308.16"><vh>f.Module</vh></v>
<v t="ekr.20160123185308.17"><vh>f.Lambda</vh></v>
</v>
<v t="ekr.20160123185308.18"><vh>f.Expressions</vh>
<v t="ekr.20160123185308.19"><vh>f.Expr</vh></v>
<v t="ekr.20160123185308.20"><vh>f.Expression</vh></v>
<v t="ekr.20160123185308.21"><vh>f.GeneratorExp</vh></v>
<v t="ekr.20160123185308.22"><vh>f.ctx nodes</vh></v>
</v>
<v t="ekr.20160123185308.23"><vh>f.Operands</vh>
<v t="ekr.20160123185308.24"><vh>f.arguments</vh></v>
<v t="ekr.20160123185308.25"><vh>f.arg (Python3 only)</vh></v>
<v t="ekr.20160123185308.26"><vh>f.Attribute</vh></v>
<v t="ekr.20160123185308.27"><vh>f.Bytes</vh></v>
<v t="ekr.20160123185308.28"><vh>f.Call &amp; f.keyword</vh>
<v t="ekr.20160123185308.29"><vh>f.keyword</vh></v>
</v>
<v t="ekr.20160123185308.30"><vh>f.comprehension</vh></v>
<v t="ekr.20160123185308.31"><vh>f.Dict</vh></v>
<v t="ekr.20160123185308.32"><vh>f.Ellipsis</vh></v>
<v t="ekr.20160123185308.33"><vh>f.ExtSlice</vh></v>
<v t="ekr.20160123185308.34"><vh>f.Index</vh></v>
<v t="ekr.20160123185308.35"><vh>f.List</vh></v>
<v t="ekr.20160123185308.36"><vh>f.ListComp</vh></v>
<v t="ekr.20160123185308.37"><vh>f.Name</vh></v>
<v t="ekr.20160123185308.38"><vh>f.Num</vh></v>
<v t="ekr.20160123185308.39"><vh>f.Repr</vh></v>
<v t="ekr.20160123185308.40"><vh>f.Slice</vh></v>
<v t="ekr.20160123185308.41"><vh>f.Str</vh></v>
<v t="ekr.20160123185308.42"><vh>f.Subscript</vh></v>
<v t="ekr.20160123185308.43"><vh>f.Tuple</vh></v>
</v>
<v t="ekr.20160123185308.44"><vh>f.Operators</vh>
<v t="ekr.20160123185308.45"><vh>f.BinOp</vh></v>
<v t="ekr.20160123185308.46"><vh>f.BoolOp</vh></v>
<v t="ekr.20160123185308.47"><vh>f.Compare</vh></v>
<v t="ekr.20160123185308.48"><vh>f.UnaryOp</vh></v>
<v t="ekr.20160123185308.49"><vh>f.ifExp (ternary operator)</vh></v>
</v>
<v t="ekr.20160123185308.50"><vh>f.Statements</vh>
<v t="ekr.20160123185308.51"><vh>f.Assert</vh></v>
<v t="ekr.20160123185308.52"><vh>f.Assign</vh></v>
<v t="ekr.20160123185308.53"><vh>f.AugAssign</vh></v>
<v t="ekr.20160123185308.54"><vh>f.Break</vh></v>
<v t="ekr.20160123185308.55"><vh>f.Continue</vh></v>
<v t="ekr.20160123185308.56"><vh>f.Delete</vh></v>
<v t="ekr.20160123185308.57"><vh>f.ExceptHandler</vh></v>
<v t="ekr.20160123185308.58"><vh>f.Exec</vh></v>
<v t="ekr.20160123185308.59"><vh>f.For</vh></v>
<v t="ekr.20160123185308.60"><vh>f.Global</vh></v>
<v t="ekr.20160123185308.61"><vh>f.If</vh></v>
<v t="ekr.20160123185308.62"><vh>f.Import &amp; helper</vh>
<v t="ekr.20160123185308.63"><vh>f.get_import_names</vh></v>
</v>
<v t="ekr.20160123185308.64"><vh>f.ImportFrom</vh></v>
<v t="ekr.20160123185308.65"><vh>f.Pass</vh></v>
<v t="ekr.20160123185308.66"><vh>f.Print</vh></v>
<v t="ekr.20160123185308.67"><vh>f.Raise</vh></v>
<v t="ekr.20160123185308.68"><vh>f.Return</vh></v>
<v t="ekr.20160123185308.69"><vh>f.Suite</vh></v>
<v t="ekr.20160123185308.70"><vh>f.TryExcept</vh></v>
<v t="ekr.20160123185308.71"><vh>f.TryFinally</vh></v>
<v t="ekr.20160123185308.72"><vh>f.While</vh></v>
<v t="ekr.20160123185308.73"><vh>f.With</vh></v>
<v t="ekr.20160123185308.74"><vh>f.Yield</vh></v>
</v>
<v t="ekr.20160123185308.75"><vh>f.Utils</vh>
<v t="ekr.20160123185308.76"><vh>f.kind</vh></v>
<v t="ekr.20160123185308.77"><vh>f.indent</vh></v>
<v t="ekr.20160123185308.78"><vh>f.op_name</vh></v>
</v>
</v>
<v t="ekr.20160123185308.79"><vh>class StubFormatter (AstFormatter)</vh>
<v t="ekr.20160123185308.80"><vh>sf.Constants &amp; Name</vh></v>
</v>
<v t="ekr.20160123185308.81"><vh>class StubTraverser (ast.NodeVisitor)</vh>
<v t="ekr.20160123185308.82"><vh>st.indent &amp; out</vh></v>
<v t="ekr.20160123185308.83"><vh>st.run</vh></v>
<v t="ekr.20160123185308.84"><vh>st.visit (not used)</vh></v>
<v t="ekr.20160123185308.85"><vh>st.Visitors</vh>
<v t="ekr.20160123185308.86"><vh>st.ClassDef</vh></v>
<v t="ekr.20160123185308.87"><vh>st.FunctionDef &amp; helpers</vh>
<v t="ekr.20160123185308.88"><vh>format_arguments &amp; helper</vh>
<v t="ekr.20160123185308.89"><vh>munge_arg</vh></v>
</v>
<v t="ekr.20160123185308.90"><vh>format_returns</vh></v>
</v>
<v t="ekr.20160123185308.91"><vh>st.Return</vh></v>
</v>
</v>
</v>
<v t="ekr.20111017085134.16114"><vh>@button outlineToClipboard</vh></v>
<v t="ekr.20111017085134.16071"><vh>@button pydoc</vh></v>
<v t="ekr.20150525161132.1"><vh>@button tokens2tree</vh>
<v t="ekr.20150525161132.2"><vh>&lt;&lt; imports &gt;&gt;</vh></v>
</v>
<v t="ekr.20170301022829.1"><vh>@ignore buttons new in Leo 5.5</vh>
<v t="ekr.20170301014329.1"><vh>@button cycling syntax coloring</vh></v>
<v t="ekr.20170211083757.1"><vh>@button Demo @key=Ctrl-9</vh>
<v t="ekr.20170211083757.2"><vh>&lt;&lt; imports &gt;&gt;</vh></v>
<v t="ekr.20170211083757.3"><vh>&lt;&lt; class myDemo &gt;&gt;</vh>
<v t="ekr.20170211083757.4"><vh>setup</vh></v>
<v t="ekr.20170211083757.5"><vh>setup_script</vh></v>
<v t="ekr.20170211083757.6"><vh>teardown</vh></v>
<v t="ekr.20170211083757.7"><vh>teardown_script</vh></v>
</v>
<v t="ekr.20170211083757.8"><vh>demo-script</vh>
<v t="ekr.20170211083757.9"><vh>First</vh></v>
<v t="ekr.20170211083757.10"><vh>Full featured outliner</vh></v>
<v t="ekr.20170211083757.11"><vh>Leo's panes</vh></v>
<v t="ekr.20170211083757.12"><vh>Leo creates scripts from outlines</vh></v>
<v t="ekr.20170211083757.13"><vh>Clones and cff</vh></v>
<v t="ekr.20170211083757.14"><vh>Last</vh></v>
</v>
</v>
<v t="ekr.20161006092435.1"><vh>@button import-tab-files</vh>
<v t="ekr.20161006092435.2"><vh>class TabImporter</vh>
<v t="ekr.20161006092435.3"><vh>check</vh></v>
<v t="ekr.20161006092435.4"><vh>dump_stack</vh></v>
<v t="ekr.20161006092435.5"><vh>lws</vh></v>
<v t="ekr.20161006092435.6"><vh>scan</vh></v>
<v t="ekr.20161006092435.7"><vh>scan_helper</vh></v>
<v t="ekr.20161006092435.8"><vh>undent</vh></v>
</v>
</v>
<v t="ekr.20170301023612.1"><vh>@button insert headlines as comments</vh></v>
<v t="ekr.20170212105552.1"><vh>@button IntroSlides @key=Ctrl-9</vh>
<v t="ekr.20170212105552.2"><vh>&lt;&lt; imports &gt;&gt;</vh></v>
<v t="ekr.20170212105552.3"><vh>&lt;&lt; class IntroSlides &gt;&gt;</vh>
<v t="ekr.20170212105552.4"><vh>setup</vh></v>
<v t="ekr.20170212105552.5"><vh>setup_script</vh></v>
<v t="ekr.20170212105552.6"><vh>teardown</vh></v>
<v t="ekr.20170212105552.7"><vh>teardown_script</vh></v>
</v>
<v t="ekr.20170212105552.8"><vh>&lt;&lt; main &gt;&gt;</vh></v>
<v t="ekr.20170212105552.9"><vh>Leo's Main Window</vh></v>
<v t="ekr.20170212105552.10"><vh>intro-slides-script</vh>
<v t="ekr.20170212105552.11"><vh>Slide 1: Leo's main window</vh></v>
</v>
</v>
<v t="ekr.20160923132656.1"><vh>@button introspect</vh></v>
<v t="ekr.20161031130627.1"><vh>@button pep8 @key=Ctrl-5</vh>
<v t="ekr.20161031130627.2"><vh>class Pep8</vh>
<v t="ekr.20161031130627.3"><vh>change_all &amp; helpers</vh>
<v t="ekr.20161031130627.4"><vh>change_body</vh></v>
<v t="ekr.20161031130627.5"><vh>change_headline</vh></v>
</v>
<v t="ekr.20161031130627.6"><vh>get_name</vh></v>
<v t="ekr.20161031130627.7"><vh>run</vh></v>
<v t="ekr.20161031130627.8"><vh>to_pep8</vh></v>
</v>
<v t="ekr.20161031130627.9"><vh>clear</vh></v>
</v>
<v t="ekr.20170225023738.1"><vh>@button test-http</vh></v>
<v t="ekr.20170120110015.1"><vh>@ignore importer scripts</vh>
<v t="ekr.20161120175101.1"><vh>@button make-md-heads</vh>
<v t="ekr.20161120175101.2"><vh>markup</vh></v>
</v>
<v t="ekr.20161123085419.1"><vh>@button make-table</vh></v>
<v t="ekr.20161124034654.1"><vh>@button make-importer</vh>
<v t="ekr.20161124034654.2"><vh>&lt;&lt; define run &amp; helpers &gt;&gt;</vh>
<v t="ekr.20161124034654.3"><vh>copy_tree</vh></v>
<v t="ekr.20161124034654.4"><vh>make_substitutions</vh></v>
<v t="ekr.20161124034654.5"><vh>run</vh></v>
<v t="ekr.20161124034654.6"><vh>substitue</vh></v>
</v>
<v t="ekr.20161124034654.7"><vh>@@file importers/{{name}}.py</vh>
<v t="ekr.20161124034654.8"><vh>class {{cap_name}}_Importer</vh>
<v t="ekr.20161124034654.9"><vh>{{name}}.Overrides</vh>
<v t="ekr.20161124034654.10"><vh>{{name}}.clean_headline</vh></v>
<v t="ekr.20161124034654.11"><vh>{{name}}.clean_nodes</vh></v>
</v>
</v>
<v t="ekr.20161124034654.12"><vh>class class {{cap_name}}_ScanState</vh>
<v t="ekr.20161124034654.13"><vh>{{name}}_state.level</vh></v>
<v t="ekr.20161124034654.14"><vh>{{name}}_state.update</vh></v>
</v>
</v>
</v>
<v t="ekr.20161124133327.1"><vh>@button make-test</vh>
<v t="ekr.20161124133327.2"><vh>&lt;&lt; define preamble &gt;&gt;</vh></v>
</v>
<v t="ekr.20161204063803.1"><vh>@button make-md-toc</vh>
<v t="ekr.20161204063803.2"><vh>run</vh></v>
<v t="ekr.20161204063803.3"><vh>mak_link</vh></v>
<v t="ekr.20161204063803.4"><vh>make_toc</vh></v>
</v>
</v>
</v>
<v t="ekr.20181019042717.1"><vh>@ignore at-button nodes in LeoSettings.leo</vh>
<v t="ekr.20181019042907.1"><vh>@button check-bindings</vh>
<v t="ekr.20181019042907.2"><vh>defineSetNames</vh></v>
<v t="ekr.20181019042907.3"><vh>doSet</vh></v>
<v t="ekr.20181019042907.4"><vh>doShortcuts</vh></v>
<v t="ekr.20181019042907.5"><vh>checkSets</vh></v>
<v t="ekr.20181019042907.6"><vh>main</vh></v>
</v>
<v t="ekr.20181019042834.1"><vh>@button check-menus-cmds</vh></v>
<v t="ekr.20181019042808.1"><vh>@button check-settings</vh>
<v t="ekr.20181019042808.2"><vh>ctor</vh></v>
<v t="ekr.20181019042808.3"><vh>check &amp; helpers</vh>
<v t="ekr.20181019042808.4"><vh>filter_get_x</vh></v>
<v t="ekr.20181019042808.5"><vh>filter_user_config</vh></v>
</v>
<v t="ekr.20181019042808.6"><vh>error</vh></v>
<v t="ekr.20181019042808.7"><vh>get_commanders</vh></v>
<v t="ekr.20181019042808.8"><vh>get_configs &amp; helpers</vh>
<v t="ekr.20181019042808.9"><vh>get_configs_from_outline &amp; helper</vh>
<v t="ekr.20181019042808.10"><vh>scan_for_configs</vh></v>
</v>
</v>
<v t="ekr.20181019042808.11"><vh>get_settings &amp; helper</vh>
<v t="ekr.20181019042808.12"><vh>is_setting</vh></v>
<v t="ekr.20181019042808.13"><vh>parse_setting</vh></v>
</v>
<v t="ekr.20181019042808.14"><vh>munge</vh></v>
<v t="ekr.20181019042808.15"><vh>run</vh></v>
</v>
</v>
</v>
<v t="ekr.20170303064120.1"><vh>What's new in this file</vh>
<v t="ekr.20181020061554.1"><vh>Curses gui stuff</vh>
<v t="ekr.20181020061600.1"><vh>@test to_key</vh></v>
<v t="ekr.20181020061502.1"><vh>script: verify links (to check curses gui)</vh></v>
</v>
<v t="ekr.20181019042505.1"><vh>Developing &amp; maintaining Leo</vh>
<v t="ekr.20181019042544.1"><vh>script: regularize settings names</vh></v>
<v t="ekr.20181019043251.1"><vh>@ignore at-button nodes in leoPy.leo</vh>
<v t="ekr.20181019043237.1"><vh>@button backup-repo</vh></v>
</v>
<v t="ekr.20181019042717.1"></v>
<v t="ekr.20181020064400.1"><vh>@ignore at-button nodes in leoPlugins.leo</vh>
<v t="ekr.20181020064321.1"><vh>@button make-md-test</vh>
<v t="ekr.20181020064321.2"><vh>&lt;&lt; define preamble &gt;&gt;</vh></v>
</v>
</v>
</v>
<v t="ekr.20170303064128.1"><vh>Leo 5.5</vh>
<v t="ekr.20160923133728.1"><vh>Remove tabs from leo/modes/*.py</vh></v>
<v t="ekr.20161017063308.1"><vh>Find problems in pylint-leo-rc.txt</vh></v>
<v t="ekr.20141105055521.16"><vh>Replace body.x with body.wrapper.x</vh></v>
<v t="ekr.20170120110948.4"><vh>Print Qt color names</vh></v>
<v t="ekr.20170301022829.1"></v>
</v>
<v t="ekr.20170804153254.1"><vh>Leo 5.6</vh>
<v t="ekr.20170411105625.1"><vh>Script: get git branch name using pygit2</vh></v>
<v t="ekr.20170804153229.1"><vh>script: find non-tracing g.unitTesting</vh></v>
</v>
<v t="ekr.20180529105231.1"><vh>Leo 5.7.4</vh>
<v t="ekr.20180529105204.1"><vh>script: get-child-headlines</vh></v>
</v>
</v>
<v t="ekr.20181231155722.1"><vh>Leo 5.8.1</vh>
<v t="ekr.20190117144022.1"><vh>@@button goto-test (Terry Brown)</vh>
<v t="ekr.20190117144022.2"><vh>&lt;&lt; docstring &gt;&gt;</vh></v>
</v>
<v t="ekr.20181231155727.1"><vh>@@command make-vim-node</vh></v>
<v t="ekr.20190106073221.1"><vh>script: find-chains (EKR)</vh>
<v t="ekr.20190106073221.2"><vh>standard methods</vh></v>
</v>
<v t="ekr.20190117144035.3"><vh>script: run pytest in separate process</vh></v>
<v t="ekr.20190117144035.2"><vh>script: stand-alone run pytest</vh></v>
<v t="ekr.20190307044803.1"><vh>script: recursive-clean-lines</vh></v>
</v>
<v t="ekr.20190609162248.1"><vh>Leo 6.0</vh>
<v t="ekr.20190509062342.1"><vh>sqlite3 demo</vh></v>
</v>
</vnodes>
<tnodes>
<t tx="ekr.20061008055616"></t>
<t tx="ekr.20070427110751"></t>
<t tx="ekr.20070615131954"></t>
<t tx="ekr.20111017085134.16069"></t>
<t tx="ekr.20111017085134.16070"># **** Change these as needed ***
import os, sys

tempFileName = g.os_path_abspath(
    g.os_path_join(g.app.testDir,'jythonScript.py'))

if sys.platform == 'win32':
    jython = r'C:\Jython-21\jython.bat'
    command = '%s "%s"' % (jython,tempFileName) 
else:
    jython = r'cd ~/jython-2.1 ; ./jython'
    command = '%s "%s" &amp;' % (jython,tempFileName)

script = g.getScript(c,p).strip()
if not script:
    s = "no script in %s" % p.h
    g.es(s) ; print s
else:
    f = file(tempFileName,'w')
    f.write(script + '\n')
    f.close()
    print command
    os.system(command)
</t>
<t tx="ekr.20111017085134.16071">import os, sys, threading

python = sys.executable
pythonDir,junk = g.os_path_split(python)
pydoc = g.os_path_join(pythonDir,'Lib','pydoc.py')
command = '%s %s -g' % (python,pydoc)

# Execute the command in a separate thread.
def go():
    os.system(command)
    
threading.Thread(target=go).start()
</t>
<t tx="ekr.20111017085134.16072"># This works, but is too slow to be really useful.

count = 0
for p in c.all_unique_positions():
    if p.isDirty():
        c.checkPythonNode (p,suppressErrors=False)
        count += 1
        
g.es('%s nodes checked' % count)
</t>
<t tx="ekr.20111017085134.16074"># Move selected text of the body down one line.

@others

moveLinesDown(c,p)
</t>
<t tx="ekr.20111017085134.16075">def moveLinesDown(c,p):
    
    undoType = 'Move Lines Down'
    head,lines,tail,oldSel,oldYview = c.getBodyLines()
    if not tail or not lines: return
    tail = g.splitLines(tail)[1:]
    lines = '\n'.join(lines) + '\n'
    lines = g.splitLines(lines)
    # Move the lines down.
    lines.insert(0,tail[0])
    tail = tail[1:]
    if not tail: lines.insert(1,'\n')
    # Convert back to strings.
    tail = ''.join(tail)
    lines = ''.join(lines)
    # Adjust selection.
    sel1,sel2 = oldSel
    row,col = sel1.split('.') ; sel1 = '%d.%s' % (int(row)+1,col)
    row,col = sel2.split('.') ; sel2 = '%d.%s' % (int(row)+1,col)
    newSel = sel1,sel2
    c.updateBodyPane(head,lines,tail,undoType,newSel,oldYview)
</t>
<t tx="ekr.20111017085134.16076"># Move selected text of the body up one line.

@others

moveLinesUp(c,p)
</t>
<t tx="ekr.20111017085134.16077">def moveLinesUp(c,p):
    
    undoType = 'Move Lines Up'
    head,lines,tail,oldSel,oldYview = c.getBodyLines()
    if not head or not lines: return
    # A slight adjustment: lines doesn't end in '\n'.
    head = g.splitLines(head)
    lines = '\n'.join(lines) + '\n'
    lines = g.splitLines(lines)
    # Move the lines up.
    lines.append(head[-1])
    head = head[:-1]
    # Convert back to strings.
    head = ''.join(head)
    lines = ''.join(lines)[:-1] # Undo the adjustment above.
    # Adjust selection.
    sel1,sel2 = oldSel
    row,col = sel1.split('.') ; sel1 = '%d.%s' % (int(row)-1,col)
    row,col = sel2.split('.') ; sel2 = '%d.%s' % (int(row)-1,col)
    newSel = sel1,sel2
    c.updateBodyPane(head,lines,tail,undoType,newSel,oldYview)
</t>
<t tx="ekr.20111017085134.16078">'''Analyze external calls in lisp files.'''

import glob
class lispAnalyzer:
    @others

base = '/media/disk/XEmacs/XEmacs-21.4.13/lisp/*.el'
paths = glob.glob(base)
# g.es(g.listToString(paths))
paths = [paths[0]]

x = lispAnalyzer(c,paths)
x.run()
</t>
<t tx="ekr.20111017085134.16079">def __init__ (self,c,paths):

    self.c = c
    self.paths = paths

    # Debugging.
    self.debug = True
    self.trace = False

    # Semantic info.
    self.def_keywords = ('defun','defvar',)
    self.indent_keywords = ('if','prog','prog1','progn','set',)
    self.expr_keywords = ('and','not','or',)

    self.indent = 0 # Indentation of production output.

    # Dispatch dictionary.
    self.dispatchDict = {}
</t>
<t tx="ekr.20111017085134.16080">def run(self):

    fn = self.paths[0]
    f = open(fn)
    s = f.read()
    g.es_print(fn)
    # g.trace(s)
    s = self.stripStrings(s)
    s = self.stripComments(s)
    defs = self.findDefs(s)
    calls = self.findCalls(s,defs)
    calls = self.stripLispIds(calls)
    defs.sort()
    calls.sort()
    g.trace('defs...\n',g.listToString(defs))
    g.trace('calls...\n',g.listToString(calls))
</t>
<t tx="ekr.20111017085134.16081">def findCalls (self,s,defs):

    calls = []
    i = 0
    while i &lt; len(s):
        progress = i
        ch = s[i]
        if ch.isalnum() or ch == u'_':
            j = self.skipId(s,i)
            theId = s[i:j].strip()
            if theId not in defs and theId not in calls:
                calls.append(theId)
            i = j
        else: i += 1
        assert progress &lt; i

    return calls       
</t>
<t tx="ekr.20111017085134.16082">def findDefs (self,s):

    defs = [] ; tag = '(defun'
    i = 0
    while True:
        progress = i
        j = s.find(tag,i)
        if j == -1:
            return defs
        i = j + len(tag)
        j = g.skip_ws(s,i)
        if j &gt; i:
            k = self.skipId(s,j)
            if k &gt; j:
                defs.append(s[j:k])
            i = k
        assert progress &lt; i 
</t>
<t tx="ekr.20111017085134.16083">def stripComments(self,s):

    result = []
    i = 0
    while i &lt; len(s):
        progress = i
        ch = s[i]
        if ch == ';':
            i = self.skipComment(s,i)
        else:
            result.append(ch)
            i += 1
        assert progress &lt; i

    return ''.join(result)
</t>
<t tx="ekr.20111017085134.16084">def stripLispIds (self,aList):

    lispIds = [
        't','f',
        'apply',
        'boundp',
        'car','cons','cdr','consp',
        'eq','equal','eval',
        'lamda','lambda',
        'macro',
        'nil','not','null','numberp',
        'or',
        'unless',
        'vector','vectorp',
        # special forms
        'and',
        'catch',
        'cond',
        'condition-case',
        'defconst',
        'defmacro',
        'defun',
        'defvar',
        'function',
        'if',
        'interactive',
        'let',
        'let*',
        'or',
        'prog1',
        'prog2',
        'progn',
        'quote',
        'save-current-buffer',
        'save-excursion',
        'save-restriction',
        'save-window-excursion',
        'setq',
        'setq-default',
        'track-mouse',
        'unwind-protect',
        'while',
        'with-output-to-temp-buffer',
    ]

    return [z for z in aList if z not in lispIds]
</t>
<t tx="ekr.20111017085134.16085">def stripStrings(self,s):

    result = []
    i = 0
    while i &lt; len(s):
        progress = i
        ch = s[i]
        if ch == '"':
            i = self.skipString(s,i)
        elif ch == "'":
            i = self.skipId(s,i+1)
        else:
            result.append(ch)
            i += 1
        assert progress &lt; i

    return ''.join(result)
</t>
<t tx="ekr.20111017085134.16086">class token:

    '''Representing one elisp syntactic entity,
    with a list of preceding comments.'''

    def __init__ (self,comments,kind,val):
        self.comments = comments[:]
        self.kind = kind
        self.val = val
            # For blocks, a list of tokens.
            # For all other tokens, the spelling of the token.

    def __repr__ (self):
        return '&lt;token kind: %s, val: %s&gt;' % (self.kind,self.val)

    def __str__ (self):
        if self.kind == 'block:':
            return 'block: [snip]'
        elif self.kind == 'string:':
            return '%s%s' % (self.kind,self.val[:20])
        else:
            return '%s%s' % (self.kind,self.val)
</t>
<t tx="ekr.20111017085134.16087">def choose(self,cond,a,b): # warning: evaluates all arguments

    if cond: return a
    else: return b
</t>
<t tx="ekr.20111017085134.16088">def dumpList(self,aList):

    if type(aList) == type([]):
        result = self.dumpListHelper(aList,indent=0)
        return '\n'.join(result)
    else:
        return repr(aList)

def dumpListHelper(self,aList,indent):

    result = []
    leading = ' ' * (4 * indent)

    for z in aList:
        if z is None:
            result.append('%s%s' % (leading,'None'))
        elif z == []:
            result.append('%s%s' % (leading,'[]'))
        elif type(z) == type([]):
            result.append('%s%s' % (leading,'['))
            result.extend(self.dumpListHelper(z,indent+1))
            result.append('%s%s' % (leading,']'))
        elif isinstance(z,self.token):
            if z.kind=='block:':
                result.append('%s%s' % (leading,'block:'))
                result.extend(self.dumpListHelper(z.val,indent+1))
                # result.append('%s%s' % (leading,'block:]'))
            else:
                result.append('%s%s' % (leading,str(z)))
        else:
            result.append('%s%s' % (leading,str(z)))

    return result

listToString = dumpList
</t>
<t tx="ekr.20111017085134.16089"></t>
<t tx="ekr.20111017085134.16090">def parse(self,s):

    # Generate the nodes, including directive and section references.
    return self.scanForest(s)
</t>
<t tx="ekr.20111017085134.16091">def scan(self,s,i):

    '''Scan an elisp expression.'''

    start = i ; end = len(s) ; result = []
    comments = [] ; token = self.token
    # A hack. ignore initial @language lisp
    tag = '@language lisp'
    if i == 0 and s[i:i+len(tag)]==tag:
        i += len(tag)
    while i &lt; end:
        progress = i
        ch = s[i]
        if ch == ';':
            j = self.skipComment(s,i)
            start = i = j
        elif ch == '"':
            j = self.skipString(s,i)
            start = i = j
        elif ch.isalnum() or ch == u'_':
            j = self.skipId(s,i)
            result.append(token(comments,'id:',s[i:j]))
            start = i = j
        elif ch =='(':
            i += 1
            j,aList = self.scan(s,i)
            result.append(token(comments,'block:',aList))
            start = i = j
        elif ch == ')':
            i += 1
            return i,result
        else:
            # if ch == "'": ch = 'quote'
            # if ch not in (' ','\t','\n','\r'):
                # result.append(token(comments,'op:',ch))
            i += 1
        assert progress &lt; i,'i: %d, ch: %s' % (i,repr(s[i]))

    if start &lt; end:
        tail = s[start:end].strip()
        if tail:
            result.append(token(comments,'tail:',tail))
            comment = []
    if comments:
        result.append(token(comments,'trailing-comment:',''))

    return i,result
</t>
<t tx="ekr.20111017085134.16092">def skipComment (self,s,i):

    '''Skip a comment.'''

    while i &lt; len(s):
        if s[i] == '\n':
            break
        i += 1
    return i
</t>
<t tx="ekr.20111017085134.16093">def skipId (self,s,i):

    while i &lt; len(s):
        ch = s[i]
        if ch.isalnum() or ch in ('_','-'):
            i += 1
        else:
            break
    return i
</t>
<t tx="ekr.20111017085134.16094">def skipString(self,s,i):

    """Skip a string literal."""

    assert(s[i] == '"')
    i += 1
    while i &lt; len(s):
        ch = s[i]
        if ch == '\\' : i += 2
        elif ch == '"':
            i += 1 ; break
        else: i += 1

    return i
</t>
<t tx="ekr.20111017085134.16095">def scanForest (self,s):

    i = 0 ; result = []

    while i &lt; len(s):
        progress = i
        i,aList = self.scan(s,i)
        aList and result.extend(aList)
        assert i &gt; progress

    return result


</t>
<t tx="ekr.20111017085134.16096">@ From Richard Deibenkorn:

1. Attempt what is not certain. Certainty may or may not come later. It may then
be a valuable delusion.

2. The pretty, initial position which falls short of completeness is not to be
valued--except as stimulus for further moves.

3. Do search.  But in order to find other than what is looked for.

4. Use and respond to the initial fresh qualities but consider them absolutely
expendable.
</t>
<t tx="ekr.20111017085134.16097">def gen(self,tokens,indent,init=False):

    result = []

    if init: result.append('='*40)

    for token in tokens:
        aList = self.gen_token(token,indent)
        result.extend(aList)

    if init: result.append('-'*40)

    return result

</t>
<t tx="ekr.20111017085134.16098">def gen_token(self,token,indent):

    result = []

    if self.debug:
        if token.kind == 'block:':
            aList = self.gen_block(token,indent)
            result.extend(aList)
        else:
            self.put_token(token,indent,result)
    else:
        if token.kind == 'block:':
            self.gen_block(token,indent)
        else:
            self.put_code_token(token)

    return result
</t>
<t tx="ekr.20111017085134.16099">def gen_block (self,token,indent):

    if not (token and token.val):
        return []

    blockList = token.val
    token2 = blockList[0]
    result = []

    if token2.kind.startswith('id'):
        aList = self.gen_block_id(token2.val,blockList,indent)
    else:
        if self.debug:
            self.put('block...',[],indent,result)
        aList = self.gen(token.val,indent+1)

    result.extend(aList)
    return result
</t>
<t tx="ekr.20111017085134.16100">def gen_block_id (self,theId,tokens,indent):

    result = []

    # Eventually there will be a lookup of the dispatch dict here.
    if theId == 'let':
        aList = self.gen_let(tokens,indent)
    elif theId == 'if':
        aList = self.gen_if(tokens,indent)
    elif theId in self.def_keywords:
        aList = self.gen_def(theId,tokens,indent)
    elif theId in self.indent_keywords:
        self.put('%s...' % (theId),[],indent,result)
        aList = self.gen(tokens[1:],indent+1)
    elif theId in self.expr_keywords:
        aList = self.gen_expr(theId,tokens[1:],indent+1)
    else:
        aList = self.gen_call(theId,tokens[1:],indent)

    result.extend(aList)
    return result
</t>
<t tx="ekr.20111017085134.16101">def gen_call (self,funcId,tokens,indent):

    result = []

    if self.debug:
        self.put('call: %s' % (funcId),[],indent,result)
        for token in tokens:
            aList = self.gen_arg(token,indent+1)
            result.extend(aList)
    else:
        self.put_code_line('%s(' % (funcId))
        for token in tokens:
            self.gen_arg(token,indent+1)
        self.put_code(')')

    return result

</t>
<t tx="ekr.20111017085134.16102">def gen_arg(self,token,indent):

    result = []

    if self.debug:
        if token.kind == 'block:':
            self.put('arg block:...',[],indent,result)
            aList = self.gen_block(token,indent)
            result.extend(aList)
        else:
            self.put_token(token,indent,result)
    else:
        if token.kind == 'block:':
            aList = self.gen_block(token,indent)
            self.put_code(''.join(aList))
        else:
            self.put_code_token(token)

    return result
</t>
<t tx="ekr.20111017085134.16103">def gen_def(self,theId,tokens,indent):

    result = []

    if not tokens or len(tokens) &lt; 3:
        result.append('*** bad def tokens')
        return result

    defToken,idToken = tokens[0:2]
    if idToken.kind != 'id:':
        result.append('*** bad def id')
        return result

    if self.debug:
        self.put(theId,idToken.val,indent,result)
        aList = self.gen(tokens[2:],indent+1)
        result.extend(aList)
    else:
        self.put_code('def %s (' % idToken.val)
        self.gen_token(tokens[2],indent)
        self.put_code('): # end def\n')
        self.indent += 1
        self.gen(tokens[3:],indent+1)
        self.indent -= 1

    return result
</t>
<t tx="ekr.20111017085134.16104">@ if condition then-form else-forms.

If the evaluated condition is non-nil, then-form is evaluated and the result
returned. Otherwise, the else-forms are evaluated in textual order, and the
value of the last one is returned. If condition has the value nil, and no
else-forms are given, if returns nil.
@c

def gen_if (self,tokens,indent):

    # tokens[0]: id:if
    # tokens[1] cond

    for i in xrange(len(tokens)):
        g.trace('tokens[%d]: %s' % (i,self.dumpList(tokens[i])))

    # g.trace(self.dumpList(tokens))

    result = []

    if self.debug:
        self.put('if...',[],indent,result)
        aList = self.gen(tokens[1:],indent+1)
        result.extend(aList)
    else:
        self.put_code('if ')
        self.gen(tokens[1:],indent+1)
        self.put_code(': # end if\n')

    return result
</t>
<t tx="ekr.20111017085134.16105">def gen_then (self,token):

    pass
</t>
<t tx="ekr.20111017085134.16106">def gen_expr (self,theId,aList,indent):

    binops = ('and','or',)
    result = []

    self.put(theId,[],indent,result)
    aList = self.gen(aList,indent+1)

    result.extend(aList)
    return result
</t>
<t tx="ekr.20111017085134.16107">@
(let ((variable value)
      (variable value)
      ...)
  body...)
@c

def gen_let (self,tokens,indent):

    if not tokens: return []
    if len(tokens) != 3:
        g.trace('unusual let')
        result = self.gen(tokens,indent+1)
        return result

    if 0:
        for i in xrange(len(tokens)):
            g.trace('token',i,tokens[i])

    letToken,bindingToken,bodyToken = tokens
    result = []
    self.put('let...',[],indent,result)
    self.put('let-bindings...',[],indent+1,result)
    aList = self.gen_let_bindings(bindingToken,indent+2)
    result.extend(aList)
    self.put('let-block...',[],indent+1,result)
    aList = self.gen_block(bodyToken,indent+2)
    result.extend(aList)
    return result
</t>
<t tx="ekr.20111017085134.16108">def gen_let_bindings (self,token,indent):

    result = []

    if token.kind != 'block:':
        g.trace('unexpected let')
        return result

    for z in token.val:
        if z.kind == 'block:': # one (id,val) pair
            if z.val and len(z.val) == 2:
                token1 = z.val[0]
                token2 = z.val[1]
                self.put('let-id',token1,indent,result)
                self.put('let-val...',[],indent,result)
                if token2.kind == 'block:':
                    aList = self.gen_block(token2,indent+1)
                    result.extend(aList)
                else:
                    #g.trace('no let list')
                    self.put_token(token2,indent+1,result)
            else:
                g.trace('unexpected let 2')

    return result
</t>
<t tx="ekr.20111017085134.16109"></t>
<t tx="ekr.20111017085134.16110">def put (self,kind,val,indent,result):

    '''Append one or more lines of output to result.'''

    leading = '%2d: %s' % (indent,' ' * indent)

    if kind == 'string:':
        val = self.choose(len(val)&gt;20,val[:20]+'..."',val)

    if val:
        s = '%s%s %s' % (leading,str(kind),str(val))
    else:
        s = '%s%s' % (leading,str(kind))

    result.append(s)
</t>
<t tx="ekr.20111017085134.16111">def put_token (self,token,indent,result):

    for z in token.comments:
        self.put('comment:',z,indent,result)

    self.put(token.kind,token.val,indent,result)
</t>
<t tx="ekr.20111017085134.16112">def put_code_line (self,s):

    s2 = '%s%s' % (' '*self.indent,s)
    print s2,

def put_code (self,s):

    print s,
</t>
<t tx="ekr.20111017085134.16113">def put_code_token (self,token):

    if token.kind == 'block:':
        self.put_code('&lt;block&gt;')
    else:
        self.put_code(token.val)

</t>
<t tx="ekr.20111017085134.16114">result = []
firstLevel = p.level()

for p in p.self_and_subtree_iter():
    head = p.moreHead(firstLevel)
    head = g.toEncodedString(head,'ascii',reportErrors=True)
    result.append(head)
    body = p.moreBody() # Inserts escapes for '+' and '-' characters.
    if body:
        body = g.toEncodedString(body,'ascii',reportErrors=True)
        result.append(body)

result = '\n'.join(result) + '\n'
# print result
w = c.frame.body.bodyCtrl
w.clipboard_clear()
w.clipboard_append(result)
</t>
<t tx="ekr.20141105055521.16">@language python

'''
A script to replace body.x with body.wrapper.x for all x in the WrapperAPI.

It is *not undoable* to save massive amounts of memory.
Please run on an already-saved .leo file, and take all other
reasonable precautions.

If replace is False, it will just report the changes to be made.
'''
import leo.core.leoFrame as leoFrame
replace = False
aList = sorted([z for z in dir(leoFrame.WrapperAPI) if not z.startswith('__')])
nodes = 0
for p in c.all_unique_positions():
    s = p.b
    nodes += 1
    found = False
    for target in aList:
        i = 0
        pattern = 'body.' + target
        while True:
            i = s.find(pattern,i)
            if i == -1:
                break
            if g.match_word(s,i,pattern):
                if not found:
                    print('In node: %s' % p.h)
                    found = True
                i1,i2 = g.getLine(s,i)
                if replace:
                    j = i + len('body.')
                    s = s[:j] + 'wrapper.' + s[j:]
                    print(s[i1:i2+len('wrapper.')].rstrip())
                    i += len('wrapper.') + len(pattern)
                else:
                    print(s[i1:i2].rstrip())
                    i += len(pattern)
            else:
                i += len(pattern)
    if found and replace:
        p.b = s
</t>
<t tx="ekr.20141116105945.2"></t>
<t tx="ekr.20141116105945.3">gnx: maphew.20130809155103.2862
</t>
<t tx="ekr.20141116105945.4"></t>
<t tx="ekr.20150302053516.3"></t>
<t tx="ekr.20150508132450.1">g.cls()

class CreateDecorators:
    '''
    A class to create decorators from tables in getPublicCommands.
    This class uses a node called "Found: getPublicCommands".
    
    This @button node must be executed in LeoPy.leo.
    '''
    def __init__(self,c):
        self.c = c
        self.fixups = self.create_fixups()
        self.n = 0
        self.n_fail = 0
    @others

CreateDecorators(c).run()
</t>
<t tx="ekr.20150508132450.2">def create_d(self,lines,publicCommands):
    '''Create a dict. keys are method names; values are command names.'''
    trace = False
    if trace:
        print('')
        g.trace(publicCommands.h)
    d = {}
    for s in lines:
        aList = s.split()
        if len(aList) &gt; 2:
            aList = [aList[0],' '.join(aList[1:])]
        c_name,f_name = aList[0].strip(),aList[1].strip()
        if ' ' not in f_name:
            f_name = f_name.split('.')[-1]
        # if '(' in f_name:
            # f_name = f_name[:f_name.find('(')]
        if trace: g.trace('%45s %s' % (c_name,f_name))
        d [f_name] = c_name
    return d
</t>
<t tx="ekr.20150508132450.3">def create_decorator(self,c_name,f_name,root):
    '''
    Search root for a definition of f_name.
    If found, insert @cmd(f_name) before the definition.
    '''
    # g.trace('%45s %s' % (c_name,f_name))
    found = False
    for p in root.self_and_subtree():
        result = []
        for s in g.splitLines(p.b):
            if g.match_word(s,0,'def ' + f_name):
                if found:
                    g.trace('duplicate def',f_name)
                else:
                    found = True
                    decorator = '@cmd(%s)\n' % (c_name)
                    result.append(decorator)
                    # print('%s%s' % (decorator,s))
            result.append(s)
    return found
</t>
<t tx="ekr.20150508132450.4">def create_decorators(self,d,root):
    '''Create decorators for all items in d in root's tree.'''
    print('\n%s\n' % root.h)
    if root.h in self.fixups:
        roots = []
        aList = self.fixups.get(root.h)
        for root2_h in aList:
            root2 = g.findNodeAnywhere(self.c,root2_h)
            if root2:
                g.trace(root.h,'=====&gt;',root2.h)
                roots.append(root2)
            else:
                g.trace('===== not found',root2_h)
    else:
        roots = [root]
    for f_name in sorted(d.keys()):
        found = False
        for root in roots:
            c_name = d.get(f_name)
            found = self.create_decorator(c_name,f_name,root)
            if found: break
        if not found:
            g.trace('not found',f_name)
            self.n_fail += 1
</t>
<t tx="ekr.20150508132450.5">def create_fixups(self):
    '''
    Return a fixup dict.
    Keys are headlines for classes.
    Values are new headlines of nodes containing the actual class.
    '''
    return {
        'ChapterCommandsClass': ['class ChapterController'],
        'EditCommandsClass': [
            'EditCommandsClass',
            'class Commands',
            'class LeoQtFrame',
            'class LeoBody',
        ],
        'class SearchCommandsClass': ['class LeoFind (LeoFind.py)'],
        'KeyHandlerCommandsClass (add docstrings)': [
            'class KeyHandlerClass',
            'class AutoCompleterClass',
        ]
    }
</t>
<t tx="ekr.20150508132450.6">def find_class(self,p):
    '''Return the position of the class enclosing p.'''
    for p2 in p.parents():
        if p2.h.lower().find('class') &gt; -1 and p2.b.find('class') &gt; -1:
            return p2
    else:
        g.trace('*** no class for p.h')
        return None
</t>
<t tx="ekr.20150508132450.7">def find_next_clone(self,p):
    v = p.v
    p = p.copy()
    p.moveToThreadNext()
    wrapped = False
    while 1:
        # g.trace(p.v,p.h)
        if p and p.v == v:
            break
        elif p:
            p.moveToThreadNext()
        elif wrapped:
            break
        else:
            wrapped = True
            p = c.rootPosition()
    return p
</t>
<t tx="ekr.20150508132450.8">def munge_lines(self,root,publicCommands):
    '''Return munged lines of '''
    # print('')
    # g.trace(root.h)
    s = publicCommands.b
    i,j = s.find('{'),s.find('}')
    s = s[i+1:j]
    # print(s)
    lines = sorted([z.strip() for z in g.splitLines(s) if z.strip()])
    lines = [z for z in lines if not z.startswith('#')]
    lines = [z[:z.find('#')] if z.find('#') &gt; -1 else z for z in lines]
    lines = [z.rstrip().rstrip(',') for z in lines]
    lines = [z[1:] for z in lines]
    lines = [z.replace("':",' ') for z in lines]
    # print('\n'.join(lines))
    self.n += len(lines)
    return lines
</t>
<t tx="ekr.20150508132450.9">def run(self):
    '''Top-level code.'''
    self.n = 0
    found = g.findNodeAnywhere(c,'Found: getPublicCommands')
    assert found
    for child in found.children():
        publicCommands = self.find_next_clone(child)
        root = self.find_class(publicCommands)
        if root:
            lines = self.munge_lines(root,publicCommands)
            d = self.create_d(lines,publicCommands)
            self.create_decorators(d,root)
    print('\n%s commands %s failed' % (self.n,self.n_fail))
</t>
<t tx="ekr.20150525161132.1">r'''The script to test AddTokensToTree class.'''
g.cls()
if c.isChanged():
    c.save()
&lt;&lt; imports &gt;&gt;
project = False
if project:
    aList = leoBeautify.ProjectUtils().project_files('leo')
    aList = ['@file %s' % (g.shortFileName(z).rstrip()) for z in aList]
    aList = aList
    settings_d = {}
else:
    aList = [
        'unit test: leoBeautify.py',
        # '@file leoFileCommands.py',
        # '@file leoBeautify.py',
    ]
    settings_d = {
        'ast_tokens_d': False,
        'stats': True,
        'input_string': True,
        'input_lines': False,
        'input_tokens': False,
        'token_list': False,
        'code_list': False,
        'output_string': True,
    }
assert aList,'no input in %s' % (p.h)
t1 = time.clock()
for h in aList:
    p2 = g.findNodeAnywhere(c,h)
    if p2:
        try:
            leoBeautify.test_LeoTidy(c,h,p2,settings_d)
        except Exception:
            g.es_exception()
if project:
    print('done: %4.2f sec.' % (time.clock()-t1))
</t>
<t tx="ekr.20150525161132.2"># import leo.external.PythonTidy as PythonTidy
import leo.core.leoAst as leoAst
import leo.core.leoBeautify as leoBeautify
import imp
import time
imp.reload(leoAst)
imp.reload(leoBeautify)
# imp.reload(PythonTidy)
</t>
<t tx="ekr.20160123185308.1">'''
Make a stub file in the ~/home directory for every @&lt;file&gt; node in the
selected tree.
'''
import ast
import os
import textwrap
import leo.core.leoGlobals as g
@others
MakeStubFile(c).run(c.p)
</t>
<t tx="ekr.20160123185308.10">def format(self, node):
    '''Format the node (or list of nodes) and its descendants.'''
    self.level = 0
    val = self.visit(node)
    return val and val.strip() or ''
</t>
<t tx="ekr.20160123185308.11">def visit(self, node):
    '''Return the formatted version of an Ast node, or list of Ast nodes.'''
    if isinstance(node, (list, tuple)):
        return ','.join([self.visit(z) for z in node])
    elif node is None:
        return 'None'
    else:
        assert isinstance(node, ast.AST), node.__class__.__name__
        method_name = 'do_' + node.__class__.__name__
        method = getattr(self, method_name)
        s = method(node)
        # pylint: disable=unidiomatic-typecheck
        assert type(s) == type('abc'), type(s)
        return s
</t>
<t tx="ekr.20160123185308.12"></t>
<t tx="ekr.20160123185308.13"># ClassDef(identifier name, expr* bases, stmt* body, expr* decorator_list)

def do_ClassDef(self, node):
    result = []
    name = node.name # Only a plain string is valid.
    bases = [self.visit(z) for z in node.bases] if node.bases else []
    if bases:
        result.append(self.indent('class %s(%s):\n' % (name, ','.join(bases))))
    else:
        result.append(self.indent('class %s:\n' % name))
    for z in node.body:
        self.level += 1
        result.append(self.visit(z))
        self.level -= 1
    return ''.join(result)
</t>
<t tx="ekr.20160123185308.14"># FunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list)

def do_FunctionDef(self, node):
    '''Format a FunctionDef node.'''
    result = []
    if node.decorator_list:
        for z in node.decorator_list:
            result.append('@%s\n' % self.visit(z))
    name = node.name # Only a plain string is valid.
    args = self.visit(node.args) if node.args else ''
    result.append(self.indent('def %s(%s):\n' % (name, args)))
    for z in node.body:
        self.level += 1
        result.append(self.visit(z))
        self.level -= 1
    return ''.join(result)
</t>
<t tx="ekr.20160123185308.15">def do_Interactive(self, node):
    for z in node.body:
        self.visit(z)
</t>
<t tx="ekr.20160123185308.16">def do_Module(self, node):
    assert 'body' in node._fields
    result = ''.join([self.visit(z) for z in node.body])
    return result # 'module:\n%s' % (result)
</t>
<t tx="ekr.20160123185308.17">def do_Lambda(self, node):
    return self.indent('lambda %s: %s' % (
        self.visit(node.args),
        self.visit(node.body)))
</t>
<t tx="ekr.20160123185308.18"></t>
<t tx="ekr.20160123185308.19">def do_Expr(self, node):
    '''An outer expression: must be indented.'''
    return self.indent('%s\n' % self.visit(node.value))
</t>
<t tx="ekr.20160123185308.2">class MakeStubFile:
    '''A class to make Python stub (.pyi) files.'''
    @others
</t>
<t tx="ekr.20160123185308.20">def do_Expression(self, node):
    '''An inner expression: do not indent.'''
    return '%s\n' % self.visit(node.body)
</t>
<t tx="ekr.20160123185308.21">def do_GeneratorExp(self, node):
    elt = self.visit(node.elt) or ''
    gens = [self.visit(z) for z in node.generators]
    gens = [z if z else '&lt;**None**&gt;' for z in gens] ### Kludge: probable bug.
    return '&lt;gen %s for %s&gt;' % (elt, ','.join(gens))
</t>
<t tx="ekr.20160123185308.22">def do_AugLoad(self, node):
    return 'AugLoad'

def do_Del(self, node):
    return 'Del'

def do_Load(self, node):
    return 'Load'

def do_Param(self, node):
    return 'Param'

def do_Store(self, node):
    return 'Store'
</t>
<t tx="ekr.20160123185308.23"></t>
<t tx="ekr.20160123185308.24"># arguments = (expr* args, identifier? vararg, identifier? kwarg, expr* defaults)

def do_arguments(self, node):
    '''Format the arguments node.'''
    kind = self.kind(node)
    assert kind == 'arguments', kind
    args = [self.visit(z) for z in node.args]
    defaults = [self.visit(z) for z in node.defaults]
    # Assign default values to the last args.
    args2 = []
    n_plain = len(args) - len(defaults)
    for i in range(len(args)):
        if i &lt; n_plain:
            args2.append(args[i])
        else:
            args2.append('%s=%s' % (args[i], defaults[i - n_plain]))
    # Now add the vararg and kwarg args.
    name = getattr(node, 'vararg', None)
    if name: args2.append('*' + name)
    name = getattr(node, 'kwarg', None)
    if name: args2.append('**' + name)
    return ','.join(args2)
</t>
<t tx="ekr.20160123185308.25"># Python 3:
# arg = (identifier arg, expr? annotation)

def do_arg(self, node):
    if node.annotation:
        return self.visit(node.annotation)
    else:
        return ''
</t>
<t tx="ekr.20160123185308.26"># Attribute(expr value, identifier attr, expr_context ctx)

def do_Attribute(self, node):
    return '%s.%s' % (
        self.visit(node.value),
        node.attr) # Don't visit node.attr: it is always a string.
</t>
<t tx="ekr.20160123185308.27">def do_Bytes(self, node): # Python 3.x only.
    assert g.isPython3
    return str(node.s)
</t>
<t tx="ekr.20160123185308.28"># Call(expr func, expr* args, keyword* keywords, expr? starargs, expr? kwargs)

def do_Call(self, node):
    # g.trace(node,Utils().dump_ast(node))
    func = self.visit(node.func)
    args = [self.visit(z) for z in node.args]
    for z in node.keywords:
        # Calls f.do_keyword.
        args.append(self.visit(z))
    if getattr(node, 'starargs', None):
        args.append('*%s' % (self.visit(node.starargs)))
    if getattr(node, 'kwargs', None):
        args.append('**%s' % (self.visit(node.kwargs)))
    args = [z for z in args if z] # Kludge: Defensive coding.
    return '%s(%s)' % (func, ','.join(args))
</t>
<t tx="ekr.20160123185308.29"># keyword = (identifier arg, expr value)

def do_keyword(self, node):
    # node.arg is a string.
    value = self.visit(node.value)
    # This is a keyword *arg*, not a Python keyword!
    return '%s=%s' % (node.arg, value)
</t>
<t tx="ekr.20160123185308.3">def __init__(self, c):
    self.c = c
    self.d = self.scan_types_data(c) or self.make_types_dict(c)
        # Keys are strings, values are Type objects.
</t>
<t tx="ekr.20160123185308.30">def do_comprehension(self, node):
    result = []
    name = self.visit(node.target) # A name.
    it = self.visit(node.iter) # An attribute.
    result.append('%s in %s' % (name, it))
    ifs = [self.visit(z) for z in node.ifs]
    if ifs:
        result.append(' if %s' % (''.join(ifs)))
    return ''.join(result)
</t>
<t tx="ekr.20160123185308.31">def do_Dict(self, node):
    result = []
    keys = [self.visit(z) for z in node.keys]
    values = [self.visit(z) for z in node.values]
    if len(keys) == len(values):
        result.append('{\n' if keys else '{')
        items = []
        for i in range(len(keys)):
            items.append('  %s:%s' % (keys[i], values[i]))
        result.append(',\n'.join(items))
        result.append('\n}' if keys else '}')
    else:
        print('Error: f.Dict: len(keys) != len(values)\nkeys: %s\nvals: %s' % (
            repr(keys), repr(values)))
    return ''.join(result)
</t>
<t tx="ekr.20160123185308.32">def do_Ellipsis(self, node):
    return '...'
</t>
<t tx="ekr.20160123185308.33">def do_ExtSlice(self, node):
    return ':'.join([self.visit(z) for z in node.dims])
</t>
<t tx="ekr.20160123185308.34">def do_Index(self, node):
    return self.visit(node.value)
</t>
<t tx="ekr.20160123185308.35">def do_List(self, node):
    # Not used: list context.
    # self.visit(node.ctx)
    elts = [self.visit(z) for z in node.elts]
    elst = [z for z in elts if z] # Defensive.
    return '[%s]' % ','.join(elts)
</t>
<t tx="ekr.20160123185308.36">def do_ListComp(self, node):
    elt = self.visit(node.elt)
    gens = [self.visit(z) for z in node.generators]
    gens = [z if z else '&lt;**None**&gt;' for z in gens] ### Kludge: probable bug.
    return '%s for %s' % (elt, ''.join(gens))
</t>
<t tx="ekr.20160123185308.37">def do_Name(self, node):
    return node.id
</t>
<t tx="ekr.20160123185308.38">def do_Num(self, node):
    return repr(node.n)
</t>
<t tx="ekr.20160123185308.39"># Python 2.x only

def do_Repr(self, node):
    return 'repr(%s)' % self.visit(node.value)
</t>
<t tx="ekr.20160123185308.4">def make_types_dict(self, c):
    '''Return a dict whose keys are names and values are type specs.'''
    return {
        'aList': 'Sequence',
        'aList2': 'Sequence',
        'c': 'Commander',
        'i': 'int',
        'j': 'int',
        'k': 'int',
        'node': 'ast.Ast',
        'p': 'Position',
        's': 'str',
        's2': 'str',
        'v': 'VNode',
    }
</t>
<t tx="ekr.20160123185308.40">def do_Slice(self, node):
    lower, upper, step = '', '', ''
    if getattr(node, 'lower', None) is not None:
        lower = self.visit(node.lower)
    if getattr(node, 'upper', None) is not None:
        upper = self.visit(node.upper)
    if getattr(node, 'step', None) is not None:
        step = self.visit(node.step)
    if step:
        return '%s:%s:%s' % (lower, upper, step)
    else:
        return '%s:%s' % (lower, upper)
</t>
<t tx="ekr.20160123185308.41">def do_Str(self, node):
    '''This represents a string constant.'''
    return repr(node.s)
</t>
<t tx="ekr.20160123185308.42"># Subscript(expr value, slice slice, expr_context ctx)

def do_Subscript(self, node):
    value = self.visit(node.value)
    the_slice = self.visit(node.slice)
    return '%s[%s]' % (value, the_slice)
</t>
<t tx="ekr.20160123185308.43">def do_Tuple(self, node):
    elts = [self.visit(z) for z in node.elts]
    return '(%s)' % ','.join(elts)
</t>
<t tx="ekr.20160123185308.44"></t>
<t tx="ekr.20160123185308.45">def do_BinOp(self, node):
    return '%s%s%s' % (
        self.visit(node.left),
        self.op_name(node.op),
        self.visit(node.right))
</t>
<t tx="ekr.20160123185308.46">def do_BoolOp(self, node):
    op_name = self.op_name(node.op)
    values = [self.visit(z) for z in node.values]
    return op_name.join(values)
</t>
<t tx="ekr.20160123185308.47">def do_Compare(self, node):
    result = []
    lt = self.visit(node.left)
    # ops   = [self.visit(z) for z in node.ops]
    ops = [self.op_name(z) for z in node.ops]
    comps = [self.visit(z) for z in node.comparators]
    result.append(lt)
    if len(ops) == len(comps):
        for i in range(len(ops)):
            result.append('%s%s' % (ops[i], comps[i]))
    else:
        g.trace('ops', repr(ops), 'comparators', repr(comps))
    return ''.join(result)
</t>
<t tx="ekr.20160123185308.48">def do_UnaryOp(self, node):
    return '%s%s' % (
        self.op_name(node.op),
        self.visit(node.operand))
</t>
<t tx="ekr.20160123185308.49">def do_IfExp(self, node):
    return '%s if %s else %s ' % (
        self.visit(node.body),
        self.visit(node.test),
        self.visit(node.orelse))
</t>
<t tx="ekr.20160123185308.5">def scan_types_data(self, c):
    '''Create self.d from @data stub-types nodes.'''
    aList = c.config.getData(
        'stub-types',
        strip_comments=True,
        strip_data=True)
    d = {}
    for s in aList:
        name, value = s.split(None,1)
        d[name.strip()] = value.strip()
    if False:
        for key in sorted(d.keys()):
            g.trace(key, d.get(key))
    return d
</t>
<t tx="ekr.20160123185308.50"></t>
<t tx="ekr.20160123185308.51">def do_Assert(self, node):
    test = self.visit(node.test)
    if getattr(node, 'msg', None):
        message = self.visit(node.msg)
        return self.indent('assert %s, %s' % (test, message))
    else:
        return self.indent('assert %s' % test)
</t>
<t tx="ekr.20160123185308.52">def do_Assign(self, node):
    return self.indent('%s=%s\n' % (
        '='.join([self.visit(z) for z in node.targets]),
        self.visit(node.value)))
</t>
<t tx="ekr.20160123185308.53">def do_AugAssign(self, node):
    return self.indent('%s%s=%s\n' % (
        self.visit(node.target),
        self.op_name(node.op), # Bug fix: 2013/03/08.
        self.visit(node.value)))
</t>
<t tx="ekr.20160123185308.54">def do_Break(self, node):
    return self.indent('break\n')
</t>
<t tx="ekr.20160123185308.55">def do_Continue(self, node):
    return self.indent('continue\n')
</t>
<t tx="ekr.20160123185308.56">def do_Delete(self, node):
    targets = [self.visit(z) for z in node.targets]
    return self.indent('del %s\n' % ','.join(targets))
</t>
<t tx="ekr.20160123185308.57">def do_ExceptHandler(self, node):
    result = []
    result.append(self.indent('except'))
    if getattr(node, 'type', None):
        result.append(' %s' % self.visit(node.type))
    if getattr(node, 'name', None):
        if isinstance(node.name, ast.AST):
            result.append(' as %s' % self.visit(node.name))
        else:
            result.append(' as %s' % node.name) # Python 3.x.
    result.append(':\n')
    for z in node.body:
        self.level += 1
        result.append(self.visit(z))
        self.level -= 1
    return ''.join(result)
</t>
<t tx="ekr.20160123185308.58"># Python 2.x only

def do_Exec(self, node):
    body = self.visit(node.body)
    args = [] # Globals before locals.
    if getattr(node, 'globals', None):
        args.append(self.visit(node.globals))
    if getattr(node, 'locals', None):
        args.append(self.visit(node.locals))
    if args:
        return self.indent('exec %s in %s\n' % (
            body, ','.join(args)))
    else:
        return self.indent('exec %s\n' % (body))
</t>
<t tx="ekr.20160123185308.59">def do_For(self, node):
    result = []
    result.append(self.indent('for %s in %s:\n' % (
        self.visit(node.target),
        self.visit(node.iter))))
    for z in node.body:
        self.level += 1
        result.append(self.visit(z))
        self.level -= 1
    if node.orelse:
        result.append(self.indent('else:\n'))
        for z in node.orelse:
            self.level += 1
            result.append(self.visit(z))
            self.level -= 1
    return ''.join(result)
</t>
<t tx="ekr.20160123185308.6">def make_stub_file(self, p):
    '''Make a stub file in ~/stubs for the @&lt;file&gt; node at p.'''
    import ast
    import leo.core.leoAst as leoAst
    assert p.isAnyAtFileNode()
    c = self.c
    fn = p.anyAtFileNodeName()
    if not fn.endswith('.py'):
        g.es_print('not a python file', fn)
        return
    ### abs_fn = g.os_path_finalize_join(g.app.loadDir, fn)
    abs_fn = g.fullPath(c, p)
    if not g.os_path_exists(abs_fn):
        g.es_print('not found', abs_fn)
        return
    stubs = g.os_path_finalize(g.os_path_expanduser('~/stubs'))
    if g.os_path_exists(stubs):
        base_fn = g.os_path_basename(fn)
        out_fn = g.os_path_finalize_join(stubs,base_fn)
    else:
        g.es_print('not found', stubs)
        return
        # out_fn = g.os_path_finalize_join(g.app.loadDir, fn)
    out_fn = out_fn[:-3] + '.pyi'
    s = open(abs_fn).read()
    node = ast.parse(s,filename=fn,mode='exec')
    leoAst.StubTraverser(self.c, self.d, out_fn).run(node)
</t>
<t tx="ekr.20160123185308.60">def do_Global(self, node):
    return self.indent('global %s\n' % (
        ','.join(node.names)))
</t>
<t tx="ekr.20160123185308.61">def do_If(self, node):
    result = []
    result.append(self.indent('if %s:\n' % (
        self.visit(node.test))))
    for z in node.body:
        self.level += 1
        result.append(self.visit(z))
        self.level -= 1
    if node.orelse:
        result.append(self.indent('else:\n'))
        for z in node.orelse:
            self.level += 1
            result.append(self.visit(z))
            self.level -= 1
    return ''.join(result)
</t>
<t tx="ekr.20160123185308.62">def do_Import(self, node):
    names = []
    for fn, asname in self.get_import_names(node):
        if asname:
            names.append('%s as %s' % (fn, asname))
        else:
            names.append(fn)
    return self.indent('import %s\n' % (
        ','.join(names)))
</t>
<t tx="ekr.20160123185308.63">def get_import_names(self, node):
    '''Return a list of the the full file names in the import statement.'''
    result = []
    for ast2 in node.names:
        if self.kind(ast2) == 'alias':
            data = ast2.name, ast2.asname
            result.append(data)
        else:
            g.trace('unsupported kind in Import.names list', self.kind(ast2))
    return result
</t>
<t tx="ekr.20160123185308.64">def do_ImportFrom(self, node):
    names = []
    for fn, asname in self.get_import_names(node):
        if asname:
            names.append('%s as %s' % (fn, asname))
        else:
            names.append(fn)
    return self.indent('from %s import %s\n' % (
        node.module,
        ','.join(names)))
</t>
<t tx="ekr.20160123185308.65">def do_Pass(self, node):
    return self.indent('pass\n')
</t>
<t tx="ekr.20160123185308.66"># Python 2.x only

def do_Print(self, node):
    vals = []
    for z in node.values:
        vals.append(self.visit(z))
    if getattr(node, 'dest', None):
        vals.append('dest=%s' % self.visit(node.dest))
    if getattr(node, 'nl', None):
        # vals.append('nl=%s' % self.visit(node.nl))
        vals.append('nl=%s' % node.nl)
    return self.indent('print(%s)\n' % (
        ','.join(vals)))
</t>
<t tx="ekr.20160123185308.67">def do_Raise(self, node):
    args = []
    for attr in ('type', 'inst', 'tback'):
        if getattr(node, attr, None) is not None:
            args.append(self.visit(getattr(node, attr)))
    if args:
        return self.indent('raise %s\n' % (
            ','.join(args)))
    else:
        return self.indent('raise\n')
</t>
<t tx="ekr.20160123185308.68">def do_Return(self, node):
    if node.value:
        return self.indent('return %s\n' % (
            self.visit(node.value)))
    else:
        return self.indent('return\n')
</t>
<t tx="ekr.20160123185308.69"># def do_Suite(self,node):
    # for z in node.body:
        # s = self.visit(z)
</t>
<t tx="ekr.20160123185308.7">def run(self, p):
    '''Make stub files for all files in p's tree.'''
    if p.isAnyAtFileNode():
        self.make_stub_file(p)
        return
    # First, look down tree.
    after, p2 = p.nodeAfterTree(), p.firstChild()
    found = False
    while p2 and p != after:
        if p2.isAnyAtFileNode():
            self.make_stub_file(p2)
            p2.moveToNext()
            found = True
        else:
            p2.moveToThreadNext()
    if not found:
        # Look up the tree.
        for p2 in p.parents():
            if p2.isAnyAtFileNode():
                self.make_stub_file(p2)
                break
        else:
            g.es('no files found in tree:', p.h)
</t>
<t tx="ekr.20160123185308.70">def do_TryExcept(self, node):
    result = []
    result.append(self.indent('try:\n'))
    for z in node.body:
        self.level += 1
        result.append(self.visit(z))
        self.level -= 1
    if node.handlers:
        for z in node.handlers:
            result.append(self.visit(z))
    if node.orelse:
        result.append('else:\n')
        for z in node.orelse:
            self.level += 1
            result.append(self.visit(z))
            self.level -= 1
    return ''.join(result)
</t>
<t tx="ekr.20160123185308.71">def do_TryFinally(self, node):
    result = []
    result.append(self.indent('try:\n'))
    for z in node.body:
        self.level += 1
        result.append(self.visit(z))
        self.level -= 1
    result.append(self.indent('finally:\n'))
    for z in node.finalbody:
        self.level += 1
        result.append(self.visit(z))
        self.level -= 1
    return ''.join(result)
</t>
<t tx="ekr.20160123185308.72">def do_While(self, node):
    result = []
    result.append(self.indent('while %s:\n' % (
        self.visit(node.test))))
    for z in node.body:
        self.level += 1
        result.append(self.visit(z))
        self.level -= 1
    if node.orelse:
        result.append('else:\n')
        for z in node.orelse:
            self.level += 1
            result.append(self.visit(z))
            self.level -= 1
    return ''.join(result)
</t>
<t tx="ekr.20160123185308.73">def do_With(self, node):
    result = []
    result.append(self.indent('with '))
    if hasattr(node, 'context_expression'):
        result.append(self.visit(node.context_expresssion))
    vars_list = []
    if hasattr(node, 'optional_vars'):
        try:
            for z in node.optional_vars:
                vars_list.append(self.visit(z))
        except TypeError: # Not iterable.
            vars_list.append(self.visit(node.optional_vars))
    result.append(','.join(vars_list))
    result.append(':\n')
    for z in node.body:
        self.level += 1
        result.append(self.visit(z))
        self.level -= 1
    result.append('\n')
    return ''.join(result)
</t>
<t tx="ekr.20160123185308.74">def do_Yield(self, node):
    if getattr(node, 'value', None):
        return self.indent('yield %s\n' % (
            self.visit(node.value)))
    else:
        return self.indent('yield\n')
</t>
<t tx="ekr.20160123185308.75"></t>
<t tx="ekr.20160123185308.76">def kind(self, node):
    '''Return the name of node's class.'''
    return node.__class__.__name__
</t>
<t tx="ekr.20160123185308.77">def indent(self, s):
    return '%s%s' % (' ' * 4 * self.level, s)
</t>
<t tx="ekr.20160123185308.78">@nobeautify

def op_name (self,node,strict=True):
    '''Return the print name of an operator node.'''
    d = {
        # Binary operators. 
        'Add':       '+',
        'BitAnd':    '&amp;',
        'BitOr':     '|',
        'BitXor':    '^',
        'Div':       '/',
        'FloorDiv':  '//',
        'LShift':    '&lt;&lt;',
        'Mod':       '%',
        'Mult':      '*',
        'Pow':       '**',
        'RShift':    '&gt;&gt;',
        'Sub':       '-',
        # Boolean operators.
        'And':   ' and ',
        'Or':    ' or ',
        # Comparison operators
        'Eq':    '==',
        'Gt':    '&gt;',
        'GtE':   '&gt;=',
        'In':    ' in ',
        'Is':    ' is ',
        'IsNot': ' is not ',
        'Lt':    '&lt;',
        'LtE':   '&lt;=',
        'NotEq': '!=',
        'NotIn': ' not in ',
        # Context operators.
        'AugLoad':  '&lt;AugLoad&gt;',
        'AugStore': '&lt;AugStore&gt;',
        'Del':      '&lt;Del&gt;',
        'Load':     '&lt;Load&gt;',
        'Param':    '&lt;Param&gt;',
        'Store':    '&lt;Store&gt;',
        # Unary operators.
        'Invert':   '~',
        'Not':      ' not ',
        'UAdd':     '+',
        'USub':     '-',
    }
    name = d.get(self.kind(node),'&lt;%s&gt;' % node.__class__.__name__)
    if strict: assert name,self.kind(node)
    return name
</t>
<t tx="ekr.20160123185308.79">class StubFormatter (AstFormatter):
    @others
</t>
<t tx="ekr.20160123185308.8">class AstFormatter:
    '''
    A class to recreate source code from an AST.
    
    This does not have to be perfect, but it should be close.
    
    Also supports optional annotations such as line numbers, file names, etc.
    '''
    # No ctor.
    # pylint: disable=consider-using-enumerate
    @others
</t>
<t tx="ekr.20160123185308.80"># Return generic markers allow better pattern matches.

def do_BoolOp(self, node): # Python 2.x only.
    return 'bool'

def do_Bytes(self, node): # Python 3.x only.
    return 'bytes' # return str(node.s)

def do_Name(self, node):
    return 'bool' if node.id in ('True', 'False') else node.id

def do_Num(self, node):
    return 'number' # return repr(node.n)

def do_Str(self, node):
    '''This represents a string constant.'''
    return 'str' # return repr(node.s)
</t>
<t tx="ekr.20160123185308.81">class StubTraverser (ast.NodeVisitor):
    
    def __init__(self, c, d, output_fn):
        '''Ctor for StubTraverser class.'''
        self.c = c
        self.d = d
        self.format = StubFormatter().format
        self.in_function = False
        self.level = 0
        self.output_file = None
        self.output_fn = output_fn
        self.returns = set()

    @others
</t>
<t tx="ekr.20160123185308.82">def indent(self, s):
    '''Return s, properly indented.'''
    return '%s%s' % (' ' * 4 * self.level, s)

def out(self, s):
    '''Output the string to the console or the file.'''
    if self.output_file:
        self.output_file.write(self.indent(s)+'\n')
    else:
        print(self.indent(s))
</t>
<t tx="ekr.20160123185308.83">def run(self, node):
    '''StubTraverser.run: write the stubs in node's tree to self.output_fn.'''
    c = self.c
    dir_ = g.os_path_dirname(self.output_fn)
    if g.os_path_exists(dir_):
        self.output_file = open(self.output_fn, 'w')
        aList = c.config.getData('stub-prefix')
        if aList:
            for z in aList:
                self.out(z.strip())
        self.visit(node)
        self.output_file.close()
        self.output_file = None
        g.es_print('wrote', self.output_fn)
    else:
        g.es_print('not found:', dir_)

</t>
<t tx="ekr.20160123185308.84"># This is needed only when subclassing from the leoAst.AstFullTraverser class.

# def visit(self, node):
    # '''Visit a *single* ast node.  Visitors are responsible for visiting children!'''
    # assert isinstance(node, ast.AST), node.__class__.__name__
    # method = getattr(self, 'do_' + node.__class__.__name__)
    # method(node)
</t>
<t tx="ekr.20160123185308.85"></t>
<t tx="ekr.20160123185308.86"># ClassDef(identifier name, expr* bases, stmt* body, expr* decorator_list)

def visit_ClassDef(self, node):

    # Format...
    if not node.name.startswith('_'):
        if node.bases:
            s = '(%s)' % ','.join([self.format(z) for z in node.bases])
        else:
            s = ''
        self.out('class %s%s:' % (node.name, s))
    # Visit...
    self.level += 1
    old_in_function = self.in_function
    self.in_function = False
    for z in node.body:
        self.visit(z)
    self.level -= 1
    self.in_function = old_in_function
</t>
<t tx="ekr.20160123185308.87"># FunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list)

def visit_FunctionDef(self, node):
    
    # Do nothing if we are already in a function.
    # We do not generate stubs for inner defs.
    if self.in_function or node.name.startswith('_'):
        return
    # First, visit the function body.
    self.returns = set()
    self.in_function = True
    self.level += 1
    for z in node.body:
        self.visit(z)
    self.level -= 1
    self.in_function = False
    # Format *after* traversing
    self.out('def %s(%s) -&gt; %s: ...' % (
        node.name,
        self.format_arguments(node.args),
        self.format_returns(node)))
</t>
<t tx="ekr.20160123185308.88"># arguments = (expr* args, identifier? vararg, identifier? kwarg, expr* defaults)

def format_arguments(self, node):
    '''
    Format the arguments node.
    Similar to AstFormat.do_arguments, but it is not a visitor!
    '''
    assert isinstance(node,ast.arguments), node
    args = [self.format(z) for z in node.args]
    defaults = [self.format(z) for z in node.defaults]
    # Assign default values to the last args.
    result = []
    n_plain = len(args) - len(defaults)
    # pylint: disable=consider-using-enumerate
    for i in range(len(args)):
        s = self.munge_arg(args[i])
        if i &lt; n_plain:
            result.append(s)
        else:
            result.append('%s=%s' % (s, defaults[i - n_plain]))
    # Now add the vararg and kwarg args.
    name = getattr(node, 'vararg', None)
    if name: result.append('*' + name)
    name = getattr(node, 'kwarg', None)
    if name: result.append('**' + name)
    return ', '.join(result)
</t>
<t tx="ekr.20160123185308.89">def munge_arg(self, s):
    '''Add an annotation for s if possible.'''
    a = self.d.get(s)
    return '%s: %s' % (s, a) if a else s
</t>
<t tx="ekr.20160123185308.9"></t>
<t tx="ekr.20160123185308.90">def format_returns(self, node):
    '''Calculate the return type.'''
    def split(s):
        return '\n     ' + self.indent(s) if len(s) &gt; 30 else s
        
    r = list(self.returns)
    r = [self.format(z) for z in r]
    # if r: g.trace(r)
    if len(r) == 0:
        return 'None'
    if len(r) == 1:
        return split(r[0])
    elif 'None' in r:
        r.remove('None')
        return split('Optional[%s]' % ', '.join(r))
    else:
        # return 'Any'
        s = ', '.join(r)
        if len(s) &gt; 30:
            return ', '.join(['\n    ' + self.indent(z) for z in r])
        else:
            return split(', '.join(r))
</t>
<t tx="ekr.20160123185308.91">def visit_Return(self, node):

    self.returns.add(node.value)
</t>
<t tx="ekr.20160923132656.1">@language python
"""Introspect"""

# By Terry Brown.  Requires Python 2.x.

# https://groups.google.com/forum/#!msg/leo-editor/Qu2HccpC_wc/_ee11jIvAQAJ

import types

sub_mode = 'instance'
# 'instance' or 'class' - controls which, instance or class names,
# are put it a subnode.  'instance class' sub-nodes both.
# '' appends classes after names, not useful.

def classname(thing):
    if hasattr(thing, '__class__'):
        return thing.__class__.__name__
    else:
        return thing.__name__

if not hasattr(c.p.v, '_introspection_target'):
    txt = g.app.gui.runAskOkCancelStringDialog(
        c, "Introspect what", "Introspect what")
    if txt is not None:
        o = eval(txt)
        c.p.v._introspection_target = o
        c.p.h = "%s %s" % (txt, classname(o))

# c.p.deletePositionsInList([i.copy() for i in p.children()])

obj = c.p.v._introspection_target
g.es(classname(obj))

def show_obj(c, obj):

    inames = sorted(dir(obj))
    
    things = {}
    instances = []
    for iname in inames:
        
        if iname.startswith('__'):
            continue
        
        o = getattr(obj, iname)
        cname = classname(o)
        instances.append((iname, o))
        things.setdefault(cname, []).append(instances[-1])

    if 'instance' in sub_mode:
        tnd = c.p.v.insertAsNthChild(0)
        tnd.h = "&lt;by name&gt;"
    else:
        tnd = c.p.v

    instances.sort()
    for iname, o in instances:
        
        if classname(o) == 'position':
            # apparently this collapses the space-time continuum?
            continue
        
        nd = tnd.insertAsLastChild()
        
        if not seen_already(tnd, nd, iname, o):
            nd.h = "%s %s" % (iname, format_type(nd, o))
            nd._introspection_target = o

    if 'class' in sub_mode:
        ttnd = c.p.v.insertAsNthChild(0)
        ttnd.h = "&lt;by class&gt;"
    else:
        ttnd = c.p.v

    for cname in sorted(things):
    
        if len(things[cname]) == 1:
            tnd = ttnd
        else:
            tnd = ttnd.insertAsLastChild()
            tnd.h = "&lt;%s&gt;"%cname
    
        for iname, o in sorted(things[cname]):
            
            if cname == 'position':
                # apparently this collapses the space-time continuum?
                continue
            
            nd = tnd.insertAsLastChild()
            if not seen_already(tnd, nd, iname, o):
                show_child(nd, iname, o)
                nd._introspection_target = o
         
def seen_already(tnd, nd, iname, o):
        
    up = tnd.parents
    while up:
        if (hasattr(up[0], '_introspection_target') and
            up[0]._introspection_target is o):
            break
        up = up[0].parents
    else:
        return False
        
    nd.h = "[%s %s]" % (classname(o), iname)
    pos = c.vnode2position(up[0])
    nd.b = pos.get_UNL(with_file=True, with_proto=True)
    
    return True
            
def show_child(nd, iname, o):
                
    nd._introspection_target = o
    nd.h = "%s %s" % (format_type(nd, o), iname)
    
docable = (
    types.ClassType, types.MethodType, types.UnboundMethodType, 
    types.BuiltinFunctionType, types.BuiltinMethodType,
)
    
def format_type(nd, o):
    
    if isinstance(o, docable):
        if hasattr(o, '__doc__'):
            nd.b = o.__doc__
    
    if isinstance(o, (str, unicode)):
        nd.b = o
        return "%s '%s'" % (classname(o), o[:20])
    elif isinstance(o, bool):
        return "%s %s" % (classname(o), 'T' if o else 'F')
    elif isinstance(o, (int, float)):
        return "%s %s" % (classname(o), o)
    elif isinstance(o, (tuple, list, dict)):
        return "%s %s" % (classname(o), len(o))
    else:
        return classname(o)
    
def show_list(c, list_):
    
    if len(list_) &gt; 100:
        nd = c.p.v.insertAsLastChild()
        nd.h = "&lt;%s of %d items truncated&gt;" % len(list_.__class__.__name__, list_)
        
    if len(list_) == 0:
        nd = c.p.v.insertAsLastChild()
        nd.h = "&lt;%s of 0 items&gt;" % list_.__class__.__name__
        
    for n, i in enumerate(list_[:100]):
        nd = c.p.v.insertAsLastChild()
        show_child(nd, '', i)
        nd.h = "%d: %s" % (n, nd.h)
        nd._introspection_target = i

def show_dict(c, dict_):
    
    if len(dict_) &gt; 100:
        nd = c.p.v.insertAsLastChild()
        nd.h = "&lt;dict of %d items truncated&gt;" % len(dict_)
        
    if len(dict_) == 0:
        nd = c.p.v.insertAsLastChild()
        nd.h = "&lt;dict of 0 items&gt;"
        
    keys = dict_.keys()
    keys.sort()
        
    for k in keys[:100]:
        nd = c.p.v.insertAsLastChild()
        i = dict_[k]
        show_child(nd, '', i)
        nd.h = "%s: %s" % (k, nd.h)
        nd._introspection_target = i

dispatch = {
    list: show_list,
    tuple: show_list,
    dict: show_dict,
}

func = dispatch.get(type(obj), show_obj)

func(c, obj)
   
c.p.expand()
c.redraw()
</t>
<t tx="ekr.20160923133728.1">@language python

import glob
path = g.os_path_join(g.app.loadDir, '..', 'modes', '*.py')
# print(g.os_path_exists(path))
aList = glob.glob(path)
# print('\n'.join(sorted(aList)))
for fn in aList:
    f = open(fn, 'r')
    s1 = f.read()
    f.close()
    s2 = s1.replace('\t', '    ')
    if s1 != s2:
        print('changed: %s' % fn)
        f = open(fn, 'w')
        f.write(s2)
        f.close()
</t>
<t tx="ekr.20161006092435.1">'''Import tab-indented files.'''
g.cls()
if c.isChanged():
    c.save()
separate = True # True: put all lines in separate nodes.
path = r'c:/test/tab_file_test.txt'
if 1:
    # Use the TabImporter class in leoImport.py.
    import leo.core.leoImport as leoImport
    importer = leoImport.TabImporter(c, separate=separate)
    importer.import_files([path])
else:
    # Use a custom class.
    @others
    s = open(path).read()
    last = c.lastTopLevel()
    root = last.insertAfter()
    root.h = path
    TabImporter(c, root=root, separate=separate).scan(s)
    g.es_print('Imported %s' % path)
    c.selectPosition(root)
    root.expand()
    c.redraw()
</t>
<t tx="ekr.20161006092435.2">class TabImporter:
    
    def __init__(self, c, root, separate):
        '''Ctor for the TabImporter class.'''
        self.c = c
        self.stack = []
        self.root = root
        self.separate = separate

    @others
</t>
<t tx="ekr.20161006092435.3">def check(self, lines):
    '''Return False and warn if lines contains mixed leading tabs/blanks.'''
    blanks, tabs = 0, 0
    for s in lines:
        lws = self.lws(s)
        if '\t' in lws: tabs += 1
        if ' ' in lws: blanks += 1
    if tabs and blanks:
        g.es_print('intermixed leading blanks and tabs.')
        return False
    else:
        return True
</t>
<t tx="ekr.20161006092435.4">def dump_stack(self):
    '''Dump the stack, containing (level, p) tuples.'''
    g.trace('==========')
    for i, data in enumerate(self.stack):
        level, p = data
        print('%2s %s %r' % (i, level, p.h))
</t>
<t tx="ekr.20161006092435.5">def lws(self, s):
    '''Return the length of the leading whitespace of s.'''
    for i, ch in enumerate(s):
        if ch not in ' \t':
            return s[:i]
    return s
    
    
</t>
<t tx="ekr.20161006092435.6">def scan(self, s1):
    trace = False and not g.unitTesting
    c, root, separate = self.c, self.root, self.separate
    if not s1.strip() or not root:
        return
    if trace: g.trace('importing to %s' % root.h)
    lines = g.splitLines(s1)
    if self.check(lines):
        self.stack = []
        for s in lines:
            if s.strip() or not separate:
                self.scan_helper(s)
</t>
<t tx="ekr.20161006092435.7">def scan_helper(self, s):
    '''Update the stack as necessary and return (level, parent, stack).'''
    trace = False and not g.unitTesting
    root, separate, stack = self.root, self.separate, self.stack
    if stack:
        level, parent = stack[-1]
    else:
        level, parent = 0, None
    lws = len(self.lws(s))
    if trace:
        g.trace('----- level: %s lws: %s %s' % (level, lws, s.rstrip()))
    h = s.strip()
    if lws == level:
        if separate or not parent:
            # Replace the top of the stack with a new entry.
            if stack:
                stack.pop()
            grand_parent = stack[-1][1] if stack else root
            parent = grand_parent.insertAsLastChild() # lws == level
            parent.h = h
            stack.append((level, parent),)
        elif not parent.h:
            parent.h = h
    elif lws &gt; level:
        # Create a new parent.
        level = lws
        parent = parent.insertAsLastChild()
        parent.h = h
        stack.append((level, parent),)
    else:
        # Find the previous parent.
        if trace: self.dump_stack()
        while stack:
            level2, parent2 = stack.pop()
            if level2 == lws:
                grand_parent = stack[-1][1] if stack else root
                parent = grand_parent.insertAsLastChild() # lws &lt; level
                parent.h = h
                level = lws
                stack.append((level, parent),)
                break
        else:
            level = 0
            parent = root.insertAsLastChild()
            parent.h = h
            stack = [(0, parent),]
    if trace:
        g.trace('DONE: lws: %s level: %s parent: %s' % (lws, level, parent.h))
        self.dump_stack()
    assert parent and parent == stack[-1][1]
        # An important invariant.
    assert level == stack[-1][0], (level, stack[-1][0])
    if not separate:
        parent.b = parent.b + self.undent(level, s)
    return level
</t>
<t tx="ekr.20161006092435.8">def undent(self, level, s):
    '''Unindent all lines of p.b by level.'''
    # g.trace(level, s.rstrip())
    if level &lt;= 0:
        return s
    if s.strip():
        lines = g.splitLines(s)
        ch = lines[0][0]
        assert ch in ' \t', repr(ch)
        # Check that all lines start with the proper lws.
        lws = ch * level
        for s in lines:
            if not s.startswith(lws):
                g.trace('bad indentation: %r' % s)
                return s
        return ''.join([z[len(lws):] for z in lines])
    else:
        return ''
</t>
<t tx="ekr.20161017063308.1">g.cls()
print_all_lines = True
table = [
    r'c:\leo.repo\leo-editor\leo\test\pylint-leo-rc.txt',
    r'c:\leo.repo\leo-editor\leo\test\pylint-leo-rc-ref.txt',
]
for path in table:
    f = open(path)
    s = f.read()
    f.close()
    # print(len(s))
    errors = []
    n = 0
    for i, line in enumerate(g.splitLines(s)):
        try:
            if print_all_lines:
                print('  %3s %4s %s' % (i+1, n, line.rstrip()))
            else:
                g.toUnicode(line)
        except UnicodeEncodeError:
            print('**%3s %4s %s' % (i+1, n, len(line.rstrip())))
            errors.append(i+1)
        n += len(line)
    print('%s error lines: %s' % (g.shortFileName(path), errors))
</t>
<t tx="ekr.20161031130627.1">'''
Undoably converts the word at the cursor to pep8 style throughout a given tree.
Also sets the find text to the new word.
'''
# aTestExample notFoundExample.
import re
# clear()
table = (
    'BLS.new_scan &amp; helpers',
    'BLS.Code generation',
)
@others
Pep8(table, change=True).run()
</t>
<t tx="ekr.20161031130627.2">class Pep8:
    '''
    Convert the word under the cursor to pep8 style in all subtrees in
    table.
    '''
    
    def __init__ (self, table, change=False):
        '''Ctor for Pep8 class.'''
        self.change = change
        self.table = table
        
    @others
</t>
<t tx="ekr.20161031130627.3">def change_all(self, name, new_name, root):
    '''Undoably change name to new_name throughout root's tree.'''
    u = c.undoer
    bunch = u.beforeChangeTree(root)
    found = False
    self.pattern = re.compile(r'\b%s\b' % name)
    for p in root.self_and_subtree():
        found = self.change_headline(name, new_name, p) or found
        found = self.change_body(name, new_name, p) or found
    if found:
        u.afterChangeTree(root, 'pep8', bunch)
    return found
</t>
<t tx="ekr.20161031130627.4">def change_body(self, name, new_name, p):
    indices = []
    for m in self.pattern.finditer(p.b):
        indices.append(str(m.start()))
    if indices:
        n = len(indices)
        g.es_print('%s change%s: %s' % (n, g.plural(n), p.h))
        s = p.b
        for i in reversed(indices):
            i = int(i)
            s = s[:i] + new_name + s[i+len(name):]
        if self.change:
            p.b = s
            p.setDirty()
        else:
            g.es_print(s)
    return bool(indices)
</t>
<t tx="ekr.20161031130627.5">def change_headline(self, name, new_name, p):
    m = self.pattern.search(p.h)
    if m:
        i = m.start()
        s = p.h
        s = s[:i] + new_name + s[i+len(name):]
        if self.change:
            p.h = s
            p.setDirty()
            g.es_print('changed headline', s)
        else:
            g.es_print('headline', s)
    return bool(m)
</t>
<t tx="ekr.20161031130627.6">def get_name(self):
    i, j = c.editCommands.extendToWord(event=None, select=False)
    w = c.frame.body.wrapper
    s = w.getAllText()
    name = s[i:j]
    return name
</t>
<t tx="ekr.20161031130627.7">def run(self):
    # self.clear()
    name = self.get_name()
    new_name = self.to_pep8(name)
    if len(name) &lt; 2:
        g.es_print('name too short:', name)
    elif new_name == name:
        g.es_print('already pep8:', name)
    else:
        g.es_print('%s -&gt; %s' % (name, new_name))
        c.findCommands.ftm.setFindText(new_name)
            # Preload the replacement text.
        found = False
        for target in table:
            root = g.findNodeAnywhere(c, target)
            assert root, target
            found = self.change_all(name, new_name, root) or found
        if found:
            c.redraw()
        else:
            g.es_print('not found:', name)
</t>
<t tx="ekr.20161031130627.8">def to_pep8(self, s):
    
    if len(s) &gt; 1 and s[0].islower() and s.lower() != s:
        result = []
        for ch in s:
            result.append(ch)
            if ch.isupper():
                result.pop()
                result.append('_%s' % (ch.lower()))
        return ''.join(result)
    else:
        return name
</t>
<t tx="ekr.20161031130627.9">def clear():
    g.cls()
    c.k.simulateCommand('clear-log')
</t>
<t tx="ekr.20161120175101.1">'''
Create markdown headers throughout the nearest .md outline.

That is, prepend p.b[0] with markdown section markup, if appriate.
'''
g.cls()
import re
@others

def predicate(p):
    return p.isAnyAtFileNode() and p.h.strip().endswith('.md')

for root in c.all_unique_roots(predicate):
    print(root.h)
    for p in root.self_and_subtree():
        markup(p, root)
c.redraw()

@language python
@tabwidth -4
</t>
<t tx="ekr.20161120175101.2">pattern = re.compile(r'^(#+\s+)(.*)$')

def markup(p, root):
    '''prepend p.b[0] with markdown section markup, if appriate.'''
    root_level = root.level()
    lines = g.splitLines(p.b)
    if len(lines) &lt; 2: return
    line0, line1 = lines[0], lines[1]
    if (
        not p.h.startswith('@md-ignore') and
        not line0.isspace() and # A real first line.
        not line0.startswith('@') and # Not a directive
        line1.isspace() # the next line is blank
    ):
        # Remove existing markup.
        m = pattern.match(line0)
        if m:  line0 = m.group(2) + '\n'
        # Add the correct markup.
        hashes = '#'*(p.level()-root_level+1)
        lines[0] = '%s %s' % (hashes, line0)
    # Ensure a blank line, so as not to interfere with later headers.
    s = ''.join(lines).rstrip()+'\n\n'
    if p.b != s:
        g.es_print('changed: %s' % (p.h))
        p.setDirty()
        c.setChanged(True)
        p.b = s
</t>
<t tx="ekr.20161123085419.1">'''
Create a table of expected headlines in a unit test.

To use this script, select the root of the tree containing the expected
results. After running this, copy the table from the console.
'''
g.cls()
# Proper escapes are tricky.
table = [
    '"%s",' % p.h.replace('\\', '\\\\').replace('"', '\\"')
        for p in c.p.subtree()
]
print("table = (\n    %s\n)" % '\n    '.join(table))
</t>
<t tx="ekr.20161124034654.1">g.cls()
# define constants that describe the new language.
name = 'otl'
    # The name of the file, and the prefix for classes.
language = 'plain'
    # The name of the language, case doesn't matter.
extensions = ['.org',]
    # A list of file extensions supported by this importer.
strict = False
    # True if leading whitespace is particularly significant.
state_ivar = 'self.not_used'
    # 'self.indent' for python, coffeescript.
    # 'self.curlies' for many other languages
    # '(self, curlies, self.parens)' for more complex comparisons
&lt;&lt; define run &amp; helpers &gt;&gt;
run(extensions, language, name, state_ivar)
</t>
<t tx="ekr.20161124034654.10">### Define an override if desired...

if 0: # The base class
    def clean_headline(self, s):
        '''Return a cleaned up headline s.'''
        return s.strip()
        
if 0: # A more complex example, for the C language.
    def clean_headline(self, s):
        '''Return a cleaned up headline s.'''
        import re
        type1 = r'(static|extern)*'
        type2 = r'(void|int|float|double|char)*'
        class_pattern = r'\s*(%s)\s*class\s+(\w+)' % (type1)
        pattern = r'\s*(%s)\s*(%s)\s*(\w+)' % (type1, type2)
        m = re.match(class_pattern, s)
        if m:
            prefix1 = '%s ' % (m.group(1)) if m.group(1) else ''
            return '%sclass %s' % (prefix1, m.group(2))
        m = re.match(pattern, s)
        if m:
            prefix1 = '%s ' % (m.group(1)) if m.group(1) else ''
            prefix2 = '%s ' % (m.group(2)) if m.group(2) else ''
            h = m.group(3) or '&lt;no c function name&gt;'
            return '%s%s%s' % (prefix1, prefix2, h)
        else:
            return s
</t>
<t tx="ekr.20161124034654.11">def clean_nodes(self, parent):
    '''
    Clean all nodes in parent's tree.
    Subclasses override this as desired.
    See perl_i.clean_nodes for an examplle.
    '''
    pass
</t>
<t tx="ekr.20161124034654.12">class {{cap_name}}_ScanState:
    '''A class representing the state of the {{name}} line-oriented scan.'''
    
    def __init__(self, d=None):
        '''{{cap_name}}_ScanState.__init__'''
        if d:
            prev = d.get('prev')
            self.context = prev.context
            ### Adjust these by hand.
            self.curlies = prev.curlies
        else:
            self.context = ''
            ### Adjust these by hand.
            self.curlies = 0

    def __repr__(self):
        '''{{cap_name}}_ScanState.__repr__'''
        ### Adjust these by hand.
        return "{{cap_name}}_ScanState context: %r curlies: %s" % (
            self.context, self.curlies)

    __str__ = __repr__

    @others
</t>
<t tx="ekr.20161124034654.13">def level(self):
    '''{{cap_name}}_ScanState.level.'''
    return {{state_ivar}}

</t>
<t tx="ekr.20161124034654.14">def update(self, data):
    '''
    {{cap_name}}_ScanState.update

    Update the state using the 6-tuple returned by v2_scan_line.
    Return i = data[1]
    '''
    context, i, delta_c, delta_p, delta_s, bs_nl = data
    # All ScanState classes must have a context ivar.
    self.context = context
    self.curlies += delta_c  
    ### Update {{cap_name}}_ScanState ivars
    # self.bs_nl = bs_nl
    # self.parens += delta_p
    # self.squares += delta_s
    return i
</t>
<t tx="ekr.20161124034654.2">@others
</t>
<t tx="ekr.20161124034654.3">def copy_tree(source, root, h):
    '''Copy the source tree to the node after p, with headline h.'''
    p2 = root.insertAfter()
    source.copyTreeFromSelfTo(p2)
    p2.h = h
    return p2
 
</t>
<t tx="ekr.20161124034654.4">def make_substitutions(destination, patterns):
    '''Make all substitutions in the destination tree.'''
    for p in destination.self_and_subtree():
        h = substitute(p.h, patterns)
        if p.h != h:
            # g.trace('CHANGED:', p.h, '==&gt;', h)
            p.h = h
        b = substitute(p.b, patterns)
        if p.b != b:
            # g.trace('CHANGED:', p.b, '==&gt;', b)
            p.b = b
</t>
<t tx="ekr.20161124034654.5">def run(extensions, language, name, state_ivar):
    '''The driver for this script.'''
    patterns = {
        'cap_name': name.capitalize(),
        'extensions': '[%s]' % ', '.join(["'%s'" % (z) for z in extensions]),
        'language': language.lower(),
        'name': name.lower(),
        'strict': 'True' if strict else 'False',
        'state_ivar': state_ivar,
    }
    h = '@button make-importer'
    root = g.findNodeAnywhere(c, h)
    assert root, h
    h = '@@file importers/{{name}}.py'
    source = g.findNodeInTree(c, root, h)
    assert source, h
    destination = copy_tree(source, root, h)
    make_substitutions(destination, patterns)
    c.contractAllHeadlines()
    c.redraw()
</t>
<t tx="ekr.20161124034654.6">def substitute(s, patterns):
    '''Make all substitutions in s.'''
    for pattern in patterns:
        find = '{{%s}}' % pattern
        replace = patterns.get(pattern)
        i = 0
        while i &lt; len(s):
            progress = i
            j = s.find(find, i)
            if j == -1: break
            s = s[:j] + replace + s[j+len(find):]
            i = j+len(replace)
            assert progress &lt; i
    return s
</t>
<t tx="ekr.20161124034654.7">'''The @auto importer for the {{name}} language.'''
import leo.plugins.importers.linescanner as linescanner
Importer = linescanner.Importer
@others
importer_dict = {
    'class': {{cap_name}}_Importer,
    'extensions': {{extensions}},
}
@language python
@tabwidth -4


</t>
<t tx="ekr.20161124034654.8">class {{cap_name}}_Importer(Importer):
    '''The importer for the {{name}} lanuage.'''

    def __init__(self, importCommands, atAuto):
        '''{{cap_name}}_Importer.__init__'''
        # Init the base class.
        Importer.__init__(self,
            importCommands,
            atAuto = atAuto,
            language = '{{language}}',
            state_class = {{cap_name}}_ScanState,
            strict = {{strict}},
        )
        
    @others
</t>
<t tx="ekr.20161124034654.9"># These can be overridden in subclasses.
</t>
<t tx="ekr.20161124133327.1">'''Make an @test node for the importer whose name is given.'''
name = 'javascript'
d = g.app.permanentScriptDict
tag = 'make_test_%s_n' % name
n = d.get(tag, 0) + 1
d [tag] = n
d = {'n': n, 'name': name}
&lt;&lt; define preamble &gt;&gt;
p = c.lastTopLevel().insertAfter()
p.b = preamble
p.h = '@test %(name)s importer-%(n)s' % d
c.redraw()
c.selectPosition(p)
c.bodyWantsFocusNow()
c.frame.body.wrapper.setInsertPoint(len(p.b))
</t>
<t tx="ekr.20161124133327.2">preamble = '''\
if 1:
    # The preamble...
    g.cls()
    if c.isChanged(): c.save()
    import imp
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.%(name)s as %(name)s
    imp.reload(linescanner)
    imp.reload(%(name)s)
# insert test for %(name)s here.
''' % d
</t>
<t tx="ekr.20161204063803.1">'''Make a markdown table of contents from an @auto-md node.'''
g.cls()
if c.isChanged(): c.save()

class Controller:
    '''Controller class for @button md-toc.'''
    @others
    
if 0:
    h = '@auto-md importers.md'
    p = g.findTopLevelNode(c, h)
    assert p, h
else:
    p = c.p
Controller().run(p)
@language python
@tabwidth -4
</t>
<t tx="ekr.20161204063803.2">def run(self, p):
    '''The driver for @button md-toc.'''
    if p.h.startswith('@auto-md '): #  or p.h.endswith('.md'):
        last = c.lastTopLevel()
        self.root = last.insertAfter()
        self.root.h = 'Table of contents'
        self.make_toc(p)
    else:
        print('must be an @auto-md node or an x.md node: %s' % p.h)
</t>
<t tx="ekr.20161204063803.3">def make_link(self, s):
    '''Return the markdown link for s.'''
    result = []
    for ch in s.lower():
        if ch in ' -':
            result.append('-')
        elif ch.isalnum():
            result.append(ch)
        else:
            pass
    return ''.join(result)
</t>
<t tx="ekr.20161204063803.4">def make_toc(self, p):
    '''Create the toc in self.root.b.'''
    result, stack = [], []
    prefix = p.h.lstrip('@auto-md').strip()
    for p in p.subtree():
        level = p.level() - self.root.level()
        assert level &gt; 0
        if len(stack) &lt; level:
            stack.append(1)
        else:
            stack = stack[:level]
        n = stack[-1]
        stack[-1] = n+1
        indent = ' '*4*(level-1)
        line = '%s%s. [%s](%s#%s)\n' % (
            indent, n, p.h, prefix, self.make_link(p.h))
        result.append(line)
    if 0:
        g.trace(p.h)
        g.printList(result)
    else:
        self.root.b = ''.join(result)
    c.redraw()
</t>
<t tx="ekr.20161206070406.1">gnx: ekr.20161206070323.1
</t>
<t tx="ekr.20161206090903.1">gnx: ekr.20161206070323.2
unl: &lt;&lt; what c2py does &gt;&gt;
gnx: ekr.20161206070323.3
unl: &lt;&lt; theory of operation &gt;&gt;
gnx: ekr.20161206070323.4
unl: &lt;&lt; specify user types &gt;&gt;
gnx: ekr.20161206070323.5
unl: &lt;&lt; define testData &gt;&gt;
gnx: ekr.20161206070323.6
unl: speedTest
gnx: ekr.20161206070323.7
unl: leo1to2
gnx: ekr.20161206070323.8
unl: leo1to2--&gt;leo1to2
gnx: ekr.20161206070323.9
unl: leo1to2--&gt;convertLeo1to2
gnx: ekr.20161206070323.10
unl: leo1to2--&gt;convertStringLeo1to2
gnx: ekr.20161206070323.11
unl: leo1to2--&gt;convertCodeList1to2
gnx: ekr.20161206070323.12
unl: c2py entry points
gnx: ekr.20161206070323.13
unl: c2py entry points--&gt;convertCurrentTree
gnx: ekr.20161206070323.14
unl: c2py entry points--&gt;convertLeoTree
gnx: ekr.20161206070323.15
unl: c2py entry points--&gt;convertCFileToPython
gnx: ekr.20161206070323.16
unl: convertCStringToPython &amp; helpers (top level)
gnx: ekr.20161206070323.17
unl: convertCStringToPython &amp; helpers (top level)--&gt;convertCodeList (main pattern function)
gnx: ekr.20161206070323.18
unl: convertCStringToPython &amp; helpers (top level)--&gt;convertDocList
gnx: ekr.20161206070323.19
unl: convertCStringToPython &amp; helpers (top level)--&gt;skipDocPart
gnx: ekr.20161206070323.20
unl: convertCStringToPython &amp; helpers (top level)--&gt;skipCodePart
gnx: ekr.20161206070323.21
unl: Scanning &amp; Replacing...
gnx: ekr.20161206070323.22
unl: Scanning &amp; Replacing...--&gt;convertLeadingBlanks
gnx: ekr.20161206070323.23
unl: Scanning &amp; Replacing...--&gt;mungeAllFunctions
gnx: ekr.20161206070323.24
unl: Scanning &amp; Replacing...--&gt;mungeAllFunctions--&gt;handlePossibleFunctionHeader
gnx: ekr.20161206070323.25
unl: Scanning &amp; Replacing...--&gt;mungeAllFunctions--&gt;massageFunctionArgs
gnx: ekr.20161206070323.26
unl: Scanning &amp; Replacing...--&gt;mungeAllFunctions--&gt;massageFunctionHead (sets gClassName)
gnx: ekr.20161206070323.27
unl: Scanning &amp; Replacing...--&gt;mungeAllFunctions--&gt;massageFunctionBody
gnx: ekr.20161206070323.28
unl: Scanning &amp; Replacing...--&gt;mungeAllFunctions--&gt;massageFunctionBody--&gt;massageIvars
gnx: ekr.20161206070323.29
unl: Scanning &amp; Replacing...--&gt;mungeAllFunctions--&gt;massageFunctionBody--&gt;removeCasts
gnx: ekr.20161206070323.30
unl: Scanning &amp; Replacing...--&gt;mungeAllFunctions--&gt;massageFunctionBody--&gt;removeTypeNames
gnx: ekr.20161206070323.31
unl: Scanning &amp; Replacing...--&gt;handleAllKeywords
gnx: ekr.20161206070323.32
unl: Scanning &amp; Replacing...--&gt;handleAllKeywords--&gt;handleKeyword
gnx: ekr.20161206070323.33
unl: Scanning &amp; Replacing...--&gt;isX...
gnx: ekr.20161206070323.34
unl: Scanning &amp; Replacing...--&gt;isX...--&gt;isWs and isWOrNl
gnx: ekr.20161206070323.35
unl: Scanning &amp; Replacing...--&gt;isX...--&gt;isSectionDef
gnx: ekr.20161206070323.36
unl: Scanning &amp; Replacing...--&gt;isX...--&gt;isStringOrComment
gnx: ekr.20161206070323.37
unl: Scanning &amp; Replacing...--&gt;find... &amp; match...
gnx: ekr.20161206070323.38
unl: Scanning &amp; Replacing...--&gt;find... &amp; match...--&gt;findInCode
gnx: ekr.20161206070323.39
unl: Scanning &amp; Replacing...--&gt;find... &amp; match...--&gt;findInList
gnx: ekr.20161206070323.40
unl: Scanning &amp; Replacing...--&gt;find... &amp; match...--&gt;match
gnx: ekr.20161206070323.41
unl: Scanning &amp; Replacing...--&gt;find... &amp; match...--&gt;matchWord
gnx: ekr.20161206070323.42
unl: Scanning &amp; Replacing...--&gt;remove...
gnx: ekr.20161206070323.43
unl: Scanning &amp; Replacing...--&gt;remove...--&gt;removeAllCComments
gnx: ekr.20161206070323.44
unl: Scanning &amp; Replacing...--&gt;remove...--&gt;removeAllCSentinels
gnx: ekr.20161206070323.45
unl: Scanning &amp; Replacing...--&gt;remove...--&gt;removeAllPythonComments
gnx: ekr.20161206070323.46
unl: Scanning &amp; Replacing...--&gt;remove...--&gt;removeAllPythonSentinels
gnx: ekr.20161206070323.47
unl: Scanning &amp; Replacing...--&gt;remove...--&gt;removeAtRoot
gnx: ekr.20161206070323.48
unl: Scanning &amp; Replacing...--&gt;remove...--&gt;removeBlankLines
gnx: ekr.20161206070323.49
unl: Scanning &amp; Replacing...--&gt;remove...--&gt;removeExcessWs
gnx: ekr.20161206070323.50
unl: Scanning &amp; Replacing...--&gt;remove...--&gt;removeExcessWs--&gt;removeExessWsFromLine
gnx: ekr.20161206070323.51
unl: Scanning &amp; Replacing...--&gt;remove...--&gt;removeLeadingAtCode
gnx: ekr.20161206070323.52
unl: Scanning &amp; Replacing...--&gt;remove...--&gt;removeMatchingBrackets
gnx: ekr.20161206070323.53
unl: Scanning &amp; Replacing...--&gt;remove...--&gt;removeSemicolonsAtEndOfLines
gnx: ekr.20161206070323.54
unl: Scanning &amp; Replacing...--&gt;remove...--&gt;removeTrailingWs
gnx: ekr.20161206070323.55
unl: Scanning &amp; Replacing...--&gt;replace... &amp; safeReplace
gnx: ekr.20161206070323.56
unl: Scanning &amp; Replacing...--&gt;replace... &amp; safeReplace--&gt;replace
gnx: ekr.20161206070323.57
unl: Scanning &amp; Replacing...--&gt;replace... &amp; safeReplace--&gt;replaceComments
gnx: ekr.20161206070323.58
unl: Scanning &amp; Replacing...--&gt;replace... &amp; safeReplace--&gt;replaceSectionDefs
gnx: ekr.20161206070323.59
unl: Scanning &amp; Replacing...--&gt;replace... &amp; safeReplace--&gt;safeReplace
gnx: ekr.20161206070323.60
unl: Scanning &amp; Replacing...--&gt;skip... &amp; prev...
gnx: ekr.20161206070323.61
unl: Scanning &amp; Replacing...--&gt;skip... &amp; prev...--&gt;prevNonWsChar and prevNonWsOrNlChar
gnx: ekr.20161206070323.62
unl: Scanning &amp; Replacing...--&gt;skip... &amp; prev...--&gt;skipCBlockComment
gnx: ekr.20161206070323.63
unl: Scanning &amp; Replacing...--&gt;skip... &amp; prev...--&gt;skipPastLine
gnx: ekr.20161206070323.64
unl: Scanning &amp; Replacing...--&gt;skip... &amp; prev...--&gt;skipPastWord
gnx: ekr.20161206070323.65
unl: Scanning &amp; Replacing...--&gt;skip... &amp; prev...--&gt;skipString
gnx: ekr.20161206070323.66
unl: Scanning &amp; Replacing...--&gt;skip... &amp; prev...--&gt;skipStringOrComment
gnx: ekr.20161206070323.67
unl: Scanning &amp; Replacing...--&gt;skip... &amp; prev...--&gt;skipToMatchingBracket
gnx: ekr.20161206070323.68
unl: Scanning &amp; Replacing...--&gt;skip... &amp; prev...--&gt;skipWs and skipWsAndNl
gnx: ekr.20161206070323.69
unl: Scanning &amp; Replacing...--&gt;stringToList &amp; listToString
gnx: ekr.20161206070323.70
unl: Scanning &amp; Replacing...--&gt;stringToList &amp; listToString--&gt;stringToList
gnx: ekr.20161206070323.71
unl: Scanning &amp; Replacing...--&gt;stringToList &amp; listToString--&gt;listToString
</t>
<t tx="ekr.20170120110015.1"></t>
<t tx="ekr.20170120110948.4"># This script prints the list of known Qt names. Qt seems to ignore case.
from leo.core.leoQt import QtGui
aList = sorted([g.u(z) for z in QtGui.QColor().colorNames()])
print('\n'.join(aList))
</t>
<t tx="ekr.20170211083757.1">if c.isChanged(): c.save()
&lt;&lt; imports &gt;&gt;
&lt;&lt; class MyDemo &gt;&gt;
# Don't use @others here.
# The *same* command/key binding calls both demo-start and demo.next.
try:
    if getattr(g.app, 'demo', None):
        g.app.demo.next()
    else:
        g.cls()
        c.frame.log.clearTab('Log')
        g.es_print('Starting MyDemo')
        c.k.demoNextKey = c.k.strokeFromSetting('Ctrl-9')
            # Tell k.masterKeyHandler to process Ctrl-9 immediately.
            # Binding demo-next in a setting does *not* work.
        demo = MyDemo(c)
        p = g.findNodeAnywhere(c, '@button Demo @key=Ctrl-9')
        script_tree = g.findNodeInTree(c, p, 'demo-script')
        demo.start(script_tree, auto_run=True)
except Exception:
    g.app.demo = None
    raise
</t>
<t tx="ekr.20170211083757.10"># Create, move, promote, demote, hoist.
demo.retain(Title('Leo is a full featured outliner.'))
demo.wait(1.0)
###
demo.insert_node('a new node', keys=True, speed=10.0)
###
c.moveOutlineRight()
###
# demo.end() # Test of early exit.
###
demo.insert_node('another headline')
###
demo.insert_node('yet another node')
###
p = g.findNodeInTree(c, demo.root, 'a new node')
assert p, 'a new node'
c.selectPosition(p)
demo.wait(0.25)
###
c.demote()
demo.wait(1.0)
###
demo.delete_retained_widgets()
</t>
<t tx="ekr.20170211083757.11"># The body pane shows the text of the selected outline node.
</t>
<t tx="ekr.20170211083757.12"># Section refs, @others, @file
</t>
<t tx="ekr.20170211083757.13"></t>
<t tx="ekr.20170211083757.14"># Callout('Thanks for watching')
###
# demo.next()
</t>
<t tx="ekr.20170211083757.2">from leo.core.leoQt import QtGui
import leo.plugins.demo as demo_module
import imp
imp.reload(demo_module)
</t>
<t tx="ekr.20170211083757.3">class MyDemo (demo_module.Demo):
    
    @others
</t>
<t tx="ekr.20170211083757.4">def setup(self, p=None):
    c = self.c
    self.end_on_exception = True # Good for debugging.
    self.delta = 10
    demo.set_text_delta(10)
    self.geometry1 = self.get_top_geometry()
    p = g.findNodeAnywhere(c, 'Demo Area')
    self.root = p.copy() if p else None
    if p:
        p.expand()
        c.selectPosition(p)
    # c.frame.equalSizedPanes()
    c.redraw()
    self.set_youtube_position()
</t>
<t tx="ekr.20170211083757.5">def setup_script(self):
    self.delete_widgets()
</t>
<t tx="ekr.20170211083757.6">def teardown(self):
    c = self.c
    self.delete_all_widgets()
    # self.set_top_geometry(self.geometry1)
    if hasattr(self, 'delta') and self.delta &gt; 0:
        self.set_text_delta(-self.delta)
    if self.root and c.positionExists(self.root, trace=False):
        self.root.deleteAllChildren()
    p = c.lastTopLevel()
    p.expand()
    c.selectPosition(p)
    c.redraw()
</t>
<t tx="ekr.20170211083757.7">def teardown_script(self):
    if self.auto_run:
        # Default wait.
        self.wait(0.5)
</t>
<t tx="ekr.20170211083757.8">@language python
</t>
<t tx="ekr.20170211083757.9">Callout('Hello. This tutorial introduces Leo')
# Callout("First, I'll increase the text size for easier viewing")
# demo.next(wait=1.0)
</t>
<t tx="ekr.20170212105552.1">@language python
'''Create intro slides for screen shots.'''
# The *same* command/key binding calls both demo-start and demo.next.
if c.isChanged():
    c.save()
&lt;&lt; imports &gt;&gt;
#
# Do NOT use @others here.
#
&lt;&lt; class IntroSlides &gt;&gt;
&lt;&lt; main &gt;&gt;
if getattr(g.app, 'demo', None):
    g.app.demo.next()
else:
    demo = IntroSlides(c)
    main(c, demo,
        auto_run=False,
        hoist_node = "Leo's Main Window",
        script_name='intro-slides-script')
</t>
<t tx="ekr.20170212105552.10">@language python
</t>
<t tx="ekr.20170212105552.11">Callout("This is Leo's main window")

###
demo.next()
</t>
<t tx="ekr.20170212105552.2">from leo.core.leoQt import QtGui
import leo.plugins.demo as demo_module
# import imp
# imp.reload(demo_module)
</t>
<t tx="ekr.20170212105552.3">class IntroSlides (demo_module.Demo):
    
    @others
</t>
<t tx="ekr.20170212105552.4">def setup(self, p=None):
    c = self.c
    self.end_on_exception = True # Good for debugging.
    self.delta = 0
    demo.set_text_delta(self.delta)
    # self.set_youtube_position()
    if hasattr(self, 'hoist_node'):
        c.selectPosition(self.hoist_node)
        c.hoist()
    c.redraw()
</t>
<t tx="ekr.20170212105552.5">def setup_script(self):
    self.delete_widgets()
</t>
<t tx="ekr.20170212105552.6">def teardown(self):
    c = self.c
    self.delete_all_widgets()
    if self.delta &gt; 0:
        self.set_text_delta(-self.delta)
    if self.hoist_node:
        c.selectPosition(self.hoist_node)
        c.dehoist()
    c.redraw()
</t>
<t tx="ekr.20170212105552.7">def teardown_script(self):
    if self.auto_run:
        # Default wait.
        self.wait(0.5)
</t>
<t tx="ekr.20170212105552.8">def main(c, demo, script_name, auto_run=False, hoist_node=None):
    g.cls()
    k = c.k
    class_name = demo.__class__.__name__
    c.frame.log.clearTab('Log')
    g.es_print('Starting', class_name)
    k.demoNextKey = k.strokeFromSetting('Ctrl-9')
        # Tell k.masterKeyHandler to process Ctrl-9 immediately.
        # Binding demo-next in a setting does *not* work.
    h = '@button %s @key=Ctrl-9' % class_name
    p = g.findNodeAnywhere(c, h)
    assert p, h
    script_tree = g.findNodeInTree(c, p, script_name)
    assert script_tree, repr(script_name)
    demo.hoist_node = hoist_node and g.findNodeInTree(c, p, hoist_node)
    demo.start(script_tree, auto_run=auto_run)
</t>
<t tx="ekr.20170212105552.9"></t>
<t tx="ekr.20170225023738.1">'''
Web development involves endless reloading of pages.  It gets old really fast.

This @button allows me to fiddle with the .css and javascript for mod_http
itself without having to reload Leo. Oh so useful. I can just change the
settings in myLeoSettings and hit Ctrl-p to re-execute the button. 

This trick doesn't work when changing mod_http.py itself, but most of
the work involved the css and javascript.

This pattern could be useful to other web developers.
'''

# g.cls()
if c.isChanged():
    c.save()
# *Always* use the most current settings.
g.app.pluginsController.loadOnePlugin(
    'leo.plugins.mod_http',
    tag='open0',
    verbose=False)
g.app.loadManager.readGlobalSettingsFiles()
g.handleUrl('http://127.0.0.1:8130/leoPlugins.leo')
</t>
<t tx="ekr.20170301014329.1">'''Cycle syntax coloring when there are multiple @langauge directives in a node.'''
# Original by Terry Brown, Revised by EKR.
while not p.isRoot():
    if p.b.strip().startswith("@language "):
        lines = g.splitLines(p.b)
        words = lines[0].split()
        # Careful: don't treat comments as languages.
        if len(words) &gt; 2 and words[2][0].isalpha():
            # Cycle the languages on line 1.
            line0 = '%s %s %s\n' % (words[0], ' '.join(words[2:]), words[1])
            p.b = line0 + ''.join(lines[1:])
            c.selectVisBack()
            c.selectVisNext()
            break
    p.moveToParent()
else:
    g.es("No ambiguous @language directive found")
</t>
<t tx="ekr.20170301022829.1"># Please don't ignore these :-)
</t>
<t tx="ekr.20170301023612.1">'''
    insert / update headlines as comments in @nosent R code
    https://gist.github.com/tbnorth/eb913fcab82f6a4b37734b5156543308
'''
# By Terry Brown
headlines = []
for nd in p.self_and_subtree():
    if nd.h and nd.h[0] == '@' or nd.b and nd.b[0] == '@':
        continue
    headlines.append(nd.h)
    lines = nd.b.split('\n')
    if lines and lines[0].startswith('### '):
        del lines[0]
    if lines and lines[0].strip():
        lines[0: 0] = [""]
    lines[0: 0] = [
        "### %s %s" % (nd.h, "#" * (80 - len(nd.h) - 5)),
    ]
    if '.coffee' in p.h:
        lines[0: 0] = [""]
    if lines[-1].strip():
        lines.append("")
    if lines[-2].strip():
        lines.append("")
    b = '\n'.join(lines)
    if nd.b != b:
        nd.b = b
g.es('\n'.join(headlines))
c.redraw()
</t>
<t tx="ekr.20170303064120.1"></t>
<t tx="ekr.20170303064128.1"></t>
<t tx="ekr.20170411105625.1"># http://stackoverflow.com/questions/26134026/
# how-to-get-the-current-checked-out-git-branch-name-through-pygit2

import pygit2
path = g.os_path_finalize_join(g.app.loadDir, '..', '..')
repo = pygit2.Repository(path)
head = repo.head
# print(head)
print(head.name)
print(head.shorthand)
</t>
<t tx="ekr.20170804153229.1">def predicate(p):
    return any([
        s.find('g.unitTesting') &gt; -1 and s.find('trace') == -1
            for s in g.splitLines(p.b)
        ])
        
p = c.cloneFindByPredicate(
    generator = c.all_unique_positions,
    predicate = predicate,
    flatten = True,
)
p.h = 'clone-find-predicate: real use of g.unitTesting'
p.b = '%s nodes' % p.numberOfChildren()
</t>
<t tx="ekr.20170804153254.1"></t>
<t tx="ekr.20180529105204.1">s = p.b
for child in p.children():
    s = s + '\n- ' + child.h
p.b = s</t>
<t tx="ekr.20180529105231.1"></t>
<t tx="ekr.20181019042505.1"></t>
<t tx="ekr.20181019042544.1"># Replace underscore by - in settings names.
# See https://github.com/leo-editor/leo-editor/issues/993
g.cls()
import re
kinds = (
    'Bool', 'Color', 'Data',
    'Directory', 'Encoding', # Not found.
    'Float', 'Int',
    'Path', 'Ratio', # Not found.
    'String',
)
for kind in kinds:
    print('===== %s =====\n' % kind)
    pat = re.compile(r"get%s\s*\([\'\"]([\w_]+)[\'\"][,)]" % kind)
    for p in c.all_positions():
        s = p.b
        i, found = 0, False
        while True:
            m = pat.search(s[i:])
            if not m:
                break
            start, end = m.start(1), m.end(1)
            all = s[i+m.start(0):i+m.end(0)]
            word = s[i+start:i+end]
            if '_' in word:
                found = True
                print('')
                print('-----', p.h)
                print(all)
                s = s[:i+start] + word.replace('_','-') + s[i+end:]
                print(s[i+m.start(0):i+m.end(0)])
            i += end
        if found:
            assert p.b != s, p.h
            # print(s)
            p.b = s
            p.v.setDirty()
c.setChanged()
c.redraw()     
</t>
<t tx="ekr.20181019042717.1"></t>
<t tx="ekr.20181019042808.1">'''Check the consistency of all settings.'''
# https://github.com/leo-editor/leo-editor/issues/993

class Controller:
    @others

Controller(c).run()
</t>
<t tx="ekr.20181019042808.10">def scan_for_configs(self, p, d):
    '''
    Scan the body text of p, finding all calls to config.getX.
    
    This code does not know about `if 0`, but does know about comments.
    '''
    kinds = (
        'getBool', 'getColor', 'getInt', 'getFloat',
        # '@font', # special case.
        'getPath', 'getRatio', 'getString',
    )
    i, s = 0, p.b
    while i &lt; len(s):
        progress = i
        ch = s[i]
        if (
            ch == '@' and
            (g.match(s, i, '@ ') or g.match(s, i, '@\n')) and
            (i == 0 or s[i - 1] == '\n')
        ):
            # Skip the @doc part.
            i = s.find('\n@c', i)
            if i == -1: break
        elif ch == '#':
            i = g.skip_to_end_of_line(s, i)
        elif ch in ('"', "'"):
            i = g.skip_python_string(s, i, verbose=False)
        elif ch == '_' or ch.isalpha():
            j = g.skip_id(s, i)
            kind = s[i: j]
            if kind in kinds:
                # We have found a call to getBool, etc.
                i = g.skip_ws(s, j)
                if g.match(s, i, '('):
                    i = g.skip_ws(s, i + 1)
                    if g.match(s, i, '"') or g.match(s, i, "'"):
                        j = g.skip_string(s, i)
                        name = s[i + 1: j - 1]
                        aList = d.get(kind, [])
                        if name not in aList:
                            aList.append(name)
                        d[kind] = aList
                else:
                    j = i
            i = j
        else:
            i += 1
        assert progress &lt; i
    return d
</t>
<t tx="ekr.20181019042808.11">def get_settings(self):
    '''Return a dict containing a representation
    of all settings in leoSettings.leo.
    '''
    trace = False
    c, d = self.settings, {}
    print('scanning: %s' % c.shortFileName())
    settings_node = g.findNodeAnywhere(c, '@settings')
    if not settings_node:
        return self.error('no @settings node')
    for p in settings_node.subtree():
        if self.is_setting(p):
            kind, name = self.parse_setting(p)
            if name:
                # name = self.munge(name)
                aList = d.get(kind, [])
                if name not in aList:
                    aList.append(name)
                d[kind] = aList
            else:
                self.error('no name for %s' % (kind))
    if trace:
        keys = list(d.keys())
        for key in sorted(keys):
            print(key)
            aList = d.get(key)
            for name in sorted(aList):
                print('  ' + name)
    return d
</t>
<t tx="ekr.20181019042808.12">def is_setting(self, p):
    # For now, these are enough
    table = (
        '@bool', '@color', '@int', '@float',
        # '@font', # special case.
        '@ratio', '@path', '@string',
    )
    for s in table:
        if g.match_word(p.h, 0, s):
            return True
    return False
</t>
<t tx="ekr.20181019042808.13">def parse_setting(self, p):
    s = p.h
    assert s[0] == '@'
    i = g.skip_id(s, 1)
    kind = s[: i]
    assert kind
    i = g.skip_ws(s, i)
    j = g.skip_id(s, i, chars='-')
    name = s[i: j]
    return kind, name
</t>
<t tx="ekr.20181019042808.14">def munge(self, s):
    '''Return the canonicalized name for settings and arguments to c.config.getX.'''
    return g.toUnicode(s.replace('-', '').replace('_', '').lower())
</t>
<t tx="ekr.20181019042808.15">def run(self):
    g.cls()
    self.get_commanders()
    configs = self.get_configs()
    settings = self.get_settings()
    if self.errors == 0:
        self.check(configs, settings)
    g.trace('done')
</t>
<t tx="ekr.20181019042808.2">def __init__(self, c):
    self.c = c
    self.errors = 0
    # Commanders...
    self.core = None # leoPy.leo.
    self.plugins = None # leoPlugins.leo.
    self.settings = None # leoSettings.leo.
</t>
<t tx="ekr.20181019042808.3">def check(self, configs_d, settings_d):
    munge = self.munge
    table = ('Bool', 'Int', 'Float', 'Ratio', 'Path', 'String',) # 'Color', 'Font',
    #
    # Print missing user settings...
    for kind in table:
        config_key = 'get%s' % kind
        settings_key = '@%s' % kind.lower()
        configs = configs_d.get(config_key, [])
        settings = settings_d.get(settings_key, [])
        m_configs = [munge(z) for z in configs]
        m_settings = [munge(z) for z in settings]
        missing = set([z for z in m_configs if not z in m_settings])
        aList = [z for z in missing if self.filter_user_config(z)]
        if aList:
            print('\nmissing %s %s settings...\n' % (len(aList), settings_key))
            for z in sorted(aList):
                aList2 = [z2 for z2 in configs if munge(z2) == munge(z)]
                g.printObj(aList2)
    #
    # Print missing calls to c.config.getX...
    for kind in table:
        config_key = 'get%s' % kind
        settings_key = '@%s' % kind.lower()
        configs = configs_d.get(config_key, [])
        settings = settings_d.get(settings_key, [])
        m_configs = [munge(z) for z in configs]
        m_settings = [munge(z) for z in settings]
        missing = set([z for z in m_settings if not z in m_configs])
        aList = [z for z in missing if self.filter_get_x(z)]
        if aList:
            print('\nmissing %s config.%s calls...\n' % (len(aList), config_key))
            for z in sorted(aList):
                aList2 = [z2 for z2 in settings if munge(z2) == munge(z)]
                g.printObj(aList2)
</t>
<t tx="ekr.20181019042808.4">def filter_get_x(self, setting):
    '''
    Return False if we can safely ignore a missing call to config.get(setting).
    
    Everything here is a hack. Some are bigger than others.
    '''
    munge = self.munge
    #
    # These *ivars* are set by the GlobalConfigManager class.
    # There *should* be settings for all of these, despite missing config.get calls.
    table = (
        # encodingIvarsDict...
            "default_at_auto_file_encoding",
            "default_derived_file_encoding",
            "new_leo_file_encoding",
        # defaultsDict...
            "color_directives_in_plain_text",
            "output_doc_chunks",
            "page_width",
            "tab_width",
            "tangle_outputs_header",
            "target_language",
            "underline_undefined_section_names",
        # ivarsDict
            "at_root_bodies_start_in_doc_mode",
            "create_nonexistent_directories",
            "output_initial_comment",
            "output_newline",
            "page_width",
            "read_only",
            "redirect_execute_script_output_to_log_pane",
            "relative_path_base_directory",
            "remove_sentinels_extension",
            "save_clears_undo_buffer",
            "stylesheet",
            "tab_width",
            "target_language",
            "trailing_body_newlines",
            "use_plugins",
            "undo_granularity",
            "write_strips_blank_lines",
    )
    table = [munge(z) for z in table]
    if setting in table:
        return False
    #
    # unitTest.leo tests test-darwin-setting and test-win32-setting
    if setting in ('testdarwinsetting', 'testwin32setting'):
        return False
    #
    # Stylesheets use these settings.
    for pattern in (
        'bg', 'border', 'color', 'fg', 'font',
        'leogreen', 'leoyello',
        'margin', 'padding', 'relief',
        'solarized', 'split-bar', 'text-foreground', 'tree-image',
    ):
        if setting.find(munge(pattern)) &gt; -1:
            return False
    #
    # These plugins/use settings in non-standard ways.
    if setting.startswith(
        ('bookmarks', 'datenodes', 'http', 'opml',
        'rst3', 'todo', 'vim', 'zodb'),
    ):
        return False
    #
    # Find settings are defined in non-standard ways.
    for pattern in (
        'batch', 'change-text', 'find-text', 'ignore-case',
        'mark-changes', 'mark-finds', 'node-only', 'pattern-match',
        'reverse', 'search-body', 'search-headline', 'suboutline-only',
        'whole-word', 'wrap',
    ):
        if setting == munge(pattern):
            return False
    #
    # Issue a warning.
    return True
</t>
<t tx="ekr.20181019042808.5">def filter_user_config(self, setting):
    '''
    Return False if we can safely ignore a setting that does not exist in leoSettings.leo.
    
    Everything here is a hack. Some are bigger than others.
    '''
    munge = self.munge
    #
    # unitTest.leo tests test-darwin-setting and test-win32-setting
    if setting in ('testdarwinsetting', 'testwin32setting'):
        return False
    #
    # The calls to config.get* are commented out in the code,
    # but get_configs isn't smart enough to know that.
    for ignore in (
        'auto-set-ignore-case',
        'find-def-creates-clones',
        'qt-rich-text-zoom-in',
        'theme-name',
        'pytest-path', # In a (disabled) @button node
        'leo-to-html-%s', # Loads multiple settings from an .ini file.
    ):
        if setting == munge(ignore):
            return False
    #
    # Stylesheets use these settings.
    # It would be a major project to discover what settings
    # are actually used in the present stylesheet.
    for pattern in (
        'bg', 'border', 'color', 'fg', 'font',
        'leogreen', 'leoyello',
        'margin', 'padding', 'relief',
        'solarized', 'split-bar', 'text-foreground', 'tree-image',
    ):
        if setting.find(munge(pattern)) &gt; -1:
            return False
    #
    # These plugins use settings in non-standard ways.
    if setting.startswith(
        ('activepath', 'bookmarks', 'datenodes', 'http', 'opml',
        'rst3', 'todo', 'vim', 'zodb'),
    ):
        return False
    #
    # Find settings are defined in non-standard ways.
    for pattern in (
        'batch', 'change-text', 'find-text', 'ignore-case',
        'mark-changes', 'mark-finds', 'node-only', 'pattern-match',
        'reverse', 'search-body', 'search-headline', 'suboutline-only',
        'whole-word', 'wrap',
    ):
        if setting == munge(pattern):
            return False
    #
    # Tangle/untagle settings are deprecated and imo should not exist.
    for pattern in (
        'output-doc-flag', 'tangle-batch-flag',
        'untangle-batch-flag', 'use-header-flag',
    ):
        if setting == munge(pattern):
            return False
    #
    # Issue a warning.
    return True
</t>
<t tx="ekr.20181019042808.6">def error(self, s):
    print(s)
    self.errors += 1
</t>
<t tx="ekr.20181019042808.7">def get_commanders(self):
    '''Open files as needed and set the commander ivars.'''

    def open_commander(fn):
        c = g.openWithFileName(fn, old_c=self.c, gui=g.app.nullGui)
        if not c:
            self.error('not found: %s' % fn)
        return c

    join, loadDir = g.os_path_join, g.app.loadDir
    self.core = open_commander(join(loadDir, '..', 'core', 'leoPy.leo'))
        # Opening LeoPyRef.leo would be slower.
    self.plugins = open_commander(join(loadDir, '..', 'plugins', 'leoPlugins.leo'))
    self.settings = open_commander(join(loadDir, '..', 'config', 'leoSettings.leo'))
</t>
<t tx="ekr.20181019042808.8">def get_configs(self):
    '''
    Return a dict containing a representation of all calls to x.config.getX.
    '''
    d = {}
    for c in (self.core, self.plugins):
        print('scanning: %s' % c.shortFileName())
        self.get_configs_from_outline(c, d)
    return d
</t>
<t tx="ekr.20181019042808.9">def get_configs_from_outline(self, c, d):
    '''
    Scan the outline for all calls to x.config.getX and add items to d.
    '''
    for p in c.all_positions():
        self.scan_for_configs(p, d)
    return d
</t>
<t tx="ekr.20181019042834.1">'''Check that all commands mentioned in the @menus tree actually exist.'''

def checkMenu (p):
    for p2 in p.subtree_iter():
        if p2.h.startswith('@item'):
            checkItem(p.h,p2)

def checkItem (menuName,p):
    h = p.h[len('@item'):].replace('&amp;','').replace('*','').strip()
    if h != '-' and h not in c.commandsDict:
        print ('command not found: %s: %s' % (menuName,p.h))

menus = g.findNodeAnywhere(c,'@menus')
assert menus, 'no @menus tree'
for p in menus.subtree_iter():
    if p.h.startswith('@menu'):
        checkMenu(p.copy())

print ('done')
</t>
<t tx="ekr.20181019042907.1">'''Check for commands that exist in some but not all key- binding sets.'''
g.cls()
import leo.core.leoConfig as leoConfig
# import leo.core.leoTest as leoTest
parser = leoConfig.SettingsTreeParser(c)
# Add these as required to handle commands defined by plugins.
optionalCommandPrefixes = ['group-operations']
optionalCommandNames = [
    # These are the command names as defined by plugins.
    # LeoSlideShows.leo defines buttons whose commands do not end in '-command'.
    'next-slide-command','next-slide-show-command',
    'prev-slide-command','prev-slide-show-command',
    # The ipython plugin.
    'start-ipython','get-ipython-results','push-to-ipython',
    # The viewrendered plugin.
    'vr-toggle',
]
setNames = []
setsDict = {} # keys are set names, values are dicts of command names.
shortcutsDict = {}
@others
main()
</t>
<t tx="ekr.20181019042907.2">def defineSetNames():
    global setNames
    if 1:
        setNames = []
        for p in c.allNodes_iter():
            h = p.headString()
            if h.startswith('@keys'):
                h = h[5:].strip()
                if h not in setNames:
                    setNames.append(h)
        g.es('Found these sets...')
        for setName in setNames:
            g.es_print('  %s' % str(setName))
    else:
        setNames = [
            'Default Emacs shortcuts',
            'Legacy Leo bindings',
            'Legacy Leo shortcuts with important Emacs bindings',
            'No bindings',
            'EKR bindings: a mix',
            'EKR bindings: Mode-oriented',
        ]

    setNames.sort()
</t>
<t tx="ekr.20181019042907.3">def doSet(p,name):

    global shortcutsDict

    shortcutsDict = {}

    for p in p.subtree_iter():
        if p.headString().startswith('@shortcuts'):
            doShortcuts(p,name)
</t>
<t tx="ekr.20181019042907.4">def doShortcuts(p,setName):

    global parser,setsDict,shortcutsDict

    d = setsDict.get(setName,{})
    s = p.bodyString()
    lines = g.splitLines(s)
    for line in lines:
        line = line.strip()
        if line and not line.startswith('#'):
            commandName,si = parser.parseShortcutLine('test',line)
            if not si:
                g.es_print('In %s:\nmissing "=" in shortcut line:%s' % (
                    p.headString(),repr(line)),color='red')
            else:
                # Having multiple shortcuts for a command if fine,
                # But having multiple commands for a shortcut is not.
                shortcut = si.stroke
                pane = si.pane
                if shortcut not in (None,'None','none'):
                    aList = shortcutsDict.get(shortcut,[])
                    if aList:
                        for commandName2,pane2 in aList:
                            if pane == pane2:
                                g.es_print('duplicate shortcut %s in set %s: previous command: %s' % (
                                    shortcut,setName,commandName2),color='red')
                        else:
                            aList.append((commandName,pane),)
                    else:
                        shortcutsDict [shortcut] = [(commandName,pane),]

                data = d.get(commandName)
                if data:
                    shortcut2,pane2 = data
                    if shortcut == shortcut2 and pane == pane2:
                        g.es_print('duplicate %s in set %s' % (
                            commandName,setName),color='red')
                else:
                    data = shortcut,pane
                    d[commandName] = data

    setsDict[setName] = d
</t>
<t tx="ekr.20181019042907.5">def checkSets():

    global setNames, optionalCommandPrefixes, optionalCommandNames
    # Compute the union of all the command names.
    allNames = {}
    for setName in setNames:
        d = setsDict.get(setName)
        if d:
            for key in d.keys():
                allNames[key] = key
        else:
            g.es_print('No setsDict for %s' % (repr(setName)),color='red')
    keys = sorted(allNames.keys())
    # Warn about missing names.
    for setName in ('No bindings',): # setNames:
        d = setsDict.get(setName)
        if d:
            for key in keys:
                if key not in ('none','None',None) and key not in d.keys():
                    # Don't warn about missing 'enter-xxx-mode' commands.
                    if (
                        not (key.startswith('enter-') and key.endswith('-mode')) and
                        not (key.startswith('press-') and key.endswith('-button'))
                    ):
                        g.es_print('%s is missing %-35s = None' % (setName,repr(key)))
        else:
            g.es_print("'@keys No bindings' not found",color='blue')
    # Warn about undefined commands.
    for key in keys:
        if not c.commandsDict.get(key):
            ok = False
            # full-command and quick command are weird special cases.
            if key not in ('None',None,'full-command','quick-command'):
                # Don't warn about missing 'enter-xxx-mode' commands.
                if key.startswith('enter-') and key.endswith('-mode'):
                    ok = True
                elif key.startswith('press-') and key.endswith('-button'):
                    ok = True
                for prefix in optionalCommandPrefixes:
                    if key.startswith(prefix):
                        ok = True
                for optionalCommand in optionalCommandNames:
                    if key == optionalCommand:
                        ok = True
                if not ok:
                    g.es_print('Undefined command name: %s' % (key))
</t>
<t tx="ekr.20181019042907.6">def main ():

    global setNames
    defineSetNames()

    g.es_print('-' * 40)
    seen = {}
    for p in c.allNodes_iter():
        h = p.headString()
        if h.startswith('@keys'):
            h = h[5:].strip()
            if not seen.get(h):
                seen[h] = True
                doSet(p,h)
    checkSets()
    g.es('Check Bindings done')
</t>
<t tx="ekr.20181019043237.1">@language python
import os
import subprocess
import sys
import time
win = sys.platform.startswith('win')
old_dir = g.os_path_abspath('.')
if win:
    new_dir = r'C:\leo.repo\leo-editor'
    path = r'C:\Users\edreamleo\Backup'
else:
    new_dir = '/home/edward/leo.repo/leo-editor'
    path = '/home/edward/Backup'
assert g.os_path_exists(new_dir), repr(new_dir)
assert g.os_path_exists(path), repr(path)
stamp = time.strftime("%Y%m%d-%H%M%S")
fn = g.os_path_finalize_join(path, 'leo-bundle-all-%s' % (stamp))
bundle_command = 'git bundle create %s --all' % fn
print(bundle_command)
os.chdir(new_dir)
# os.system(bundle_command)
proc = subprocess.Popen(bundle_command, shell=True)
proc.wait()
os.chdir(old_dir)
print('done! wrote %s' % fn)
</t>
<t tx="ekr.20181019043251.1"></t>
<t tx="ekr.20181020061502.1">g.cls()
table = (
    ('c.frame', c.frame),
    ('c.frame.tree', c.frame.tree),
    ('c.frame.tree.canvas', c.frame.tree.canvas),
    ('c.frame.tree.treeWidget', c.frame.tree.treeWidget), # Qt only.
    ('-----', None),
    ('c.frame.body', c.frame.body),
    ('c.frame.body.widget', c.frame.body.widget),
    ('c.frame.body.wrapper', c.frame.body.wrapper),
)
for tag, obj in table:
    print('%30s %s' % (tag, obj.__class__.__name__ if obj else ''))
</t>
<t tx="ekr.20181020061554.1"></t>
<t tx="ekr.20181020061600.1"># Tests curses gui.
g.cls()
import imp
import curses.ascii as a
import leo.plugins.cursesGui2 as cursesGui2
imp.reload(cursesGui2)
h = cursesGui2.CursesKeyHandler()
for i in range(255):
    char, shortcut = h.to_key(i)
    s = a.controlnames[i] if i &lt;= 32 else a.unctrl(i)
    print('%3s %-8s %-7r %r' % (i, s, char, shortcut))
for i in range(352):
    if i &gt; 255:
        char, shortcut = h.to_key(i)
        # s = a.controlnames[i] if i &lt;= 32 else a.unctrl(i)
        print('%3s %-7r %r' % (i, char, shortcut))
</t>
<t tx="ekr.20181020064321.1">'''Make an @test node for the importer whose name is given.'''
name = 'markdown'
d = g.app.permanentScriptDict
tag = 'make_test_%s_n' % name
n = d.get(tag, 0) + 1
d [tag] = n
d = {'cap_name': name.capitalize(), 'n': n, 'name': name}
&lt;&lt; define preamble &gt;&gt;
p = c.lastTopLevel().insertAfter()
p.b = preamble
p.h = '@test %(name)s importer-%(n)s' % d
c.redraw()
c.selectPosition(p)
c.bodyWantsFocusNow()
c.frame.body.wrapper.setInsertPoint(len(p.b))
</t>
<t tx="ekr.20181020064321.2">preamble = '''\
if 1:
    # The preamble...
    g.cls()
    if c.isChanged(): c.save()
    import leo.plugins.importers.linescanner as linescanner
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.markdown as markdown
    # Reload all.
    import imp
    imp.reload(linescanner)
    imp.reload(markdown)
    imp.reload(leoImport)
    ic = leoImport.LeoImportCommands(c)
    x = markdown.Markdown_Importer(ic, atAuto=False)   
# insert test for %(name)s here.
''' % d
</t>
<t tx="ekr.20181020064400.1"></t>
<t tx="ekr.20181231155722.1"></t>
<t tx="ekr.20181231155727.1">'''
Select from the cursor to a line starting with "endfunction",
then do 'extract' command.
'''
s = c.p.b
w = c.frame.body.wrapper
i = w.getInsertPoint()
target = '\nendfunction'
j = s.find(target, i)
if j &gt; -1:
    j += len(target)
    j = g.skip_line(s,j)
    w.setSelectionRange(i, j, insert=i)
    c.frame.body.wrapper.setSelectionRange(i, j, insert=i)
    c.k.simulateCommand('extract')
</t>
<t tx="ekr.20190106073221.1">'''To be run in leoPy.leo: find Leo's important chains.'''
g.cls()
import re
bases, chains = ['self.', 'c.', 'g.'], set()
id_pat = r'\w[\w0-9]*'

def get_lines():
    '''Return a list of lines containing chains.'''
    pat = re.compile(r'%s\.%s\.\w' % (id_pat, id_pat))
    lines = set()
    for p in c.all_unique_positions():
        for line in g.splitLines(p.b):
            if pat.search(line):
                lines.add(line)
    lines = list(lines)
    print('%s lines' % len(lines))
    return lines
    
s = ''.join(get_lines())

def find_chains(base):
    chains.add(base)
    base = base.replace('.', r'\.')
    pat = re.compile(r'\b(%s%s\.)(%s)' % (base, id_pat, id_pat))
    for m in re.finditer(pat, s) or []:
        chain, follow = m.group(1), m.group(2)
        if chain not in chains: # and follow not in methods:
            bases.append(chain)
            chains.add(chain)
            
def munge_chains(chains):
    '''Remove simple ivars and use c instead of self.c.'''
    chains = [z.rstrip('.') for z in sorted(list(chains))]
    chains = sorted(list(set([z[5:] if z.startswith('self.c.') else z for z in chains])))
        # Replace self.c with c.
    chains = [z for z in chains if z.count('.') &gt; 0]
    chains = [z for z in chains if not z.startswith('self.') or z.count('.') &gt; 1]
    return chains

while bases:
    find_chains(bases.pop())
chains = munge_chains(chains)
g.printObj(chains, tag='%s chains' % len(chains))</t>
<t tx="ekr.20190106073221.2">if 0:
    methods = (
        'copy', # general method.
        'add', # set methods
        'append', 'extend', 'insert', 'pop', 'remove', 'split', 'sort', # list methods
        'get',  'keys', 'items', 'values', # dict methods.
        'endswith', 'finditer', 'lower', 'strip', 'lstrip', 'rstrip', 'startswith', 'upper',
            # string methods.
    )</t>
<t tx="ekr.20190117144022.1">&lt;&lt; docstring &gt;&gt;
import re
tests_path = c.config.getString("pytest-path") or "tests"
info = {}

# climb up node tree collecting info.
for nd in p.self_and_parents_iter():
    definition = re.match(r'def ([^( ]*)\(', p.b)
    if definition and not info.get('func'):
        info['func'] = definition.group(1)
    if nd.h.endswith('.py') and not info.get('file'):
        info['file'] = nd.h.split()[-1].split('/')[-1]
    if nd.h.strip('/') == tests_path.strip('/'):
        info['test'] = True

nd = p.copy()

if info.get('test'):  # we started in these tests folder
    while nd.h.strip('/') != tests_path.strip('/'):
        nd = nd.parent()  # climb up to code folder
    if info.get('file'):  # find or create code file
        target = info['file'][5:]
        for sib in nd.self_and_siblings():
            if sib.h.endswith(target):
                nd = sib
                break
        else:
            nd = nd.insertAfter()
            nd.h = '@auto ' + target
    if info.get('func'):  # find or create code function
        target = info['func'][5:]
        for child in nd.children():
            if child.h == target:
                nd = child
                break
        else:
            nd = nd.insertAsLastChild()
            nd.h = target
            nd.b = 'def'  # let abbreviation build the rest
else:  # we stared in the code folder
    if info.get('func'):  # get up to file level (weak, could be deeper)
        nd.moveToParent()
    for sib in nd.self_and_siblings():  # find or create tests folder
        if sib.h.strip('/') == tests_path.strip('/'):
            nd = sib
            break
    else:
        nd = nd.insertBefore()
        nd.h = "/%s/" % tests_path.strip('/')
        nd.b = "@path %s" % tests_path
    if info.get('file'):  # find or create test file
        target = 'test_' + info['file']
        for child in nd.children():
            if child.h.endswith(target):
                nd = child
                break
        else:
            nd = nd.insertAsLastChild()
            nd.h = "@auto %s" % target
            nd.b = "import %s\n\n@others\n" % info['file'].replace('.py', '')
    if info.get('func'):  # find or create test function
        target = 'test_' + info['func']
        for child in nd.children():
            if child.h == target:
                nd = child
                break
        else:
            nd = nd.insertAsLastChild()
            nd.h = target
            nd.b = "def %s():\n    assert %s. == 'otters'\n" % (
                target, info['file'].replace('.py', ''))

c.selectPosition(nd)
c.redraw()
</t>
<t tx="ekr.20190117144022.2">"""
switch between code and test

If you're using `pytest`[1] and use the layout described below, this @button code
will jump you between a function and its test, creating the (test)function
if it doesn't already exist.  Also the tests folder and `test_foo.py` file.
It assumes use of the `active_path` plugin which headlines folders as
`/myFolder/` with body text `@path myFolder`.

This code is very heavy on assumptions, but a lot of those are driven
by pytest default behavior.

To run tests, use `python -m pytest`, as anything involving py.test is
deprecated, and for some reason `pytest` finds files but runs no tests.
Tested with pytest 3.x, note Ubuntu 16.04 seems to still be on 2.x

Assumed layout:

/tests/
    test_utils.py
        def test_add_one()...
        def test_sub_one()...
    test_gui.py
        def test_load_buttons()...
utils.py
    def add_one()...
    def sub_one()...
gui.py
    def load_buttons()...

So running this code from a button will jump you from
test_sub_one() back to sub_one() and visa versa creating any
missing parts of the hierarchy in the process.

[1] https://docs.pytest.org/en/latest/
"""</t>
<t tx="ekr.20190117144035.2">g.cls()
import os
import subprocess
loadDir = g.app.loadDir
if 1:
    table = (
        (os.path.abspath(os.path.join(loadDir, '..', '..')), None),
    )
else:
    table = (
        (os.path.abspath(os.path.join(loadDir, '..', 'core')), None),
        (os.path.abspath(os.path.join(loadDir, '..', 'test')), None),
        (os.path.abspath(os.path.join(loadDir, '..', 'plugins', 'test')), None),
    )
for path, ignore in table:
    assert os.path.exists(path), repr(path)
    # subprocess.Popen(r'python %s %s' % (prog, path), shell=True)
    ignore = '-k %s ' % (ignore) if ignore else ''
    command = r'pytest %s%s' % (ignore, path)
    subprocess.Popen(command, shell=True)</t>
<t tx="ekr.20190117144035.3">g.cls()
import os
import subprocess
loadDir = g.app.loadDir
prog = g.os_path_finalize_join(loadDir, '..', '..', 'run_pytest_tests.py')
if 1:
    paths = (
        os.path.abspath(os.path.join(loadDir, '..', '..')),
    )
else:
    paths = (
        os.path.abspath(os.path.join(loadDir, '..', 'core')),
        os.path.abspath(os.path.join(loadDir, '..', 'test')),
        os.path.abspath(os.path.join(loadDir, '..', 'plugins', 'test')),
    )
for path in paths:
    assert os.path.exists(path), repr(path)
    subprocess.Popen(r'python %s %s' % (prog, path), shell=True)
</t>
<t tx="ekr.20190307044803.1">'''
Recursively clean all lines in a folder.

Do this before importing to @clean.
'''
g.cls()

directory = r'C:\apps\pyzo\source\pyzo'

def clean_dir(directory):
    for path in g.get_files_in_directory(directory, kinds=['.py']):
        clean_file(path)
        
def clean_file(path):
    with open(path, 'r') as f:
        file_s = f.read()
    lines = []
    for line in g.splitLines(file_s):
        if line.rstrip():
            lines.append(line.rstrip())
        if line.endswith('\n'):
            lines.append('\n')
    new_s = ''.join(lines)
    if file_s != new_s:
        with open(path, 'w') as f:
            f.write(new_s)
            print('wrote: %s' % path)
    
clean_dir(directory)
</t>
<t tx="ekr.20190509062342.1"># From https://docs.python.org/3/library/sqlite3.html

# I'll only mention changes to the python demo here.

import datetime
import sqlite3
conn = sqlite3.connect('example.db')

# Change 1:  Name the cursor 'cursor' to preserve Leo's c.
cursor = conn.cursor()
    
# Change 2: Catch any exception.
# This allows this demo to continue if the table already exists.
try:
    cursor.execute('''CREATE TABLE stocks
    (date text, trans text, symbol text, qty real, price real)''')
except Exception:
    pass

cursor.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)")
conn.commit()

# Change 3: don't bother closing and reopning the connection.

t = ('RHAT',)
cursor.execute('SELECT * FROM stocks WHERE symbol=?', t)
purchases = [
    ('2006-03-28', 'BUY',  'IBM',  1000, 45.00),
    ('2006-04-05', 'BUY',  'MSFT', 1000, 72.00),
    ('2006-04-06', 'SELL', 'IBM',  500,  53.00),
]
cursor.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases)

# Change 4: Get the result as a iterator.

# Don't exhaust the iterator by printing results!
query = 'SELECT * FROM stocks ORDER BY price'
result = cursor.execute(query)

# Change 5: Put the results a new @query node, with a timestamp.
last = c.lastTopLevel()
p = last.insertAfter()
timestamp = datetime.datetime.now().strftime("%Y%m%d:%H%M%S")
p.h = '@query %s: %s' % (timestamp, query)
p.b = '\n'.join([str(z) for z in result])
#
# Make the new node visible.
last.expand()
c.redraw() 
</t>
<t tx="ekr.20190609162248.1"></t>
<t tx="lkj.20190712002811.1"></t>
<t tx="maphew.20190209160547.1">gnx: maphew.20130809155103.2863
</t>
<t tx="mhw-debug-1081.20190310203401.1">Scripts only of interest when on Microsoft Windows platform.
@path win

The register- and unregister-leo scripts have been moved to Desktop-integration.leo</t>
<t tx="mhw.20181210131101.1">True (recommended):
    Write "E" attribute bits in &lt;v&gt; elements.
    Leo outlines will record the expansion state of all nodes.
    
False: (Good for files like unitTest.leo)
    Suppress "E" attribute bits in &lt;v&gt; elements.
    Only the ancestors of the presently selected node will
    be expanded when Leo opens an outline.</t>
</tnodes>
</leo_file>
