Beispiel #1
0
def normalize_tags(contents, is_stable_tag=lambda tag: False):
    """Normalize open and close tags to ensure proper nesting
       This is especially useful for saving to HTML

       is_stable_tag -- a function that returns True iff a tag should not
       be touched (``stable'').

       NOTE: All iterators will be turned to None's.  Since were are changing
       tag order, iterators no longer make sense

       NOTE: assumes we do not have any 'beginstr' and 'endstr' items
    """

    open_stack = []
    contents = PushIter(contents)

    for item in contents:
        kind, it, param = item

        if kind == "begin":

            if is_stable_tag(param):
                # if stable tag, skim ahead to see its closing tag
                stable_span = LinkedList()
                within_closes = set()
                for item2 in contents:
                    stable_span.append(item2)
                    if item2[0] == "end":
                        # look at closing tags
                        if item2[2] == param:
                            # found matching stable close
                            break

                        else:
                            # record tags that close within the stable_span
                            within_closes.add(item2[2])

                # push items back on contents stream
                for item2 in reversed(stable_span):
                    contents.push(item2)

                # define tag classes
                # preopen = open_stack

                # preopen_inside = preopen's with a close in stable_span
                preopen_inside = []
                for tag in open_stack:
                    if tag in within_closes:
                        preopen_inside.append(tag)

                # close preopen_inside
                for item2 in _normalize_close(open_stack, preopen_inside):
                    yield item2

                # yield stable open
                open_stack.append(param)
                yield ("begin", None, param)

                # reopen preopen_inside
                for tag in preopen_inside:
                    open_stack.append(tag)
                    yield ("begin", None, tag)

            else:
                # yield item unchanged
                open_stack.append(param)
                yield ("begin", None, param)

        elif kind == "end":

            for item2 in _normalize_close(open_stack, [param]):
                yield item2

        else:
            yield (kind, None, param)
Beispiel #2
0
class UndoStack(object):
    """UndoStack for maintaining undo and redo actions"""
    def __init__(self, maxsize=sys.maxint):
        """maxsize -- maximum size of undo list"""

        # stacks maintaining (undo,redo) pairs
        self._undo_actions = LinkedList()
        self._redo_actions = []

        # grouping several actions into one
        self._group_counter = 0
        self._pending_actions = []

        # suppress undo/redo while counter > 0
        self._suppress_counter = 0

        # maximum size undo stack
        self._maxsize = maxsize

        self._in_progress = False

    def do(self, action, undo, execute=True):
        """Perform action() (if execute=True) and place (action,undo) pair
           on stack"""

        if self._suppress_counter > 0:
            return

        if self._group_counter == 0:
            # grouping is not active, push action pair and clear redo stack
            self._undo_actions.append((action, undo))
            self._redo_actions = []

            # TODO: should stack be suppressed at this time?
            if execute:
                action()

            # maintain proper undo size
            while len(self._undo_actions) > self._maxsize:
                self._undo_actions.pop_front()
        else:
            # grouping is active, place action pair on pending stack
            self._pending_actions.append((action, undo))
            self._redo_actions = []
            if execute:
                action()

    def undo(self):
        """Undo last action on stack"""
        assert self._group_counter == 0

        if len(self._undo_actions) > 0:
            action, undo = self._undo_actions.pop()
            self.suppress()
            self._in_progress = True
            undo()
            self._in_progress = False
            self.resume()
            self._redo_actions.append((action, undo))

    def redo(self):
        """Redo last action on stack"""
        assert self._group_counter == 0

        if len(self._redo_actions) > 0:
            action, undo = self._redo_actions.pop()
            self.suppress()
            self._in_progress = True
            action()
            self._in_progress = False
            self.resume()
            self._undo_actions.append((action, undo))

            while len(self._undo_actions) > self._maxsize:
                self._undo_actions.pop_front()

    def begin_action(self):
        """Start grouping actions
           Can be called recursively.  Must have corresponding end_action() call
        """
        self._group_counter += 1

    def end_action(self):
        """Stop grouping actions
           Can be called recursively.
        """
        self._group_counter -= 1
        assert self._group_counter >= 0

        if self._group_counter == 0:
            if len(self._pending_actions) > 0:
                actions, undos = zip(*self._pending_actions)

                self._undo_actions.append(
                    (cat_funcs(actions), cat_funcs(reversed(undos))))
                self._pending_actions = []

                while len(self._undo_actions) > self._maxsize:
                    self._undo_actions.pop_front()

    def abort_action(self):
        """
        Stop grouping actions and throw away actions collected so far
        """

        self._group_counter = 0
        self._pending_actions = []

    def suppress(self):
        """Suppress pushing actions on stack
           Can be called recursively.  Must have corresponding resume() call"""
        self._suppress_counter += 1

    def resume(self):
        """Resume pushing actions on stack
           Can be called recursively.
        """
        self._suppress_counter -= 1
        assert self._suppress_counter >= 0

    def is_suppressed(self):
        """Returns True if UndoStack is being suprressed"""
        return self._suppress_counter > 0

    def reset(self):
        """Clear UndoStack of all actions"""
        self._undo_actions.clear()
        self._redo_actions = []
        self._group_counter = 0
        self._pending_actions = []
        self._suppress_counter = 0

    def is_in_progress(self):
        """Returns True if undo or redo is in progress"""
        return self._in_progress
