Пример #1
0
def getCommandList():
    '''Return list of all command modules in leo/commands.'''
    pattern = g.os_path_finalize_join('.', 'leo', 'commands', '*.py')
    return sorted([
        g.shortFileName(fn)
            for fn in glob.glob(pattern)
                if g.shortFileName(fn) != '__init__.py'])
Пример #2
0
 def run(self, files):
     """Process all files"""
     self.files = files
     t1 = time.clock()
     for fn in files:
         s, e = g.readFileIntoString(fn)
         if s:
             self.tot_s += len(s)
             g.trace("%8s %s" % ("{:,}".format(len(s)), g.shortFileName(fn)))
             # Print len(s), with commas.
             # Fast, accurate:
             # 1.9 sec for parsing.
             # 2.5 sec for Null AstFullTraverer traversal.
             # 2.7 sec to generate all strings.
             # 3.8 sec to generate all reports.
             s1 = g.toEncodedString(s)
             self.tot_lines += len(g.splitLines(s))
             # Adds less than 0.1 sec.
             node = ast.parse(s1, filename="before", mode="exec")
             ShowDataTraverser(self, fn).visit(node)
             # elif 0: # Too slow, too clumsy: 3.3 sec for tokenizing
             # readlines = g.ReadLinesClass(s).next
             # for token5tuple in tokenize.generate_tokens(readlines):
             # pass
             # else: # Inaccurate. 2.2 sec to generate all reports.
             # self.scan(fn, s)
         else:
             g.trace("skipped", g.shortFileName(fn))
     t2 = time.clock()
     # Get the time exlusive of print time.
     self.show_results()
     g.trace("done: %4.1f sec." % (t2 - t1))
Пример #3
0
 def create_file_node(self, diff_list, fn1, fn2):
     '''Create an organizer node for the file.'''
     p = self.root.insertAsLastChild()
     p.h = '%s, %s' % (g.shortFileName(fn1).strip(),
                       g.shortFileName(fn2).strip())
     p.b = ''.join(diff_list)
     return p
Пример #4
0
def run(fn, verbose):
    '''Run pylint on fn.'''
    trace = False and not g.unitTesting
    # theDir is empty for the -f option.
    from pylint import lint
    assert lint
    rc_fn = os.path.abspath(os.path.join('leo', 'test', 'pylint-leo-rc.txt'))
    if not os.path.exists(rc_fn):
        print('pylint rc file not found: %s' % (rc_fn))
        return
    if verbose:
        path = g.os_path_dirname(fn)
        dirs = path.split(os.sep)
        theDir = dirs and dirs[-1] or ''
        print('pylint-leo.py: %s%s%s' % (theDir, os.sep, g.shortFileName(fn)))
    # Call pylint in a subprocess so Pylint doesn't abort *this* process.
    args = ','.join([
        "fn=r'%s'" % (fn),
        "rc=r'%s'" % (rc_fn),
    ])
    if 0:  # Prints error number.
        args.append(
            '--msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg}')
    command = '%s -c "import leo.core.leoGlobals as g; g.run_pylint(%s)"' % (
        sys.executable, args)
    t1 = time.clock()
    g.execute_shell_commands(command)
    t2 = time.clock()
    if trace:
        g.trace('%4.2f %s' % (t2 - t1, g.shortFileName(fn)))
Пример #5
0
    def start_process(self, c, command, kind, fn=None, shell=False):
        '''Start or queue a process described by command and fn.'''
        trace = False and not g.unitTesting
        self.data = data = self.ProcessData(c, kind, fn, shell)
        if self.pid:
            # A process is already active.  Add a new callback.
            if trace: self.put_log('===== Adding callback for %s' % g.shortFileName(fn))

            def callback(data=data):
                fn = data.fn
                self.put_log('%s: %s' % (kind, g.shortFileName(fn)))
                self.pid = subprocess.Popen(
                    command,
                    shell=shell,
                    stderr=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    universal_newlines=True,
                )
                if trace: self.put_log('===== Starting: %s for %s' % (
                    id(self.pid), g.shortFileName(fn)))

            data.callback = callback
            self.process_queue.append(data)
        else:
            # Start the process immediately.
            self.put_log('%s: %s' % (kind, g.shortFileName(fn)))
            self.pid = subprocess.Popen(
                command,
                shell=shell,
                stderr=subprocess.PIPE,
                stdout=subprocess.PIPE,
                universal_newlines=True,
            )
            if trace: self.put_log('===== Starting: %s for %s' % (
                id(self.pid), g.shortFileName(fn)))
Пример #6
0
def getCommandList():
    '''Return list of all command modules in leo/commands.'''
    pattern = g.os_path_finalize_join('.', 'leo', 'commands', '*.py')
    return sorted([
        g.shortFileName(fn) for fn in glob.glob(pattern)
        if g.shortFileName(fn) != '__init__.py'
    ])
Пример #7
0
    def start_process(self, c, command, kind, fn=None, shell=False):
        '''Start or queue a process described by command and fn.'''
        trace = False and not g.unitTesting
        self.data = data = self.ProcessData(c, kind, fn, shell)
        if self.pid:
            # A process is already active.  Add a new callback.
            if trace: self.put_log('===== Adding callback for %s' % g.shortFileName(fn))

            def callback(data=data):
                fn = data.fn
                self.put_log('%s: %s' % (kind, g.shortFileName(fn)))
                self.pid = subprocess.Popen(
                    command,
                    shell=shell,
                    stderr=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    universal_newlines=True,
                )
                if trace: self.put_log('===== Starting: %s for %s' % (
                    id(self.pid), g.shortFileName(fn)))

            data.callback = callback
            self.process_queue.append(data)
        else:
            # Start the process immediately.
            self.put_log('%s: %s' % (kind, g.shortFileName(fn)))
            self.pid = subprocess.Popen(
                command,
                shell=shell,
                stderr=subprocess.PIPE,
                stdout=subprocess.PIPE,
                universal_newlines=True,
            )
            if trace: self.put_log('===== Starting: %s for %s' % (
                id(self.pid), g.shortFileName(fn)))
