예제 #1
0
 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)
예제 #2
0
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'])
예제 #3
0
 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()
예제 #4
0
 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()
예제 #5
0
 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)
예제 #6
0
 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()
예제 #7
0
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."
    )
예제 #8
0
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))
예제 #9
0
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.")
예제 #10
0
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.")
예제 #11
0
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'])
예제 #12
0
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)
예제 #13
0
    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()
예제 #14
0
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))
예제 #15
0
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 = []
예제 #16
0
 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
예제 #17
0
 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)
예제 #18
0
 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
예제 #19
0
 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)
예제 #20
0
 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)
예제 #21
0
 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)
예제 #22
0
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}")
예제 #23
0
 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)
예제 #24
0
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}")
예제 #25
0
 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)
예제 #26
0
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}")
예제 #27
0
    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
예제 #28
0
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)
예제 #29
0
    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
예제 #30
0
 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.