Skip to content

Commit 9c6fb8b

Browse files
alpha release
0 parents  commit 9c6fb8b

File tree

11 files changed

+264
-0
lines changed

11 files changed

+264
-0
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Build EXE and Release
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
build:
10+
runs-on: windows-latest
11+
12+
steps:
13+
- name: Checkout code
14+
uses: actions/checkout@v3
15+
16+
- name: Set up Python
17+
uses: actions/setup-python@v4
18+
with:
19+
python-version: '3.13.2'
20+
21+
- name: Install dependencies
22+
run: |
23+
python -m pip install --upgrade pip
24+
pip install -r requirements.txt
25+
pip install pyinstaller
26+
27+
- name: Build executable with PyInstaller
28+
run: |
29+
pyinstaller app.py --onefile --noconsole --name c_editor
30+
31+
- name: Get short commit hash
32+
id: vars
33+
run: echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
34+
35+
- name: Create GitHub Release
36+
uses: softprops/action-gh-release@v1
37+
with:
38+
tag_name: "build-${{ env.SHORT_SHA }}"
39+
name: "Build ${{ env.SHORT_SHA }}"
40+
draft: false
41+
prerelease: false
42+
files: dist/c_editor.exe
43+
env:
44+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# PyInstaller
7+
# Usually created in dist/ and build/ folders
8+
dist/
9+
build/
10+
*.spec
11+
12+
# Installer logs
13+
pip-log.txt
14+
pip-delete-this-directory.txt
15+
16+
# Environments
17+
.env
18+
.venv/
19+
venv/
20+
ENV/
21+
env.bak/
22+
env/
23+
24+
# IDE files
25+
.vscode/
26+
.idea/
27+
*.sublime-project
28+
*.sublime-workspace
29+
30+
# OS generated
31+
.DS_Store
32+
Thumbs.db
33+
desktop.ini
34+
35+
# Temp
36+
*.log
37+
temp/

app.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import customtkinter as ctk
2+
from ui.theme import setup_theme
3+
from ui.widgets import create_editor, create_output, create_menu
4+
from utils.highlighter import highlight
5+
6+
app = ctk.CTk()
7+
app.geometry("1000x750")
8+
app.title("C Code Editor & Runner")
9+
10+
setup_theme()
11+
12+
# Shared state
13+
state = {
14+
"current_file": None,
15+
"editor": None,
16+
"output": None,
17+
}
18+
19+
# === Toolbar Menu (Top) ===
20+
create_menu(app, state)
21+
22+
# === Main Frame (Editor + Output) ===
23+
main_frame = ctk.CTkFrame(app)
24+
main_frame.pack(fill="both", expand=True)
25+
26+
# === Code Editor (Middle) ===
27+
state["editor"] = create_editor(main_frame)
28+
29+
# === Output Console (Bottom) ===
30+
state["output"] = create_output(main_frame)
31+
32+
# === Default Template ===
33+
starter = """#include <stdio.h>
34+
35+
int main() {
36+
int x;
37+
printf("Enter a number: ");
38+
scanf("%d", &x);
39+
printf("You entered: %d\\n", x);
40+
return 0;
41+
}
42+
"""
43+
state["editor"].insert("1.0", starter)
44+
highlight(state["editor"])
45+
46+
app.mainloop()

compiler/compiler.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import subprocess
2+
3+
def check_gcc_installed():
4+
"""Check if gcc (MinGW) is available in PATH."""
5+
try:
6+
result = subprocess.run(["gcc", "--version"], capture_output=True, text=True)
7+
return result.returncode == 0
8+
except FileNotFoundError:
9+
return False
10+
11+
def compile_c_code(source_path: str, exe_path: str):
12+
"""Compile the C file using gcc and return status and message."""
13+
compile_cmd = ["gcc", source_path, "-o", exe_path]
14+
15+
try:
16+
result = subprocess.run(compile_cmd, capture_output=True, text=True)
17+
if result.returncode != 0:
18+
return False, f"[Compilation Error]\n{result.stderr}"
19+
return True, "[Compilation Successful]\n"
20+
except Exception as e:
21+
return False, f"[Error] Failed to compile: {e}"