Пример #8
0
def run(fn, verbose):
    '''Run pylint on fn.'''
    trace = False and not g.unitTesting
    # theDir is empty for the -f option.
    from pylint import lint
    assert lint
    rc_fn = os.path.abspath(os.path.join('leo','test','pylint-leo-rc.txt'))
    if not os.path.exists(rc_fn):
        print('pylint rc file not found: %s' % (rc_fn))
        return
    if verbose:
        path = g.os_path_dirname(fn)
        dirs = path.split(os.sep)
        theDir = dirs and dirs[-1] or ''
        print('pylint-leo.py: %s%s%s' % (theDir,os.sep,g.shortFileName(fn)))
    # Call pylint in a subprocess so Pylint doesn't abort *this* process.
    args = ','.join([
        "fn=r'%s'" % (fn),
        "rc=r'%s'" % (rc_fn),
    ])
    if 0: # Prints error number.
        args.append('--msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg}')
    command = '%s -c "import leo.core.leoGlobals as g; g.run_pylint(%s)"' % (
        sys.executable, args)
    t1 = time.clock()
    g.execute_shell_commands(command)
    t2 = time.clock()
    if trace:
        g.trace('%4.2f %s' % (t2-t1, g.shortFileName(fn)))
Пример #9
0
 def run(self, files):
     '''Process all files'''
     self.files = files
     t1 = time.clock()
     for fn in files:
         s, e = g.readFileIntoString(fn)
         if s:
             self.tot_s += len(s)
             g.trace('%8s %s' %
                     ("{:,}".format(len(s)), g.shortFileName(fn)))
             # Print len(s), with commas.
             # Fast, accurate:
             # 1.9 sec for parsing.
             # 2.5 sec for Null AstFullTraverer traversal.
             # 2.7 sec to generate all strings.
             # 3.8 sec to generate all reports.
             s1 = g.toEncodedString(s)
             self.tot_lines += len(g.splitLines(s))
             # Adds less than 0.1 sec.
             node = ast.parse(s1, filename='before', mode='exec')
             ShowDataTraverser(self, fn).visit(node)
             # elif 0: # Too slow, too clumsy: 3.3 sec for tokenizing
             # readlines = g.ReadLinesClass(s).next
             # for token5tuple in tokenize.generate_tokens(readlines):
             # pass
             # else: # Inaccurate. 2.2 sec to generate all reports.
             # self.scan(fn, s)
         else:
             g.trace('skipped', g.shortFileName(fn))
     t2 = time.clock()
     # Get the time exlusive of print time.
     self.show_results()
     g.trace('done: %4.1f sec.' % (t2 - t1))
Пример #10
0
def getGuiPluginsList():

    pattern = g.os_path_finalize_join(".", "leo", "plugins", "qt_*.py")
    aList = [g.shortFileName(fn) for fn in glob.glob(pattern) if g.shortFileName(fn) != "__init__.py"]
    aList.extend(["free_layout", "nested_splitter"])
    if "qt_main.py" in aList:
        # Auto-generated file.
        aList.remove("qt_main.py")
    return sorted(aList)
Пример #11
0
def createScriptsMenu (tag,keywords):

    c = keywords.get("c")
    path = os.path.join(g.app.loadDir,"..","scripts")

    if os.path.exists(path):

        # Create lists of scripts and subdirectories.
        entries = glob.glob(os.path.join(path,"*"))
        top_scripts = glob.glob(os.path.join(path,"*.py"))
        dirs = [f for f in entries if os.path.isdir(f)]
        #@+<< Return if no scripts exist anywhere >>
        #@+node:EKR.20040517080555.38: *3* << Return if no scripts exist anywhere >>
        if not top_scripts:
            found = False
            for dir in dirs:
                scripts = glob.glob(os.path.join(dir,"*.py"))
                if scripts:
                    found = True ; break
            if not found:
                return
        #@-<< Return if no scripts exist anywhere >>

        scriptsMenu = c.frame.menu.createNewMenu("&Scripts")
        table = []
        #@+<< Create top-level entries for every script in top_scripts >>
        #@+node:EKR.20040517080555.39: *3* << Create top-level entries for every script in top_scripts >>
        table = []
        top_scripts.sort()
        for script in top_scripts:
            name = g.shortFileName(script)
            def doScript(event=None,name=name):
                g.executeScript(name)
            table.append((name,None,doScript),)

        c.frame.menu.createMenuEntries(scriptsMenu, table,dynamicMenu=True)
        #@-<< Create top-level entries for every script in top_scripts >>
        for dir in dirs:
            files = glob.glob(os.path.join(dir,"*.py"))
            if files:
                #@+<< Create a submenu for dir containing each file in files >>
                #@+node:EKR.20040517080555.40: *3* << Create a submenu for dir containing each file in files >>
                # Create the submenu.
                name = os.path.join("scripts",g.shortFileName(dir))
                menu = c.frame.menu.createNewMenu(name,"&Scripts")

                # Populate the submenu.
                table = []
                for file in files:
                    name = g.shortFileName(file)
                    # EKR: use doScript1 to keep pylint happy.
                    def doScript1(event=None,name=name):
                        g.executeScript(name)
                    table.append((name,None,doScript1),)

                c.frame.menu.createMenuEntries(menu, table,dynamicMenu=True)
Пример #12
0
 def __init__(self, controller, fn):
     '''Ctor for ShopDataTraverser class.'''
     module_tuple = g.shortFileName(fn), 'module', g.shortFileName(fn)
     # fn, kind, s.
     self.context_stack = [module_tuple]
     self.controller = controller
     self.fn = g.shortFileName(fn)
     self.formatter = leoAst.AstFormatter()
     # leoAst.AstPatternFormatter()
     self.trace = False
Пример #13
0
 def __init__(self, controller, fn):
     """Ctor for ShopDataTraverser class."""
     module_tuple = g.shortFileName(fn), "module", g.shortFileName(fn)
     # fn, kind, s.
     self.context_stack = [module_tuple]
     self.controller = controller
     self.fn = g.shortFileName(fn)
     self.formatter = leoAst.AstFormatter()
     # leoAst.AstPatternFormatter()
     self.trace = False
Пример #14
0
 def find_c(self, path):
     '''Return the commander associated with path, or None.'''
     g = self.g
     self.update()
     path = g.os_path_normcase(path)
     short_path = g.shortFileName(path)
     for c in self.commanders_list:
         fn = g.os_path_normcase(c.fileName())
         short_fn = g.shortFileName(fn)
         if fn == path or short_fn == short_path:
             return c
