fortrangoingonforty/fortress / fa50d33

Browse files

v1.0.2: Restructure installation, add NixOS support

- Move binary to /usr/lib/fortress/fortress (out of PATH)
- Add wrapper script /usr/bin/fortress that calls the binary
- Eliminate fortress-bin naming convention
- Add flake.nix for NixOS users
- Update shell integrations (fortress.sh, fortress.fish) with better path detection
- Add CLAUDE.md for Claude Code guidance
- Support /usr/lib64 path for 64-bit RPM systems
Authored by espadonne
SHA
fa50d33683e5878552f1d8fdde00627fcaf8e9d4
Parents
272a1cf
Tree
42852d4

8 changed files

StatusFile+-
A CLAUDE.md 60 0
M PKGBUILD 7 4
A flake.nix 91 0
A fortress-wrapper.sh 21 0
M fortress.fish 33 21
M fortress.sh 33 12
M fortress.spec 15 4
M fpm.toml 1 1
CLAUDE.mdadded
@@ -0,0 +1,60 @@
1
+# CLAUDE.md
2
+
3
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+## Build Commands
6
+
7
+```bash
8
+fpm build                          # Debug build
9
+fpm build --flag "-O2"             # Release build with optimization
10
+fpm build --flag "-g -Wall -Wextra" # Build with debug flags and warnings
11
+fpm run                            # Build and run
12
+fpm test                           # Run test suite
13
+```
14
+
15
+**Dependencies**: gfortran 10+ (or ifort), fpm, ncurses library
16
+
17
+## Architecture
18
+
19
+FORTRESS is a CLI file manager written in modern Fortran (2008+) with dual-pane navigation, git integration, and fuzzy search.
20
+
21
+### Module Structure
22
+
23
+```
24
+app/main.f90              # Main event loop, state management, user input (~1100 LOC)
25
+src/
26
+├── filesystem/fs_ops.f90     # Directory reading, path manipulation, fzf search, file ops
27
+├── ui/display.f90            # Dual-pane rendering (30% parent | 70% current), color output
28
+├── ui/preview.f90            # File preview functionality
29
+├── terminal/term_control.f90 # Raw mode, ANSI codes, terminal size, key reading
30
+├── git/git_ops.f90           # Git status, staging, commits, push/pull, diff display
31
+└── version/version.f90       # Version info (auto-generated by stamp-version.sh)
32
+```
33
+
34
+### Key Patterns
35
+
36
+**State Management**: The main event loop in `main.f90` manages:
37
+- Navigation state (`current_dir`, `parent_dir`, `selected`, `scroll_offset`)
38
+- Mode flags (`move_mode`, `in_rename_mode`, `in_selection_mode`)
39
+- Clipboard (`has_clipboard`, `clipboard_paths[]`, copy vs cut)
40
+- Multi-select tracking (`is_selected[]`, `selection_count`)
41
+- Favorites stored in `~/.fortress_favorites`
42
+
43
+**Terminal Control**:
44
+- Uses alternate screen buffer (`ESC[?1049h/l`) to prevent scroll artifacts
45
+- Raw mode via `stty` for non-blocking, character-by-character input
46
+- Terminal size caching (refreshes every 100 calls)
47
+
48
+**External Commands**: All shell commands use `execute_command_line()` - ensure proper escaping for paths with special characters.
49
+
50
+**Git Integration**: Uses git CLI directly; status is cached with 500ms TTL. Directories show recursive status indicators.
51
+
52
+**Shell Integration**: `~/.fortress_cd` file enables cd-on-exit feature; wrapper scripts in `fortress.sh`/`fortress.fish` read this file.
53
+
54
+### Constants
55
+
56
+Defined across modules: `MAX_PATH=512`, `MAX_FILES=500`
57
+
58
+### Color Scheme
59
+
60
+Blue=directories, Green=executables, Grey=dotfiles, Red=cut files/staged, Yellow=warnings/incoming changes
PKGBUILDmodified
@@ -1,6 +1,6 @@
11
 # Maintainer: Matthew Wolffe <mfwolffe@outlook.com>