core/file_ops.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from tkinter import filedialog
2+
3+
def new_file(state):
4+
state["current_file"] = None
5+
state["editor"].delete("1.0", "end")
6+
state["output"].delete("1.0", "end")
7+
8+
def open_file(state, highlight):
9+
path = filedialog.askopenfilename(filetypes=[("C Files", "*.c")])
10+
if path:
11+
with open(path, "r") as file:
12+
code = file.read()
13+
state["editor"].delete("1.0", "end")
14+
state["editor"].insert("1.0", code)
15+
state["current_file"] = path
16+
highlight(state["editor"])
17+
18+
def save_file(state):
19+
if state["current_file"]:
20+
with open(state["current_file"], "w") as file:
21+
file.write(state["editor"].get("1.0", "end-1c"))
22+
else:
23+
save_file_as(state)
24+
25+
def save_file_as(state):
26+
path = filedialog.asksaveasfilename(defaultextension=".c", filetypes=[("C Files", "*.c")])
27+
if path:
28+
state["current_file"] = path
29+
with open(path, "w") as file:
30+
file.write(state["editor"].get("1.0", "end-1c"))

core/runner.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import os
2+
import platform
3+
import subprocess
4+
from compiler.compiler import compile_c_code, check_gcc_installed
5+
6+
def run_code(state):
7+
code = state["editor"].get("1.0", "end-1c")
8+
state["output"].delete("1.0", "end")
9+
10+
if not check_gcc_installed():
11+
state["output"].insert("1.0", "[ERROR] GCC (MinGW) is not installed or not in PATH.")
12+
return
13+
14+
os.makedirs("temp", exist_ok=True)
15+
src = os.path.join("temp", "program.c")
16+
exe = os.path.join("temp", "program.exe")
17+
18+
with open(src, "w") as f:
19+
f.write(code)
20+
21+
success, msg = compile_c_code(src, exe)
22+
state["output"].insert("1.0", msg)
23+
24+
if success:
25+
if platform.system() == "Windows":
26+
subprocess.Popen(f'start cmd /k "{exe}"', shell=True)
27+
else:
28+
subprocess.Popen(['x-terminal-emulator', '-e', exe])

editor_config.py

Whitespace-only changes.

requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
customtkinter
2+
pygments
3+
pyinstaller

ui/theme.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import customtkinter as ctk
2+
3+
def setup_theme():
4+
ctk.set_appearance_mode("dark")
5+
ctk.set_default_color_theme("blue")

ui/widgets.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import customtkinter as ctk
2+
from core.file_ops import new_file, open_file, save_file, save_file_as
3+
from core.runner import run_code
4+
from utils.highlighter import highlight
5+
6+
def create_editor(parent):
7+
editor = ctk.CTkTextbox(parent, font=("Consolas", 14), wrap="none")
8+
editor.pack(fill="both", expand=True, padx=10, pady=(10, 5))
9+
return editor
10+
11+
def create_output(parent):
12+
output = ctk.CTkTextbox(parent, height=130, font=("Consolas", 12), text_color="lime")
13+
output.pack(fill="x", padx=10, pady=(0, 10))
14+
return output
15+
16+
def create_menu(parent, state):
17+
frame = ctk.CTkFrame(parent, height=40, fg_color="#1e1e1e") # dark toolbar style
18+
frame.pack(fill="x", padx=0, pady=0)
19+
20+
button_style = {
21+
"corner_radius": 0,
22+
"height": 32,
23+
"fg_color": "#2d2d30",
24+
"hover_color": "#3e3e42",
25+
"text_color": "white"
26+
}
27+
28+
ctk.CTkButton(frame, text="New", command=lambda: new_file(state), **button_style).pack(side="left", padx=(10, 4))
29+
ctk.CTkButton(frame, text="Open", command=lambda: open_file(state, highlight), **button_style).pack(side="left", padx=4)
30+
ctk.CTkButton(frame, text="Save", command=lambda: save_file(state), **button_style).pack(side="left", padx=4)
31+
ctk.CTkButton(frame, text="Save As", command=lambda: save_file_as(state), **button_style).pack(side="left", padx=4)
32+
ctk.CTkButton(frame, text="Compile & Run", command=lambda: run_code(state), **button_style).pack(side="left", padx=(10, 4))

0 commit comments

Comments
 (0)