commit 2863fc8284df8be9dfe07f42ad9e650e0cf649a6 Author: Rafał Paluch Date: Thu Dec 4 23:31:01 2025 +0100 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/cad b/cad new file mode 100755 index 0000000..a3c9925 --- /dev/null +++ b/cad @@ -0,0 +1,56 @@ +#!/bin/bash + +if [ -z "$1" ]; then + echo "❌ Błąd: Musisz podać plik!" + echo "👉 Użycie: cad nazwa_pliku.py" + exit 1 +fi + +FILE=$1 +FULL_PATH=$(realpath $FILE) +SESSION="cad_session" +LIVE_SCRIPT="/home/pali112/Build123d/live.py" + +# 1. Zabijamy starą sesję +tmux kill-session -t $SESSION 2>/dev/null + +echo "🚀 Tworzę sesję..." + +# ========================================== +# OKNO 1: CODE +# ========================================== +tmux new-session -d -s $SESSION -n 'Code' "vim $FILE" + +# ========================================== +# OKNO 2: SERVER +# ========================================== +echo "🖥️ Przygotowuję maszynownię..." + +# 1. Tworzymy drugie okno +tmux new-window -t $SESSION -n 'Server' +sleep 0.5 # Daj mu chwilę na wstanie + +# 2. URUCHAMIAMY SERWER (Góra) +# W tym momencie mamy tylko jeden panel, więc ślemy do niego. +tmux send-keys -t "${SESSION}:Server" "python3 -m ocp_vscode --host 0.0.0.0 --port 3939" C-m + +# 3. DZIELIMY OKNO +echo "✂️ Dzielę ekran..." +# Dzielimy aktywne okno (Server). +# Flaga -d nie jest użyta, więc focus przenosi się do NOWEGO (dolnego) panelu. +# Używamy -l 15 zamiast %, żeby wymusić stałą wysokość (15 linii tekstu na dole) - to pewniejsze. +tmux split-window -t "${SESSION}:Server" -v -l 15 +sleep 0.5 # Ważna pauza! + +# 4. URUCHAMIAMY RUNNERA (Dół) +# Skoro po splicie kursor jest na dole, ślemy po prostu do okna Server. +tmux send-keys -t "${SESSION}:Server" "python3 $LIVE_SCRIPT $FULL_PATH" C-m + +# ========================================== +# FINISH +# ========================================== +# Wracamy do kodu +tmux select-window -t "${SESSION}:Code" + +echo "✅ Gotowe! Podłączam..." +tmux attach-session -t $SESSION diff --git a/live.py b/live.py new file mode 100644 index 0000000..6213955 --- /dev/null +++ b/live.py @@ -0,0 +1,90 @@ +import sys +import time +import importlib +import os +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler +from threading import Timer + +# --- KONFIGURACJA --- +VIEWER_PORT = 3939 +DELAY_SECONDS = 0.1 # Czeka na ciszę przez 0.5s zanim przeładuje +# -------------------- + +if len(sys.argv) < 2: + print("❌ Błąd: Nie podałeś nazwy pliku!") + sys.exit(1) + +RAW_PATH = sys.argv[1] +ABS_PATH = os.path.abspath(RAW_PATH) +DIR_NAME = os.path.dirname(ABS_PATH) +FILE_NAME = os.path.basename(ABS_PATH) +MODULE_NAME = os.path.splitext(FILE_NAME)[0] + +print(f"📂 Katalog roboczy: {DIR_NAME}") +os.chdir(DIR_NAME) +if "." not in sys.path: + sys.path.insert(0, ".") + +# --- IMPORTY CAD --- +print(f"🔥 Ładuję biblioteki CAD...") +import build123d +from ocp_vscode import show, set_port + +# Konfigurujemy klienta, żeby gadał z portem 3939 +set_port(VIEWER_PORT) + +print(f"🚀 GOTOWE! Nasłuchuję zmian w: {FILE_NAME}") + +# --- OBSŁUGA ZMIAN PLIKU --- +class RebuildHandler(FileSystemEventHandler): + def __init__(self): + self.timer = None + + def on_modified(self, event): + # Reagujemy tylko na zmianę TEGO konkretnego pliku + if os.path.abspath(event.src_path) == ABS_PATH: + # Jeśli zegar już tyka, anulujemy go (bo przyszło nowe zdarzenie = Vim jeszcze pisze) + if self.timer: + self.timer.cancel() + + # Ustawiamy nowy timer. Odpali się tylko jeśli przez 0.5s nic nowego nie przyjdzie. + self.timer = Timer(DELAY_SECONDS, self.process_reload) + self.timer.start() + + def process_reload(self): + print(f"♻️ Przeliczam {MODULE_NAME}... ", end="", flush=True) + start_time = time.time() + try: + # Magia przeładowania modułu bez restartu procesu + if MODULE_NAME in sys.modules: + importlib.reload(sys.modules[MODULE_NAME]) + else: + importlib.import_module(MODULE_NAME) + + print(f"Gotowe ({time.time() - start_time:.2f}s)") + except Exception as e: + # Łapiemy błędy składni/CAD, żeby runner się nie wywalił + print(f"\n❌ BŁĄD KODU:\n{e}") + +if __name__ == "__main__": + # 1. Pierwsze uruchomienie przy starcie + try: + importlib.import_module(MODULE_NAME) + except Exception as e: + print(f"⚠️ Startowy błąd w kodzie: {e}") + + # 2. Uruchomienie obserwatora (Watchdog) + event_handler = RebuildHandler() + observer = Observer() + # Obserwujemy katalog, ale w handlerze filtrujemy tylko nasz plik + observer.schedule(event_handler, path='.', recursive=False) + observer.start() + + try: + while True: + time.sleep(1) + except KeyboardInterrupt: + observer.stop() + print("\n🛑 Koniec pracy.") + observer.join() diff --git a/my_configs.vim b/my_configs.vim new file mode 100644 index 0000000..36c3f75 --- /dev/null +++ b/my_configs.vim @@ -0,0 +1,19 @@ +" Dodaj globalne tagi dla biblioteki BOSL2 +set tags+=~/.build123_tags + +" Skrót do następnego bufora: \ + Tab +nnoremap :bnext +nnoremap w :w !python % + +" Używaj ruff jako lintera (sprawdzanie błędów) +let g:ale_linters = { +\ 'python': ['flake8'] +\} + +" Używaj ruff jako fixera (do :ALEFix) +let g:ale_fixers = { +\ 'python': ['ruff_format'] +\} + +" [ działa jak przełącznik: raz włącza, raz wyłącza tryb PASTE +nnoremap [ :set invpaste paste? diff --git a/my_others/my_others b/my_others/my_others new file mode 120000 index 0000000..9199894 --- /dev/null +++ b/my_others/my_others @@ -0,0 +1 @@ +/home/pali112/Nextcloud/start/my_others \ No newline at end of file diff --git a/my_others/snippets/python.snippets b/my_others/snippets/python.snippets new file mode 100644 index 0000000..0065f9a --- /dev/null +++ b/my_others/snippets/python.snippets @@ -0,0 +1,85 @@ +snippet build123d + from build123d import * +snippet ocp + from ocp_vscode import * +snippet box + Box(${1:length}, ${2:width}, ${3:height}) + +snippet text + Text("${1:what?}", font_size=${2:ile?}) + + +snippet otwieramy + offset(amount=-${1:grubosc_scianki}, openings=${2:what}.faces().sort_by(Axis.Z)[-1]) + +snippet loc + with Locations((${1:x}, ${2:y}, ${3:z})): + +snippet rec + Rectangle(${1:dlugosc}, ${2:szerokosc}) + + +snippet filletpolyline + FilletPolyline((${1:pts1}, ${2:pts2}), (${3:pts3}, ${4:pts4}), (${5:pts5}, ${6:pts5}), radius=${7:fillet radius}) + + + +snippet part + with BuildPart() as ${1:what?}: +snippet sketch + with BuildSketch() as ${1:what?}: + +snippet line + with BuildLine() as ${1:what?}: + +snippet debug + debug(${1:what?}) +snippet move + move(Location((${1:0}, ${2:0}, ${3:0}))) + +snippet extrude + extrude(amount=${1:ile?}) + +snippet align + align=Align.${1:what?} + +snippet alignl + align=(Align.${1:what?}, Align.${2:what?}, Align.${3:what?}) + +snippet fs + ${1:what?}.faces().sort_by(Axis.${2:what?}) + + +snippet grid + with GridLocations(${1:x_spacing,}, ${2:y_spacing}, ${3:x_count}, ${4:y_count}) + +snippet mode + mode=Mode.${1:what?} + +snippet fillet + fillet(${1:objects}, ${2:radius}) + +snippet circle + Circle(${1:radius}) + +snippet mirror + mirror(about=Plane.${1:XY}) + +snippet triangle + Triangle(a=${1:a}, ${2:b}, ${3:c}, ${4:opcional_Angle1}, ${5:optional_Angle2}, ${6:opcional_Angle3}) + +snippet cone + Cone(bottom_radius=${1:ile?}, top_radius=${2:ile?}, height=${3:ile?}) + +snippet scale + scale(${1:what?}, by=${2:scale_factor}) + +snippet show + show(${1:what?}) +snippet showc + show(${1:what?}, colors=["${2:grey}"]) +snippet joint_location + joint_location((${1:x}, ${2:y}, ${3:z})) + +snippet recr + RectangleRounded(${1:dlugosc}, ${2:szerokosc}, ${3:radius}) diff --git a/skrotyApp.py b/skrotyApp.py new file mode 100644 index 0000000..1e5051c --- /dev/null +++ b/skrotyApp.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 + +import os +import tkinter as tk +from tkinter import filedialog, messagebox +import subprocess + +def browse_exec(): + path = filedialog.askopenfilename(title="Wybierz plik wykonywalny (AppImage/skrypt)") + if path: + entry_exec.delete(0, tk.END) + entry_exec.insert(0, path) + +def browse_icon(): + path = filedialog.askopenfilename(title="Wybierz ikonę", filetypes=[("Pliki graficzne", "*.png *.svg *.ico *.jpg *.jpeg")]) + if path: + entry_icon.delete(0, tk.END) + entry_icon.insert(0, path) + +def choose_location(): + location = var_location.get() + if location == "local": + return os.path.expanduser("~/.local/share/applications") + elif location == "system": + return "/usr/share/applications" + elif location == "desktop": + return os.path.join(os.path.expanduser("~"), "Pulpit") + else: + return os.path.expanduser("~") + +def create_desktop_entry(): + name = entry_name.get().strip() + exec_path = entry_exec.get().strip() + icon_path = entry_icon.get().strip() + terminal = var_terminal.get() + + if not name or not exec_path: + messagebox.showerror("Błąd", "Nazwa aplikacji i ścieżka do pliku wykonywalnego są wymagane.") + return + + terminal_value = "true" if terminal else "false" + + desktop_content = f"""[Desktop Entry] +Type=Application +Name={name} +Exec="{exec_path}" +{"Icon=" + icon_path if icon_path else ""} +Terminal={terminal_value} +""" + + filename = name.lower().replace(" ", "_") + ".desktop" + folder = choose_location() + desktop_path = os.path.join(folder, filename) + + try: + if folder.startswith("/usr"): + # Zapis przez pkexec do katalogu systemowego + tmpfile = f"/tmp/{filename}" + with open(tmpfile, "w") as f: + f.write(desktop_content) + subprocess.run(["pkexec", "cp", tmpfile, desktop_path], check=True) + subprocess.run(["pkexec", "chmod", "755", desktop_path], check=True) + os.remove(tmpfile) + else: + os.makedirs(folder, exist_ok=True) + with open(desktop_path, 'w') as f: + f.write(desktop_content) + os.chmod(desktop_path, 0o755) + + messagebox.showinfo("Sukces", f"Skrót utworzony: {desktop_path}") + except Exception as e: + messagebox.showerror("Błąd", f"Nie udało się zapisać skrótu:\n{e}") + +# GUI +root = tk.Tk() +root.title("Tworzenie skrótu .desktop") + +tk.Label(root, text="Nazwa aplikacji:").grid(row=0, column=0, sticky="e") +entry_name = tk.Entry(root, width=40) +entry_name.grid(row=0, column=1, pady=2) + +tk.Label(root, text="Ścieżka do pliku:").grid(row=1, column=0, sticky="e") +entry_exec = tk.Entry(root, width=40) +entry_exec.grid(row=1, column=1, pady=2) +tk.Button(root, text="Przeglądaj", command=browse_exec).grid(row=1, column=2) + +tk.Label(root, text="Ikona (opcjonalnie):").grid(row=2, column=0, sticky="e") +entry_icon = tk.Entry(root, width=40) +entry_icon.grid(row=2, column=1, pady=2) +tk.Button(root, text="Przeglądaj", command=browse_icon).grid(row=2, column=2) + +var_terminal = tk.BooleanVar() +tk.Checkbutton(root, text="Uruchamiane w terminalu", variable=var_terminal).grid(row=3, column=1, pady=4) + +tk.Label(root, text="Miejsce zapisu:").grid(row=4, column=0, sticky="e") +var_location = tk.StringVar(value="local") +tk.Radiobutton(root, text="Lokalnie (~/.local/share/applications)", variable=var_location, value="local").grid(row=4, column=1, sticky="w") +tk.Radiobutton(root, text="Systemowo (/usr/share/applications)", variable=var_location, value="system").grid(row=5, column=1, sticky="w") +tk.Radiobutton(root, text="Pulpit", variable=var_location, value="desktop").grid(row=6, column=1, sticky="w") + +tk.Button(root, text="Utwórz skrót", command=create_desktop_entry, bg="#4CAF50", fg="white").grid(row=7, column=1, pady=10) + +root.mainloop() + diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..dea98aa --- /dev/null +++ b/start.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +echo "Utworzenie linków" +ln -s /home/pali112/Nextcloud/start/my_configs.vim /home/pali112/.vim_runtime/my_configs.vim +ln -s /home/pali112/Nextcloud/start/my_others /home/pali112/.vim_runtime/my_others +ln -s /home/pali112/Nextcloud/start/.zshrc /home/pali112/.zshrc +ln -s /home/pali112/Nextcloud/start/.build123_tags /home/pali112/.build123_tags +ln -s /home/pali112/Nextcloud/start/.flake8 /home/pali112/.flake8 +ln -s /home/pali112/Nextcloud/start/.tmux.conf /home/pali112/.tmux.conf +ln -s /home/pali112/Nextcloud/start/live.py /home/pali112/Build123d/live.py + +KATALOG="/home/pali112/.local/bin" + +# 1. Sprawdzenie, czy katalog istnieje +if [ ! -d "$KATALOG" ]; then + + # 2. Jeśli NIE istnieje (-d sprawdza katalog, ! odwraca wynik) + echo "Katalog $KATALOG nie istnieje. Tworzę go..." + + # 3. Utworzenie katalogu + # Flaga -p zapewnia, że wszystkie potrzebne katalogi nadrzędne (.local) też zostaną utworzone, jeśli ich nie ma. + mkdir -p "$KATALOG" + + # 4. Sprawdzenie, czy operacja się powiodła + if [ $? -eq 0 ]; then + echo "Katalog $KATALOG został pomyślnie utworzony." + else + echo "Błąd: Nie udało się utworzyć katalogu $KATALOG." + fi + +else + # 5. Jeśli katalog już istnieje + echo "Katalog $KATALOG już istnieje wykonuję kolejne rzeczy" +fi + +echo "Tworzenie linku cad" +ln -s /home/pali112/Nextcloud/start/cad /home/pali112/.local/bin/cad + +