clide-editor 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- clide_editor-0.1.0/LICENSE +21 -0
- clide_editor-0.1.0/PKG-INFO +89 -0
- clide_editor-0.1.0/README.md +67 -0
- clide_editor-0.1.0/clide/__init__.py +5 -0
- clide_editor-0.1.0/clide/__main__.py +4 -0
- clide_editor-0.1.0/clide/clide.py +658 -0
- clide_editor-0.1.0/clide/icons/logo.ico +0 -0
- clide_editor-0.1.0/clide_editor.egg-info/PKG-INFO +89 -0
- clide_editor-0.1.0/clide_editor.egg-info/SOURCES.txt +12 -0
- clide_editor-0.1.0/clide_editor.egg-info/dependency_links.txt +1 -0
- clide_editor-0.1.0/clide_editor.egg-info/entry_points.txt +2 -0
- clide_editor-0.1.0/clide_editor.egg-info/top_level.txt +1 -0
- clide_editor-0.1.0/pyproject.toml +37 -0
- clide_editor-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Moinak Debnath
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: clide-editor
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A tiny, no-frills C code editor built with Python + tkinter
|
|
5
|
+
Author: Moinak Debnath
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/findstring/clide
|
|
8
|
+
Project-URL: Repository, https://github.com/findstring/clide
|
|
9
|
+
Project-URL: Issues, https://github.com/findstring/clide/issues
|
|
10
|
+
Keywords: editor,c,ide,tkinter,syntax-highlighting
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Win32 (MS Windows)
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: C
|
|
16
|
+
Classifier: Topic :: Software Development
|
|
17
|
+
Classifier: Topic :: Text Editors
|
|
18
|
+
Requires-Python: >=3.9
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
> 🤖 **Note:** This README was written by Claude AI, because the dev (me) was too lazy to write one myself. The code, however, is 100% hand-written — except for the giant list of C keywords/types/functions used for syntax highlighting, which Claude also helped generate because who's memorizing `stdc_leading_zeros` for fun.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## What is this?
|
|
28
|
+
|
|
29
|
+
CLIDE is a lightweight library based C editor with syntax highlighting, line numbers, auto-indent, and a one-key "compile and run" workflow using `gcc`. No bloat, no plugins, no 400 MB Electron shell — just a `tkinter` window that gets out of your way.
|
|
30
|
+
|
|
31
|
+
Built mostly as a personal project / learning exercise, not (yet) a serious rival to VS Code.
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
- 🎨 **Syntax highlighting** for C — keywords, types, functions, strings, char literals, comments (single-line and block), numbers, and preprocessor directives
|
|
36
|
+
- 🔢 **Line numbers** that track scrolling and zoom
|
|
37
|
+
- 🔍 **Zoom in/out** with `Ctrl + Mouse Wheel`
|
|
38
|
+
- ⏎ **Auto-indent** — adds/removes indentation automatically after `{`, `}`, and `:`
|
|
39
|
+
- ▶️ **Run with F5** — compiles your file with `gcc` and runs it in a new console window
|
|
40
|
+
- 💾 **Open / Save / Save As** from the File menu or `Ctrl+O` / `Ctrl+S`
|
|
41
|
+
- 📋 **Paste-aware highlighting** — pasted multi-line code gets highlighted properly, not just the current line
|
|
42
|
+
- 🎨 **Style Configurator** — change background, foreground colour and also fonts
|
|
43
|
+
- 🖱️ Undo/redo support (unlimited undo history)
|
|
44
|
+
|
|
45
|
+
## Requirements
|
|
46
|
+
|
|
47
|
+
- Python 3.x with `tkinter` (usually bundled with Python on Windows)
|
|
48
|
+
- `gcc` installed and available on your system `PATH` (for the Run feature)
|
|
49
|
+
- Windows — the "Run" feature and maximized window launch currently rely on Windows-specific behavior (see Limitations below)
|
|
50
|
+
|
|
51
|
+
## Getting Started
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install clide-editor
|
|
55
|
+
python -m clide
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Open a `.c` file with `Ctrl+O`, write some code, hit `F5` to compile and run it.
|
|
59
|
+
|
|
60
|
+
## Version
|
|
61
|
+
|
|
62
|
+
**v0.1.0** — early days. Things work, but expect rough edges.
|
|
63
|
+
|
|
64
|
+
## Limitations
|
|
65
|
+
|
|
66
|
+
- **Windows-only for now.** The maximized-window launch and the `F5` run command (`cmd /k gcc ...`) both assume Windows. Running this on Linux/macOS will likely misbehave or crash on the run step.
|
|
67
|
+
- **Single-line-focused highlighting.** Typing re-highlights the line you're on; large structural edits elsewhere in the file (outside of paste) aren't automatically re-scanned.
|
|
68
|
+
- **No project/workspace support** — it's a single-file editor, not a full IDE. No multi-file tabs yet.
|
|
69
|
+
- **No build configuration** — compilation is a hardcoded `gcc file.c -o file.exe`, no custom flags, no Makefile support.
|
|
70
|
+
- **No autocomplete, linting, or error highlighting** — you find out about bugs when `gcc` yells at you.
|
|
71
|
+
- **No find & replace** yet.
|
|
72
|
+
|
|
73
|
+
## To Be Featured (Roadmap)
|
|
74
|
+
|
|
75
|
+
- [ ] Cross-platform support (Linux/macOS build + run)
|
|
76
|
+
- [ ] Find & Replace
|
|
77
|
+
- [ ] Multiple tabs / multi-file projects
|
|
78
|
+
- [ ] Custom compiler flags / build settings
|
|
79
|
+
- [ ] Bracket matching + auto-close brackets
|
|
80
|
+
- [ ] Inline error markers from `gcc` output
|
|
81
|
+
- [ ] Proper packaging (so you don't need Python installed to run it)
|
|
82
|
+
|
|
83
|
+
## Contributing
|
|
84
|
+
|
|
85
|
+
This is a small personal project, but if you spot a bug or have an idea, feel free to open an issue or PR.
|
|
86
|
+
|
|
87
|
+
## License
|
|
88
|
+
|
|
89
|
+
See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
> 🤖 **Note:** This README was written by Claude AI, because the dev (me) was too lazy to write one myself. The code, however, is 100% hand-written — except for the giant list of C keywords/types/functions used for syntax highlighting, which Claude also helped generate because who's memorizing `stdc_leading_zeros` for fun.
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## What is this?
|
|
6
|
+
|
|
7
|
+
CLIDE is a lightweight library based C editor with syntax highlighting, line numbers, auto-indent, and a one-key "compile and run" workflow using `gcc`. No bloat, no plugins, no 400 MB Electron shell — just a `tkinter` window that gets out of your way.
|
|
8
|
+
|
|
9
|
+
Built mostly as a personal project / learning exercise, not (yet) a serious rival to VS Code.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- 🎨 **Syntax highlighting** for C — keywords, types, functions, strings, char literals, comments (single-line and block), numbers, and preprocessor directives
|
|
14
|
+
- 🔢 **Line numbers** that track scrolling and zoom
|
|
15
|
+
- 🔍 **Zoom in/out** with `Ctrl + Mouse Wheel`
|
|
16
|
+
- ⏎ **Auto-indent** — adds/removes indentation automatically after `{`, `}`, and `:`
|
|
17
|
+
- ▶️ **Run with F5** — compiles your file with `gcc` and runs it in a new console window
|
|
18
|
+
- 💾 **Open / Save / Save As** from the File menu or `Ctrl+O` / `Ctrl+S`
|
|
19
|
+
- 📋 **Paste-aware highlighting** — pasted multi-line code gets highlighted properly, not just the current line
|
|
20
|
+
- 🎨 **Style Configurator** — change background, foreground colour and also fonts
|
|
21
|
+
- 🖱️ Undo/redo support (unlimited undo history)
|
|
22
|
+
|
|
23
|
+
## Requirements
|
|
24
|
+
|
|
25
|
+
- Python 3.x with `tkinter` (usually bundled with Python on Windows)
|
|
26
|
+
- `gcc` installed and available on your system `PATH` (for the Run feature)
|
|
27
|
+
- Windows — the "Run" feature and maximized window launch currently rely on Windows-specific behavior (see Limitations below)
|
|
28
|
+
|
|
29
|
+
## Getting Started
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install clide-editor
|
|
33
|
+
python -m clide
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Open a `.c` file with `Ctrl+O`, write some code, hit `F5` to compile and run it.
|
|
37
|
+
|
|
38
|
+
## Version
|
|
39
|
+
|
|
40
|
+
**v0.1.0** — early days. Things work, but expect rough edges.
|
|
41
|
+
|
|
42
|
+
## Limitations
|
|
43
|
+
|
|
44
|
+
- **Windows-only for now.** The maximized-window launch and the `F5` run command (`cmd /k gcc ...`) both assume Windows. Running this on Linux/macOS will likely misbehave or crash on the run step.
|
|
45
|
+
- **Single-line-focused highlighting.** Typing re-highlights the line you're on; large structural edits elsewhere in the file (outside of paste) aren't automatically re-scanned.
|
|
46
|
+
- **No project/workspace support** — it's a single-file editor, not a full IDE. No multi-file tabs yet.
|
|
47
|
+
- **No build configuration** — compilation is a hardcoded `gcc file.c -o file.exe`, no custom flags, no Makefile support.
|
|
48
|
+
- **No autocomplete, linting, or error highlighting** — you find out about bugs when `gcc` yells at you.
|
|
49
|
+
- **No find & replace** yet.
|
|
50
|
+
|
|
51
|
+
## To Be Featured (Roadmap)
|
|
52
|
+
|
|
53
|
+
- [ ] Cross-platform support (Linux/macOS build + run)
|
|
54
|
+
- [ ] Find & Replace
|
|
55
|
+
- [ ] Multiple tabs / multi-file projects
|
|
56
|
+
- [ ] Custom compiler flags / build settings
|
|
57
|
+
- [ ] Bracket matching + auto-close brackets
|
|
58
|
+
- [ ] Inline error markers from `gcc` output
|
|
59
|
+
- [ ] Proper packaging (so you don't need Python installed to run it)
|
|
60
|
+
|
|
61
|
+
## Contributing
|
|
62
|
+
|
|
63
|
+
This is a small personal project, but if you spot a bug or have an idea, feel free to open an issue or PR.
|
|
64
|
+
|
|
65
|
+
## License
|
|
66
|
+
|
|
67
|
+
See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
import tkinter as tk
|
|
2
|
+
from tkinter import messagebox
|
|
3
|
+
from tkinter import filedialog
|
|
4
|
+
from tkinter import simpledialog
|
|
5
|
+
import tkinter.font as tkfont
|
|
6
|
+
from tkinter import ttk
|
|
7
|
+
from tkinter import colorchooser
|
|
8
|
+
import sys
|
|
9
|
+
import os
|
|
10
|
+
import subprocess
|
|
11
|
+
|
|
12
|
+
CLIDE_VERSION = "v0.1.0"
|
|
13
|
+
SCRIPT_PATH = os.path.abspath(__file__)
|
|
14
|
+
LOGO_ICO = os.path.join(os.path.dirname(SCRIPT_PATH), "icons", "logo.ico")
|
|
15
|
+
COMMON_BG = "gray5"
|
|
16
|
+
COMMON_FG = "gray70"
|
|
17
|
+
COMMON_FONTSIZE = 16
|
|
18
|
+
COMMON_FONT = "Iosevka" # You can change it to your desired font
|
|
19
|
+
|
|
20
|
+
# This Section is fully done by CLAUDE as i dont know all the types
|
|
21
|
+
|
|
22
|
+
C_TYPES = {
|
|
23
|
+
"void",
|
|
24
|
+
"char", "signed char", "unsigned char",
|
|
25
|
+
"short", "short int", "signed short", "signed short int",
|
|
26
|
+
"unsigned short", "unsigned short int",
|
|
27
|
+
"int", "signed", "signed int",
|
|
28
|
+
"unsigned", "unsigned int",
|
|
29
|
+
"long", "long int", "signed long", "signed long int",
|
|
30
|
+
"unsigned long", "unsigned long int",
|
|
31
|
+
"long long", "long long int", "signed long long", "signed long long int",
|
|
32
|
+
"unsigned long long", "unsigned long long int",
|
|
33
|
+
"float",
|
|
34
|
+
"double",
|
|
35
|
+
"long double",
|
|
36
|
+
"_Bool",
|
|
37
|
+
"_Complex",
|
|
38
|
+
"_Imaginary",
|
|
39
|
+
|
|
40
|
+
# <stddef.h>
|
|
41
|
+
"size_t", "ptrdiff_t", "wchar_t", "max_align_t", "nullptr_t", # nullptr_t is C23
|
|
42
|
+
|
|
43
|
+
# <stdint.h>
|
|
44
|
+
"int8_t", "int16_t", "int32_t", "int64_t",
|
|
45
|
+
"uint8_t", "uint16_t", "uint32_t", "uint64_t",
|
|
46
|
+
"int_least8_t", "int_least16_t", "int_least32_t", "int_least64_t",
|
|
47
|
+
"uint_least8_t", "uint_least16_t", "uint_least32_t", "uint_least64_t",
|
|
48
|
+
"int_fast8_t", "int_fast16_t", "int_fast32_t", "int_fast64_t",
|
|
49
|
+
"uint_fast8_t", "uint_fast16_t", "uint_fast32_t", "uint_fast64_t",
|
|
50
|
+
"intptr_t", "uintptr_t", "intmax_t", "uintmax_t",
|
|
51
|
+
|
|
52
|
+
# <stdio.h>
|
|
53
|
+
"FILE", "fpos_t",
|
|
54
|
+
|
|
55
|
+
# <time.h>
|
|
56
|
+
"time_t", "clock_t", "struct tm", "struct timespec",
|
|
57
|
+
|
|
58
|
+
# <stdarg.h>
|
|
59
|
+
"va_list",
|
|
60
|
+
|
|
61
|
+
# <stdlib.h>
|
|
62
|
+
"div_t", "ldiv_t", "lldiv_t",
|
|
63
|
+
|
|
64
|
+
# <setjmp.h>
|
|
65
|
+
"jmp_buf",
|
|
66
|
+
|
|
67
|
+
# <signal.h>
|
|
68
|
+
"sig_atomic_t",
|
|
69
|
+
|
|
70
|
+
# <wchar.h>
|
|
71
|
+
"wint_t", "mbstate_t",
|
|
72
|
+
|
|
73
|
+
# <locale.h>
|
|
74
|
+
"struct lconv",
|
|
75
|
+
|
|
76
|
+
# <threads.h> (C11)
|
|
77
|
+
"thrd_t", "mtx_t", "cnd_t", "tss_t", "once_flag", "thrd_start_t", "tss_dtor_t",
|
|
78
|
+
|
|
79
|
+
# <stdatomic.h> (C11)
|
|
80
|
+
"atomic_flag", "memory_order",
|
|
81
|
+
"atomic_bool", "atomic_char", "atomic_int", "atomic_long", "atomic_llong",
|
|
82
|
+
"atomic_uint", "atomic_ulong", "atomic_ullong", "atomic_size_t",
|
|
83
|
+
"atomic_intptr_t", "atomic_uintptr_t", "atomic_ptrdiff_t",
|
|
84
|
+
"atomic_intmax_t", "atomic_uintmax_t",
|
|
85
|
+
|
|
86
|
+
# <uchar.h>
|
|
87
|
+
"char8_t", # C23
|
|
88
|
+
"char16_t", "char32_t",
|
|
89
|
+
"bool"
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
C_FUNCTIONS = {
|
|
93
|
+
# <stdio.h>
|
|
94
|
+
"printf", "fprintf", "sprintf", "snprintf",
|
|
95
|
+
"vprintf", "vfprintf", "vsprintf", "vsnprintf",
|
|
96
|
+
"scanf", "fscanf", "sscanf", "vscanf", "vfscanf", "vsscanf",
|
|
97
|
+
"fopen", "freopen", "fclose", "fflush",
|
|
98
|
+
"fread", "fwrite",
|
|
99
|
+
"fgetc", "getc", "fgets", "fputc", "putc", "fputs",
|
|
100
|
+
"getchar", "putchar", "puts", "gets_s",
|
|
101
|
+
"ungetc",
|
|
102
|
+
"fseek", "ftell", "rewind", "fgetpos", "fsetpos",
|
|
103
|
+
"fseeko", "ftello",
|
|
104
|
+
"feof", "ferror", "clearerr", "perror",
|
|
105
|
+
"remove", "rename", "tmpfile", "tmpnam",
|
|
106
|
+
"setbuf", "setvbuf",
|
|
107
|
+
|
|
108
|
+
# <stdlib.h>
|
|
109
|
+
"malloc", "calloc", "realloc", "free", "aligned_alloc", "free_sized", "free_aligned_sized", # last two C23
|
|
110
|
+
"atof", "atoi", "atol", "atoll",
|
|
111
|
+
"strtod", "strtof", "strtold",
|
|
112
|
+
"strtol", "strtoll", "strtoul", "strtoull",
|
|
113
|
+
"rand", "srand",
|
|
114
|
+
"abort", "exit", "_Exit", "quick_exit",
|
|
115
|
+
"atexit", "at_quick_exit",
|
|
116
|
+
"system", "getenv",
|
|
117
|
+
"bsearch", "qsort", "qsort_r",
|
|
118
|
+
"abs", "labs", "llabs",
|
|
119
|
+
"div", "ldiv", "lldiv",
|
|
120
|
+
"mblen", "mbtowc", "wctomb", "mbstowcs", "wcstombs",
|
|
121
|
+
|
|
122
|
+
# <string.h>
|
|
123
|
+
"memcpy", "memmove", "memcmp", "memchr", "memset",
|
|
124
|
+
"memccpy",
|
|
125
|
+
"strcpy", "strncpy", "strcat", "strncat", "strcmp", "strncmp",
|
|
126
|
+
"strchr", "strrchr", "strstr", "strpbrk", "strspn", "strcspn",
|
|
127
|
+
"strtok", "strtok_r",
|
|
128
|
+
"strlen", "strerror", "strcoll", "strxfrm",
|
|
129
|
+
"strdup", "strndup",
|
|
130
|
+
"memset_explicit", "memset_s", # newer / annex-K style
|
|
131
|
+
|
|
132
|
+
# <ctype.h>
|
|
133
|
+
"isalnum", "isalpha", "isblank", "iscntrl", "isdigit", "isgraph",
|
|
134
|
+
"islower", "isprint", "ispunct", "isspace", "isupper", "isxdigit",
|
|
135
|
+
"tolower", "toupper",
|
|
136
|
+
|
|
137
|
+
# <math.h>
|
|
138
|
+
"sin", "cos", "tan", "asin", "acos", "atan", "atan2",
|
|
139
|
+
"sinh", "cosh", "tanh", "asinh", "acosh", "atanh",
|
|
140
|
+
"exp", "exp2", "expm1", "log", "log2", "log10", "log1p", "logb",
|
|
141
|
+
"pow", "sqrt", "cbrt", "hypot",
|
|
142
|
+
"ceil", "floor", "trunc", "round", "lround", "llround", "nearbyint", "rint", "lrint", "llrint",
|
|
143
|
+
"fmod", "remainder", "remquo",
|
|
144
|
+
"copysign", "nan", "nextafter", "nexttoward",
|
|
145
|
+
"fdim", "fmax", "fmin", "fma",
|
|
146
|
+
"fabs", "frexp", "ldexp", "modf", "scalbn", "scalbln",
|
|
147
|
+
"ilogb", "erf", "erfc", "tgamma", "lgamma",
|
|
148
|
+
"isfinite", "isinf", "isnan", "isnormal", "signbit",
|
|
149
|
+
"isgreater", "isgreaterequal", "isless", "islessequal", "islessgreater", "isunordered",
|
|
150
|
+
|
|
151
|
+
# <time.h>
|
|
152
|
+
"time", "difftime", "mktime", "asctime", "ctime",
|
|
153
|
+
"gmtime", "localtime", "strftime",
|
|
154
|
+
"clock", "timespec_get", "timespec_getres", # timespec_getres is C23
|
|
155
|
+
|
|
156
|
+
# <wchar.h>, <wctype.h> — wide-char variants
|
|
157
|
+
"wcslen", "wcscpy", "wcsncpy", "wcscat", "wcsncat", "wcscmp", "wcsncmp",
|
|
158
|
+
"wcschr", "wcsrchr", "wcsstr", "wcstok",
|
|
159
|
+
"fwprintf", "fwscanf", "swprintf", "swscanf", "wprintf", "wscanf",
|
|
160
|
+
"iswalpha", "iswdigit", "iswspace", "towlower", "towupper",
|
|
161
|
+
|
|
162
|
+
# <setjmp.h>
|
|
163
|
+
"setjmp", "longjmp",
|
|
164
|
+
|
|
165
|
+
# <signal.h>
|
|
166
|
+
"signal", "raise",
|
|
167
|
+
|
|
168
|
+
# <assert.h>
|
|
169
|
+
# assert() is a macro, listed above
|
|
170
|
+
|
|
171
|
+
# <locale.h>
|
|
172
|
+
"setlocale", "localeconv",
|
|
173
|
+
|
|
174
|
+
# <stdarg.h> (function-like macros)
|
|
175
|
+
"va_start", "va_arg", "va_end", "va_copy",
|
|
176
|
+
|
|
177
|
+
# <threads.h>
|
|
178
|
+
"thrd_create", "thrd_join", "thrd_detach", "thrd_exit", "thrd_yield",
|
|
179
|
+
"thrd_sleep", "thrd_current", "thrd_equal",
|
|
180
|
+
"mtx_init", "mtx_lock", "mtx_unlock", "mtx_trylock", "mtx_timedlock", "mtx_destroy",
|
|
181
|
+
"cnd_init", "cnd_signal", "cnd_broadcast", "cnd_wait", "cnd_timedwait", "cnd_destroy",
|
|
182
|
+
"call_once",
|
|
183
|
+
"tss_create", "tss_get", "tss_set", "tss_delete",
|
|
184
|
+
|
|
185
|
+
# <stdatomic.h>
|
|
186
|
+
"atomic_init", "atomic_store", "atomic_load", "atomic_exchange",
|
|
187
|
+
"atomic_compare_exchange_strong", "atomic_compare_exchange_weak",
|
|
188
|
+
"atomic_fetch_add", "atomic_fetch_sub", "atomic_fetch_or",
|
|
189
|
+
"atomic_fetch_and", "atomic_fetch_xor",
|
|
190
|
+
"atomic_flag_test_and_set", "atomic_flag_clear",
|
|
191
|
+
"atomic_thread_fence", "atomic_signal_fence", "atomic_is_lock_free",
|
|
192
|
+
|
|
193
|
+
# <uchar.h>
|
|
194
|
+
"mbrtoc8", "c8rtomb", # C23
|
|
195
|
+
"mbrtoc16", "c16rtomb", "mbrtoc32", "c32rtomb",
|
|
196
|
+
|
|
197
|
+
# <stdbit.h> (C23) — bit utilities
|
|
198
|
+
"stdc_leading_zeros", "stdc_leading_ones", "stdc_trailing_zeros", "stdc_trailing_ones",
|
|
199
|
+
"stdc_first_leading_zero", "stdc_first_leading_one",
|
|
200
|
+
"stdc_first_trailing_zero", "stdc_first_trailing_one",
|
|
201
|
+
"stdc_count_zeros", "stdc_count_ones", "stdc_has_single_bit",
|
|
202
|
+
"stdc_bit_width", "stdc_bit_floor", "stdc_bit_ceil",
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
C_KEYWORDS = {
|
|
206
|
+
"auto", "break", "case", "char", "const", "continue",
|
|
207
|
+
"default", "do", "else", "enum", "extern",
|
|
208
|
+
"float", "for", "goto", "if", "int", "long",
|
|
209
|
+
"register", "return", "short", "signed", "sizeof", "static",
|
|
210
|
+
"struct", "switch", "typedef", "union", "unsigned", "void",
|
|
211
|
+
"volatile", "while",
|
|
212
|
+
"inline",
|
|
213
|
+
"restrict",
|
|
214
|
+
"_Bool",
|
|
215
|
+
"_Complex",
|
|
216
|
+
"_Imaginary",
|
|
217
|
+
"_Alignas",
|
|
218
|
+
"_Alignof",
|
|
219
|
+
"_Atomic",
|
|
220
|
+
"_Generic",
|
|
221
|
+
"_Noreturn",
|
|
222
|
+
"_Static_assert",
|
|
223
|
+
"_Thread_local",
|
|
224
|
+
"alignas",
|
|
225
|
+
"alignof",
|
|
226
|
+
"bool",
|
|
227
|
+
"true",
|
|
228
|
+
"false",
|
|
229
|
+
"static_assert",
|
|
230
|
+
"thread_local",
|
|
231
|
+
"typeof",
|
|
232
|
+
"typeof_unqual",
|
|
233
|
+
"constexpr",
|
|
234
|
+
"nullptr",
|
|
235
|
+
"_BitInt",
|
|
236
|
+
"_Decimal32",
|
|
237
|
+
"_Decimal64",
|
|
238
|
+
"_Decimal128",
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
class WINDOW:
|
|
242
|
+
def __init__(self):
|
|
243
|
+
self.file = ""
|
|
244
|
+
self.multiline_comment = False
|
|
245
|
+
self.fontsize = COMMON_FONTSIZE
|
|
246
|
+
self.bgcolor = COMMON_BG
|
|
247
|
+
self.fgcolor = COMMON_FG
|
|
248
|
+
self.indent_size = 4
|
|
249
|
+
self.indented_count = 0
|
|
250
|
+
self.window = tk.Tk()
|
|
251
|
+
self.font = COMMON_FONT
|
|
252
|
+
if self.font not in tkfont.families():
|
|
253
|
+
self.font = "Courier New"
|
|
254
|
+
x = int((self.window.winfo_screenwidth() - self.window.winfo_screenwidth() / 1.4) // 2)
|
|
255
|
+
y = int((self.window.winfo_screenheight() - (self.window.winfo_screenheight() / 1.2) - 75) // 2)
|
|
256
|
+
self.window.geometry(f"{int(self.window.winfo_screenwidth() / 1.4)}x{int(self.window.winfo_screenheight() / 1.2)}+{x}+{y}")
|
|
257
|
+
self.window.state("zoomed")
|
|
258
|
+
self.window.title("CLIDE")
|
|
259
|
+
self.window.grid_rowconfigure(0, weight = 1)
|
|
260
|
+
self.window.grid_rowconfigure(1, weight = 0)
|
|
261
|
+
self.window.grid_columnconfigure(0, weight = 0)
|
|
262
|
+
self.window.grid_columnconfigure(1, weight = 1)
|
|
263
|
+
self.window.grid_columnconfigure(2, weight = 0)
|
|
264
|
+
try:
|
|
265
|
+
self.window.iconbitmap(LOGO_ICO)
|
|
266
|
+
except:
|
|
267
|
+
messagebox.showerror("Logo Error", f"Unable to find {LOGO_ICO}")
|
|
268
|
+
|
|
269
|
+
self.main_menubar = tk.Menu(self.window)
|
|
270
|
+
self.main_menubar_file_menu = tk.Menu(self.main_menubar, tearoff=0)
|
|
271
|
+
self.main_menubar_file_menu.add_command(label="Open", command = self.open_file)
|
|
272
|
+
self.main_menubar_file_menu.add_command(label="Save", command = self.save_file)
|
|
273
|
+
self.main_menubar_file_menu.add_command(label="Save as", command = self.saveas_file)
|
|
274
|
+
self.main_menubar_file_menu.add_separator()
|
|
275
|
+
self.main_menubar_file_menu.add_command(label="Exit", command=self.window.quit)
|
|
276
|
+
self.main_menubar.add_cascade(label="File", menu=self.main_menubar_file_menu)
|
|
277
|
+
|
|
278
|
+
self.main_menubar_run_menu = tk.Menu(self.main_menubar, tearoff=0)
|
|
279
|
+
self.main_menubar_run_menu.add_command(label="Run C file F5", command = self.run_file)
|
|
280
|
+
self.main_menubar.add_cascade(label="Run", menu=self.main_menubar_run_menu)
|
|
281
|
+
|
|
282
|
+
self.main_menubar_settings_menu = tk.Menu(self.main_menubar, tearoff=0)
|
|
283
|
+
self.main_menubar_settings_menu.add_command(label="Style Configurator...", command = self.style_configurator)
|
|
284
|
+
self.main_menubar_settings_menu.add_command(label="About and Info...", command = self.about_info)
|
|
285
|
+
self.main_menubar.add_cascade(label="Settings", menu=self.main_menubar_settings_menu)
|
|
286
|
+
self.window.config(menu=self.main_menubar)
|
|
287
|
+
|
|
288
|
+
self.main_scrollbar_x = tk.Scrollbar(self.window, orient="horizontal")
|
|
289
|
+
self.main_scrollbar_x.grid(row = 1, column = 0, columnspan = 2, sticky = "ew")
|
|
290
|
+
|
|
291
|
+
self.main_scrollbar_y = tk.Scrollbar(self.window, orient="vertical")
|
|
292
|
+
self.main_scrollbar_y.grid(row = 0, column = 2, sticky = "ns")
|
|
293
|
+
|
|
294
|
+
self.line_numbers_width = 20
|
|
295
|
+
|
|
296
|
+
self.line_numbers = tk.Canvas(self.window, highlightthickness=0, width = self.line_numbers_width, bg = self.bgcolor)
|
|
297
|
+
self.line_numbers.grid(row = 0, column = 0, sticky = "ns")
|
|
298
|
+
|
|
299
|
+
def on_textscroll(first, last):
|
|
300
|
+
self.main_scrollbar_y.set(first, last)
|
|
301
|
+
self.update_clide()
|
|
302
|
+
|
|
303
|
+
self.editor = tk.Text(self.window ,
|
|
304
|
+
bg = self.bgcolor,
|
|
305
|
+
insertbackground="gray70",
|
|
306
|
+
fg = self.fgcolor ,
|
|
307
|
+
wrap="none",
|
|
308
|
+
undo=True,
|
|
309
|
+
maxundo=-1,
|
|
310
|
+
font = (self.font, COMMON_FONTSIZE),
|
|
311
|
+
xscrollcommand = self.main_scrollbar_x.set,
|
|
312
|
+
yscrollcommand=on_textscroll)
|
|
313
|
+
self.editor.grid(row = 0, column = 1, sticky = "nsew")
|
|
314
|
+
self.editor.edit_modified(False)
|
|
315
|
+
|
|
316
|
+
self.main_scrollbar_x.config(command = self.editor.xview)
|
|
317
|
+
self.main_scrollbar_y.config(command = self.editor.yview)
|
|
318
|
+
self.editor.bind("<KeyRelease>", self.update_clide)
|
|
319
|
+
self.editor.bind("<Control-o>", self.open_file)
|
|
320
|
+
self.editor.bind("<Control-s>", self.save_file)
|
|
321
|
+
self.editor.bind("<Return>", self.indent_line)
|
|
322
|
+
self.editor.bind("<F5>", self.run_file)
|
|
323
|
+
self.editor.bind("<Control-v>", self.paste_text)
|
|
324
|
+
self.editor.bind("<Control-MouseWheel>", self.zoom_text)
|
|
325
|
+
self.editor.tag_configure("keyword", foreground="yellow")
|
|
326
|
+
self.editor.tag_configure("string", foreground="#ff8080")
|
|
327
|
+
self.editor.tag_configure("preprocessor", foreground="orange")
|
|
328
|
+
self.editor.tag_configure("brackets", foreground="lightblue")
|
|
329
|
+
self.editor.tag_configure("functions", foreground="violet")
|
|
330
|
+
self.editor.tag_configure("comment", foreground="grey")
|
|
331
|
+
self.editor.tag_configure("type", foreground="green")
|
|
332
|
+
|
|
333
|
+
def about_info(self, event = None):
|
|
334
|
+
win = tk.Toplevel(self.window)
|
|
335
|
+
win.attributes("-topmost", True)
|
|
336
|
+
win.title("About and Info")
|
|
337
|
+
try:
|
|
338
|
+
win.iconbitmap(LOGO_ICO)
|
|
339
|
+
except:
|
|
340
|
+
messagebox.showerror("Logo Error", f"Unable to find {LOGO_ICO}")
|
|
341
|
+
win.focus_force()
|
|
342
|
+
win.focus_set()
|
|
343
|
+
win.configure(bg=self.bgcolor)
|
|
344
|
+
tk.Label(win, text ="Software name : CLIDE", font = (self.font, 16), fg = self.fgcolor, bg = self.bgcolor).pack(pady=10, anchor = "nw")
|
|
345
|
+
tk.Label(win, text =f"Software version : {CLIDE_VERSION}", font = (self.font, 16), fg = self.fgcolor, bg = self.bgcolor).pack(pady=10, anchor = "nw")
|
|
346
|
+
tk.Label(win, text ="Maintainer : Moinak debnath", font = (self.font, 16), fg = self.fgcolor, bg = self.bgcolor).pack(pady=10, anchor = "nw")
|
|
347
|
+
tk.Label(win, text ="Contributors : Claude (AI assistance)", font = (self.font, 16), fg = self.fgcolor, bg = self.bgcolor).pack(pady=10, anchor = "nw")
|
|
348
|
+
tk.Label(win, text ="Description : A code editor for C", font = (self.font, 16), fg = self.fgcolor, bg = self.bgcolor).pack(pady=10, anchor = "nw")
|
|
349
|
+
tk.Label(win, text ="License : MIT", font = (self.font, 16), fg = self.fgcolor, bg = self.bgcolor).pack(pady=10, anchor = "nw")
|
|
350
|
+
|
|
351
|
+
win.update_idletasks()
|
|
352
|
+
|
|
353
|
+
w = win.winfo_width()
|
|
354
|
+
h = win.winfo_height()
|
|
355
|
+
|
|
356
|
+
x = (win.winfo_screenwidth() - w) // 2
|
|
357
|
+
y = ((win.winfo_screenheight() - h) // 2) - 50 # to remove the taskbar and show the relative center
|
|
358
|
+
|
|
359
|
+
win.geometry(f"{w}x{h}+{x}+{y}")
|
|
360
|
+
|
|
361
|
+
def style_configurator(self, event = None):
|
|
362
|
+
win = tk.Toplevel(self.window)
|
|
363
|
+
win.attributes("-topmost", True)
|
|
364
|
+
win.title("Style Configurator")
|
|
365
|
+
x = int((win.winfo_screenwidth() - win.winfo_screenwidth() / 3) // 2)
|
|
366
|
+
y = int((win.winfo_screenheight() - (win.winfo_screenheight() / 2.5) - 75) // 2)
|
|
367
|
+
win.geometry(f"{int(win.winfo_screenwidth() / 3)}x{int(win.winfo_screenheight() / 2.5)}+{x}+{y}")
|
|
368
|
+
try:
|
|
369
|
+
win.iconbitmap(LOGO_ICO)
|
|
370
|
+
except:
|
|
371
|
+
messagebox.showerror("Logo Error", f"Unable to find {LOGO_ICO}")
|
|
372
|
+
win.focus_force()
|
|
373
|
+
win.focus_set()
|
|
374
|
+
win.configure(bg=self.bgcolor)
|
|
375
|
+
win.grid_rowconfigure(0, weight = 1)
|
|
376
|
+
win.grid_rowconfigure(1, weight = 1)
|
|
377
|
+
win.grid_rowconfigure(2, weight = 1)
|
|
378
|
+
win.grid_columnconfigure(0, weight = 1)
|
|
379
|
+
win.grid_columnconfigure(1, weight = 1)
|
|
380
|
+
|
|
381
|
+
def change_fg():
|
|
382
|
+
fg = colorchooser.askcolor()
|
|
383
|
+
if not fg[1]:
|
|
384
|
+
return
|
|
385
|
+
fg = fg[1]
|
|
386
|
+
self.fgcolor = fg
|
|
387
|
+
self.editor.configure(fg = self.fgcolor)
|
|
388
|
+
fg_button.config(text=f"{self.fgcolor} ➕", fg=self.fgcolor)
|
|
389
|
+
self.update_clide()
|
|
390
|
+
|
|
391
|
+
def change_bg():
|
|
392
|
+
bg = colorchooser.askcolor()
|
|
393
|
+
if not bg[1]:
|
|
394
|
+
return
|
|
395
|
+
bg = bg[1]
|
|
396
|
+
self.bgcolor = bg
|
|
397
|
+
self.editor.configure(bg = self.bgcolor)
|
|
398
|
+
bg_button.config(text=f"{self.bgcolor} ➕", fg=self.bgcolor)
|
|
399
|
+
self.line_numbers.configure(bg = self.bgcolor)
|
|
400
|
+
self.update_clide()
|
|
401
|
+
|
|
402
|
+
tk.Label(win, text = "Foreground Colour ", font = (self.font, 14), bg = self.bgcolor ,fg = "gray70").grid(row = 0, column = 0, padx = 30, sticky = "w")
|
|
403
|
+
fg_button = tk.Button(win, relief = "flat",font = (self.font, 14), text = f"{self.fgcolor} ➕", bg ="gray30" ,fg = self.fgcolor, command = change_fg)
|
|
404
|
+
fg_button.grid(row = 0, column = 1, sticky = "w", columnspan = 1)
|
|
405
|
+
|
|
406
|
+
tk.Label(win, text = "Background Colour ",font = (self.font, 14), bg = self.bgcolor ,fg = "gray70").grid(row = 1, column = 0, padx = 30, sticky = "w")
|
|
407
|
+
bg_button = tk.Button(win, relief = "flat",font = (self.font, 14), text = f"{self.bgcolor} ➕", bg ="gray30" ,fg = self.fgcolor, command = change_bg)
|
|
408
|
+
bg_button.grid(row = 1, column = 1, sticky = "w", columnspan = 1)
|
|
409
|
+
|
|
410
|
+
tk.Label(
|
|
411
|
+
win,
|
|
412
|
+
text="Font",
|
|
413
|
+
font=(self.font, 14),
|
|
414
|
+
bg=self.bgcolor,
|
|
415
|
+
fg="gray70"
|
|
416
|
+
).grid(row=2, column=0, padx = 30, sticky="w")
|
|
417
|
+
|
|
418
|
+
choice = tk.StringVar(value=self.font)
|
|
419
|
+
|
|
420
|
+
def change_font(event = None):
|
|
421
|
+
self.font = combo.get()
|
|
422
|
+
self.editor.configure(font = (self.font, self.fontsize))
|
|
423
|
+
self.update_clide()
|
|
424
|
+
|
|
425
|
+
fonts = sorted(tkfont.families())
|
|
426
|
+
combo = ttk.Combobox(
|
|
427
|
+
win,
|
|
428
|
+
textvariable=choice,
|
|
429
|
+
values=fonts,
|
|
430
|
+
state="readonly",
|
|
431
|
+
width=30,
|
|
432
|
+
)
|
|
433
|
+
combo.grid(row=2, column=1, padx=10, pady=5, sticky="w")
|
|
434
|
+
win.after(100, lambda: combo.set(self.font))
|
|
435
|
+
combo.bind("<<ComboboxSelected>>", change_font)
|
|
436
|
+
|
|
437
|
+
def paste_text(self, event=None):
|
|
438
|
+
start = self.editor.index("insert")
|
|
439
|
+
|
|
440
|
+
try:
|
|
441
|
+
data = self.editor.clipboard_get()
|
|
442
|
+
except tk.TclError:
|
|
443
|
+
return "break"
|
|
444
|
+
self.editor.insert("insert", data)
|
|
445
|
+
|
|
446
|
+
end = self.editor.index(f"{start}+{len(data)}c")
|
|
447
|
+
pasted_first_line = int(self.editor.index(start).split(".")[0])
|
|
448
|
+
pasted_last_line = int(self.editor.index(end).split(".")[0])
|
|
449
|
+
|
|
450
|
+
for line in range(pasted_first_line, pasted_last_line + 1):
|
|
451
|
+
self.syntax_highlight(f"{line}.0", f"{line}.end")
|
|
452
|
+
|
|
453
|
+
return "break"
|
|
454
|
+
|
|
455
|
+
def zoom_text(self, event=None):
|
|
456
|
+
if event:
|
|
457
|
+
if event.delta > 0:
|
|
458
|
+
if self.fontsize >= 80:
|
|
459
|
+
return
|
|
460
|
+
self.fontsize += 1
|
|
461
|
+
self.editor.configure(font=(self.font, self.fontsize, "bold"))
|
|
462
|
+
self.line_numbers_width += 1
|
|
463
|
+
self.line_numbers.configure(width = self.line_numbers_width)
|
|
464
|
+
self.update_clide()
|
|
465
|
+
|
|
466
|
+
elif event.delta < 0:
|
|
467
|
+
if self.fontsize <= 10:
|
|
468
|
+
return
|
|
469
|
+
self.fontsize -= 1
|
|
470
|
+
self.editor.configure(font=(self.font, self.fontsize, "bold"))
|
|
471
|
+
self.line_numbers_width -= 1
|
|
472
|
+
self.line_numbers.configure(width = self.line_numbers_width)
|
|
473
|
+
self.update_clide()
|
|
474
|
+
|
|
475
|
+
def indent_line(self, event=None):
|
|
476
|
+
line = self.editor.get("insert linestart", "insert")
|
|
477
|
+
|
|
478
|
+
indent = len(line) - len(line.lstrip(" "))
|
|
479
|
+
|
|
480
|
+
if line.rstrip().endswith(("{", ":")):
|
|
481
|
+
indent += self.indent_size
|
|
482
|
+
elif line.rstrip().endswith("}"):
|
|
483
|
+
indent -= self.indent_size
|
|
484
|
+
self.editor.insert("insert", "\n" + " " * indent)
|
|
485
|
+
return "break"
|
|
486
|
+
|
|
487
|
+
def syntax_highlight(self, start, end):
|
|
488
|
+
if self.multiline_comment:
|
|
489
|
+
self.editor.tag_add( "comment", start, end)
|
|
490
|
+
words = self.editor.get(start, end)
|
|
491
|
+
lc = len(words)
|
|
492
|
+
word = ""
|
|
493
|
+
in_string = False
|
|
494
|
+
in_char = False
|
|
495
|
+
in_preprocessor = False
|
|
496
|
+
string_start = 0
|
|
497
|
+
char_start = 0
|
|
498
|
+
for i in range(0, lc, 1):
|
|
499
|
+
if words[i] in (" ", "\t"):
|
|
500
|
+
continue
|
|
501
|
+
word += words[i]
|
|
502
|
+
if words[i:i+2] == "//" and not in_string and not in_preprocessor:
|
|
503
|
+
self.editor.tag_add( "comment", f"{start}+{i-1}c", end)
|
|
504
|
+
break
|
|
505
|
+
|
|
506
|
+
elif words[i:i+2] == "/*" and not in_string and not in_preprocessor:
|
|
507
|
+
self.multiline_comment = True
|
|
508
|
+
self.editor.tag_add( "comment", f"{start}+{i-1}c", end)
|
|
509
|
+
continue
|
|
510
|
+
|
|
511
|
+
elif words[i:i+2] == "*/" and not in_string and not in_preprocessor:
|
|
512
|
+
self.multiline_comment = False
|
|
513
|
+
continue
|
|
514
|
+
|
|
515
|
+
elif word in C_TYPES:
|
|
516
|
+
self.editor.tag_add( "type", f"{start}+{i-len(word)+1}c", f"{start}+{i+1}c")
|
|
517
|
+
word = ""
|
|
518
|
+
|
|
519
|
+
elif word in C_KEYWORDS:
|
|
520
|
+
self.editor.tag_add( "keyword", f"{start}+{i-len(word)+1}c", f"{start}+{i+1}c")
|
|
521
|
+
word = ""
|
|
522
|
+
|
|
523
|
+
elif word in C_FUNCTIONS:
|
|
524
|
+
self.editor.tag_add( "functions", f"{start}+{i-len(word)+1}c", f"{start}+{i+1}c")
|
|
525
|
+
word = ""
|
|
526
|
+
|
|
527
|
+
elif words[i] == '"':
|
|
528
|
+
if not in_string:
|
|
529
|
+
in_string = True
|
|
530
|
+
string_start = i
|
|
531
|
+
else:
|
|
532
|
+
in_string = False
|
|
533
|
+
self.editor.tag_add( "string", f"{start}+{string_start}c", f"{start}+{i+1}c")
|
|
534
|
+
word = ""
|
|
535
|
+
|
|
536
|
+
elif words[i] == "'":
|
|
537
|
+
if not in_char:
|
|
538
|
+
in_char = True
|
|
539
|
+
char_start = i
|
|
540
|
+
else:
|
|
541
|
+
in_char = False
|
|
542
|
+
self.editor.tag_add( "string", f"{start}+{char_start}c", f"{start}+{i+1}c")
|
|
543
|
+
word = ""
|
|
544
|
+
|
|
545
|
+
elif words[i] in "{}()[];,+-*=<>":
|
|
546
|
+
self.editor.tag_add( "brackets", f"{start}+{i}c", f"{start}+{i+1}c")
|
|
547
|
+
word = ""
|
|
548
|
+
|
|
549
|
+
elif words[i] in ".!%&|^~?:/":
|
|
550
|
+
# operators/punctuation not covered above (ternary, logical,
|
|
551
|
+
# bitwise, modulo, division, member access, etc.) aren't
|
|
552
|
+
# highlighted, but must still break the token so it doesn't
|
|
553
|
+
# glue onto the next identifier
|
|
554
|
+
word = ""
|
|
555
|
+
|
|
556
|
+
elif words[i:i+1] == "#":
|
|
557
|
+
self.editor.tag_add( "preprocessor", f"{start}+{i}c", end)
|
|
558
|
+
break
|
|
559
|
+
|
|
560
|
+
def update_clide(self, event=None):
|
|
561
|
+
start = self.editor.index("insert linestart")
|
|
562
|
+
end = self.editor.index("insert lineend")
|
|
563
|
+
self.syntax_highlight(start, end)
|
|
564
|
+
if self.editor.edit_modified() and self.file:
|
|
565
|
+
self.window.title(f"CLIDE - *{self.file}")
|
|
566
|
+
|
|
567
|
+
self.line_numbers.delete("all")
|
|
568
|
+
line_count = int(self.editor.index("end-1c").split(".")[0])
|
|
569
|
+
digits = len(str(line_count))
|
|
570
|
+
self.line_numbers.config(width=digits * self.fontsize + 1)
|
|
571
|
+
index = self.editor.index("@0,0")
|
|
572
|
+
|
|
573
|
+
while True:
|
|
574
|
+
info = self.editor.dlineinfo(index)
|
|
575
|
+
if info is None:
|
|
576
|
+
break
|
|
577
|
+
|
|
578
|
+
y = info[1]
|
|
579
|
+
line = index.split(".")[0]
|
|
580
|
+
|
|
581
|
+
self.line_numbers.create_text(5, y, font = (self.font, self.fontsize), fill=self.fgcolor, text=line, anchor="nw")
|
|
582
|
+
index = self.editor.index(f"{index}+1line")
|
|
583
|
+
|
|
584
|
+
def run_file(self, event=None):
|
|
585
|
+
if not self.file:
|
|
586
|
+
messagebox.showerror("No File", "Currently No File is opened")
|
|
587
|
+
return
|
|
588
|
+
exe = os.path.splitext(self.file)[0] + ".exe"
|
|
589
|
+
|
|
590
|
+
subprocess.Popen(f'cmd /k gcc "{self.file}" -o "{exe}" && "{exe}" & pause & exit', creationflags=subprocess.CREATE_NEW_CONSOLE)
|
|
591
|
+
|
|
592
|
+
def open_file(self, event=None):
|
|
593
|
+
filename = filedialog.askopenfilename(
|
|
594
|
+
filetypes=[
|
|
595
|
+
("All Files", "*.*")
|
|
596
|
+
]
|
|
597
|
+
)
|
|
598
|
+
if not filename:
|
|
599
|
+
return
|
|
600
|
+
|
|
601
|
+
size = os.path.getsize(filename)
|
|
602
|
+
size = size / 1024**2
|
|
603
|
+
if (size) > 1:
|
|
604
|
+
permission = messagebox.askyesno("Warning", f"Loading This File Could Take Time\n Size of the file is {size} mb\n Do you want to load it ?")
|
|
605
|
+
if not permission:
|
|
606
|
+
return
|
|
607
|
+
text = None
|
|
608
|
+
try:
|
|
609
|
+
with open(filename, "r", encoding="utf-8") as f:
|
|
610
|
+
text = f.read().expandtabs(4)
|
|
611
|
+
except Exception as e:
|
|
612
|
+
messagebox.showerror("Unable", f"Unable to Load File {e}")
|
|
613
|
+
|
|
614
|
+
self.editor.delete("1.0", "end")
|
|
615
|
+
self.editor.insert("1.0", text)
|
|
616
|
+
self.multiline_comment = False
|
|
617
|
+
last_line = int(self.editor.index("end-1c").split(".")[0])
|
|
618
|
+
|
|
619
|
+
for line in range(1, last_line + 1):
|
|
620
|
+
self.syntax_highlight(f"{line}.0", f"{line}.end")
|
|
621
|
+
|
|
622
|
+
self.file = filename
|
|
623
|
+
self.editor.edit_modified(False)
|
|
624
|
+
self.window.title(f"CLIDE - {self.file}")
|
|
625
|
+
self.update_clide()
|
|
626
|
+
|
|
627
|
+
def save_file(self, event=None):
|
|
628
|
+
if not self.file:
|
|
629
|
+
return
|
|
630
|
+
|
|
631
|
+
with open(self.file, "w", encoding="utf-8") as f:
|
|
632
|
+
f.write(self.editor.get("1.0", "end-1c"))
|
|
633
|
+
|
|
634
|
+
self.update_clide()
|
|
635
|
+
self.editor.edit_modified(False)
|
|
636
|
+
self.window.title(f"CLIDE - {self.file}")
|
|
637
|
+
|
|
638
|
+
def saveas_file(self, event=None):
|
|
639
|
+
path = filedialog.asksaveasfilename(
|
|
640
|
+
defaultextension=".c",
|
|
641
|
+
filetypes=[("C source", "*.c"), ("All Files", "*.*")]
|
|
642
|
+
)
|
|
643
|
+
if not path:
|
|
644
|
+
return
|
|
645
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
646
|
+
f.write(self.editor.get("1.0", "end-1c"))
|
|
647
|
+
self.file = path
|
|
648
|
+
self.editor.edit_modified(False)
|
|
649
|
+
self.window.title(f"CLIDE - {self.file}")
|
|
650
|
+
self.update_clide()
|
|
651
|
+
|
|
652
|
+
def main():
|
|
653
|
+
window = WINDOW()
|
|
654
|
+
window.window.mainloop()
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
if __name__ == "__main__":
|
|
658
|
+
main()
|
|
Binary file
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: clide-editor
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A tiny, no-frills C code editor built with Python + tkinter
|
|
5
|
+
Author: Moinak Debnath
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/findstring/clide
|
|
8
|
+
Project-URL: Repository, https://github.com/findstring/clide
|
|
9
|
+
Project-URL: Issues, https://github.com/findstring/clide/issues
|
|
10
|
+
Keywords: editor,c,ide,tkinter,syntax-highlighting
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Win32 (MS Windows)
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: C
|
|
16
|
+
Classifier: Topic :: Software Development
|
|
17
|
+
Classifier: Topic :: Text Editors
|
|
18
|
+
Requires-Python: >=3.9
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
> 🤖 **Note:** This README was written by Claude AI, because the dev (me) was too lazy to write one myself. The code, however, is 100% hand-written — except for the giant list of C keywords/types/functions used for syntax highlighting, which Claude also helped generate because who's memorizing `stdc_leading_zeros` for fun.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## What is this?
|
|
28
|
+
|
|
29
|
+
CLIDE is a lightweight library based C editor with syntax highlighting, line numbers, auto-indent, and a one-key "compile and run" workflow using `gcc`. No bloat, no plugins, no 400 MB Electron shell — just a `tkinter` window that gets out of your way.
|
|
30
|
+
|
|
31
|
+
Built mostly as a personal project / learning exercise, not (yet) a serious rival to VS Code.
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
- 🎨 **Syntax highlighting** for C — keywords, types, functions, strings, char literals, comments (single-line and block), numbers, and preprocessor directives
|
|
36
|
+
- 🔢 **Line numbers** that track scrolling and zoom
|
|
37
|
+
- 🔍 **Zoom in/out** with `Ctrl + Mouse Wheel`
|
|
38
|
+
- ⏎ **Auto-indent** — adds/removes indentation automatically after `{`, `}`, and `:`
|
|
39
|
+
- ▶️ **Run with F5** — compiles your file with `gcc` and runs it in a new console window
|
|
40
|
+
- 💾 **Open / Save / Save As** from the File menu or `Ctrl+O` / `Ctrl+S`
|
|
41
|
+
- 📋 **Paste-aware highlighting** — pasted multi-line code gets highlighted properly, not just the current line
|
|
42
|
+
- 🎨 **Style Configurator** — change background, foreground colour and also fonts
|
|
43
|
+
- 🖱️ Undo/redo support (unlimited undo history)
|
|
44
|
+
|
|
45
|
+
## Requirements
|
|
46
|
+
|
|
47
|
+
- Python 3.x with `tkinter` (usually bundled with Python on Windows)
|
|
48
|
+
- `gcc` installed and available on your system `PATH` (for the Run feature)
|
|
49
|
+
- Windows — the "Run" feature and maximized window launch currently rely on Windows-specific behavior (see Limitations below)
|
|
50
|
+
|
|
51
|
+
## Getting Started
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install clide-editor
|
|
55
|
+
python -m clide
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Open a `.c` file with `Ctrl+O`, write some code, hit `F5` to compile and run it.
|
|
59
|
+
|
|
60
|
+
## Version
|
|
61
|
+
|
|
62
|
+
**v0.1.0** — early days. Things work, but expect rough edges.
|
|
63
|
+
|
|
64
|
+
## Limitations
|
|
65
|
+
|
|
66
|
+
- **Windows-only for now.** The maximized-window launch and the `F5` run command (`cmd /k gcc ...`) both assume Windows. Running this on Linux/macOS will likely misbehave or crash on the run step.
|
|
67
|
+
- **Single-line-focused highlighting.** Typing re-highlights the line you're on; large structural edits elsewhere in the file (outside of paste) aren't automatically re-scanned.
|
|
68
|
+
- **No project/workspace support** — it's a single-file editor, not a full IDE. No multi-file tabs yet.
|
|
69
|
+
- **No build configuration** — compilation is a hardcoded `gcc file.c -o file.exe`, no custom flags, no Makefile support.
|
|
70
|
+
- **No autocomplete, linting, or error highlighting** — you find out about bugs when `gcc` yells at you.
|
|
71
|
+
- **No find & replace** yet.
|
|
72
|
+
|
|
73
|
+
## To Be Featured (Roadmap)
|
|
74
|
+
|
|
75
|
+
- [ ] Cross-platform support (Linux/macOS build + run)
|
|
76
|
+
- [ ] Find & Replace
|
|
77
|
+
- [ ] Multiple tabs / multi-file projects
|
|
78
|
+
- [ ] Custom compiler flags / build settings
|
|
79
|
+
- [ ] Bracket matching + auto-close brackets
|
|
80
|
+
- [ ] Inline error markers from `gcc` output
|
|
81
|
+
- [ ] Proper packaging (so you don't need Python installed to run it)
|
|
82
|
+
|
|
83
|
+
## Contributing
|
|
84
|
+
|
|
85
|
+
This is a small personal project, but if you spot a bug or have an idea, feel free to open an issue or PR.
|
|
86
|
+
|
|
87
|
+
## License
|
|
88
|
+
|
|
89
|
+
See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
clide/__init__.py
|
|
5
|
+
clide/__main__.py
|
|
6
|
+
clide/clide.py
|
|
7
|
+
clide/icons/logo.ico
|
|
8
|
+
clide_editor.egg-info/PKG-INFO
|
|
9
|
+
clide_editor.egg-info/SOURCES.txt
|
|
10
|
+
clide_editor.egg-info/dependency_links.txt
|
|
11
|
+
clide_editor.egg-info/entry_points.txt
|
|
12
|
+
clide_editor.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
clide
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "clide-editor"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A tiny, no-frills C code editor built with Python + tkinter"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.9"
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "Moinak Debnath" }
|
|
15
|
+
]
|
|
16
|
+
keywords = ["editor", "c", "ide", "tkinter", "syntax-highlighting"]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 3 - Alpha",
|
|
19
|
+
"Environment :: Win32 (MS Windows)",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: C",
|
|
23
|
+
"Topic :: Software Development",
|
|
24
|
+
"Topic :: Text Editors",
|
|
25
|
+
]
|
|
26
|
+
dependencies = []
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/findstring/clide"
|
|
30
|
+
Repository = "https://github.com/findstring/clide"
|
|
31
|
+
Issues = "https://github.com/findstring/clide/issues"
|
|
32
|
+
|
|
33
|
+
[project.scripts]
|
|
34
|
+
clide = "clide:main"
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.package-data]
|
|
37
|
+
clide = ["icons/*.ico"]
|