Пример #15
0
def getCoreList():
    
    pattern = g.os_path_finalize_join('.','leo','core','leo*.py')
    aList = [
        g.shortFileName(fn)
            for fn in glob.glob(pattern)
                if g.shortFileName(fn) != '__init__.py']
    aList.extend([
         'runLeo.py',
    ])
    return sorted(aList)
Пример #16
0
 def find_c(self,path):
     '''Return the commander associated with path, or None.'''
     g = self.g
     self.update()
     path = g.os_path_normcase(path)
     short_path = g.shortFileName(path)
     for c in self.commanders_list:
         fn = g.os_path_normcase(c.fileName())
         short_fn = g.shortFileName(fn)
         if fn == path or short_fn == short_path:
             return c
Пример #17
0
def getCoreList():
    pattern = g.os_path_finalize_join('.', 'leo', 'core', 'leo*.py')
    # pattern = g.os_path_finalize_join('leo','core','leo*.py')
    aList = [
        g.shortFileName(fn) for fn in glob.glob(pattern)
        if g.shortFileName(fn) != '__init__.py'
    ]
    aList.extend([
        'runLeo.py',
    ])
    return sorted(aList)
Пример #18
0
 def find_c(self, path):
     """Return the commander associated with path, or None."""
     g = self.g  # type:ignore # mypy seems confused. g is a local var.
     self.update()
     path = g.os_path_normcase(path)
     short_path = g.shortFileName(path)
     for c in self.commanders_list:
         fn = g.os_path_normcase(c.fileName())
         short_fn = g.shortFileName(fn)
         if fn == path or short_fn == short_path:
             return c
     return None
Пример #19
0
 def callback(data=data):
     fn = data.fn
     self.put_log('%s: %s' % (kind, g.shortFileName(fn)))
     self.pid = subprocess.Popen(
         command,
         shell=shell,
         stderr=subprocess.PIPE,
         stdout=subprocess.PIPE,
         universal_newlines=True,
     )
     if trace: self.put_log('===== Starting: %s for %s' % (
         id(self.pid), g.shortFileName(fn)))
Пример #20
0
 def callback(data=data):
     fn = data.fn
     self.put_log('%s: %s' % (kind, g.shortFileName(fn)))
     self.pid = subprocess.Popen(
         command,
         shell=shell,
         stderr=subprocess.PIPE,
         stdout=subprocess.PIPE,
         universal_newlines=True,
     )
     if trace: self.put_log('===== Starting: %s for %s' % (
         id(self.pid), g.shortFileName(fn)))
Пример #21
0
def getGuiPluginsList():
    pattern = g.os_path_finalize_join('.', 'leo', 'plugins', 'qt_*.py')
    aList = [
        g.shortFileName(fn) for fn in glob.glob(pattern)
        if g.shortFileName(fn) != '__init__.py'
    ]
    aList.extend([
        'free_layout',
        'nested_splitter',
    ])
    if 'qt_main.py' in aList:
        # Auto-generated file.
        aList.remove('qt_main.py')
    return sorted(aList)
Пример #22
0
def getGuiPluginsList():
    pattern = g.os_path_finalize_join('.', 'leo', 'plugins', 'qt_*.py')
    aList = [
        g.shortFileName(fn)
            for fn in glob.glob(pattern)
                if g.shortFileName(fn) != '__init__.py']
    aList.extend([
        'free_layout',
        'nested_splitter',
    ])
    if 'qt_main.py' in aList:
        # Auto-generated file.
        aList.remove('qt_main.py')
    return sorted(aList)
Пример #23
0
    def __init__(self, c, images):
        """Create a Recent Sections listbox dialog."""

        self.c = c
        self.images = images
        self.label = None
        self.title = "Recent nodes for %s" % g.shortFileName(c.mFileName)
        self.lt_nav_button = self.rt_nav_button = None  # Created by createFrame.

        # Create the show-recent-sections-dialog command.
        self.addCommand()

        # Add 'Recent' button to icon bar.
        self.addIconBarButtons()

        # Init the base class. (calls createFrame)
        # N.B.  The base class contains positionList ivar.
        tkinterListBoxDialog.__init__(self, c, self.title, self.label)

        self.fillbox()  # Must be done initially.

        if not recentInitiallyVisible:
            self.top.withdraw()

        self.updateButtons()

        self.addGeneratorCommands()

        c.bind(self.top, "<Up>", self.up)
        c.bind(self.top, "<Down>", self.down)
Пример #24
0
 def __repr__(self):
     return 'PyTarget: %s kind: %s @others: %s p: %s' % (
         self.state,
         self.kind,
         int(self.at_others_flag),
         g.shortFileName(self.p.h),
     )
Пример #25
0
 def createOutlineFromCacheList(self, parent_v, aList, fileName, top=True):
     '''
     Create outline structure from recursive aList built by makeCacheList.
     '''
     trace = False and not g.unitTesting  # and fileName.endswith('leoFileCommands.py')
     c = self.c
     if not c:
         g.internalError('no c')
         return
     if top:
         if trace: g.trace(g.shortFileName(fileName))
         c.cacheListFileName = fileName
     if not aList:
         if trace: g.trace('no list')
         return
     h, b, gnx, children = aList
     if h is not None:
         v = parent_v
         # Does this destroy the ability to handle the rare case?
         v._headString = g.toUnicode(h)
         v._bodyString = g.toUnicode(b)
     for child_tuple in children:
         h, b, gnx, grandChildren = child_tuple
         if trace:
             g.trace('%30s %3s %s' % (gnx, len(grandChildren), h.strip()))
         isClone, child_v = self.fastAddLastChild(fileName, gnx, parent_v)
         if isClone:
             self.checkForChangedNodes(child_tuple, fileName, parent_v)
         else:
             self.createOutlineFromCacheList(child_v,
                                             child_tuple,
                                             fileName,
                                             top=False)
Пример #26
0
    def __init__ (self,c,images):

        """Create a Recent Sections listbox dialog."""

        self.c = c
        self.images = images
        self.label = None
        self.title = "Recent nodes for %s" % g.shortFileName(c.mFileName)
        self.lt_nav_button = self.rt_nav_button = None # Created by createFrame.

        # Create the show-recent-sections-dialog command.
        self.addCommand()

        # Add 'Recent' button to icon bar.
        self.addIconBarButtons()

        # Init the base class. (calls createFrame)
        # N.B.  The base class contains positionList ivar.
        tkinterListBoxDialog.__init__(self,c,self.title,self.label)

        self.fillbox() # Must be done initially.

        if not recentInitiallyVisible:
            self.top.withdraw()

        self.updateButtons()

        self.addGeneratorCommands()

        c.bind(self.top,"<Up>",self.up)
        c.bind(self.top,"<Down>",self.down)