22
 pkgname=fortress
3
-pkgver=0.9.99
3
+pkgver=1.0.2
44
 pkgrel=1
55
 pkgdesc="A command-line file explorer written in modern Fortran with cd-on-exit"
66
 arch=('x86_64' 'aarch64')
@@ -20,10 +20,13 @@ build() {
2020
 package() {
2121
     cd "$srcdir/$pkgname-$pkgver"
2222
 
23
-    # Install the binary
24
-    install -Dm755 "build/gfortran_"*"/app/fortress" "$pkgdir/usr/bin/fortress-bin"
23
+    # Install the binary to lib (not directly in PATH)
24
+    install -Dm755 "build/gfortran_"*"/app/fortress" "$pkgdir/usr/lib/fortress/fortress"
2525
 
26
-    # Install shell integration files
26
+    # Install wrapper script to /usr/bin/fortress
27
+    install -Dm755 "fortress-wrapper.sh" "$pkgdir/usr/bin/fortress"
28
+
29
+    # Install shell integration files (for cd-on-exit when sourced)
2730
     install -Dm644 "fortress.sh" "$pkgdir/usr/share/fortress/fortress.sh"
2831
     install -Dm644 "fortress.fish" "$pkgdir/usr/share/fortress/fortress.fish"
2932
 
flake.nixadded
@@ -0,0 +1,91 @@
1
+{
2
+  description = "FORTRESS - A command-line file explorer written in modern Fortran";
3
+
4
+  inputs = {
5
+    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
6
+    flake-utils.url = "github:numtide/flake-utils";
7
+  };
8
+
9
+  outputs = { self, nixpkgs, flake-utils }:
10
+    flake-utils.lib.eachDefaultSystem (system:
11
+      let
12
+        pkgs = nixpkgs.legacyPackages.${system};
13
+
14
+        fortress = pkgs.stdenv.mkDerivation rec {
15
+          pname = "fortress";
16
+          version = "1.0.2";
17
+
18
+          src = ./.;
19
+
20
+          nativeBuildInputs = with pkgs; [
21
+            gfortran
22
+            fortran-fpm
23
+            makeWrapper
24
+          ];
25
+
26
+          buildInputs = with pkgs; [
27
+            ncurses
28
+          ];
29
+
30
+          buildPhase = ''
31
+            # fpm needs a writable home for cache
32
+            export HOME=$(mktemp -d)
33
+            fpm build --flag "-O2"
34
+          '';
35
+
36
+          installPhase = ''
37
+            # Install binary to lib directory
38
+            mkdir -p $out/lib/fortress
39
+            cp build/gfortran_*/app/fortress $out/lib/fortress/fortress
40
+
41
+            # Create wrapper script in bin
42
+            mkdir -p $out/bin
43
+            makeWrapper $out/lib/fortress/fortress $out/bin/fortress
44
+
45
+            # Install shell integration files
46
+            mkdir -p $out/share/fortress
47
+            cp fortress.sh $out/share/fortress/
48
+            cp fortress.fish $out/share/fortress/
49
+
50
+            # Patch fortress.sh to find binary in nix store
51
+            substituteInPlace $out/share/fortress/fortress.sh \
52
+              --replace '/usr/lib/fortress/fortress' "$out/lib/fortress/fortress"
53
+
54
+            # Install docs
55
+            mkdir -p $out/share/doc/fortress
56
+            cp README.md $out/share/doc/fortress/
57
+            [ -f USAGE.md ] && cp USAGE.md $out/share/doc/fortress/ || true
58
+          '';
59
+
60
+          meta = with pkgs.lib; {
61
+            description = "A command-line file explorer written in modern Fortran with fzf integration";
62
+            homepage = "https://github.com/FortranGoingOnForty/fortress";
63
+            license = licenses.mit;
64
+            platforms = platforms.unix;
65
+            mainProgram = "fortress";
66
+          };
67
+        };
68
+      in
69
+      {
70
+        packages = {
71
+          default = fortress;
72
+          fortress = fortress;
73
+        };
74
+
75
+        apps.default = {
76
+          type = "app";
77
+          program = "${fortress}/bin/fortress";
78
+        };
79
+
80
+        devShells.default = pkgs.mkShell {
81
+          buildInputs = with pkgs; [
82
+            gfortran
83
+            fortran-fpm
84
+            ncurses
85
+            fzf
86
+            git
87
+          ];
88
+        };
89
+      }
90
+    );
91
+}
fortress-wrapper.shadded
@@ -0,0 +1,21 @@
1
+#!/usr/bin/env bash
2
+# FORTRESS wrapper script
3
+# Installed to /usr/bin/fortress, calls binary at /usr/lib/fortress/fortress
4
+#
5
+# Note: This script cannot change your shell's directory. For cd-on-exit
6
+# functionality (press 'c' to navigate), source fortress.sh in your shell rc:
7
+#   source /usr/share/fortress/fortress.sh
8
+#
9
+# The shell function will take precedence over this script when sourced.
10
+
11
+if [ -n "$FORTRESS_BIN" ] && [ -x "$FORTRESS_BIN" ]; then
12
+    exec "$FORTRESS_BIN" "$@"
13
+elif [ -x "/usr/lib/fortress/fortress" ]; then
14
+    exec /usr/lib/fortress/fortress "$@"
15
+elif [ -x "/usr/lib64/fortress/fortress" ]; then
16
+    exec /usr/lib64/fortress/fortress "$@"
17
+else
18
+    echo "fortress: binary not found" >&2
19
+    echo "Set FORTRESS_BIN to override the binary location." >&2
20
+    exit 1
21
+fi
fortress.fishmodified
@@ -3,42 +3,54 @@
33
 #   ~/.config/fish/functions/fortress.fish
44
 # or
55
 #   /usr/share/fish/vendor_functions.d/fortress.fish (system-wide)
6
+#
7
+# This provides the cd-on-exit feature. Without this function,
8
+# you can still run fortress but 'c' won't change your shell's directory.
69
 
710
 function fortress --description "Navigate filesystem with FORTRESS and cd on exit"
8
-    # Set fortress directory - prefer system install, fallback to FORTRESS_DIR env var
9
-    set -l fortress_dir
1011
     set -l fortress_exe
1112
 
12
-    # Check for fortress-bin in PATH first (works for all package managers including Homebrew)
13
-    if command -v fortress-bin &> /dev/null
13
+    # Check standard install locations (lib path first, then legacy bin path)
14
+    if test -x /usr/lib/fortress/fortress
15
+        set fortress_exe /usr/lib/fortress/fortress
16
+    else if test -x /usr/lib64/fortress/fortress
17
+        set fortress_exe /usr/lib64/fortress/fortress
18
+    else if command -v fortress-bin &> /dev/null
19
+        # Legacy: fortress-bin in PATH (Homebrew, older packages)
1420
         set fortress_exe fortress-bin
15
-    else if test -x /usr/bin/fortress-bin
16
-        # Use system-installed binary (RPM/AUR)
17
-        set fortress_exe /usr/bin/fortress-bin
21
+    else if set -q FORTRESS_BIN
22
+        # Allow override via environment variable
23
+        set fortress_exe $FORTRESS_BIN
1824
     else if set -q FORTRESS_DIR
19
-        set fortress_dir $FORTRESS_DIR
20
-        set fortress_exe $fortress_dir/build/gfortran_*/app/fortress
25
+        # Development: FORTRESS_DIR points to repo root
26
+        set fortress_exe $FORTRESS_DIR/build/gfortran_*/app/fortress
2127
     else
22
-        # Fallback to local development path
23
-        set fortress_dir $HOME/Documents/GithubOrgs/FortranGoingOnForty/fortress
24
-        set fortress_exe $fortress_dir/build/gfortran_*/app/fortress
28
+        # Fallback: look for any fortress executable (NixOS, custom installs)
29
+        set -l found (type -P fortress 2>/dev/null)
30
+        if test -n "$found" -a -x "$found"
31
+            set fortress_exe $found
32
+        else
33
+            echo "fortress: binary not found. Set FORTRESS_BIN or FORTRESS_DIR." >&2
34
+            return 1
35
+        end
2536
     end
2637
 
2738
     # Run fortress
28
-    if test -n "$fortress_exe"
29
-        eval $fortress_exe
30
-    else
31
-        $fortress_dir/build/gfortran_*/app/fortress
32
-    end
39
+    eval $fortress_exe $argv
40
+    set -l exit_code $status
3341
 
3442
     # Check if fortress wants us to cd somewhere
3543
     if test -f $HOME/.fortress_cd
3644
         set -l target_dir (cat $HOME/.fortress_cd)
3745
         rm -f $HOME/.fortress_cd
38
-        if cd $target_dir 2>/dev/null
39
-            echo "fortress: changed directory to "(pwd)
40
-        else
41
-            echo "fortress: failed to change directory to $target_dir" >&2
46
+        if test -n "$target_dir" -a -d "$target_dir"
47
+            if cd $target_dir 2>/dev/null
48
+                echo "fortress: changed directory to "(pwd)
49
+            else
50
+                echo "fortress: failed to change directory to $target_dir" >&2
51
+            end
4252
         end
4353
     end
54
+
55
+    return $exit_code
4456
 end
fortress.shmodified
@@ -1,38 +1,59 @@
11
 # FORTRESS shell integration
22
 # Add this to your .bashrc or .zshrc:
3
-#   source ~/Documents/GithubOrgs/FortranGoingOnForty/fortress/fortress.sh
3
+#   source /usr/share/fortress/fortress.sh
44
 #
55
 # Then use: fortress
6
+#
7
+# This provides the cd-on-exit feature. Without sourcing this file,
8
+# you can still run fortress but 'c' won't change your shell's directory.
69
 
710
 fortress() {
811
     # Determine which fortress binary to use
912
     local fortress_exe
1013
 
11
-    # Check for fortress-bin in PATH first (works for all package managers including Homebrew)
12
-    if command -v fortress-bin &> /dev/null; then
14
+    # Check standard install locations (lib path first, then legacy bin path)
15
+    if [ -x "/usr/lib/fortress/fortress" ]; then
16
+        fortress_exe="/usr/lib/fortress/fortress"
17
+    elif [ -x "/usr/lib64/fortress/fortress" ]; then
18
+        fortress_exe="/usr/lib64/fortress/fortress"
19
+    elif command -v fortress-bin &> /dev/null; then
20
+        # Legacy: fortress-bin in PATH (Homebrew, older packages)
1321
         fortress_exe="fortress-bin"
14
-    elif [ -x "/usr/bin/fortress-bin" ]; then
15
-        # Use system-installed binary (via package manager like RPM/AUR)
16
-        fortress_exe="/usr/bin/fortress-bin"
22
+    elif [ -n "$FORTRESS_BIN" ]; then
23
+        # Allow override via environment variable
24
+        fortress_exe="$FORTRESS_BIN"
1725
     elif [ -n "$FORTRESS_DIR" ]; then
18
-        # Use FORTRESS_DIR if set
26
+        # Development: FORTRESS_DIR points to repo root
1927
         fortress_exe="$FORTRESS_DIR/build/gfortran_"*"/app/fortress"
2028
     else
21
-        # Fallback to local development path
22
-        fortress_exe="$HOME/Documents/GithubOrgs/FortranGoingOnForty/fortress/build/gfortran_"*"/app/fortress"
29
+        # Fallback: look for any fortress executable (NixOS, custom installs)
30
+        # Use command -v to find it, but filter out this function
31
+        local found
32
+        found=$(type -P fortress 2>/dev/null)
33
+        if [ -n "$found" ] && [ -x "$found" ]; then
34
+            fortress_exe="$found"
35
+        else
36
+            echo "fortress: binary not found. Set FORTRESS_BIN or FORTRESS_DIR." >&2
37
+            return 1
38
+        fi
2339
     fi
2440
 
2541
     # Run fortress
26
-    $fortress_exe
42
+    "$fortress_exe" "$@"
43
+    local exit_code=$?
2744
 
2845
     # Check if fortress wants us to cd somewhere
2946
     if [ -f "$HOME/.fortress_cd" ]; then
3047
         local target_dir
3148
         target_dir=$(cat "$HOME/.fortress_cd")
3249
         rm -f "$HOME/.fortress_cd"
33
-        cd "$target_dir" || return 1
34
-        echo "fortress: changed directory to $(pwd)"
50
+        if [ -n "$target_dir" ] && [ -d "$target_dir" ]; then
51
+            cd "$target_dir" || return 1
52
+            echo "fortress: changed directory to $(pwd)"
53
+        fi
3554
     fi
55
+
56
+    return $exit_code
3657
 }
3758
 
3859
 # For zsh compatibility
fortress.specmodified
@@ -1,7 +1,7 @@
11
 %global debug_package %{nil}
22
 
33
 Name:           fortress
4
-Version:        1.0.1
4
+Version:        1.0.2
55
 Release:        1%{?dist}
66
 Summary:        A command-line file explorer written in modern Fortran with cd-on-exit
77
 
@@ -42,13 +42,17 @@ fpm build --flag "-O2 -ffree-line-length-none"
4242
 
4343
 %install
4444
 mkdir -p %{buildroot}%{_bindir}
45
+mkdir -p %{buildroot}%{_libdir}/%{name}
4546
 mkdir -p %{buildroot}%{_datadir}/%{name}
4647
 mkdir -p %{buildroot}%{_datadir}/fish/vendor_functions.d
4748
 mkdir -p %{buildroot}%{_sysconfdir}/profile.d
4849
 mkdir -p %{buildroot}%{_docdir}/%{name}
4950
 
50
-# Install the binary
51
-install -Dm755 build/gfortran_*/app/fortress %{buildroot}%{_bindir}/fortress-bin
51
+# Install the binary to lib (not directly in PATH)
52
+install -Dm755 build/gfortran_*/app/fortress %{buildroot}%{_libdir}/%{name}/fortress
53
+
54
+# Install wrapper script to bin
55
+install -Dm755 fortress-wrapper.sh %{buildroot}%{_bindir}/fortress
5256
 
5357
 # Install shell integration files to shared location
5458
 install -Dm644 fortress.sh %{buildroot}%{_datadir}/%{name}/fortress.sh
@@ -69,7 +73,8 @@ fi
6973
 %files
7074
 %license LICENSE
7175
 %doc README.md
72
-%{_bindir}/fortress-bin
76
+%{_bindir}/fortress
77
+%{_libdir}/%{name}/fortress
7378
 %{_datadir}/%{name}/fortress.sh
7479
 %{_datadir}/%{name}/fortress.fish
7580
 %config(noreplace) %{_sysconfdir}/profile.d/fortress.sh
@@ -105,6 +110,12 @@ cat <<'EOF'
105110
 EOF
106111
 
107112
 %changelog
113
+* Sat Dec 28 2025 mfw <mfwolffe@outlook.com> - 1.0.2-1
114
+- Move binary to /usr/lib/fortress/, add wrapper script to /usr/bin/fortress
115
+- Eliminate fortress-bin naming, both script and binary now named fortress
116
+- Add NixOS flake.nix support
117
+- Improve shell integration scripts with better path detection
118
+
108119
 * Fri Dec 05 2025 mfw <espadon@outlook.com> - 1.0.0-1
109120
 - Fix top status bar not rendering on some terminals
110121
 - Merge favorites: fuzzy jump, rename mode, git mode toggle, Alt-key bindings
fpm.tomlmodified
@@ -1,5 +1,5 @@
11
 name = "fortress"
2
-version = "1.0.1"
2
+version = "1.0.2"
33
 license = "MIT"
44
 author = "Matthew Wolffe"
55
 maintainer = "mfwolffe@outlook.com"