# IDLEX EXTENSION
##    """
##    Copyright(C) 2011-2012 The Board of Trustees of the University of Illinois.
##    All rights reserved.
##
##    Developed by:   Roger D. Serwy
##                    University of Illinois
##
##    Permission is hereby granted, free of charge, to any person obtaining
##    a copy of this software and associated documentation files (the
##    "Software"), to deal with the Software without restriction, including
##    without limitation the rights to use, copy, modify, merge, publish,
##    distribute, sublicense, and/or sell copies of the Software, and to
##    permit persons to whom the Software is furnished to do so, subject to
##    the following conditions:
##
##    + Redistributions of source code must retain the above copyright
##      notice, this list of conditions and the following disclaimers.
##    + Redistributions in binary form must reproduce the above copyright
##      notice, this list of conditions and the following disclaimers in the
##      documentation and/or other materials provided with the distribution.
##    + Neither the names of Roger D. Serwy, the University of Illinois, nor
##      the names of its contributors may be used to endorse or promote
##      products derived from this Software without specific prior written
##      permission.
##
##    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
##    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
##    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
##    IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR
##    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
##    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
##    THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
##
##
##
##
##    Clear Window Extension
##
##    About:
##
##        It provides "Clear Shell Window" under "Options"
##        with ability to undo.
##
##    Part of Issue 6143
##
##    """

config_extension_def = """
[ClearWindow]
enable=1
enable_editor=0
enable_shell=1
[ClearWindow_cfgBindings]
clear-window=<Control-Key-l>
"""


jn = lambda x,y: '%i.%i' % (x,y)        # join integers to text coordinates
sp = lambda x: tuple(map(int, x.split('.')))   # convert tkinter Text coordinate to a line and column tuple

import sys
import re
from idlelib.UndoDelegator import DeleteCommand

ansi_re = re.compile(r'\x01?\x1b\[(.*?)m\x02?')
def strip_ansi(s):
    return ansi_re.sub("", s)

class ClearWindow:
    menudefs = [
        ('options', [
               ('Clear Shell Window', '<<clear-window>>'),
       ]),]

    def __init__(self, editwin):
        self.editwin = editwin
        self.text = self.editwin.text
        self.text.bind("<<clear-window>>", self.clear_window)

    def clear_window_event(self, ev=None):
        self.clear_window(ev)
        return "break"

    def clear_window(self, event):

        per = self.editwin.per
        text = per.bottom
        
        iomark_orig = text.index('iomark')
        line_io, col_io = sp(iomark_orig)

        # if cursor is at the prompt, preserve the prompt (multiline)
        prompt = strip_ansi(sys.ps1)
        backlines = prompt.count('\n')
        prompt_start = jn(line_io-backlines, 0)
        maybe_prompt = text.get(prompt_start, prompt_start + '+%ic' % len(prompt))
        at_prompt = maybe_prompt == prompt

        if at_prompt:
            endpos = text.index(prompt_start)
        else:
            endpos = text.index('iomark linestart')

        dump = text.dump('1.0', endpos, all=True)

        # Add a command to the undo delegator
        undo = self.editwin.undo
        if undo:
            dc = ClearWindowDeleteCommand('1.0', endpos, dump)
            undo.addcmd(dc)

        text.edit_reset() # clear out Tkinter's undo history

        
class ClearWindowDeleteCommand(DeleteCommand):
    def __init__(self, index1, index2, dump):
        DeleteCommand.__init__(self, index1, index2)
        self.dump = dump

    def do(self, text):
        text.delete(self.index1, self.index2)
        text.see('insert')

    def redo(self, text):
        text.delete(self.index1, self.index2)
        text.see('insert')

    def undo(self, text):
        # inspired by "Serializing a text widget" at http://wiki.tcl.tk/9167
        dump = self.dump
        tag = {} # remember the index where a tag was activated
        for key, value, index in dump:
            if key == 'text':
                text.insert(index, value, '')
            elif key == 'tagon':
                tag[value] = index
            elif key == 'tagoff':
                text.tag_add(value, tag[value], index)
                del tag[value]
        # extend existing tags to the end position
        for value in tag:
            text.tag_add(value, tag[value], self.index2)
        text.see('insert')