Пример #27
0
    def __init__(self, filename, parent, **kwargs):
        '''
        Called automatically from pyzo's createEditor function.
        '''

        assert g.pyzo, g.callers()
        g.pr('\nOutlineEditorShim.__init__', g.shortFileName(filename))
        # g.printObj(g.callers(30).split(','), tag='OutlineEditorShim.__init__')
        super().__init__(parent, **kwargs)
        # CodeEditorBase only passes args to *its* base class.
        self.setObjectName('OutlineEditorShim')
        self.c = None  # Set in createOutlineFrame.
        self._filename = self.filename = filename
        # Essential, so the tab will close properly.
        self._name = self.name = os.path.split(filename)[1]
        # To set the tab's name properly.
        if not isinstance(self, CodeEditorBase):
            g.pr('\nOutlineEditorShim: using shims\n')
            #
            # Needed if this is just a QWidget.
            self._breakPoints = {}
            # self.breakPointsChanged.emit(self)
            # self.__breakPointArea.update()
            self.lineEndingsHumanReadable = 'CRLF'
            self.document = DocumentShim
            self.horizontalScrollBar = ScrollBarShim
            self.parser = g.TracingNullObject(tag='OutlineEditorShim.parser')
            self.textCursor = TextCursorShim
            self.verticalScrollBar = ScrollBarShim
        # Create the outline!
        self.createOutlineFrame()
Пример #28
0
    def check_all(self, log_flag, paths, pyflakes_errors_only):
        '''Run pyflakes on all files in paths.'''
        from pyflakes import api, reporter
        total_errors = 0
        for fn in sorted(paths):
            # Report the file name.
            sfn = g.shortFileName(fn)
            s = g.readFileIntoEncodedString(fn)
            if s.strip():
                if not pyflakes_errors_only:
                    g.es('Pyflakes: %s' % sfn)
                # Send all output to the log pane.

                class LogStream:

                    def write(self, s):
                        if s.strip():
                            g.es_print(s)
                                # It *is* useful to send pyflakes errors to the console.

                r = reporter.Reporter(
                        errorStream=LogStream(),
                        warningStream=LogStream(),
                    )
                errors = api.check(s, sfn, r)
                total_errors += errors
        return total_errors
Пример #29
0
 def check_all(self, log_flag, pyflakes_errors_only, roots):
     """Run pyflakes on all files in paths."""
     try:
         from pyflakes import api, reporter
     except Exception:  # ModuleNotFoundError
         return True  # Pretend all is fine.
     total_errors = 0
     for i, root in enumerate(roots):
         fn = self.finalize(root)
         sfn = g.shortFileName(fn)
         # #1306: nopyflakes
         if any([
                 z.strip().startswith('@nopyflakes')
                 for z in g.splitLines(root.b)
         ]):
             continue
         # Report the file name.
         s = g.readFileIntoEncodedString(fn)
         if s and s.strip():
             if not pyflakes_errors_only:
                 g.es(f"Pyflakes: {sfn}")
             # Send all output to the log pane.
             r = reporter.Reporter(
                 errorStream=self.LogStream(i, roots),
                 warningStream=self.LogStream(i, roots),
             )
             errors = api.check(s, sfn, r)
             total_errors += errors
     return total_errors
Пример #30
0
 def regularize_whitespace(self, lines):
     """
     Regularize leading whitespace in s:
     Convert tabs to blanks or vice versa depending on the @tabwidth in effect.
     """
     kind = 'tabs' if self.tab_width > 0 else 'blanks'
     kind2 = 'blanks' if self.tab_width > 0 else 'tabs'
     fn = g.shortFileName(self.root.h)
     count, result, tab_width = 0, [], self.tab_width
     self.ws_error = False  # 2016/11/23
     if tab_width < 0:  # Convert tabs to blanks.
         for n, line in enumerate(lines):
             i, w = g.skip_leading_ws_with_indent(line, 0, tab_width)
             # Use negative width.
             s = g.computeLeadingWhitespace(w, -abs(tab_width)) + line[i:]
             if s != line:
                 count += 1
             result.append(s)
     elif tab_width > 0:  # Convert blanks to tabs.
         for n, line in enumerate(lines):
             # Use positive width.
             s = g.optimizeLeadingWhitespace(line, abs(tab_width))
             if s != line:
                 count += 1
             result.append(s)
     if count:
         self.ws_error = True  # A flag to check.
         if not g.unitTesting:
             # g.es_print('Warning: Intermixed tabs and blanks in', fn)
             # g.es_print('Perfect import test will ignoring leading whitespace.')
             g.es('changed leading %s to %s in %s line%s in %s' % (
                 kind2, kind, count, g.plural(count), fn))
         if g.unitTesting:  # Sets flag for unit tests.
             self.report('changed %s lines' % count)
     return result
Пример #31
0
 def __repr__(self):
     return 'Target: %s @others: %s refs: %s p: %s' % (
         self.state,
         int(self.at_others_flag),
         int(self.gen_refs),
         g.shortFileName(self.p.h),
     )
Пример #32
0
    def add_class_names(self, p):
        """
        Add class names to headlines for all descendant nodes.

        Called only when @bool add-context-to-headlines is True.
        """
        if g.unitTesting:
            return  # Don't changes the expected headlines.
        after, fn, class_name = None, None, None
        for p in p.self_and_subtree():
            # Part 1: update the status.
            m = self.file_pattern.match(p.h)
            if m:
                prefix = m.group(1)
                fn = g.shortFileName(p.h[len(prefix) :].strip())
                after, class_name = None, None
                continue
            if p.h.startswith('@path '):
                after, fn, class_name = None, None, None
            elif p.h.startswith('class '):
                class_name = p.h[5:].strip()
                if class_name:
                    after = p.nodeAfterTree()
                    continue
            elif p == after:
                after, class_name = None, None
            # Part 2: update the headline.
            if class_name:
                if not p.h.startswith(class_name):
                    p.h = '%s.%s' % (class_name, p.h)
            elif fn and self.add_file_context:
                tag = ' (%s)' % fn
                if not p.h.endswith(tag):
                    p.h += tag
