def open_file(self, root): '''Open the the file in vim using c.openWith.''' c = self.c efc = g.app.externalFilesController # Common arguments. tab_arg = "-tab" if self.uses_tab else "" remote_arg = "--remote" + tab_arg + "-silent" args = [self.vim_exe, "--servername", "LEO", remote_arg] # No cursor arg. if self.entire_file: # vim-open-file args.append('+0') # Go to first line of the file. This is an Ex command. assert root.isAnyAtFileNode(), root dir_ = g.setDefaultDirectory(c, root) fn = c.os_path_finalize_join(dir_, root.anyAtFileNodeName()) else: # vim-open-node args.append(self.get_cursor_arg()) # Set the cursor position to the current line in the node. ext = 'txt' fn = efc.create_temp_file(c, ext, c.p) c_arg = '%s %s' % (' '.join(args), fn) command = 'subprocess.Popen(%s,shell=True)' % c_arg try: subprocess.Popen(c_arg, shell=True) except OSError: g.es_print(command) g.es_exception()
def connect (self,fname): '''Connect to the server. Return True if the connection was established.''' trace = False and not g.unitTesting if trace: g.trace(fname,socket) if hasattr(socket,'AF_UNIX'): try: # pylint: disable=E1101 # E1101:LProtoClient.connect: Module 'socket' has no 'AF_UNIX' member self.socket = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) self.socket.connect(fname) return True except Exception: g.es_print('lproto.py: failed to connect!',fname) g.es_exception(full=False,c=None) return False else: try: host = '172.16.0.0' # host is a local address. port = 1 self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) self.socket.connect((host,port),) self.socket.connect(fname) return True except Exception: g.es_print('lproto.py: failed to connect! host: %s, port: %s' % ( host,port)) g.es_exception(full=False,c=None) return False
def export_outline(self, root, fn=None): ''' Entry point for export-jupyter-notebook Export the given .ipynb file. ''' self.root = root if not fn: fn = self.get_file_name() if not fn: return False try: nb = self.make_notebook() s = self.convert_notebook(nb) except Exception: g.es_exception() return False if not s: return False s = g.toEncodedString(s, encoding='utf-8', reportErrors=True) try: with open(fn, 'wb') as f: f.write(s) g.es_print('wrote: %s' % fn) except IOError: g.es_print('can not open: %s' % fn) return True
def listenToLog(self, event=None): ''' A socket listener, listening on localhost. See: https://docs.python.org/2/howto/logging-cookbook.html#sending-and-receiving-logging-events-across-a-network Start this listener first, then start the broadcaster. leo/plugins/cursesGui2.py is a typical broadcaster. ''' # Kill any previous listener. if g.app.log_listener: g.es_print('Killing previous listener') try: g.app.log_listener.kill() except Exception: g.es_exception() g.app.log_listener = None # Start a new listener. g.es_print('Starting log_listener.py') path = g.os_path_finalize_join(g.app.loadDir, '..', 'external', 'log_listener.py') g.app.log_listener = subprocess.Popen( [sys.executable, path], shell=False, universal_newlines=True, )
def scan_tag(self, s, i, tag_level): ''' Scan an xml tag starting with "<" or "</". Adjust the stack as appropriate: - "<" adds the tag to the stack. - "</" removes the top of the stack if it matches. ''' assert s[i] == '<', repr(s[i]) end_tag = self.match(s, i, '</') # Scan the tag. i += (2 if end_tag else 1) m = self.ch_pattern.match(s, i) if m: tag = m.group(0).lower() i += len(m.group(0)) else: # All other '<' characters should have had xml/html escapes applied to them. self.error('missing tag in position %s of %r' % (i, s)) g.es_print(repr(s)) return i, tag_level if end_tag: self.pop_to_tag(tag, s) if tag in self.start_tags: tag_level -= 1 else: self.stack.append(tag) if tag in self.start_tags: tag_level += 1 return i, tag_level
def open_file(self, root): '''Open the the file in vim using c.openWith.''' trace = False and not g.unitTesting c = self.c # Common arguments. if trace: g.trace(self.entire_file, root.h) cursor_arg = self.get_cursor_arg() tab_arg = "-tab" if self.uses_tab else "" remote_arg = "--remote" + tab_arg + "-silent" if self.entire_file: # vim-open-file. assert root.isAnyAtFileNode(), root args = [self.vim_exe, "--servername", "LEO", remote_arg] # No cursor arg. dir_ = g.setDefaultDirectory(c, root) fn = c.os_path_finalize_join(dir_, root.anyAtFileNodeName()) c_arg = '%s %s' % (' '.join(args), fn) command = 'subprocess.Popen(%s,shell=True)' % c_arg if trace: g.trace(command) try: subprocess.Popen(c_arg, shell=True) except OSError: g.es_print(command) g.es_exception() else: # vim-open-node root.v._vim_old_body = root.v.b # Not used in existing code, but it may be used elsewhere. args = [self.vim_exe, "--servername", "LEO", remote_arg, cursor_arg] if trace: g.trace('c.openWith(%s)' % args) d = {'args': args, 'ext': None, 'kind': 'subprocess.Popen', 'p': root.copy(), } c.openWith(d=d)
def error(self, s): '''Issue an error, but do *not* cause a unit test to fail.''' trace = False or not g.unitTesting if trace: g.es_print(s) # Tell i.check to strip lws. self.ws_error = True
def splitList (self,ivar,setting): '''Process lines containing pairs of entries in a list whose *name* is ivar. Put the results in ivars whose names are ivar1 and ivar2.''' result1 = [] ; result2 = [] aList = getattr(self,ivar) # Look for pairs. Comments have already been removed. for s in aList: pair = s.split(' ') if len(pair) == 2 and pair[0].strip() and pair[1].strip(): result1.append(pair[0].strip()) result2.append(pair[1].strip()) else: g.es_print('%s: ignoring line: %s' % (setting,s)) # Set the ivars. name1 = '%s1' % ivar name2 = '%s2' % ivar setattr(self,name1, result1) setattr(self,name2, result2) if 0: g.trace(name1,getattr(self,name1)) g.trace(name2,getattr(self,name2))
def run(self, p=None): '''Run flake8 on all Python @<file> nodes in c.p's tree.''' c = self.c root = p or c.p # Make sure Leo is on sys.path. leo_path = g.os_path_finalize_join(g.app.loadDir, '..') if leo_path not in sys.path: sys.path.append(leo_path) # Run flake8 on all Python @<file> nodes in root's tree. t1 = time.time() found = False for p in root.self_and_subtree(): found |= self.find(p) # Look up the tree if no @<file> nodes were found. if not found: for p in root.parents(): if self.find(p): found = True break # If still not found, expand the search if root is a clone. if not found: isCloned = any([p.isCloned() for p in root.self_and_parents()]) # g.trace(isCloned,root.h) if isCloned: for p in c.all_positions(): if p.isAnyAtFileNode(): isAncestor = any([z.v == root.v for z in p.self_and_subtree()]) # g.trace(isAncestor,p.h) if isAncestor and self.find(p): break paths = list(set(self.seen)) if paths: self.check_all(paths) g.es_print('flake8: %s file%s in %s' % ( len(paths), g.plural(paths), g.timeSince(t1)))
def createMenusFromTables(self): c = self.c aList = c.config.getMenusList() if aList: self.createMenusFromConfigList(aList) else: g.es_print('No @menu setting found')
def writeAbbreviations(self, event): '''Write abbreviations to a file.''' c = self.c fileName = g.app.gui.runSaveFileDialog(c, initialfile=None, title='Write Abbreviations', filetypes=[("Text", "*.txt"), ("All files", "*")], defaultextension=".txt") if not fileName: return try: d = self.abbrevs f = open(fileName, 'w') for name in sorted(d.keys()): val, tag = self.abbrevs.get(name) val = val.replace('\n', '\\n') # Fix bug #236: write continuations in same format as in # @data abbreviations nodes ### New code. ### val = ''.join([': %s' % (z) for z in g.splitLines(val)]) s = '%s=%s\n' % (name, val) if not g.isPython3: s = g.toEncodedString(s, reportErrors=True) f.write(s) f.close() g.es_print('wrote: %s' % fileName) except IOError: g.es('can not create', fileName)
def findNode(self,c,p,headline): '''Return the node in p's subtree with given headline.''' p = g.findNodeInTree(c,p,headline) if not p: g.es_print('can not find',headline) assert False return p
def open_file(self, root): '''Open the the file in vim using c.openWith.''' trace = (False or self.trace) and not g.unitTesting c = self.c efc = g.app.externalFilesController # Common arguments. if trace: g.trace(self.entire_file, root.h) # cursor_arg = self.get_cursor_arg() tab_arg = "-tab" if self.uses_tab else "" remote_arg = "--remote" + tab_arg + "-silent" args = [self.vim_exe, "--servername", "LEO", remote_arg] # No cursor arg. if self.entire_file: # vim-open-file assert root.isAnyAtFileNode(), root dir_ = g.setDefaultDirectory(c, root) fn = c.os_path_finalize_join(dir_, root.anyAtFileNodeName()) else: # vim-open-node ext = 'txt' fn = efc.create_temp_file(c, ext, c.p) c_arg = '%s %s' % (' '.join(args), fn) command = 'subprocess.Popen(%s,shell=True)' % c_arg if trace: g.trace(command) try: subprocess.Popen(c_arg, shell=True) except OSError: g.es_print(command) g.es_exception()
def restore_gnx(self,d,gnx,root,unl): ''' d is an *outer* gnx dict, associating nodes *outside* the tree with positions. Let p1 be the position of the node *within* root's tree corresponding to unl. Let p2 be the position of any node *outside* root's tree with the given gnx. - Set p1.v.fileIndex = gnx. - If p2 exists, relink p1 so it is a clone of p2. ''' trace = False and not g.unitTesting p1 = self.find_position_for_relative_unl(root,unl) fn = self.c.shortFileName() if p1: p2 = d.get(gnx) old_gnx = p1.v.gnx if p2: if p1.h == p2.h and p1.b == p2.b: p1._relinkAsCloneOf(p2) # Warning: p1 *no longer exists* here. # _relinkAsClone does *not* set p1.v = p2.v. if trace: g.trace(fn,'clone:',old_gnx,'->',gnx,unl) else: g.es_print('mismatch in cloned node',p1.h) elif trace: g.trace(fn,' node:',old_gnx,'->',gnx,unl) g.app.nodeIndices.updateLastIndex(g.toUnicode(gnx)) else: if trace: g.trace('unl not found: %s' % unl)
def strip(self): '''Display a file with all sentinel lines removed''' # get a path object for this position c = self.c currentPath = self.getCurrentPath() if currentPath.exists(): path = currentPath.abspath() s = 'currentPath: %s' % path g.es_print(s) filelines = path.lines() # Add an @ignore directive. lines = ['@ignore\n'] verbatim = False for line in filelines: if verbatim: lines.append(line) verbatim = False elif line.strip().startswith('#@verbatim'): verbatim = True elif not line.strip().startswith('#@'): lines.append(line) c.setBodyText(self.current,''.join(lines)) else: g.warning('path does not exist: %s' % (str(currentPath)))
def run(self): '''Run Pylint on all Python @<file> nodes in c.p's tree.''' c, root = self.c, self.c.p rc_fn = self.get_rc_file() if not rc_fn: return # Make sure Leo is on sys.path. leo_path = g.os_path_finalize_join(g.app.loadDir, '..') if leo_path not in sys.path: sys.path.append(leo_path) # Run lint on all Python @<file> nodes in root's tree. t1 = time.time() found = False for p in root.self_and_subtree(): found |= self.check(p, rc_fn) # Look up the tree if no @<file> nodes were found. if not found: for p in root.parents(): if self.check(p, rc_fn): found = True break # If still not found, expand the search if root is a clone. if not found: isCloned = any([p.isCloned() for p in root.self_and_parents()]) # g.trace(isCloned,root.h) if isCloned: for p in c.all_positions(): if p.isAnyAtFileNode(): isAncestor = any([z.v == root.v for z in p.self_and_subtree()]) # g.trace(isAncestor,p.h) if isAncestor and self.check(p, rc_fn): break if self.wait: g.es_print('pylint done %s' % g.timeSince(t1))
def regularize_node(self,p,scanner): '''Regularize node p so that it will not cause problems.''' ok,parts = scanner(atAuto=True,parent=p,s=p.b,prepass=True) if not ok and not parts: g.es_print('please regularize:',p.h) return ok,parts
def open_index(self, idx_dir): global index_error_given if os.path.exists(idx_dir): try: return open_dir(idx_dir) except ValueError: if not index_error_given: index_error_given = True g.es_print('bigdash.py: exception in whoosh.open_dir') g.es_print('please remove this directory:', g.os_path_normpath(idx_dir)) return None # Doesn't work: open_dir apparently leaves resources open, # so shutil.rmtree(idx_dir) fails. # g.es_print('re-creating', repr(idx_dir)) # try: # import shutil # shutil.rmtree(idx_dir) # os.mkdir(idx_dir) # self.create() # return open_dir(idx_dir) # except Exception as why: # g.es_print(why) # return None else: try: os.mkdir(idx_dir) self.create() return open_dir(idx_dir) except Exception: g.es_exception() return None
def pop_to_tag(self, tag, s): ''' Attempt to pop tag from the top of the stack. If the top doesn't match, issue a warning and attempt to recover. ''' trace = False if not self.stack: self.error('Empty tag stack: %s' % tag) g.es_print(repr(s)) return if trace: g.trace(tag, repr(s)) g.printList(self.stack) top = self.stack[-1] if top == tag: self.stack.pop() return # Only issue one warning per file. if trace or self.tag_warning_given: self.tag_warning_given = True self.error('mismatched closing tag: %s top: %s' % (tag, top)) g.es_print(repr(s)) if trace: g.trace(self.root.h) g.printList(self.stack) # Attempt a recovery. if tag in self.stack: while self.stack: top = self.stack.pop() # if trace: g.trace('POP: ', top) if top == tag: return
def findBuffer(self, name): v = self.tnodes.get(name) for p in self.c.all_unique_positions(): if p.v == v: return p g.es_print("no node named", name, color='orange') return None
def cleanAtCleanTree(self, event): ''' Adjust whitespace in the nearest @clean tree, searching c.p and its ancestors. ''' c = self.c # Look for an @clean node. for p in c.p.self_and_parents(): if g.match_word(p.h, 0, '@clean') and p.h.rstrip().endswith('.py'): break else: g.es_print('no an @clean node found', p.h, color='blue') return # pylint: disable=undefined-loop-variable # p is certainly defined here. bunch = c.undoer.beforeChangeTree(p) n = 0 undoType = 'clean-@clean-tree' for p2 in p.subtree(): if self.cleanAtCleanNode(p2, undoType): n += 1 if n > 0: c.setChanged(True) c.undoer.afterChangeTree(p, undoType, bunch) g.es_print('%s node%s cleaned' % (n, g.plural(n)))
def abort(self): '''undo all monkey-patches.''' g.es_print('exiting table.py plugin') c, ec = self.c, self.ec c.tableController = None c.k.handleDefaultChar = self.old_handleDefaultChar ec.insertNewlineBase = self.old_insert_newline
def onIdle (tag,keywords): """Save the current document if it has a name""" global gDict guiName = g.app.gui.guiName() if guiName not in ('qt','qttabs'): return c = keywords.get('c') d = gDict.get(c.hash()) if c and d and c.exists and c.mFileName and not g.app.killed and not g.unitTesting: # Wait the entire interval after c is first changed or saved. # Imo (EKR) this is the desired behavior. # It gives the user a chance to revert changes before they are changed. if c.changed: w = c.get_focus() if isinstance(w, QtWidgets.QLineEdit): # Saving now would destroy the focus. # There is **no way** to recreate outline editing after a redraw. pass else: last = d.get('last') interval = d.get('interval') if time.time()-last >= interval: g.es_print("Autosave: %s" % time.ctime(),color="orange") c.fileCommands.save(c.mFileName) c.set_focus(w,force=True) d['last'] = time.time() gDict[c.hash()] = d else: d['last'] = time.time() gDict[c.hash()] = d
def diff_file(self, fn): '''Create an outline describing the git diffs for fn.''' c = self.c s1 = self.get_file_from_rev(self.rev1, fn) s2 = self.get_file_from_rev(self.rev2, fn) lines1 = g.splitLines(s1) lines2 = g.splitLines(s2) diff_list = list(difflib.unified_diff( lines1, lines2, self.rev1 or 'uncommitted', self.rev2 or 'uncommitted', )) diff_list.insert(0, '@language patch\n') self.file_node = self.create_file_node(diff_list, fn) if c.looksLikeDerivedFile(fn): c1 = self.make_at_file_outline(fn, s1, self.rev1) c2 = self.make_at_file_outline(fn, s2, self.rev2) else: root = self.find_file(fn) if root: c1 = self.make_at_clean_outline(fn, root, s1, self.rev1) c2 = self.make_at_clean_outline(fn, root, s2, self.rev2) else: g.es_print('No outline for', fn) c1 = c2 = None if c1 and c2: self.make_diff_outlines(fn, c1, c2) self.file_node.b = '%s\n@language %s\n' % ( self.file_node.b.rstrip(), c2.target_language)
def createMenusFromTables(self): '''(leoMenu) Usually over-ridden.''' c = self.c aList = c.config.getMenusList() if aList: self.createMenusFromConfigList(aList) else: g.es_print('No @menu setting found')
def clear(self, verbose=False): # Deletes all files in the fcache subdirectory. # It would be more thorough to delete everything # below the root directory, but it's not necessary. if verbose: g.red('clearing cache at directory...\n') g.es_print(self.root) self.conn.execute('delete from cachevalues;')
def reportIfNodeChanged(self, child_tuple, child_v, fileName, parent_v): ''' Schedule a recovered node if child_v is substantially different from an earlier version. Issue a (rare) warning if two different files are involved. ''' trace = (False or g.app.debug) and not g.unitTesting always_warn = True # True always warn about changed nodes. c = self.c h, b, gnx, grandChildren = child_tuple old_b, new_b = child_v.b, b old_h, new_h = child_v.h, h # Leo 5.6: test headlines. same_head = old_h == new_h same_body = ( old_b == new_b or new_b.endswith('\n') and old_b == new_b[: -1] or old_b.endswith('\n') and new_b == old_b[: -1] ) if same_head and same_body: return old_roots = list(getattr(child_v, 'tempRoots', set())) same_file = ( len(old_roots) == 0 or len(old_roots) == 1 and old_roots[0] == fileName ) must_warn = not same_file if not hasattr(child_v, 'tempRoots'): child_v.tempRoots = set() child_v.tempRoots.add(fileName) if trace: # g.trace('same h: %s, same b: %s same fn: %s' % ( # same_head, same_body, same_file)) g.trace('fileName', fileName) g.trace('tempRoots', old_roots) if must_warn: # This is the so-called "rare" case: # The node differs in two different external files. self.warning('out-of-sync node: %s' % h) g.es_print('using node in %s' % fileName) if always_warn or must_warn: if c.make_node_conflicts_node: g.es_print('creating recovered node:', h) c.nodeConflictList.append(g.bunch( tag='(cached)', fileName=fileName, gnx=gnx, b_old=child_v.b, h_old=child_v.h, b_new=b, h_new=h, root_v=parent_v, )) # Always update the node. child_v.h, child_v.b = h, b child_v.setDirty() c.changed = True # Tell getLeoFile to propegate dirty nodes.
def add_words_from_dict(self, kind, fn, words): '''For use by DefaultWrapper.''' trace = False and not g.unitTesting if trace: g.es_print('%6s words in %6s dictionary: %s' % ( len(words or []), kind, g.os_path_normpath(fn))) for word in words or []: self.words.add(word) self.words.add(word.lower())
def run(self): '''run the refactorings.''' proj = self.proj if proj: proj.validate(proj.root) self.refactor() proj.close() else: g.es_print('rope not found')
def clear(self, verbose=False): # Deletes all files in the fcache subdirectory. # It would be more thorough to delete everything # below the root directory, but it's not necessary. if verbose: g.red('clearing cache at directory...\n') g.es_print(self.root) for z in self.keys(): self.__delitem__(z)
def error(self, s): g.es_print(s)
def error(self, s): g.es_print('error: %s' % (s), color='red')
def find_missing_docstrings(event): '''Report missing docstrings in the log, with clickable links.''' c = event.get('c') if not c: return #@+others # Define functions #@+node:ekr.20190615181104.1: *4* function: has_docstring def has_docstring(lines, n): ''' Returns True if function/method/class whose definition starts on n-th line in lines has a docstring ''' # By Виталије Милошевић. for line in lines[n:]: s = line.strip() if not s or s.startswith('#'): continue if s.startswith(('"""', "'''")): return True return False #@+node:ekr.20190615181104.2: *4* function: is_a_definition def is_a_definition(line): '''Return True if line is a definition line.''' # By Виталије Милошевић. # It may be useful to skip __init__ methods because their docstring # is usually docstring of the class return (line.startswith(('def ', 'class ')) and not line.partition(' ')[2].startswith('__init__')) #@+node:ekr.20190615182754.1: *4* function: is_root def is_root(p): ''' A predicate returning True if p is an @<file> node that is not under @nopylint. ''' for parent in p.self_and_parents(): if g.match_word(parent.h, 0, '@nopylint'): return False return p.isAnyAtFileNode() and p.h.strip().endswith('.py') #@+node:ekr.20190615180900.1: *4* function: clickable_link def clickable_link(p, i): '''Return a clickable link to line i of p.b.''' link = p.get_UNL(with_proto=True, with_count=True, with_index=True) return "%s,%d" % (link, i) #@-others count, found, t1 = 0, [], time.clock() for root in g.findRootsWithPredicate(c, c.p, predicate=is_root): for p in root.self_and_subtree(): lines = p.b.split('\n') for i, line in enumerate(lines): if is_a_definition(line) and not has_docstring(lines, i): count += 1 if root.v not in found: found.append(root.v) g.es_print('') g.es_print(root.h) print(line) g.es(line, nodeLink=clickable_link(p, i + 1)) break g.es_print('') g.es_print('found %s missing docstring%s in %s file%s in %5.2f sec.' % (count, g.plural(count), len(found), g.plural(len(found)), (time.clock() - t1)))
def note(s): g.es_print(s)
def warning(self, s): g.es_print(f"Warning: {s}")
def oops(message, i, j): # This can be called from c-to-python, in which case warnings should be suppressed. if giveWarnings: g.error('** changed ', p.h) g.es_print('%s after\n%s' % (message, repr(''.join(s[i:j]))))
def warning (self,s): g.es_print('Warning: %s' % (s))
def add_bookmark(self): """Return the file like 'f' that leo_interface.send_head makes """ parsed_url = urlparse.urlparse(self.request_handler.path) query = urlparse.parse_qs(parsed_url.query) # print(parsed_url.query) # print(query) name = query.get('name', ['NO TITLE'])[0] url = query['url'][0] c = None # outline for bookmarks previous = None # previous bookmark for adding selections parent = None # parent node for new bookmarks using_root = False path = self.bookmark_unl # g.trace(path) if path: # EKR i = path.find('#') if i > -1: path = path[:i].strip() unl = path[i + 1:].strip() else: path = path unl = '' parsed = urlparse.urlparse(path) # self.bookmark_unl) # EKR leo_path = os.path.expanduser(parsed.path) c = g.openWithFileName(leo_path, old_c=None) if c: g.es_print("Opened '%s' for bookmarks" % path) # self.bookmark_unl) parsed = urlparse.urlparse(unl) # self.bookmark_unl) # EKR if parsed.fragment: g.recursiveUNLSearch(parsed.fragment.split("-->"), c) parent = c.currentPosition() if parent.hasChildren(): previous = parent.getFirstChild() else: g.es_print("Failed to open '%s' for bookmarks" % self.bookmark_unl) if c is None: using_root = True c = g.app.commanders()[0] parent = c.rootPosition() previous = c.rootPosition() f = StringIO() if previous and url == previous.b.split('\n', 1)[0]: # another marking of the same page, just add selection self.add_bookmark_selection(previous, query.get('selection', [''])[0]) c.selectPosition(previous) # required for body text redraw c.redraw() f.write(""" <body onload="setTimeout('window.close();', 350);" style='font-family:mono'> <p>Selection added</p></body>""") return f if '_form' in query: # got extra details, save to new node f.write(""" <body onload="setTimeout('window.close();', 350);" style='font-family:mono'> <p>Bookmark saved</p></body>""") if using_root: nd = parent.insertAfter() nd.moveToRoot(c.rootPosition()) else: nd = parent.insertAsNthChild(0) if g.pluginIsLoaded('leo.plugins.bookmarks'): nd.h = name else: nd.h = '@url ' + name selection = query.get('selection', [''])[0] if selection: selection = '\n\n"""\n' + selection + '\n"""' nd.b = "%s\n\nTags: %s\n\n%s\n\nCollected: %s%s\n\n%s" % ( url, query.get('tags', [''])[0], query.get('_name', [''])[0], time.strftime("%c"), selection, query.get('description', [''])[0], ) c.setChanged(True) c.selectPosition(nd) # required for body text redraw c.redraw() return f # send form to collect extra details f.write(""" <html><head><style> body {font-family:mono; font-size: 80%%;} th {text-align:right} </style> </head><body onload='document.getElementById("tags").focus();'> <form method='GET' action='/_/add/bkmk/'> <input type='hidden' name='_form' value='1'/> <input type='hidden' name='_name' value=%s/> <input type='hidden' name='selection' value=%s/> <table> <tr><th>Tags:</th><td><input id='tags' name='tags' size='60'/>(comma sep.)</td></tr> <tr><th>Title:</th><td><input name='name' value=%s size='60'/></td></tr> <tr><th>URL:</th><td><input name='url' value=%s size='60'/></td></tr> <tr><th>Notes:</th><td><textarea name='description' cols='60' rows='6'></textarea></td></tr> </table> <input type='submit' value='Save'/><br/> </form> </body></html>""" % (quoteattr(name), quoteattr(query.get( 'selection', [''])[0]), quoteattr(name), quoteattr(url))) return f
def pwd_command(self, event=None): """Refresh an @<file> node from disk.""" g.es_print('pwd:', os.getcwd())
def hello_command2(event): g.es_print('Hello 2 from %s' % (g.shortFileName(__file__)), color='red')
def hello_command(event): g.es_print('Hello from %s' % (g.shortFileName(__file__)), color='purple')
def pr(*args, **keys): if not g.app.unitTesting: g.es_print(*args, **keys)
def report(message): g.es_print('loadOnePlugin: %s' % message)
def getScript( c, p, useSelectedText=True, forcePythonSentinels=True, sentinels=True, language='python', ): ''' Return the expansion of the selected text of node p. Return the expansion of all of node p's body text if p is not the current node or if there is no text selection. ''' #@+others #@+node:bob.20170726143458.18: *4* extractExecutableString() def extractExecutableString(c, p, s, language='python'): ''' Return all lines for the given @language directive. Ignore all lines under control of any other @language directive. ''' if leoG.unitTesting: return s # Regretable, but necessary. langCur = language pattern = re.compile(r'\s*@language\s+(\w+)') result = [] for line in leoG.splitLines(s): m = pattern.match(line) if m: # Found an @language directive. langCur = m.group(1) elif langCur == language: result.append(line) return ''.join(result) #@+node:bob.20170726143458.19: *4* composeScript() def composeScript(c, p, s, forcePythonSentinels=True, sentinels=True): '''Compose a script from p.b.''' if s.strip(): # Important: converts unicode to utf-8 encoded strings. script = c.atFileCommands.stringToString( p.copy(), s, forcePythonSentinels=forcePythonSentinels, sentinels=sentinels) script = script.replace("\r\n", "\n") # Use brute force. # Important, the script is an **encoded string**, not a unicode string. return script else: return '' #@-others w = c.frame.body.wrapper if not p: p = c.p try: if leoG.app.inBridge: s = p.b elif w and p == c.p and useSelectedText and w.hasSelection(): s = w.getSelectedText() else: s = p.b # Remove extra leading whitespace so the user may execute indented code. s = leoG.removeExtraLws(s, c.tab_width) s = extractExecutableString(c, p, s, language) script = composeScript(c, p, s, forcePythonSentinels=forcePythonSentinels, sentinels=sentinels) except Exception: leoG.es_print("unexpected exception in Leo-Babel getScript()") raise return script
def open_temp_file(self, c, d, fn, testing=False): ''' Open a temp file corresponding to fn in an external editor. d is a dictionary created from an @openwith settings node. 'args': the command-line arguments to be used to open the file. 'ext': the file extension. 'kind': the method used to open the file, such as subprocess.Popen. 'name': menu label (used only by the menu code). 'shortcut': menu shortcut (used only by the menu code). ''' trace = False and not g.unitTesting testing = testing or g.unitTesting arg_tuple = d.get('args', []) arg = ' '.join(arg_tuple) kind = d.get('kind') try: # All of these must be supported because they # could exist in @open-with nodes. command = '<no command>' if kind == 'os.startfile': command = 'os.startfile(%s)' % self.join(arg, fn) if trace: g.trace(command) # pylint: disable=no-member # trust the user not to use this option on Linux. if not testing: os.startfile(self.join(arg, fn)) elif kind == 'exec': g.es_print('open-with exec no longer valid.') # command = 'exec(%s)' % self.join(arg,fn) # if trace: g.trace(command) # if not testing: # exec(self.join(arg,fn),{},{}) elif kind == 'os.spawnl': filename = g.os_path_basename(arg) command = 'os.spawnl(%s,%s,%s)' % (arg, filename, fn) if trace: g.trace(command) if not testing: os.spawnl(os.P_NOWAIT, arg, filename, fn) elif kind == 'os.spawnv': filename = os.path.basename(arg_tuple[0]) vtuple = arg_tuple[1:] vtuple.insert(0, filename) # add the name of the program as the first argument. # Change suggested by Jim Sizelove. vtuple.append(fn) command = 'os.spawnv(%s)' % (vtuple) if trace: g.trace(command) if not testing: os.spawnv(os.P_NOWAIT, arg[0], vtuple) #??? elif kind == 'subprocess.Popen': c_arg = self.join(arg, fn) command = 'subprocess.Popen(%s)' % c_arg if trace: g.trace(command) if not testing: try: subprocess.Popen(c_arg, shell=True) except OSError: g.es_print('c_arg', repr(c_arg)) g.es_exception() elif g.isCallable(kind): # Invoke openWith like this: # c.openWith(data=[func,None,None]) # func will be called with one arg, the filename if trace: g.trace('%s(%s)' % (kind, fn)) command = '%s(%s)' % (kind, fn) if not testing: kind(fn) else: command = 'bad command:' + str(kind) if not testing: g.trace(command) return command # for unit testing. except Exception: g.es('exception executing open-with command:', command) g.es_exception() return 'oops: %s' % command
def ad_command(self, event=None): #@+<< adoc command docstring >> #@+node:ekr.20190515115100.1: *3* << adoc command docstring >> ''' The adoc command writes all @adoc nodes in the selected tree to the files given in each @doc node. If no @adoc nodes are found, the command looks up the tree. Each @adoc node should have the form: `@adoc x.adoc`. Relative file names are relative to the base directory. See below. By default, the adoc command creates AsciiDoctor headings from Leo headlines. However, the following kinds of nodes are treated differently: - @ignore-tree: Ignore the node and its descendants. - @ignore-node: Ignore the node. - @no-head: Ignore the headline. Do not generate a heading. After running the adoc command, use the asciidoctor command to convert the x.adoc files to x.html. Settings -------- AsciiDoctor itself provides many settings, including:: = Title :stylesdir: mystylesheets/ :stylesheet: mystyles.css These can also be specified on the command line:: asciidoctor -a stylesdir=mystylesheets/ -a stylesheet=mystyles.css @string adoc-base-directory specifies the base for relative file names. The default is c.frame.openDirectory Scripting interface ------------------- Scripts may invoke the adoc command as follows:: event = g.Bunch(base_dicrectory=my_directory, p=some_node) c.asciiDoctorCommands.ad_command(event=event) This @button node runs the adoc command and coverts all results to .html:: import os paths = c.asciiDoctorCommands.ad_command(event=g.Bunch(p=p)) paths = [z.replace('/', os.path.sep) for z in paths] input_paths = ' '.join(paths) g.execute_shell_commands(['asciidoctor %s' % input_paths]) ''' #@-<< adoc command docstring >> def predicate(p): return self.ad_filename(p) # Find all roots. t1 = time.time() c = self.c p = event.p if event and hasattr(event, 'p') else c.p if event and hasattr(event, 'base_directory'): self.base_directory = event.base_directory else: directory = c.config.getString('adoc-base-directory') self.base_directory = directory or c.frame.openDirectory roots = g.findRootsWithPredicate(c, p, predicate=predicate) if not roots: g.warning('No @ascii-doctor nodes in', p.h) return [] # Write each root. paths = [] for p in roots: path = self.write_root(p) if path: paths.append(path) t2 = time.time() g.es_print('adoc: wrote %s file%s in %4.2f sec.' % ( len(paths), g.plural(len(paths)), t2 - t1)) return paths
def error(self, s): '''Issue an error, but do *not* cause a unit test to fail.''' g.es_print('\nin %s' % self.root.h) g.es_print(s) # Tell i.check to strip lws. self.ws_error = True
def report(message): if trace and not g.unitTesting: g.es_print(f"loadOnePlugin: {message}")
def do_fts(self, tgt, qs): ss = g.toUnicode(qs) q = None if ss.startswith("f "): q = ss[2:] if not (q or ss.startswith("fts ")): return False if not whoosh: g.es("Whoosh not installed (easy_install whoosh)") return False # print("Doing fts: %s" % qs) fts = self.fts if ss.strip() == "fts init": fts.create() for c2 in g.app.commanders(): g.es_print("Scanning: %s" % c2.shortFileName()) fts.index_nodes(c2) g.es_print('Scan complete') if ss.strip() == "fts add": # print("Add new docs") docs = set(fts.statistics()["documents"]) # print("Have docs", docs) for c2 in g.app.commanders(): fn = c2.mFileName if fn not in docs: g.es_print("Adding document to index: %s" % c2.shortFileName()) fts.index_nodes(c2) g.es_print('Add complete') if ss.strip() == "fts refresh": for c2 in g.app.commanders(): fn = c2.mFileName g.es_print("Refreshing: %s" % c2.shortFileName()) fts.drop_document(fn) fts.index_nodes(c2) g.es_print('Refresh complete') gc = self.gnxcache gc.clear() gc.update_new_cs() if q: self.do_find(tgt, q)
def convert_at_file_to_at_auto(self, root): if root.isAtFileNode(): ConvertController(self.c, root).run() else: g.es_print('not an @file node:', root.h)
def open_file_in_external_editor(self, c, d, fn, testing=False): """ Open a file fn in an external editor. This will be an entire external file, or a temp file for a single node. d is a dictionary created from an @openwith settings node. 'args': the command-line arguments to be used to open the file. 'ext': the file extension. 'kind': the method used to open the file, such as subprocess.Popen. 'name': menu label (used only by the menu code). 'p': the nearest @<file> node, or None. 'shortcut': menu shortcut (used only by the menu code). """ testing = testing or g.unitTesting arg_tuple = d.get('args', []) arg = ' '.join(arg_tuple) kind = d.get('kind') try: # All of these must be supported because they # could exist in @open-with nodes. command = '<no command>' if kind in ('os.system', 'os.startfile'): # New in Leo 5.7: # Use subProcess.Popen(..., shell=True) c_arg = self.join(arg, fn) if not testing: try: subprocess.Popen(c_arg, shell=True) except OSError: g.es_print('c_arg', repr(c_arg)) g.es_exception() elif kind == 'exec': g.es_print('open-with exec no longer valid.') elif kind == 'os.spawnl': filename = g.os_path_basename(arg) command = f"os.spawnl({arg},{filename},{fn})" if not testing: os.spawnl(os.P_NOWAIT, arg, filename, fn) elif kind == 'os.spawnv': filename = os.path.basename(arg_tuple[0]) vtuple = arg_tuple[1:] vtuple.insert(0, filename) # add the name of the program as the first argument. # Change suggested by Jim Sizelove. vtuple.append(fn) command = f"os.spawnv({vtuple})" if not testing: os.spawnv(os.P_NOWAIT, arg[0], vtuple) #??? elif kind == 'subprocess.Popen': c_arg = self.join(arg, fn) command = f"subprocess.Popen({c_arg})" if not testing: try: subprocess.Popen(c_arg, shell=True) except OSError: g.es_print('c_arg', repr(c_arg)) g.es_exception() elif hasattr(kind, '__call__'): # Invoke openWith like this: # c.openWith(data=[func,None,None]) # func will be called with one arg, the filename command = f"{kind}({fn})" if not testing: kind(fn) else: command = 'bad command:' + str(kind) if not testing: g.trace(command) return command # for unit testing. except Exception: g.es('exception executing open-with command:', command) g.es_exception() return f"oops: {command}"
def drop_document(self, docfile): writer = self.ix.writer() g.es_print("Drop index: %s" % g.shortFileName(docfile)) writer.delete_by_term("doc", docfile) writer.commit()
def error(self, s): '''Report an error.''' g.es_print(s, color='red')
def write(self, s): if s.strip(): g.es_print(s)
def findNode(self, c, p, headline): p = g.findNodeInTree(c, p, headline) if not p: g.es_print('can not find', headline) assert False return p
def message(self, s): g.es_print(s, color='orange')
#@+leo-ver=5-thin #@+node:ekr.20160412101008.1: * @file importers/ipynb.py '''The @auto importer for Jupyter (.ipynb) files.''' import re import leo.core.leoGlobals as g trace_import = False try: import nbformat except ImportError: if trace_import: g.es_print('import-jupyter-notebook requires nbformat package') nbformat = None #@+others #@+node:ekr.20160412101537.2: ** class Import_IPYNB class Import_IPYNB(object): '''A class to import .ipynb files.''' #@+others #@+node:ekr.20160412101537.3: *3* ctor def __init__(self, c=None, importCommands=None, atAuto=None): '''Ctor for Import_IPYNB class.''' self.c = importCommands.c if importCommands else c # Commander of present outline. # g.trace('(Import_IPYNB)', self.c) self.cell = None # The present cell node. self.cell_n = None # The number of the top-level node being scanned. self.code_language = None
def report(self, s): '''Issue a message.''' g.es_print(s)
def regularize_node(self, p, scanner): '''Regularize node p so that it will not cause problems.''' ok, parts = scanner(atAuto=True, parent=p, s=p.b, prepass=True) if not ok and not parts: g.es_print('please regularize:', p.h) return ok, parts
def run(self): '''Convert an @file tree to @auto tree.''' trace = True and not g.unitTesting trace_s = False cc = self c = cc.c root, pd = cc.root, c.persistenceController # set the expected imported headline for all vnodes. t1 = time.clock() cc.set_expected_imported_headlines(root) t2 = time.clock() # Delete all previous @data nodes for this tree. cc.delete_at_data_nodes(root) t3 = time.clock() # Ensure that all nodes of the tree are regularized. ok = pd.prepass(root) t4 = time.clock() if not ok: g.es_print('Can not convert', root.h, color='red') if trace: g.trace( '\n set_expected_imported_headlines: %4.2f sec' % (t2 - t1), # '\n delete_at_data_nodes: %4.2f sec' % (t3-t2), '\n prepass: %4.2f sec' % (t4 - t3), '\n total: %4.2f sec' % (t4 - t1)) return # Create the appropriate @data node. at_auto_view = pd.update_before_write_foreign_file(root) t5 = time.clock() # Write the @file node as if it were an @auto node. s = cc.strip_sentinels() t6 = time.clock() if trace and trace_s: g.trace('source file...\n', s) # Import the @auto string. ok, p = cc.import_from_string(s) t7 = time.clock() if ok: # Change at_auto_view.b so it matches p.gnx. at_auto_view.b = pd.at_data_body(p) # Recreate the organizer nodes, headlines, etc. pd.update_after_read_foreign_file(p) t8 = time.clock() # if not ok: # p.h = '@@' + p.h # g.trace('restoring original @auto file') # ok,p = cc.import_from_string(s) # if ok: # p.h = '@@' + p.h + ' (restored)' # if p.next(): # p.moveAfter(p.next()) t9 = time.clock() else: t8 = t9 = time.clock() if trace: g.trace( '\n set_expected_imported_headlines: %4.2f sec' % (t2 - t1), # '\n delete_at_data_nodes: %4.2f sec' % (t3-t2), '\n prepass: %4.2f sec' % (t4 - t3), '\n update_before_write_foreign_file:%4.2f sec' % (t5 - t4), '\n strip_sentinels: %4.2f sec' % (t6 - t5), '\n import_from_string: %4.2f sec' % (t7 - t6), '\n update_after_read_foreign_file %4.2f sec' % (t8 - t7), '\n import_from_string (restore) %4.2f sec' % (t9 - t8), '\n total: %4.2f sec' % (t9 - t1)) if p: c.selectPosition(p) c.redraw()