Кароч, замутил я тут шнягу на Питоне – Текставый Ридиктор, шоб писать всякое и не терять! Чо умеет мой красавчегПишешь текст, жмёшь 'Сохранить файл' – и оно в .txt падает, ещё и спросит, если переписать надо. Открываешь любой .txt кнопкой 'Открыть файл', грузит шустро. Поиск и замена – вбил чо найти, чо вставить, и готово! Счётчик символов, шоб знать, скока ты наклепал. Номера строк слева, как в навороченных IDE, шоб не запутаться (2, 3, 4, 5 – само рисуется). Эмодзи юзай сколько влезет – ✌ сохраняет и не плюётся. Автосохранение каждые полминуты, шоб не про***ть гениальное. Тёмная темка, шоб глаза не вытекли, и скролл синхронный – крути как хошь. import tkinter as tk from tkinter import ttk, filedialog, messagebox import os def update_char_count(event=None): content = text_area.get(1.0, tk.END).strip() char_count.set(f"Символов: {len(content)}") update_line_numbers() def update_line_numbers(): line_numbers.config(state="normal") line_numbers.delete(1.0, tk.END) total_lines = int(text_area.index("end-1c").split(".")[0]) for i in range(1, total_lines): line_numbers.insert(tk.END, f"{i}\n") if total_lines == 1: line_numbers.insert(tk.END, "1") line_numbers.config(state="disabled") def sync_scroll(*args): if len(args) == 1: line_numbers.yview_moveto(args[0]) text_area.yview_moveto(args[0]) elif len(args) == 2: line_numbers.yview_scroll(int(args[0]), args[1]) text_area.yview_scroll(int(args[0]), args[1]) def save_file(): filename = entry_filename.get().strip() if not filename: messagebox.showwarning("Ошибка", "Введите название файла!") return if not filename.endswith(".txt"): filename += ".txt" text_content = text_area.get(1.0, tk.END).strip() if not text_content: messagebox.showwarning("Ошибка", "Текст пустой, сохранять нечего!") return if os.path.exists(filename): if not messagebox.askyesno("Подтверждение", f"Файл '{filename}' уже существует. Перезаписать?"): return with open(filename, "w", encoding="utf-8") as file: file.write(text_content) messagebox.showinfo("Успех", f"Файл '{filename}' сохранён!") entry_filename.delete(0, tk.END) text_area.delete(1.0, tk.END) update_char_count() def open_file(): filepath = filedialog.askopenfilename(filetypes=[("Текстовые файлы", "*.txt")]) if filepath: try: with open(filepath, "r", encoding="utf-8") as file: content = file.read() text_area.delete(1.0, tk.END) text_area.insert(1.0, content) entry_filename.delete(0, tk.END) entry_filename.insert(0, filepath.split("/")[-1].replace(".txt", "")) update_char_count() except Exception as e: messagebox.showerror("Ошибка", f"Не удалось открыть файл: {e}") def autosave(): filename = entry_filename.get().strip() if filename and text_area.get(1.0, tk.END).strip(): if not filename.endswith(".txt"): filename += ".txt" with open(filename, "w", encoding="utf-8") as file: file.write(text_area.get(1.0, tk.END).strip()) root.after(30000, autosave) def search_and_replace(): search_text = entry_search.get().strip() replace_text = entry_replace.get().strip() if not search_text: messagebox.showwarning("Ошибка", "Введите текст для поиска!") return content = text_area.get(1.0, tk.END) if search_text in content: new_content = content.replace(search_text, replace_text) text_area.delete(1.0, tk.END) text_area.insert(1.0, new_content) messagebox.showinfo("Успех", f"Заменено '{search_text}' на '{replace_text}'") update_char_count() else: messagebox.showwarning("Ошибка", f"'{search_text}' не найдено!") root = tk.Tk() root.title("Текстовый редактор") root.geometry("800x600") root.configure(bg="#2b2b2b") root.option_add("*Font", "Arial 11") root.tk.call("tk", "scaling", 2.0) style = ttk.Style() style.theme_use("clam") style.configure("TLabel", background="#2b2b2b", foreground="#ffffff", font=("Arial", 10)) style.configure("TButton", background="#4a4a4a", foreground="#ffffff", font=("Arial", 10, "bold"), borderwidth=0) style.map("TButton", background=[("active", "#6a6a6a")]) style.configure("TEntry", fieldbackground="#3c3c3c", foreground="#ffffff", borderwidth=0) title_label = ttk.Label(root, text="Текстовый редактор", font=("Arial", 16, "bold")) title_label.pack(pady=15) filename_frame = tk.Frame(root, bg="#2b2b2b") filename_frame.pack(pady=5) ttk.Label(filename_frame, text="Название файла:").grid(row=0, column=0, padx=10, pady=5, sticky="e") entry_filename = ttk.Entry(filename_frame, width=40) entry_filename.grid(row=0, column=1, padx=10, pady=5) char_count = tk.StringVar(value="Символов: 0") char_label = ttk.Label(root, textvariable=char_count) char_label.pack(pady=5) search_frame = tk.Frame(root, bg="#2b2b2b") search_frame.pack(pady=5) ttk.Label(search_frame, text="Найти:").grid(row=0, column=0, padx=10, pady=5, sticky="e") entry_search = ttk.Entry(search_frame, width=20) entry_search.grid(row=0, column=1, padx=10, pady=5) ttk.Label(search_frame, text="Заменить на:").grid(row=0, column=2, padx=10, pady=5, sticky="e") entry_replace = ttk.Entry(search_frame, width=20) entry_replace.grid(row=0, column=3, padx=10, pady=5) replace_button = ttk.Button(search_frame, text="Заменить", command=search_and_replace) replace_button.grid(row=0, column=4, padx=10, pady=5) button_frame = tk.Frame(root, bg="#2b2b2b") button_frame.pack(pady=10) save_button = ttk.Button(button_frame, text="Сохранить файл", command=save_file) save_button.grid(row=0, column=0, padx=10) open_button = ttk.Button(button_frame, text="Открыть файл", command=open_file) open_button.grid(row=0, column=1, padx=10) text_frame = tk.Frame(root, bg="#2b2b2b") text_frame.pack(padx=20, pady=10, fill="both", expand=True) line_numbers = tk.Text(text_frame, width=4, bg="#2b2b2b", fg="#888888", font=("Arial", 11), borderwidth=0) line_numbers.pack(side="left", fill="y") text_area = tk.Text(text_frame, bg="#3c3c3c", fg="#ffffff", font=("Arial", 11), borderwidth=0, insertbackground="#ffffff") text_area.pack(side="left", fill="both", expand=True) text_area.config(yscrollcommand=sync_scroll) line_numbers.config(yscrollcommand=sync_scroll) scrollbar = ttk.Scrollbar(text_frame, command=sync_scroll) scrollbar.pack(side="right", fill="y") text_area.bind("<KeyRelease>", update_char_count) text_area.bind("<Return>", update_char_count) text_area.bind("<MouseWheel>", lambda e: sync_scroll(-int(e.delta/120), "units")) text_area.delete(1.0, tk.END) update_char_count() root.after(30000, autosave) root.mainloop() Python import tkinter as tk from tkinter import ttk, filedialog, messagebox import os def update_char_count(event=None): content = text_area.get(1.0, tk.END).strip() char_count.set(f"Символов: {len(content)}") update_line_numbers() def update_line_numbers(): line_numbers.config(state="normal") line_numbers.delete(1.0, tk.END) total_lines = int(text_area.index("end-1c").split(".")[0]) for i in range(1, total_lines): line_numbers.insert(tk.END, f"{i}\n") if total_lines == 1: line_numbers.insert(tk.END, "1") line_numbers.config(state="disabled") def sync_scroll(*args): if len(args) == 1: line_numbers.yview_moveto(args[0]) text_area.yview_moveto(args[0]) elif len(args) == 2: line_numbers.yview_scroll(int(args[0]), args[1]) text_area.yview_scroll(int(args[0]), args[1]) def save_file(): filename = entry_filename.get().strip() if not filename: messagebox.showwarning("Ошибка", "Введите название файла!") return if not filename.endswith(".txt"): filename += ".txt" text_content = text_area.get(1.0, tk.END).strip() if not text_content: messagebox.showwarning("Ошибка", "Текст пустой, сохранять нечего!") return if os.path.exists(filename): if not messagebox.askyesno("Подтверждение", f"Файл '{filename}' уже существует. Перезаписать?"): return with open(filename, "w", encoding="utf-8") as file: file.write(text_content) messagebox.showinfo("Успех", f"Файл '{filename}' сохранён!") entry_filename.delete(0, tk.END) text_area.delete(1.0, tk.END) update_char_count() def open_file(): filepath = filedialog.askopenfilename(filetypes=[("Текстовые файлы", "*.txt")]) if filepath: try: with open(filepath, "r", encoding="utf-8") as file: content = file.read() text_area.delete(1.0, tk.END) text_area.insert(1.0, content) entry_filename.delete(0, tk.END) entry_filename.insert(0, filepath.split("/")[-1].replace(".txt", "")) update_char_count() except Exception as e: messagebox.showerror("Ошибка", f"Не удалось открыть файл: {e}") def autosave(): filename = entry_filename.get().strip() if filename and text_area.get(1.0, tk.END).strip(): if not filename.endswith(".txt"): filename += ".txt" with open(filename, "w", encoding="utf-8") as file: file.write(text_area.get(1.0, tk.END).strip()) root.after(30000, autosave) def search_and_replace(): search_text = entry_search.get().strip() replace_text = entry_replace.get().strip() if not search_text: messagebox.showwarning("Ошибка", "Введите текст для поиска!") return content = text_area.get(1.0, tk.END) if search_text in content: new_content = content.replace(search_text, replace_text) text_area.delete(1.0, tk.END) text_area.insert(1.0, new_content) messagebox.showinfo("Успех", f"Заменено '{search_text}' на '{replace_text}'") update_char_count() else: messagebox.showwarning("Ошибка", f"'{search_text}' не найдено!") root = tk.Tk() root.title("Текстовый редактор") root.geometry("800x600") root.configure(bg="#2b2b2b") root.option_add("*Font", "Arial 11") root.tk.call("tk", "scaling", 2.0) style = ttk.Style() style.theme_use("clam") style.configure("TLabel", background="#2b2b2b", foreground="#ffffff", font=("Arial", 10)) style.configure("TButton", background="#4a4a4a", foreground="#ffffff", font=("Arial", 10, "bold"), borderwidth=0) style.map("TButton", background=[("active", "#6a6a6a")]) style.configure("TEntry", fieldbackground="#3c3c3c", foreground="#ffffff", borderwidth=0) title_label = ttk.Label(root, text="Текстовый редактор", font=("Arial", 16, "bold")) title_label.pack(pady=15) filename_frame = tk.Frame(root, bg="#2b2b2b") filename_frame.pack(pady=5) ttk.Label(filename_frame, text="Название файла:").grid(row=0, column=0, padx=10, pady=5, sticky="e") entry_filename = ttk.Entry(filename_frame, width=40) entry_filename.grid(row=0, column=1, padx=10, pady=5) char_count = tk.StringVar(value="Символов: 0") char_label = ttk.Label(root, textvariable=char_count) char_label.pack(pady=5) search_frame = tk.Frame(root, bg="#2b2b2b") search_frame.pack(pady=5) ttk.Label(search_frame, text="Найти:").grid(row=0, column=0, padx=10, pady=5, sticky="e") entry_search = ttk.Entry(search_frame, width=20) entry_search.grid(row=0, column=1, padx=10, pady=5) ttk.Label(search_frame, text="Заменить на:").grid(row=0, column=2, padx=10, pady=5, sticky="e") entry_replace = ttk.Entry(search_frame, width=20) entry_replace.grid(row=0, column=3, padx=10, pady=5) replace_button = ttk.Button(search_frame, text="Заменить", command=search_and_replace) replace_button.grid(row=0, column=4, padx=10, pady=5) button_frame = tk.Frame(root, bg="#2b2b2b") button_frame.pack(pady=10) save_button = ttk.Button(button_frame, text="Сохранить файл", command=save_file) save_button.grid(row=0, column=0, padx=10) open_button = ttk.Button(button_frame, text="Открыть файл", command=open_file) open_button.grid(row=0, column=1, padx=10) text_frame = tk.Frame(root, bg="#2b2b2b") text_frame.pack(padx=20, pady=10, fill="both", expand=True) line_numbers = tk.Text(text_frame, width=4, bg="#2b2b2b", fg="#888888", font=("Arial", 11), borderwidth=0) line_numbers.pack(side="left", fill="y") text_area = tk.Text(text_frame, bg="#3c3c3c", fg="#ffffff", font=("Arial", 11), borderwidth=0, insertbackground="#ffffff") text_area.pack(side="left", fill="both", expand=True) text_area.config(yscrollcommand=sync_scroll) line_numbers.config(yscrollcommand=sync_scroll) scrollbar = ttk.Scrollbar(text_frame, command=sync_scroll) scrollbar.pack(side="right", fill="y") text_area.bind("<KeyRelease>", update_char_count) text_area.bind("<Return>", update_char_count) text_area.bind("<MouseWheel>", lambda e: sync_scroll(-int(e.delta/120), "units")) text_area.delete(1.0, tk.END) update_char_count() root.after(30000, autosave) root.mainloop() юзайте, если шарите, или просто ржите