def make_stub_file(self, p): '''Make a stub file in ~/stubs for the @<file> node at p.''' import ast assert p.isAnyAtFileNode() c = self.c fn = p.anyAtFileNodeName() if not fn.endswith('.py'): g.es_print('not a python file', fn) return abs_fn = g.fullPath(c, p) if not g.os_path_exists(abs_fn): g.es_print('not found', abs_fn) return if g.os_path_exists(self.output_directory): base_fn = g.os_path_basename(fn) out_fn = g.os_path_finalize_join(self.output_directory, base_fn) else: g.es_print('not found', self.output_directory) return out_fn = out_fn[:-3] + '.pyi' out_fn = g.os_path_normpath(out_fn) self.output_fn = out_fn # compatibility with stand-alone script s = open(abs_fn).read() node = ast.parse(s, filename=fn, mode='exec') # Make the traverser *after* creating output_fn and output_directory ivars. x = self.msf.StubTraverser(controller=self) x.output_fn = self.output_fn x.output_directory = self.output_directory x.trace_matches = self.trace_matches x.trace_patterns = self.trace_patterns x.trace_reduce = self.trace_reduce x.trace_visitors = self.trace_visitors x.run(node)
def xdb_command(event): '''Start the external debugger on a toy test program.''' c = event.get('c') if not c: return path = g.fullPath(c, c.p) if not path: g.trace('Not in an @<file> tree') return if not g.os_path_exists(path): return g.trace('not found', path) os.chdir(g.os_path_dirname(path)) xdb = getattr(g.app, 'xdb', None) if xdb: # Just issue a message. xdb.write('xdb active: use Quit button or db-q to terminate') # Killing the previous debugger works, # *provided* we don't try to restart xdb! # That would create a race condition on g.app.xdb. # xdb.do_quit() else: # Start the debugger in a separate thread. g.app.xdb = xdb = Xdb(path) xdb.start() xdb.qr.put(['clear-stdout'])
def open_file_in_commander(self, ext, path): '''Open the given path in a Leonine manner.''' # # 1. Open .leo files as in open-outline command... path = os.path.normpath(path) if g.app.loadManager.isLeoFile(path): c = g.openWithFileName(path, old_c=self.c) if not c: return c.k.makeAllBindings() g.chdir(path) g.setGlobalOpenDir(path) return # # 2. Search open commanders for a matching @<file> node. for c in g.app.commanders(): for p in c.all_unique_positions(): if (p.isAnyAtFileNode() and path == os.path.normpath(g.fullPath(c, p))): if getattr(c.frame.top, 'leo_master', None): c.frame.top.leo_master.select(c) c.selectPosition(p) c.redraw() return # # 3. Open a dummy file, removing sentinels from derived files. c = g.openWithFileName(path, old_c=self.c) c.k.makeAllBindings() g.chdir(path) g.setGlobalOpenDir(path) c.selectPosition(c.rootPosition()) c.redraw()
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 # Use os.path.normpath to give system separators. fn = os.path.normpath(g.fullPath(c, root)) # #1914. 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 make_stub_file(self, p): '''Make a stub file in ~/stubs for the @<file> node at p.''' import ast import leo.core.leoAst as leoAst assert p.isAnyAtFileNode() c = self.c fn = p.anyAtFileNodeName() if not fn.endswith('.py'): g.es_print('not a python file', fn) return abs_fn = g.fullPath(c, p) if not g.os_path_exists(abs_fn): g.es_print('not found', abs_fn) return if g.os_path_exists(self.output_directory): base_fn = g.os_path_basename(fn) out_fn = g.os_path_finalize_join(self.output_directory, base_fn) else: g.es_print('not found', self.output_directory) return out_fn = out_fn[:-3] + '.pyi' out_fn = os.path.normpath(out_fn) self.output_fn = out_fn # compatibility with stand-alone script s = open(abs_fn).read() node = ast.parse(s,filename=fn,mode='exec') leoAst.StubTraverser(controller=self).run(node)
def idle_check_commander(self, c): """ Check all external files corresponding to @<file> nodes in c for changes. """ # #1240: Check the .leo file itself. self.idle_check_leo_file(c) # # #1100: always scan the entire file for @<file> nodes. # #1134: Nested @<file> nodes are no longer valid, but this will do no harm. state = 'no' for p in c.all_unique_positions(): if not p.isAnyAtFileNode(): continue path = g.fullPath(c, p) if not self.has_changed(path): continue # Prevent further checks for path. self.set_time(path) self.checksum_d[path] = self.checksum(path) # Check file. if p.isAtAsisFileNode() or p.isAtNoSentFileNode(): # #1081: issue a warning. self.warn(c, path, p=p) continue if state in ('yes', 'no'): state = self.ask(c, path, p=p) if state in ('yes', 'yes-all'): c.redraw(p=p) c.refreshFromDisk(p) c.redraw()
def orange_diff_files(event): """ Show the diffs that would result from beautifying the external files at c.p. """ c = event.get('c') if not c or not c.p: return t1 = time.process_time() tag = 'beautify-files-diff' g.es(f"{tag}...") settings = orange_settings(c) roots = g.findRootsWithPredicate(c, c.p) for root in roots: filename = g.fullPath(c, root) if os.path.exists(filename): print('') print(f"{tag}: {g.shortFileName(filename)}") changed = leoAst.Orange( settings=settings).beautify_file_diff(filename) changed_s = 'changed' if changed else 'unchanged' g.es(f"{changed_s:>9}: {g.shortFileName(filename)}") else: print('') print(f"{tag}: file not found:{filename}") g.es(f"file not found:\n{filename}") t2 = time.process_time() print('') g.es_print( f"{tag}: {len(roots)} file{g.plural(len(roots))} in {t2 - t1:5.2f} sec." )
def xdb_breakpoint(event): '''Set the breakpoint at the presently select line in Leo.''' c = event.get('c') if not c: return p = c.p xdb = getattr(g.app, 'xdb', None) if not xdb: print('xdb not active') return w = c.frame.body.wrapper if not w: return x = c.gotoCommands root, fileName = x.find_root(p) if not root: g.trace('no root', p.h) return path = g.fullPath(c, root) n0 = x.find_node_start(p=p) if n0 is None: g.trace('no n0') return c.bodyWantsFocusNow() i = w.getInsertPoint() s = w.getAllText() row, col = g.convertPythonIndexToRowCol(s, i) n = x.node_offset_to_file_line(row, p, root) if n is not None: xdb.qc.put('b %s:%s' % (path, n+1))
def orange_files(event): """beautify one or more files at c.p.""" c = event.get('c') if not c or not c.p: return t1 = time.process_time() tag = 'beautify-files' g.es(f"{tag}...") settings = orange_settings(c) roots = g.findRootsWithPredicate(c, c.p) n_changed = 0 for root in roots: filename = g.fullPath(c, root) if os.path.exists(filename): print('') print(f"{tag}: {g.shortFileName(filename)}") changed = leoAst.Orange(settings=settings).beautify_file(filename) if changed: n_changed += 1 changed_s = 'changed' if changed else 'unchanged' g.es(f"{changed_s:>9}: {g.shortFileName(filename)}") else: print('') print(f"{tag}: file not found:{filename}") g.es(f"{tag}: file not found:\n{filename}") t2 = time.process_time() print('') g.es_print(f"total files: {len(roots)}, " f"changed files: {n_changed}, " f"in {t2 - t1:5.2f} sec.")
def fstringify_files_silent(event): """Silently fstringifying the external files at c.p.""" c = event.get('c') if not c or not c.p: return t1 = time.process_time() tag = 'silent-fstringify-files' g.es(f"{tag}...") n_changed = 0 roots = g.findRootsWithPredicate(c, c.p) for root in roots: filename = g.fullPath(c, root) if os.path.exists(filename): changed = leoAst.Fstringify().fstringify_file_silent(filename) if changed: n_changed += 1 else: print('') print(f"File not found:{filename}") g.es(f"File not found:\n{filename}") t2 = time.process_time() print('') n_tot = len(roots) g.es_print(f"{n_tot} total file{g.plural(len(roots))}, " f"{n_changed} changed file{g.plural(n_changed)} " f"in {t2 - t1:5.2f} sec.")
def xdb_command(event): '''Start the external debugger on a toy test program.''' c = event.get('c') if not c: return path = g.fullPath(c, c.p) if not path: g.trace('Not in an @<file> tree') return if not g.os_path_exists(path): g.trace('not found', path) return os.chdir(g.os_path_dirname(path)) xdb = getattr(g.app, 'xdb', None) if xdb: # Just issue a message. xdb.write('xdb active: use Quit button or db-q to terminate') # Killing the previous debugger works, # *provided* we don't try to restart xdb! # That would create a race condition on g.app.xdb. # xdb.do_quit() else: # Start the debugger in a separate thread. g.app.xdb = xdb = Xdb(path) xdb.start() xdb.qr.put(['clear-stdout'])
def show_line(line, fn): """ Put the cursor on the requested line of the given file. fn should be a full path to a file. """ c = g.app.log.c target = g.os_path_finalize(fn).replace('\\', '/') if not g.os_path_exists(fn): g.trace('===== Does not exist', fn) return for p in c.all_positions(): if p.isAnyAtFileNode(): path = g.fullPath(c, p).replace('\\', '/') if target == path: # Select the line. junk_p, junk_offset, ok = c.gotoCommands.find_file_line(n=line, p=p) if not ok: g.trace('FAIL:', target) c.bodyWantsFocusNow() return p = make_at_file_node(line, target) junk_p, junk_offset, ok = c.gotoCommands.find_file_line(n=line, p=p) if not ok: g.trace('FAIL:', target)
def open_with(self, c, d): """ Called by c.openWith to handle items in the Open With... menu. 'd' a dict created from an @openwith settings node with these keys: '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). """ try: ext = d.get('ext') if not g.doHook('openwith1', c=c, p=c.p, v=c.p.v, d=d): root = d.get('p') if root: # Open the external file itself. path = g.fullPath(c, root) # #1914. self.open_file_in_external_editor(c, d, path) else: # Open a temp file containing just the node. p = c.p ext = self.compute_ext(c, p, ext) path = self.compute_temp_file_path(c, p, ext) if path: self.remove_temp_file(p, path) self.create_temp_file(c, ext, p) self.open_file_in_external_editor(c, d, path) g.doHook('openwith2', c=c, p=c.p, v=c.p.v, d=d) except Exception: g.es('unexpected exception in c.openWith') g.es_exception()
def onPostSave(tag=None, keywords=None): """After saving an @nosent file, replace all tabs with spaces.""" global nosentNodes c = keywords.get('c') if c: for p in nosentNodes: g.red("node %s found" % p.h) # Use os.path.normpath to give system separators. fname = os.path.normpath(g.fullPath(c, p)) # #1914. f = open(fname,"r") lines = f.readlines() f.close() #@+<< add a newline before def or class >> #@+node:ekr.20040331151007.3: *3* << add a newline before def or class >> for i, s in enumerate(lines): ls = s.lstrip() if ls.startswith("def ") or ls.startswith("class "): try: if lines[i-1].strip() != "": lines[i] = "\n" + lines[i] except IndexError: pass #@-<< add a newline before def or class >> #@+<< replace tabs with spaces >> #@+node:ekr.20040331151007.4: *3* << replace tabs with spaces >> s = ''.join(lines) fh = open(fname,"w") fh.write(s.replace("\t",NSPACES)) fh.close() #@-<< replace tabs with spaces >> nosentNodes = []
def find(self, p): """Return True and add p's path to self.seen if p is a Python @<file> node.""" c = self.c fn = p.anyAtFileNodeName() found = fn and fn.endswith('.py') if found: path = g.fullPath(c, p) # #1914. self.seen.append(path) return found
def check_all(self, roots): """Run mypy on all files in paths.""" c = self.c if not mypy: print('install mypy with `pip install mypy`') return self.unknown_path_names = [] for root in roots: fn = os.path.normpath(g.fullPath(c, root)) self.check_file(fn, root)
def get_fn(self, p): """ Finalize p's file name. Return if p is not an @file node for a python file. """ c = self.c fn = p.isAnyAtFileNode() if not fn: g.trace(f"not an @<file> node: {p.h!r}") return None return g.fullPath(c, p) # #1914
def idle_check_at_file_node(self, c, p): '''Check the @<file> node at p for external changes.''' path = g.fullPath(c, p) if self.has_changed(c, path): if self.ask(c, path, p=p): c.redraw_now(p=p) c.refreshFromDisk(p) c.redraw() # Always update the path & time to prevent future warnings. self.set_time(path) self.checksum_d[path] = self.checksum(path)
def idle_check_at_file_node(self, c, p): '''Check the @<file> node at p for external changes.''' path = g.fullPath(c, p) if self.has_changed(c, path): if self.ask(c, path, p=p): c.redraw(p=p) c.refreshFromDisk(p) c.redraw() # Always update the path & time to prevent future warnings. self.set_time(path) self.checksum_d[path] = self.checksum(path)
def test_bug_1889(self): # Test #1889: Honor ~ in ancestor @path nodes. # Create a new outline with @file node and save it bridge = self.bridge() with tempfile.TemporaryDirectory() as temp_dir: filename = f"{temp_dir}{os.sep}test_file.leo" c = bridge.openLeoFile(filename) root = c.rootPosition() root.h = '@path ~/sub-directory/' child = root.insertAsLastChild() child.h = '@file test_bug_1889.py' child.b = '@language python\n# test #1889' path = g.fullPath(c, child) assert '~' not in path, repr(path)
def blacken_files(event): """Run black on one or more files at c.p.""" c = event.get('c') if not c or not c.p: return tag = 'blacken-files' if not black: g.es_print(f"{tag} can not import black") return for root in g.findRootsWithPredicate(c, c.p): path = g.fullPath(c, root) if path and os.path.exists(path): g.es_print(f"{tag}: {path}") g.execute_shell_commands(f"&black --skip-string-normalization {path}") else: print(f"{tag}: file not found:{path}") g.es(f"{tag}: file not found:\n{path}")
def idle_check_at_file_node(self, c, p): '''Check the @<file> node at p for external changes.''' trace = False # Matt, set this to True, but only for the file that interests you.\ # trace = p.h == '@file unregister-leo.leox' path = g.fullPath(c, p) has_changed = self.has_changed(c, path) if trace: g.trace('changed', has_changed, p.h) if has_changed: if p.isAtAsisFileNode() or p.isAtNoSentFileNode(): # Fix #1081: issue a warning. self.warn(c, path, p=p) elif self.ask(c, path, p=p): c.redraw(p=p) c.refreshFromDisk(p) c.redraw() # Always update the path & time to prevent future warnings. self.set_time(path) self.checksum_d[path] = self.checksum(path)
def flake8_command(event): """ Run flake8 on all nodes of the selected tree, or the first @<file> node in an ancestor. """ tag = 'flake8-files' if not flake8: g.es_print(f"{tag} can not import flake8") return c = event and event.get('c') if not c or not c.p: return python = sys.executable for root in g.findRootsWithPredicate(c, c.p): path = g.fullPath(c, root) if path and os.path.exists(path): g.es_print(f"{tag}: {path}") g.execute_shell_commands(f'&"{python}" -m flake8 "{path}"') else: g.es_print(f"{tag}: file not found:{path}")
def blacken_files_diff(event): """ Show the diffs that would result from blacking the external files at c.p. """ c = event.get('c') if not c or not c.p: return tag = 'blacken-files-diff' if not black: g.es_print(f"{tag} can not import black") return for root in g.findRootsWithPredicate(c, c.p): path = g.fullPath(c, root) if path and os.path.exists(path): g.es_print(f"{tag}: {path}") g.execute_shell_commands(f"&black --skip-string-normalization --diff {path}") else: print(f"{tag}: file not found:{path}") g.es(f"{tag}: file not found:\n{path}")
def run(self, last_path=None): """Run Pylint on all Python @<file> nodes in c.p's tree.""" c, root = self.c, self.c.p if not lint: g.es_print('pylint is not installed') return False self.rc_fn = self.get_rc_file() if not self.rc_fn: return False # 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) # Ignore @nopylint trees. def predicate(p): 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', '.pyw')) # #2354. roots = g.findRootsWithPredicate(c, root, predicate=predicate) data = [(self.get_fn(p), p.copy()) for p in roots] data = [z for z in data if z[0] is not None] if not data and last_path: # Default to the last path. fn = last_path for p in c.all_positions(): if p.isAnyAtFileNode() and g.fullPath(c, p) == fn: data = [(fn, p.copy())] break if not data: g.es('pylint: no files found', color='red') return None for fn, p in data: self.run_pylint(fn, p) # #1808: return the last data file. return data[-1] if data else False
def show_line(line, fn): ''' Put the cursor on the requested line of the given file. fn should be a full path to a file. ''' c = g.app.log.c target = g.os_path_finalize(fn).replace('\\','/') if not g.os_path_exists(fn): g.trace('===== Does not exist', fn) return for p in c.all_positions(): if p.isAnyAtFileNode(): path = g.fullPath(c, p).replace('\\','/') if target == path: # Select the line. junk_p, junk_offset, ok = c.gotoCommands.find_file_line(n=line, p=p) if not ok: g.trace('FAIL:', target) c.bodyWantsFocusNow() return p = make_at_file_node(line, target) junk_p, junk_offset, ok = c.gotoCommands.find_file_line(n=line, p=p) if not ok: g.trace('FAIL:', target)
def _getpath(self, p): c = self.c path = g.fullPath(c, p) # #1914 # Use os.path.normpath to give system separators. return os.path.normpath(g.os_path_dirname(path)) # #1914
def finalize(self, p): """Finalize p's path.""" c = self.c # Use os.path.normpath to give system separators. return os.path.normpath(g.fullPath(c, p)) # #1914.