# ghostty-tex

[Project page](https://adamdeprince.com/ghosttty-tex.html) ·
[Package download](https://distribution.goblinreactor.com/ghostty-tex/ghostty-tex-0.1.4.tar) ·
[Source archive](https://distribution.goblinreactor.com/ghostty-tex/ghostty-tex-0.1.4-source.tar.gz)

Terminal Emacs (`emacs -nw`) in [Ghostty](https://ghostty.org), local or over SSH:

- kills/copies go to the system clipboard via OSC 52
- compiled PDF/DVI opens on the **left** via the **Kitty graphics protocol** (not Sixel)
- the `.tex` source stays on the **right**

This is an Emacs package, not a replacement `init.el`.  It does not touch gptel, themes, or the rest of your config.  Turn it off and the hooks/advice/keys go away.

`kitty-graphics.el` is vendored ([cashmeredev/kitty-graphics.el](https://github.com/cashmeredev/kitty-graphics.el), GPL-2-or-later).

## Install

### 1. Drop-in directory (easiest to tar, easiest to delete)

```sh
tar xzf ghostty-tex-0.1.4.tar.gz -C ~/.emacs.d
# results in ~/.emacs.d/ghostty-tex-0.1.4/
# rename if you want a stable path:
mv ~/.emacs.d/ghostty-tex-0.1.4 ~/.emacs.d/ghostty-tex
```

`~/.emacs.d/early-init.el` (create it if you don't have one):

```elisp
(load (expand-file-name "ghostty-tex/ghostty-tex-early.el"
                        user-emacs-directory)
      nil t)
```

`~/.emacs.d/init.el` (or `~/.emacs`):

```elisp
(add-to-list 'load-path (expand-file-name "ghostty-tex" user-emacs-directory))
(require 'ghostty-tex)
(ghostty-tex-mode 1)
```

Restart Emacs.  Remove: delete `~/.emacs.d/ghostty-tex`, delete those three lines, restart.

### 2. `package.el` (install / uninstall from Emacs)

```sh
make dist          # produces dist/ghostty-tex-0.1.4.tar
```

Then `M-x package-install-file RET dist/ghostty-tex-0.1.4.tar RET`.

```elisp
(ghostty-tex-mode 1)
```

Still add the early-init snippet above (look in `elpa/ghostty-tex-0.1.4/` for `ghostty-tex-early.el`).

Remove: `M-x package-delete RET ghostty-tex RET`, drop `(ghostty-tex-mode 1)`, restart.

### 3. Not a full `init.el` blob

Don't copy someone else's entire `~/.emacs.d`.  That overwrites gptel, package lists, and machine-local customizations, and there is no clean uninstall.  This package is the extract of the Ghostty/LaTeX work only.

## Keys (TeX buffers)

| Key | Action |
|---|---|
| `C-c C-c` | save, run LaTeX, show PDF on the left |
| `C-u C-c C-c` | AUCTeX command prompt (BibTeX, Clean, …) |
| `C-c C-v` | view the existing PDF without compiling |
| `C-c n` / `M-n` | next PDF page |
| `C-c p` / `M-p` | previous PDF page |

Set `ghostty-tex-take-over-compile` to `nil` if you want stock `C-c C-c`.

Paste with the terminal (Cmd-V / Ctrl-Shift-V), not `C-y`.  OSC 52 is write-only.

## PDF render resolution

DocView pages are generated as PNGs sized for the terminal that is attached
right now.  Before choosing a DPI, kitty-graphics sends the xterm `CSI 16 t`
query and combines the returned cell width/height in pixels with the PDF
pane's width/height in cells.  The query is forced for every render decision;
an Emacs session kept alive across mosh disconnects therefore does not treat
the previous client's pixel geometry as current.

Inside tmux 3.6 or newer, kitty-graphics instead queries the live
`client_cell_width` and `client_cell_height` formats because tmux does not
reliably pass `CSI 16 t` through.  These values likewise follow the currently
attached client rather than the original mosh connection.

`kitty-graphics-doc-view-resolution-scale` controls source pixels per display
pixel.  Its default, `2.0`, gives sharp text and approximately 2x zoom
headroom; use `1.0` for exact-fit rendering.  Adaptive DPI can move up or down
without an artificial floor or ceiling: the freshly reported cell geometry and
the page pane dimensions determine the positive integer DPI.  Set the scale to
`nil` to disable adaptive DPI.

```elisp
;; Optional: exact-fit rendering.
(setq kitty-graphics-doc-view-resolution-scale 1.0)
```

Version 0.1.4 fixes a blank-preview race during adaptive reconversion:
DocView can rewrite a page between the pixel-size query and transmission.
Only complete PNG snapshots are now transmitted and cached; an empty or
partially written page is retried when conversion finishes.  After upgrading,
restart Emacs to discard any image IDs cached by the earlier version.

## Disable without deleting

```elisp
(ghostty-tex-mode -1)
```

or `M-x ghostty-tex-mode`.  Advice, hooks, and the TeX keymap are removed.  Restart Emacs after deleting the files.

## System packages

The machine you sit at must run **Ghostty**.  SSH hosts only need Emacs and the conversion tools.

### macOS

```sh
brew install emacs ghostscript imagemagick mupdf
brew install --cask ghostty
# LaTeX:
brew install --cask mactex-no-gui
```

### Linux (Debian/Ubuntu)

```sh
sudo apt-get install -y \
  emacs ghostscript dvipng \
  texlive-latex-base texlive-latex-recommended \
  mupdf-tools imagemagick ncurses-bin
```

| Package | Why |
|---|---|
| `emacs` | 27.1 or newer |
| `ghostscript` | DocView PDF rasterizer |
| `dvipng` | DVI → PNG |
| `texlive-latex-*` | `pdflatex` |
| `mupdf-tools` | `mutool`; faster PDF pages |
| `imagemagick` | kitty-graphics still conversion |
| `ncurses-bin` | `tic` for Ghostty terminfo on SSH hosts |

AUCTeX is optional but recommended: `M-x package-install RET auctex`.

On an SSH host, install Ghostty's terminfo so `TERM=xterm-ghostty` is valid:

```sh
infocmp -x xterm-ghostty | ssh HOST -- tic -x -
# macOS system infocmp is often too old:
# /opt/homebrew/opt/ncurses/bin/infocmp -x xterm-ghostty | ssh HOST -- tic -x -
```

### tmux

Kitty graphics need `set -g allow-passthrough on`.

## Tarball

```sh
make check
# compiles, runs unit tests, builds the archives, and installs the package.el
# archive into an isolated temporary Emacs directory as a release test

# dist/ghostty-tex-0.1.4.tar      -> M-x package-install-file
# dist/ghostty-tex-0.1.4.tar.gz   -> unpack into ~/.emacs.d
# dist/ghostty-tex-0.1.4-source.tar.gz -> source, Makefile, and tests
```