Пример #33
0
 def check_blanks_and_tabs(self, lines):
     """Check for intermixed blank & tabs."""
     # Do a quick check for mixed leading tabs/blanks.
     fn = g.shortFileName(self.root.h)
     w = self.tab_width
     blanks = tabs = 0
     for s in lines:
         lws = self.get_str_lws(s)
         blanks += lws.count(' ')
         tabs += lws.count('\t')
     # Make sure whitespace matches @tabwidth directive.
     if w < 0:
         ok = tabs == 0
         message = 'tabs found with @tabwidth %s in %s' % (w, fn)
     elif w > 0:
         ok = blanks == 0
         message = 'blanks found with @tabwidth %s in %s' % (w, fn)
     if ok:
         ok = (blanks == 0 or tabs == 0)
         message = 'intermixed blanks and tabs in: %s' % (fn)
     if not ok:
         if g.unitTesting:
             self.report(message)
         else:
             g.es(message)
     return ok
Пример #34
0
def fstringify_diff_files(event):
    """
    Show the diffs that would result from fstringifying the external files at
    c.p.
    """
    c = event.get('c')
    if not c or not c.p:
        return
    t1 = time.process_time()
    tag = 'fstringify-files-diff'
    g.es(f"{tag}...")
    roots = g.findRootsWithPredicate(c, c.p)
    for root in roots:
        filename = g.fullPath(c, root)
        if os.path.exists(filename):
            print('')
            print(g.shortFileName(filename))
            changed = leoAst.Fstringify().fstringify_file_diff(filename)
            changed_s = 'changed' if changed else 'unchanged'
            g.es_print(f"{changed_s:>9}: {g.shortFileName(filename)}")
        else:
            print('')
            print(f"File not found:{filename}")
            g.es(f"File not found:\n{filename}")
    t2 = time.process_time()
    print('')
    g.es_print(
        f"{len(roots)} file{g.plural(len(roots))} in {t2 - t1:5.2f} sec.")
Пример #35
0
def fstringify_files(event):
    """fstringify one or more files at c.p."""
    c = event.get('c')
    if not c or not c.p:
        return
    t1 = time.process_time()
    tag = 'fstringify-files'
    g.es(f"{tag}...")
    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(g.shortFileName(filename))
            changed = leoAst.Fstringify().fstringify_file(filename)
            changed_s = 'changed' if changed else 'unchanged'
            if changed: n_changed += 1
            g.es_print(f"{changed_s:>9}: {g.shortFileName(filename)}")
        else:
            print('')
            print(f"File not found:{filename}")
            g.es(f"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.")
Пример #36
0
 def open_dict_file(self, fn):
     '''Open or create the dict with the given fn.'''
     trace = False and not g.unitTesting
     language = self.language
     if not fn or not language:
         return None
     if g.app.spellDict:
         if trace: g.trace('already open', self.c.fileName(), fn)
         return g.app.spellDict
     if not g.os_path_exists(fn):
         # Fix bug 1175013: leo/plugins/spellpyx.txt is
         # both source controlled and customized.
         self.create(fn)
     if g.os_path_exists(fn):
         # Merge the local and global dictionaries.
         try:
             self.clean_dict(fn)
             d = enchant.DictWithPWL(language, fn)
             if trace: g.trace('open', g.shortFileName(self.c.fileName()), fn)
         except Exception:
             # This is off-putting, and not necessary.
             # g.es('Error reading dictionary file', fn)
             # g.es_exception()
             d = enchant.Dict(language)
     else:
         # A fallback.  Unlikely to happen.
         d = enchant.Dict(language)
     return d
Пример #37
0
    def start_process(self, c, command, kind,
        fn=None,
        link_pattern=None,
        link_root=None,
        shell=False,
    ):
        '''Start or queue a process described by command and fn.'''
        self.data = data = self.ProcessData(c, kind, fn, link_pattern, link_root, shell)
        if self.pid:
            # A process is already active.  Add a new callback.

            def callback(data=data, kind=kind):
                fn = data.fn
                self.put_log('%s: %s\n' % (kind, g.shortFileName(fn)))
                self.pid = subprocess.Popen(
                    command,
                    shell=shell,
                    stderr=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    universal_newlines=True,
                )
            data.callback = callback
            self.process_queue.append(data)
        else:
            # Start the process immediately.
            self.kind = kind
            self.put_log('%s: %s\n' % (kind, g.shortFileName(fn)))
            self.pid = subprocess.Popen(
                command,
                shell=shell,
                stderr=subprocess.PIPE,
                stdout=subprocess.PIPE,
                universal_newlines=True,
            )
Пример #38
0
def getPluginsList():
    '''Return a list of all important plugins.'''
    aList = []
    # g.app.loadDir does not exist: use '.' instead.
    for theDir in ('', 'importers', 'writers'):
        pattern = g.os_path_finalize_join('.', 'leo', 'plugins', theDir,
                                          '*.py')
        for fn in glob.glob(pattern):
            sfn = g.shortFileName(fn)
            if sfn != '__init__.py':
                sfn = os.sep.join([theDir, sfn]) if theDir else sfn
                aList.append(sfn)
    remove = [
        'free_layout.py',  # Gui-related.
        'gtkDialogs.py',  # Many errors, not important.
        'leofts.py',  # Not (yet) in leoPlugins.leo.
        'nested_splitter.py',  # Gui-related.
        'qtGui.py',  # Dummy file
        'qt_main.py',  # Created automatically.
    ]
    aList = sorted([z for z in aList if z not in remove])
    # Remove all gui related items.
    for z in sorted(aList):
        if z.startswith('qt_'):
            aList.remove(z)
    # g.trace('\n'.join(aList))
    return aList
