Metadata-Version: 2.4
Name: turbopython-ide
Version: 0.5.0
Summary: Turbo Pascal's IDE, for Python: a terminal desktop of windows, menus and a debugger
Keywords: terminal,tui,ide,editor,python,borland,turbo-pascal
License-Expression: Apache-2.0
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: POSIX
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: User Interfaces
Classifier: Topic :: Terminals
Classifier: Typing :: Typed
Requires-Dist: turbodesk[syntax]>=0.2
Requires-Python: >=3.12
Description-Content-Type: text/markdown

# Turbo Python

A Python IDE in the shape of Turbo Pascal 7.0: a desktop of windows, a menu bar, a status line, and the compile-land-on-the-error-fix-recompile loop that made the original worth using.

```
   File  Edit  Search  Run  Compile  Debug  Tools  Options  Window  Help
╔[■]════════════════════════════ GREET.PY ═════════════════════════════ 1 [↑]╗
║ 1 def greet(name):                                                         ║
║ 2     """Say hello."""                                                     ║
║ 3     return f"hello {name}"                                               ║
║ 4                                                                          ║
║ 5                                                                          ║
║ 6 for who in ['world', 'turbodesk']:                                       ║
║ 7     print(greet(who))                                                    ║
║ 8                                                                          ║
║                                                                            ║
╚  1:1 ══════════════════════════════════════════════════════════════════════◢
 F1 Help  F2 Save  F3 Open  Alt+F9 Compile  F9 Make  F10 Menu
```

## Run it

```sh
uv sync
uv run turbopython greet.py
```

`F10` opens the menu bar and `File ▸ Exit` leaves, so there is a way out before you have learned a single key.

## What it does today

**Run a program and land on the line that broke it.** A traceback goes into the Messages window as a jump list, and the cursor lands on the deepest frame in *your* code — not the one inside `json/decoder.py`, which is not a file you can fix.

**Compile without running.** `Alt-F9` is `compile(src, name, "exec")`: instant, and a `SyntaxError` puts the message on the window's top line with the cursor on the column it names.

**Make and test the way Python projects actually do.** `Compile ▸ Make` reads the nearest `Makefile` and lists its targets; `Run ▸ Tests` runs `pytest` and puts every failure where <kbd>Enter</kbd> jumps to it. Borland's Make byte-compiled the units a program needed, which is a step Python does for itself.

```
   File  Edit  Search  Run  Compile  Debug  Tools  Options  Window  Help
╔[■]══════════════════┌────────────────────────┐═══════════════════════ 1 [↑]╗
║ 1 def greet(name):  │ Run            Ctrl-F9 │                             ║
║ 2     """Say hello."│ Tests                  │                             ║
║ 3     return f"hello├────────────────────────┤                             ║
║ 4                   │ Step over           F8 │                             ║
║ 5                   │ Trace into          F7 │                             ║
║ 6 for who in ['world│ Go to cursor        F4 │                             ║
║ 7     print(greet(wh├────────────────────────┤                             ║
║ 8                   │ Program reset  Ctrl-F2 │                             ║
║                     │ Parameters...          │                             ║
║                     └────────────────────────┘                             ║
╚  1:1 ══════════════════════════════════════════════════════════════════════◢
 F1 Help  F2 Save  F3 Open  Alt+F9 Compile  F9 Make  F10 Menu
```

Greyed items are the ones with nothing behind them *right now* — no window open, no program running — which is how Borland's menus worked. It is worth knowing what that greying cannot tell you: an item naming a command nobody ever wrote greys identically, and three of those sat on these menus for months. A test now reads `commands.py` and fails if a menu item names something unimplemented.

**See the shape of the project.** `Search ▸ Outline` docks a window showing what is in the file in front, rebuilt from the live buffer as you type. `Search ▸ Class browser` is the same `ast` walk read across every file: what derives from what, project-wide, with the module beside each class. Arrows walk either one and open the file it names; Space folds. Both are stdlib and neither needs a language server. `Ctrl+Enter` on a name goes to where this file defines it, and looks for a module only when it does not.

**A language server, when there is one.** `ruff server` starts in the background after the first frame and never before it: the IDE is up and working without one, which is the rule the whole layer is built to. Diagnostics land in the Messages window as the same jump list the compiler's errors and the test failures use — <kbd>Enter</kbd> goes to the line. `Tools ▸ Diagnostics` lists them, and the status line says which mode you are in (`lsp`, `lsp down`, or nothing at all when none was asked for). No node runtime, and nothing on any menu exists only when a server is running.

**Find a file by typing at it.** `File ▸ Find file` (`Shift-F3`) is a fuzzy picker over the project — `wfr` finds `widgets/frame.py`. `F3` still opens the tree, because the two answer different questions: one is for looking around, the other for when you already know the name.

**A primary file, which is what 7.0 called a run configuration.** `Compile ▸ Primary file...` names the program Run acts on however many windows are open over it, so editing a module and pressing Run does not run the module. `Clear primary file` gives the front window back.

**An editor with the things an editor needs.** Syntax colouring, line numbers, find and replace, undo that groups a run of keystrokes, `standard` / `vim` / `emacs` keymaps, and a mouse that puts the caret where you press and selects what you drag over.

**Windows.** Overlapping, draggable by the title bar, resizable from any corner, zoom, tile, cascade. `Alt-1` to `Alt-9` raise one by number.

**Ruff, mypy and pytest** in the Tools menu, each parsed into the same jump list.

## Keys

Two schemes, and it asks which on first run rather than guessing:

- **Turbo Pascal** — what Borland shipped. Needs a terminal that sends Alt.
- **Modern** — every Turbo binding that works anyway, plus a second key for each one Borland put on Alt: `F7` for `Alt-F9`, `F12` for `Alt-F5`, `Ctrl-W` for `Alt-F3`, `Ctrl-Q` for `Alt-X`.

**macOS sends no Alt by default.** The Option key composes characters there — `Option-E` then `e` is `é` — so `Alt-X` never arrives. Modern is the default on a Mac, and `Help ▸ Key test` says which setting turns Alt on for your terminal (`Use Option as Meta key` in Terminal.app, `Esc+` in iTerm2).

The menu shows the key the *active* scheme binds, so an accelerator never promises something that does nothing.

## What it is not, yet

No debugger. That is the next milestone: breakpoints in the gutter, step and trace, a watch window and the call stack, over `bdb` in a subprocess. No class browser, no project files, no REPL window. `notes/turbopython-ide.md` in this repository is the plan, and it is honest about what is missing.

## Why it exists

It is the largest application built on [turbodesk](https://turbodesk.lab.abilian.com), and it was built to find out what the library was missing. It found a great deal: the window stack, the menu bar, focus groups, drag gestures, an editor gutter and syntax colouring are all in the library now because this needed them. `notes/turbodesk-roadmap.md` records that trade in both directions.
