teek 0.1.0
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.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +139 -0
- data/Rakefile +316 -0
- data/ext/teek/extconf.rb +79 -0
- data/ext/teek/stubs.h +33 -0
- data/ext/teek/tcl9compat.h +211 -0
- data/ext/teek/tcltkbridge.c +1597 -0
- data/ext/teek/tcltkbridge.h +42 -0
- data/ext/teek/tkfont.c +218 -0
- data/ext/teek/tkphoto.c +477 -0
- data/ext/teek/tkwin.c +144 -0
- data/lib/teek/background_none.rb +158 -0
- data/lib/teek/background_ractor4x.rb +410 -0
- data/lib/teek/background_thread.rb +272 -0
- data/lib/teek/debugger.rb +742 -0
- data/lib/teek/demo_support.rb +150 -0
- data/lib/teek/ractor_support.rb +246 -0
- data/lib/teek/version.rb +5 -0
- data/lib/teek.rb +540 -0
- data/sample/calculator.rb +260 -0
- data/sample/debug_demo.rb +45 -0
- data/sample/goldberg.rb +1803 -0
- data/sample/goldberg_helpers.rb +170 -0
- data/sample/minesweeper/assets/MINESWEEPER_0.png +0 -0
- data/sample/minesweeper/assets/MINESWEEPER_1.png +0 -0
- data/sample/minesweeper/assets/MINESWEEPER_2.png +0 -0
- data/sample/minesweeper/assets/MINESWEEPER_3.png +0 -0
- data/sample/minesweeper/assets/MINESWEEPER_4.png +0 -0
- data/sample/minesweeper/assets/MINESWEEPER_5.png +0 -0
- data/sample/minesweeper/assets/MINESWEEPER_6.png +0 -0
- data/sample/minesweeper/assets/MINESWEEPER_7.png +0 -0
- data/sample/minesweeper/assets/MINESWEEPER_8.png +0 -0
- data/sample/minesweeper/assets/MINESWEEPER_F.png +0 -0
- data/sample/minesweeper/assets/MINESWEEPER_M.png +0 -0
- data/sample/minesweeper/assets/MINESWEEPER_X.png +0 -0
- data/sample/minesweeper/minesweeper.rb +452 -0
- data/sample/threading_demo.rb +499 -0
- data/teek.gemspec +32 -0
- metadata +179 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/* tcltkbridge.h - Shared definitions for tk-ng C extension
|
|
2
|
+
*
|
|
3
|
+
* This header provides shared types and functions for the tcltklib extension,
|
|
4
|
+
* allowing code to be split across multiple .c files.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
#ifndef TCLTKBRIDGE_H
|
|
8
|
+
#define TCLTKBRIDGE_H
|
|
9
|
+
|
|
10
|
+
#include <ruby.h>
|
|
11
|
+
#include <tcl.h>
|
|
12
|
+
#include <tk.h>
|
|
13
|
+
#include "tcl9compat.h"
|
|
14
|
+
|
|
15
|
+
/* Interp struct stored in Ruby object */
|
|
16
|
+
struct tcltk_interp {
|
|
17
|
+
Tcl_Interp *interp;
|
|
18
|
+
int deleted;
|
|
19
|
+
VALUE callbacks; /* Hash: id_string => proc (GC-marked) */
|
|
20
|
+
VALUE thread_queue; /* Array: pending procs from other threads (GC-marked) */
|
|
21
|
+
unsigned long next_id; /* Next callback ID */
|
|
22
|
+
int timer_interval_ms; /* Mainloop timer interval for thread yielding */
|
|
23
|
+
Tcl_ThreadId main_thread_id; /* Thread that created the interp */
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/* Shared globals - defined in tcltkbridge.c */
|
|
27
|
+
extern VALUE eTclError;
|
|
28
|
+
extern const rb_data_type_t interp_type;
|
|
29
|
+
|
|
30
|
+
/* Get interpreter from Ruby object, raising if deleted */
|
|
31
|
+
struct tcltk_interp *get_interp(VALUE self);
|
|
32
|
+
|
|
33
|
+
/* Photo image functions - defined in tkphoto.c */
|
|
34
|
+
void Init_tkphoto(VALUE cInterp);
|
|
35
|
+
|
|
36
|
+
/* Font functions - defined in tkfont.c */
|
|
37
|
+
void Init_tkfont(VALUE cInterp);
|
|
38
|
+
|
|
39
|
+
/* Tk window query functions - defined in tkwin.c */
|
|
40
|
+
void Init_tkwin(VALUE cInterp);
|
|
41
|
+
|
|
42
|
+
#endif /* TCLTKBRIDGE_H */
|
data/ext/teek/tkfont.c
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/* tkfont.c - Font measurement C functions for tk-ng
|
|
2
|
+
*
|
|
3
|
+
* Fast font and text measurement using Tk's font C API.
|
|
4
|
+
* These functions bypass Tcl string parsing for better performance.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
#include "tcltkbridge.h"
|
|
8
|
+
|
|
9
|
+
/* ---------------------------------------------------------
|
|
10
|
+
* Interp#text_width(font_name, text)
|
|
11
|
+
*
|
|
12
|
+
* Measure pixel width of text string using Tk_TextWidth.
|
|
13
|
+
* Faster than querying via Tcl font measure command.
|
|
14
|
+
*
|
|
15
|
+
* Arguments:
|
|
16
|
+
* font_name - Font description string (e.g., "Helvetica 12", "TkDefaultFont")
|
|
17
|
+
* text - Text string to measure
|
|
18
|
+
*
|
|
19
|
+
* Returns integer pixel width.
|
|
20
|
+
*
|
|
21
|
+
* See: https://www.tcl-lang.org/man/tcl9.0/TkLib/MeasureChar.html
|
|
22
|
+
* --------------------------------------------------------- */
|
|
23
|
+
|
|
24
|
+
static VALUE
|
|
25
|
+
interp_text_width(VALUE self, VALUE font_name, VALUE text)
|
|
26
|
+
{
|
|
27
|
+
struct tcltk_interp *tip = get_interp(self);
|
|
28
|
+
Tk_Window mainWin;
|
|
29
|
+
Tk_Font tkfont;
|
|
30
|
+
const char *font_str;
|
|
31
|
+
const char *text_str;
|
|
32
|
+
int width;
|
|
33
|
+
|
|
34
|
+
StringValue(font_name);
|
|
35
|
+
StringValue(text);
|
|
36
|
+
|
|
37
|
+
font_str = StringValueCStr(font_name);
|
|
38
|
+
text_str = StringValueCStr(text);
|
|
39
|
+
|
|
40
|
+
/* Get the main window for font allocation */
|
|
41
|
+
mainWin = Tk_MainWindow(tip->interp);
|
|
42
|
+
if (!mainWin) {
|
|
43
|
+
rb_raise(eTclError, "Tk not initialized (no main window)");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Get the font */
|
|
47
|
+
tkfont = Tk_GetFont(tip->interp, mainWin, font_str);
|
|
48
|
+
if (!tkfont) {
|
|
49
|
+
rb_raise(eTclError, "font not found: %s - %s",
|
|
50
|
+
font_str, Tcl_GetStringResult(tip->interp));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Measure the text width */
|
|
54
|
+
width = Tk_TextWidth(tkfont, text_str, (int)strlen(text_str));
|
|
55
|
+
|
|
56
|
+
/* Release the font */
|
|
57
|
+
Tk_FreeFont(tkfont);
|
|
58
|
+
|
|
59
|
+
return INT2NUM(width);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* ---------------------------------------------------------
|
|
63
|
+
* Interp#font_metrics(font_name)
|
|
64
|
+
*
|
|
65
|
+
* Get font metrics using Tk_GetFontMetrics.
|
|
66
|
+
* Faster than querying via Tcl font metrics command.
|
|
67
|
+
*
|
|
68
|
+
* Arguments:
|
|
69
|
+
* font_name - Font description string (e.g., "Helvetica 12", "TkDefaultFont")
|
|
70
|
+
*
|
|
71
|
+
* Returns Hash with:
|
|
72
|
+
* :ascent - Pixels from baseline to top of highest character
|
|
73
|
+
* :descent - Pixels from baseline to bottom of lowest character
|
|
74
|
+
* :linespace - Total line height (ascent + descent)
|
|
75
|
+
*
|
|
76
|
+
* See: https://www.tcl-lang.org/man/tcl9.0/TkLib/FontId.html
|
|
77
|
+
* --------------------------------------------------------- */
|
|
78
|
+
|
|
79
|
+
static VALUE
|
|
80
|
+
interp_font_metrics(VALUE self, VALUE font_name)
|
|
81
|
+
{
|
|
82
|
+
struct tcltk_interp *tip = get_interp(self);
|
|
83
|
+
Tk_Window mainWin;
|
|
84
|
+
Tk_Font tkfont;
|
|
85
|
+
Tk_FontMetrics fm;
|
|
86
|
+
const char *font_str;
|
|
87
|
+
VALUE result;
|
|
88
|
+
|
|
89
|
+
StringValue(font_name);
|
|
90
|
+
font_str = StringValueCStr(font_name);
|
|
91
|
+
|
|
92
|
+
/* Get the main window for font allocation */
|
|
93
|
+
mainWin = Tk_MainWindow(tip->interp);
|
|
94
|
+
if (!mainWin) {
|
|
95
|
+
rb_raise(eTclError, "Tk not initialized (no main window)");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* Get the font */
|
|
99
|
+
tkfont = Tk_GetFont(tip->interp, mainWin, font_str);
|
|
100
|
+
if (!tkfont) {
|
|
101
|
+
rb_raise(eTclError, "font not found: %s - %s",
|
|
102
|
+
font_str, Tcl_GetStringResult(tip->interp));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* Get font metrics */
|
|
106
|
+
Tk_GetFontMetrics(tkfont, &fm);
|
|
107
|
+
|
|
108
|
+
/* Build result hash */
|
|
109
|
+
result = rb_hash_new();
|
|
110
|
+
rb_hash_aset(result, ID2SYM(rb_intern("ascent")), INT2NUM(fm.ascent));
|
|
111
|
+
rb_hash_aset(result, ID2SYM(rb_intern("descent")), INT2NUM(fm.descent));
|
|
112
|
+
rb_hash_aset(result, ID2SYM(rb_intern("linespace")), INT2NUM(fm.linespace));
|
|
113
|
+
|
|
114
|
+
/* Release the font */
|
|
115
|
+
Tk_FreeFont(tkfont);
|
|
116
|
+
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* ---------------------------------------------------------
|
|
121
|
+
* Interp#measure_chars(font_name, text, max_pixels, opts={})
|
|
122
|
+
*
|
|
123
|
+
* Measure how many characters/bytes of text fit within a pixel width limit.
|
|
124
|
+
* Useful for text truncation, ellipsis, and line wrapping.
|
|
125
|
+
*
|
|
126
|
+
* Arguments:
|
|
127
|
+
* font_name - Font description string (e.g., "Helvetica 12")
|
|
128
|
+
* text - Text string to measure
|
|
129
|
+
* max_pixels - Maximum pixel width allowed (-1 for unlimited)
|
|
130
|
+
* opts - Optional hash:
|
|
131
|
+
* :partial_ok - Allow partial character at boundary (default: false)
|
|
132
|
+
* :whole_words - Break only at word boundaries (default: false)
|
|
133
|
+
* :at_least_one - Always return at least one character (default: false)
|
|
134
|
+
*
|
|
135
|
+
* Returns Hash with:
|
|
136
|
+
* :bytes - Number of bytes that fit within max_pixels
|
|
137
|
+
* :width - Actual pixel width of those bytes
|
|
138
|
+
*
|
|
139
|
+
* See: https://www.tcl-lang.org/man/tcl9.0/TkLib/MeasureChar.html
|
|
140
|
+
* --------------------------------------------------------- */
|
|
141
|
+
|
|
142
|
+
static VALUE
|
|
143
|
+
interp_measure_chars(int argc, VALUE *argv, VALUE self)
|
|
144
|
+
{
|
|
145
|
+
struct tcltk_interp *tip = get_interp(self);
|
|
146
|
+
VALUE font_name, text, max_pixels_val, opts;
|
|
147
|
+
Tk_Window mainWin;
|
|
148
|
+
Tk_Font tkfont;
|
|
149
|
+
const char *font_str;
|
|
150
|
+
const char *text_str;
|
|
151
|
+
int max_pixels;
|
|
152
|
+
int flags;
|
|
153
|
+
int length;
|
|
154
|
+
int num_bytes;
|
|
155
|
+
VALUE result;
|
|
156
|
+
|
|
157
|
+
rb_scan_args(argc, argv, "31", &font_name, &text, &max_pixels_val, &opts);
|
|
158
|
+
|
|
159
|
+
StringValue(font_name);
|
|
160
|
+
StringValue(text);
|
|
161
|
+
|
|
162
|
+
font_str = StringValueCStr(font_name);
|
|
163
|
+
text_str = StringValueCStr(text);
|
|
164
|
+
max_pixels = NUM2INT(max_pixels_val);
|
|
165
|
+
|
|
166
|
+
/* Parse flags from options */
|
|
167
|
+
flags = 0;
|
|
168
|
+
if (!NIL_P(opts) && TYPE(opts) == T_HASH) {
|
|
169
|
+
VALUE val;
|
|
170
|
+
val = rb_hash_aref(opts, ID2SYM(rb_intern("partial_ok")));
|
|
171
|
+
if (RTEST(val)) flags |= TK_PARTIAL_OK;
|
|
172
|
+
val = rb_hash_aref(opts, ID2SYM(rb_intern("whole_words")));
|
|
173
|
+
if (RTEST(val)) flags |= TK_WHOLE_WORDS;
|
|
174
|
+
val = rb_hash_aref(opts, ID2SYM(rb_intern("at_least_one")));
|
|
175
|
+
if (RTEST(val)) flags |= TK_AT_LEAST_ONE;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* Get the main window for font allocation */
|
|
179
|
+
mainWin = Tk_MainWindow(tip->interp);
|
|
180
|
+
if (!mainWin) {
|
|
181
|
+
rb_raise(eTclError, "Tk not initialized (no main window)");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* Get the font */
|
|
185
|
+
tkfont = Tk_GetFont(tip->interp, mainWin, font_str);
|
|
186
|
+
if (!tkfont) {
|
|
187
|
+
rb_raise(eTclError, "font not found: %s - %s",
|
|
188
|
+
font_str, Tcl_GetStringResult(tip->interp));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/* Measure characters */
|
|
192
|
+
num_bytes = Tk_MeasureChars(tkfont, text_str, (int)strlen(text_str),
|
|
193
|
+
max_pixels, flags, &length);
|
|
194
|
+
|
|
195
|
+
/* Release the font */
|
|
196
|
+
Tk_FreeFont(tkfont);
|
|
197
|
+
|
|
198
|
+
/* Build result hash */
|
|
199
|
+
result = rb_hash_new();
|
|
200
|
+
rb_hash_aset(result, ID2SYM(rb_intern("bytes")), INT2NUM(num_bytes));
|
|
201
|
+
rb_hash_aset(result, ID2SYM(rb_intern("width")), INT2NUM(length));
|
|
202
|
+
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* ---------------------------------------------------------
|
|
207
|
+
* Init_tkfont - Register font methods on Teek::Interp class
|
|
208
|
+
*
|
|
209
|
+
* Called from Init_tcltklib in tcltkbridge.c
|
|
210
|
+
* --------------------------------------------------------- */
|
|
211
|
+
|
|
212
|
+
void
|
|
213
|
+
Init_tkfont(VALUE cInterp)
|
|
214
|
+
{
|
|
215
|
+
rb_define_method(cInterp, "text_width", interp_text_width, 2);
|
|
216
|
+
rb_define_method(cInterp, "font_metrics", interp_font_metrics, 1);
|
|
217
|
+
rb_define_method(cInterp, "measure_chars", interp_measure_chars, -1);
|
|
218
|
+
}
|