def fastAddLastChild(self, parent_v, gnxString): ''' Create new VNode as last child of the receiver. If the gnx exists already, create a clone instead of new VNode. ''' trace = False and not g.unitTesting c = self.c indices = g.app.nodeIndices gnxString = g.toUnicode(gnxString) gnxDict = c.fileCommands.gnxDict if gnxString is None: v = None else: v = gnxDict.get(gnxString) is_clone = v is not None if trace: g.trace( 'clone', '%-5s' % (is_clone), 'parent_v', parent_v, 'gnx', gnxString, 'v', repr(v)) if is_clone: pass else: if gnxString: assert g.isUnicode(gnxString) v = leoNodes.VNode(context=c, gnx=gnxString) if g.trace_gnxDict: g.trace(c.shortFileName(), gnxString, v) else: v = leoNodes.VNode(context=c) # This is not an error: it can happen with @auto nodes. # g.trace('**** no gnx for',v,parent_v) child_v = v child_v._linkAsNthChild(parent_v, parent_v.numberOfChildren()) child_v.setVisited() # Supress warning/deletion of unvisited nodes. return is_clone, child_v
def connect (self,fname): '''Connect to the server. Return True if the connection was established.''' trace = False and not g.unitTesting if trace: g.trace(fname,socket) if hasattr(socket,'AF_UNIX'): try: # pylint: disable=E1101 # E1101:LProtoClient.connect: Module 'socket' has no 'AF_UNIX' member self.socket = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) self.socket.connect(fname) return True except Exception: g.es_print('lproto.py: failed to connect!',fname) g.es_exception(full=False,c=None) return False else: try: host = '172.16.0.0' # host is a local address. port = 1 self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) self.socket.connect((host,port),) self.socket.connect(fname) return True except Exception: g.es_print('lproto.py: failed to connect! host: %s, port: %s' % ( host,port)) g.es_exception(full=False,c=None) return False
def must_update (self,keywords): '''Return True if we must update the rendering pane.''' pc = self c,p = pc.c,pc.c.p if g.unitTesting: return False if keywords.get('force'): pc.active = True if trace: g.trace('force: activating') return True if c != keywords.get('c') or not pc.active: if trace: g.trace('not active') return False if pc.locked: if trace: g.trace('locked') return False if pc.gnx != p.v.gnx: if trace: g.trace('changed node') return True if len(p.b) != pc.length: if trace: g.trace('text changed') return True # This will be called at idle time. # if trace: g.trace('no change') return False
def reportChangedClone(self, child_v, b, h, gnx): trace = (False or g.app.debug) and not g.unitTesting c = self.c fileName = c.cacheListFileName old, new = child_v.b, b same = ( old == new or new.endswith('\n') and old == new[: -1] or old.endswith('\n') and new == old[: -1]) # if trace and not same: if trace and (not same or h == 'writeException'): g.trace('same %s old %s new %s %s %s' % ( same, len(old), len(new), h, fileName)) # This would make it impossible to clear nodes! # if not new: return same if same: return c.nodeConflictList.append(g.bunch( tag='(cached)', fileName=fileName, gnx=gnx, b_old=child_v.b, h_old=child_v.h, b_new=b, h_new=h, )) # Always issue the warning. g.error("cached read node changed:", child_v.h) child_v.h, child_v.b = h, b child_v.setDirty() c.changed = True # Tell getLeoFile to propegate dirty nodes.
def update_graphics_script (self,s,keywords): '''Update the graphics script in the vr pane.''' pc = self ; c = pc.c force = keywords.get('force') if pc.gs and not force: return if not pc.gs: splitter = c.free_layout.get_top_splitter() # Careful: we may be unit testing. if not splitter: g.trace('no splitter') return # Create the widgets. pc.gs = QtWidgets.QGraphicsScene(splitter) pc.gv = QtWidgets.QGraphicsView(pc.gs) w = pc.gv.viewport() # A QWidget # Embed the widgets. def delete_callback(): for w in (pc.gs,pc.gv): w.deleteLater() pc.gs = pc.gv = None pc.embed_widget(w,delete_callback=delete_callback) c.executeScript( script=s, namespace={'gs':pc.gs,'gv':pc.gv})
def next_place(self, s, offset=0): """ Given string s containing a placeholder like <| block |>, return (s2,start,end) where s2 is s without the <| and |>, and start, end are the positions of the beginning and end of block. """ trace = False c = self.c new_pos = s.find(c.abbrev_place_start, offset) new_end = s.find(c.abbrev_place_end, offset) if (new_pos < 0 or new_end < 0) and offset: new_pos = s.find(c.abbrev_place_start) new_end = s.find(c.abbrev_place_end) if not (new_pos < 0 or new_end < 0): g.es("Found placeholder earlier in body") if new_pos < 0 or new_end < 0: if trace: g.trace('new_pos', new_pos, 'new_end', new_end) return s, None, None start = new_pos place_holder_delim = s[new_pos: new_end + len(c.abbrev_place_end)] place_holder = place_holder_delim[ len(c.abbrev_place_start): -len(c.abbrev_place_end)] s2 = s[: start] + place_holder + s[start + len(place_holder_delim):] end = start + len(place_holder) if trace: g.trace(start, end, g.callers()) return s2, start, end
def viewrendered(event): """Open render view for commander""" c = event.get('c') if not c: return None global controllers vr = controllers.get(c.hash()) if vr: if trace: g.trace('** controller exists: %s' % (vr)) vr.show() else: controllers[c.hash()] = vr = ViewRenderedController(c) if trace: g.trace('** new controller: %s' % (vr)) if hasattr(c,'free_layout'): vr._ns_id = '_leo_viewrendered' # for free_layout load/save splitter = c.free_layout.get_top_splitter() # Careful: we may be unit testing. if splitter: ok = splitter.add_adjacent(vr,'bodyFrame','right-of') if not ok: splitter.insert(0, vr) else: vr.setWindowTitle("Rendered View") vr.resize(600, 600) vr.show() c.bodyWantsFocusNow() # The following conflicts with F11: help-for-command. # I'm not sure why it was needed, but for sure it can not be used. # def at_idle(c=c): # c.bodyWantsFocusNow() # QtCore.QTimer.singleShot(0,at_idle) return vr
def find_parent(self, level, h): ''' Return the parent at the indicated level, allocating place-holder nodes as necessary. ''' assert level >= 0 while level < len(self.stack): self.stack.pop() top = self.stack[-1] if 1: # Experimental fix for #877. if level > len(self.stack): print('') g.trace('Unexpected markdown level for: %s' % h) print('') while level > len(self.stack): child = self.create_child_node( parent = top, body = None, headline = 'INSERTED NODE' ) self.stack.append(child) assert level == len(self.stack), (level, len(self.stack)) child = self.create_child_node( parent = top, body = None, headline = h, # Leave the headline alone ) self.stack.append(child) assert self.stack assert 0 <= level < len(self.stack), (level, len(self.stack)) return self.stack[level]
def redraw(self): "redraw after menu used" g.trace(g.callers()) # IMPORTANT ASSUMPTION: called only after menu used # read updates from menu choice # Tk seems to use menu label when '' is used as value? # note, keys not present if coming via clear_all if self.pickles.has_key('node'): if self.pickles['node'].get() == 'CLEO_BLANK': self.pickles['node'].set('') if self.pickles.has_key('archetype'): if self.pickles['archetype'].get() == 'CLEO_BLANK': self.pickles['archetype'].set('') for ky, vl in self.pickles.iteritems(): self.setat(self.pickleV, ky, vl.get()) self.loadIcons(self.pickleP) self.clear_marks(self.c.frame.tree.canvas) self.update_project(self.pickleP) c = self.c c.setChanged(True) c.redraw_now()
def put_sentinels(self,i): '''Put all the sentinels to the results''' x = self if 0 <= i < len(x.sentinels): sentinels = x.sentinels[i] if x.trace: g.trace('%3s %s' % (i,sentinels)) x.results.extend(sentinels)
def skip_possible_regex(self, s, i): '''look ahead for a regex /''' trace = False and not g.unitTesting if trace: g.trace(repr(s)) assert s[i] in '=(', repr(s[i]) i += 1 while i < len(s) and s[i] in ' \t': i += 1 if i < len(s) and s[i] == '/': i += 1 while i < len(s): progress = i ch = s[i] # g.trace(repr(ch)) if ch == '\\': i += 2 elif ch == '/': i += 1 break else: i += 1 assert progress < i if trace: g.trace('returns', i, s[i] if i < len(s) else '') return i-1
def parse_body(self,p): body = self.untangle(p) # body is the script in p's body. # print("Body") # print(body) if self.trace and self.verbose: g.trace('pass1',p.h,'\n',body) self.d ['p'] = p.copy() backop = None segs = re.finditer('^(@x (.*))$',body,re.MULTILINE) for mo in segs: op = mo.group(2).strip() # print("Oper",op) if op.startswith('='): # print("Assign", op) backop = ('=', op.rstrip('{').lstrip('='), mo.end(1)) elif op == '{': backop = ('runblock', mo.end(1)) elif op == '}': bo = backop[0] # print("backop",bo) if bo == '=': self.let_body(backop[1].strip(), body[backop[2] : mo.start(1)]) elif bo == 'runblock': self.runblock(body[backop[1] : mo.start(1)]) else: self.runblock(op)
def propagate_changed_lines(self,new_public_lines,old_private_lines,marker,p=None): #@+<< docstring >> #@+node:ekr.20150207044400.9: *5* << docstring >> ''' The Mulder update algorithm, revised by EKR. Use the diff between the old and new public lines to insperse sentinels from old_private_lines into the result. The algorithm never deletes or rearranges sentinels. However, verbatim sentinels may be inserted or deleted as needed. ''' #@-<< docstring >> x = self trace = (False or x.trace) and g.unitTesting x.init_ivars(new_public_lines,old_private_lines,marker) sm = difflib.SequenceMatcher(None,x.a,x.b) if trace: x.dump_args() # Ensure leading sentinels are put first. x.put_sentinels(0) x.sentinels[0] = [] for tag,ai,aj,bi,bj in sm.get_opcodes(): if trace: g.trace('%3s %s' % (ai,tag)) f = x.dispatch_dict.get(tag,x.op_bad) f(tag,ai,aj,bi,bj) # Put the trailing sentinels & check the result. x.results.extend(x.trailing_sentinels) # check_output is likely to be more buggy than the code under test. # x.check_output() if trace: x.dump_lines(x.results,'results') return x.results
def starts_block(self, i, lines, new_state, prev_state, stack): '''True if the line startswith class or def outside any context.''' # pylint: disable=arguments-differ trace = False and not g.unitTesting if prev_state.in_context(): return False line = lines[i] m = self.starts_pattern.match(line) if not m: return False top = stack[-1] prev_indent = top.state.indent if top.kind == 'None' and new_state.indent > 0: # Underindented top-level class/def. return False elif top.kind == 'def' and new_state.indent > prev_indent: # class/def within a def. return False elif top.at_others_flag and new_state.indent > prev_indent: return False else: if trace and new_state.indent > prev_indent: g.trace(prev_indent, new_state.indent, repr(line)) g.trace('@others', top.at_others_flag) return True
def skip_block(self, i, index, lines, prev_state, stack): ''' Find the end of a class/def starting at index on line i of lines. Return (kind, i, j), where kind in (None, 'class', 'def') .''' trace = True and not g.unitTesting index1 = index line = lines[i] kind = 'class' if line.strip().startswith('class') else 'def' i += 1 while i < len(lines): progress = i line = lines[i] index += len(line) new_state = self.scan_line(line, prev_state) top = stack[-1] if trace: g.trace('new level', new_state.level(), 'line', line) # Similar to self.ends_block. if (not self.is_ws_line(line) and not prev_state.in_context() and new_state.level() <= top.state.level() ): return kind, index1, index prev_state = new_state i += 1 assert progress < i return None, -1, -1
def split(self,index,side,w=None,name=None): """replace the adjacent widget with a NestedSplitter containing the widget and an Action button""" trace = False and g and not g.unitTesting sizes = self.sizes() old = self.widget(index+side-1) #X old_name = old and old.objectName() or '<no name>' #X splitter_name = self.objectName() or '<no name>' if w is None: w = NestedSplitterChoice(self) if isinstance(old, NestedSplitter): old.addWidget(w) old.equalize_sizes() #X index = old.indexOf(w) #X return old,index # For viewrendered plugin. else: orientation = self.other_orientation[self.orientation()] new = NestedSplitter(self, orientation=orientation, root=self.root) #X if name: new.setObjectName(name) self.insertWidget(index+side-1, new) new.addWidget(old) new.addWidget(w) new.equalize_sizes() #X index = new.indexOf(w) #X return new,index # For viewrendered plugin. if trace: g.trace('name: %s index: %s side: %s w: %s' % ( name,index,side,w)) self.setSizes(sizes)
def unhide(self, all=False): trace = False and not g.unitTesting c = self.c w = c.frame.body.widget cursor = w.textCursor() cfmt = cursor.charFormat() if cfmt.fontPointSize() == self.pts or all: if trace: g.trace() if all: cursor.setPosition(0) cursor.setPosition(len(w.toPlainText()), cursor.KeepAnchor) else: end = cursor.position() # move left to find left end of range while ( cursor.movePosition(cursor.PreviousCharacter) and cursor.charFormat().fontPointSize() == self.pts ): pass start = cursor.position() # move right to find left end of range cursor.setPosition(end) while ( cursor.movePosition(cursor.NextCharacter) and cursor.charFormat().fontPointSize() == self.pts ): pass # select range and restore normal size cursor.setPosition(start, cursor.KeepAnchor) # Common code. cfmt.setFontPointSize(self.size) cfmt.setFontLetterSpacing(100) cursor.setCharFormat(cfmt)
def check_the_final_output(self, new_private_lines, new_public_lines, sentinel_lines, marker): """ Check that we produced a valid output. Input: new_targetlines: the lines with sentinels which produce changed_lines_without_sentinels. sentinels: new_targetlines should include all the lines from sentinels. checks: 1. new_targetlines without sentinels must equal changed_lines_without_sentinels. 2. the sentinel lines of new_targetlines must match 'sentinels' """ new_public_lines2, new_sentinel_lines2 = self.separate_sentinels( new_private_lines, marker) lines1 = new_public_lines lines2 = new_public_lines2 sents1 = sentinel_lines sents2 = new_sentinel_lines2 if 1: # Ignore trailing ws: s1 = ''.join(lines1).rstrip() s2 = ''.join(lines2).rstrip() lines1 = g.splitLines(s1) lines2 = g.splitLines(s2) if 1: # Ignore trailing ws on every line. lines1 = [z.rstrip() for z in lines1] lines2 = [z.rstrip() for z in lines2] sents1 = [z.rstrip() for z in sents1] sents2 = [z.rstrip() for z in sents2] lines_ok = lines1 == lines2 sents_ok = sents1 == sents2 if g.unitTesting: # The unit test will report the error. return lines_ok and sents_ok if not lines_ok: if 1: g.trace() d = difflib.Differ() # g.trace('Different!!',d) aList = list(d.compare(new_public_lines2,new_public_lines)) pprint.pprint(aList) else: self.show_error( lines1 = new_public_lines2, lines2 = new_public_lines, message = "Error in updating public file!", lines1_message = "new public lines (derived from new private lines)", lines2_message = "new public lines") if not sents_ok: self.show_error( lines1 = sentinel_lines, lines2 = new_sentinel_lines2, message = "Sentinals not preserved!", lines1_message = "old sentinels", lines2_message = "new sentinels") return lines_ok and sents_ok
def callTagHandler (self,bunch,tag,keywords): '''Call the event handler.''' trace = False and not g.unitTesting traceIdle = True handler,moduleName = bunch.fn,bunch.moduleName if trace and (traceIdle or tag != 'idle'): c = keywords.get('c') name = moduleName ; tag2 = 'leo.plugins.' if name.startswith(tag2): name = name[len(tag2):] g.trace('c: %s %23s : %s . %s' % ( c and c.shortFileName() or '<no c>', tag,handler.__name__,name)) # Make sure the new commander exists. for key in ('c','new_c'): c = keywords.get(key) if c: # Make sure c exists and has a frame. if not c.exists or not hasattr(c,'frame'): # g.pr('skipping tag %s: c does not exist or does not have a frame.' % tag) return None # Calls to registerHandler from inside the handler belong to moduleName. self.loadingModuleNameStack.append(moduleName) try: result = handler(tag,keywords) except Exception: g.es("hook failed: %s, %s, %s" % (tag, handler, moduleName)) g.es_exception() result = None self.loadingModuleNameStack.pop() return result
def adjustParent(self, parent, headline): '''Return the proper parent of the new node.''' trace = False and not g.unitTesting level, lastLevel = self.sectionLevel, self.lastSectionLevel lastParent = self.lastParent if trace: g.trace('**entry level: %s lastLevel: %s lastParent: %s' % ( level, lastLevel, lastParent and lastParent.h or '<none>')) if self.lastParent: if level <= lastLevel: parent = lastParent.parent() while level < lastLevel: level += 1 parent = parent.parent() else: # level > lastLevel. level -= 1 parent = lastParent while level > lastLevel: level -= 1 h2 = '@rst-no-head %s' % headline body = '' parent = self.createFunctionNode(h2, body, parent) else: assert self.root self.lastParent = self.root if not parent: parent = self.root if trace: g.trace('level %s lastLevel %s %s returns %s' % ( level, lastLevel, headline, parent.h)) #self.lastSectionLevel = self.sectionLevel self.lastParent = parent.copy() return parent.copy()
def onCreate(tag, keys): '''Create a Tables instance for the outline.''' c = keys.get('c') if c: c.tableController = TableController(c) else: g.trace('can not create TableController')
def dismiss_menu_bar(self): m = self; c = m.c # c.frame.menu.deactivateMenuBar() g.trace() menubar = c.frame.top.leo_menubar menubar.setActiveAction(None) menubar.repaint()
def undent_coffeescript_body(self, s): '''Return the undented body of s.''' trace = False and not g.unitTesting and self.root.h.endswith('1.coffee') lines = g.splitLines(s) if trace: g.trace('='*20) self.print_lines(lines) # Undent all leading whitespace or comment lines. leading_lines = [] for line in lines: if self.is_ws_line(line): # Tricky. Stipping a black line deletes it. leading_lines.append(line if line.isspace() else line.lstrip()) else: break i = len(leading_lines) # Don't unindent the def/class line! It prevents later undents. tail = self.undent_body_lines(lines[i:], ignoreComments=True) # Remove all blank lines from leading lines. if 0: for i, line in enumerate(leading_lines): if not line.isspace(): leading_lines = leading_lines[i:] break result = ''.join(leading_lines) + tail if trace: g.trace('-'*20) self.print_lines(g.splitLines(result)) return result
def selectChapterByName (self,name,collapse=True,create=True): '''Select a chapter. Return True if a redraw is needed.''' trace = False and not g.unitTesting cc,c = self,self.c if type(name) == type(9): return cc.note('PyQt5 chapaters not supported') chapter = cc.chaptersDict.get(name) if chapter: cc.selectChapterByNameHelper(chapter,collapse=collapse) elif create: # There is an @chapter node, but no actual chapter. if trace: g.trace('*** creating',name) cc.createChapterByName(name,p=c.p,undoType='Create Chapter') else: # create is False if called from the minibuffer. # do nothing if the user mis-types. cc.note('no such chapter: %s' % name) chapter = cc.chaptersDict.get('main') if chapter: self.selectChapterByNameHelper(chapter,collapse=collapse) else: g.trace(g.callers()) cc.error('no main chapter!')
def post_pass(self, parent): '''Massage the created nodes.''' trace = False and not g.unitTesting and self.root.h.endswith('1.coffee') if trace: g.trace('='*60) for p in parent.self_and_subtree(): print('***** %s' % p.h) g.printList(p.v._import_lines) # ===== Generic: use base Importer methods ===== self.clean_all_headlines(parent) self.clean_all_nodes(parent) # ===== Specific to coffeescript ===== # self.move_trailing_lines(parent) # ===== Generic: use base Importer methods ===== self.unindent_all_nodes(parent) # # This sub-pass must follow unindent_all_nodes. self.promote_trailing_underindented_lines(parent) # # This probably should be the last sub-pass. self.delete_all_empty_nodes(parent) if trace: g.trace('-'*60) for p in parent.self_and_subtree(): print('***** %s' % p.h) g.printList(p.v._import_lines)
def get(self, key, default=None): trace = False and g.unitTesting if trace: g.trace('(PickleShareDB)') try: return self[key] except KeyError: return default
def load_states(self): if not self.c.db: return try: stored = self.c.db['tabulanotes'] except KeyError: return mwstate = stored.pop("mainwindow") self.restoreState(mwstate) # still think leo should maintain a dict like this. # EKR: :-) ncache = dict((p.gnx, p.copy()) for p in self.c.all_unique_positions()) for gnx, geom in stored.items(): try: ncache[gnx] except KeyError: g.trace("lost note", gnx) continue n = self.add_note(ncache[gnx]) n.parent().restoreGeometry(geom)
def readFile(self, fileName): '''Read the opml file.''' dumpTree = False if not fileName: return g.trace('no fileName') c = self.c.new() # Create the new commander *now* # so that created vnodes will have the proper context. # Pass one: create the intermediate nodes. dummyRoot = self.parse_opml_file(fileName) if not dummyRoot: return if dumpTree: self.dumpTree(dummyRoot) # Pass two: create the outline from the sax nodes. children = self.createVnodes(c, dummyRoot) p = leoNodes.Position(v=children[0], childIndex=0, stack=None) # Check the outline. errors = c.checkOutline() if errors: c.dumpOutline() return g.trace('%s errors!' % errors) # if self.opml_read_derived_files: # at = c.atFileCommands # c.fileCommands.tnodesDict = self.createTnodesDict() # self.resolveTnodeLists(c) # if self.opml_read_derived_files: # c.atFileCommands.readAll(c.rootPosition()) c.selectPosition(p) c.redraw() return c # for testing.
def __init__(self, root): """ Init the PickleShareDB class. root: The directory that contains the data. Created if it doesn't exist. """ trace = False and not g.unitTesting self.root = abspath(expanduser(root)) if trace: g.trace('PickleShareDB', self.root) if not isdir(self.root) and not g.unitTesting: self._makedirs(self.root) self.cache = {} # Keys are normalized file names. # Values are tuples (obj, orig_mod_time) def loadz(fileobj): if fileobj: val = pickle.loads( zlib.decompress(fileobj.read())) return val else: return None def dumpz(val, fileobj): if fileobj: compressed = zlib.compress(pickle.dumps( val, pickle.HIGHEST_PROTOCOL)) fileobj.write(compressed) self.loader = loadz self.dumper = dumpz
def image(self, pane, fn, center=None, height=None, width=None): '''Put an image in the indicated pane.''' m = self parent = m.pane_widget(pane) if parent: w = QtGui.QLabel('label', parent) fn = m.resolve_icon_fn(fn) if not fn: return None pixmap = QtGui.QPixmap(fn) if not pixmap: return g.trace('Not a pixmap: %s' % (fn)) if height: pixmap = pixmap.scaledToHeight(height) if width: pixmap = pixmap.scaledToWidth(width) w.setPixmap(pixmap) if center: g_w = w.geometry() g_p = parent.geometry() dx = (g_p.width() - g_w.width()) / 2 w.move(g_w.x() + dx, g_w.y() + 10) w.show() m.widgets.append(w) return w else: g.trace('bad pane: %s' % (pane)) return None
def expandAbbrev(self, event, stroke): ''' Not a command. Called from k.masterCommand to expand abbreviations in event.widget. Words start with '@'. ''' trace = False and not g.unitTesting verbose = True c, p = self.c, self.c.p w = self.editWidget(event, forceFocus=False) w_name = g.app.gui.widget_name(w) if not w: return False ch = self.get_ch(event, stroke, w) if not ch: return False if trace and verbose: g.trace('ch: %5r stroke.s: %12r w: %s %s %s' % ( ch, stroke and stroke.s, id(w), w_name , p.h)) s, i, j, prefixes = self.get_prefixes(w) for prefix in prefixes: i, tag, word, val = self.match_prefix(ch, i, j, prefix, s) if word: # Fix another part of #438. if w_name.startswith('head'): if val == '__NEXT_PLACEHOLDER': i = w.getInsertPoint() if i > 0: w.delete(i-1) p.h = w.getAllText() # Do not call c.endEditing here. if trace: g.trace('FOUND tag: %r word: %r' % (tag, word)) break else: return False # 448: Add abbreviations for commands. if 0: # This is not worth documenting. val, tag = self.abbrevs.get(word, (None, None)) if val and c.k.commandExists(val): if trace: g.trace(word, '==>', val) # Execute the command directly, so as not to call this method recursively. commandName = val func = c.commandsDict.get(commandName) c.doCommand(func, commandName, event) return c.abbrev_subst_env['_abr'] = word if tag == 'tree': self.root = p.copy() self.last_hit = p.copy() self.expand_tree(w, i, j, val, word) else: # Never expand a search for text matches. place_holder = '__NEXT_PLACEHOLDER' in val if place_holder: expand_search = bool(self.last_hit) else: self.last_hit = None expand_search = False if trace: g.trace('expand_search: %s last_hit: %s' % ( expand_search, self.last_hit and self.last_hit.h)) self.expand_text(w, i, j, val, word, expand_search) # Restore the selection range. if self.save_ins: if trace: g.trace('RESTORE sel: %s ins: %s' % ( self.save_sel, self.save_ins)) ins = self.save_ins # pylint: disable=unpacking-non-sequence sel1, sel2 = self.save_sel if sel1 == sel2: # New in Leo 5.5 self.post_pass() else: # some abbreviations *set* the selection range # so only restore non-empty ranges w.setSelectionRange(sel1, sel2, insert=ins) return True
def selectChapterForPosition(self, p, chapter=None): ''' Select a chapter containing position p. New in Leo 4.11: prefer the given chapter if possible. Do nothing if p if p does not exist or is in the presently selected chapter. Note: this code calls c.redraw() if the chapter changes. ''' trace = False and not g.unitTesting c, cc = self.c, self # New in Leo 4.11 if cc.selectChapterLockout: return selChapter = cc.getSelectedChapter() if trace: g.trace('***', p.h, chapter.name if chapter else None, selChapter.name if selChapter else None, g.callers()) if not p: if trace: g.trace('no p') return if not c.positionExists(p): if trace: g.trace('does not exist', p.h) return # New in Leo 4.11: prefer the given chapter if possible. theChapter = chapter or selChapter if not theChapter: return # First, try the presently selected chapter. firstName = theChapter.name if firstName == 'main': if trace: g.trace('no search: main chapter:', p.h) return if theChapter.positionIsInChapter(p): if trace: g.trace('position found in chapter:', theChapter.name, p.h) cc.selectChapterByName(theChapter.name) return for name in cc.chaptersDict: if name not in (firstName, 'main'): theChapter = cc.chaptersDict.get(name) if theChapter.positionIsInChapter(p): if trace: g.trace('select:', theChapter.name) cc.selectChapterByName(name) break else: if trace: g.trace('select main') cc.selectChapterByName('main') # Fix bug 869385: Chapters make the nav_qt.py plugin useless c.redraw_now()
def oops(message): g.trace(message)
def report_version(): try: import flake8 print('flake8 version: %s' % flake8.__version__) except ImportError: g.trace('can not import flake8')
def demo_end(self, event=None, chain=False): '''End the present demo.''' if getattr(g.app, 'demo', None): g.app.demo.end() else: g.trace('no demo instance')
def prev_command(self, event=None, chain=False): '''Run the next demo script.''' if getattr(g.app, 'demo', None): g.app.demo.prev() else: g.trace('no demo instance')
def make_script_substitutions(self, i, j, val): '''Make scripting substitutions in node p.''' trace = False and not g.unitTesting c = self.c if not c.abbrev_subst_start: if trace: g.trace('no subst_start') return val, False # Nothing to undo. if c.abbrev_subst_start not in val: return val, False # Perform all scripting substitutions. self.save_ins = None self.save_sel = None while c.abbrev_subst_start in val: prefix, rest = val.split(c.abbrev_subst_start, 1) content = rest.split(c.abbrev_subst_end, 1) if len(content) != 2: break content, rest = content if trace: g.trace('**c', c.shortFileName()) g.trace('**p', c.p.h) g.trace('**content', repr(content)) try: self.expanding = True c.abbrev_subst_env['x'] = '' exec(content, c.abbrev_subst_env, c.abbrev_subst_env) except Exception: g.es_print('exception evaluating', content) finally: self.expanding = False x = c.abbrev_subst_env.get('x') if x is None: x = '' val = "%s%s%s" % (prefix, x, rest) # Save the selection range. w = c.frame.body.wrapper self.save_ins = w.getInsertPoint() self.save_sel = w.getSelectionRange() if trace: g.trace('sel', self.save_sel, 'ins', self.save_ins) if val == "__NEXT_PLACEHOLDER": # user explicitly called for next placeholder in an abbrev. # inserted previously val = '' do_placeholder = True else: do_placeholder = False # Huh? oldSel = i, j c.frame.body.onBodyChanged(undoType='Typing', oldSel=oldSel) if trace: g.trace(do_placeholder, val) return val, do_placeholder
def open_temp_file(self, c, d, fn, testing=False): ''' Open a temp file corresponding to fn in an external editor. d is a dictionary created from an @openwith settings node. 'args': the command-line arguments to be used to open the file. 'ext': the file extension. 'kind': the method used to open the file, such as subprocess.Popen. 'name': menu label (used only by the menu code). 'shortcut': menu shortcut (used only by the menu code). ''' trace = False and not g.unitTesting testing = testing or g.unitTesting arg_tuple = d.get('args', []) arg = ' '.join(arg_tuple) kind = d.get('kind') try: # All of these must be supported because they # could exist in @open-with nodes. command = '<no command>' if kind == 'os.startfile': command = 'os.startfile(%s)' % self.join(arg, fn) if trace: g.trace(command) # pylint: disable=no-member # trust the user not to use this option on Linux. if not testing: os.startfile(self.join(arg, fn)) elif kind == 'exec': g.es_print('open-with exec no longer valid.') # command = 'exec(%s)' % self.join(arg,fn) # if trace: g.trace(command) # if not testing: # exec(self.join(arg,fn),{},{}) elif kind == 'os.spawnl': filename = g.os_path_basename(arg) command = 'os.spawnl(%s,%s,%s)' % (arg, filename, fn) if trace: g.trace(command) if not testing: os.spawnl(os.P_NOWAIT, arg, filename, fn) elif kind == 'os.spawnv': filename = os.path.basename(arg_tuple[0]) vtuple = arg_tuple[1:] vtuple.insert(0, filename) # add the name of the program as the first argument. # Change suggested by Jim Sizelove. vtuple.append(fn) command = 'os.spawnv(%s)' % (vtuple) if trace: g.trace(command) if not testing: os.spawnv(os.P_NOWAIT, arg[0], vtuple) #??? elif kind == 'subprocess.Popen': c_arg = self.join(arg, fn) command = 'subprocess.Popen(%s)' % c_arg if trace: g.trace(command) if not testing: try: subprocess.Popen(c_arg, shell=True) except OSError: g.es_print('c_arg', repr(c_arg)) g.es_exception() elif g.isCallable(kind): # Invoke openWith like this: # c.openWith(data=[func,None,None]) # func will be called with one arg, the filename if trace: g.trace('%s(%s)' % (kind, fn)) command = '%s(%s)' % (kind, fn) if not testing: kind(fn) else: command = 'bad command:' + str(kind) if not testing: g.trace(command) return command # for unit testing. except Exception: g.es('exception executing open-with command:', command) g.es_exception() return 'oops: %s' % command
def oops(): g.trace('unknown kind', self.kind)
def open_file_in_external_editor(self, c, d, fn, testing=False): """ Open a file fn in an external editor. This will be an entire external file, or a temp file for a single node. d is a dictionary created from an @openwith settings node. 'args': the command-line arguments to be used to open the file. 'ext': the file extension. 'kind': the method used to open the file, such as subprocess.Popen. 'name': menu label (used only by the menu code). 'p': the nearest @<file> node, or None. 'shortcut': menu shortcut (used only by the menu code). """ testing = testing or g.unitTesting arg_tuple = d.get('args', []) arg = ' '.join(arg_tuple) kind = d.get('kind') try: # All of these must be supported because they # could exist in @open-with nodes. command = '<no command>' if kind in ('os.system', 'os.startfile'): # New in Leo 5.7: # Use subProcess.Popen(..., shell=True) c_arg = self.join(arg, fn) if not testing: try: subprocess.Popen(c_arg, shell=True) except OSError: g.es_print('c_arg', repr(c_arg)) g.es_exception() elif kind == 'exec': g.es_print('open-with exec no longer valid.') elif kind == 'os.spawnl': filename = g.os_path_basename(arg) command = f"os.spawnl({arg},{filename},{fn})" if not testing: os.spawnl(os.P_NOWAIT, arg, filename, fn) elif kind == 'os.spawnv': filename = os.path.basename(arg_tuple[0]) vtuple = arg_tuple[1:] # add the name of the program as the first argument. # Change suggested by Jim Sizelove. vtuple.insert(0, filename) vtuple.append(fn) command = f"os.spawnv({vtuple})" if not testing: os.spawnv(os.P_NOWAIT, arg[0], vtuple) #??? elif kind == 'subprocess.Popen': c_arg = self.join(arg, fn) command = f"subprocess.Popen({c_arg})" if not testing: try: subprocess.Popen(c_arg, shell=True) except OSError: g.es_print('c_arg', repr(c_arg)) g.es_exception() elif hasattr(kind, '__call__'): # Invoke openWith like this: # c.openWith(data=[func,None,None]) # func will be called with one arg, the filename command = f"{kind}({fn})" if not testing: kind(fn) else: command = 'bad command:' + str(kind) if not testing: g.trace(command) return command # for unit testing. except Exception: g.es('exception executing open-with command:', command) g.es_exception() return f"oops: {command}"
def createCommonButton(self, p, script, rclicks=None): ''' Create a button in the icon area for a common @button node in an @setting tree. Binds button presses to a callback that executes the script. Important: Common @button and @command scripts now *do* update dynamically provided that myLeoSettings.leo is open. Otherwise the callback executes the static script. See https://github.com/leo-editor/leo-editor/issues/171 ''' trace = False and not g.unitTesting c = self.c if trace: g.trace('global @button IN', c.shortFileName()) g.trace('FROM:', p.gnx, p.v.context.shortFileName(), p.h) gnx = p.gnx args = self.getArgs(p) # Fix bug #74: problems with @button if defined in myLeoSettings.leo docstring = g.getDocString(p.b).strip() statusLine = docstring or 'Global script button' shortcut = self.getShortcut(p.h) # Get the shortcut from the @key field in the headline. if shortcut: statusLine = '%s = %s' % (statusLine.rstrip(), shortcut) # We must define the callback *after* defining b, # so set both command and shortcut to None here. b = self.createIconButton( args=args, text=p.h, command=None, statusLine=statusLine, kind='at-button', ) if not b: return # Now that b is defined we can define the callback. # Yes, the callback *does* use b (to delete b if requested by the script). buttonText = self.cleanButtonText(p.h) cb = AtButtonCallback( b=b, buttonText=buttonText, c=c, controller=self, docstring=docstring, gnx=gnx, # tag:#367: the gnx is needed for the Goto Script command. # 2018/03/13: Use gnx to search myLeoSettings.leo if it is open. script=script, ) # Now patch the button. self.iconBar.setCommandForButton( button=b, command=cb, # This encapsulates the script. command_p=p and p.copy(), # tag:#567 controller=self, gnx=gnx, # For the find-button function. script=script, ) self.handleRclicks(rclicks) # At last we can define the command. self.registerAllCommands(args=args, func=cb, h=p.h, pane='button', source_c=p.v.context, tag='@button')
def init(): '''Return True if the plugin has loaded successfully.''' g.trace('pyplot_backend.py is not a plugin.') return False
def find_script(self): trace = False and not g.unitTesting gnx = self.gnx # First, search self.c for the gnx. if trace: g.trace('searching %s for %s' % (self.c.shortFileName(), gnx)) for p in self.c.all_positions(): if p.gnx == gnx: script = self.controller.getScript(p) if trace: g.trace('FOUND', len(script or '')) return script # See if myLeoSettings.leo is open. for c in g.app.commanders(): if c.shortFileName().endswith('myLeoSettings.leo'): break else: c = None if trace: g.trace('myLeoSettings.leo is not open') if c: # Search myLeoSettings.leo file for the gnx. if trace: g.trace('searching %s for %s' % (c.shortFileName(), gnx)) for p in c.all_positions(): if p.gnx == gnx: script = self.controller.getScript(p) if trace: g.trace('FOUND', len(script or '')) return script if trace: g.trace('can not find gnx: %s in %s' % (gnx, c.shortFileName())) if trace: g.trace('Using STATIC script: length: %s' % len(self.script or '')) # g.printObj(g.splitLines(self.script or '')) return self.script
def test_beautifier(c, h, p, settings): '''Test Leo's beautifier code''' if not p: g.trace('not found: %s' % h) return s = g.getScript(c, p, useSelectedText=False, forcePythonSentinels=True, useSentinels=False) g.trace(h.strip()) t1 = time.time() s1 = g.toEncodedString(s) node1 = ast.parse(s1, filename='before', mode='exec') t2 = time.time() readlines = g.ReadLinesClass(s).next tokens = list(tokenize.generate_tokens(readlines)) t3 = time.time() beautifier = PythonTokenBeautifier(c) keep_blank_lines = settings.get('tidy-keep-blank-lines') if keep_blank_lines is not None: beautifier.delete_blank_lines = not keep_blank_lines s2 = beautifier.run(tokens) t4 = time.time() try: s2_e = g.toEncodedString(s2) node2 = ast.parse(s2_e, filename='before', mode='exec') ok = compare_ast(node1, node2) except Exception: g.es_exception() ok = False t5 = time.time() # Update the stats beautifier.n_input_tokens += len(tokens) beautifier.n_output_tokens += len(beautifier.code_list) beautifier.n_strings += len(s2) beautifier.parse_time += (t2 - t1) beautifier.tokenize_time += (t3 - t2) beautifier.beautify_time += (t4 - t3) beautifier.check_time += (t5 - t4) beautifier.total_time += (t5 - t1) if settings.get('input_string'): print('==================== input_string') for i, z in enumerate(g.splitLines(s)): print('%4s %s' % (i + 1, z.rstrip())) if settings.get('input_lines'): print('==================== input_lines') dump_tokens(tokens, verbose=False) if settings.get('input_tokens'): print('==================== input_tokens') dump_tokens(tokens, verbose=True) if settings.get('output_tokens'): print('==================== code_list') for i, z in enumerate(beautifier.code_list): print('%4s %s' % (i, z)) if settings.get('output_string'): print('==================== output_string') for i, z in enumerate(g.splitLines(s2)): if z == '\n': print('%4s' % (i + 1)) elif z.rstrip(): print('%4s %s' % (i + 1, z.rstrip())) else: print('%4s %r' % (i + 1, str(z))) if settings.get('stats'): beautifier.print_stats() if not ok: print('*************** fail: %s ***************' % (h)) return beautifier
def __iter__(self): trace = False and g.unitTesting if trace: g.trace('(PickleShareDB)', list(self.keys())) for k in list(self.keys()): yield k
def runDebugScriptCommand(self, event=None): '''Called when user presses the 'debug-script' button or executes the debug-script command.''' c = self.c p = c.p script = g.getScript(c, p, useSelectedText=True, useSentinels=False) if script: #@+<< set debugging if debugger is active >> #@+node:ekr.20060523084441: *5* << set debugging if debugger is active >> g.trace(self.debuggerKind) if self.debuggerKind == 'winpdb': try: import rpdb2 debugging = rpdb2.g_debugger is not None except ImportError: debugging = False elif self.debuggerKind == 'idle': # import idlelib.Debugger.py as Debugger # debugging = Debugger.interacting debugging = True else: debugging = False #@-<< set debugging if debugger is active >> if debugging: #@+<< create leoScriptModule >> #@+node:ekr.20060524073716: *5* << create leoScriptModule >> (mod_scripting.py) target = g.os_path_join(g.app.loadDir, 'leoScriptModule.py') f = None try: f = open(target, 'w') f.write('# A module holding the script to be debugged.\n') if self.debuggerKind == 'idle': # This works, but uses the lame pdb debugger. f.write('import pdb\n') f.write('pdb.set_trace() # Hard breakpoint.\n') elif self.debuggerKind == 'winpdb': f.write('import rpdb2\n') f.write( 'if rpdb2.g_debugger is not None: # don\'t hang if the debugger isn\'t running.\n' ) f.write( ' rpdb2.start_embedded_debugger(pwd="",fAllowUnencrypted=True) # Hard breakpoint.\n' ) # f.write('# Remove all previous variables.\n') f.write('# Predefine c, g and p.\n') f.write('import leo.core.leoGlobals as g\n') f.write('c = g.app.scriptDict.get("c")\n') f.write( 'script_gnx = g.app.scriptDict.get("script_gnx")\n') f.write('p = c.p\n') f.write('# Actual script starts here.\n') f.write(script + '\n') finally: if f: f.close() #@-<< create leoScriptModule >> # pylint: disable=no-name-in-module g.app.scriptDict['c'] = c g.app.scriptDict = {'script_gnx': p.gnx} if 'leoScriptModule' in sys.modules.keys(): del sys.modules['leoScriptModule'] # Essential. import leo.core.leoScriptModule as leoScriptModule assert leoScriptModule # for pyflakes. else: g.error('No debugger active') c.bodyWantsFocus()
def trace(self): if self.tracing: g.trace("%10s: %s" % (self.name, repr(g.toEncodedString(self.val))))
def _makedirs(self, fn, mode=0o777): trace = False and not g.unitTesting if trace: g.trace(self.root) os.makedirs(fn, mode)
def endElementNS(self, name, qname): g.trace(name)
def __contains__(self, key): trace = False and g.unitTesting if trace: g.trace('(PickleShareDB)', key) return self.has_key(key) # NOQA
def skippedEntity(self, name): g.trace(name)
def save(self, event=None, fileName=None): """Save a Leo outline to a file.""" if False and g.app.gui.guiName() == 'curses': g.trace('===== Save disabled in curses gui =====') return c = self p = c.p # Do this now: w may go away. w = g.app.gui.get_focus(c) inBody = g.app.gui.widget_name(w).startswith('body') if inBody: p.saveCursorAndScroll() if g.unitTesting and g.app.unitTestDict.get('init_error_dialogs') is not None: # A kludge for unit testing: # indicated that c.init_error_dialogs and c.raise_error_dialogs # will be called below, *without* actually saving the .leo file. c.init_error_dialogs() c.raise_error_dialogs(kind='write') return if g.app.disableSave: g.es("save commands disabled", color="purple") return c.init_error_dialogs() # 2013/09/28: use the fileName keyword argument if given. # This supports the leoBridge. # Make sure we never pass None to the ctor. if fileName: c.frame.title = g.computeWindowTitle(fileName) c.mFileName = fileName if not c.mFileName: c.frame.title = "" c.mFileName = "" if c.mFileName: # Calls c.setChanged(False) if no error. g.app.syntax_error_files = [] c.fileCommands.save(c.mFileName) c.syntaxErrorDialog() else: root = c.rootPosition() if not root.next() and root.isAtEditNode(): # There is only a single @edit node in the outline. # A hack to allow "quick edit" of non-Leo files. # See https://bugs.launchpad.net/leo-editor/+bug/381527 fileName = None # Write the @edit node if needed. if root.isDirty(): c.atFileCommands.writeOneAtEditNode(root) c.setChanged(False) else: fileName = ''.join(c.k.givenArgs) if not fileName: fileName = g.app.gui.runSaveFileDialog(c, initialfile=c.mFileName, title="Save", filetypes=[("Leo files", "*.leo *.db"),], defaultextension=g.defaultLeoFileExtension(c)) c.bringToFront() if fileName: # Don't change mFileName until the dialog has suceeded. c.mFileName = g.ensure_extension(fileName, g.defaultLeoFileExtension(c)) c.frame.title = c.computeWindowTitle(c.mFileName) c.frame.setTitle(c.computeWindowTitle(c.mFileName)) # 2013/08/04: use c.computeWindowTitle. c.openDirectory = c.frame.openDirectory = g.os_path_dirname(c.mFileName) # Bug fix in 4.4b2. if g.app.qt_use_tabs and hasattr(c.frame, 'top'): c.frame.top.leo_master.setTabName(c, c.mFileName) c.fileCommands.save(c.mFileName) g.app.recentFilesManager.updateRecentFiles(c.mFileName) g.chdir(c.mFileName) # Done in FileCommands.save. # c.redraw_after_icons_changed() c.raise_error_dialogs(kind='write') # *Safely* restore focus, without using the old w directly. if inBody: c.bodyWantsFocus() p.restoreCursorAndScroll() else: c.treeWantsFocus()
def ignorableWhitespace(self, content): g.trace()
def startElementNS(self, name, qname, attrs): g.trace(name)
def get_new_dict(self, context): ''' Return a *general* state dictionary for the given context. Subclasses may override... ''' trace = False and g.unitTesting comment, block1, block2 = self.single_comment, self.block1, self.block2 def add_key(d, key, data): aList = d.get(key, []) aList.append(data) d[key] = aList if context: d = { # key kind pattern ends? '\\': [ ('len+1', '\\', None), ], '#': [ ('len', '###', context == '###'), ], '"': [ ('len', '"', context == '"'), ], "'": [ ('len', "'", context == "'"), ], } if block1 and block2: add_key(d, block2[0], ('len', block1, True)) else: # Not in any context. d = { # key kind pattern new-ctx deltas '\\': [ ('len+1', '\\', context, None), ], '#': [ ('len', '###', '###', None), ], # Docstring '"': [ ('len', '"', '"', None), ], "'": [ ('len', "'", "'", None), ], '{': [ ('len', '{', context, (1, 0, 0)), ], '}': [ ('len', '}', context, (-1, 0, 0)), ], '(': [ ('len', '(', context, (0, 1, 0)), ], ')': [ ('len', ')', context, (0, -1, 0)), ], '[': [ ('len', '[', context, (0, 0, 1)), ], ']': [ ('len', ']', context, (0, 0, -1)), ], } if comment: add_key(d, comment[0], ('all', comment, '', None)) if block1 and block2: add_key(d, block1[0], ('len', block1, block1, None)) if trace: g.trace('created %s dict for %r state ' % (self.name, context)) return d
def processingInstruction(self, target, data): g.trace()
def unselect(self): '''Remember chapter info when a chapter is about to be unselected.''' trace = False and not g.unitTesting c = self.c # Always try to return to the same position. if trace: g.trace('======================', self) # g.trace('main', self.cc.getChapter('main')) self.p = c.p if self.name == 'main': if trace: g.trace(self) return root = None while c.hoistStack: bunch = c.hoistStack.pop() root = bunch.p if root == self.root: if trace: g.trace('found', root.h) break if trace and not root: # Not serious. Can be caused by a user de-hoist. g.trace('error unselecting', self) # Re-institute the previous hoist. if c.hoistStack: p = c.hoistStack[-1].p if trace: g.trace('re-hoist', p.h, c.positionExists(p)) # Careful: c.selectPosition would pop the hoist stack. c.setCurrentPosition(p) else: if trace: g.trace('empty hoist-stack') p = root or c.p c.setCurrentPosition(p) if trace: g.trace(c.hoistStack)
def must_update(self, keywords): '''Return True if we must update the rendering pane.''' pc = self c, p = pc.c, pc.c.p if g.unitTesting: return False if keywords.get('force'): pc.active = True if trace: g.trace('force: activating', p.h) return True if c != keywords.get('c') or not pc.active: if trace: g.trace('not active', p.h) return False if pc.locked: if trace: g.trace('locked', p.h) return False if pc.gnx != p.v.gnx: if trace: g.trace('changed node', p.h) return True if len(p.b) != pc.length: if pc.get_kind(p) in ('html', 'pyplot'): if trace: g.trace('html or pyplot text changed', p.h) pc.length = len(p.b) return False # Only update explicitly. else: if trace: g.trace('text changed', p.h) return True # This will be called at idle time. # if trace: g.trace('no change') return False
def findPositionInChapter(self, p1, strict=False): '''Return a valid position p such that p.v == v.''' trace = False and not g.unitTesting verbose = False c, name = self.c, self.name # Bug fix: 2012/05/24: Search without root arg in the main chapter. if name == 'main' and c.positionExists(p1): return p1 if not p1: if trace and verbose: g.trace('no p1', self) return None root = self.findRootNode() if not root: if trace: g.trace('no root:', self) return None if c.positionExists(p1, root=root.copy()): if trace and verbose: g.trace('found', p1.h, 'in', self) return p1 if strict: if trace: g.trace('strict test fails', p1.h, 'in', self) return None if name == 'main': theIter = c.all_unique_positions else: theIter = root.self_and_subtree for p in theIter(): if p.v == p1.v: if trace: g.trace('found vnode', p1.h, 'in', self) return p.copy() if trace: g.trace('not found', p1.h, 'in', self) return None
def cut_stack(self, new_state, stack): '''Cut back the stack until stack[-1] matches new_state.''' trace = False and g.unitTesting if trace: g.trace(new_state) g.printList(stack) assert len(stack) > 1 # Fail on entry. while stack: top_state = stack[-1].state if new_state.level() < top_state.level(): if trace: g.trace('new_state < top_state', top_state) assert len(stack) > 1, stack # < stack.pop() elif top_state.level() == new_state.level(): if trace: g.trace('new_state == top_state', top_state) assert len(stack) > 1, stack # == stack.pop() break else: # This happens often in valid coffescript programs. if trace: g.trace('new_state > top_state', top_state) break # Restore the guard entry if necessary. if len(stack) == 1: if trace: g.trace('RECOPY:', stack) stack.append(stack[-1]) assert len(stack) > 1 # Fail on exit. if trace: g.trace('new target.p:', stack[-1].p.h)