Пример #39
0
 def open_dict(self, fn, language):
     '''Open or create the dict with the given fn.'''
     trace = False and not g.unitTesting
     if not fn or not language:
         return
     d = g.app.spellDict
     if d:
         self.d = d
         if trace: g.trace('already open', self.c.fileName(), fn)
         return
     if not g.os_path_exists(fn):
         # Fix bug 1175013: leo/plugins/spellpyx.txt is both source controlled and customized.
         self.create(fn)
     if g.os_path_exists(fn):
         # Merge the local and global dictionaries.
         try:
             self.clean_dict(fn)
             self.d = enchant.DictWithPWL(language, fn)
             if trace: g.trace('open', g.shortFileName(self.c.fileName()), fn)
         except Exception:
             g.es_exception()
             g.error('not a valid dictionary file', fn)
             self.d = enchant.Dict(language)
     else:
         # A fallback.  Unlikely to happen.
         self.d = enchant.Dict(language)
     # Use only a single copy of the dict.
     g.app.spellDict = self.d
Пример #40
0
    def __init__ (self,c,images):

        """Create a Marks listbox dialog."""

        self.c = c
        self.images = images

        self.label = None
        self.title = 'Marks for %s' % g.shortFileName(c.mFileName) # c.frame.title

        # Init the base class and call self.createFrame.
        tkinterListBoxDialog.__init__(self,c,self.title,self.label)

        # Create the show-marks-dialog command.
        self.addCommand()


        if not marksInitiallyVisible:
            self.top.withdraw()

        self.addButtons()

        # Create the marks menu generator commands.
        self.addGeneratorCommands()

        c.bind(self.top,"<Up>",self.up)
        c.bind(self.top,"<Down>",self.down)
Пример #41
0
def getPluginsList():
    '''Return a list of all important plugins.'''
    aList = []
    # g.app.loadDir does not exist: use '.' instead.
    for theDir in ('','importers','writers'):
        pattern = g.os_path_finalize_join('.','leo','plugins',theDir,'*.py')
        for fn in glob.glob(pattern):
            sfn = g.shortFileName(fn)
            if sfn != '__init__.py':
                sfn = os.sep.join([theDir,sfn]) if theDir else sfn
                aList.append(sfn)
    remove = [
        'free_layout.py',       # Gui-related.
        'gtkDialogs.py',        # Many errors, not important.
        'leofts.py',            # Not (yet) in leoPlugins.leo.
        'nested_splitter.py',   # Gui-related.
        'qtGui.py',             # Dummy file
        'qt_main.py',           # Created automatically.
    ]
    aList = sorted([z for z in aList if z not in remove])
    # Remove all gui related items.
    for z in sorted(aList):
        if z.startswith('qt_'):
            aList.remove(z)
    # g.trace('\n'.join(aList))
    return aList
Пример #42
0
 def createOutlineFromCacheList(self, parent_v, aList, fileName, top=True):
     '''
     Create outline structure from recursive aList built by makeCacheList.
     '''
     trace = False and not g.unitTesting # and fileName.endswith('leoFileCommands.py')
     c = self.c
     if not c:
         g.internalError('no c')
         return
     if top:
         if trace: g.trace(g.shortFileName(fileName))
         c.cacheListFileName = fileName
     if not aList:
         if trace: g.trace('no list')
         return
     h, b, gnx, children = aList
     if h is not None:
         v = parent_v
         # Does this destroy the ability to handle the rare case?
         v._headString = g.toUnicode(h)
         v._bodyString = g.toUnicode(b)
     for child_tuple in children:
         h, b, gnx, grandChildren = child_tuple
         if trace:
             g.trace('%30s %3s %s' % (gnx, len(grandChildren), h.strip()))
         isClone, child_v = self.fastAddLastChild(fileName, gnx, parent_v)
         if isClone:
             self.checkForChangedNodes(child_tuple, fileName, parent_v)
         else:
             self.createOutlineFromCacheList(child_v, child_tuple, fileName, top=False)
Пример #43
0
 def readFile(self, fileName, root):
     '''
     Read the file from the cache if possible.
     Return (s,ok,key)
     '''
     trace = (False or g.app.debug) and not g.unitTesting
     showHits, showLines, verbose = False, False, True
     sfn = g.shortFileName(fileName)
     if not g.enableDB:
         if trace and verbose: g.trace('g.enableDB is False', sfn)
         return '', False, None
     s = g.readFileIntoEncodedString(fileName, silent=True)
     if s is None:
         if trace: g.trace('empty file contents', sfn)
         return s, False, None
     assert not g.isUnicode(s)
     if trace and showLines:
         for i, line in enumerate(g.splitLines(s)):
             print('%3d %s' % (i, repr(line)))
     # There will be a bug if s is not already an encoded string.
     key = self.fileKey(root.h, s, requireEncodedString=True)
     ok = self.db and key in self.db
     if ok:
         if trace and showHits: g.trace('cache hit', key[-6:], sfn)
         # Delete the previous tree, regardless of the @<file> type.
         while root.hasChildren():
             root.firstChild().doDelete()
         # Recreate the file from the cache.
         aList = self.db.get(key)
         self.createOutlineFromCacheList(root.v, aList, fileName=fileName)
     elif trace:
         g.trace('cache miss', key[-6:], sfn)
     return s, ok, key
Пример #44
0
def getPluginsList():
    """Return a list of all important plugins."""
    aList = []
    # g.app.loadDir does not exist: use '.' instead.
    for theDir in ("", "importers", "writers"):
        pattern = g.os_path_finalize_join(".", "leo", "plugins", theDir, "*.py")
        for fn in glob.glob(pattern):
            sfn = g.shortFileName(fn)
            if sfn != "__init__.py":
                sfn = os.sep.join([theDir, sfn]) if theDir else sfn
                aList.append(sfn)
    remove = [
        "free_layout.py",  # Gui-related.
        "gtkDialogs.py",  # Many errors, not important.
        "leofts.py",  # Not (yet) in leoPlugins.leo.
        "nested_splitter.py",  # Gui-related.
        "qtGui.py",  # Dummy file
        "qt_main.py",  # Created automatically.
    ]
    aList = sorted([z for z in aList if z not in remove])
    # Remove all gui related items.
    for z in sorted(aList):
        if z.startswith("qt_"):
            aList.remove(z)
    # g.trace('\n'.join(aList))
    return aList
Пример #45
0
    def check_all(self, log_flag, paths):
        '''Run pyflakes on all files in paths.'''
        from pyflakes import api, reporter
        total_errors = 0
        for fn in sorted(paths):
            # Report the file name.
            sfn = g.shortFileName(fn)
            s = g.readFileIntoEncodedString(fn, silent=False)
            if s.strip():
                g.es('Pyflakes: %s' % sfn)

                # Send all output to the log pane.
                class LogStream:
                    def write(self, s):
                        if s.strip():
                            g.es_print(s)
                            # It *is* useful to send pyflakes errors to the console.

                r = reporter.Reporter(
                    errorStream=LogStream(),
                    warningStream=LogStream(),
                )
                errors = api.check(s, sfn, r)
                total_errors += errors
        return total_errors
