diff --git a/lua/chameleon/config.lua b/lua/chameleon/config.lua new file mode 100644 index 0000000..0c85e0d --- /dev/null +++ b/lua/chameleon/config.lua @@ -0,0 +1,62 @@ +local _setup = {} + +local function normalize_path() + if not _setup.save_dir_path then + return + end + + _setup.save_dir_path = vim.fn.fnamemodify(_setup.save_dir_path, ":p") +end + +local function normalize_setup() + if not _setup.themes then + error("chameleon: 'themes' is a required field inside the config") + end + + for index, value in ipairs(_setup.themes) do + if type(value) == "string" then + _setup.themes[index] = { + name = value, + colorscheme = value, + } + end + if value.name and not value.colorscheme then + local tmp = vim.tbl_deep_extend("force", _setup.themes[index], value) + tmp.colorscheme = tmp.name + _setup.themes[index] = tmp + end + end +end + +local function setup(user_config) + _setup = vim.tbl_deep_extend("keep", user_config, {}) + + normalize_setup() + normalize_path() +end + +local function get_config() + return _setup +end + +local function save_dir_enabled() + return _setup.save_dir_path ~= nil +end + +local function name_to_config(theme_name) + for _, value in ipairs(_setup.themes) do + if value.name == theme_name then + return value + end + end + return {} +end + +return { + setup = setup, + normalize_path = normalize_path, + normalize_setup = normalize_setup, + save_dir_enabled = save_dir_enabled, + get_config = get_config, + name_to_config = name_to_config, +} diff --git a/lua/chameleon/init.lua b/lua/chameleon/init.lua new file mode 100644 index 0000000..e06c4af --- /dev/null +++ b/lua/chameleon/init.lua @@ -0,0 +1,41 @@ +local config = require("chameleon.config") +local loader = require("chameleon.loader") + +local switch = function(opts) + local theme_config = config.name_to_config(opts) + + if theme_config.before and type(theme_config.before) == "string" then + local ok, before = pcall(loadstring, theme_config.before) + if not ok then + error("chameleon: failed executing 'before' action.") + end + if before then + before() + end + end + + local ok, _ = pcall(vim.cmd, string.format("colorscheme %s", theme_config.colorscheme)) + if not ok then + error(string.format("chameleon: theme is not loaded %s", theme_config.colorscheme)) + end + + if theme_config.after and type(theme_config.after) == "string" then + local ok, after = pcall(loadstring, theme_config.after) + if not ok then + error("chameleon: failed executing 'after' action.") + end + if after then + after() + end + end + + if config.save_dir_enabled() then + loader.save(opts) + end +end + +return { + switch = switch, + setup = config.setup, + restore = loader.restore, +} diff --git a/lua/chameleon/loader.lua b/lua/chameleon/loader.lua new file mode 100644 index 0000000..e1670f4 --- /dev/null +++ b/lua/chameleon/loader.lua @@ -0,0 +1,63 @@ +local config = require("chameleon.config") + +local function save(theme_name) + local theme_config = config.name_to_config(theme_name) + local save_path = config.get_config().save_dir_path + + local file = io.open(save_path, "r") + if file == nil then + error(string.format("chameleon: Invalid file path '%s' for saving theme choice.", save_path)) + end + + local before_str = "nil" + local after_str = "nil" + + if theme_config.before then + before_str = theme_config.before + end + + if theme_config.after then + after_str = theme_config.after + end + + local config_content = "-- chameleon.nvim\n" + .. "-- This file is used to reload your theme settings on restart\n" + .. string.format("local colorscheme = '%s'\n", theme_config.colorscheme) + .. string.format("local before = %s\n", before_str) + .. string.format("local after = %s\n", after_str) + .. "return { colorscheme = colorscheme, before = before, after = after }" + + local outfile = io.open(save_path, "w") + if outfile == nil then + error(string.format("chameleon: Invalid file path '%s' for saving theme choice.", save_path)) + end + outfile:write(config_content) + outfile:close() +end + +local function restore() + local save_path = config.get_config().save_dir_path + local saved_config = dofile(save_path) + + if not saved_config.colorscheme then + return + end + + if saved_config.before and type(saved_config.before) == "function" then + saved_config.before() + end + + local ok, _ = pcall(vim.cmd, string.format("colorscheme %s", saved_config.colorscheme)) + if not ok then + error("chameleon: theme not loaded") + end + + if saved_config.after and type(saved_config.after) == "function" then + saved_config.after() + end +end + +return { + save = save, + restore = restore, +} diff --git a/lua/telescope/_extensions/chameleon.lua b/lua/telescope/_extensions/chameleon.lua new file mode 100644 index 0000000..47d393e --- /dev/null +++ b/lua/telescope/_extensions/chameleon.lua @@ -0,0 +1,60 @@ +local has_telescope, telescope = pcall(require, "telescope") + +if not has_telescope then + return +end + +local finders = require("telescope.finders") +local pickers = require("telescope.pickers") +local telescope_config = require("telescope.config").values +local actions = require("telescope.actions") +local action_state = require("telescope.actions.state") +local config = require("chameleon.config") +local _chameleon = require("chameleon") + +local function create_finder() + local themes = config.get_config().themes + + table.sort(themes, function(a, b) + return a.name:upper() < b.name:upper() + end) + return finders.new_table({ + results = themes, + entry_maker = function(entry) + return { + value = entry, + display = entry.name, + ordinal = entry.name, + } + end, + }) +end + +local function chameleon(opts) + opts = opts or {} + + pickers + .new(opts, { + prompt_title = "Chameleon: Themes", + finder = create_finder(), + previewer = false, + sorter = telescope_config.generic_sorter(opts), + attach_mappings = function(prompt_bufnr, _) + actions.select_default:replace(function() + actions.close(prompt_bufnr) + local selection = action_state.get_selected_entry() + local theme_config = selection.value + _chameleon.switch(theme_config.name) + end) + return true + end, + }) + :find() +end + +return telescope.register_extension({ + setup = config.setup, + exports = { + chameleon = chameleon, + }, +}) diff --git a/plugin/chameleon.lua b/plugin/chameleon.lua new file mode 100644 index 0000000..c7935fe --- /dev/null +++ b/plugin/chameleon.lua @@ -0,0 +1,3 @@ +vim.api.nvim_create_user_command("Chameleon", function(opts) + require("chameleon").switch(opts.args) +end, {})