mos-tui 1.0.0 → 1.0.2
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.
- package/core/OS_CP.c +6 -2
- package/core/mos.sh +12 -13
- package/core/mos_tui.py +109 -42
- package/output.txt +0 -0
- package/package.json +2 -2
package/core/OS_CP.c
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#include<stdio.h>
|
|
2
2
|
#include <stdbool.h>
|
|
3
3
|
#include<time.h>
|
|
4
|
+
#include <stdlib.h>
|
|
4
5
|
|
|
5
6
|
// Declaring the required Memory and Registers
|
|
6
7
|
char M[100][4]; // main storage of size 100 x 4
|
|
@@ -261,8 +262,11 @@ int main() {
|
|
|
261
262
|
|
|
262
263
|
start = clock();
|
|
263
264
|
|
|
264
|
-
|
|
265
|
-
|
|
265
|
+
char *infile = getenv("MOS_INPUT");
|
|
266
|
+
char *outfile = getenv("MOS_OUTPUT");
|
|
267
|
+
|
|
268
|
+
fin = fopen(infile ? infile : "input.txt", "r");
|
|
269
|
+
fout = fopen(outfile ? outfile : "output.txt", "w");
|
|
266
270
|
|
|
267
271
|
if (fin == NULL) {
|
|
268
272
|
printf("Input file not found\n");
|
package/core/mos.sh
CHANGED
|
@@ -4,41 +4,40 @@
|
|
|
4
4
|
# Usage: ./mos.sh
|
|
5
5
|
# Run from the same directory as OS_CP.c
|
|
6
6
|
# ─────────────────────────────────────────────────────────────
|
|
7
|
-
|
|
8
7
|
set -e
|
|
9
8
|
|
|
10
9
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
10
|
TUI="$SCRIPT_DIR/mos_tui.py"
|
|
11
|
+
PROJECT_DIR="$(pwd)" # where the user IS standing — must have OS_CP.c
|
|
12
12
|
|
|
13
13
|
# Check Python 3
|
|
14
14
|
if ! command -v python3 &>/dev/null; then
|
|
15
|
-
echo "python3 not found. Install
|
|
15
|
+
echo "python3 not found. Install: sudo apt install python3"
|
|
16
16
|
exit 1
|
|
17
17
|
fi
|
|
18
18
|
|
|
19
19
|
# Check gcc
|
|
20
20
|
if ! command -v gcc &>/dev/null; then
|
|
21
|
-
echo "gcc not found. Install
|
|
21
|
+
echo "gcc not found. Install: sudo apt install gcc"
|
|
22
22
|
exit 1
|
|
23
23
|
fi
|
|
24
24
|
|
|
25
|
-
#
|
|
26
|
-
if [ ! -f "OS_CP.c" ]; then
|
|
27
|
-
echo "
|
|
28
|
-
echo "
|
|
29
|
-
echo " Launching TUI anyway — you can still use it without the source."
|
|
25
|
+
# Warn if OS_CP.c is missing
|
|
26
|
+
if [ ! -f "$PROJECT_DIR/OS_CP.c" ]; then
|
|
27
|
+
echo "WARNING: OS_CP.c not found in: $PROJECT_DIR"
|
|
28
|
+
echo " cd into the folder that contains OS_CP.c, then run mos.sh again."
|
|
30
29
|
fi
|
|
31
30
|
|
|
32
|
-
# Ensure the TUI script is alongside
|
|
33
31
|
if [ ! -f "$TUI" ]; then
|
|
34
|
-
echo "
|
|
32
|
+
echo "mos_tui.py not found at: $TUI"
|
|
35
33
|
exit 1
|
|
36
34
|
fi
|
|
37
35
|
|
|
38
|
-
# Set up terminal properly
|
|
39
36
|
export TERM="${TERM:-xterm-256color}"
|
|
40
37
|
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
# cd into the project dir so Python's os.getcwd() == where OS_CP.c is
|
|
39
|
+
cd "$PROJECT_DIR"
|
|
43
40
|
|
|
41
|
+
echo "Starting MOS Terminal UI..."
|
|
42
|
+
sleep 0.2
|
|
44
43
|
python3 "$TUI"
|
package/core/mos_tui.py
CHANGED
|
@@ -28,8 +28,45 @@ C_INPUT = 9 # green on black (input text)
|
|
|
28
28
|
C_ORANGE = 10 # yellow bright (used for EXEC tags)
|
|
29
29
|
C_STAT_VAL = 11 # cyan bold for stat values
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
# Locate OS_CP.c by searching:
|
|
32
|
+
# 1. Directory explicitly set via MOS_SOURCE env var
|
|
33
|
+
# 2. Current working directory
|
|
34
|
+
# 3. Walk UP from cwd (handles npm package subdirectory installs)
|
|
35
|
+
# 4. Walk UP from script location
|
|
36
|
+
def _find_source():
|
|
37
|
+
# Env override — highest priority
|
|
38
|
+
env_src = os.environ.get("MOS_SOURCE")
|
|
39
|
+
if env_src and os.path.exists(env_src):
|
|
40
|
+
return os.path.abspath(env_src)
|
|
41
|
+
|
|
42
|
+
# Search upward from cwd
|
|
43
|
+
search = os.getcwd()
|
|
44
|
+
for _ in range(6):
|
|
45
|
+
candidate = os.path.join(search, "OS_CP.c")
|
|
46
|
+
if os.path.exists(candidate):
|
|
47
|
+
return candidate
|
|
48
|
+
parent = os.path.dirname(search)
|
|
49
|
+
if parent == search:
|
|
50
|
+
break
|
|
51
|
+
search = parent
|
|
52
|
+
|
|
53
|
+
# Search upward from script location
|
|
54
|
+
search = os.path.dirname(os.path.abspath(__file__))
|
|
55
|
+
for _ in range(6):
|
|
56
|
+
candidate = os.path.join(search, "OS_CP.c")
|
|
57
|
+
if os.path.exists(candidate):
|
|
58
|
+
return candidate
|
|
59
|
+
parent = os.path.dirname(search)
|
|
60
|
+
if parent == search:
|
|
61
|
+
break
|
|
62
|
+
search = parent
|
|
63
|
+
|
|
64
|
+
# Fallback — cwd (will show a clear error)
|
|
65
|
+
return os.path.join(os.getcwd(), "OS_CP.c")
|
|
66
|
+
|
|
67
|
+
SOURCE = _find_source()
|
|
68
|
+
_CWD = os.path.dirname(SOURCE) # always the folder that contains OS_CP.c
|
|
69
|
+
BINARY = os.path.join(_CWD, "mos_bin")
|
|
33
70
|
|
|
34
71
|
# ── STATE ─────────────────────────────────────────────────────────────────────
|
|
35
72
|
class State:
|
|
@@ -64,12 +101,14 @@ state = State()
|
|
|
64
101
|
# ── COMPILE ───────────────────────────────────────────────────────────────────
|
|
65
102
|
def compile_source():
|
|
66
103
|
if not os.path.exists(SOURCE):
|
|
67
|
-
state.
|
|
68
|
-
state.add_debug("
|
|
104
|
+
state.add_debug("ERR", f"OS_CP.c not found at: {SOURCE}")
|
|
105
|
+
state.add_debug("WARN", f"Run this tool from the folder containing OS_CP.c")
|
|
106
|
+
state.add_debug("WARN", f"Current dir: {_CWD}")
|
|
69
107
|
return False
|
|
70
108
|
state.add_debug("INFO", f"Compiling {SOURCE}...")
|
|
71
109
|
result = subprocess.run(
|
|
72
110
|
["gcc", "-o", BINARY, SOURCE, "-lm"],
|
|
111
|
+
cwd=_CWD,
|
|
73
112
|
capture_output=True, text=True
|
|
74
113
|
)
|
|
75
114
|
if result.returncode != 0:
|
|
@@ -87,24 +126,32 @@ def run_program(input_text, callback):
|
|
|
87
126
|
state.status = "RUNNING"
|
|
88
127
|
state.add_debug("INFO", f"─── Run #{state.run_count} started ───")
|
|
89
128
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
129
|
+
# Use a dedicated temp directory so input.txt and output.txt are isolated
|
|
130
|
+
run_dir = tempfile.mkdtemp(prefix='mos_run_')
|
|
131
|
+
fin_path = os.path.join(run_dir, "input.txt")
|
|
132
|
+
fout_path = os.path.join(run_dir, "output.txt")
|
|
133
|
+
|
|
134
|
+
with open(fin_path, 'w') as f:
|
|
135
|
+
f.write(input_text)
|
|
93
136
|
|
|
94
|
-
|
|
137
|
+
state.add_debug("INFO", f"Input written → {fin_path}")
|
|
95
138
|
|
|
96
139
|
t0 = time.perf_counter()
|
|
97
140
|
try:
|
|
98
141
|
result = subprocess.run(
|
|
99
142
|
[BINARY],
|
|
100
|
-
stdin=open(fin_path),
|
|
101
143
|
capture_output=True,
|
|
102
144
|
text=True,
|
|
103
145
|
timeout=10,
|
|
104
|
-
|
|
146
|
+
cwd=run_dir, # binary runs inside temp dir
|
|
147
|
+
env={**os.environ,
|
|
148
|
+
'MOS_INPUT': fin_path, # env var override (your updated C uses this)
|
|
149
|
+
'MOS_OUTPUT': fout_path}
|
|
105
150
|
)
|
|
106
151
|
elapsed_ms = (time.perf_counter() - t0) * 1000
|
|
107
152
|
|
|
153
|
+
state.add_debug("INFO", f"Process exited (code={result.returncode})")
|
|
154
|
+
|
|
108
155
|
# Parse stdout debug lines from the C program
|
|
109
156
|
for line in result.stdout.strip().splitlines():
|
|
110
157
|
line = line.strip()
|
|
@@ -131,20 +178,32 @@ def run_program(input_text, callback):
|
|
|
131
178
|
for line in result.stderr.strip().splitlines():
|
|
132
179
|
state.add_debug("ERR", line)
|
|
133
180
|
|
|
134
|
-
# Read output.txt
|
|
181
|
+
# Read output.txt from the run directory (guaranteed location)
|
|
135
182
|
output_content = []
|
|
136
|
-
if os.path.exists(
|
|
137
|
-
with open("output.txt") as f:
|
|
138
|
-
output_content = f.read().splitlines()
|
|
139
|
-
elif os.path.exists(fout_path):
|
|
183
|
+
if os.path.exists(fout_path):
|
|
140
184
|
with open(fout_path) as f:
|
|
141
185
|
output_content = f.read().splitlines()
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
state.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
186
|
+
state.add_debug("OK", f"Output read from {fout_path} ({len(output_content)} lines)")
|
|
187
|
+
else:
|
|
188
|
+
state.add_debug("WARN", f"output.txt not created at {fout_path}")
|
|
189
|
+
|
|
190
|
+
# Debug: show raw repr of each line so we can see spaces vs real content
|
|
191
|
+
for idx, line in enumerate(output_content):
|
|
192
|
+
stripped = line.rstrip()
|
|
193
|
+
if stripped:
|
|
194
|
+
state.add_output(stripped)
|
|
195
|
+
else:
|
|
196
|
+
# Don't add pure-blank lines from TERMINATE()'s \n\n — skip them
|
|
197
|
+
# but log them so user can see in debug
|
|
198
|
+
state.add_debug("INFO", f"output line {idx+1}: (blank/whitespace only)")
|
|
199
|
+
|
|
200
|
+
if result.returncode == 0:
|
|
201
|
+
if not output_content:
|
|
202
|
+
state.add_output("[output.txt was empty — check your PD instruction address]")
|
|
203
|
+
elif not any(l.strip() for l in output_content):
|
|
204
|
+
state.add_output("[output.txt had only blank lines — PD address may point to empty memory]")
|
|
205
|
+
state.add_debug("WARN", "All output lines were blank — GD and PD addresses must match")
|
|
206
|
+
state.add_debug("WARN", "e.g. GD10 reads into addr 10-19, so use PD10 to print it")
|
|
148
207
|
|
|
149
208
|
state.exec_time_ms = elapsed_ms
|
|
150
209
|
state.run_history.append((f"Run #{state.run_count}", elapsed_ms))
|
|
@@ -158,7 +217,8 @@ def run_program(input_text, callback):
|
|
|
158
217
|
state.add_debug("ERR", f"Runner error: {e}")
|
|
159
218
|
state.status = "ERROR"
|
|
160
219
|
finally:
|
|
161
|
-
|
|
220
|
+
import shutil
|
|
221
|
+
try: shutil.rmtree(run_dir, ignore_errors=True)
|
|
162
222
|
except: pass
|
|
163
223
|
|
|
164
224
|
callback()
|
|
@@ -300,10 +360,14 @@ def draw_output_panel(win, active):
|
|
|
300
360
|
fill_line(win, y)
|
|
301
361
|
if li < len(lines):
|
|
302
362
|
line = lines[li]
|
|
363
|
+
# line number gutter
|
|
364
|
+
gutter = f"{li+1:3} "
|
|
365
|
+
safe_addstr(win, y, 1, gutter, curses.color_pair(C_DIM))
|
|
303
366
|
col = curses.color_pair(C_GREEN)
|
|
304
367
|
if not line.strip():
|
|
305
|
-
|
|
306
|
-
|
|
368
|
+
safe_addstr(win, y, 5, "~", curses.color_pair(C_DIM))
|
|
369
|
+
else:
|
|
370
|
+
safe_addstr(win, y, 5, line[:inner_w-5], col)
|
|
307
371
|
|
|
308
372
|
# ── PANEL: CHART ──────────────────────────────────────────────────────────────
|
|
309
373
|
SPARK_CHARS = " ▁▂▃▄▅▆▇█"
|
|
@@ -434,33 +498,34 @@ def draw_titlebar(stdscr, W):
|
|
|
434
498
|
|
|
435
499
|
# ── SAMPLE PROGRAMS ───────────────────────────────────────────────────────────
|
|
436
500
|
SAMPLES = [
|
|
501
|
+
# Sample 1: Read data into addr 10, print from addr 10
|
|
437
502
|
"""$AMJ
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
SR30
|
|
441
|
-
LR30
|
|
442
|
-
PD30
|
|
503
|
+
GD10
|
|
504
|
+
PD10
|
|
443
505
|
H
|
|
444
506
|
$DTA
|
|
445
|
-
Hello MOS!
|
|
507
|
+
Hello MOS!
|
|
446
508
|
$END""",
|
|
509
|
+
# Sample 2: Read two lines, print both
|
|
447
510
|
"""$AMJ
|
|
448
511
|
GD10
|
|
449
512
|
PD10
|
|
450
|
-
|
|
451
|
-
|
|
513
|
+
GD30
|
|
514
|
+
PD30
|
|
452
515
|
H
|
|
453
516
|
$DTA
|
|
454
|
-
First
|
|
455
|
-
Second
|
|
517
|
+
First Line
|
|
518
|
+
Second Line
|
|
456
519
|
$END""",
|
|
520
|
+
# Sample 3: Load, store, compare, branch
|
|
457
521
|
"""$AMJ
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
522
|
+
GD10
|
|
523
|
+
LR10
|
|
524
|
+
SR20
|
|
525
|
+
PD20
|
|
462
526
|
H
|
|
463
527
|
$DTA
|
|
528
|
+
Stored Data
|
|
464
529
|
$END""",
|
|
465
530
|
]
|
|
466
531
|
_sample_idx = [0]
|
|
@@ -573,12 +638,12 @@ def main(stdscr):
|
|
|
573
638
|
stdscr.keypad(True)
|
|
574
639
|
|
|
575
640
|
state.add_debug("INFO", "MOS Terminal UI started")
|
|
576
|
-
state.add_debug("INFO", f"
|
|
641
|
+
state.add_debug("INFO", f"Working dir: {_CWD}")
|
|
577
642
|
if os.path.exists(SOURCE):
|
|
578
|
-
state.add_debug("OK", f"Found
|
|
643
|
+
state.add_debug("OK", f"Found OS_CP.c — press F6 to compile")
|
|
579
644
|
else:
|
|
580
|
-
state.add_debug("
|
|
581
|
-
state.add_debug("WARN", "
|
|
645
|
+
state.add_debug("ERR", f"OS_CP.c not found in: {_CWD}")
|
|
646
|
+
state.add_debug("WARN", "cd into your project folder, then rerun ./mos.sh")
|
|
582
647
|
|
|
583
648
|
load_sample()
|
|
584
649
|
|
|
@@ -675,6 +740,8 @@ def main(stdscr):
|
|
|
675
740
|
state.debug_scroll = 0
|
|
676
741
|
|
|
677
742
|
def done():
|
|
743
|
+
state.focus = 2 # auto-switch to Output panel
|
|
744
|
+
state.output_scroll = 0 # scroll to top of output
|
|
678
745
|
redraw()
|
|
679
746
|
|
|
680
747
|
t = threading.Thread(target=run_program, args=(input_text, done), daemon=True)
|
package/output.txt
ADDED
|
File without changes
|
package/package.json
CHANGED