diff --git a/init.lua b/init.lua index 8539ffc..aac2fc1 100644 --- a/init.lua +++ b/init.lua @@ -2,6 +2,7 @@ local vim = vim local host = vim.loop.os_gethostname() obsidian_dir = "~/Documents/Notebooks" require("options") -- ./lua/options.lua +require("remote_clipboard").setup() -- ./lua/remote_clipboard.lua require("plugins") -- ./lua/plugins.lua require("utils.t3_functions") -- ./lua/utils/t3_functions.lua require("obsidian_config") -- ./lua/obsidian_config.lua @@ -104,7 +105,8 @@ if host == "xps13" then -- }) -- }) elseif host == "Intrepid" then - cyberdream() + -- Uses the full Omarchy theme catalog instead of a fixed colorscheme; + -- see set_colorscheme()/VimEnter below for the actual hot-reload wiring. -- require('tokyonight').setup({ -- style = "storm", -- "storm", "moon", "day", "night" -- transparent = false, -- Enable transparent background @@ -164,7 +166,9 @@ end local function set_colorscheme() if want_truecolor() then vim.o.termguicolors = true - if not pcall(vim.cmd.colorscheme, "cyberdream") then + if host == "Intrepid" then + require("omarchy_theme").setup() + elseif not pcall(vim.cmd.colorscheme, "cyberdream") then pcall(vim.cmd.colorscheme, "habamax") end else diff --git a/lua/omarchy_theme.lua b/lua/omarchy_theme.lua new file mode 100644 index 0000000..9b052ff --- /dev/null +++ b/lua/omarchy_theme.lua @@ -0,0 +1,109 @@ +-- Full Omarchy theme-catalog hot-reload, for hosts that want Neovim to track +-- the system theme (`omarchy-theme-set`) instead of a fixed colorscheme. +-- +-- Omarchy's default LazyVim config gets this for free from lazy.nvim's file +-- watcher + a symlinked plugin spec (lua/plugins/theme.lua -> +-- ~/.local/state/omarchy/current/theme/neovim.lua). This config doesn't run +-- lazy.nvim, so instead: read that same generated spec file directly (it's +-- the authoritative theme-name -> colorscheme mapping Omarchy maintains) and +-- watch the state directory ourselves with vim.uv. +local M = {} + +local state_dir = vim.fn.expand("~/.local/state/omarchy/current") +local theme_spec_file = state_dir .. "/theme/neovim.lua" + +local transparent_groups = { + "Normal", "NormalFloat", "FloatBorder", "Pmenu", "Terminal", "EndOfBuffer", + "FoldColumn", "Folded", "SignColumn", "LineNr", "CursorLineNr", "NormalNC", + "WhichKeyFloat", "TelescopeBorder", "TelescopeNormal", "TelescopePromptBorder", + "TelescopePromptTitle", "NvimTreeNormal", "NvimTreeVertSplit", "NvimTreeEndOfBuffer", + "NotifyINFOBody", "NotifyERRORBody", "NotifyWARNBody", "NotifyTRACEBody", "NotifyDEBUGBody", + "NotifyINFOTitle", "NotifyERRORTitle", "NotifyWARNTitle", "NotifyTRACETitle", "NotifyDEBUGTitle", + "NotifyINFOBorder", "NotifyERRORBorder", "NotifyWARNBorder", "NotifyTRACEBorder", "NotifyDEBUGBorder", +} + +local function apply_transparency() + for _, name in ipairs(transparent_groups) do + local ok, hl = pcall(vim.api.nvim_get_hl, 0, { name = name, link = false }) + if ok then + hl.bg = nil + vim.api.nvim_set_hl(0, name, hl) + end + end +end + +-- Pull the colorscheme name out of Omarchy's generated theme spec, e.g.: +-- return { +-- { "folke/tokyonight.nvim", priority = 1000 }, +-- { "LazyVim/LazyVim", opts = { colorscheme = "tokyonight-night" } }, +-- } +local function read_colorscheme() + local chunk, err = loadfile(theme_spec_file) + if not chunk then + vim.notify("omarchy_theme: " .. tostring(err), vim.log.levels.WARN) + return nil + end + + local ok, spec = pcall(chunk) + if not ok or type(spec) ~= "table" then + return nil + end + + for _, entry in ipairs(spec) do + if entry[1] == "LazyVim/LazyVim" and entry.opts and entry.opts.colorscheme then + return entry.opts.colorscheme + end + end +end + +function M.reload() + local colorscheme = read_colorscheme() + if not colorscheme then + return + end + + vim.o.background = "dark" + vim.cmd("highlight clear") + if vim.fn.exists("syntax_on") == 1 then + vim.cmd("syntax reset") + end + + if not pcall(vim.cmd.colorscheme, colorscheme) then + vim.notify("omarchy_theme: colorscheme '" .. colorscheme .. "' not found", vim.log.levels.WARN) + return + end + + apply_transparency() + vim.cmd("redraw!") +end + +local watching = false + +-- `omarchy-theme-set` swaps the whole `current/theme` directory (rm -rf + +-- mv), so re-arm the watch after every fire or it goes stale once the old +-- inode is gone. +local function watch() + if watching then + return + end + watching = true + + local handle = vim.uv.new_fs_event() + local function start() + handle:start(state_dir, {}, vim.schedule_wrap(function() + handle:stop() + vim.defer_fn(function() + M.reload() + start() + end, 150) + end)) + end + start() +end + +function M.setup() + M.reload() + watch() +end + +return M diff --git a/lua/plugins.lua b/lua/plugins.lua index fe84557..c7b1653 100644 --- a/lua/plugins.lua +++ b/lua/plugins.lua @@ -1,7 +1,32 @@ local vim = vim local host = vim.loop.os_gethostname() -vim.pack.add({ +-- Omarchy's full colorscheme catalog (mirrors omarchy-nvim's all-themes.lua), +-- only installed on hosts that hot-reload through lua/omarchy_theme.lua. +local omarchy_theme_plugins = { + { src = "https://github.com/ribru17/bamboo.nvim" }, + { src = "https://github.com/bjarneo/aether.nvim", version = "v3", name = "aether" }, + { src = "https://github.com/bjarneo/ethereal.nvim" }, + { src = "https://github.com/bjarneo/hackerman.nvim" }, + { src = "https://github.com/bjarneo/vantablack.nvim" }, + { src = "https://github.com/bjarneo/white.nvim" }, + { src = "https://github.com/catppuccin/nvim", name = "catppuccin" }, + { src = "https://github.com/neanias/everforest-nvim" }, + { src = "https://github.com/kepano/flexoki-neovim" }, + { src = "https://github.com/ellisonleao/gruvbox.nvim" }, + { src = "https://github.com/rebelot/kanagawa.nvim" }, + { src = "https://github.com/tahayvr/matteblack.nvim" }, + { src = "https://github.com/gthelding/monokai-pro.nvim" }, + { src = "https://github.com/EdenEast/nightfox.nvim" }, + { src = "https://github.com/rose-pine/neovim", name = "rose-pine" }, + { src = "https://github.com/ficcdaf/ashen.nvim" }, + { src = "https://github.com/folke/tokyonight.nvim" }, + { src = "https://github.com/OldJobobo/miasma.nvim" }, + { src = "https://github.com/OldJobobo/retro-82.nvim" }, + { src = "https://github.com/omacom-io/lumon.nvim" }, +} + +local plugin_specs = { -- { src = "https://github.com/folke/tokyonight.nvim" }, { src = "https://github.com/scottmckendry/cyberdream.nvim" }, { src = "https://github.com/nvim-tree/nvim-web-devicons" }, @@ -71,7 +96,15 @@ vim.pack.add({ { src = "https://github.com/amitds1997/remote-nvim.nvim" }, { src = "https://github.com/epwalsh/obsidian.nvim" }, { src = "https://github.com/monkeyxite/nvim-mail", version = "03b9d7d1eea8e6a06cd7f3e477e17f164d267ea5" }, -}) +} + +if host == "Intrepid" then + for _, spec in ipairs(omarchy_theme_plugins) do + table.insert(plugin_specs, spec) + end +end + +vim.pack.add(plugin_specs) require('mini.icons').setup({}) require('mini.pick').setup({}) diff --git a/lua/remote_clipboard.lua b/lua/remote_clipboard.lua new file mode 100644 index 0000000..873a8f8 --- /dev/null +++ b/lua/remote_clipboard.lua @@ -0,0 +1,100 @@ +-- Clipboard for sessions whose yanks may need to reach another machine: +-- every copy is emitted as OSC 52 (inside tmux this becomes a tmux buffer, +-- rebroadcast to every attached client, local or SSH). Paste prefers the +-- local Wayland clipboard when one is available, so content copied in other +-- apps remains pasteable; without a display, paste is an OSC 52 query that +-- tmux (or the terminal) answers. +-- +-- Ported from Omarchy's default nvim config (config/remote_clipboard.lua) so +-- this config keeps working over SSH/tmux the same way Omarchy's does. +local M = {} + +local function proc_lines(pid, file) + local ok, lines = pcall(vim.fn.readfile, "/proc/" .. pid .. "/" .. file) + return ok and lines or {} +end + +local function proc_ppid(pid) + for _, line in ipairs(proc_lines(pid, "status")) do + local ppid = line:match("^PPid:%s+(%d+)") + if ppid then + return tonumber(ppid) + end + end +end + +local function ancestor_process_named(name) + local pid = vim.fn.getpid() + + for _ = 1, 16 do + local ppid = proc_ppid(pid) + if not ppid or ppid <= 1 then + return false + end + + local comm = proc_lines(ppid, "comm")[1] or "" + if comm:find(name, 1, true) then + return true + end + + pid = ppid + end + + return false +end + +function M.setup() + local in_tmux = vim.env.TMUX ~= nil + local in_ssh = vim.env.SSH_TTY ~= nil or vim.env.SSH_CONNECTION ~= nil + local in_herdr = vim.env.HERDR_PANE_ID ~= nil or ancestor_process_named("herdr") + + if not (in_tmux or in_ssh or in_herdr) then + return + end + + local osc52 = require("vim.ui.clipboard.osc52") + local has_wayland = vim.env.WAYLAND_DISPLAY ~= nil + and vim.fn.executable("wl-copy") == 1 + and vim.fn.executable("wl-paste") == 1 + + local function copy(register) + local emit = osc52.copy(register) + + return function(lines) + if has_wayland then + local cmd = { "wl-copy", "--sensitive", "--type", "text/plain" } + if register == "*" then + cmd[#cmd + 1] = "--primary" + end + vim.fn.system(cmd, lines) + end + + emit(lines) + end + end + + local function paste(register) + if not has_wayland then + return osc52.paste(register) + end + + return function() + local cmd = { "wl-paste", "--no-newline" } + if register == "*" then + cmd[#cmd + 1] = "--primary" + end + + local lines = vim.fn.systemlist(cmd, "", 1) + return vim.v.shell_error == 0 and lines or {} + end + end + + vim.g.clipboard = { + name = "RemoteClipboard", + copy = { ["+"] = copy("+"), ["*"] = copy("*") }, + paste = { ["+"] = paste("+"), ["*"] = paste("*") }, + cache_enabled = 0, + } +end + +return M