Beispiel #3
0
def normalize_tags(contents, is_stable_tag=lambda tag: False):
    """Normalize open and close tags to ensure proper nesting
       This is especially useful for saving to HTML

       is_stable_tag -- a function that returns True iff a tag should not
       be touched (``stable'').

       NOTE: All iterators will be turned to None's.  Since were are changing
       tag order, iterators no longer make sense

       NOTE: assumes we do not have any 'beginstr' and 'endstr' items
    """

    open_stack = []
    contents = PushIter(contents)

    for item in contents:
        kind, it, param = item

        if kind == "begin":

            if is_stable_tag(param):
                # if stable tag, skim ahead to see its closing tag
                stable_span = LinkedList()
                within_closes = set()
                for item2 in contents:
                    stable_span.append(item2)
                    if item2[0] == "end":
                        # look at closing tags
                        if item2[2] == param:
                            # found matching stable close
                            break

                        else:
                            # record tags that close within the stable_span
                            within_closes.add(item2[2])

                # push items back on contents stream
                for item2 in reversed(stable_span):
                    contents.push(item2)

                # define tag classes
                # preopen = open_stack

                # preopen_inside = preopen's with a close in stable_span
                preopen_inside = []
                for tag in open_stack:
                    if tag in within_closes:
                        preopen_inside.append(tag)

                # close preopen_inside
                for item2 in _normalize_close(open_stack, preopen_inside):
                    yield item2

                # yield stable open
                open_stack.append(param)
                yield ("begin", None, param)

                # reopen preopen_inside
                for tag in preopen_inside:
                    open_stack.append(tag)
                    yield ("begin", None, tag)

            else:
                # yield item unchanged
                open_stack.append(param)
                yield ("begin", None, param)

        elif kind == "end":

            for item2 in _normalize_close(open_stack, [param]):
                yield item2

        else:
            yield (kind, None, param)
Beispiel #4
0
class UndoStack(object):
    """UndoStack for maintaining undo and redo actions"""

    def __init__(self, maxsize=sys.maxint):
        """maxsize -- maximum size of undo list"""

        # stacks maintaining (undo,redo) pairs
        self._undo_actions = LinkedList()
        self._redo_actions = []

        # grouping several actions into one
        self._group_counter = 0
        self._pending_actions = []

        # suppress undo/redo while counter > 0
        self._suppress_counter = 0

        # maximum size undo stack
        self._maxsize = maxsize

        self._in_progress = False

    def do(self, action, undo, execute=True):
        """Perform action() (if execute=True) and place (action,undo) pair
           on stack"""

        if self._suppress_counter > 0:
            return

        if self._group_counter == 0:
            # grouping is not active, push action pair and clear redo stack
            self._undo_actions.append((action, undo))
            self._redo_actions = []

            # TODO: should stack be suppressed at this time?
            if execute:
                action()

            # maintain proper undo size
            while len(self._undo_actions) > self._maxsize:
                self._undo_actions.pop_front()
        else:
            # grouping is active, place action pair on pending stack
            self._pending_actions.append((action, undo))
            self._redo_actions = []
            if execute:
                action()

    def undo(self):
        """Undo last action on stack"""
        assert self._group_counter == 0

        if len(self._undo_actions) > 0:
            action, undo = self._undo_actions.pop()
            self.suppress()
            self._in_progress = True
            undo()
            self._in_progress = False
            self.resume()
            self._redo_actions.append((action, undo))

    def redo(self):
        """Redo last action on stack"""
        assert self._group_counter == 0

        if len(self._redo_actions) > 0:
            action, undo = self._redo_actions.pop()
            self.suppress()
            self._in_progress = True
            action()
            self._in_progress = False
            self.resume()
            self._undo_actions.append((action, undo))

            while len(self._undo_actions) > self._maxsize:
                self._undo_actions.pop_front()

    def begin_action(self):
        """Start grouping actions
           Can be called recursively.  Must have corresponding end_action() call
        """
        self._group_counter += 1

    def end_action(self):
        """Stop grouping actions
           Can be called recursively.
        """
        self._group_counter -= 1
        assert self._group_counter >= 0

        if self._group_counter == 0:
            if len(self._pending_actions) > 0:
                actions, undos = zip(*self._pending_actions)

                self._undo_actions.append((cat_funcs(actions), cat_funcs(reversed(undos))))
                self._pending_actions = []

                while len(self._undo_actions) > self._maxsize:
                    self._undo_actions.pop_front()

    def abort_action(self):
        """
        Stop grouping actions and throw away actions collected so far
        """

        self._group_counter = 0
        self._pending_actions = []

    def suppress(self):
        """Suppress pushing actions on stack
           Can be called recursively.  Must have corresponding resume() call"""
        self._suppress_counter += 1

    def resume(self):
        """Resume pushing actions on stack
           Can be called recursively.
        """
        self._suppress_counter -= 1
        assert self._suppress_counter >= 0

    def is_suppressed(self):
        """Returns True if UndoStack is being suprressed"""
        return self._suppress_counter > 0

    def reset(self):
        """Clear UndoStack of all actions"""
        self._undo_actions.clear()
        self._redo_actions = []
        self._group_counter = 0
        self._pending_actions = []
        self._suppress_counter = 0

    def is_in_progress(self):
        """Returns True if undo or redo is in progress"""
        return self._in_progress