Пример #46
0
 def createOutlineFromCacheList(self, parent_v, aList, fileName, top=True):
     """
     Create outline structure from recursive aList built by makeCacheList.
     """
     trace = False and not g.unitTesting
     c = self.c
     if not c:
         g.internalError('no c')
     if top:
         if trace: g.trace(g.shortFileName(fileName))
         c.cacheListFileName = fileName
     if not aList:
         if trace: g.trace('no list')
         return
     h, b, gnx, children = aList
     if h is not None:
         v = parent_v
         v._headString = g.toUnicode(h) # 2017/01/16
         v._bodyString = g.toUnicode(b) # 2017/01/16
     for z in children:
         h, b, gnx, grandChildren = z
         isClone, child_v = self.fastAddLastChild(parent_v, gnx)
         if isClone:
             self.reportChangedClone(child_v, b, h, gnx)
         else:
             self.createOutlineFromCacheList(
                 child_v, z, fileName, top=False)
Пример #47
0
 def open_dict(self, fn, language):
     '''Open or create the dict with the given fn.'''
     trace = False and not g.unitTesting
     if not fn or not language:
         return
     d = g.app.spellDict
     if d:
         self.d = d
         if trace: g.trace('already open', self.c.fileName(), fn)
         return
     if not g.os_path_exists(fn):
         # Fix bug 1175013: leo/plugins/spellpyx.txt is both source controlled and customized.
         self.create(fn)
     if g.os_path_exists(fn):
         # Merge the local and global dictionaries.
         try:
             self.clean_dict(fn)
             self.d = enchant.DictWithPWL(language, fn)
             if trace:
                 g.trace('open', g.shortFileName(self.c.fileName()), fn)
         except Exception:
             g.es_exception()
             g.error('not a valid dictionary file', fn)
             self.d = enchant.Dict(language)
     else:
         # A fallback.  Unlikely to happen.
         self.d = enchant.Dict(language)
     # Use only a single copy of the dict.
     g.app.spellDict = self.d
Пример #48
0
def getPluginsList():
    '''Return a list of all important plugins.'''
    aList = []
    # g.app.loadDir does not exist: use '.' instead.
    for theDir in ('importers','writers'):
        pattern = g.os_path_finalize_join('.','leo','plugins',theDir,'*.py')
        for fn in glob.glob(pattern):
            sfn = g.shortFileName(fn)
            if sfn != '__init__.py':
                aList.append(os.sep.join([theDir,sfn]))
    aList.extend([
        'baseNativeTree',
        'bookmarks',
        'contextmenu',
        'leoOPML',
        'lineNumbers',
        # 'mod_http',
        'mod_scripting',
        'nav_qt',
        'quicksearch',
        'todo',
        'vim.py',
        'viewrendered.py',
        'xemacs.py',
    ])
    return aList
Пример #49
0
 def add_class_names(self, p):
     '''Add class names to headlines for all descendant nodes.'''
     if g.app.unitTesting:
         return # Don't changes the expected headlines.
     after, fn, class_name = None, None, None
     for p in p.self_and_subtree():
         # Part 1: update the status.
         m = self.file_pattern.match(p.h)
         if m:
             prefix = m.group(1)
             fn = g.shortFileName(p.h[len(prefix):].strip())
             after, class_name = None, None
             continue
         elif p.h.startswith('@path '):
             after, fn, class_name = None, None, None
         elif p.h.startswith('class '):
             class_name = p.h[5:].strip()
             if class_name:
                 after = p.nodeAfterTree()
                 continue
         elif p == after:
             after, class_name = None, None
         # Part 2: update the headline.
         if class_name:
             if not p.h.startswith(class_name):
                 p.h = '%s.%s' % (class_name, p.h)
         elif fn:
             tag = ' (%s)' % fn
             if not p.h.endswith(tag):
                 p.h += tag
Пример #50
0
    def shadowPathName (self,filename):

        '''Return the full path name of filename, resolved using c.fileName()'''

        x = self ; c = x.c

        baseDir = x.baseDirName()
        fileDir = g.os_path_dirname(filename)

        # 2011/01/26: bogomil: redirect shadow dir
        if self.shadow_in_home_dir:

            # Each .leo file has a separate shadow_cache in base dir
            fname = "_".join([os.path.splitext(os.path.basename(c.mFileName))[0],"shadow_cache"])

            # On Windows incorporate the drive letter to the private file path
            if os.name == "nt":
                fileDir = fileDir.replace(':','%')

            # build the chache path as a subdir of the base dir            
            fileDir = "/".join([baseDir, fname, fileDir])

        return baseDir and c.os_path_finalize_join(
                baseDir,
                fileDir, # Bug fix: honor any directories specified in filename.
                x.shadow_subdir,
                x.shadow_prefix + g.shortFileName(filename))
Пример #51
0
 def __repr__(self):
     return 'PyTarget: %s kind: %s @others: %s p: %s' % (
         self.state,
         self.kind,
         int(self.at_others_flag),
         g.shortFileName(self.p.h),
     )
Пример #52
0
 def __repr__(self):
     return 'Target: %s @others: %s refs: %s p: %s' % (
         self.state,
         int(self.at_others_flag),
         int(self.gen_refs),
         g.shortFileName(self.p.h),
     )
Пример #53
0
 def check_blanks_and_tabs(self, lines):
     '''Check for intermixed blank & tabs.'''
     # Do a quick check for mixed leading tabs/blanks.
     fn = g.shortFileName(self.root.h)
     w = self.tab_width
     blanks = tabs = 0
     for s in g.splitLines(lines):
         lws = self.get_str_lws(s)
         blanks += lws.count(' ')
         tabs += lws.count('\t')
     # Make sure whitespace matches @tabwidth directive.
     if w < 0:
         ok = tabs == 0
         message = 'tabs found with @tabwidth %s in %s' % (w, fn)
     elif w > 0:
         ok = blanks == 0
         message = 'blanks found with @tabwidth %s in %s' % (w, fn)
     if ok:
         ok = blanks == 0 or tabs == 0
         message = 'intermixed blanks and tabs in: %s' % (fn)
     if not ok:
         if g.unitTesting:
             self.report(message)
         else:
             g.es(message)
     return ok
