Skip to content
42 changes: 39 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@

A personalized Neovim configuration based on [kickstart.nvim](https://github.com/nvim-lua/kickstart.nvim), tailored for Java and Go development with a focus on clean keybindings, git integration, and a minimal UI.

## Requirements

- **Neovim 0.10+** (uses `vim.keymap`, `vim.diagnostic.config`, and other modern APIs)
- **JDK 21+** for Java LSP (jdtls)
- Nerd Font (JetBrainsMono recommended)

## Quick Install

One-liner that installs all dependencies and clones the config (supports **macOS**, **CentOS/RHEL**, and **Azure Linux/CBL-Mariner**):

```sh
sh -c "$(curl -fsSL https://raw.githubusercontent.com/advpetc/kickstart.nvim/master/install.sh)"
sh -c "$(curl -fsSL https://raw.githubusercontent.com/advpetc/kickstart.nvim/rdev-setup/install.sh)"
```

This will:
Expand All @@ -26,7 +32,7 @@ If you prefer to install dependencies yourself:

```sh
# 1. Clone the config
git clone https://github.com/advpetc/kickstart.nvim.git ~/.config/nvim
git clone -b rdev-setup https://github.com/advpetc/kickstart.nvim.git ~/.config/nvim

# 2. Install dependencies (macOS example)
brew install neovim ripgrep fd gh node go
Expand All @@ -50,6 +56,26 @@ sudo dnf install -y git make gcc gcc-c++ unzip curl ripgrep fd-find nodejs

</details>

<details><summary>Azure Linux / CBL-Mariner</summary>

```sh
# Neovim (from GitHub release)
curl -fsSL https://github.com/neovim/neovim/releases/download/v0.10.4/nvim-linux-x86_64.tar.gz -o /tmp/nvim.tar.gz
sudo mkdir -p /opt/nvim && sudo tar -xzf /tmp/nvim.tar.gz -C /opt/nvim --strip-components=1
sudo ln -sf /opt/nvim/bin/nvim /usr/local/bin/nvim

# System tools (use tdnf on CBL-Mariner 2.0, dnf on Azure Linux 3.0)
sudo tdnf install -y git make gcc unzip curl ripgrep nodejs

# fd (not in repos — install from GitHub release)
FD_VERSION=$(curl -fsSL https://api.github.com/repos/sharkdp/fd/releases/latest | grep '"tag_name"' | sed -E 's/.*"v?([^"]+)".*/\1/')
curl -fsSL "https://github.com/sharkdp/fd/releases/download/v${FD_VERSION}/fd-v${FD_VERSION}-x86_64-unknown-linux-gnu.tar.gz" -o /tmp/fd.tar.gz
tar -xzf /tmp/fd.tar.gz -C /tmp
sudo cp /tmp/fd-v${FD_VERSION}-x86_64-unknown-linux-gnu/fd /usr/local/bin/fd
```

</details>

## Plugins

| Plugin | Purpose |
Expand Down Expand Up @@ -213,11 +239,21 @@ Sessions are stored in `~/.local/state/nvim/sessions/` via `mini.sessions`:

The Java configuration uses [nvim-jdtls](https://github.com/mfussenegger/nvim-jdtls) with:

- **JDK 21** (Microsoft build) at `/Library/Java/JavaVirtualMachines/jdk21.0.6-msft.jdk/Contents/Home`
- **JDK 21+** required (auto-detected, see resolution order below)
- **Gradle & Maven** import support with source downloading
- **DAP debugging** with hot code replace
- **Workspace**: `~/.local/share/nvim/jdtls-workspace/`

### JDK Resolution Order

1. `JDTLS_JAVA_HOME` environment variable (explicit override)
2. Known JDK 21 paths on Linux:
- `/export/apps/jdk/JDK-21_0_0-msft` (LinkedIn internal)
- `/usr/lib/jvm/java-21-openjdk`
- `/usr/lib/jvm/java-21-openjdk-amd64`
3. macOS: `/usr/libexec/java_home -v 21`
4. `JAVA_HOME` environment variable (fallback)

> Run `./gradlew build` before opening a project to generate required jars.
> Use `<leader>jx` (`:JdtlsClearCache`) to reset the jdtls workspace if things go wrong.

Expand Down
35 changes: 20 additions & 15 deletions init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,22 @@ vim.keymap.set('n', '<C-k>', '<C-w><C-k>', { desc = 'Move focus to the upper win
vim.keymap.set('n', '<leader>cp', function()
local path = vim.fn.expand '%'
vim.fn.setreg('+', path)
-- Also copy via OSC 52 for remote SSH sessions
local ok, osc52 = pcall(require, 'osc52')
if ok then
osc52.copy(path)
end
print('Copied: ' .. path)
end, { desc = '[C]opy file [P]ath (relative)' })

vim.keymap.set('n', '<leader>cP', function()
local path = vim.fn.expand '%:p'
vim.fn.setreg('+', path)
-- Also copy via OSC 52 for remote SSH sessions
local ok, osc52 = pcall(require, 'osc52')
if ok then
osc52.copy(path)
end
print('Copied: ' .. path)
end, { desc = '[C]opy file [P]ath (absolute)' })

Expand All @@ -240,6 +250,11 @@ vim.keymap.set('n', '<leader>cl', function()
return
end
vim.fn.setreg('+', url)
-- Also copy via OSC 52 for remote SSH sessions
local ok, osc52 = pcall(require, 'osc52')
if ok then
osc52.copy(url)
end
vim.notify('Copied: ' .. url, vim.log.levels.INFO)
end, { desc = '[C]opy GitHub [L]ink' })

Expand Down Expand Up @@ -658,7 +673,9 @@ require('lazy').setup({
-- By default, Neovim doesn't support everything that is in the LSP specification.
-- When you add blink.cmp, luasnip, etc. Neovim now has *more* capabilities.
-- So, we create new capabilities with blink.cmp, and then broadcast that to the servers.
local capabilities = require('blink.cmp').get_lsp_capabilities()
local capabilities = vim.lsp.protocol.make_client_capabilities()
local ok, blink = pcall(require, 'blink.cmp')
if ok then capabilities = vim.tbl_deep_extend('force', capabilities, blink.get_lsp_capabilities()) end

-- Enable the following language servers
-- Feel free to add/remove any LSPs that you want here. They will automatically be installed.
Expand Down Expand Up @@ -959,20 +976,8 @@ require('lazy').setup({
end,
},

{ -- Highlight, edit, and navigate code
'nvim-treesitter/nvim-treesitter',
config = function()
local filetypes = { 'bash', 'c', 'diff', 'html', 'java', 'lua', 'luadoc', 'markdown', 'markdown_inline', 'query', 'vim', 'vimdoc' }
-- Only auto-install parsers if tree-sitter CLI is available
if vim.fn.executable 'tree-sitter' == 1 then
require('nvim-treesitter').install(filetypes)
end
vim.api.nvim_create_autocmd('FileType', {
pattern = filetypes,
callback = function() vim.treesitter.start() end,
})
end,
},
-- Note: Neovim 0.11+ has built-in treesitter support
-- Treesitter will be enabled automatically for supported filetypes

-- The following comments only work if you have downloaded the kickstart repo, not just copy pasted the
-- init.lua. If you want these files, they are in the repository, so you can just download them and
Expand Down
126 changes: 123 additions & 3 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# bash install.sh --help # show help
#
# One-liner (no clone needed):
# sh -c "$(curl -fsSL https://raw.githubusercontent.com/advpetc/kickstart.nvim/master/install.sh)"
# sh -c "$(curl -fsSL https://raw.githubusercontent.com/advpetc/kickstart.nvim/rdev-setup/install.sh)"
#
set -euo pipefail

Expand Down Expand Up @@ -481,6 +481,125 @@ install_jdk() {
esac
}

# ─── Setup JDTLS_JAVA_HOME (LinkedIn environments) ───────────────────────────

setup_jdtls_java_home() {
log_step "JDTLS Java Configuration"

local jdk_base_dir="/export/apps/jdk"
local selected_jdk=""
local selected_version=0
local is_compatible=false

# Check if the LinkedIn JDK directory exists
if [ ! -d "$jdk_base_dir" ]; then
log_info "JDK directory $jdk_base_dir not found — skipping JDTLS_JAVA_HOME setup"
log_info "If jdtls fails, set JDTLS_JAVA_HOME manually to your Java 21+ installation"
return 0
fi

# Scan for all JDK installations and find the best one
log_info "Scanning for Java installations in $jdk_base_dir..."

while IFS= read -r jdk_dir; do
local jdk_path="$jdk_base_dir/$jdk_dir"

# Skip if not a directory or no java binary
[ ! -d "$jdk_path" ] && continue
[ ! -x "$jdk_path/bin/java" ] && continue

# Extract version number from directory name (e.g., JDK-21_0_0-msft -> 21)
local version_major
if [[ "$jdk_dir" =~ JDK-([0-9]+) ]]; then
version_major="${BASH_REMATCH[1]}"
else
continue
fi

# Prefer Java 21+ (compatible with jdtls), but track highest version found
if [ "$version_major" -ge 21 ]; then
if [ "$version_major" -gt "$selected_version" ]; then
selected_jdk="$jdk_path"
selected_version="$version_major"
is_compatible=true
fi
elif [ "$version_major" -gt "$selected_version" ]; then
# Fallback: track highest version even if < 21
selected_jdk="$jdk_path"
selected_version="$version_major"
fi
done < <(ls "$jdk_base_dir" 2>/dev/null)

# No JDK found at all
if [ -z "$selected_jdk" ]; then
log_warn "No JDK installations found in $jdk_base_dir"
log_info "If jdtls fails, set JDTLS_JAVA_HOME manually to your Java 21+ installation"
return 0
fi

# Verify the selected JDK is actually executable
if ! "$selected_jdk/bin/java" -version &>/dev/null; then
log_warn "Selected JDK at $selected_jdk is not executable"
return 0
fi

# Provide appropriate feedback based on version
if [ "$is_compatible" = true ]; then
log_ok "Found Java $selected_version at $selected_jdk (compatible with jdtls)"
else
log_warn "Found Java $selected_version at $selected_jdk"
log_warn "jdtls requires Java 21+. LSP may fail to start."
log_info "Install Java 21+ and re-run this script, or set JDTLS_JAVA_HOME manually"
fi

# Add to .bashrc if not already there
if [ -f "$HOME/.bashrc" ]; then
if grep -q "export JDTLS_JAVA_HOME=" "$HOME/.bashrc" 2>/dev/null; then
log_info "Updating JDTLS_JAVA_HOME in .bashrc..."
# Remove old entry and add new one
sed -i.bak '/export JDTLS_JAVA_HOME=/d' "$HOME/.bashrc"
sed -i.bak '/# Java.*for JDTLS/d' "$HOME/.bashrc"
else
log_info "Adding JDTLS_JAVA_HOME to .bashrc..."
fi
cat >> "$HOME/.bashrc" <<EOF

# Java $selected_version for JDTLS (Neovim Java LSP)
export JDTLS_JAVA_HOME=$selected_jdk
EOF
log_ok "JDTLS_JAVA_HOME added to .bashrc"
fi

# Add to .zshrc if it exists
if [ -f "$HOME/.zshrc" ]; then
if grep -q "export JDTLS_JAVA_HOME=" "$HOME/.zshrc" 2>/dev/null; then
log_info "Updating JDTLS_JAVA_HOME in .zshrc..."
# Remove old entry and add new one
sed -i.bak '/export JDTLS_JAVA_HOME=/d' "$HOME/.zshrc"
sed -i.bak '/# Java.*for JDTLS/d' "$HOME/.zshrc"
else
log_info "Adding JDTLS_JAVA_HOME to .zshrc..."
fi
cat >> "$HOME/.zshrc" <<EOF

# Java $selected_version for JDTLS (Neovim Java LSP)
export JDTLS_JAVA_HOME=$selected_jdk
EOF
log_ok "JDTLS_JAVA_HOME added to .zshrc"
fi

# Export for current session
export JDTLS_JAVA_HOME="$selected_jdk"

if [ "$is_compatible" = true ]; then
log_ok "JDTLS configured to use Java $selected_version"
log_info "Environment variable will be available in new shells. Current session already has it."
else
log_warn "JDTLS configured with Java $selected_version (may not work - needs 21+)"
log_info "Environment variable will be available in new shells. Current session already has it."
fi
}

# ─── Install Nerd Font ────────────────────────────────────────────────────────

install_nerd_font() {
Expand Down Expand Up @@ -579,7 +698,7 @@ clone_nvim_config() {

log_info "Cloning Neovim config from $NVIM_CONFIG_REPO..."
mkdir -p "$(dirname "$NVIM_CONFIG_DIR")"
git clone "$NVIM_CONFIG_REPO" "$NVIM_CONFIG_DIR"
git clone -b rdev-setup "$NVIM_CONFIG_REPO" "$NVIM_CONFIG_DIR"
log_ok "Neovim config cloned to $NVIM_CONFIG_DIR"
}

Expand Down Expand Up @@ -663,7 +782,7 @@ show_help() {
echo "Usage: bash install.sh"
echo ""
echo "One-liner install (no clone needed):"
echo " sh -c \"\\\$(curl -fsSL https://raw.githubusercontent.com/advpetc/kickstart.nvim/master/install.sh)\""
echo " sh -c \"\\\$(curl -fsSL https://raw.githubusercontent.com/advpetc/kickstart.nvim/rdev-setup/install.sh)\""
echo ""
echo "Installs all dependencies for the Neovim configuration and clones the"
echo "config repo to ~/.config/nvim/ (backs up any existing config)."
Expand Down Expand Up @@ -711,6 +830,7 @@ main() {
install_tree_sitter_cli # after Node.js — uses npm on Linux
install_go
install_jdk
setup_jdtls_java_home # Configure Java 21 for jdtls if available
install_nerd_font
setup_li_format
bootstrap_lazy_nvim
Expand Down
33 changes: 33 additions & 0 deletions lua/custom/plugins/clipboard.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
-- OSC 52 clipboard support for remote SSH sessions
-- Works without X11 forwarding in modern terminals (iTerm2, WezTerm, Alacritty, Windows Terminal)
return {
{
'ojroques/nvim-osc52',
config = function()
require('osc52').setup {
max_length = 0, -- Maximum length of selection (0 for no limit)
silent = false, -- Disable message on successful copy
trim = false, -- Trim text before copy
}

-- Auto-copy ALL yanks to system clipboard via OSC 52
local function copy()
if vim.v.event.operator == 'y' then
-- Copy from the register that was yanked to
local register = vim.v.event.regname
if register == '' then
-- Default register, use unnamed register
require('osc52').copy_register '"'
else
require('osc52').copy_register(register)
end
end
end

vim.api.nvim_create_autocmd('TextYankPost', { callback = copy })

-- Manual copy keymap (copies visual selection to system clipboard)
vim.keymap.set('v', '<leader>y', require('osc52').copy_visual, { desc = 'Copy to system clipboard (OSC52)' })
end,
},
}
2 changes: 2 additions & 0 deletions lua/custom/plugins/git.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ return {
{ '<leader>gh', '<cmd>DiffviewFileHistory %<cr>', desc = 'Git file history' },
{ '<leader>gH', '<cmd>DiffviewFileHistory<cr>', desc = 'Git branch history' },
{ '<leader>gc', '<cmd>DiffviewClose<cr>', desc = 'Close diff view' },
{ '<leader>gR', '<cmd>!git reset --hard<cr>', desc = 'Git reset --hard (entire repo)' },
{ '<leader>gr', '<cmd>!git reset<cr>', desc = 'Git reset (unstage all, keep changes)' },
},
opts = {
enhanced_diff_hl = true,
Expand Down
Loading