<commit_before>#!/usr/bin/env python

import os.path
import re
import sys

import tkinter as tk
import tkinter.filedialog
import tkinter.messagebox
import tkinter.scrolledtext

VERSION = [0, 0, 0]
ABANDON_MSG = 'Abandon unsaved changes?'


class Application(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.pack(expand=1, fill='both')
        self.createWidgets()
        self.filename = None
        self.settitle()
        master.protocol("WM_DELETE_WINDOW", self.quit)

    def createWidgets(self):
        self.menu = tk.Menu(self)

        filemenu = tk.Menu(self.menu, tearoff=0)
        filemenu.add_command(label='Open', underline=0, command=self.open,
                             accelerator='Ctrl+O')
        self.bind_all('<Control-o>', self.open)
        filemenu.add_command(label='Save', underline=0, command=self.save,
                             accelerator='Ctrl+S')
        self.bind_all('<Control-s>', self.save)
        filemenu.add_command(label='Save As...', underline=5,
                             command=self.saveas, accelerator='Ctrl+Shift+S')
        self.bind_all('<Control-S>', self.saveas)
        filemenu.add_separator()
        filemenu.add_command(label='Quit', underline=0, accelerator='Ctrl+Q',
                             command=self.quit)
        self.bind_all('<Control-q>', self.quit)
        self.menu.add_cascade(label='File', underline=0, menu=filemenu)

        editmenu = tk.Menu(self.menu, tearoff=0)
        editmenu.add_command(label='Undo', underline=0, command=self.undo,
                             accelerator='Ctrl+Z')
        self.bind_all('<Control-z>', self.undo)
        editmenu.add_command(label='Redo', underline=0, command=self.redo,
                             accelerator='Ctrl+Y')
        self.bind_all('<Control-y>', self.redo)
        self.menu.add_cascade(label='Edit', underline=0, menu=editmenu)

        root.config(menu=self.menu)

        self.status = tkinter.Label(self, text='', relief='sunken',
                                    anchor='w')
        self.status.pack(side='bottom', fill='x')

        self.textin = tk.Text(self, height=0, undo=1)
        self.textin.bind('<Return>', self.sendtext)
        self.textin.bind('<Control-o>', self.open)
        self.textin.pack(side='bottom', fill='x')

        self.textout = tkinter.scrolledtext.ScrolledText(self, undo=1)
        self.textout.bind('<Return>', self.autoindent)
        self.textout.bind('<Control-o>', self.open)
        self.textout.pack(side='bottom', expand=1, fill='both')

    def state(self, text=''):
        self.status['text'] = text

    def settitle(self):
        if self.filename:
            self.master.title(os.path.basename(self.filename))
        else:
            self.master.title('{} {}.{}.{}'.format(sys.argv[0], *VERSION))

    def abandon(self):
        if not self.textout.edit_modified():
            return True
        elif tkinter.messagebox.askokcancel(ABANDON_MSG, ABANDON_MSG):
            return True
        return False

    def open(self, event=None):
        if not self.abandon():
            return 'break'
        filename = tkinter.filedialog.askopenfilename()
        if filename:
            self.filename = filename
            self.settitle()
            self.textout.delete('1.0', 'end')
            self.state('Opening...')
            with open(filename) as f:
                self.textout.insert('insert', f.read())
            self.state('Opened "{}".'.format(os.path.basename(self.filename)))
            self.textout.edit_modified(0)
        return 'break'

    def save(self, event=None):
        if self.filename:
            self.writeout()
        else:
            self.saveas(event)

    def saveas(self, event=None):
        filename = tkinter.filedialog.asksaveasfilename()
        if filename:
            self.filename = filename
            self.settitle()
            self.writeout()

    def writeout(self):
        self.state('Saving...')
        with open(self.filename, 'w') as f:
            f.write(self.textout.get('1.0', 'end'))
        self.state('Saved "{}".'.format(os.path.basename(self.filename)))
        self.textout.edit_modified(0)

    def sendtext(self, event):
        self.textout.insert('end', self.textin.get('1.0', 'end'))
        self.textin.delete('1.0', 'end')
        return 'break'

    def autoindent(self, event):
        line = self.textout.get('insert linestart', 'insert lineend')
        indent = re.match('^[\t ]*', line).group(0)
        self.textout.insert('insert', '\n' + indent)
        return 'break'

    def getundofocus(self):
        widget = self.focus_get()
        if widget not in (self.textin, self.textout):
            widget = self.textout
        return widget

    def undo(self, event=None):
        widget = self.getundofocus()
        try:
            widget.edit_undo()
            self.state()
        except tkinter.TclError as e:
            self.state('{}.'.format(str(e).capitalize()))

    def redo(self, event=None):
        widget = self.getundofocus()
        try:
            widget.edit_redo()
            self.state()
        except tkinter.TclError as e:
            self.state('{}.'.format(str(e).capitalize()))

    def quit(self, event=None):
        if self.abandon():
            super().quit()


root = tk.Tk()
app = Application(master=root)
app.mainloop()
<commit_msg>Fix double undo/redo bug<commit_after>#!/usr/bin/env python

import os.path
import re
import sys

import tkinter as tk
import tkinter.filedialog
import tkinter.messagebox
import tkinter.scrolledtext

VERSION = [0, 0, 0]
ABANDON_MSG = 'Abandon unsaved changes?'


class Application(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.pack(expand=1, fill='both')
        self.createWidgets()
        self.filename = None
        self.settitle()
        master.protocol("WM_DELETE_WINDOW", self.quit)

    def createWidgets(self):
        self.menu = tk.Menu(self)

        filemenu = tk.Menu(self.menu, tearoff=0)
        filemenu.add_command(label='Open', underline=0, command=self.open,
                             accelerator='Ctrl+O')
        self.bind_all('<Control-o>', self.open)
        filemenu.add_command(label='Save', underline=0, command=self.save,
                             accelerator='Ctrl+S')
        self.bind_all('<Control-s>', self.save)
        filemenu.add_command(label='Save As...', underline=5,
                             command=self.saveas, accelerator='Ctrl+Shift+S')
        self.bind_all('<Control-S>', self.saveas)
        filemenu.add_separator()
        filemenu.add_command(label='Quit', underline=0, accelerator='Ctrl+Q',
                             command=self.quit)
        self.bind_all('<Control-q>', self.quit)
        self.menu.add_cascade(label='File', underline=0, menu=filemenu)

        editmenu = tk.Menu(self.menu, tearoff=0)
        editmenu.add_command(label='Undo', underline=0, command=self.undo,
                             accelerator='Ctrl+Z')
        editmenu.add_command(label='Redo', underline=0, command=self.redo,
                             accelerator='Ctrl+Y')
        self.menu.add_cascade(label='Edit', underline=0, menu=editmenu)

        root.config(menu=self.menu)

        self.status = tkinter.Label(self, text='', relief='sunken',
                                    anchor='w')
        self.status.pack(side='bottom', fill='x')

        self.textin = tk.Text(self, height=0, undo=1)
        self.textin.bind('<Return>', self.sendtext)
        self.textin.bind('<Control-z>', self.undo)
        self.textin.bind('<Control-y>', self.redo)
        self.textin.bind('<Control-o>', self.open)
        self.textin.pack(side='bottom', fill='x')

        self.textout = tkinter.scrolledtext.ScrolledText(self, undo=1)
        self.textout.bind('<Return>', self.autoindent)
        self.textout.bind('<Control-z>', self.undo)
        self.textout.bind('<Control-y>', self.redo)
        self.textout.bind('<Control-o>', self.open)
        self.textout.pack(side='bottom', expand=1, fill='both')

    def state(self, text=''):
        self.status['text'] = text

    def settitle(self):
        if self.filename:
            self.master.title(os.path.basename(self.filename))
        else:
            self.master.title('{} {}.{}.{}'.format(sys.argv[0], *VERSION))

    def abandon(self):
        if not self.textout.edit_modified():
            return True
        elif tkinter.messagebox.askokcancel(ABANDON_MSG, ABANDON_MSG):
            return True
        return False

    def open(self, event=None):
        if not self.abandon():
            return 'break'
        filename = tkinter.filedialog.askopenfilename()
        if filename:
            self.filename = filename
            self.settitle()
            self.textout.delete('1.0', 'end')
            self.state('Opening...')
            with open(filename) as f:
                self.textout.insert('insert', f.read())
            self.state('Opened "{}".'.format(os.path.basename(self.filename)))
            self.textout.edit_modified(0)
        return 'break'

    def save(self, event=None):
        if self.filename:
            self.writeout()
        else:
            self.saveas(event)

    def saveas(self, event=None):
        filename = tkinter.filedialog.asksaveasfilename()
        if filename:
            self.filename = filename
            self.settitle()
            self.writeout()

    def writeout(self):
        self.state('Saving...')
        with open(self.filename, 'w') as f:
            f.write(self.textout.get('1.0', 'end'))
        self.state('Saved "{}".'.format(os.path.basename(self.filename)))
        self.textout.edit_modified(0)

    def sendtext(self, event):
        self.textout.insert('end', self.textin.get('1.0', 'end'))
        self.textin.delete('1.0', 'end')
        return 'break'

    def autoindent(self, event):
        line = self.textout.get('insert linestart', 'insert lineend')
        indent = re.match('^[\t ]*', line).group(0)
        self.textout.insert('insert', '\n' + indent)
        return 'break'

    def getundofocus(self):
        widget = self.focus_get()
        if widget not in (self.textin, self.textout):
            widget = self.textout
        return widget

    def undo(self, event=None):
        widget = self.getundofocus()
        try:
            widget.edit_undo()
            self.state()
        except tkinter.TclError as e:
            self.state('{}.'.format(str(e).capitalize()))
        return 'break'

    def redo(self, event=None):
        widget = self.getundofocus()
        try:
            widget.edit_redo()
            self.state()
        except tkinter.TclError as e:
            self.state('{}.'.format(str(e).capitalize()))
        return 'break'

    def quit(self, event=None):
        if self.abandon():
            super().quit()


root = tk.Tk()
app = Application(master=root)
app.mainloop()

{'fraction_non_alphanumeric': 0.14685823406383558, 'fraction_numerical': 0.005456033463671911, 'mean_word_length': 2.198022681011922, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5458749', 'n_tokens_mistral': 3479, 'n_tokens_neox': 3415, 'n_words': 589}