leojs
leojs copied to clipboard
Some U.A. from Leo are unsupported in LeoJS (it writes .leo files with corrupted UAs)
The bug
- Change a
.leofile in leoJS. - Open the file with (desktop) Leo.
The following crash happens for many (all?) previously visited nodes:
getDescendentUnknownAttributes Can not unpickle str PLACE HOLDER 286470300a286470310a286470320a532769735f
Traceback (most recent call last):
File "C:\Repos\leo-editor\leo\core\leoFileCommands.py", line 1197, in getDescendentUnknownAttributes
val = pickle.loads(bin) # Returns a Python object.
TypeError: unhashable type: 'dict'
Severity
These messages are annoying, but do not cause data loss.
Saving the .leo file eliminates the messages when desktop Leo next opens the file.
Workaround
On my machine I changed fc.getDescendentUnknownAttributes as follows to give the annoying message only once:
def getDescendentUnknownAttributes(self, s: str, v: VNode = None) -> Value:
"""Unhexlify and unpickle t/v.descendentUnknownAttribute field."""
try:
# Changed in version 3.2: Accept only bytestring or bytearray objects as input.
s_bytes = g.toEncodedString(s) # 2011/02/22
# Throws a TypeError if val is not a hex string.
bin = binascii.unhexlify(s_bytes)
val = pickle.loads(bin) # Returns a Python object.
return val
except Exception:
# g.es_exception()
# g.trace('Can not unpickle', s.__class__.__name__, v and v.h, s[:40])
if v:
g.print_unique_message(f"Can not unpickle: {v.h}")
return None
@edreamleo thanks!
If you can, please provide a leo file that reproduces the problem. (the one before it was saved in LeoJS)
@boltex It appears that LeoJS corrupts any file containing a descendentVnodeUnknownAttributes attr. Here is one example:
<?xml version="1.0" encoding="utf-8"?>
<!-- Created by Leo: https://leo-editor.github.io/leo-editor/leo_toc.html -->
<leo_file xmlns:leo="https://leo-editor.github.io/leo-editor/namespaces/leo-python-editor/1.1" >
<leo_header file_format="2"/>
<globals/>
<preferences/>
<find_panel_settings/>
<vnodes>
<v t="ekr.20111002001133.2144" descendentVnodeUnknownAttributes="7d7100285803000000302e3071017d7102580b0000005f5f626f6f6b6d61726b7371037d7104580700000069735f647570657105580500000066616c7365710673735803000000302e3171077d710868037d7109580700000069735f64757065710a580500000066616c7365710b73735807000000302e322e362e30710c7d710d68037d710e580700000069735f64757065710f580500000066616c7365711073735808000000302e322e362e323471117d71125808000000616e6e6f7461746571137d71142858080000007072696f7269747971155804000000393939397116580a000000707269736574646174657117580a000000323032302d31312d3131711875735803000000302e3371197d711a68037d711b580700000069735f64757065711c580500000066616c7365711d73735806000000302e332e3133711e7d711f68037d7120580700000069735f647570657121580500000066616c7365712273735806000000302e332e313471237d712468037d7125580700000069735f647570657126580500000066616c7365712773735803000000302e3871287d712968137d712a2858080000007072696f72697479712b580400000039393939712c580a00000070726973657464617465712d580a000000323032312d30332d3330712e7573752e"><vh>Startup</vh>
<v t="ekr.20170713105049.6" descendentVnodeUnknownAttributes="7d710058010000003071017d7102580b0000005f5f626f6f6b6d61726b7371037d7104580700000069735f647570657105580500000066616c736571067373732e"><vh>#@persistence</vh></v>
<v t="ekr.20111002001133.2168" descendentVnodeUnknownAttributes="7d71002858010000003071017d7102580b0000005f5f626f6f6b6d61726b7371037d7104580700000069735f647570657105580500000066616c7365710673735808000000302e31302e362e3071077d710868037d7109580700000069735f64757065710a580500000066616c7365710b73735809000000302e31302e362e3234710c7d710d5808000000616e6e6f74617465710e7d710f2858080000007072696f7269747971105804000000393939397111580a000000707269736574646174657112580a000000323032302d31312d313171137573752e"><vh>@settings</vh>
<v t="ekr.20250321170720.1"><vh>@bool allow-script-return-result = True</vh></v>
<v t="ekr.20230317072300.1"><vh>@bool allow-text-zoom = True</vh></v>
<v t="ekr.20210306054745.1"><vh>@bool check-python-code-on-write = True</vh></v>
<v t="ekr.20200518064548.1"><vh>@bool use-german-keyboard = False</vh></v>
<v t="ekr.20230327032043.1"><vh>@bool use-mouse-expand-gestures = False</vh></v>
<v t="ekr.20210531084324.1"><vh>@data exec-script-commands</vh></v>
<v t="ekr.20210531094929.1"><vh>@data exec-script-patterns</vh></v>
<v t="ekr.20160316094834.1"><vh>@data history-list</vh></v>
<v t="ekr.20210414174148.1"><vh>@rclick say-hi @args=say hi</vh></v>
<v t="ekr.20240726151728.1"><vh>@string qt-layout-name = legacy</vh></v>
<v t="ekr.20140918130403.2193" descendentVnodeUnknownAttributes="7d7100285805000000302e362e3071017d7102580b0000005f5f626f6f6b6d61726b7371037d7104580700000069735f647570657105580500000066616c7365710673735806000000302e362e323471077d71085808000000616e6e6f7461746571097d710a2858080000007072696f72697479710b580400000039393939710c580a00000070726973657464617465710d580a000000323032302d31312d3131710e7573752e"><vh>Buttons & commands</vh>
<v t="ekr.20171218081254.1"><vh>#@button count-children</vh></v>
<v t="ekr.20220704210149.1"><vh>#@button print-gnx @key=f6</vh></v>
<v t="ekr.20171022115210.1"><vh>#@button show-uas</vh></v>
<v t="ekr.20230618112751.1"><vh>#@button take-screen-shot</vh></v>
<v t="ekr.20241012032943.1"><vh>#@command test @key=f5</vh></v>
<v t="ekr.20170411194404.1"><vh>@button backup</vh></v>
<v t="ekr.20150402122915.1" descendentVnodeUnknownAttributes="7d7100285803000000302e3071017d7102580b0000005f5f626f6f6b6d61726b7371037d7104580700000069735f647570657105580500000066616c7365710673735804000000302e323471077d71085808000000616e6e6f7461746571097d710a2858080000007072696f72697479710b580400000039393939710c580a00000070726973657464617465710d580a000000323032302d31312d3131710e7573752e"><vh>@ignore Disabled buttons</vh>
<v t="ekr.20190515192551.1" descendentVnodeUnknownAttributes="7d710058010000003071017d7102580b0000005f5f626f6f6b6d61726b7371037d7104580700000069735f647570657105580500000066616c736571067373732e"><vh>@button adoc</vh></v>
<v t="ekr.20131017180426.2539"><vh>@button clean-text</vh></v>
<v t="ekr.20150511065348.1"><vh>@button create decorators</vh>
<v t="ekr.20150511065348.2"><vh>create_d</vh></v>
<v t="ekr.20150511065348.3"><vh>create_decorator</vh></v>
<v t="ekr.20150511065348.4"><vh>create_decorators</vh></v>
<v t="ekr.20150511065348.5"><vh>create_fixups</vh></v>
<v t="ekr.20150511065348.6"><vh>find_class</vh></v>
<v t="ekr.20150511065348.7"><vh>find_next_clone</vh></v>
<v t="ekr.20150511065348.8"><vh>munge_lines</vh></v>
<v t="ekr.20150511065348.9"><vh>run</vh></v>
</v>
<v t="ekr.20170301014406.1"><vh>@button cycling syntax coloring</vh></v>
<v t="ekr.20180407182938.1"><vh>@button dump uA</vh></v>
<v t="ekr.20241110171219.1"><vh>@button dump-state-dict</vh></v>
<v t="ekr.20170610081535.1"><vh>@button expand-section</vh></v>
<v t="ekr.20200322213121.1"><vh>@button graalvm</vh></v>
<v t="ekr.20160517122729.1"><vh>@button introspect</vh></v>
<v t="ekr.20111002001214.6923"><vh>@button join-path</vh></v>
<v t="ekr.20231123111324.1"><vh>@button load-readme</vh></v>
<v t="ekr.20150511065408.1"><vh>@button make-decorators2</vh>
<v t="ekr.20150511065408.2"><vh>create_d</vh></v>
<v t="ekr.20150511065408.3"><vh>create_decorator</vh></v>
<v t="ekr.20150511065408.4"><vh>create_decorators V2</vh></v>
<v t="ekr.20150511065408.5"><vh>define_s</vh></v>
<v t="ekr.20150511065408.6"><vh>munge_lines</vh></v>
<v t="ekr.20150511065408.7"><vh>run V2</vh></v>
</v>
<v t="ekr.20180327111918.1"><vh>@button munge</vh></v>
<v t="ekr.20141021085632.2299"><vh>@button print-gnx</vh></v>
<v t="ekr.20140918125647.2189"><vh>@button print-ss</vh></v>
<v t="ekr.20160304051536.1"><vh>@button print-ua</vh></v>
<v t="ekr.20200303124744.1"><vh>@button proto</vh></v>
<v t="ekr.20200303123433.1"><vh>@button qt-demo</vh></v>
<v t="ekr.20170629162056.1"><vh>@button rclick-test</vh>
<v t="ekr.20180124064122.1"><vh>@rclick hi</vh></v>
</v>
<v t="ekr.20181028130924.1"><vh>@button reload-leowapp</vh></v>
<v t="ekr.20180926104417.1"><vh>@button save-clipboard</vh></v>
<v t="ekr.20180926061406.1"><vh>@button screen-shot @key=ctrl-1</vh></v>
<v t="ekr.20141021100322.2315"><vh>@button set-ua</vh></v>
<v t="ekr.20111002001214.6922"><vh>@button split-path</vh></v>
<v t="ekr.20201109162524.1" descendentVnodeUnknownAttributes="7d710058010000003071017d71025808000000616e6e6f7461746571037d71042858080000007072696f7269747971055804000000393939397106580a000000707269736574646174657107580a000000323032302d31312d313171087573732e"><vh>@button test-undo-body</vh></v>
<v t="ekr.20201110091730.1"><vh>@button test-undo-head</vh></v>
<v t="ekr.20150501042918.1"><vh>@button timeit</vh></v>
<v t="ekr.20131121085011.1751"><vh>@button toggle-debug-app</vh></v>
<v t="ekr.20160531065801.1"><vh>@button unit-tests</vh></v>
<v t="ekr.20140913151035.3604"><vh>@command test @key=Ctrl-F7</vh></v>
</v>
</v>
<v t="ekr.20250329085219.1"><vh>Chapters</vh>
<v t="ekr.20250329085219.2"><vh>@bool use-chapter-tabs = True</vh></v>
<v t="ekr.20250329085219.3"><vh>@bool use-chapters = True</vh></v>
<v t="ekr.20250329085219.4"><vh>@bool chapter-dropdown-left = False</vh></v>
</v>
<v t="ekr.20250329085342.1"><vh>@chapter Chapter 1</vh>
<v t="ekr.20250329085411.1"><vh>Chapter 1</vh></v>
</v>
<v t="ekr.20250329085349.1"><vh>@chapter Chapter 2</vh>
<v t="ekr.20250329085443.1"><vh>Chapter 2</vh>
<v t="ekr.20250331190146.1"><vh>Chapter 2, child 1</vh></v>
</v>
</v>
</v>
<v t="ekr.20140918130403.2193" descendentVnodeUnknownAttributes="7d7100285805000000302e362e3071017d7102580b0000005f5f626f6f6b6d61726b7371037d7104580700000069735f647570657105580500000066616c7365710673735806000000302e362e323471077d71085808000000616e6e6f7461746571097d710a2858080000007072696f72697479710b580400000039393939710c580a00000070726973657464617465710d580a000000323032302d31312d3131710e7573752e"></v>
<v t="ekr.20180126175239.1" descendentVnodeUnknownAttributes="7d71002858010000003071017d7102580b0000005f5f626f6f6b6d61726b7371037d7104580700000069735f647570657105580500000066616c7365710673735804000000302e313371077d710868037d7109580700000069735f64757065710a580500000066616c7365710b73735804000000302e3134710c7d710d68037d710e580700000069735f64757065710f580500000066616c736571107373752e"><vh>Scripts</vh>
<v t="ekr.20150115062912.1"><vh> Recursive import script</vh>
<v t="ekr.20240208210018.1"><vh><< rust dir_list >></vh></v>
</v>
<v t="ekr.20130422173617.9359"><vh>script: check syntax of all docutils files</vh></v>
<v t="ekr.20150302052400.3"><vh>script: clean ekr-spellpyx.txt</vh></v>
<v t="ekr.20180211124129.1"><vh>script: compare LeoDocs.leo</vh></v>
<v t="ekr.20221022090126.1"><vh>script: delete the "Settings" tab</vh></v>
<v t="ekr.20160811105733.1"><vh>script: Filter New Trier class list</vh></v>
<v t="ekr.20180126051628.1"><vh>script: get issues</vh></v>
<v t="ekr.20180126053155.1"><vh>script: get user tips</vh></v>
<v t="ekr.20240302052316.1"><vh>script: import to .txt files</vh></v>
<v t="ekr.20130115100852.9016"><vh>script: insert icon</vh></v>
<v t="ekr.20160926055309.1"><vh>script: massage book for rst</vh></v>
<v t="ekr.20231023035556.1"><vh>script: remove copyright</vh></v>
<v t="ekr.20111016205745.5062"><vh>script: rename picture files</vh></v>
<v t="ekr.20180126174551.1" descendentVnodeUnknownAttributes="7d710058010000003071017d7102580b0000005f5f626f6f6b6d61726b7371037d7104580700000069735f647570657105580500000066616c736571067373732e"><vh>script: render latex formula</vh></v>
<v t="ekr.20190602065922.1" descendentVnodeUnknownAttributes="7d710058010000003071017d7102580b0000005f5f626f6f6b6d61726b7371037d7104580700000069735f647570657105580500000066616c736571067373732e"><vh>script: split body</vh></v>
<v t="ekr.20180228080856.1"><vh>script: switch between pytest code and test</vh></v>
<v t="ekr.20210724082245.1"><vh>script: update ~/SlideShow</vh>
<v t="ekr.20210724085930.1"><vh><< other directories >></vh></v>
</v>
<v t="ekr.20241207020428.1"><vh>Test scripts</vh>
<v t="ekr.20240624052855.1"><vh>test-script: Add red frame (works)</vh>
<v t="ekr.20240624053504.1"><vh>helpers</vh></v>
</v>
<v t="ekr.20240521150404.1"><vh>test-script: detach VR pane (works)</vh></v>
<v t="ekr.20240518074638.1"><vh>test-script: insert in body (works)</vh>
<v t="ekr.20240518074638.2"><vh>helpers</vh></v>
</v>
<v t="ekr.20240517034559.1"><vh>test-script: insert in main splitter (works)</vh>
<v t="ekr.20240518073948.1"><vh>helpers</vh></v>
</v>
</v>
</v>
<v t="ekr.20220327060129.1"><vh>--- recent settings</vh>
<v t="ekr.20140907200120.2073"><vh>@bool qt-use-scintilla = False</vh></v>
<v t="ekr.20220913071804.2"><vh>@bool tree-declutter = False</vh></v>
<v t="ekr.20161206100037.1"><vh>@string target-language = python</vh></v>
</v>
<v t="ekr.20150115062912.1"></v>
<v t="ekr.20160316094834.1"></v>
<v t="ekr.20240726151728.1"></v>
<v t="ekr.20200316054710.1" descendentVnodeUnknownAttributes="7d710058010000003071017d71025808000000616e6e6f7461746571037d71042858080000007072696f7269747971055804000000393939397106580a000000707269736574646174657107580a000000323032312d30332d333071087573732e"><vh>@enabled-plugins</vh></v>
</v>
<v t="ekr.20250528090321.1"><vh>A node</vh></v>
</vnodes>
<tnodes>
<t tx="ekr.20111002001133.2144"></t>
<t tx="ekr.20111002001133.2168" __bookmarks="7d7100580700000069735f647570657101580500000066616c73657102732e">@language rest
@wrap
The @settings tree contains all active settings.
Settings outside this tree have no effect.</t>
<t tx="ekr.20111002001214.6922">'''@button (ekr.leo) Split the body text at semicolons'''
# No longer needed on Windows 10
w = c.frame.body.widget
p.b = '\n'.join(p.b.split(';'))
c.bodyWantsFocusNow()
# w.selectAllText()
</t>
<t tx="ekr.20111002001214.6923">'''@button (ekr.leo) Join the lines, with ; separators'''
# No longer needed on Windows 10
w = c.frame.body.widget
aList = [z.rstrip() for z in p.b.split('\n')]
p.b = ';'.join(aList)
c.bodyWantsFocusNow()
</t>
<t tx="ekr.20111016205745.5062">"""
Pictures are in
C:\Users\edreamleo\AppData\Local\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets
Copy them by hand to C:\Users\edreamleo\Pictures\WinSpotLight folder.
"""
import glob, shutil
path = r'C:\Users\edreamleo\Pictures\WinSpotLight\*'
files = glob.glob(path)
# g.printObj(sorted(files), tag='BEFORE')
for s in sorted(files):
# Just add .jpg
if not s.endswith('.jpg'):
shutil.move(s, s + '.jpg')
g.printObj(sorted(glob.glob(path)), tag='AFTER')
</t>
<t tx="ekr.20130115100852.9016"># Use delete-node-icons to remove icons.
table = (
'edittrash.png',
'connect_no.png',
'error.png',
)
for icon in table:
fn = g.os_path_finalize_join(g.app.loadDir,
'..', 'Icons', 'Tango', '16x16', 'status', icon)
if g.os_path_exists(fn):
c.editCommands.insertIconFromFile(path=fn)
</t>
<t tx="ekr.20130422173617.9359"># The following files fail on Python 3 because of Python 2.x syntax for unicode characters:
# (now passes) utils/punctuation_chars.py,
# utils/math/latex2mathml.py,
# writers/manpage.py,
# writers/latex2e/__init__.py
g.cls()
import os
path = g.os_path_finalize_join(g.app.loadDir,'..','extensions','docutils')
if g.isPython3:
exclude = ('punctuation2.py',)
else:
exclude = ('punctuation3.py',)
for root, dirs, files in os.walk(path):
for fn in files:
if fn.endswith('.py'):
fn = g.os_path_join(root,fn)
if not g.shortFileName(fn) in exclude:
s,e = g.readFileIntoString(fn)
c.testManager.checkFileSyntax(fn,s,reraise=False,suppress=False)
print('all files in leo/extensions/docutils pass')
</t>
<t tx="ekr.20131017180426.2539">'''(ekr.leo) Clean newlines from EKR text.'''
s = p.b.replace('\n\n','\nPARA\n')
s = s.replace('\n',' ')
s = s.replace(' PARA ','\n\n')
s = s.replace(' ',' ')
p.b = s
</t>
<t tx="ekr.20131121085011.1751">g.app.debug_app = not g.app.debug_app
g.app.debug_widgets = not g.app.debug_widgets
print('g.app.debug_app: %s' % g.app.debug_app)
print('g.app.debug_widgets: %s' % g.app.debug_widgets)</t>
<t tx="ekr.20140907200120.2073"></t>
<t tx="ekr.20140913151035.3604">print('Test')</t>
<t tx="ekr.20140918125647.2189">c.k.simulateCommand('print-style-sheet')</t>
<t tx="ekr.20140918130403.2193">@language python
</t>
<t tx="ekr.20141021085632.2299">'''@button (ekr.leo) print the gnx.'''
# g.cls()
print('timestamp: %s lastIndex: %s' % (g.app.nodeIndices.timeString,g.app.nodeIndices.lastIndex))
print('gnxs: -----')
for p in c.p.self_and_subtree():
print('%s %s' % (p.v.gnx,p.h))
print('uAs: -----')
for p in c.p.self_and_subtree():
if p.v.u:
print('%s %s' % (p.v.u,p.h))
# print('done')
</t>
<t tx="ekr.20141021100322.2315">'''@button (ekr.leo) set the ua to 'test-head' '''
p.v.u = {'test-head':p.h}
p.setDirty()
c.setChanged(True)
c.redraw()
</t>
<t tx="ekr.20150115062912.1">@language python
"""Recursively import all python files in a directory and clean the result."""
@tabwidth -4 # For a better match.
g.cls()
<< rust dir_list >>
# dir_ = r'C:\Python\Python3.12\Lib\site-packages\jupytext'
# dir_ = r'C:\Python\Python3.12\Lib\site-packages\jupytext_config'
dir_ = r'C:\Python\Python3.13\Lib\site-packages\IPython\core\historyapp.py'
c.recursiveImport(
dir_=dir_,
kind = '@clean', # '@auto', '@clean', '@nosent','@file',
recursive = True,
safe_at_file = True,
# '.html', '.js', '.json', '.py', '.rs', '.svg', '.ts', '.tsx']
# '.codon', '.cpp', '.cc', '.el', '.scm',
theTypes = ['.py',],
verbose = True,
)
if 1:
last = c.lastTopLevel()
last.expand()
if last.hasChildren():
last.firstChild().expand()
c.redraw(last)
print('Done')</t>
<t tx="ekr.20150302052400.3">if 1:
fn = g.os_path_finalize_join(g.app.loadDir,'..','..','ekr-spellpyx.txt')
with open(fn) as f:
s = ''.join(sorted(set(g.splitLines(f.read().strip()+'\n'))))
with open(fn,'w') as f:
f.write(s)
g.es('done',len(s))
else:
p.b = ''.join(sorted(set(g.splitLines(p.b.rstrip()+'\n'))))</t>
<t tx="ekr.20150402122915.1"></t>
<t tx="ekr.20150501042918.1">c.testManager.runTimerOnNode(p,count=100000)
</t>
<t tx="ekr.20150511065348.1">g.cls()
print('===== Start =====')
class CreateDecorators:
'''
A class to create decorators from tables in getPublicCommands.
Note: the node "Found: getPublicCommands" must exist.
'''
def __init__(self,c,make_changes):
self.c = c
self.fixups = self.create_fixups()
self.n = 0
self.n_fail = 0
self.make_changes=make_changes
self.suppress = [
'c.frame.body and c.frame.body.addEditor',
'cls','cloneFindParents','cycleTabFocus',
'k and k.keyboardQuit',
'menuShortcutPlaceHolder','removeBlankLines',
'saveBuffersKillLeo',
]
@others
CreateDecorators(c,make_changes=False).run()
</t>
<t tx="ekr.20150511065348.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) > 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.20150511065348.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))
trace = False
found = False
decorator = "@cmd('%s')\n" % (c_name)
for p in root.self_and_subtree():
changed,result = False,[]
for s in g.splitLines(p.b):
if g.match_word(s,0,'def ' + f_name):
if found:
if f_name not in self.suppress:
g.trace('duplicate def',f_name)
else:
changed,found = True,True
result.append(decorator)
# print('%s%s' % (decorator,s))
result.append(s)
# if changed and self.make_changes:
# new_body = ''.join(result)
# # use git as our undo :-)
# p.b = new_body
return found
</t>
<t tx="ekr.20150511065348.4">def create_decorators(self,d,root):
'''Create decorators for all items in d in root's tree.'''
# print('***** %s' % 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,'=====>',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 and f_name not in self.suppress:
print('===== not found: %30s %s' % (root.h,f_name))
self.n_fail += 1
</t>
<t tx="ekr.20150511065348.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.20150511065348.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') > -1 and p2.b.find('class') > -1:
return p2
else:
g.trace('*** no class for p.h')
return None
</t>
<t tx="ekr.20150511065348.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.20150511065348.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('#') > -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.20150511065348.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.20150511065408.1">g.cls()
# Changed files:
# leoApp.py
# leoAtFile.py
# leoCommands.py
# leoFileCommands.py
# leoFrame.py
# leoUndo.py
# qt_frame.py
make_changes = True
# True, actually make the change
class CreateDecorators:
'''
A class to create decorators from tables in getPublicCommands.
Note: the node "Found: getPublicCommands" must exist.
'''
def __init__(self):
self.n = 0
self.n_fail = 0
self.s = self.define_s()
@others
CreateDecorators().run()
</t>
<t tx="ekr.20150511065408.2">def create_d(self,lines):
'''Create a dict. keys are method names; values are command names.'''
trace = False
d = {}
for s in lines:
aList = s.split()
if len(aList) > 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.20150511065408.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.
'''
trace = True
found = False
decorator = "@cmd('%s')\n" % (c_name)
for p in root.self_and_subtree():
changed,result = False,[]
for s in g.splitLines(p.b):
if g.match_word(s,0,'def ' + f_name):
if found:
if f_name not in self.suppress:
g.trace('duplicate def',f_name)
else:
changed,found = True,True
result.append(decorator)
# print('%s%s' % (decorator,s))
result.append(s)
if changed and make_changes:
new_body = ''.join(result)
print('%40s %s' % (p.h[:40],decorator.rstrip()))
# use git as our undo :-)
# p.b = new_body
return found
</t>
<t tx="ekr.20150511065408.4">def create_decorators(self,d): ### ,root):
'''Create decorators for all items in d in root's tree.'''
table = (
'class Commands', # c.
'class LeoQtFrame', # f.
'class LeoFrame', # f.
'class LeoApp', # g.app.
'@file leoAtFile.py', # c.atFileCommands
'@file leoFileCommands.py', # c.fileCommands
'class Undoer', # c.undoer
)
roots = []
for h in table:
root = g.findNodeAnywhere(c,h)
assert root,h
roots.append(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 and f_name not in self.suppress:
print('===== not found: %s' % (f_name))
self.n_fail += 1
</t>
<t tx="ekr.20150511065408.5"># 'check-all-python-code': c.checkAllPythonCode,
# 'check-python-code': c.checkPythonCode,
# 'extract-python-method': c.extractPythonMethod,
# 'extract-section': c.extractSection,
# 'import-at-file': c.importAtFile,
# 'import-at-root': c.importAtRoot,
# 'import-cweb-files': c.importCWEBFiles,
# 'import-derived-file': c.importDerivedFile,
# 'import-flattened-outline': c.importFlattenedOutline,
# 'import-noweb-files': c.importNowebFiles,
# 'mark-changed-roots': c.markChangedRoots,
# 'mark-clones': c.markClones,
# 'open-compare-window': c.openCompareWindow,
# 'open-online-tutorial': c.leoTutorial,
# 'reformat-body': c.reformatBody, # 2013/10/02.
def define_s(self):
return '''
'abort-edit-headline': f.abortEditLabelCommand,
'about-leo': c.about,
'add-comments': c.addComments,
'beautify': c.beautifyPythonCode,
'beautify-all': c.beautifyAllPythonCode,
'beautify-c': c.beautifyCCode,
'beautify-tree': c.beautifyPythonTree,
'cascade-windows': f.cascade,
'check-derived-file': c.atFileCommands.checkDerivedFile,
'check-leo-file': c.fileCommands.checkLeoFile,
'check-outline': c.fullCheckOutline,
'clean-recent-files': c.cleanRecentFiles,
'clear-recent-files': c.clearRecentFiles,
'clone-node': c.clone,
'clone-node-to-last-node': c.cloneToLastNode,
'close-window': c.close,
'contract-all': c.contractAllHeadlines,
'contract-all-other-nodes': c.contractAllOtherNodes,
'contract-node': c.contractNode,
'contract-or-go-left': c.contractNodeOrGoToParent,
'contract-parent': c.contractParent,
'convert-all-blanks': c.convertAllBlanks,
'convert-all-tabs': c.convertAllTabs,
'convert-blanks': c.convertBlanks,
'convert-tabs': c.convertTabs,
'copy-node': c.copyOutline,
'copy-text': f.copyText,
'cut-node': c.cutOutline,
'cut-text': f.cutText,
'de-hoist': c.dehoist,
'delete-comments': c.deleteComments,
'delete-node': c.deleteOutline,
'demote': c.demote,
'dump-outline': c.dumpOutline,
'edit-headline': c.editHeadline,
'end-edit-headline': f.endEditLabelCommand,
'equal-sized-panes': f.equalSizedPanes,
'execute-script': c.executeScript,
'exit-leo': g.app.onQuit,
'expand-all': c.expandAllHeadlines,
'expand-all-subheads': c.expandAllSubheads,
'expand-ancestors-only': c.expandOnlyAncestorsOfNode,
'expand-and-go-right': c.expandNodeAndGoToFirstChild,
'expand-next-level': c.expandNextLevel,
'expand-node': c.expandNode,
'expand-or-go-right': c.expandNodeOrGoToFirstChild,
'expand-prev-level': c.expandPrevLevel,
'expand-to-level-1': c.expandLevel1,
'expand-to-level-2': c.expandLevel2,
'expand-to-level-3': c.expandLevel3,
'expand-to-level-4': c.expandLevel4,
'expand-to-level-5': c.expandLevel5,
'expand-to-level-6': c.expandLevel6,
'expand-to-level-7': c.expandLevel7,
'expand-to-level-8': c.expandLevel8,
'expand-to-level-9': c.expandLevel9,
'export-headlines': c.exportHeadlines,
'extract': c.extract,
'extract-names': c.extractSectionNames,
'find-next-clone': c.findNextClone,
'flatten-outline': c.flattenOutline,
'flatten-outline-to-node': c.flattenOutlineToNode,
'go-back': c.goPrevVisitedNode,
'go-forward': c.goNextVisitedNode,
'goto-first-node': c.goToFirstNode,
'goto-first-sibling': c.goToFirstSibling,
'goto-first-visible-node': c.goToFirstVisibleNode,
'goto-last-node': c.goToLastNode,
'goto-last-sibling': c.goToLastSibling,
'goto-last-visible-node': c.goToLastVisibleNode,
'goto-next-changed': c.goToNextDirtyHeadline,
'goto-next-clone': c.goToNextClone,
'goto-next-history-node': c.goToNextHistory,
'goto-next-marked': c.goToNextMarkedHeadline,
'goto-next-node': c.selectThreadNext,
'goto-next-sibling': c.goToNextSibling,
'goto-next-visible': c.selectVisNext,
'goto-parent': c.goToParent,
'goto-prev-history-node': c.goToPrevHistory,
'goto-prev-node': c.selectThreadBack,
'goto-prev-sibling': c.goToPrevSibling,
'goto-prev-visible': c.selectVisBack,
'hide-invisibles': c.hideInvisibles,
'hoist': c.hoist,
'import-file': c.importAnyFile,
'indent-region': c.indentBody,
'insert-body-time': c.insertBodyTime,
'insert-child': c.insertChild,
'insert-node': c.insertHeadline,
'insert-node-before': c.insertHeadlineBefore,
'mark': c.markHeadline,
'mark-changed-items': c.markChangedHeadlines,
'mark-subheads': c.markSubheads,
'match-brackets': c.findMatchingBracket,
'minimize-all': f.minimizeAll,
'move-outline-down': c.moveOutlineDown,
'move-outline-left': c.moveOutlineLeft,
'move-outline-right': c.moveOutlineRight,
'move-outline-up': c.moveOutlineUp,
'new': c.new,
'open-cheat-sheet-leo': c.openCheatSheet,
'open-leoDocs-leo': c.leoDocumentation,
'open-leoPlugins-leo': c.openLeoPlugins,
'open-leoSettings-leo': c.openLeoSettings,
'open-local-settings': c.selectAtSettingsNode,
'open-myLeoSettings-leo': c.openMyLeoSettings,
'open-offline-tutorial': f.leoHelp,
'open-online-home': c.leoHome,
'open-online-toc': c.openLeoTOC,
'open-online-tutorials': c.openLeoTutorials,
'open-online-videos': c.openLeoVideos,
'open-outline': c.open,
'open-python-window': c.openPythonWindow,
'open-quickstart-leo': c.leoQuickStart,
'open-scripts-leo': c.openLeoScripts,
'open-users-guide': c.openLeoUsersGuide,
'open-with': c.openWith,
'outline-to-cweb': c.outlineToCWEB,
'outline-to-noweb': c.outlineToNoweb,
'paste-node': c.pasteOutline,
'paste-retaining-clones': c.pasteOutlineRetainingClones,
'paste-text': f.pasteText,
'pretty-print-all-python-code': c.prettyPrintAllPythonCode,
'pretty-print-python-code': c.prettyPrintPythonCode,
'promote': c.promote,
'read-at-auto-nodes': c.readAtAutoNodes,
'read-at-file-nodes': c.readAtFileNodes,
'read-at-shadow-nodes': c.readAtShadowNodes,
'read-file-into-node': c.readFileIntoNode,
'read-outline-only': c.readOutlineOnly,
'redo': c.undoer.redo,
'reformat-paragraph': c.reformatParagraph,
'refresh-from-disk': c.refreshFromDisk,
'remove-sentinels': c.removeSentinels,
'resize-to-screen': f.resizeToScreen,
'revert': c.revert,
'save-all': c.saveAll,
'save-file': c.save,
'save-file-as': c.saveAs,
'save-file-as-unzipped': c.saveAsUnzipped,
'save-file-as-zipped': c.saveAsZipped,
'save-file-to': c.saveTo,
'set-colors': c.colorPanel,
'set-font': c.fontPanel,
'settings': c.preferences,
'show-invisibles': c.showInvisibles,
'sort-children': c.sortChildren,
'sort-recent-files': c.sortRecentFiles,
'sort-siblings': c.sortSiblings,
'tangle': c.tangle,
'tangle-all': c.tangleAll,
'tangle-marked': c.tangleMarked,
'toggle-active-pane': f.toggleActivePane,
'toggle-angle-brackets': c.toggleAngleBrackets,
'toggle-invisibles': c.toggleShowInvisibles,
'toggle-sparse-move': c.toggleSparseMove,
'toggle-split-direction': f.toggleSplitDirection,
'undo': c.undoer.undo,
'unformat-paragraph': c.unformatParagraph,
'unindent-region': c.dedentBody,
'unmark-all': c.unmarkAll,
'untangle': c.untangle,
'untangle-all': c.untangleAll,
'untangle-marked': c.untangleMarked,
'weave': c.weave,
'write-at-auto-nodes': c.atFileCommands.writeAtAutoNodes,
'write-at-file-nodes': c.fileCommands.writeAtFileNodes,
'write-at-shadow-nodes': c.fileCommands.writeAtShadowNodes,
'write-dirty-at-auto-nodes': c.atFileCommands.writeDirtyAtAutoNodes,
'write-dirty-at-file-nodes': c.fileCommands.writeDirtyAtFileNodes,
'write-dirty-at-shadow-nodes': c.fileCommands.writeDirtyAtShadowNodes,
'write-file-from-node': c.writeFileFromNode,
'write-missing-at-file-nodes': c.fileCommands.writeMissingAtFileNodes,
'write-outline-only': c.fileCommands.writeOutlineOnly,
'''
</t>
<t tx="ekr.20150511065408.6">def munge_lines(self,s):
'''Return munged lines of 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('#') > -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]
self.n += len(lines)
return lines
</t>
<t tx="ekr.20150511065408.7">def run(self):
'''Top-level code.'''
lines = self.munge_lines(self.s)
d = self.create_d(lines)
self.create_decorators(d)
print('%s commands %s failed' % (self.n,self.n_fail))
</t>
<t tx="ekr.20160304051536.1">d = p.v.u
if d:
for key in sorted(d):
print('%10s %s' % (key, d.get(key)))</t>
<t tx="ekr.20160316094834.1">beautify-tree
backup
ctrl-click-at-cursor
# expand-main-splitter
# contract-main-splitter
# expand-body-pane
# import-ipynb
# exec-py-file
# find-source-for-command
# execute-script
# expand-vr-pane
# contract-body-pane
# contract-vr-pane
# contract-vr3-pane
# contract-log-pane
# parse-ipynb
# test.ipynb
# vr-toggle
# vr3-toggle
# add-editor
# beautify-files
# clone-to-at-spot
# help-for-layouts
# import-any-file
# import-to-indented-c
# import-to-indented-lisp
# import-to-indented-typescript
# merge-node-with-next-node
# merge-node-with-prev-node
# pylint
# refresh-from-disk
# reload-outline
# reload-settings
# show-layouts
# show-plugin-handlers
# stickynote
</t>
<t tx="ekr.20160517122729.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 = "<by name>"
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 = "<by class>"
else:
ttnd = c.p.v
for cname in sorted(things):
if len(things[cname]) == 1:
tnd = ttnd
else:
tnd = ttnd.insertAsLastChild()
tnd.h = "<%s>"%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_) > 100:
nd = c.p.v.insertAsLastChild()
nd.h = "<%s of %d items truncated>" % len(list_.__class__.__name__, list_)
if len(list_) == 0:
nd = c.p.v.insertAsLastChild()
nd.h = "<%s of 0 items>" % 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_) > 100:
nd = c.p.v.insertAsLastChild()
nd.h = "<dict of %d items truncated>" % len(dict_)
if len(dict_) == 0:
nd = c.p.v.insertAsLastChild()
nd.h = "<dict of 0 items>"
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.20160531065801.1">g.cls()
import unittest
# import pyflakes
# print(pyflakes)
import os
import sys
path = g.os_path_finalize_join(os.curdir, '..')
print(path)
if 0:
import importlib
import importlib.util
# importlib.invalidate_caches()
pyflakes = importlib.util.spec_from_file_location("pyflakes", path)
# importlib.import_module('pyflakes', path)
else:
if 'pyflakes' in sys.modules:
del sys.modules['pyflakes']
if sys.path[0] != path:
sys.path.insert(0, path)
import pyflakes
print(pyflakes)
if 1:
from pyflakes.test import test_api, test_doctests, test_imports, test_other
from pyflakes.test import test_return_with_arguments_inside_generator
from pyflakes.test import test_undefined_names
tests = (
test_api,
test_doctests,
test_imports, test_other,
test_return_with_arguments_inside_generator,
test_undefined_names,
)
loader = unittest.TestLoader()
suite = unittest.TestSuite()
for module in tests:
suite.addTest(loader.loadTestsFromModule(module))
unittest.TextTestRunner(verbosity=1).run(suite)</t>
<t tx="ekr.20160811105733.1">g.cls()
errors, n = 0, 0
path = r'c:\prog\NT1967masterLIST.csv'
s = open(path,'r').read()
s = g.toUnicode(s)
lines = g.splitLines(s)
print(len(lines))
for line in lines[1:]:
line = line.strip()
if line:
fields = line.split(',')
if len(fields) > 2 and ('deceased' in fields[2].lower()):
try:
date = fields[2].lower().replace('deceased','').strip()
# print('%4s %20s %s %s' % (fields[0], date, fields[3], fields[1]))
print('%10s %s %s' % (date, fields[3], fields[1]))
n += 1
except Exception:
print('%4s **********' % (fields[0]))
errors += 1
if errors:
print('%s errors' % errors)
print('%s deceased classmates' % n)
</t>
<t tx="ekr.20160926055309.1">use_tags = False
if use_tags:
tc = c.theTagController
assert tc, 'when use_tags is True this script requires nodetags.py plugin'
root1 = g.findNodeAnywhere(c, 'my book')
assert root1, 'my book not found'
root2 = g.findNodeAnywhere(c, 'my book (sphinx)')
if root2:
while root2.hasChildren():
root2.firstChild().doDelete()
else:
last = c.lastTopLevel()
root2 = last.insertAfter()
root2.h = 'my book (sphinx)'
nasm = '.. code:: nasm\n\n'
for p in root1.self_and_subtree():
if not use_tags or use_tags and 'nasm' in tc.get_tags(p):
print(p.h)
p2 = root2.insertAsLastChild()
p2.h = p.h
p2.b = nasm + p.b
root2.expand()
c.redraw()</t>
<t tx="ekr.20161206100037.1"></t>
<t tx="ekr.20170301014406.1">@language python
'''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()
if len(words) > 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.20170411194404.1">"""
Back up this .leo file.
os.environ['LEO_BACKUP'] must be the path to an existing (writable) directory.
"""
c.backup_helper(sub_dir='ekr')
</t>
<t tx="ekr.20170610081535.1">'''take a selected region, convert each line to a section reference.'''
# For Eric S. Johansson
current = c.p
body = c.frame.body
u,undoType = c.undoer, 'expand sections'
last = c.lastTopLevel()
wrapper = c.frame.body.wrapper
sel_1, sel_2 = wrapper.getSelectionRange()
ins = wrapper.getInsertPoint()
tab_width = c.getTabWidth(c.p)
head, lines, tail, oldSel, oldYview = c.getBodyLines()
u.beforeChangeGroup(current, undoType)
lines_3 = []
for s in lines:
start_of_line, width_of_line = g.skip_leading_ws_with_indent(s, 0, c.tab_width)
new_section_heading = g.angleBrackets('{}')
l2 = s[start_of_line:].strip()
header = new_section_heading.format(l2)
# calculate replacement line for source material
lines_3.append((" "*start_of_line) + l2 + "\n")
undo_data = u.beforeInsertNode(current)
new_node = p.insertAsLastChild()
new_node.h = header
new_node.b = "'''\n'''"
u.afterInsertNode(new_node, 'Insert-Node', undo_data)
# New
c.redraw(current) # Selects the old node.
preserveSel = sel_1 == sel_2
if preserveSel:
ins += tab_width
oldSel = ins, ins
c.updateBodyPane(head, ''.join(lines_3), tail, undoType, oldSel, oldYview, preserveSel)
u.afterChangeGroup(current, undoType)
</t>
<t tx="ekr.20170629162056.1">print(p.h)
assert False</t>
<t tx="ekr.20170713105049.6" __bookmarks="7d7100580700000069735f647570657101580500000066616c73657102732e">@nosearch
</t>
<t tx="ekr.20171022115210.1">d = {
'annotate': {'priority': 2, 'prisetdate': '2017-10-22'}
'icons': [{'yoffset': 0,
'where': 'beforeHeadline',
'file': 'C:\\leo.repo\\leo-editor\\leo\\Icons\\cleo\\pri2.png',
'type': 'file',
'xoffset': 2,
'relPath': 'cleo\\pri2.png',
'on': 'vnode',
'xpad': 1,
'cleoIcon': '1'}]
}
g.printDict(p.u)
</t>
<t tx="ekr.20171218081254.1">print(c.p.numberOfChildren())</t>
<t tx="ekr.20180124064122.1">print('hi: %s' % p.h)</t>
<t tx="ekr.20180126051628.1">g.getGitIssues(
c = c,
include_body=False,
label_list = ['Bug', 'Enhancement'],
milestone = '5.7',
)
</t>
<t tx="ekr.20180126053155.1">import leo.core.leoTips as leoTips
leoTips.make_tip_nodes(c)
</t>
<t tx="ekr.20180126174551.1" __bookmarks="7d7100580700000069735f647570657101580500000066616c73657102732e">"""Render a formula in latex to formula.png"""
# http://stackoverflow.com/questions/9818279/render-equation-to-png-file-using-python
# \theta=\theta+C(1+\theta-\beta)\sqrt{1-\theta}succ_mul
import leo.core.leoGlobals as g
from io import BytesIO as StringIO
import matplotlib.pyplot as plt
import time
def render_latex(formula, fontsize=12, dpi=300, format_='svg'):
"""Renders LaTeX formula into image.
"""
fig = plt.figure(figsize=(0.01, 0.01))
fig.text(0, 0, u'${}$'.format(formula), fontsize=fontsize)
buffer_ = StringIO()
fig.savefig(buffer_, dpi=dpi, transparent=True, format=format_, bbox_inches='tight', pad_inches=0.0)
plt.close(fig)
return buffer_.getvalue()
t1 = time.process_time()
formula = r'\theta=\theta+C(1+\theta-\beta)\sqrt{1-\theta}succ_mul'
image_bytes = render_latex(formula, fontsize=10, dpi=200, format_='png')
with open('formula.png', 'wb') as image_file:
image_file.write(image_bytes)
g.es_print('%5.2f sec' % (time.process_time()-t1))
</t>
<t tx="ekr.20180126175239.1" __bookmarks="7d7100580700000069735f647570657101580500000066616c73657102732e"></t>
<t tx="ekr.20180211124129.1"># Note: everything is in test/compare, so no need to worry about changing files.
import leo.core.leoCompare as leoCompare
outlines = [
'LeoDocs.leo',
'LeoDocs-matt1.leo',
'LeoDocs-matt2.leo'
]
paths = [g.os_path_finalize_join('c:/test/compare', z) for z in outlines]
for path in paths:
if not g.os_path_exists(path):
print('does not exist: %r' % path)
break
else:
leoCompare.CompareLeoOutlines(c).diff_list_of_files(paths,visible=True)
</t>
<t tx="ekr.20180228080856.1">"""
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/
"""
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.20180327111918.1"># Make sustitutions...
aList = [
('pandas', 'pd'),
('numpy', 'np'),
]
s = p.b
for pat1, pat2 in aList:
s = s.replace(pat1, pat2)
# Create a new node, with the new text.
p2 = c.p.insertAfter()
p2.h = "Substitutions"
p2.b = s
c.selectPosition(p2)
c.redraw()
</t>
<t tx="ekr.20180407182938.1">g.cls()
d = p.v.u
print(p.h)
g.printDict(d)
</t>
<t tx="ekr.20180926061406.1">'''Create a screenshot of the present Leo outline and save it to .leo/screen_captures.'''
# --window-size=682x1264 is recommended.
from leo.core.leoQt import isQt5, QtGui
import time
base = r'C:\Users\edreamleo\.leo\screen_captures'
assert g.os_path_exists(base), repr(base)
window = g.app.gui.qtApp.activeWindow()
w = window.grab() if isQt5 else QtGui.QPixmap.grabWindow(window.winID())
fn = '%s.png' % time.strftime('%Y-%m-%d-%H-%M-%S')
path = g.os_path_finalize_join(base, fn)
w.save(path, 'png')
g.es_print('saved: %s' % path)
</t>
<t tx="ekr.20180926104417.1">'''
Save an image on the clipboard to .leo/screen_captures.
Use Alt-PrintScn to copy the active window to the clipboard.
'''
import time
app = g.app.gui.qtApp
app.processEvents()
image = app.clipboard().image()
if not image.isNull():
base = r'C:\Users\edreamleo\.leo\screen_captures'
assert g.os_path_exists(base), repr(base)
fn = '%s.png' % time.strftime('%Y-%m-%d-%H.%M.%S')
path = g.os_path_finalize_join(base, fn)
image.save(path, 'png')
g.es_print('saved: %s' % path)
</t>
<t tx="ekr.20181028130924.1"># g.cls()
if 1:
print('----- restarting -----')
c.k.simulateCommand('reload-all-settings')
import imp
import leo.plugins.leowapp as leowapp
imp.reload(leowapp)
pc = g.app.pluginsController
pc.unloadOnePlugin('leoapp', verbose=True)
pc.loadOnePlugin('leowapp', tag='open0', verbose=True)
g.execute_shell_commands('&moz http://127.0.0.1:8100/ekr.leo')
</t>
<t tx="ekr.20190515192551.1" __bookmarks="7d7100580700000069735f647570657101580500000066616c73657102732e">'''A prototype of running adoc and asciidoctor.'''
import os
p = g.findNodeAnywhere(c, r'@adoc ad_test.adoc')
assert p
paths = c.asciiDoctorCommands.adoc_command(event=g.Bunch(p=p),verbose=False)
paths = [os.path.abspath(os.path.normpath(z)) for z in paths]
input_paths = ' '.join(paths)
g.execute_shell_commands(['asciidoctor %s' % input_paths])
output_paths = ' '.join([z.replace('.adoc', '.html') for z in paths])
for path in paths:
print(f"wrote: {path}\n")
if 0:
# optional: open .html files in the default browser.
g.execute_shell_commands([output_paths])
</t>
<t tx="ekr.20190602065922.1" __bookmarks="7d7100580700000069735f647570657101580500000066616c73657102732e">root = c.lastTopLevel().insertAfter()
root.h = p.h
for i, line in enumerate(g.splitLines(p.b)):
p2 = root.insertAsLastChild()
p2.h = 'Node %s' % i
p2.b = line
c.redraw()
</t>
<t tx="ekr.20200303123433.1">demo = r"C:\leo.repo\qt-examples\src\pyqt-official/qtdemo/qtdemo.py"
g.execute_shell_commands(rf'&python "{demo}"')
</t>
<t tx="ekr.20200303124744.1">demo = r"C:\test\qt_proto.py"
g.execute_shell_commands(rf'&python {demo}')
</t>
<t tx="ekr.20200316054710.1" annotate="7d71002858080000007072696f7269747971015804000000393939397102580a000000707269736574646174657103580a000000323032312d30332d33307104752e"> # Recommended plugins, from leoSettings.leo:
plugins_menu.py
contextmenu.py # Required by the vim.py and xemacs.py plugins.
mod_scripting.py
nav_qt.py
viewrendered.py
# viewrendered3.py
### Testing
# define_qt_layouts.py
# nodetags.py
# quicksearch.py
# todo.py
# stickynotes.py
### All others.
# backlink.py
# bookmarks.py
# freewin.py
# mod_autosave.py
# quickMove.py
# screenshots.py
# settings_finder.py
# rpcalc.py
# wikiview.py
</t>
<t tx="ekr.20200322213121.1">"""
Run the Javascripot code in the node selected in the outline.
"""
from subprocess import run
graal = r"C:\apps\graalvm-ce-java11-20.0.0\languages\js\bin\js.exe"
progfile = r"C:\test\grall_input.txt"
s = c.atFileCommands.stringToString(
p, p.b, forcePythonSentinels=False, sentinels=False)
prog = s.replace("\r\n", "\n") # Use brute force.
with open(progfile, 'w') as f:
f.write(s)
cmd = f'{graal} {progfile}'
result = run(cmd, capture_output=True, text=True, encoding='utf-8')
print(result.stdout or 'no output')
</t>
<t tx="ekr.20200518064548.1">
</t>
<t tx="ekr.20201109162524.1" annotate="7d71002858080000007072696f7269747971015804000000393939397102580a000000707269736574646174657103580a000000323032302d31312d31317104752e">u = c.undoer
command = 'Uppercase Body'
bunch = u.beforeChangeBody(p)
p.b = p.b.upper()
c.setChanged()
p.setDirty()
u.afterChangeBody(p, command, bunch)
</t>
<t tx="ekr.20201110091730.1">u = c.undoer
command = 'Uppercase Head'
bunch = u.beforeChangeHead(p)
p.h = p.h.upper()
c.setChanged()
p.setDirty()
u.afterChangeHead(p, command, bunch)
</t>
<t tx="ekr.20210306054745.1"></t>
<t tx="ekr.20210414174148.1">g.cls()
print('rclick hi: %s' % c.p.h)
print('dir()', dir())
print(script_args)
print(script_gnx)</t>
<t tx="ekr.20210531084324.1"># This node contains the commands needed to execute a program in a particular language.
# Format: language-name: command
# Create a temporary file if c.p is not any kind of @<file> node.
# Compute the final command as follows:
# 1. If command contains <FILE>, replace <FILE> with the full path to the external file.
# 2. If command contains <NO-FILE>, just remove <NO-FILE>.
# 3. Otherwise, append the full path to the external file to the command.
go: go run . <NO-FILE>
python: python
rust: rustc
</t>
<t tx="ekr.20210531094929.1"># This node contains the regex pattern to determine the line number in error messages.
# Format: language-name: regex pattern
#
# Patterns must define two groups, in either order:
# One group, containing only digits, defines the line number.
# The other group defines the file name.
go: ^\s*(.*):([0-9]+):([0-9]+):.+$
python: ^\s*File "(.+)", line ([0-9]+), in .+$
rust: ^\s*--> (.+):([0-9]+):([0-9]+)\s*$</t>
<t tx="ekr.20210724082245.1">g.cls()
import random
import os
import shutil
base_path = r'C:\Users\Edward~1\Edward4'
assert os.path.exists(base_path), base_path
slideshow_path = r'C:\Users\Edward~1\SlideShow'
assert os.path.exists(slideshow_path), slideshow_path
assert os.path.isdir(slideshow_path)
kinds = {}
files = []
directories = []
starting_directories_s = r"""\
main\lust
"""
<< other directories >>
starting_directories = starting_directories_s.split('\n')[1:]
# g.printObj(starting_directories)
starting_directories = [os.path.join(base_path, z) for z in starting_directories if z]
g.printObj(starting_directories)
#
# Delete all files in ~/Slideshow
for filename in os.listdir(slideshow_path):
file_path = os.path.join(slideshow_path, filename)
if os.path.isfile(file_path):
os.unlink(file_path)
def do_dir(path):
for z in os.scandir(path):
if z.is_dir():
directories.append(z.path)
do_dir(z.path)
elif z.is_file():
ext = os.path.splitext(z.path)[1].lower()
kinds [ext] = kinds.get(ext, 0) + 1
if ext in ('.jpeg', '.jpg', '.bmp', '.png'):
files.append(z.path)
# do_dir(base_path)
for dir_ in starting_directories:
do_dir(dir_)
print(f"Found {len(files)} pictures in {len(directories)} directories")
#
# Add randomized files to ~/Slideshow.
random_files = random.sample(files, min(100, len(files)))
for f in random_files:
shutil.copy(f, slideshow_path)
print('Updated', slideshow_path)
</t>
<t tx="ekr.20210724085930.1"># main\lust\bdsm
# main\lust\couples
# main\lust\couples\before-after
# main\lust\couples\couples-other
# main\lust\couples\couples-sex
# main\lust\couples\cum
# main\lust\couples\mutual
# main\lust\couples\vintage-gf
# main\lust\ready
# main\lust\ready\Lust-2003 & earlier
# main\lust\ready\Lust-2004
# main\lust\ready\Lust-2005
# main\lust\ready\Lust-2006
# main\lust\ready\Lust-2007
# main\lust\ready\Lust-2008
# main\lust\ready\Lust-2009
# main\lust\ready\Lust-2010
# main\lust\ready\Lust-2011
# main\lust\ready\Lust-2012
# main\lust\ready\Lust-2013
# main\lust\ready\Lust-2014
# main\lust\ready\Lust-2015
# main\lust\ready\Lust-2016
# main\lust\ready\Lust-2017
# main\lust\ready\Lust-2018
# main\lust\ready\Lust-2019
# main\Lust-2020
# main\multiple-best
# main\nn
# main\nn\bikini
# main\nn\faces-for-cum
# main\nn\honeymoon
# main\nn\honeymoon\New
# main\nn\prom-single
# main\nn\swimmers
# main\selfie
# main\voy
# main\young
# others
# others\cl
# others\cl\face-clit
# others\face-cock
# others\pro
# others\vintage
</t>
<t tx="ekr.20220327060129.1"></t>
<t tx="ekr.20220704210149.1">print(p.gnx)</t>
<t tx="ekr.20220913071804.2">Set to True to enable node appearance modifications
See tree-declutter-patterns
</t>
<t tx="ekr.20221022090126.1"># show-settings creates this tab.
c.frame.log.deleteTab('Settings')</t>
<t tx="ekr.20230317072300.1"></t>
<t tx="ekr.20230327032043.1"></t>
<t tx="ekr.20230618112751.1">@language python
"""Take a screenshot and save it in ~/.leo"""
g.app.pluginsController.loadOnePlugin('leo.plugins.screenshots', verbose=True)
c.k.simulateCommand('take-global-screen-shot')
</t>
<t tx="ekr.20231023035556.1">h = '--- @edit files'
root = g.findTopLevelNode(c, h)
start_s = 'LilyPond is free software:'
end_s = 'If not, see <http://www.gnu.org/licenses/>.'
for p in root.children():
s = p.b
i = s.find(start_s)
j = s.find(end_s)
if -1 < i < j:
s = s[:i] + s[j + len(end_s):]
p.b = s
else:
print('not found', p.h)
print('done')</t>
<t tx="ekr.20231123111324.1">g.cls()
import os
file_name = g.os_path_finalize_join(g.app.loadDir, '..', '..', 'README.md')
assert os.path.exists(file_name), file_name
g.openWithFileName(file_name, old_c = c)</t>
<t tx="ekr.20240208210018.1">dir_list = (
r'C:\Repos\RustPython\common\src',
r'C:\Repos\RustPython\compiler\codegen\src',
r'C:\Repos\RustPython\compiler\core\src',
r'C:\Repos\RustPython\compiler\src',
r'C:\Repos\RustPython\compiler\codegen\src', # compile.rs: AST to bytecode.
r'C:\Repos\RustPython\compiler\core\src', # bytecode.rs: implements bytecodes.
r'C:\Repos\RustPython\derive\src',
r'C:\Repos\RustPython\derive-impl\src',
r'C:\Repos\RustPython\pylib\src',
r'C:\Repos\RustPython\src',
r'C:\Repos\RustPython\stdlib\src',
r'C:\Repos\RustPython\vm\src', # compiler.rs.
r'C:\Repos\RustPython\vm\src\stdlib', # *****ast.rs Also, many .rs versions of stdlib.
r'C:\Repos\RustPython\vm\src\vm', # compile.rs.
r'C:\Repos\RustPython\vm\src\stdlib\ast', # gen.rs automatically generated by ast/asdl_rs.py.
)
</t>
<t tx="ekr.20240302052316.1">g.cls()
import os
fn = 'README.md'
path = g.os_path_finalize_join(g.app.loadDir, '..', '..', fn)
contents = g.readFileIntoUnicodeString(path)
last = c.lastTopLevel()
p = last.insertAfter()
p.h = fn
c.importCommands.createOutline(p, ext='.txt', s=contents)
c.redraw(p)</t>
<t tx="ekr.20240517034559.1">"""
Example script to insert/hide a red frame in the main splitter.
"""
from leo.core.leoQt import QtWidgets
QFrame = QtWidgets.QFrame
@others # Define helpers
gui = g.app.gui
red_frame = gui.find_widget_by_name(c, 'red-frame')
if red_frame:
toggle(red_frame)
else:
main_splitter = gui.find_widget_by_name(c, 'main_splitter')
red_frame = make_red_frame()
main_splitter.insertWidget(1, red_frame)
</t>
<t tx="ekr.20240518073948.1">def toggle(w: QFrame) -> None:
if w.isVisible():
w.hide()
else:
w.show()
def make_red_frame() -> QFrame:
w = QtWidgets.QFrame()
max_width = w.maximumSize().width()
desired_height = 200
w.setMinimumSize(max_width, desired_height)
w.setStyleSheet("background: 'red';")
w.setObjectName('red-frame')
return w
</t>
<t tx="ekr.20240518074638.1">"""
Example script: Create or toggle a blue QSplitter containing a red QFrame.
"""
from leo.core.leoQt import QtWidgets
QFrame = QtWidgets.QFrame
QSplitter = QtWidgets.QSplitter
@others # Define helpers
gui = g.app.gui
blue_splitter = gui.find_widget_by_name(c, 'blue-splitter')
red_frame = gui.find_widget_by_name(c, 'red-frame')
if red_frame:
toggle(blue_splitter)
else:
red_frame = make_red_frame()
parent_w = gui.find_widget_by_name(c, 'bodyFrame')
assert(parent_w)
blue_splitter = make_blue_splitter()
blue_splitter.setParent(parent_w)
blue_splitter.insertWidget(0, red_frame)
blue_splitter.show()</t>
<t tx="ekr.20240518074638.2">def toggle(w: QFrame) -> None:
if w.isVisible():
w.hide()
else:
w.show()
def make_red_frame() -> QFrame:
w = QtWidgets.QFrame()
max_width = w.maximumSize().width()
desired_height = 100
w.setMinimumSize(max_width, desired_height)
w.setStyleSheet("background: 'red';")
w.setObjectName('red-frame')
return w
def make_blue_splitter() -> QSplitter:
w = QtWidgets.QSplitter()
w.setStyleSheet("background: 'blue';")
w.setObjectName('blue-splitter')
return w
</t>
<t tx="ekr.20240521150404.1">"""
Example script to activate the VR plugin and detach its pane.
"""
gui = g.app.gui
c.doCommandByName('vr') # Try to activate the VR plugin.
vr = gui.find_widget_by_name(c, 'viewrendered_pane')
if vr:
vr.setParent(None)
vr.resize(500, 400)
vr.move(50, 50)
vr.show()
</t>
<t tx="ekr.20240624052855.1">"""
Add a red frame to the body pane or a new splitter, depending on the main
splitter's *initial* orientation.
This script can only be run once. To see both possibilities, execute
toggle-split-orientation before running this script.
"""
from leo.core.leoQt import Orientation, QtWidgets
QFrame = QtWidgets.QFrame
QSplitter = QtWidgets.QSplitter
@others # Define helpers
gui = g.app.gui
main_splitter = gui.find_widget_by_name(c, 'main_splitter')
red_frame = gui.find_widget_by_name(c, 'red-frame')
if red_frame:
toggle(red_frame)
elif main_splitter.orientation() == Orientation.Vertical:
# Share the red pane with the body pane by creating a new splitter.
new_splitter = make_splitter()
red_frame = make_red_frame()
main_splitter.addWidget(new_splitter)
body_frame = gui.find_widget_by_name(c, 'bodyFrame')
new_splitter.addWidget(body_frame)
new_splitter.addWidget(red_frame)
# Give equal width to all splitter panes.
new_splitter.setSizes([100000] * len(new_splitter.sizes()))
main_splitter.setSizes([100000] * len(main_splitter.sizes()))
else:
# Add the red frame in the secondary splitter.
secondary_splitter = gui.find_widget_by_name(c, 'secondary_splitter')
red_frame = make_red_frame()
secondary_splitter.addWidget(red_frame)
# Give equal width to the panes in the secondary splitter.
secondary_splitter.setSizes([100000] * len(secondary_splitter.sizes()))
c.redraw()
c.bodyWantsFocusNow()
</t>
<t tx="ekr.20240624053504.1">def toggle(w: QFrame) -> None:
if w.isVisible():
w.hide()
else:
w.show()
def make_blue_splitter() -> QSplitter:
w = QtWidgets.QSplitter()
# w.setStyleSheet("background: 'blue';")
w.setObjectName('blue-splitter')
return w
def make_red_frame() -> QFrame:
w = QtWidgets.QFrame()
max_width = w.maximumSize().width()
desired_height = 200
w.setMinimumSize(max_width, desired_height)
w.setStyleSheet("background: 'red';")
w.setObjectName('red-frame')
return w
def make_splitter() -> QSplitter:
w = QtWidgets.QSplitter()
w.setObjectName('new-splitter')
return w
</t>
<t tx="ekr.20240726151728.1"># legacy: (default) Leo's legacy layout
# big-tree: replaces @bool big-outline-pane
# horizontal-thirds: VR & VR3 panes at bottom.</t>
<t tx="ekr.20241012032943.1">print('@command test')</t>
<t tx="ekr.20241110171219.1">g.cls()
colorizer = c.frame.body.colorizer
g.printObj(colorizer.stateDict)</t>
<t tx="ekr.20241207020428.1"></t>
<t tx="ekr.20250321170720.1">True: Scripts to be executed (from @command, @button, CTRL+B from body pane, etc... ) will be wrapped in
def main():
<script>
result = main()
to allow for return values to be captured if your script tries to 'return' a value.
Example: If you have an @command my-command node that contains:
return 2+2
then you could run a script that contains
output = c.doCommandByName('my-command')
print(output)
which would print 4.
Note: By default, script execution will return the value it may have set in a global variable named "result". (or None)</t>
<t tx="ekr.20250329085219.1"></t>
<t tx="ekr.20250329085219.2">True: Chapter tabs appear in the outline pane.
False: Chapter tabs do not appear.</t>
<t tx="ekr.20250329085219.3">True: Chapter commands are functional.
False: Chapter commands do not exists.
Leo shows the chapters dropdown box only if this setting is True.
</t>
<t tx="ekr.20250329085219.4">True: Position the Chapters drop-down at the left of the icon bar.</t>
<t tx="ekr.20250329085342.1"></t>
<t tx="ekr.20250329085349.1"></t>
<t tx="ekr.20250329085411.1">Chapter 1</t>
<t tx="ekr.20250329085443.1">Chapter 2</t>
<t tx="ekr.20250331190146.1"></t>
<t tx="ekr.20250528090321.1">Blah blah blah</t>
</tnodes>
</leo_file>