fortrangoingonforty/fortsh / a68e7cd

Browse files

update README for v1.5.0 — refresh platform matrix, test counts, features, install methods

Authored by espadonne
SHA
a68e7cd791fa05cfcb50b881dce687f4b1c7ee78
Parents
b082598
Tree
d023fc6

1 changed file

StatusFile+-
M README.md 132 151
README.mdmodified
@@ -3,63 +3,94 @@
33
 
44
 A shell written in Fortran. Because we can.
55
 
6
-> **Warning - macOS ARM64 Users**: Due to compiler limitations on apple silicon, command lines are limited to 127 characters. All features work (history, tab completion, syntax highlighting, etc.), but you can't type commands longer than 127 bytes. This is a fundamental limitation of both available compilers: gfortran has 7+ critical bugs (stack corruption, heap corruption, segfaults), while flang-new has a 127-byte string operation limit to prevent heap corruption. We see flang-new as the lesser evil. For details, see COMPILER_NOTES.md.
7
-
86
 ## Status
97
 
10
-**POSIX compliance**: 3,776/3,776 tests passing across 25 test suites
8
+**CI**: All green across x86_64 Linux, ARM64 Linux, and macOS ARM64 (Apple Silicon)
9
+**POSIX compliance**: 3,632+ tests passing across 23 POSIX suites
10
+**Builtin tests**: 850+ passing | **Integration tests**: 482 passing | **Stress tests**: 204 passing
11
+**Interactive PTY tests**: 180+ passing
1112
 **bash compatibility**: ~99%
1213
 **Chance you'll miss the other 1%**: Low
1314
 
1415
 Turns out you can write a pretty decent shell in Fortran. Who knew.
1516
 
17
+## Install
18
+
19
+**Homebrew** (macOS / Linux):
20
+```bash
21
+brew install FortranGoingOnForty/tap/fortsh
22
+```
23
+
24
+**AUR** (Arch Linux):
25
+```bash
26
+yay -S fortsh
27
+```
28
+
29
+**From source**:
30
+```bash
31
+git clone https://github.com/FortranGoingOnForty/fortsh.git
32
+cd fortsh
33
+make release
34
+sudo make install    # /usr/local/bin
35
+```
36
+
37
+Binary lands in `bin/fortsh`. Shocking, I know.
38
+
1639
 ## What Works
1740
 
1841
 Pretty much everything:
1942
 
2043
 - All POSIX required features
2144
 - All the bash stuff people actually use
22
-- Job control
23
-- History with Ctrl+R
24
-- Tab completion
25
-- History suggestions a la fish
26
-- fuzzy matching a la fish
45
+- Job control (fg, bg, jobs, wait)
46
+- History with Ctrl+R and autosuggestions
47
+- Tab completion for commands, paths, and variables
48
+- Syntax highlighting as you type
2749
 - Arrays (indexed and associative)
28
-- Parameter expansion (`${var#stuff}`, etc.)
50
+- Full parameter expansion (`${var#pattern}`, `${var//find/replace}`, `${var^^}`, etc.)
2951
 - Process substitution (`<(cmd)`, `>(cmd)`)
30
-- Brace expansion (`{1..10}`)
52
+- Brace expansion (`{1..10..2}`, `{a,b}{1,2}`)
53
+- C-style for loops (`for ((i=0; i<10; i++))`)
54
+- ANSI-C quoting (`$'\t\n\e[31m'`)
55
+- Indirect expansion (`${!ref}`, `${!ref:-fallback}`)
56
+- Coprocesses (`coproc { cmd; }`)
3157
 - Regex matching with capture groups (`BASH_REMATCH`)
