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 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
- fin = fopen("input.txt", "r");
265
- fout = fopen("output.txt", "w");
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 it with: sudo apt install python3"
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 it with: sudo apt install gcc"
21
+ echo "gcc not found. Install: sudo apt install gcc"
22
22
  exit 1
23
23
  fi
24
24
 
25
- # Check OS_CP.c exists in current dir
26
- if [ ! -f "OS_CP.c" ]; then
27
- echo " OS_CP.c not found in current directory."
28
- echo " Place OS_CP.c here or cd into the right folder, then re-run."
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 " mos_tui.py not found at: $TUI"
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
- echo " Starting MOS Terminal UI..."
42
- sleep 0.3
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
- BINARY = "./mos_bin"
32
- SOURCE = "OS_CP.c"
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.compile_error = f"'{SOURCE}' not found in current directory."
68
- state.add_debug("ERR", f"Source file {SOURCE} not found")
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
- with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False, prefix='mos_in_') as fin:
91
- fin.write(input_text)
92
- fin_path = fin.name
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
- fout_path = fin_path.replace('mos_in_', 'mos_out_').replace('.txt', '_out.txt')
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
- env={**os.environ, 'MOS_INPUT': fin_path, 'MOS_OUTPUT': fout_path}
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 if it was produced
181
+ # Read output.txt from the run directory (guaranteed location)
135
182
  output_content = []
136
- if os.path.exists("output.txt"):
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
- for line in output_content:
144
- state.add_output(line)
145
-
146
- if not output_content and result.returncode == 0:
147
- state.add_output("[No output written check PD instruction addresses]")
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
- try: os.unlink(fin_path)
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
- col = curses.color_pair(C_DIM)
306
- safe_addstr(win, y, 1, line[:inner_w], col)
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
- LR10
439
- GD20
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
- GD20
451
- PD20
513
+ GD30
514
+ PD30
452
515
  H
453
516
  $DTA
454
- First Data
455
- Second Data
517
+ First Line
518
+ Second Line
456
519
  $END""",
520
+ # Sample 3: Load, store, compare, branch
457
521
  """$AMJ
458
- LR05
459
- CR05
460
- BT07
461
- PD05
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"Looking for {SOURCE} in: {os.getcwd()}")
641
+ state.add_debug("INFO", f"Working dir: {_CWD}")
577
642
  if os.path.exists(SOURCE):
578
- state.add_debug("OK", f"Found {SOURCE} — press F6 to compile")
643
+ state.add_debug("OK", f"Found OS_CP.c — press F6 to compile")
579
644
  else:
580
- state.add_debug("WARN", f"{SOURCE} not found in current directory")
581
- state.add_debug("WARN", "Place OS_CP.c here and press F6")
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mos-tui",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "MOS Terminal UI Launcher",
5
5
  "bin": {
6
6
  "mos": "./bin/mos.js"
@@ -8,4 +8,4 @@
8
8
  "type": "commonjs",
9
9
  "author": "Ayush",
10
10
  "license": "MIT"
11
- }
11
+ }