-- http://lua-users.org/wiki/StringTrim function trim6(s) return s:match '^()%s*$' and '' or s:match '^%s*(.*%S)' end -- from norcalli/nvim_utils function nvim_create_augroups(definitions) for group_name, definition in pairs(definitions) do vim.api.nvim_command('augroup ' .. group_name) vim.api.nvim_command('autocmd!') for _, def in ipairs(definition) do -- if type(def) == 'table' and type(def[#def]) == 'function' then -- def[#def] = lua_callback(def[#def]) -- end local command = table.concat(vim.tbl_flatten { 'autocmd', def }, ' ') vim.api.nvim_command(command) end vim.api.nvim_command('augroup END') end end local state = { initialized = false, pid = -1, stdin_handle = nil, config = {}, } local M = {} local function ensure_config() if state.config == nil then state.config = {} end end local function get_config() ensure_config() return state.config end local function edit_config(fn) ensure_config() fn(state.config) end local function apply_mode(mode) local config = get_config() local sel = config.schemes[mode] or {} local colorscheme = sel.colorscheme or nil local bg = sel.background or mode local lualineTheme = sel.lualine or nil vim.api.nvim_command('set background=' .. bg) if colorscheme ~= nil then vim.api.nvim_command('colorscheme ' .. colorscheme) end require('lualine').setup { options = { theme = lualineTheme } } if config.onchange ~= nil then config.onchange(mode) end state.current_mode = mode end function M.update() local mode = vim.fn.system('dark-notify --exit') mode = trim6(mode) apply_mode(mode) end function M.set_mode(mode) mode = trim6(mode) if not (mode == "light" or mode == "dark") then error("mode must be either \"light\" or \"dark\"" .. mode) return end apply_mode(mode) end function M.toggle() local mode = state.current_mode if mode == "light" then mode = "dark" elseif mode == "dark" then mode = "light" else M.update() return end apply_mode(mode) end local function init_dark_notify() -- Docs on this vim.loop stuff: https://github.com/luvit/luv local handle, pid local stdout = vim.loop.new_pipe(false) local stdin = vim.loop.new_pipe(false) local function onexit() vim.loop.close(handle, vim.schedule_wrap(function() vim.loop.shutdown(stdout) vim.loop.shutdown(stdin) state.initialized = false state.pid = nil state.stdin_handle = nil end)) end local function onread(err, chunk) assert(not err, err) if (chunk) then local mode = trim6(chunk) if not (mode == "light" or mode == "dark") then error("dark-notify output not expected: " .. chunk) return end apply_mode(mode) end end handle, pid = vim.loop.spawn( "dark-notify", { stdio = { stdin, stdout, nil } }, vim.schedule_wrap(onexit) ) vim.loop.read_start(stdout, vim.schedule_wrap(onread)) state.initialized = true state.pid = pid state.stdin_handle = stdin -- For whatever reason, nvim isn't killing child processes properly on exit -- So if you don't do this, you get zombie dark-notify processes hanging about. nvim_create_augroups({ DarkNotifyKillChildProcess = { { "VimLeave", "*", "lua require('dark_notify').stop()" }, } }) end -- For whatever reason, killing the child process doesn't work, at all. So we -- send it the line "quit\n", and it kills itself. function M.stop() if state.stdin_handle == nil then return end vim.loop.write(state.stdin_handle, "quit\n") -- process quits itself, calls onexit -- config gets edited from there end function M.configure(config) if config == nil then return end local lightline_loaders = config.lightline_loaders or {} local schemes = config.schemes or {} local onchange = config.onchange for _, mode in pairs({ "light", "dark" }) do if type(schemes[mode]) == "string" then schemes[mode] = { colorscheme = schemes[mode] } end end edit_config(function(conf) conf.lightline_loaders = lightline_loaders conf.schemes = schemes conf.onchange = onchange end) end function M.run(config) if config ~= nil or get_config().schemes == nil then -- if it's nil, it's a first run, so configure with no options. config = config or {} M.configure(config) end local config = get_config() if not config.initialized then -- first run on startup, also happens to apply current mode init_dark_notify() elseif state.current_mode ~= nil then -- we have run it before, but we're updating the settings -- so don't reset to system, but do apply changed config. local mode = state.current_mode apply_mode(mode) end end return M -- init.lua or init.vim in a lua <