32
-- Vi mode (if you're into that)
58
+- Vi and Emacs editing modes
59
+- Per-builtin help texts (`help cd`, `help export`, etc.)
60
+- fzf integration (file browser, history search, directory jump, git browser)
3361
 
3462
 ## What Doesn't Work
3563
 
3664
 - Some advanced vi mode features (yank/put, marks)
37
-- Nested brace expansion (who uses this?)
3865
 - Your expectations, probably
3966
 - More?!
4067
 
4168
 ## Building
4269
 
4370
 Requires:
44
-- A Fortran 2018 compiler (gfortran 8+, or LLVM flang-new for macOS ARM64)
71
+- A Fortran 2018 compiler (gfortran 8+, or flang-new for macOS ARM64)
4572
 - GNU Make
46
-- POSIX system (Linux, BSD, macOS)
73
+- A C compiler (gcc or clang)
74
+- POSIX system (Linux, macOS)
4775
 - Realistic expectations
4876
 
49
-**macOS ARM64 Note**: Use `brew install llvm` to get flang-new. See the warning at the top or COMPILER_NOTES.md for details.
50
-
5177
 ```bash
52
-git clone https://github.com/FortranGoingOnForty/fortsh.git
53
-cd fortsh
54
-make
78
+make                # dev build (debug symbols, -O0)
79
+make release        # production build (optimized, stripped)
80
+make debug          # debug build with bounds checking
81
+make clean          # remove build/ and bin/
5582
 ```
5683
 
57
-Binary lands in `bin/fortsh`. Shocking, I know.
84
+### Platform Matrix
5885
 
59
-```bash
60
-sudo make install    # /usr/local/bin
61
-make dev-install    # ~/.local/bin
62
-```
86
+| Platform | Compiler | Notes |
87
+|----------|----------|-------|
88
+| Linux x86_64 | gfortran | Primary target |
89
+| Linux aarch64 | gfortran | Auto-enables C stat helpers for struct layout differences |
90
+| macOS Intel | gfortran | Works with `-frecursive` |
91
+| macOS ARM64 | flang-new (LLVM) | Required -- gfortran has 7+ critical bugs. Auto-enables C string library. Install via `brew install flang`. |
92
+
93
+The Makefile auto-detects your platform and selects the right compiler and flags. Just run `make`.
6394
 
6495
 ## Using It
6596
 
@@ -101,7 +132,7 @@ Type a directory path, press Enter. That's it.
101132
 ~/Documents/       # Go to ~/Documents
102133
 ```
103134
 
104
-Works with Tab completion.
135
+Works with Tab completion. Valid directories highlight green.
105136
 
106137
 ### Keybindings
107138
 
@@ -113,7 +144,7 @@ Works with Tab completion.
113144
 | Alt+Shift+Left | Previous directory |
114145
 | Alt+Shift+Right | Next directory |
115146
 
116
-**Fuzzy search:**
147
+**Fuzzy search (requires fzf):**
117148
 
118149
 | Key | Action |
119150
 |-----|--------|
@@ -129,7 +160,7 @@ Works for commands, paths, variables, and command-specific options.
129160
 ### Syntax Highlighting
130161
 
131162
 Colors update as you type:
132
-- Green = valid commands
163
+- Green = valid commands and directory paths
133164
 - Red = invalid commands
134165
 - Cyan = numbers
135166
 - Yellow = strings
@@ -187,6 +218,11 @@ text="Hello World"
187218
 echo ${text^^}                  # HELLO WORLD
188219
 echo ${text,,}                  # hello world
189220
 echo ${text^}                   # Hello World (first char)
221
+
222
+# Indirect expansion
223
+ref="path"
224
+echo ${!ref}                    # /usr/local/bin/fortsh (value of $path)
225
+echo ${!ref:-fallback}          # works with modifiers too
190226
 ```
191227
 
192228
 ### Arrays (Both Kinds)
@@ -262,6 +298,15 @@ mkdir -p project/{src,test,docs}/{main,utils}
262298
 touch file{1..100}.txt
263299
 ```
264300
 
301
+### ANSI-C Quoting
302
+
303
+```bash
304
+echo $'tab:\there'              # tab:	here
305
+echo $'line1\nline2'            # line1 (newline) line2
306
+echo $'it\'s fine'              # it's fine
307
+echo $'\e[31mred\e[0m'          # red (in color)
308
+```
309
+
265310
 ### Arithmetic
266311
 
267312
 ```bash
@@ -278,6 +323,11 @@ for ((i=0; i<5; i++)); do
278323
     echo "Count: $i"
279324
 done
280325
 
326
+# Multi-variable
327
+for ((i=0, j=10; i<j; i++, j--)); do
328
+    echo "$i $j"
329
+done
330
+
281331
 # Inline increment
282332
 count=0
283333
 echo $((count++))               # 0 (post-increment)
@@ -327,6 +377,19 @@ ps aux | grep fortsh | grep -v grep | awk '{print $2}' | xargs kill
327377
 command1 | command2 || echo "Pipeline failed with status $?"
328378
 ```
329379
 
380
+### Coprocesses
381
+
382
+```bash
383
+# Named coproc
384
+coproc WORKER { while read line; do echo "processed: $line"; done; }
385
+echo "hello" >&${WORKER[1]}
386
+read result <&${WORKER[0]}
387
+echo $result    # processed: hello
388
+
389
+# Brace group coproc
390
+coproc { cat -n; }
391
+```
392
+
330393
 ### Job Control
331394
 
332395
 ```bash
@@ -352,11 +415,6 @@ echo "Job completed with status $?"
352415
 ### Control Flow (The Tricky Bits)
353416
 
354417
 ```bash
355
-# C-style for loop with multiple vars
356
-for ((i=0, j=10; i<j; i++, j--)); do
357
-    echo "$i $j"
358
-done
359
-
360418
 # Case with multiple patterns
361419
 case $input in
362420
     *.txt|*.md)
@@ -453,13 +511,21 @@ trap - INT
453511
 ## Testing
454512
 
455513
 ```bash
456
-make test-all           # everything (integration + parity + POSIX)
457
-make test-posix         # POSIX compliance suite (3,776 tests)
458
-make test-parity        # bash parity tests
459
-make test-integration   # integration tests
514
+make test-posix         # POSIX compliance (~1 min)
515
+make test-posix-full    # all POSIX suites (~3 min)
516
+make test-posix-quick   # fast POSIX, skip coverage (~30s)
517
+make test-bench         # unit bench tests (memory pool, lexer, executor, C strings)
518
+make test-all           # everything including memory pool tests
460519
 make check              # comprehensive build checks
461520
 ```
462521
 
522
+Individual test suites:
523
+```bash
524
+./tests/builtins/run_builtin_tests.sh --verbose
525
+./tests/builtins/integration/run_integration_tests.sh --verbose
526
+./tests/builtins/test_stress.sh
527
+```
528
+
463529
 Interactive PTY tests (Python/pexpect):
464530
 ```bash
465531
 cd tests/interactive
@@ -478,156 +544,71 @@ All of them: `:`, `.`, `break`, `cd`, `continue`, `echo`, `eval`, `exec`, `exit`
478544
 
479545
 ### bash Compatible
480546
 
481
-The useful ones: `[[`, `alias`, `bg`, `command`, `compgen`, `complete`, `declare`, `fc`, `fg`, `history`, `jobs`, `kill`, `let`, `local`, `printenv`, `shopt`, `source`, `unalias`, `which`
547
+The useful ones: `[[`, `alias`, `bg`, `command`, `compgen`, `complete`, `coproc`, `declare`, `fc`, `fg`, `history`, `jobs`, `kill`, `let`, `local`, `printenv`, `shopt`, `source`, `unalias`, `which`
482548
 
483549
 ### fortsh Specific
484550
 
485551
 - `config` - manage config files
486552
 - `memory` - show memory stats
487553
 - `perf` - show performance metrics
554
+- `help <builtin>` - detailed help for any builtin
555
+- `defun` - function definition helper
488556
 
489
-Because why not.
490
-
491
-## macOS & Apple Silicon
557
+Every builtin has detailed help: `help cd`, `help export`, `help trap`, etc.
492558
 
493
-Apple Silicon has been an adventure. Both available Fortran compilers have serious issues on ARM64, so fortsh uses a combination of compiler selection, C interop workarounds, and platform-specific code paths to produce a functional shell. For the full story, see `COMPILER_NOTES.md`.
494
-
495
-### The Compiler Situation
496
-
497
-| Platform | Compiler | Status |
498
-|----------|----------|--------|
499
-| Linux | gfortran | Primary target, no issues |
500
-| macOS Intel | gfortran | Works with `-frecursive` |
501
-| macOS ARM64 | flang-new (LLVM) | Required — gfortran has 7+ critical bugs |
559
+## macOS ARM64 Notes
502560
 
503
-**Why not gfortran on Apple Silicon?** It has at least 8 confirmed bugs that make it unusable:
561
+Both Fortran compilers have issues on Apple Silicon. fortsh uses flang-new (LLVM) with C interop workarounds. The Makefile handles everything automatically.
504562
 
505
-1. Stack corruption on arrays >600KB
506
-2. Deferred-length allocatable strings lose their length descriptor
507
-3. `intent(out)` subroutine return epilogue segfaults
508
-4. Allocatable string assignment corrupts the heap
509
-5. Automatic finalization crashes
510
-6. Substring slicing (`buffer(:length)`) segfaults
511
-7. Empty string assignment (`buffer = ''`) corrupts the heap
512
-8. `flush()` in tight loops corrupts the heap
563
+Install flang-new via `brew install flang`. See `COMPILER_NOTES.md` for the full story on compiler bugs and workarounds.
513564
 
514
-Install flang-new via `brew install llvm`. The Makefile auto-detects ARM64 and switches compilers.
515
-
516
-### The flang-new 128-Byte Limit
517
-
518
-flang-new is far more stable, but has one glaring limitation: string buffers larger than 128 bytes cause heap corruption on substring operations and direct assignments. This means **command lines are limited to 127 characters** on Apple Silicon.
519
-
520
-Allocating strings >128 bytes works fine. Operating on them doesn't. We tried a "shadow buffer" pattern (1024-byte storage, 128-byte working buffer) — still limited to 128 effective bytes.
521
-
522
-### C String Library Workaround
523
-
524
-To mitigate flang-new's string bugs, fortsh includes a C string library (`src/c_interop/fortsh_strings.c`) that performs string operations outside the Fortran runtime. This is **auto-enabled on macOS ARM64** and provides:
525
-
526
-- Safe substring extraction (the operation that crashes flang-new)
527
-- Buffer manipulation (insert, delete, append) without heap corruption
528
-- Fortran-to-C string conversion with proper indexing translation
529
-
530
-The `buffer_ops.f90` abstraction layer routes string operations through either native Fortran (Linux) or the C library (macOS ARM64) transparently.
531
-
532
-Build flags:
533
-```bash
534
-make                    # auto-enables C strings on ARM64
535
-make NO_C_STRINGS=1     # force native Fortran strings (will crash on ARM64)
536
-```
537
-
538
-### Platform-Specific Code Paths
539
-
540
-Beyond the compiler, macOS differs from Linux in ways that required workarounds throughout the codebase:
541
-
542
-**Terminal I/O:**
543
-- `termios_t` struct is 72 bytes on macOS vs 60 on Linux (8-byte vs 4-byte `tcflag_t`)
544
-- Control character array (`NCCS`) is 20 on macOS vs 32 on Linux
545
-- `TIOCGWINSZ` ioctl constant differs (`0x40087468` vs `0x5413`)
546
-- Terminal size detection uses `tput` on macOS (direct ioctl crashes flang-new) vs ioctl on Linux
547
-
548
-**Signal numbers:**
549
-- `SIGTSTP`: 18 on macOS, 20 on Linux
550
-- `SIGCHLD`: 20 on macOS, 17 on Linux
551
-- `SIGCONT`: 19 on macOS, 18 on Linux
552
-- macOS does NOT ignore `SIGTSTP` (breaks `waitpid` by auto-reaping children)
553
-
554
-**File system:**
555
-- `stat_t` is 96 bytes on macOS vs 144 on Linux, with different field ordering
556
-- macOS has `st_birthtimespec` (birth time) — Linux does not
557
-- `open()` flags differ: `O_CREAT` is `0x200` on macOS vs `0x40` on Linux
558
-
559
-**Other:**
560
-- BSD `ps` doesn't support `--no-headers` (macOS uses `pid= -o comm=` format instead)
561
-- Fortran `block` constructs crash flang-new — variables hoisted to subroutine scope
562
-- Substring temporaries on allocatable strings trigger heap corruption — char-by-char copy used instead
563
-- `mode_t` not passed correctly through Fortran C binding — C wrapper (`fd_wrapper.c`) casts explicitly
564
-
565
-### macOS ARM64 Build
566
-
567
-```bash
568
-brew install llvm
569
-git clone https://github.com/FortranGoingOnForty/fortsh.git
570
-cd fortsh
571
-make            # auto-detects ARM64, uses flang-new + C string library
572
-```
573
-
574
-You'll see:
575
-```
576
-Using flang-new on macOS ARM64
577
-C string library ENABLED - workaround for flang-new >128 byte bug
578
-```
565
+Key differences from Linux builds:
566
+- C string library auto-enabled (works around flang-new string buffer limitations)
567
+- Platform-specific constants for signals, terminal I/O, file flags, and resource limits
568
+- Builtin output uses C-level `write()` to respect fd redirections (flang-new's Fortran I/O caches file descriptors)
579569
 
580570
 ## Known Issues
581571
 
582
-- **macOS ARM64**: 127-character command line limit (flang-new string bug, see above)
572
+- macOS ARM64 has a 127-character command line limit (flang-new string buffer constraint). All features work, but long one-liners need to be broken up or put in scripts. See `COMPILER_NOTES.md`.
583573
 - Slower than bash for large scripts (it's Fortran, not a miracle worker)
584
-- Some regex patterns with spaces need escaping (affects ~0.1% of use cases)
585574
 - Unicode support varies by system locale
586575
 - Will not make you coffee
587576
 
588
-## Why?
589
-
590
-Why not?
591
-
592
-More seriously: started as "can you even do this in Fortran?" Turns out yes. Then it became "how far can this go?" Turns out pretty far.
593
-
594
-It's actually usable now. We're as surprised as you are.
595
-
596577
 ## Project Structure
597578
 
598579
 ```
599580
 src/
600
-├── common/          # Types, errors, perf monitoring
601
-├── system/          # OS interface, signals, jobs
602
-├── parsing/         # Lexer, parser, glob
603
-├── execution/       # Command execution, builtins
604
-├── scripting/       # Variables, control flow, expansion
605
-├── io/              # Readline, redirection
581
+├── common/          # Types, errors, string pool, perf monitoring
582
+├── system/          # OS interface (POSIX syscalls), signals
583
+├── parsing/         # Lexer, grammar parser, AST, glob
584
+├── execution/       # AST executor, builtins, job control, pipelines
585
+├── scripting/       # Variables, expansion, control flow, completion
586
+├── io/              # Readline (~9000 lines), heredoc, fd redirection
587
+├── c_interop/       # C FFI: string ops, fd wrapper, terminal size
606588
 └── fortsh.f90       # Main REPL loop
607589
 ```
608590
 
609
-## Documentation
591
+~70,000 lines of Fortran, fully self-contained with no external Fortran library dependencies.
610592
 
611
-See `docs/` for:
612
-- `SHELL_PARITY_STATUS_2025_10_12.md` - current feature status
613
-- Implementation docs for specific features
614
-- POSIX compliance tracking
615
-
616
-Or just run `help` in the shell.
593
+## Why?
617594
 
618
-## Contributing
595
+Why not?
619596
 
620
-Found a bug? Cool, file an issue.
621
-Want to add a feature? Check it's not already there (spoiler: it might be).
622
-Want to make it faster? Please do.
597
+More seriously: started as "can you even do this in Fortran?" Turns out yes. Then it became "how far can this go?" Turns out pretty far.
623598
 
624
-This started as a research project and somehow became production-ready. Contributions welcome.
599
+It's actually usable now. We're as surprised as you are.
625600
 
626601
 ## Standards
627602
 
628603
 POSIX.1-2017 (IEEE Std 1003.1-2017)
629604
 bash 5.x for extensions
630605
 
606
+## Contributing
607
+
608
+Found a bug? Cool, file an issue.
609
+Want to add a feature? Check it's not already there (spoiler: it might be).
610
+Want to make it faster? Please do.
611
+
631612
 ## License
632613
 
633614
 MIT. See LICENSE file.