Metadata-Version: 2.4
Name: notispf
Version: 1.4.4
Summary: A terminal text editor inspired by the ISPF editor from z/OS
Author-email: mrthock <m64357@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/mrthock/notispf
Project-URL: Repository, https://github.com/mrthock/notispf
Project-URL: Bug Tracker, https://github.com/mrthock/notispf/issues
Keywords: editor,ispf,terminal,tui,mainframe,zos
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Text Editors
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: pygments>=2.0
Provides-Extra: qt
Requires-Dist: PyQt6>=6.5; extra == "qt"

# notispf

A text editor inspired by the ISPF editor from z/OS mainframes, available as a terminal app on all platforms, a desktop GUI on Linux and Windows, and a native Swift app on macOS.
Brings the prefix command area that ISPF users know and love to Linux, macOS, and Windows.

## Installation

### Download (no Python required)

Go to the [Releases page](https://github.com/mrthock/notispf/releases) and download for your platform:

| Platform | GUI | Terminal CLI |
|----------|-----|--------------|
| Linux    | `notispf-qt-x86_64.AppImage` | `notispf-linux` |
| macOS    | [notispf-v1.0.dmg](https://github.com/mrthock/notispf/releases/tag/v1.0-mac) | `notispf-macos` |
| Windows  | `notispf-qt-setup.exe` | `notispf-windows.exe` |

**Linux AppImage:**
```bash
chmod +x notispf-qt-x86_64.AppImage
./notispf-qt-x86_64.AppImage myfile.txt
```

**macOS Native App (v1.0):**

Download `notispf-v1.0.dmg` from the [v1.0-mac release](https://github.com/mrthock/notispf/releases/tag/v1.0-mac), open the DMG, and drag **notispf.app** to your Applications folder. Then launch it from Applications or Spotlight.

> **macOS note:** If macOS shows a security warning on first launch, right-click the app → **Open** → **Open** to bypass Gatekeeper. The app is signed with a Developer ID certificate.

> **macOS Terminal CLI note:** `xattr -d com.apple.quarantine ./notispf-macos`

**Windows installer:** Run `notispf-qt-setup.exe`. Creates a Start Menu entry and an optional desktop shortcut.

> **Windows note:** SmartScreen may warn about an unknown publisher. Click **More info** → **Run anyway**.

**Linux / macOS CLI:**
```bash
chmod +x notispf-linux   # or notispf-macos
./notispf-linux myfile.txt
mv notispf-linux ~/.local/bin/notispf   # optionally add to PATH
```

### Arch Linux / Endeavour OS / Manjaro (pacman)

A PKGBUILD is provided in [`packaging/PKGBUILD`](packaging/PKGBUILD). It installs the pre-built binary and registers it with pacman so upgrades and removal work normally.

```bash
curl -O https://raw.githubusercontent.com/mrthock/notispf/main/packaging/PKGBUILD
makepkg -si
```

Or if you already have the repo cloned:

```bash
cd packaging
makepkg -si
```

To uninstall:

```bash
pacman -R notispf
```

### Via pip

```bash
pip install notispf           # terminal version
pip install notispf[qt]       # terminal + GUI (requires PyQt6)
```

### From source

```bash
git clone https://github.com/mrthock/notispf
cd notispf
pip install -e .          # terminal version
pip install -e ".[qt]"    # terminal + GUI
```

## Usage

**macOS Native App:**
```
Launch notispf.app from Applications or Spotlight.
Use File → Open (Cmd+O) to open a file, or pass a path as an argument from the terminal.
```

**GUI (PyQt6):**
```bash
notispf-qt <file>
notispf-qt           # opens a file picker dialog
```

**Terminal:**
```bash
notispf <file>
```

## Screen Layout

```
 notispf  filename.txt                    Line 1/42  Col 1
===> _
000001|This is the first line of your file
000002|Second line here
000003|Third line
      |~
      |~
F1-HELP  F3-SAVE  F5-RFIND  F6-CMD  F7-UP  F8-DOWN  F10-LEFT  F11-RIGHT  F12-QUIT
                                                                 [message bar]
```

- **Status bar** (top row) — filename, modified flag `[+]`, current line/total, cursor column, `[HEX]` when hex mode is active
- **Command bar** (second row) — always visible; type commands here after pressing F6 to focus it
- **Prefix column** (left, 6 chars) — shows zero-padded line numbers; type prefix commands here
- **Text area** (right of `|`) — edit your file
- **Function key bar** (second-to-last row) — always-visible reference for function key shortcuts
- **Message bar** (bottom row) — status messages and feedback

## Navigation

| Key | Action |
|-----|--------|
| Arrow keys | Move cursor in text |
| Up (from top visible line) | Move to command bar |
| Page Up / Page Down | Scroll |
| Home | Focus command bar |
| Ctrl+A | Beginning of line |
| End / Ctrl+E | End of line |

## Switching Between Areas

| From | Key | To |
|------|-----|----|
| Text | Home | Command bar |
| Text | Tab | Prefix column of next line (N+1) |
| Text (col 0) | Left arrow | Prefix column of same line |
| Text (top line) | Shift+Tab | Command bar |
| Text (any other line) | Shift+Tab | Prefix column of previous line (N-1) |
| Prefix | Right arrow | Text area of same line (col 0) |
| Prefix | Home | Command bar |
| Prefix | Tab | Text area of same line |
| Prefix | Shift+Tab | Text area of previous line (N-1) |
| Command bar | Tab | Prefix area of line 1 |
| Command bar | Down arrow | Text area (cursor position preserved) |
| Command bar | Escape | Text area (cursor position preserved, bar stays visible) |

## Prefix Commands

Type a command into the prefix column, then press **Enter** to execute.
You can stage commands on multiple lines before pressing Enter — they all execute at once.

### Single-Line Commands

| Command | Action |
|---------|--------|
| `D` | Delete line |
| `Dn` | Delete n lines (e.g. `D5` deletes 5) |
| `I` | Insert blank line after |
| `In` | Insert n blank lines |
| `R` | Repeat line |
| `Rn` | Repeat line n times |
| `C` | Copy line to clipboard |
| `Cn` | Copy n lines to clipboard |
| `M` | Move line (cut to clipboard) |
| `Mn` | Move n lines |
| `A` | Paste clipboard **after** this line |
| `B` | Paste clipboard **before** this line |
| `O` | Overlay clipboard onto this line (merge; clipboard spaces don't overwrite) |
| `On` | Overlay clipboard onto n lines |
| `>n` | Indent right n columns (e.g. `>4` adds 4 spaces) |
| `<n` | Indent left n columns (removes up to n leading spaces) |
| `HEX` | Replace this line with its hex representation |
| `HEXB` | Insert a hex copy of this line below it |
| `HEXA` | Convert a hex line back to ASCII text |
| `UC` | Uppercase this line |
| `UCn` | Uppercase n lines (e.g. `UC3`) |
| `LC` | Lowercase this line |
| `LCn` | Lowercase n lines |

### Block Commands

Type the command on the **first** line of the block, then again on the **last** line.

| Command | Action |
|---------|--------|
| `DD` | Delete block |
| `CC` | Copy block to clipboard |
| `MM` | Move block (cut to clipboard) |
| `RR` | Repeat block (insert a copy below) |
| `OO` | Overlay clipboard onto block (merge clipboard text into block lines) |
| `>>n` | Indent block right n columns |
| `<<n` | Indent block left n columns |

Use `A`, `B`, or `O`/`OO` on a third line to place the clipboard after copying or moving.

**Example — move lines 3–6 to after line 10:**
1. Tab to line 3 prefix → type `MM`
2. Arrow down to line 6 → type `MM`
3. Arrow down to line 10 → type `A`
4. Press Enter

### Exclude / Show Commands

| Command | Action |
|---------|--------|
| `X` | Exclude line from display (collapse into fold row) |
| `Xn` | Exclude n lines |
| `S` | Show (un-exclude) line or the entire fold group it belongs to |
| `Sn` | Show n lines |
| `XX` | Exclude block |
| `SS` | Show block |

Excluded lines are collapsed into a single fold row showing the count. Use `SHOW ALL` on the command line to reveal everything at once.

### Prefix Mode Controls

| Key | Action |
|-----|--------|
| Enter | Execute all staged prefix commands |
| Escape | Cancel all staged commands and exit prefix mode |
| ↑ / ↓ | Move between lines (keeps staged commands) |

## Command Line

The command bar is always visible just below the status bar. Press **F6** to focus it (the cursor moves to `===>`), type a command, and press Enter to execute. After the command runs the input clears, the result appears in the message bar, and the cursor stays at `===>` ready for another command. Press **Escape** or **Down arrow** to return to the text. Press **F6** again while focused to hide the bar entirely; press **F6** once more to bring it back.

### File Commands

| Command | Action |
|---------|--------|
| `SAVE` | Save file |
| `FILE` | Save and exit |
| `CANCEL` or `QUIT` or `CAN` | Exit without saving |

### Copy File

| Command | Action |
|---------|--------|
| `COPY filename` | Save a copy of the current file to `filename` (current file path unchanged) |

### Undo / Redo

| Command | Action |
|---------|--------|
| `UNDO` | Undo last change |
| `REDO` | Redo last undone change |

### Hex Mode

| Command | Action |
|---------|--------|
| `HEX ON` | Convert entire file to hex (e.g. `Hello` → `48 65 6C 6C 6F`) |
| `HEX OFF` | Convert hex back to text |

`[HEX]` appears in the status bar while hex mode is active. `HEX ON` and `HEX OFF` each count as a single undo step.

### Exclude and Delete

```
EXCLUDE 'pattern'
EXCLUDE 'pattern' ALL
EXCLUDE 'pattern' n

DELETE 'pattern'
DELETE 'pattern' ALL
DELETE 'pattern' n
DELETE X ALL
DELETE NX ALL
```

- `EXCLUDE 'pattern'` — exclude the next matching line from display
- `EXCLUDE 'pattern' ALL` — exclude all matching lines
- `EXCLUDE 'pattern' n` — exclude the next n matching lines
- `DELETE 'pattern'` — delete the next matching line
- `DELETE 'pattern' ALL` — delete all matching lines
- `DELETE X ALL` — delete all currently excluded lines
- `DELETE NX ALL` — delete all non-excluded lines

### Show

| Command | Action |
|---------|--------|
| `SHOW ALL` | Reveal all excluded lines |

### Display

| Command | Action |
|---------|--------|
| `COLS` | Toggle the column ruler on/off |
| `CLEAR` / `RESET` / `RES` | Clear the current search highlight |
| `HELP` | Open the help screen |
| `HILIGHT OFF` | Disable syntax highlighting (default) |
| `HILIGHT ON` | Enable syntax highlighting, language detected from file extension |
| `HILIGHT <language>` | Force a specific language (e.g. `HILIGHT JCL`, `HILIGHT REXX`, `HILIGHT COBOL`, `HILIGHT SQL`, `HILIGHT PYTHON`) |

Syntax highlighting is powered by [Pygments](https://pygments.org). For a full list of supported language names, see the [Pygments lexer list](https://pygments.org/docs/lexers/).

### Find and Change

```
FIND 'text'
CHANGE 'old' 'new'
CHANGE 'old' 'new' ALL
CHANGE 'old' 'new' ALL .labelA .labelB
```

Both single and double quotes are accepted as delimiters.

Aliases: `F` for `FIND`, `C` for `CHANGE`, `CAN` for `CANCEL`, `RESET`/`RES` for `CLEAR`.

- `FIND` — locate next occurrence (case-insensitive by default)
- `CHANGE` — replace next occurrence
- `CHANGE ... ALL` — replace all occurrences in file
- `CHANGE ... ALL .A .B` — replace all occurrences between labeled lines

### Labels

Type `.A`, `.B` etc. in the prefix column to assign a label to a line.
Labels are used to define ranges for `CHANGE ... ALL .A .B`.

## Function Keys

| Key | Action |
|-----|--------|
| F1 | Help |
| F3 | Save and exit |
| F5 | Repeat last FIND (RFIND) |
| F6 | Focus command bar (or hide it if already focused) |
| F7 / Page Up | Scroll up |
| F8 / Page Down | Scroll down |
| F10 | Scroll left |
| F11 | Scroll right |
| F12 | Exit without saving |
| Ctrl+Z | Undo last change |
| Ctrl+Y | Redo last undone change |

## Contributing

notispf is designed to be easy to extend. Adding a new prefix command takes three steps:

1. Write a handler function in `notispf/commands/line_cmds.py`:

```python
def cmd_trim(buffer: Buffer, line_idx: int, count: int) -> EditorResult:
    for i in range(line_idx, min(line_idx + count, len(buffer))):
        buffer.replace_line(i, buffer.lines[i].text.rstrip())
    return EditorResult(success=True)
```

2. Register it in the same file's `register()` function:

```python
registry.register_line_cmd(CommandSpec("T", cmd_trim, description="Trim trailing whitespace"))
```

3. Add tests in `tests/test_line_cmds.py`.

That's it — no changes to the prefix state machine, display, or app controller needed.

See [ARCHITECTURE.md](ARCHITECTURE.md) for a deeper overview of the codebase.

## License

MIT
