markdown · 4895 bytes Raw Blame History

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Facsimile (fac) is a terminal text editor written in modern Fortran with VSCode-style keybindings. It uses a gap buffer for text storage and pure ANSI escape sequences for terminal rendering.

Build Commands

# Standard build (recommended)
make

# Clean and rebuild
make clean && make

# Development build with comprehensive warnings
make dev

# Debug build with runtime checks
make debug

# Show compiler info
make info

The Makefile auto-detects the platform:

  • macOS arm64: Uses gfortran-15 or flang-new from Homebrew
  • macOS Intel/Linux: Uses standard gfortran

Version Management

# Check current version
make version

# Bump versions
make bump-patch    # 0.9.1 -> 0.9.2
make bump-minor    # 0.9.1 -> 0.10.0
make bump-major    # 0.9.1 -> 1.0.0

# Full release build with checklist
make release

The VERSION file is the single source of truth. The Makefile auto-generates src/version_module.f90.

Architecture

Core Data Flow

Input → input_handler_module → command_handler_module → buffer operations → renderer_module → Terminal

Key Modules

  • src/buffer/text_buffer_module.f90: Gap buffer implementation for text storage. All operations maintain gap position for efficient insertions.

  • src/editor_state_module.f90: Central state management. Contains editor_state_t with tabs, panes, cursors, LSP state, and UI panels. This is the "god object" that gets passed around.

  • src/terminal/input_handler_module.f90: Raw keyboard input processing. Handles escape sequences, mouse events, and key combinations.

  • src/terminal/renderer_module.f90: Screen rendering with ANSI escape sequences. Handles syntax highlighting, status bar, and split panes.

  • src/commands/command_handler_module.f90: Main command dispatch. Maps key inputs to editor actions (~7000 lines).

  • src/terminal/termios_wrapper.c: C wrapper for terminal raw mode via termios.

Module Dependency Order

The Makefile's SOURCES list defines the required compilation order. Fortran modules must be compiled before modules that use them. The .NOTPARALLEL directive enforces sequential builds.

UTF-8 Handling

All cursor positions use CHARACTER indices, not byte indices. The utf8_module provides conversion functions:

  • utf8_char_count() - count characters in string
  • buffer_byte_to_char_col() - convert byte position to character column
  • buffer_char_to_byte_col() - convert character column to byte position

Pane/Tab Architecture

editor_state_t
  └── tabs[]           (multiple open files)
       └── panes[]     (split views of same file)
            ├── buffer (text content)
            ├── cursors[] (multiple cursor support)
            └── viewport (scroll position)

LSP Integration

Located in src/lsp/. Communicates with language servers via JSON-RPC over stdio:

  • lsp_server_manager_module.f90 - Server lifecycle management
  • json_module.f90 - JSON parsing/generation
  • lsp_client_module.f90 - Request/response handling

Fortran-Specific Constraints

Line Length Limit

Fortran has a 132-character line limit. Unicode characters (like box-drawing ) count as multiple bytes. Long lines must be split using & continuation:

! Bad - will fail compilation
line = '═══════════════════════════════════════════════════════════════════'

! Good - split across lines
line = '═══════════════════════' // &
       '═══════════════════════' // &
       '═══════════════════════'

Module Files

Compilation generates .mod files in the root directory. These are binary module interfaces, not source files.

Distribution

The project is distributed via three channels:

  • Homebrew: homebrew-facsimile repo with facsimile.rb formula
  • AUR: Arch User Repository PKGBUILD
  • RPM: Spec file at ~/rpmbuild/SPECS/facsimile.spec

When releasing, update all three with the new version and SHA256 hash from the GitHub release tarball.

Testing

# LSP module tests
make test-lsp

# Test LSP with editor
make test-lsp-editor

# Manual key testing
./keytest      # Basic key codes
./keytest_fac  # With fac's termios settings

Running

./fac [filename]        # Open file
./fac --version         # Show version
./fac --help            # Show help

Key bindings follow VSCode conventions: Ctrl-S save, Ctrl-Q quit, Ctrl-B file tree, Ctrl-F search, Ctrl-Z undo.