Пример #54
0
    def shadowPathName (self,filename):

        '''Return the full path name of filename, resolved using c.fileName()'''

        x = self ; c = x.c

        baseDir = x.baseDirName()
        fileDir = g.os_path_dirname(filename)

        # 2011/01/26: bogomil: redirect shadow dir
        if self.shadow_in_home_dir:

            # Each .leo file has a separate shadow_cache in base dir
            fname = "_".join([os.path.splitext(os.path.basename(c.mFileName))[0],"shadow_cache"])

            # On Windows incorporate the drive letter to the private file path
            if os.name == "nt":
                fileDir = fileDir.replace(':','%')

            # build the chache path as a subdir of the base dir            
            fileDir = "/".join([baseDir, fname, fileDir])

        return baseDir and c.os_path_finalize_join(
                baseDir,
                fileDir, # Bug fix: honor any directories specified in filename.
                x.shadow_subdir,
                x.shadow_prefix + g.shortFileName(filename))
Пример #55
0
 def open_dict_file(self, fn):
     '''Open or create the dict with the given fn.'''
     trace = False and not g.unitTesting
     language = self.language
     if not fn or not language:
         return None
     if g.app.spellDict:
         if trace: g.trace('already open', self.c.fileName(), fn)
         return g.app.spellDict
     if not g.os_path_exists(fn):
         # Fix bug 1175013: leo/plugins/spellpyx.txt is
         # both source controlled and customized.
         self.create(fn)
     if g.os_path_exists(fn):
         # Merge the local and global dictionaries.
         try:
             self.clean_dict(fn)
             d = enchant.DictWithPWL(language, fn)
             if trace: g.trace('open', g.shortFileName(self.c.fileName()), fn)
         except Exception:
             g.es('Error reading dictionary file', fn)
             g.es_exception()
             d = enchant.Dict(language)
     else:
         # A fallback.  Unlikely to happen.
         d = enchant.Dict(language)
     return d
Пример #56
0
 def readFile(self, fileName, root):
     '''
     Read the file from the cache if possible.
     Return (s,ok,key)
     '''
     trace = (False or g.app.debug) and not g.unitTesting
     showHits, showLines, verbose = False, False, True
     sfn = g.shortFileName(fileName)
     if not g.enableDB:
         if trace and verbose: g.trace('g.enableDB is False', sfn)
         return '', False, None
     s = g.readFileIntoEncodedString(fileName, silent=True)
     if s is None:
         if trace: g.trace('empty file contents', sfn)
         return s, False, None
     assert not g.isUnicode(s)
     if trace and showLines:
         for i, line in enumerate(g.splitLines(s)):
             print('%3d %s' % (i, repr(line)))
     # There will be a bug if s is not already an encoded string.
     key = self.fileKey(root.h, s, requireEncodedString=True)
     ok = self.db and key in self.db
     if ok:
         if trace and showHits: g.trace('cache hit', key[-6:], sfn)
         # Delete the previous tree, regardless of the @<file> type.
         while root.hasChildren():
             root.firstChild().doDelete()
         # Recreate the file from the cache.
         aList = self.db.get(key)
         self.createOutlineFromCacheList(root.v, aList, fileName=fileName)
     elif trace:
         g.trace('cache miss', key[-6:], sfn)
     return s, ok, key
Пример #57
0
 def callback(data=data, kind=kind):
     fn = data.fn
     self.put_log('%s: %s\n' % (kind, g.shortFileName(fn)))
     self.pid = subprocess.Popen(
         command,
         shell=shell,
         stderr=subprocess.PIPE,
         stdout=subprocess.PIPE,
         universal_newlines=True,
     )
Пример #58
0
 def destroy_external_file(self, ef):
     '''Destroy the file corresponding to the given ExternalFile instance.'''
     trace = False and not g.unitTesting
     # Do not use g.trace here.
     if ef.path and g.os_path_exists(ef.path):
         try:
             os.remove(ef.path)
             if trace:
                 print("deleting temp file: %s" % g.shortFileName(ef.path))
         except Exception:
             if trace:
                 print("can not delete temp file: %s" % ef.path)
Пример #59
0
 def has_changed(self, c, path):
     '''Return True if p's external file has changed outside of Leo.'''
     trace = False and not g.unitTesting
     verbose_init = False
     tag = 'efc.has_changed'
     if not g.os_path_exists(path):
         if trace: print('%s:does not exist %s' % (tag, path))
         return False
     if g.os_path_isdir(path):
         if trace: print('%s: %s is a directory' % (tag, path))
         return False
     fn = g.shortFileName(path)
     # First, check the modification times.
     old_time = self.get_time(path)
     new_time = self.get_mtime(path)
     if not old_time:
         # Initialize.
         self.set_time(path, new_time)
         self.checksum_d[path] = checksum = self.checksum(path)
         if trace and verbose_init:
             print('%s:init %s %s %s' % (tag, checksum, c.shortFileName(), path))
         elif trace:
             # Only print one message per commander.
             d = self.has_changed_d
             val = d.get(c)
             if not val:
                 d[c] = True
                 print('%s:init %s' % (tag, c.shortFileName()))
         return False
     if old_time == new_time:
         # print('%s:times match %s %s' % (tag,c.shortFileName(),path))
         return False
     # Check the checksums *only* if the mod times don't match.
     old_sum = self.checksum_d.get(path)
     new_sum = self.checksum(path)
     if new_sum == old_sum:
         # The modtime changed, but it's contents didn't.
         # Update the time, so we don't keep checking the checksums.
         # Return False so we don't prompt the user for an update.
         if trace: print('%s:unchanged %s %s' % (tag, old_time, new_time))
         self.set_time(path, new_time)
         return False
     else:
         # The file has really changed.
         if trace: print('%s:changed %s %s %s' % (tag, old_sum, new_sum, fn))
         assert old_time, path
         if 0: # Fix bug 208: external change overwrite protection only works once
             # https://github.com/leo-editor/leo-editor/issues/208
             # These next two lines mean that if the Leo version
             # is changed (dirtied) again, overwrite will occur without warning.
             self.set_time(path, new_time)
             self.checksum_d[path] = new_sum
         return True