# neoche Neovim editor for Eclipse Che and Red Hat OpenShift Dev Spaces. Runs Neovim in the browser via [ttyd](https://github.com/tsl0922/ttyd), following the same init container injection pattern as [che-code](https://github.com/che-incubator/che-code). ## Quick Start Append to your Dev Spaces dashboard URL: ``` ?che-editor=neoche/neovim/insiders ``` Or add to your devfile: ```yaml attributes: che-editor: neoche/neovim/insiders ``` Example -- open any GitHub repo with neoche: ``` https:///#https://github.com//?che-editor=neoche/neovim/insiders ``` ## Customizing Neovim ### Dotfiles via DOTFILES_REPO Set `DOTFILES_REPO` to a git URL containing your dotfiles. The entrypoint clones it at startup and: - Copies `.config/` into `$HOME` (for nvim config, etc.) - Copies `dot_*` prefixed files/dirs as hidden files (e.g. `dot_zshrc` becomes `$HOME/.zshrc`, `dot_oh-my-zsh` becomes `$HOME/.oh-my-zsh`) The editor definition sets this via an env var on the `neovim-runtime` component. For private repos, create a Kubernetes secret with a `DOTFILES_TOKEN` key in the workspace namespace: ```yaml apiVersion: v1 kind: Secret metadata: name: neoche-dotfiles namespace: labels: controller.devfile.io/mount-to-devworkspace: "true" controller.devfile.io/watch-secret: "true" annotations: controller.devfile.io/mount-as: env type: Opaque stringData: DOTFILES_TOKEN: ``` The entrypoint injects the token into the clone URL automatically. ### Bootstrap a Distribution If you don't have your own config, set the `NVIM_DISTRO` environment variable to bootstrap one of these distributions on first launch: | Value | Distribution | |-------|-------------| | `lazyvim` | [LazyVim](https://github.com/LazyVim/starter) | | `astrovim` | [AstroNvim](https://github.com/AstroNvim/template) | | `nvchad` | [NvChad](https://github.com/NvChad/starter) | | `kickstart` | [kickstart.nvim](https://github.com/nvim-lua/kickstart.nvim) | Set it in your devfile: ```yaml components: - name: neovim-runtime container: env: - name: NVIM_DISTRO value: lazyvim ``` The bootstrap only runs when `$HOME/.config/nvim` does not exist, so it won't overwrite dotfiles or a previously bootstrapped config. `DOTFILES_REPO` is checked first, then `NVIM_DISTRO`. ### Persistent Storage Dev Spaces persists `/home/user` across workspace restarts using a PVC. Plugins installed by lazy.nvim or any other plugin manager survive restarts. Treesitter parsers are also cached. ### Shell Set `NEOCHE_SHELL` to launch Neovim inside a shell (e.g. `zsh` or `bash`). When set, ttyd runs ` -c "nvim ."` instead of `nvim .` directly. This gives you your shell environment (aliases, prompt, PATH) when you `:terminal` or suspend Neovim. ```yaml env: - name: NEOCHE_SHELL value: zsh ``` The shell must be available in the workspace base image (UDI ships both bash and zsh). ### Auto Plugin Init On startup, if `$HOME/.config/nvim` exists (from dotfiles or distribution bootstrap), the entrypoint runs a headless Neovim pass to sync plugins before launching ttyd: ``` nvim --headless "+Lazy! sync" +qa ``` This ensures plugins and treesitter parsers are installed before you interact with the editor. With persistent storage, this only runs once. ### Treesitter Note If your nvim config uses nvim-treesitter, set `prefer_git = true` in the treesitter install config. The curl-based download method fails in some container environments due to GitHub archive naming changes: ```lua require("nvim-treesitter.install").prefer_git = true ``` ## Architecture neoche uses the same two-phase init container pattern as che-code: 1. **preStart**: The `neovim-injector` init container copies Neovim binaries (glibc + musl), ttyd, machine-exec, and entrypoint scripts into a shared `/neovim` volume 2. **postStart**: The workspace container runs `entrypoint-volume.sh`, which: - Detects the platform (glibc or musl) via `ldd /bin/ls` - Starts machine-exec on port 3333 - Clones dotfiles if `DOTFILES_REPO` is set (`.config/` and `dot_*` files) - Bootstraps a Neovim distribution if `NVIM_DISTRO` is set - Runs headless plugin sync if nvim config exists - Launches ttyd serving Neovim on port 7681 (optionally inside `NEOCHE_SHELL`) ### Environment Variables | Variable | Default | Description | |----------|---------|-------------| | `DOTFILES_REPO` | (empty) | Git URL of dotfiles repo | | `DOTFILES_TOKEN` | (empty) | PAT for private dotfiles repos (injected via secret) | | `NVIM_DISTRO` | (empty) | Bootstrap a Neovim distribution on first launch | | `NEOCHE_SHELL` | (empty) | Shell to wrap Neovim in (e.g. `zsh`, `bash`) | | `PROJECT_SOURCE` | `/projects` | Working directory for Neovim | ## Building ``` make build # build the container image make test-standalone # run locally at http://localhost:7681 make push # push to quay.io/pfeifferj/neoche:insiders ``` ### Build Args | Arg | Default | Description | |-----|---------|-------------| | `NVIM_VERSION` | `v0.10.4` | Neovim release tag | | `TTYD_VERSION` | `1.7.7` | ttyd release tag | ## Deploying to OpenShift Dev Spaces ### 1. Push the image ``` make build && make push ``` ### 2. Register the editor ``` make deploy-editor ``` This creates the editor definition ConfigMap in your Dev Spaces namespace with the required `app.kubernetes.io/part-of=che.eclipse.org` and `app.kubernetes.io/component=editor-definition` labels. ### 3. Configure image pull access The image is pulled from `quay.io/pfeifferj/neoche:insiders`. Add the registry credentials to the cluster's global pull secret: ``` oc get secret pull-secret -n openshift-config -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d > /tmp/ps.json # merge your registry creds into /tmp/ps.json oc set data secret/pull-secret -n openshift-config --from-file=.dockerconfigjson=/tmp/ps.json ``` ### 4. Storage Dev Spaces needs a StorageClass and PV for workspace PVCs. For bare-metal clusters without a dynamic provisioner: ``` # create StorageClass oc apply -f - <] EOF ``` Note: with `Retain` policy, you must clear `spec.claimRef` on the PV after each workspace deletion so it can rebind: ``` oc patch pv devspaces-pv --type json -p '[{"op":"remove","path":"/spec/claimRef"}]' ``` ## Standalone Testing Run outside of Che for quick testing: ``` podman run --rm -p 7681:7681 quay.io/pfeifferj/neoche:insiders ``` Open http://localhost:7681 in a browser. Test with a distribution: ``` podman run --rm -p 7681:7681 -e NVIM_DISTRO=lazyvim quay.io/pfeifferj/neoche:insiders ``` ## License [Eclipse Public License 2.0](LICENSE)