Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions alacritty/.local/bin/alacritty-theme-select
Original file line number Diff line number Diff line change
@@ -1,18 +1,47 @@
#!/bin/sh

NVIM_STATE="$HOME/.local/share/nvim/theme.json"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make theme.json writes resilient (ensure directory + atomic replace).

Line 22 and Line 35 write directly to "$NVIM_STATE" with >. If ~/.local/share/nvim doesn’t exist, sync fails; and truncate-in-place can briefly expose invalid JSON to Neovim’s file watcher.

Suggested fix
 NVIM_STATE="$HOME/.local/share/nvim/theme.json"
+mkdir -p "$(dirname "$NVIM_STATE")"
+
+write_nvim_state() {
+  _tmp="$(mktemp "${NVIM_STATE}.tmp.XXXXXX")" || return 1
+  printf '{"colorscheme":"%s"}' "$1" > "$_tmp" && mv "$_tmp" "$NVIM_STATE"
+}
@@
-                printf '{"colorscheme":"%s"}' "$_s" > "$NVIM_STATE";;
+                write_nvim_state "$_s";;
@@
-      printf '{"colorscheme":"%s"}' "$_s" > "$NVIM_STATE"
+      write_nvim_state "$_s"
       ;;

Also applies to: 22-23, 35-35

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@alacritty/.local/bin/alacritty-theme-select` at line 3, The NVIM_STATE writes
at lines 22-23 and 35 are not resilient because they directly write to the file
without ensuring the parent directory exists, and they use non-atomic
truncation-in-place writes with `>`. To fix this, before any write operations to
NVIM_STATE, ensure the parent directory ~/.local/share/nvim exists by creating
it with mkdir -p. Then replace the direct `>` redirections with atomic writes:
write to a temporary file in the same directory, then use mv to atomically
replace the original file. This prevents failures when the directory doesn't
exist and ensures Neovim's file watcher never sees invalid JSON.


current_theme=$(grep import "$ALACRITTY_PATH"/theme.toml | sed 's/.*\///;s/\.toml.*//')

# Alacritty and nvim use different names for some themes, so we translate before syncing.
# tokyonight_* -> tokyonight-* (alacritty uses underscores, nvim uses dashes)
# rose-pine -> rose-pine-moon (base variant has no nvim equivalent, moon is closest)
new_theme=$(
find "$ALACRITTY_THEME_DIR_PATH" -maxdepth 1 -type f -name '*.toml' -exec basename {} .toml \; \
| sort \
| fzf --tmux 60% \
--preview "alacritty-theme {} > /dev/null && bat --color=always \"$ALACRITTY_THEME_DIR_PATH\"/{}.toml"
--preview "
alacritty-theme {} > /dev/null 2>&1
_s=\$(echo {} | sed 's/tokyonight_/tokyonight-/; s/^rose-pine$/rose-pine-moon/')
case \"\$_s\" in
rose-pine-moon|rose-pine-dawn|\
catppuccin-latte|catppuccin-frappe|catppuccin-macchiato|catppuccin-mocha|\
nord|\
tokyonight-night|tokyonight-storm|tokyonight-day|tokyonight-moon)
printf '{\"colorscheme\":\"%s\"}' \"\$_s\" > \"$NVIM_STATE\";;
esac
bat --color=always \"$ALACRITTY_THEME_DIR_PATH\"/{}.toml
"
)

sync_nvim() {
_s=$(echo "$1" | sed 's/tokyonight_/tokyonight-/; s/^rose-pine$/rose-pine-moon/')
case "$_s" in
rose-pine-moon|rose-pine-dawn|\
catppuccin-latte|catppuccin-frappe|catppuccin-macchiato|catppuccin-mocha|\
nord|\
tokyonight-night|tokyonight-storm|tokyonight-day|tokyonight-moon)
printf '{"colorscheme":"%s"}' "$_s" > "$NVIM_STATE"
;;
esac
}

if [ -z "$new_theme" ]; then
echo "Theme not selected."
alacritty-theme "$current_theme"
sync_nvim "$current_theme"
exit 1
fi

alacritty-theme "$new_theme"
sync_nvim "$new_theme"
2 changes: 1 addition & 1 deletion nvim/.config/nvim/after/plugin/starter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ require("mini.starter").setup({
section = "Explorer",
},
-- Configuration
{ name = "Theme", action = ":Themery", section = "Config" },
{ name = "Theme", action = ":lua vim.g.theme_picker()", section = "Config" },
{ name = "Pack Update", action = ":lua vim.pack.update()", section = "Config" },
{ name = "Check Health", action = ":checkhealth", section = "Config" },
-- Neovim
Expand Down
229 changes: 142 additions & 87 deletions nvim/.config/nvim/after/plugin/theme.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,94 +8,149 @@ require("tokyonight")
require("nord").setup({})

local themes = {
{
name = "rose-pine-moon",
colorscheme = "rose-pine-moon",
after = [[
os.execute('alacritty-theme rose-pine-moon > /dev/null 2>&1')
]],
},
{
name = "rose-pine-dawn",
colorscheme = "rose-pine-dawn",
after = [[
os.execute('alacritty-theme rose-pine-dawn > /dev/null 2>&1')
]],
},
{
name = "catppuccin-latte",
colorscheme = "catppuccin-latte",
after = [[
os.execute('alacritty-theme catppuccin-latte > /dev/null 2>&1')
]],
},
{
name = "catppuccin-frappe",
colorscheme = "catppuccin-frappe",
after = [[
os.execute('alacritty-theme catppuccin-frappe > /dev/null 2>&1')
]],
},
{
name = "catppuccin-macchiato",
colorscheme = "catppuccin-macchiato",
after = [[
os.execute('alacritty-theme catppuccin-macchiato > /dev/null 2>&1')
]],
},
{
name = "catppuccin-mocha",
colorscheme = "catppuccin-mocha",
after = [[
os.execute('alacritty-theme catppuccin-mocha > /dev/null 2>&1')
]],
},
{
name = "nord",
colorscheme = "nord",
after = [[
os.execute('alacritty-theme nord > /dev/null 2>&1')
]],
},
{
name = "tokyonight-night",
colorscheme = "tokyonight-night",
after = [[
vim.schedule(function() vim.cmd("colorscheme tokyonight-night") end)
os.execute('alacritty-theme tokyonight_night > /dev/null 2>&1')
]],
},
{
name = "tokyonight-storm",
colorscheme = "tokyonight-storm",
after = [[
vim.schedule(function() vim.cmd("colorscheme tokyonight-storm") end)
os.execute('alacritty-theme tokyonight_storm > /dev/null 2>&1')
]],
},
{
name = "tokyonight-day",
colorscheme = "tokyonight-day",
after = [[
vim.schedule(function() vim.cmd("colorscheme tokyonight-day") end)
os.execute('alacritty-theme tokyonight_day > /dev/null 2>&1')
]],
},
{
name = "tokyonight-moon",
colorscheme = "tokyonight-moon",
after = [[
vim.schedule(function() vim.cmd("colorscheme tokyonight-moon") end)
os.execute('alacritty-theme tokyonight_moon > /dev/null 2>&1')
]],
},
"rose-pine-moon",
"rose-pine-dawn",
"catppuccin-latte",
"catppuccin-frappe",
"catppuccin-macchiato",
"catppuccin-mocha",
"nord",
"tokyonight-night",
"tokyonight-storm",
"tokyonight-day",
"tokyonight-moon",
}

require("themery").setup({
themes = themes,
livePreview = true,
-- Alacritty uses underscores for tokyonight; everything else matches nvim's name.
local alacritty_map = {
["tokyonight-night"] = "tokyonight_night",
["tokyonight-storm"] = "tokyonight_storm",
["tokyonight-day"] = "tokyonight_day",
["tokyonight-moon"] = "tokyonight_moon",
}

local state_file = vim.fn.stdpath("data") .. "/theme.json"

local function apply_alacritty(scheme)
local name = alacritty_map[scheme] or scheme
vim.fn.jobstart({ "alacritty-theme", name }, { detach = true })
end

local function save_theme(scheme)
local f = io.open(state_file, "w")
if f then
f:write(vim.fn.json_encode({ colorscheme = scheme }))
f:close()
end
end

local function load_theme()
local f = io.open(state_file, "r")
if not f then
-- Migrate from themery's state file on first run.
f = io.open(vim.fn.stdpath("data") .. "/themery/state.json", "r")
end
if not f then return end
local content = f:read("*a")
f:close()
local ok, data = pcall(vim.fn.json_decode, content)
if ok and data and data.colorscheme then
pcall(vim.cmd, "colorscheme " .. data.colorscheme)
end
end

local function open_picker()
local original = vim.g.colors_name

local function restore()
if original then
pcall(vim.cmd, "colorscheme " .. original)
end
end

local pickers = require("telescope.pickers")
local finders = require("telescope.finders")
local conf = require("telescope.config").values
local actions = require("telescope.actions")
local action_state = require("telescope.actions.state")

local function apply_selected()
local sel = action_state.get_selected_entry()
if sel then
pcall(vim.cmd, "colorscheme " .. sel.value)
end
end

pickers.new({}, {
prompt_title = "Theme",
finder = finders.new_table({ results = themes }),
sorter = conf.generic_sorter({}),
attach_mappings = function(prompt_bufnr, map)
local function nav_next()
actions.move_selection_next(prompt_bufnr)
apply_selected()
end

local function nav_prev()
actions.move_selection_previous(prompt_bufnr)
apply_selected()
end

local function confirm()
local sel = action_state.get_selected_entry()
actions.close(prompt_bufnr)
if sel then
pcall(vim.cmd, "colorscheme " .. sel.value)
save_theme(sel.value)
else
restore()
end
end

local function cancel()
actions.close(prompt_bufnr)
restore()
end

map("i", "<C-n>", nav_next)
map("i", "<Down>", nav_next)
map("n", "j", nav_next)
map("n", "<Down>", nav_next)
map("i", "<C-p>", nav_prev)
map("i", "<Up>", nav_prev)
map("n", "k", nav_prev)
map("n", "<Up>", nav_prev)
map("i", "<CR>", confirm)
map("n", "<CR>", confirm)
map("i", "<Esc>", cancel)
map("n", "<Esc>", cancel)
map("i", "<C-c>", cancel)
map("n", "q", cancel)

return true
end,
}):find()
end

-- Expose for mini.starter and other callers.
vim.g.theme_picker = open_picker

vim.api.nvim_create_autocmd("ColorScheme", {
callback = function(ev)
apply_alacritty(ev.match)
end,
})

vim.keymap.set("n", "<leader>t", function()
vim.cmd("Themery")
end, { desc = "Theme picker (Themery)" })
load_theme()

-- Reload when alacritty-theme-select writes theme.json externally.
local watcher = vim.uv.new_fs_event()
if watcher then
watcher:start(state_file, {}, vim.schedule_wrap(function(err)
if not err then
load_theme()
end
end))
end

vim.keymap.set("n", "<leader>t", open_picker, { desc = "Theme picker" })
1 change: 0 additions & 1 deletion nvim/.config/nvim/lua/greg/pack.lua
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ vim.pack.add({
{ src = gh("nvim-telescope/telescope.nvim"), version = "master" },
{ src = gh("ThePrimeagen/harpoon"), version = "master" },

{ src = gh("zaldih/themery.nvim"), version = "main" },
{ src = gh("xiyaowong/nvim-transparent"), version = "main" },

{ src = gh("rose-pine/neovim"), name = "rose-pine", version = "main" },
Expand Down