From b2215472afae7381e6cb54689750f76d4ce9ea58 Mon Sep 17 00:00:00 2001 From: winston Date: Thu, 10 Oct 2024 08:03:03 +0200 Subject: [PATCH 1/3] feat: use new neovim apis, add `:healthcheck`, fix sudo `query_command` Uses `vim.uv` over `vim.loop`, `vim.system` over `vim.fn.jobstart`, adds a `:checkhealth` hook with a query_command benchmark, and fixes the `SUDO_USER` query_command. --- lua/auto-dark-mode/health.lua | 61 +++++++++ lua/auto-dark-mode/init.lua | 236 ++++++++++++++------------------ lua/auto-dark-mode/interval.lua | 109 +++++++++++++++ lua/auto-dark-mode/types.lua | 10 -- lua/auto-dark-mode/utils.lua | 30 ---- 5 files changed, 269 insertions(+), 177 deletions(-) create mode 100644 lua/auto-dark-mode/health.lua create mode 100644 lua/auto-dark-mode/interval.lua delete mode 100644 lua/auto-dark-mode/types.lua delete mode 100644 lua/auto-dark-mode/utils.lua diff --git a/lua/auto-dark-mode/health.lua b/lua/auto-dark-mode/health.lua new file mode 100644 index 0000000..b42d832 --- /dev/null +++ b/lua/auto-dark-mode/health.lua @@ -0,0 +1,61 @@ +local M = {} + +local adm = require("auto-dark-mode") + +M.benchmark = function(iterations) + local results = {} + + for _ = 1, iterations do + local _start = vim.uv.hrtime() + vim.system(adm.state.query_command, { text = true }):wait() + local _end = vim.uv.hrtime() + table.insert(results, (_end - _start) / 1000000) + end + + local max = 0 + local min = math.huge + local sum = 0 + for _, v in pairs(results) do + max = max > v and max or v + min = min < v and min or v + sum = sum + v + end + + return { avg = sum / #results, max = max, min = min } +end + +M.check = function() + vim.health.start("auto-dark-mode.nvim") + + if adm.state.setup_correct then + vim.health.ok("Setup is correct") + else + vim.health.error("Setup is incorrect") + end + + vim.health.info("Detected operating system: " .. adm.state.system) + vim.health.info("Using query command: `" .. table.concat(adm.state.query_command, " ") .. "`") + + local benchmark = M.benchmark(30) + vim.health.info( + string.format("Benchmark: %.2fms avg / %.2fms min / %.2fms max", benchmark.avg, benchmark.min, benchmark.max) + ) + + local interval = adm.options.update_interval + local ratio = interval / benchmark.avg + local info = string.format("Update interval (%dms) is %.2fx the average query time", interval, ratio) + local error = string.format( + "Update interval (%dms) seems too short compared to current benchmarks, consider increasing it", + interval + ) + + if ratio > 30 then + vim.health.ok(info) + elseif ratio > 5 then + vim.health.warn(info) + else + vim.health.error(error) + end +end + +return M diff --git a/lua/auto-dark-mode/init.lua b/lua/auto-dark-mode/init.lua index bd9a0a2..607bae4 100644 --- a/lua/auto-dark-mode/init.lua +++ b/lua/auto-dark-mode/init.lua @@ -1,100 +1,89 @@ -local utils = require("auto-dark-mode.utils") - ----@type number -local timer_id ----@type boolean -local is_currently_dark_mode - ----@type fun(): nil | nil -local set_dark_mode ----@type fun(): nil | nil -local set_light_mode - ----@type number -local update_interval - ----@type table -local query_command ----@type "Linux" | "Darwin" | "Windows_NT" | "WSL" -local system - ----@type "light" | "dark" -local fallback - --- Parses the query response for each system ----@param res table ----@return boolean -local function parse_query_response(res) - if system == "Linux" then - -- https://github.com/flatpak/xdg-desktop-portal/blob/c0f0eb103effdcf3701a1bf53f12fe953fbf0b75/data/org.freedesktop.impl.portal.Settings.xml#L32-L46 - -- 0: no preference - -- 1: dark - -- 2: light - if string.match(res[1], "uint32 1") ~= nil then - return true - elseif string.match(res[1], "uint32 2") ~= nil then - return false - else - return fallback == "dark" - end - elseif system == "Darwin" then - return res[1] == "Dark" - elseif system == "Windows_NT" or system == "WSL" then - -- AppsUseLightTheme REG_DWORD 0x0 : dark - -- AppsUseLightTheme REG_DWORD 0x1 : light - return string.match(res[3], "0x1") == nil - end - return false -end - ----@param callback fun(is_dark_mode: boolean) -local function check_is_dark_mode(callback) - utils.start_job(query_command, { - on_stdout = function(data) - local is_dark_mode = parse_query_response(data) - callback(is_dark_mode) - end, +local M = {} + +---@alias Appearance "light" | "dark" +---@alias DetectedOS "Linux" | "Darwin" | "Windows_NT" | "WSL" + +---@class AutoDarkModeOptions +local default_options = { + -- Optional. If not provided, `vim.api.nvim_set_option_value('background', 'dark', {})` will be used. + ---@type fun(): nil | nil + set_dark_mode = function() + vim.api.nvim_set_option_value("background", "dark", {}) + end, + + -- Optional. If not provided, `vim.api.nvim_set_option_value('background', 'light', {})` will be used. + ---@type fun(): nil | nil + set_light_mode = function() + vim.api.nvim_set_option_value("background", "light", {}) + end, + + -- Every `update_interval` milliseconds a theme check will be performed. + ---@type number? + update_interval = 3000, + + -- Optional. Fallback theme to use if the system theme can't be detected. + -- Useful for linux and environments without a desktop manager. + ---@type Appearance + fallback = "dark", +} + +local function validate_options(options) + vim.validate({ + set_dark_mode = { options.set_dark_mode, "function" }, + set_light_mode = { options.set_light_mode, "function" }, + update_interval = { options.update_interval, "number" }, + fallback = { + options.fallback, + function(opt) + return opt == "dark" or opt == "light" + end, + "`fallback` must be either 'light' or 'dark'", + }, }) + M.state.setup_correct = true end ----@param is_dark_mode boolean -local function change_theme_if_needed(is_dark_mode) - if is_dark_mode == is_currently_dark_mode then - return - end - - is_currently_dark_mode = is_dark_mode - if is_currently_dark_mode then - set_dark_mode() - else - set_light_mode() - end -end - -local function start_check_timer() - timer_id = vim.fn.timer_start(update_interval, function() - check_is_dark_mode(change_theme_if_needed) - end, { ["repeat"] = -1 }) -end - -local function init() - if string.match(vim.loop.os_uname().release, "WSL") then - system = "WSL" +---@class AutoDarkModeState +M.state = { + ---@type boolean + setup_correct = false, + ---@type DetectedOS + system = nil, + ---@type table + query_command = {}, +} + +-- map the vim.loop functions to vim.uv if available +local getuid = vim.uv.getuid or vim.loop.getuid + +M.init = function() + local os_uname = vim.uv.os_uname() or vim.loop.os_uname() + + if string.match(os_uname.release, "WSL") then + M.state.system = "WSL" + if not vim.fn.executable("reg.exe") then + error([[ + auto-dark-mode.nvim: + `reg.exe` is not available. To support syncing with the host system, + this plugin relies on `reg.exe` being on the `$PATH`. + ]]) + end else - system = vim.loop.os_uname().sysname + M.state.system = os_uname.sysname end - if system == "Darwin" then - query_command = { "defaults", "read", "-g", "AppleInterfaceStyle" } - elseif system == "Linux" then + if M.state.system == "Darwin" then + M.state.query_command = { "defaults", "read", "-g", "AppleInterfaceStyle" } + elseif M.state.system == "Linux" then if not vim.fn.executable("dbus-send") then error([[ - `dbus-send` is not available. The Linux implementation of - auto-dark-mode.nvim relies on `dbus-send` being on the `$PATH`. - ]]) + auto-dark-mode.nvim: + `dbus-send` is not available. The Linux implementation of + auto-dark-mode.nvim relies on `dbus-send` being on the `$PATH`. + ]]) end - query_command = { + M.state.query_command = { "dbus-send", "--session", "--print-reply=literal", @@ -105,9 +94,8 @@ local function init() "string:org.freedesktop.appearance", "string:color-scheme", } - elseif system == "Windows_NT" or system == "WSL" then - -- Don't swap the quotes; it breaks the code - query_command = { + elseif M.state.system == "Windows_NT" or M.state.system == "WSL" then + M.state.query_command = { "reg.exe", "Query", "HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", @@ -118,66 +106,40 @@ local function init() return end - if vim.fn.has("unix") ~= 0 then - if vim.loop.getuid() == 0 then - local sudo_user = vim.env.SUDO_USER + -- when on a supported unix system, and the userid is root + if (M.state.system == "Darwin" or M.state.system == "Linux") and getuid() == 0 then + local sudo_user = vim.env.SUDO_USER - if sudo_user ~= nil then - query_command = vim.tbl_extend("keep", { "su", "-", sudo_user, "-c" }, query_command) - else - error([[ + if sudo_user ~= nil then + -- prepend the command with `su - $SUDO_USER -c` + local extra_args = { "su", "-", sudo_user, "-c" } + for _, v in pairs(M.state.query_command) do + table.insert(extra_args, v) + end + M.state.query_command = extra_args + else + error([[ auto-dark-mode.nvim: Running as `root`, but `$SUDO_USER` is not set. Please open an issue to add support for your system. ]]) - end end end - if type(set_dark_mode) ~= "function" or type(set_light_mode) ~= "function" then - error([[ - - Call `setup` first: - - require('auto-dark-mode').setup({ - set_dark_mode=function() - vim.api.nvim_set_option_value('background', 'dark') - vim.cmd('colorscheme gruvbox') - end, - set_light_mode=function() - vim.api.nvim_set_option_value('background', 'light') - end, - }) - ]]) - end + local interval = require("auto-dark-mode.interval") - check_is_dark_mode(change_theme_if_needed) - start_check_timer() -end + interval.start(M.options, M.state) -local function disable() - vim.fn.timer_stop(timer_id) + -- expose the previous `require("auto-dark-mode").disable()` function + M.disable = interval.stop_timer end ---@param options AutoDarkModeOptions -local function setup(options) - options = options or {} - - ---@param background string - local function set_background(background) - vim.api.nvim_set_option_value("background", background, {}) - end - - set_dark_mode = options.set_dark_mode or function() - set_background("dark") - end - set_light_mode = options.set_light_mode or function() - set_background("light") - end - update_interval = options.update_interval or 3000 - fallback = options.fallback or "dark" +M.setup = function(options) + M.options = vim.tbl_deep_extend("keep", options or {}, default_options) + validate_options(M.options) - init() + M.init() end -return { setup = setup, init = init, disable = disable } +return M diff --git a/lua/auto-dark-mode/interval.lua b/lua/auto-dark-mode/interval.lua new file mode 100644 index 0000000..e1952a6 --- /dev/null +++ b/lua/auto-dark-mode/interval.lua @@ -0,0 +1,109 @@ +local M = { + ---@type uv_timer_t + timer = nil, + ---@type number + timer_id = nil, + ---@type boolean + currently_in_dark_mode = nil, +} + +-- Parses the query response for each system, returning `true` if the system is +-- in Dark mode, `false` when in Light mode. +---@param res string +---@return boolean +local function parse_query_response(res) + if M.state.system == "Linux" then + -- https://github.com/flatpak/xdg-desktop-portal/blob/c0f0eb103effdcf3701a1bf53f12fe953fbf0b75/data/org.freedesktop.impl.portal.Settings.xml#L32-L46 + -- 0: no preference + -- 1: dark + -- 2: light + if string.match(res, "uint32 1") ~= nil then + return true + elseif string.match(res, "uint32 2") ~= nil then + return false + else + return M.options.fallback == "dark" + end + elseif M.state.system == "Darwin" then + return res == "Dark\n" + elseif M.state.system == "Windows_NT" or M.state.system == "WSL" then + -- AppsUseLightTheme REG_DWORD 0x0 : dark + -- AppsUseLightTheme REG_DWORD 0x1 : light + return string.match(res, "0x1") == nil + end + + return false +end + +---@param is_dark_mode boolean +local function change_theme_if_needed(is_dark_mode) + if is_dark_mode == M.currently_in_dark_mode then + return + end + + M.currently_in_dark_mode = is_dark_mode + if M.currently_in_dark_mode then + if vim.system then + vim.schedule(M.options.set_dark_mode) + else + M.options.set_dark_mode() + end + else + if vim.system then + vim.schedule(M.options.set_light_mode) + else + M.options.set_dark_mode() + end + end +end + +M.poll_dark_mode = function() + if vim.system then + vim.system(M.state.query_command, { text = true }, function(data) + local is_dark_mode = parse_query_response(data.stdout) + change_theme_if_needed(is_dark_mode) + end) + else + -- Legacy implementation using `vim.fn.jobstart` instead of `vim.system`, + -- for use in neovim <0.10.0 + vim.fn.jobstart(M.state.query_command, { + stdout_buffered = true, + on_stdout = function(_, data, _) + local is_dark_mode = parse_query_response(table.concat(data, "\n")) + change_theme_if_needed(is_dark_mode) + end, + }) + end +end + +M.start_timer = function() + ---@type number + local interval = M.options.update_interval + + if vim.uv.new_timer or vim.loop.new_timer then + M.timer = vim.uv.new_timer() or vim.loop.new_timer() + M.timer:start(interval, interval, M.poll_dark_mode) + else + M.timer_id = vim.fn.timer_start(interval, M.poll_dark_mode, { ["repeat"] = -1 }) + end +end + +M.stop_timer = function() + if vim.uv.timer_stop or vim.loop.timer_stop then + vim.uv.timer_stop(M.timer) + else + vim.fn.timer_stop(M.timer_id) + end +end + +---@param options AutoDarkModeOptions +---@param state AutoDarkModeState +M.start = function(options, state) + M.options = options + M.state = state + + M.poll_dark_mode() + M.start_timer() +end + +return M diff --git a/lua/auto-dark-mode/types.lua b/lua/auto-dark-mode/types.lua deleted file mode 100644 index 65a4e46..0000000 --- a/lua/auto-dark-mode/types.lua +++ /dev/null @@ -1,10 +0,0 @@ ----@class AutoDarkModeOptions --- Optional. If not provided, `vim.api.nvim_set_option_value('background', 'dark')` will be used. ----@field set_dark_mode nil | fun(): nil --- Optional. If not provided, `vim.api.nvim_set_option_value('background', 'light')` will be used. ----@field set_light_mode nil | fun(): nil --- Every `update_interval` milliseconds a theme check will be performed. ----@field update_interval number? --- Optional. Fallback theme to use if the system theme can't be detected. --- Useful for linux and environments without a desktop manager. ----@field fallback "light" | "dark" | nil diff --git a/lua/auto-dark-mode/utils.lua b/lua/auto-dark-mode/utils.lua deleted file mode 100644 index b9df7b9..0000000 --- a/lua/auto-dark-mode/utils.lua +++ /dev/null @@ -1,30 +0,0 @@ -local M = {} - ----@param cmd table ----@param opts {input?: string, on_stdout?: function, on_exit?: function} ----@return number | 'the job id' -function M.start_job(cmd, opts) - opts = opts or {} - local id = vim.fn.jobstart(cmd, { - stdout_buffered = true, - on_stdout = function(_, data, _) - if data and opts.on_stdout then - opts.on_stdout(data) - end - end, - on_exit = function(_, data, _) - if opts.on_exit then - opts.on_exit(data) - end - end, - }) - - if opts.input then - vim.fn.chansend(id, opts.input) - vim.fn.chanclose(id, "stdin") - end - - return id -end - -return M From 302217465cf2e4c1e1b839b8583043c273e05283 Mon Sep 17 00:00:00 2001 From: winston Date: Thu, 10 Oct 2024 22:32:39 +0200 Subject: [PATCH 2/3] feat: better `:checkhealth`, add default WSL `reg.exe` location, other various refactor --- lua/auto-dark-mode/health.lua | 46 +++++++++++++++--------- lua/auto-dark-mode/init.lua | 64 +++++++++++++++++++-------------- lua/auto-dark-mode/interval.lua | 37 +++++++++++++------ 3 files changed, 94 insertions(+), 53 deletions(-) diff --git a/lua/auto-dark-mode/health.lua b/lua/auto-dark-mode/health.lua index b42d832..565c720 100644 --- a/lua/auto-dark-mode/health.lua +++ b/lua/auto-dark-mode/health.lua @@ -1,14 +1,20 @@ local M = {} +local uv = vim.uv or vim.loop + local adm = require("auto-dark-mode") +local interval = require("auto-dark-mode.interval") M.benchmark = function(iterations) local results = {} for _ = 1, iterations do - local _start = vim.uv.hrtime() - vim.system(adm.state.query_command, { text = true }):wait() - local _end = vim.uv.hrtime() + local _start = uv.hrtime() + -- by using an empty function, parsing the response is measured, but + -- actually syncing the vim theme isn't performed + interval.poll_dark_mode(function() end) + local _end = uv.hrtime() + table.insert(results, (_end - _start) / 1000000) end @@ -24,37 +30,45 @@ M.benchmark = function(iterations) return { avg = sum / #results, max = max, min = min } end +-- support for neovim < 0.9.0 +local H = vim.health +local health = {} +health.start = H.start or H.report_start +health.ok = H.ok or H.report_ok +health.info = H.info or H.report_info +health.error = H.error or H.report_error + M.check = function() - vim.health.start("auto-dark-mode.nvim") + health.start("auto-dark-mode.nvim") if adm.state.setup_correct then - vim.health.ok("Setup is correct") + health.ok("Setup is correct") else - vim.health.error("Setup is incorrect") + health.error("Setup is incorrect") end - vim.health.info("Detected operating system: " .. adm.state.system) - vim.health.info("Using query command: `" .. table.concat(adm.state.query_command, " ") .. "`") + health.info(string.format("Detected operating system: %s", adm.state.system)) + health.info(string.format("Using query command: `%s`", table.concat(adm.state.query_command, " "))) local benchmark = M.benchmark(30) - vim.health.info( + health.info( string.format("Benchmark: %.2fms avg / %.2fms min / %.2fms max", benchmark.avg, benchmark.min, benchmark.max) ) - local interval = adm.options.update_interval - local ratio = interval / benchmark.avg - local info = string.format("Update interval (%dms) is %.2fx the average query time", interval, ratio) + local update_interval = adm.options.update_interval + local ratio = update_interval / benchmark.avg + local info = string.format("Update interval (%dms) is %.2fx the average query time", update_interval, ratio) local error = string.format( "Update interval (%dms) seems too short compared to current benchmarks, consider increasing it", - interval + update_interval ) if ratio > 30 then - vim.health.ok(info) + health.ok(info) elseif ratio > 5 then - vim.health.warn(info) + health.warn(info) else - vim.health.error(error) + health.error(error) end end diff --git a/lua/auto-dark-mode/init.lua b/lua/auto-dark-mode/init.lua index 607bae4..eb564d2 100644 --- a/lua/auto-dark-mode/init.lua +++ b/lua/auto-dark-mode/init.lua @@ -1,10 +1,17 @@ local M = {} +local uv = vim.uv or vim.loop + ---@alias Appearance "light" | "dark" ---@alias DetectedOS "Linux" | "Darwin" | "Windows_NT" | "WSL" ---@class AutoDarkModeOptions local default_options = { + -- Optional. Fallback theme to use if the system theme can't be detected. + -- Useful for linux and environments without a desktop manager. + ---@type Appearance? + fallback = "dark", + -- Optional. If not provided, `vim.api.nvim_set_option_value('background', 'dark', {})` will be used. ---@type fun(): nil | nil set_dark_mode = function() @@ -17,21 +24,13 @@ local default_options = { vim.api.nvim_set_option_value("background", "light", {}) end, - -- Every `update_interval` milliseconds a theme check will be performed. + -- Optional. Specifies the `update_interval` milliseconds a theme check will be performed. ---@type number? update_interval = 3000, - - -- Optional. Fallback theme to use if the system theme can't be detected. - -- Useful for linux and environments without a desktop manager. - ---@type Appearance - fallback = "dark", } local function validate_options(options) vim.validate({ - set_dark_mode = { options.set_dark_mode, "function" }, - set_light_mode = { options.set_light_mode, "function" }, - update_interval = { options.update_interval, "number" }, fallback = { options.fallback, function(opt) @@ -39,6 +38,9 @@ local function validate_options(options) end, "`fallback` must be either 'light' or 'dark'", }, + set_dark_mode = { options.set_dark_mode, "function" }, + set_light_mode = { options.set_light_mode, "function" }, + update_interval = { options.update_interval, "number" }, }) M.state.setup_correct = true end @@ -53,21 +55,11 @@ M.state = { query_command = {}, } --- map the vim.loop functions to vim.uv if available -local getuid = vim.uv.getuid or vim.loop.getuid - M.init = function() - local os_uname = vim.uv.os_uname() or vim.loop.os_uname() + local os_uname = uv.os_uname() if string.match(os_uname.release, "WSL") then M.state.system = "WSL" - if not vim.fn.executable("reg.exe") then - error([[ - auto-dark-mode.nvim: - `reg.exe` is not available. To support syncing with the host system, - this plugin relies on `reg.exe` being on the `$PATH`. - ]]) - end else M.state.system = os_uname.sysname end @@ -77,9 +69,9 @@ M.init = function() elseif M.state.system == "Linux" then if not vim.fn.executable("dbus-send") then error([[ - auto-dark-mode.nvim: - `dbus-send` is not available. The Linux implementation of - auto-dark-mode.nvim relies on `dbus-send` being on the `$PATH`. + auto-dark-mode.nvim: + `dbus-send` is not available. The Linux implementation of + auto-dark-mode.nvim relies on `dbus-send` being on the `$PATH`. ]]) end @@ -95,8 +87,28 @@ M.init = function() "string:color-scheme", } elseif M.state.system == "Windows_NT" or M.state.system == "WSL" then + local reg = "reg.exe" + + -- on WSL, if `reg.exe` cannot be found on the `$PATH` + -- (see interop.appendWindowsPath https://learn.microsoft.com/en-us/windows/wsl/wsl-config), + -- assume that it's in the default location + if M.state.system == "WSL" and not vim.fn.executable("reg.exe") then + local assumed_path = "/mnt/c/Windows/system32/reg.exe" + + if vim.fn.filereadable(assumed_path) then + reg = assumed_path + else + -- `reg.exe` isn't on `$PATH` or in the default location, so throw an error + error([[ + auto-dark-mode.nvim: + `reg.exe` is not available. To support syncing with the host system, + this plugin relies on `reg.exe` being on the `$PATH`. + ]]) + end + end + M.state.query_command = { - "reg.exe", + reg, "Query", "HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", "/v", @@ -107,7 +119,7 @@ M.init = function() end -- when on a supported unix system, and the userid is root - if (M.state.system == "Darwin" or M.state.system == "Linux") and getuid() == 0 then + if (M.state.system == "Darwin" or M.state.system == "Linux") and uv.getuid() == 0 then local sudo_user = vim.env.SUDO_USER if sudo_user ~= nil then @@ -122,7 +134,7 @@ M.init = function() auto-dark-mode.nvim: Running as `root`, but `$SUDO_USER` is not set. Please open an issue to add support for your system. - ]]) + ]]) end end diff --git a/lua/auto-dark-mode/interval.lua b/lua/auto-dark-mode/interval.lua index e1952a6..797bf4f 100644 --- a/lua/auto-dark-mode/interval.lua +++ b/lua/auto-dark-mode/interval.lua @@ -7,6 +7,8 @@ local M = { currently_in_dark_mode = nil, } +local uv = vim.uv or vim.loop + -- Parses the query response for each system, returning `true` if the system is -- in Dark mode, `false` when in Light mode. ---@param res string @@ -35,8 +37,10 @@ local function parse_query_response(res) return false end +-- Executes the `set_dark_mode` and `set_light_mode` hooks when needed, +-- otherwise it's a no-op. ---@param is_dark_mode boolean -local function change_theme_if_needed(is_dark_mode) +local function sync_theme(is_dark_mode) if is_dark_mode == M.currently_in_dark_mode then return end @@ -57,11 +61,17 @@ local function change_theme_if_needed(is_dark_mode) end end -M.poll_dark_mode = function() +---@param callback? fun(is_dark_mode: boolean): nil +M.poll_dark_mode = function(callback) + -- if no callback is provided, use a no-op + if callback == nil then + callback = function() end + end + if vim.system then vim.system(M.state.query_command, { text = true }, function(data) local is_dark_mode = parse_query_response(data.stdout) - change_theme_if_needed(is_dark_mode) + callback(is_dark_mode) end) else -- Legacy implementation using `vim.fn.jobstart` instead of `vim.system`, @@ -70,7 +80,7 @@ M.poll_dark_mode = function() stdout_buffered = true, on_stdout = function(_, data, _) local is_dark_mode = parse_query_response(table.concat(data, "\n")) - change_theme_if_needed(is_dark_mode) + callback(is_dark_mode) end, }) end @@ -80,17 +90,22 @@ M.start_timer = function() ---@type number local interval = M.options.update_interval - if vim.uv.new_timer or vim.loop.new_timer then - M.timer = vim.uv.new_timer() or vim.loop.new_timer() - M.timer:start(interval, interval, M.poll_dark_mode) + local timer_callback = function() + M.poll_dark_mode(sync_theme) + end + + -- needs to check for `vim.system` because the poll function depends on it + if uv and vim.system then + M.timer = uv.new_timer() + M.timer:start(interval, interval, timer_callback) else - M.timer_id = vim.fn.timer_start(interval, M.poll_dark_mode, { ["repeat"] = -1 }) + M.timer_id = vim.fn.timer_start(interval, timer_callback, { ["repeat"] = -1 }) end end M.stop_timer = function() - if vim.uv.timer_stop or vim.loop.timer_stop then - vim.uv.timer_stop(M.timer) + if uv.timer_stop then + uv.timer_stop(M.timer) else vim.fn.timer_stop(M.timer_id) end @@ -102,7 +117,7 @@ M.start = function(options, state) M.options = options M.state = state - M.poll_dark_mode() + M.poll_dark_mode(sync_theme) M.start_timer() end From ae290cacab3306823c3ffec07fcd3b84765cd6e6 Mon Sep 17 00:00:00 2001 From: winston Date: Fri, 11 Oct 2024 00:34:21 +0200 Subject: [PATCH 3/3] fix: vim.fn booleans & format error strings --- lua/auto-dark-mode/init.lua | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/lua/auto-dark-mode/init.lua b/lua/auto-dark-mode/init.lua index eb564d2..9b504d3 100644 --- a/lua/auto-dark-mode/init.lua +++ b/lua/auto-dark-mode/init.lua @@ -67,12 +67,10 @@ M.init = function() if M.state.system == "Darwin" then M.state.query_command = { "defaults", "read", "-g", "AppleInterfaceStyle" } elseif M.state.system == "Linux" then - if not vim.fn.executable("dbus-send") then - error([[ - auto-dark-mode.nvim: - `dbus-send` is not available. The Linux implementation of - auto-dark-mode.nvim relies on `dbus-send` being on the `$PATH`. - ]]) + if vim.fn.executable("dbus-send") == 0 then + error( + "auto-dark-mode.nvim: `dbus-send` is not available. The Linux implementation of auto-dark-mode.nvim relies on `dbus-send` being on the `$PATH`." + ) end M.state.query_command = { @@ -92,18 +90,16 @@ M.init = function() -- on WSL, if `reg.exe` cannot be found on the `$PATH` -- (see interop.appendWindowsPath https://learn.microsoft.com/en-us/windows/wsl/wsl-config), -- assume that it's in the default location - if M.state.system == "WSL" and not vim.fn.executable("reg.exe") then + if M.state.system == "WSL" and vim.fn.executable("reg.exe") == 0 then local assumed_path = "/mnt/c/Windows/system32/reg.exe" - if vim.fn.filereadable(assumed_path) then + if vim.fn.filereadable(assumed_path) == 1 then reg = assumed_path else -- `reg.exe` isn't on `$PATH` or in the default location, so throw an error - error([[ - auto-dark-mode.nvim: - `reg.exe` is not available. To support syncing with the host system, - this plugin relies on `reg.exe` being on the `$PATH`. - ]]) + error( + "auto-dark-mode.nvim: `reg.exe` is not available. To support syncing with the host system, this plugin relies on `reg.exe` being on the `$PATH`." + ) end end @@ -130,11 +126,9 @@ M.init = function() end M.state.query_command = extra_args else - error([[ - auto-dark-mode.nvim: - Running as `root`, but `$SUDO_USER` is not set. - Please open an issue to add support for your system. - ]]) + error( + "auto-dark-mode.nvim: Running as `root`, but `$SUDO_USER` is not set. Please open an issue to add support for your system." + ) end end