def embed(self): """called from ns_do_context - embed layout in outline's @settings, an alternative to the Load/Save named layout system """ # Careful: we could be unit testing. top_splitter = self.get_top_splitter() if not top_splitter: return c = self.c layout = top_splitter.get_saveable_layout() nd = g.findNodeAnywhere(c, "@data free-layout-layout") if not nd: settings = g.findNodeAnywhere(c, "@settings") if not settings: settings = c.rootPosition().insertAfter() settings.h = "@settings" # type:ignore nd = settings.insertAsNthChild(0) nd.h = "@data free-layout-layout" nd.b = json.dumps(layout, indent=4) nd = nd.parent() if not nd or nd.h != "@settings": g.es( "WARNING: @data free-layout-layout node is not under an active @settings node" ) c.redraw()
def test_p_relinkAsCloneOf(self): # test-outline: root # child clone a # node clone 1 # child b # child clone a # node clone 1 # child c # node clone 1 # child clone a # node clone 1 # child b # child clone a # node clone 1 c, u = self.c, self.c.undoer p = c.p.next() child_b = g.findNodeAnywhere(c, 'child b') self.assertTrue(child_b) self.assertTrue(child_b.isCloned()) # # child_c must *not* be a clone at first. child_c = g.findNodeAnywhere(c, 'child c') self.assertTrue(child_c) self.assertFalse(child_c.isCloned()) # # Change the tree. bunch = u.beforeChangeTree(p) child_c._relinkAsCloneOf(child_b) u.afterChangeTree(p, 'relink-clone', bunch) # self.dump_tree('Before...') u.undo() # self.dump_tree('After...') self.assertTrue(child_b.isCloned()) self.assertFalse(child_c.isCloned())
def embed(self): """called from ns_do_context - embed layout in outline's @settings, an alternative to the Load/Save named layout system """ # Careful: we could be unit testing. top_splitter = self.get_top_splitter() if not top_splitter: return c = self.c layout=top_splitter.get_saveable_layout() nd = g.findNodeAnywhere(c, "@data free-layout-layout") if not nd: settings = g.findNodeAnywhere(c, "@settings") if not settings: settings = c.rootPosition().insertAfter() settings.h = "@settings" nd = settings.insertAsNthChild(0) nd.h = "@data free-layout-layout" nd.b = json.dumps(layout, indent=4) nd = nd.parent() if not nd or nd.h != "@settings": g.es("WARNING: @data free-layout-layout node is not " \ "under an active @settings node") c.redraw()
def init_dict(c): """ (Re)Initialize the formats dictionary """ cs = str(c) try: fbody = g.findNodeAnywhere(c, "Headline Formats").b except Exception as e: g.es_trace("This outline has no Headline Formats node\n" + str(e)) return try: # There is something wrong. Both pylint and mypy complain. # pylint: disable=no-value-for-parameter formats = yaml.load(fbody) # type:ignore except Exception as e: g.es_trace("Could not parse Headline Format yaml file\n" + str(e)) return try: formats = formats["Headline Formats"] except Exception as e: g.es_trace("Yaml file does not have proper heading.\n" + str(e)) return #preprocess multi headline styles g.app.permanentScriptDict[cs + 'formats'] = {} try: for k, f in formats.items(): if "`" in k: _ = k.split("`") for _1 in _: g.app.permanentScriptDict[cs + 'formats'][_1.strip()] = f else: g.app.permanentScriptDict[cs + 'formats'][k] = f except Exception as e: g.es_error(e)
def lee_f(self, s): """ Open file(s)/objects in Leo - %lee hist -> open full session history in leo - Takes an object. l = [1,2,"hello"]; %lee l. Alt+I in leo pushes the object back - Takes an mglob pattern, e.g. '%lee *.cpp' or %lee 'rec:*.cpp' - Takes input history indices: %lee 4 6-8 10 12-47 """ # import os c = g_ipm.c ip = g_ipm.ip wb = g_ipm.wb try: if s == 'hist': if c: wb.ipython_history.b = g_ipm.get_history() wb.ipython_history.go() else: g.trace('no c') return if s and s[0].isdigit(): # numbers; push input slices to leo lines = self.extract_input_slices(s.strip().split(), True) v = add_var('stored_ipython_input') v.b = '\n'.join(lines) return # try editing the object directly obj = ip.user_ns.get(s, None) if obj is not None: edit_object_in_leo(obj, s) return if not c: # print('file not found: %s' % s) return # if it's not object, it's a file name / mglob pattern from IPython.external import mglob files = (os.path.abspath(f) for f in mglob.expand(s)) for fname in files: p = g.findNodeAnywhere(c, '@auto ' + fname) if not p: p = c.currentPosition().insertAfter() p.setHeadString('@auto ' + fname) if os.path.isfile(fname): c.setBodyString(p, open(fname).read()) c.selectPosition(p) print("Editing file(s), \ press ctrl+shift+w in Leo to write @auto nodes") finally: if c: c.redraw()
def test_delete_all_children_of_persistence_node(self): c, pd = self.c, self.c.persistenceController persistence = g.findNodeAnywhere(c, '@persistence') assert persistence assert pd.has_at_persistence_node() persistence.deleteAllChildren() assert persistence
def test_pd_has_at_gnxs_node(self): c, pd = self.c, self.c.persistenceController # Set up the tree. root = self.root_p root.h = '@auto root' # Make root look like an @auto node. inner_clone = root.insertAsLastChild() inner_clone.h = 'clone' outer_clone = inner_clone.clone() outer_clone.moveAfter(root) # Test the tree. persistence = g.findNodeAnywhere(c, '@persistence') assert persistence assert pd.has_at_persistence_node() # Update the tree. persistence.deleteAllChildren() # Required assert persistence pd.update_before_write_foreign_file(root) data = g.findNodeInTree(c, persistence, '@data:@auto root') assert data data2 = pd.has_at_data_node(root) assert data2 self.assertEqual(data, data2, (data, data2)) gnxs = g.findNodeInTree(c, persistence, '@gnxs') assert gnxs gnxs2 = pd.has_at_gnxs_node(root) assert gnxs2 self.assertEqual(gnxs, gnxs2, (gnxs, gnxs2))
def init_dict(c): """ (Re)Initialize the formats dictionary """ cs = str(c) try: fbody = g.findNodeAnywhere(c, "Headline Formats").b except Exception as e: g.es_trace("This outline has no Headline Formats node\n" + str(e)) return try: formats = yaml.load(fbody) except Exception as e: g.es_trace("Could not parse Headline Format yaml file\n" + str(e)) return try: formats = formats["Headline Formats"] except Exception as e: g.es_trace("Yaml file does not have proper heading.\n" + str(e)) return #preprocess multi headline styles g.app.permanentScriptDict[cs + 'formats'] = {} try: for k, f in formats.items(): if "`" in k: _ = k.split("`") for _1 in _: g.app.permanentScriptDict[cs + 'formats'][_1.strip()] = f else: g.app.permanentScriptDict[cs + 'formats'][k] = f except Exception as e: g.es_error(e)
def add_var(varname): # pylint: disable=E1101 # E1101:add_var: Class 'LeoNode' has no 'p' member c = g_ipm.c # g.trace(varname) if not c: return r = rootnode() try: if r is None: p2 = g.findNodeAnywhere(c,varname) else: p2 = g.findNodeInChildren(c,r.p,varname) if p2: return LeoNode(p2) if r is not None: p2 = r.p.insertAsLastChild() else: p2 = c.currentPosition().insertAfter() c.setHeadString(p2,varname) return LeoNode(p2) finally: c.redraw()
def find_node(self, headline): '''Return the node whose headline is given.''' c = self.c if self.root: p = g.findNodeInTree(c, self.root, headline) else: p = g.findNodeAnywhere(c, headline) return p
def test_pd_restore_gnxs(self): c, pd = self.c, self.c.persistenceController root = self.root_p # Set up the tree. persistence = g.findNodeAnywhere(c, '@persistence') assert persistence gnxs = g.findNodeAnywhere(c, '@gnxs') assert gnxs inner_clone = root.insertAsLastChild() inner_clone.h = 'clone' outer_clone = inner_clone.clone() outer_clone.moveAfter(root) node1 = root.insertAsLastChild() node1.h = 'node1' # Test. root.deleteAllChildren() pd.restore_gnxs(gnxs, root)
def run_leo_startup_node(self): c = self.c p = g.findNodeAnywhere(c,'@ipy-startup') if p: print("Running @ipy-startup nodes") for n in LeoNode(p): # self.push_from_leo(n) CommandChainDispatcher(n)
def createMyLeoSettings(c): """createMyLeoSettings - Return true if myLeoSettings.leo created ok """ name = "myLeoSettings.leo" homeLeoDir = g.app.homeLeoDir loadDir = g.app.loadDir configDir = g.app.globalConfigDir # check it doesn't already exist for path in homeLeoDir, loadDir, configDir: fileName = g.os_path_join(path, name) if g.os_path_exists(fileName): return None ok = g.app.gui.runAskYesNoDialog(c, title='Create myLeoSettings.leo?', message=f"Create myLeoSettings.leo in {homeLeoDir}?", ) if ok == 'no': return None # get '@enabled-plugins' from g.app.globalConfigDir fileName = g.os_path_join(configDir, "leoSettings.leo") leosettings = g.openWithFileName(fileName, old_c=c) enabledplugins = g.findNodeAnywhere(leosettings, '@enabled-plugins') enabledplugins = enabledplugins.b leosettings.close() # now create "~/.leo/myLeoSettings.leo" fileName = g.os_path_join(homeLeoDir, name) c2 = g.openWithFileName(fileName, old_c=c) # add content to outline nd = c2.rootPosition() nd.h = "Settings README" nd.b = ( "myLeoSettings.leo personal settings file created {time}\n\n" "Only nodes that are descendants of the @settings node are read.\n\n" "Only settings you need to modify should be in this file, do\n" "not copy large parts of leoSettings.py here.\n\n" "For more information see http://leoeditor.com/customizing.html" "".format(time=time.asctime()) ) nd = nd.insertAfter() nd.h = '@settings' nd = nd.insertAsNthChild(0) nd.h = '@enabled-plugins' nd.b = enabledplugins nd = nd.insertAfter() nd.h = '@keys' nd = nd.insertAsNthChild(0) nd.h = '@shortcuts' nd.b = ( "# You can define keyboard shortcuts here of the form:\n" "#\n" "# some-command Shift-F5\n" ) c2.redraw() return c2
def createMyLeoSettings(c): """createMyLeoSettings - Return true if myLeoSettings.leo created ok """ name = "myLeoSettings.leo" homeLeoDir = g.app.homeLeoDir loadDir = g.app.loadDir configDir = g.app.globalConfigDir # check it doesn't already exist for path in homeLeoDir, loadDir, configDir: fileName = g.os_path_join(path, name) if g.os_path_exists(fileName): return None ok = g.app.gui.runAskYesNoDialog(c, title = 'Create myLeoSettings.leo?', message = 'Create myLeoSettings.leo in %s?' % (homeLeoDir), ) if ok == 'no': return # get '@enabled-plugins' from g.app.globalConfigDir fileName = g.os_path_join(configDir, "leoSettings.leo") leosettings = g.openWithFileName(fileName, old_c=c) enabledplugins = g.findNodeAnywhere(leosettings, '@enabled-plugins') enabledplugins = enabledplugins.b leosettings.close() # now create "~/.leo/myLeoSettings.leo" fileName = g.os_path_join(homeLeoDir, name) c2 = g.openWithFileName(fileName, old_c=c) # add content to outline nd = c2.rootPosition() nd.h = "Settings README" nd.b = ( "myLeoSettings.leo personal settings file created {time}\n\n" "Only nodes that are descendants of the @settings node are read.\n\n" "Only settings you need to modify should be in this file, do\n" "not copy large parts of leoSettings.py here.\n\n" "For more information see http://leoeditor.com/customizing.html" "".format(time=time.asctime()) ) nd = nd.insertAfter() nd.h = '@settings' nd = nd.insertAsNthChild(0) nd.h = '@enabled-plugins' nd.b = enabledplugins nd = nd.insertAfter() nd.h = '@keys' nd = nd.insertAsNthChild(0) nd.h = '@shortcuts' nd.b = ( "# You can define keyboard shortcuts here of the form:\n" "#\n" "# some-command Shift-F5\n" ) c2.redraw() return c2
def openCheatSheet(self, event=None): """Open leo/doc/cheatSheet.leo""" c = self fn = g.os_path_finalize_join(g.app.loadDir, '..', 'doc', 'CheatSheet.leo') if not g.os_path_exists(fn): g.es(f"file not found: {fn}") return c2 = g.openWithFileName(fn, old_c=c) p = g.findNodeAnywhere(c2, "Leo's cheat sheet") if p: c2.selectPosition(p) p.expand() c2.redraw()
def getData(self,s): trace = False and not g.unitTesting c = self.c if 0: # Good for testing: can change the @data node on the fly. p = g.findNodeAnywhere(c,'@data %s' % s) if p: return [s for s in g.splitLines(p.b) if s.strip() and not s.startswith('#')] else: if trace: g.trace('not found: %s' % s) return [] else: return c.config.getData(s) or []
def test_pd_update_before_write_foreign_file(self): c, pd = self.c, self.c.persistenceController root = self.root_p assert root persistence = pd.find_at_persistence_node() assert persistence persistence.deleteAllChildren() root.h = '@auto root' # Make root look like an @auto node. pd.update_before_write_foreign_file(root) data = g.findNodeAnywhere(c, '@data:@auto root') assert data gnxs = g.findNodeInTree(c, data, '@gnxs') assert gnxs
def find_at_persistence_node(self): ''' Find the first @persistence node in the outline. If it does not exist, create it as the *last* top-level node, so that no existing positions become invalid. ''' c,h = self.c,'@persistence' p = g.findNodeAnywhere(c,h) if not p and self.enabled: last = c.rootPosition() while last.hasNext(): last.moveToNext() p = last.insertAfter() p.h = h return p
def test_tree(self): c = self.c table = ( (0, 'Root'), (0, 'Node 1'), (1, 'child 2'), (2, 'child 3'), (0, 'Node 4'), (1, 'child 5'), (2, 'child 6'), ) for level, h in table: p = g.findNodeAnywhere(c, h) self.assertEqual(p.h, h) self.assertEqual(p.level(), level)
def test_find_prev(self): c, settings, x = self.c, self.settings, self.x settings.find_text = 'def top1' # Start at end, so we stay in the node. grand_child = g.findNodeAnywhere(c, 'child 6') settings.p = grand_child assert settings.p settings.find_text = 'def child2' # Set c.p in the command. x.c.selectPosition(grand_child) p, pos, newpos = x.do_find_prev(settings) assert p self.assertEqual(p.h, 'child 2') s = p.b[pos:newpos] self.assertEqual(s, settings.find_text)
def openCheatSheet(self, event=None, redraw=True): '''Open leo/doc/cheatSheet.leo''' c = self fn = g.os_path_finalize_join(g.app.loadDir, '..', 'doc', 'CheatSheet.leo') # g.es_debug(g.os_path_exists(fn),fn) if g.os_path_exists(fn): c2 = g.openWithFileName(fn, old_c=c) if redraw: p = g.findNodeAnywhere(c2, "Leo's cheat sheet") if p: c2.selectPosition(p) p.expand() c2.redraw() return c2 g.es('file not found: %s' % fn) return None
def openCheatSheet(self, event=None, redraw=True): '''Open leo/doc/cheatSheet.leo''' c = self fn = g.os_path_finalize_join(g.app.loadDir, '..', 'doc', 'CheatSheet.leo') # g.es_debug(g.os_path_exists(fn),fn) if g.os_path_exists(fn): c2 = g.openWithFileName(fn, old_c=c) if redraw: p = g.findNodeAnywhere(c2, "Leo's cheat sheet") if p: c2.selectPosition(p) p.expand() c2.redraw() return c2 else: g.es('file not found: %s' % fn) return None
def push_cl_node(self, node): """ If node starts with @cl, eval it The result is put as last child of @ipy-results node, if it exists """ c = self.c if not node.b.startswith('@cl'): raise TryNext p2 = g.findNodeAnywhere(c, '@ipy-results') val = node.v if p2: es("=> @ipy-results") LeoNode(p2).v = val es(val)
def find_at_persistence_node(self): """ Find the first @persistence node in the outline. If it does not exist, create it as the *last* top-level node, so that no existing positions become invalid. """ # New in Leo 5.1: Leo never creates the @persistence node automatically. c, h = self.c, '@persistence' p = g.findNodeAnywhere(c, h) if not p and c.config.getBool('create-at-persistence-nodes-automatically'): last = c.rootPosition() while last.hasNext(): last.moveToNext() p = last.insertAfter() p.h = h g.es_print(f"created {h} node", color='red') return p
def find_at_persistence_node(self): ''' Find the first @persistence node in the outline. If it does not exist, create it as the *last* top-level node, so that no existing positions become invalid. ''' # New in Leo 5.1: Leo never creates the @persistence node automatically. c,h = self.c,'@persistence' p = g.findNodeAnywhere(c,h) if not p and c.config.getBool('create-at-persistence-nodes-automatically'): last = c.rootPosition() while last.hasNext(): last.moveToNext() p = last.insertAfter() p.h = h g.es('created %s node' % h,color='red') return p
def doFileAction(filename, c): p = g.findNodeAnywhere(c,"FileActions") if p: done = False name = os.path.split(filename)[1] for p2 in p.children(): pattern = p2.h.strip() if fnmatch.fnmatchcase(name, pattern): applyFileAction(p2, filename, c) done = True break if not done: g.warning("no file action matches " + filename) return False #TL - Inform onIconDoubleClick that no action was taken return True #TL - Inform onIconDoubleClick that action was taken g.warning("no FileActions node") return False #TL - Inform onIconDoubleClick that no action was taken
def push_cl_node(self,node): """ If node starts with @cl, eval it The result is put as last child of @ipy-results node, if it exists """ c = self.c if not node.b.startswith('@cl'): raise TryNext p2 = g.findNodeAnywhere(c,'@ipy-results') val = node.v if p2: es("=> @ipy-results") LeoNode(p2).v = val es(val)
def has_at_data_node(self,root): ''' Return the @data node corresponding to root, a foreign node. Return None if no such node exists. ''' # if g.unitTesting: # pass if not self.enabled: return None if not self.is_at_auto_node(root): return None views = g.findNodeAnywhere(self.c,'@persistence') if views: # Find a direct child of views with matching headline and body. s = self.at_data_body(root) for p in views.children(): if p.b == s: return p return None
def doFileAction(filename, c): p = g.findNodeAnywhere(c,"FileActions") if p: done = False name = os.path.split(filename)[1] for p2 in p.children(): pattern = p2.h.strip() if fnmatch.fnmatchcase(name, pattern): applyFileAction(p2, filename, c) done = True break if not done: g.warning("no file action matches " + filename) return False #TL - Inform onIconDoubleClick that no action was taken else: return True #TL - Inform onIconDoubleClick that action was taken else: g.warning("no FileActions node") return False #TL - Inform onIconDoubleClick that no action was taken
def copy_to_my_settings(self, unl, which): """copy_to_my_settings - copy setting from leoSettings.leo :param str unl: Leo UNL to copy from :param int which: 1-3, leaf, leaf's parent, leaf's grandparent :return: unl of leaf copy in myLeoSettings.leo :rtype: str """ trace = False and not g.unitTesting if trace: g.es(unl) path, unl = unl.split('#', 1) # Undo the replacements made in p.getUNL. path = path.replace("file://", "") path = path.replace("unl://", "") # Fix #434: Potential bug in settings unl = unl.replace('%20', ' ').split("-->") tail = [] if which > 1: # copying parent or grandparent but select leaf later tail = unl[-(which - 1):] unl = unl[:len(unl) + 1 - which] my_settings_c = self.c.openMyLeoSettings() my_settings_c.save() # if it didn't exist before, save required settings = g.findNodeAnywhere(my_settings_c, '@settings') c2 = g.app.loadManager.openSettingsFile(path) if not c2: return '' # Fix 434. found, maxdepth, maxp = g.recursiveUNLFind(unl, c2) if trace: g.trace('COPYING', unl) nd = settings.insertAsLastChild() dest = nd.get_UNL() self.copy_recursively(maxp, nd) my_settings_c.setChanged() my_settings_c.redraw() shortcutsDict, settingsDict = g.app.loadManager.createSettingsDicts( my_settings_c, False) self.c.config.settingsDict.update(settingsDict) my_settings_c.config.settingsDict.update(settingsDict) if trace: g.trace('-->'.join([dest] + tail)) return '-->'.join([dest] + tail)
def copy_to_my_settings(self, unl, which): """copy_to_my_settings - copy setting from leoSettings.leo :param str unl: Leo UNL to copy from :param int which: 1-3, leaf, leaf's parent, leaf's grandparent :return: unl of leaf copy in myLeoSettings.leo :rtype: str """ trace = False and not g.unitTesting if trace: g.es(unl) path, unl = unl.split('#', 1) # Undo the replacements made in p.getUNL. path = path.replace("file://", "") path = path.replace("unl://", "") # Fix #434: Potential bug in settings unl = unl.replace('%20', ' ').split("-->") tail = [] if which > 1: # copying parent or grandparent but select leaf later tail = unl[-(which - 1):] unl = unl[: len(unl) + 1 - which] my_settings_c = self.c.openMyLeoSettings() my_settings_c.save() # if it didn't exist before, save required settings = g.findNodeAnywhere(my_settings_c, '@settings') c2 = g.app.loadManager.openSettingsFile(path) if not c2: return '' # Fix 434. found, maxdepth, maxp = g.recursiveUNLFind(unl, c2) if trace: g.trace('COPYING', unl) nd = settings.insertAsLastChild() dest = nd.get_UNL() self.copy_recursively(maxp, nd) my_settings_c.setChanged() my_settings_c.redraw() shortcutsDict, settingsDict = g.app.loadManager.createSettingsDicts(my_settings_c, False) self.c.config.settingsDict.update(settingsDict) my_settings_c.config.settingsDict.update(settingsDict) if trace: g.trace('-->'.join([dest] + tail)) return '-->'.join([dest] + tail)
def has_at_persistence_node(self): """Return the @persistence node or None if it does not exist.""" return g.findNodeAnywhere(self.c, '@persistence')
def lee_f(self,s): """ Open file(s)/objects in Leo - %lee hist -> open full session history in leo - Takes an object. l = [1,2,"hello"]; %lee l. Alt+I in leo pushes the object back - Takes an mglob pattern, e.g. '%lee *.cpp' or %lee 'rec:*.cpp' - Takes input history indices: %lee 4 6-8 10 12-47 """ # import os c = g_ipm.c ip = g_ipm.ip wb = g_ipm.wb try: if s == 'hist': if c: wb.ipython_history.b = g_ipm.get_history() wb.ipython_history.go() else: g.trace('no c') return if s and s[0].isdigit(): # numbers; push input slices to leo lines = self.extract_input_slices(s.strip().split(), True) v = add_var('stored_ipython_input') v.b = '\n'.join(lines) return # try editing the object directly obj = ip.user_ns.get(s, None) if obj is not None: edit_object_in_leo(obj,s) return if not c: # print('file not found: %s' % s) return # if it's not object, it's a file name / mglob pattern from IPython.external import mglob files = (os.path.abspath(f) for f in mglob.expand(s)) for fname in files: p = g.findNodeAnywhere(c,'@auto ' + fname) if not p: p = c.currentPosition().insertAfter() p.setHeadString('@auto ' + fname) if os.path.isfile(fname): c.setBodyString(p,open(fname).read()) c.selectPosition(p) print("Editing file(s), \ press ctrl+shift+w in Leo to write @auto nodes") finally: if c: c.redraw()
#@+<< imports >> #@+node:ekr.20100811091636.5919: *3* << imports >> #@+at Here are the imports. #@@c import leo.core.leoGlobals as g if g.isPython3: import io StringIO = io.StringIO else: import StringIO StringIO = StringIO.StringIO #@-<< imports >> if 1: # Format a fixed node. h = '@button format-code' p = g.findNodeAnywhere(c, h) #@+<< options >> #@+node:ekr.20100811091636.5995: *3* << options >> fn = '%s.rst.txt' % (g.sanitize_filename(p.h)) # 'format-code.rst.txt' # g.es('output file',repr(fn)) defaultOptionsDict = { # The following options are the most important visually. 'show_doc_parts_as_paragraphs': True, 'number-code-lines': False, # The following options are definitely used in the script. 'generate-rst-header-comment': True,
def has_at_persistence_node(self): '''Return the @persistence node or None if it does not exist.''' return g.findNodeAnywhere(self.c,'@persistence')
def doNodeAction(pClicked, c): hClicked = pClicked.h.strip() #Display messages based on 'messageLevel'. Valid values: # 0 = log no messages # 1 = log that the plugin was triggered and each matched patterns # 2 = log 1 & 'event passed' # 3 = log 1,2 & 'no match to pattern' # 4 = log 1,2,3, & any code debugging messages, # matched pattern's 'directives', and '@file saved' settings messageLevel = c.config.getInt('nodeActions_message_level') if messageLevel >= 1: g.es( "nodeActions: triggered" ) #Save @file type nodes before running script if enabled saveAtFile = c.config.getBool('nodeActions_save_atFile_nodes') if messageLevel >= 4: g.blue( "nA: Global nodeActions_save_atFile_nodes=",saveAtFile) #Find the "nodeActions" node pNA = g.findNodeAnywhere(c,"nodeActions") if not pNA: pNA = g.findNodeAnywhere(c,"NodeActions") if pNA: #Found "nodeActions" node foundPattern = False passEventExternal = False #No pass to next plugin after pattern matched #Check entire subtree under the "nodeActions" node for pattern for pScript in pNA.subtree(): #Nodes with subnodes are not tested for a match if pScript.hasChildren(): continue #Don't trigger on double click of a nodeActions' pattern node if pClicked == pScript: continue pattern = pScript.h.strip() #Pattern node's header if messageLevel >= 4: g.blue( "nA: Checking pattern '" + pattern) #if directives exist, parse them and set directive flags for later use # pylint: disable=anomalous-backslash-in-string directiveExists = re.search( " \[[V>X],?[V>X]?,?[V>X]?]$", pattern ) if directiveExists: directives = directiveExists.group(0) else: directives = "[]" #What directives exist? useRegEx = re.search("X", directives) != None passEventInternal = re.search("V", directives) != None if not passEventExternal: #don't disable once enabled. passEventExternal = re.search(">", directives) != None #Remove the directives from the end of the pattern (if they exist) pattern = re.sub( " \[.*]$", "", pattern, 1) if messageLevel >= 4: g.blue( "nA: Pattern='" + pattern + "' " + "(after directives removed)") #Keep copy of pattern without directives for message log patternOriginal = pattern #if pattern begins with "@files" and clicked node is an @file type #node then replace "@files" in pattern with clicked node's @file type patternBeginsWithAtFiles = re.search( "^@files ", pattern ) clickedAtFileTypeNode = False #assume @file type node not clicked if patternBeginsWithAtFiles: #Check if first word in clicked header is in list of @file types firstWordInClickedHeader = hClicked.split()[0] if firstWordInClickedHeader in atFileTypes: clickedAtFileTypeNode = True #Tell "write @file type nodes" code #Replace "@files" in pattern with clicked node's @file type pattern = re.sub( "^@files", firstWordInClickedHeader, pattern) if messageLevel >= 4: g.blue( "nA: Pattern='" + pattern + "' " + "(after @files substitution)") #Check for pattern match to clicked node's header if useRegEx: match = re.search(pattern, hClicked) else: match = fnmatch.fnmatchcase(hClicked, pattern) if match: if messageLevel >= 1: g.blue( "nA: Matched pattern '" + patternOriginal + "'") if messageLevel >= 4: g.blue( "nA: Directives: X=",useRegEx, "V=",passEventInternal, ">=",passEventExternal,) #if @file type node, save node to disk (if configured) if clickedAtFileTypeNode: if saveAtFile: #Problem - No way found to just save clicked node, saving all c.fileCommands.writeAtFileNodes() c.requestRedrawFlag = True c.redraw() if messageLevel >= 3: g.blue( "nA: Saved '" + hClicked + "'") #Run the script applyNodeAction(pScript, pClicked, c) #Indicate that at least one pattern was matched foundPattern = True #Don't trigger more patterns unless enabled in patterns' headline if passEventInternal == False: break else: if messageLevel >= 3: g.blue("nA: Did not match '" + patternOriginal + "'") #Finished checking headline against patterns if not foundPattern: #no match to any pattern, always pass event to next plugin if messageLevel >= 1: g.blue("nA: No patterns matched to """ + hClicked + '"') return False #TL - Inform onIconDoubleClick that no action was taken elif passEventExternal == True: #last matched pattern has directive to pass event to next plugin if messageLevel >= 2: g.blue("nA: Event passed to next plugin") return False #TL - Inform onIconDoubleClick to pass double-click event else: #last matched pattern did not have directive to pass event to plugin if messageLevel >= 2: g.blue("nA: Event not passed to next plugin") return True #TL - Inform onIconDoubleClick to not pass double-click else: #nodeActions plugin enabled without a 'nodeActions' node if messageLevel >= 4: g.blue("nA: The ""nodeActions"" node does not exist") return False #TL - Inform onIconDoubleClick that no action was taken
def doNodeAction(pClicked, c): hClicked = pClicked.h.strip() #Display messages based on 'messageLevel'. Valid values: # 0 = log no messages # 1 = log that the plugin was triggered and each matched patterns # 2 = log 1 & 'event passed' # 3 = log 1,2 & 'no match to pattern' # 4 = log 1,2,3, & any code debugging messages, # matched pattern's 'directives', and '@file saved' settings messageLevel = c.config.getInt('nodeActions-message-level') if messageLevel >= 1: g.es("nodeActions: triggered") #Save @file type nodes before running script if enabled saveAtFile = c.config.getBool('nodeActions-save-atFile-nodes') if messageLevel >= 4: g.blue("nA: Global nodeActions_save_atFile_nodes=", saveAtFile) #Find the "nodeActions" node pNA = g.findNodeAnywhere(c, "nodeActions") if not pNA: pNA = g.findNodeAnywhere(c, "NodeActions") if pNA: #Found "nodeActions" node foundPattern = False passEventExternal = False #No pass to next plugin after pattern matched #Check entire subtree under the "nodeActions" node for pattern for pScript in pNA.subtree(): #Nodes with subnodes are not tested for a match if pScript.hasChildren(): continue #Don't trigger on double click of a nodeActions' pattern node if pClicked == pScript: continue pattern = pScript.h.strip() #Pattern node's header if messageLevel >= 4: g.blue("nA: Checking pattern '" + pattern) #if directives exist, parse them and set directive flags for later use # pylint: disable=anomalous-backslash-in-string directiveExists = re.search(" \[[V>X],?[V>X]?,?[V>X]?]$", pattern) if directiveExists: directives = directiveExists.group(0) else: directives = "[]" #What directives exist? useRegEx = re.search("X", directives) is not None passEventInternal = re.search("V", directives) is not None if not passEventExternal: #don't disable once enabled. passEventExternal = re.search(">", directives) is not None #Remove the directives from the end of the pattern (if they exist) pattern = re.sub(" \[.*]$", "", pattern, 1) if messageLevel >= 4: g.blue("nA: Pattern='" + pattern + "' " + "(after directives removed)") #Keep copy of pattern without directives for message log patternOriginal = pattern #if pattern begins with "@files" and clicked node is an @file type #node then replace "@files" in pattern with clicked node's @file type patternBeginsWithAtFiles = re.search("^@files ", pattern) clickedAtFileTypeNode = False #assume @file type node not clicked if patternBeginsWithAtFiles: #Check if first word in clicked header is in list of @file types firstWordInClickedHeader = hClicked.split()[0] if firstWordInClickedHeader in atFileTypes: clickedAtFileTypeNode = True #Tell "write @file type nodes" code #Replace "@files" in pattern with clicked node's @file type pattern = re.sub("^@files", firstWordInClickedHeader, pattern) if messageLevel >= 4: g.blue("nA: Pattern='" + pattern + "' " + "(after @files substitution)") #Check for pattern match to clicked node's header if useRegEx: match = re.search(pattern, hClicked) else: match = fnmatch.fnmatchcase(hClicked, pattern) if match: if messageLevel >= 1: g.blue("nA: Matched pattern '" + patternOriginal + "'") if messageLevel >= 4: g.blue( "nA: Directives: X=", useRegEx, "V=", passEventInternal, ">=", passEventExternal, ) #if @file type node, save node to disk (if configured) if clickedAtFileTypeNode: if saveAtFile: #Problem - No way found to just save clicked node, saving all c.fileCommands.writeAtFileNodes() c.redraw() if messageLevel >= 3: g.blue("nA: Saved '" + hClicked + "'") # Run the script applyNodeAction(pScript, pClicked, c) # Indicate that at least one pattern was matched foundPattern = True # Don't trigger more patterns unless enabled in patterns' headline if not passEventInternal: break else: if messageLevel >= 3: g.blue("nA: Did not match '" + patternOriginal + "'") # Finished checking headline against patterns if not foundPattern: #no match to any pattern, always pass event to next plugin if messageLevel >= 1: g.blue("nA: No patterns matched to " "" + hClicked + '"') return False #TL - Inform onIconDoubleClick that no action was taken if passEventExternal: #last matched pattern has directive to pass event to next plugin if messageLevel >= 2: g.blue("nA: Event passed to next plugin") return False #TL - Inform onIconDoubleClick to pass double-click event # #last matched pattern did not have directive to pass event to plugin if messageLevel >= 2: g.blue("nA: Event not passed to next plugin") return True #TL - Inform onIconDoubleClick to not pass double-click # # nodeActions plugin enabled without a 'nodeActions' node if messageLevel >= 4: g.blue("nA: The " "nodeActions" " node does not exist") return False #TL - Inform onIconDoubleClick that no action was taken
#@+<< imports >> #@+node:ekr.20100811091636.5919: *3* << imports >> #@+at Here are the imports. #@@c import leo.core.leoGlobals as g if g.isPython3: import io StringIO = io.StringIO else: import StringIO StringIO = StringIO.StringIO #@-<< imports >> if 1: # Format a fixed node. h = '@button format-code' p = g.findNodeAnywhere(c,h) #@+<< options >> #@+node:ekr.20100811091636.5995: *3* << options >> fn = '%s.rst.txt' % (g.sanitize_filename(p.h)) # 'format-code.rst.txt' # g.es('output file',repr(fn)) defaultOptionsDict = { # The following options are the most important visually. 'show_doc_parts_as_paragraphs': True, 'number-code-lines': False, # The following options are definitely used in the script. 'generate-rst-header-comment': True,