# hx-remote | hxr
`hx-remote` is a small Unix-only bridge for opening files in new or already-running
[Helix](https://helix-editor.com/) sessions. It uses a Unix-domain socket for local
commands and Helix's LSP `window/showDocument` support to open and focus files.
The installed executable is named `hxr`:
```console
hxr README.md
hxr --listen
hxr --status
hxr --open src/main.rs Cargo.toml
hxr --open src/main.rs:50:12
hxr --stop
## Install
Helix 24.03 or newer is required.
```console
cargo install hx-remote
```
You can also clone this repository and install from the local copy.
```console
git clone https://github.com/FluxKraken/hxr
cd hxr
cargo install --path .
```
### Helix LSP Config
Add this once to `~/.config/helix/languages.toml` (or print the snippet with
`hxr --print-config`; a copy is also in `examples/helix/languages.toml`):
```toml
[language-server.hx-remote]
command = "hxr"
args = ["--lsp"]
[[language]]
name = "hx-remote"
scope = "source.hx-remote"
file-types = ["hxremote"]
language-servers = ["hx-remote"]
```
You can check that Helix sees the executable with:
```console
hx --health hx-remote
```
## Use
To start a receiving Helix instance and open files in one command, pass the
paths directly:
```console
hxr README.md
hxr src/main.rs:50:12 Cargo.toml
```
This launches Helix with the requested files followed by the bridge's sentinel
buffer. Several files may be passed. In the normal layout Helix focuses the
first one; when using `--helix-arg=--vsplit` or `--helix-arg=--hsplit`, the last
requested split is focused. The sentinel starts the bridge in the background.
Use `--` before a filename that begins with a hyphen, for example
`hxr -- -notes.md`.
The original two-command workflow remains available. Start the receiving Helix
instance from the directory you want to use as its workspace:
```console
hxr --listen
```
This creates and opens a small sentinel file under the user cache directory.
Keep that buffer open: its language server is the bridge. From another process,
shell, or file explorer, open files in that instance with:
```console
hxr --open /absolute/path/to/file
```
Relative paths are resolved by the sending `hxr` process, so file explorers may
pass either relative or absolute paths. Several files may be sent in one call;
Helix focuses the last one.
Positions use one-based line and column numbers in either workflow:
```console
hxr src/main.rs:50:12
hxr --open src/main.rs:50
hxr --open src/main.rs:50:12
```
To open piped text, use `-`. The bridge keeps a temporary file alive for the
rest of the Helix session. `--stdin-name` supplies an extension for syntax
detection:
```console
The default socket is `$XDG_RUNTIME_DIR/hx-remote.sock` when that directory is
available, otherwise a per-user socket in the system temporary directory. Set
`HXR_SOCKET` or pass `--socket PATH` to run independent Helix listeners:
```console
HXR_SOCKET=/tmp/project-a.sock hxr --listen
HXR_SOCKET=/tmp/project-a.sock hxr --open src/lib.rs
```
Extra Helix arguments can be supplied when launching a session by repeating
`--helix-arg`:
```console
hxr --helix-arg=-w --helix-arg=/tmp/helix-working-directory --listen
hxr --helix-arg=-w --helix-arg=/tmp/helix-working-directory README.md
```
Check whether the selected socket is open and accepting connections with:
```console
hxr --status
```
The command exits successfully while a listener is present and unsuccessfully
otherwise. Stop the bridge sidecar gracefully with `hxr --stop`. If it is not
responding normally, `hxr --stop --force` terminates it immediately. Both
commands affect only the server selected by `--socket` or `HXR_SOCKET`; they do
not close Helix itself.
## How it works
When paths are passed directly, `hxr` launches Helix with those files followed
by the `.hxremote` sentinel buffer (or reverses that file order for a split
layout). This keeps a requested file focused while Helix starts `hxr --lsp` for
the sentinel in the background. That process performs the minimal LSP
initialization handshake and listens on a local Unix socket. Later, `hxr --open`
sends a path to the socket, and the sidecar emits a `window/showDocument` request
with `takeFocus = true`. The socket is permissioned to the current user (`0600`)
and stale socket files are removed safely at startup.