View source
1 # CLAUDE.md
2
3 This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
5 ## Project Overview
6
7 Facsimile (`fac`) is a terminal text editor written in modern Fortran with VSCode-style keybindings. It uses a gap buffer for text storage and pure ANSI escape sequences for terminal rendering.
8
9 ## Build Commands
10
11 ```bash
12 # Standard build (recommended)
13 make
14
15 # Clean and rebuild
16 make clean && make
17
18 # Development build with comprehensive warnings
19 make dev
20
21 # Debug build with runtime checks
22 make debug
23
24 # Show compiler info
25 make info
26 ```
27
28 The Makefile auto-detects the platform:
29 - **macOS arm64**: Uses gfortran-15 or flang-new from Homebrew
30 - **macOS Intel/Linux**: Uses standard gfortran
31
32 ## Version Management
33
34 ```bash
35 # Check current version
36 make version
37
38 # Bump versions
39 make bump-patch # 0.9.1 -> 0.9.2
40 make bump-minor # 0.9.1 -> 0.10.0
41 make bump-major # 0.9.1 -> 1.0.0
42
43 # Full release build with checklist
44 make release
45 ```
46
47 The `VERSION` file is the single source of truth. The Makefile auto-generates `src/version_module.f90`.
48
49 ## Architecture
50
51 ### Core Data Flow
52
53 ```
54 Input → input_handler_module → command_handler_module → buffer operations → renderer_module → Terminal
55 ```
56
57 ### Key Modules
58
59 - **`src/buffer/text_buffer_module.f90`**: Gap buffer implementation for text storage. All operations maintain gap position for efficient insertions.
60
61 - **`src/editor_state_module.f90`**: Central state management. Contains `editor_state_t` with tabs, panes, cursors, LSP state, and UI panels. This is the "god object" that gets passed around.
62
63 - **`src/terminal/input_handler_module.f90`**: Raw keyboard input processing. Handles escape sequences, mouse events, and key combinations.
64
65 - **`src/terminal/renderer_module.f90`**: Screen rendering with ANSI escape sequences. Handles syntax highlighting, status bar, and split panes.
66
67 - **`src/commands/command_handler_module.f90`**: Main command dispatch. Maps key inputs to editor actions (~7000 lines).
68
69 - **`src/terminal/termios_wrapper.c`**: C wrapper for terminal raw mode via termios.
70
71 ### Module Dependency Order
72
73 The Makefile's `SOURCES` list defines the required compilation order. Fortran modules must be compiled before modules that `use` them. The `.NOTPARALLEL` directive enforces sequential builds.
74
75 ### UTF-8 Handling
76
77 All cursor positions use CHARACTER indices, not byte indices. The `utf8_module` provides conversion functions:
78 - `utf8_char_count()` - count characters in string
79 - `buffer_byte_to_char_col()` - convert byte position to character column
80 - `buffer_char_to_byte_col()` - convert character column to byte position
81
82 ### Pane/Tab Architecture
83
84 ```
85 editor_state_t
86 └── tabs[] (multiple open files)
87 └── panes[] (split views of same file)
88 ├── buffer (text content)
89 ├── cursors[] (multiple cursor support)
90 └── viewport (scroll position)
91 ```
92
93 ### LSP Integration
94
95 Located in `src/lsp/`. Communicates with language servers via JSON-RPC over stdio:
96 - `lsp_server_manager_module.f90` - Server lifecycle management
97 - `json_module.f90` - JSON parsing/generation
98 - `lsp_client_module.f90` - Request/response handling
99
100 ## Fortran-Specific Constraints
101
102 ### Line Length Limit
103 Fortran has a 132-character line limit. Unicode characters (like box-drawing `═`) count as multiple bytes. Long lines must be split using `&` continuation:
104
105 ```fortran
106 ! Bad - will fail compilation
107 line = '═══════════════════════════════════════════════════════════════════'
108
109 ! Good - split across lines
110 line = '═══════════════════════' // &
111 '═══════════════════════' // &
112 '═══════════════════════'
113 ```
114
115 ### Module Files
116 Compilation generates `.mod` files in the root directory. These are binary module interfaces, not source files.
117
118 ## Distribution
119
120 The project is distributed via three channels:
121 - **Homebrew**: `homebrew-facsimile` repo with `facsimile.rb` formula
122 - **AUR**: Arch User Repository PKGBUILD
123 - **RPM**: Spec file at `~/rpmbuild/SPECS/facsimile.spec`
124
125 When releasing, update all three with the new version and SHA256 hash from the GitHub release tarball.
126
127 ## Testing
128
129 ```bash
130 # LSP module tests
131 make test-lsp
132
133 # Test LSP with editor
134 make test-lsp-editor
135
136 # Manual key testing
137 ./keytest # Basic key codes
138 ./keytest_fac # With fac's termios settings
139 ```
140
141 ## Running
142
143 ```bash
144 ./fac [filename] # Open file
145 ./fac --version # Show version
146 ./fac --help # Show help
147 ```
148
149 Key bindings follow VSCode conventions: Ctrl-S save, Ctrl-Q quit, Ctrl-B file tree, Ctrl-F search, Ctrl-Z undo.