Skip to content

Commit 924cc65

Browse files
Port over bezhermoso/base16-live-reload functionality (#6)
* doc: update README * chore: rebuild themes & docs Co-authored-by: Jamy <code@jamygolden.com> * Apply suggestions from code review Co-authored-by: Jamy <code@jamygolden.com> * Update lua/tinted-live-reload.lua Co-authored-by: Jamy <code@jamygolden.com> * doc: fix typo * fix: read output of `tinty config` better & avoid newlines --------- Co-authored-by: Jamy <code@jamygolden.com>
1 parent 74198e2 commit 924cc65

File tree

4 files changed

+268
-123
lines changed

4 files changed

+268
-123
lines changed

README.md

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,11 @@ optional arguments: a theme or a config table.
9797

9898
##### `supports` Options
9999

100-
| Key | Default | Description |
101-
| -------------- | ------- | --------------------------------------------------------------------------- |
102-
| `tinty` | `true` | If `true`, attempts to use current [Tinty] theme if available |
103-
| `tinted_shell` | `false` | If `true`, allows detection from `BASE16_THEME` env var (only outside tmux) |
100+
| Key | Default | Description |
101+
| -------------- | ------- | -------------------------------------------------------------------------------------------|
102+
| `tinty` | `true` | If `true`, attempts to use current [Tinty] theme if available |
103+
| `tinted_shell` | `false` | If `true`, allows detection from `BASE16_THEME` env var (only outside tmux) |
104+
| `live_reload` | `true` | If `true`, open Neovim instances live reloads whenever [Tinty] applies a theme system-wide |
104105

105106
##### `highlights` Options
106107

@@ -154,25 +155,35 @@ local red = require('tinted-colorscheme').colors.base08
154155
value, "tinted-nvim-default" (`base16-ayu-dark`) will be used as a fallback
155156
theme.
156157

157-
To have tinted-nvim update the theme when `tinty apply ayu-dark` is run, you
158-
need to tell Neovim to update and the easiest way to do this is to update the
159-
theme when Neovim is given focus. The following will update the theme, on window
160-
focus, if the theme has changed:
158+
To have tinted-nvim automatically update the theme when `tinty apply ayu-dark` is run, you can enable
159+
the live-reload feature.
161160

162161
```lua
163162
local tinted = require('tinted-colorscheme')
164-
tinted.setup()
165-
166-
vim.api.nvim_create_autocmd("FocusGained", {
167-
callback = function() tinted.setup() end
163+
tinted.setup(nil, {
164+
supports = {
165+
live_reload = true
166+
}
168167
})
169168
```
170169

171-
**Note**: If you don't see colours, try adding `vim.opt.termguicolors = true` to
172-
your init.lua
170+
The live-reload feature depends on [fwatch.nvim]. Add this dependency in whatever manner your plugin manager allows you.
171+
For example, with **lazy.nvim**:
173172

174-
Have a look at [Tinted Gallery] for a preview of our themes.
173+
```diff
174+
return {
175+
"tinted-theming/tinted-nvim",
176+
+ dependencies = {
177+
+ { "rktjmp/fwatch.nvim" },
178+
+ }
179+
}
180+
```
181+
182+
> ![NOTE]
183+
> If you don't see colours, try adding `vim.opt.termguicolors = true` to
184+
> your init.lua
175185
186+
Have a look at [Tinted Gallery] for a preview of our themes.
176187
## Advanced Usage
177188

178189
### Config
@@ -184,6 +195,7 @@ require('tinted-colorscheme').with_config({
184195
supports = {
185196
tinty = true,
186197
tinted_shell = false,
198+
live_reload = false -- If set to true, requires rktjump/fwatch.nvim as a dependency
187199
},
188200
highlights = {
189201
telescope = true,
@@ -197,6 +209,19 @@ require('tinted-colorscheme').with_config({
197209
})
198210
```
199211

212+
### Autocmd
213+
214+
```lua
215+
216+
vim.api.nvim_create_autocmd("User", {
217+
pattern = "TintedColorsPost",
218+
callback = function()
219+
-- Do things whenever the theme changes.
220+
local colors = require("tinted-colorscheme").colors
221+
end,
222+
})
223+
```
224+
200225
## 🗂️ Builtin Colorschemes
201226

202227
You can use any of the following schemes with `:colorscheme` (for example
@@ -660,3 +685,4 @@ contributors for work they've done.
660685
[Tinty]: https://github.com/tinted-theming/tinty
661686
[Tinted Gallery]: https://tinted-theming.github.io/tinted-gallery/
662687
[base16-nvim]: https://github.com/RRethy/base16-nvim
688+
[fwatch.nvim]: https://github.com/rktjump/fwatch.nvim

lua/tinted-colorscheme.lua

Lines changed: 122 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ function M.with_config(config)
132132

133133
local supports = vim.tbl_extend("force", {
134134
tinty = true,
135+
live_reload = false,
135136
tinted_shell = false,
136137
}, config.supports or M.config.supports or {})
137138
local highlights = vim.tbl_extend("force", {
@@ -152,100 +153,11 @@ function M.with_config(config)
152153
}
153154
end
154155

155-
--- Creates a tinted colorscheme using the colors specified.
156-
--
157-
-- Builtin colorschemes can be found in the M.colorschemes table.
158-
--
159-
-- The default Vim highlight groups (including User[1-9]), highlight groups
160-
-- pertaining to Neovim's builtin LSP, and highlight groups pertaining to
161-
-- Treesitter will be defined.
162-
--
163-
-- It's worth noting that many colorschemes will specify language specific
164-
-- highlight groups like rubyConstant or pythonInclude. However, I don't do
165-
-- that here since these should instead be linked to an existing highlight
166-
-- group.
167-
--
168-
-- @param colors (table) table with keys 'base00', 'base01', 'base02',
169-
-- 'base03', 'base04', 'base05', 'base06', 'base07', 'base08', 'base09',
170-
-- 'base0A', 'base0B', 'base0C', 'base0D', 'base0E', 'base0F'. Each key should
171-
-- map to a valid 6 digit hex color. If a string is provided, the
172-
-- corresponding table specifying the colorscheme will be used.
173-
function M.setup(colors, config)
174-
M.with_config(config or {})
175-
176-
local current_colorscheme_name = vim.g.tinted_current_colorscheme;
177-
178-
if type('colors') == 'table' or colors == '' or colors == nil then
179-
colors = M.colorschemes["tinted-nvim-default"]
180-
elseif type('colors') == 'string' then
181-
-- Return if the theme is being set to the same theme
182-
if colors == current_colorscheme_name then
183-
return
184-
end
185-
186-
local ok, colorscheme = pcall(function()
187-
vim.g.tinted_current_colorscheme = colors
188-
return M.colorschemes[colors]
189-
end)
190-
191-
if ok then
192-
colors = colorscheme
193-
else
194-
vim.g.tinted_current_colorscheme = "tinted-nvim-default"
195-
colors = M.colorschemes["tinted-nvim-default"]
196-
end
197-
end
198-
199-
if M.config.supports.tinty == true then
200-
local current_tinty_theme = vim.trim(get_tinty_theme())
201-
202-
-- If the Tinty theme is not null
203-
if current_tinty_theme ~= nil and current_tinty_theme ~= '' then
204-
-- Set to Tinty theme if new theme name is different to already set
205-
if current_tinty_theme ~= current_colorscheme_name then
206-
-- Safely get colorscheme object from Tinty theme name
207-
local ok, colorscheme = pcall(function()
208-
return M.colorschemes[current_tinty_theme]
209-
end)
210-
211-
if ok then
212-
vim.g.tinted_current_colorscheme = current_tinty_theme
213-
vim.o.termguicolors = true
214-
vim.g.tinted_colorspace = 256
215-
colors = colorscheme
216-
else
217-
vim.notify(
218-
string.format("Failed to load Tinty colorscheme '%s', falling back to default", current_tinty_theme),
219-
vim.log.levels.WARN
220-
)
221-
end
222-
-- Return if the theme is being set to the same theme
223-
else
224-
return
225-
end
226-
else
227-
vim.notify(
228-
string.format("Failed to load Tinty colorscheme '%s', falling back to default", current_tinty_theme),
229-
vim.log.levels.WARN
230-
)
231-
end
232-
-- Only trust BASE16_THEME if not inside a TMUX pane due to how TMUX handles env vars
233-
elseif M.config.tinted_shell == true and vim.env.TMUX == nil and vim.env.BASE16_THEME ~= nil then
234-
-- Safely get colorscheme object from BASE16_THEME env var
235-
local ok, colorscheme = pcall(function()
236-
return M.colorschemes[vim.env.BASE16_THEME]
237-
end)
238-
239-
if ok then
240-
vim.g.tinted_current_colorscheme = vim.env.BASE16_THEME
241-
colors = colorscheme
242-
end
243-
end
244-
245-
if vim.fn.exists('syntax_on') then
246-
vim.cmd('syntax reset')
247-
end
156+
local function trigger_autocmd()
157+
vim.cmd([[doautocmd User TintedColorsPost]])
158+
end
248159

160+
local function set_colors(colors)
249161
M.colors = colors
250162

251163
local hi = M.highlight
@@ -808,6 +720,123 @@ function M.setup(colors, config)
808720
vim.g.tinted_gui15 = M.colors.base15
809721
vim.g.tinted_gui16 = M.colors.base16
810722
vim.g.tinted_gui17 = M.colors.base17
723+
724+
trigger_autocmd()
725+
end
726+
727+
local function detect_colors_from_tinty()
728+
local current_tinty_theme = vim.trim(get_tinty_theme())
729+
730+
-- If the Tinty theme is not null
731+
if current_tinty_theme ~= nil and current_tinty_theme ~= '' then
732+
-- Set to Tinty theme if new theme name is different to already set
733+
if current_tinty_theme ~= current_colorscheme_name then
734+
-- Safely get colorscheme object from Tinty theme name
735+
local ok, colorscheme = pcall(function()
736+
return M.colorschemes[current_tinty_theme]
737+
end)
738+
739+
if ok then
740+
vim.g.tinted_current_colorscheme = current_tinty_theme
741+
vim.o.termguicolors = true
742+
vim.g.tinted_colorspace = 256
743+
return colorscheme
744+
else
745+
vim.notify(
746+
string.format("Failed to load Tinty colorscheme '%s', falling back to default", current_tinty_theme),
747+
vim.log.levels.WARN
748+
)
749+
end
750+
-- Return if the theme is being set to the same theme
751+
else
752+
return
753+
end
754+
else
755+
vim.notify(
756+
string.format("Failed to load Tinty colorscheme '%s', falling back to default", current_tinty_theme),
757+
vim.log.levels.WARN
758+
)
759+
end
760+
end
761+
762+
--- Creates a tinted colorscheme using the colors specified.
763+
--
764+
-- Builtin colorschemes can be found in the M.colorschemes table.
765+
--
766+
-- The default Vim highlight groups (including User[1-9]), highlight groups
767+
-- pertaining to Neovim's builtin LSP, and highlight groups pertaining to
768+
-- Treesitter will be defined.
769+
--
770+
-- It's worth noting that many colorschemes will specify language specific
771+
-- highlight groups like rubyConstant or pythonInclude. However, I don't do
772+
-- that here since these should instead be linked to an existing highlight
773+
-- group.
774+
--
775+
-- @param colors (table) table with keys 'base00', 'base01', 'base02',
776+
-- 'base03', 'base04', 'base05', 'base06', 'base07', 'base08', 'base09',
777+
-- 'base0A', 'base0B', 'base0C', 'base0D', 'base0E', 'base0F'. Each key should
778+
-- map to a valid 6 digit hex color. If a string is provided, the
779+
-- corresponding table specifying the colorscheme will be used.
780+
function M.setup(colors, config)
781+
M.with_config(config or {})
782+
783+
local current_colorscheme_name = vim.g.tinted_current_colorscheme;
784+
785+
if type('colors') == 'table' or colors == '' or colors == nil then
786+
colors = M.colorschemes["tinted-nvim-default"]
787+
elseif type('colors') == 'string' then
788+
-- Return if the theme is being set to the same theme
789+
if colors == current_colorscheme_name then
790+
return
791+
end
792+
793+
local ok, colorscheme = pcall(function()
794+
vim.g.tinted_current_colorscheme = colors
795+
return M.colorschemes[colors]
796+
end)
797+
798+
if ok then
799+
colors = colorscheme
800+
else
801+
vim.g.tinted_current_colorscheme = "tinted-nvim-default"
802+
colors = M.colorschemes["tinted-nvim-default"]
803+
end
804+
end
805+
806+
-- Live-reload only supports reading current theme from Tinty.
807+
if M.config.supports.live_reload == true and M.config.supports.tinty == false then
808+
vim.notify(
809+
"Live-reload feature only works with Tinty integration.",
810+
vim.log.levels.WARN
811+
)
812+
end
813+
814+
if M.config.supports.tinty == true then
815+
colors = detect_colors_from_tinty()
816+
if M.config.supports.live_reload then
817+
require("tinted-live-reload").setup_live_reload(function()
818+
set_colors(detect_colors_from_tinty())
819+
end)
820+
end
821+
822+
-- Only trust BASE16_THEME if not inside a TMUX pane due to how TMUX handles env vars
823+
elseif M.config.tinted_shell == true and vim.env.TMUX == nil and vim.env.BASE16_THEME ~= nil then
824+
-- Safely get colorscheme object from BASE16_THEME env var
825+
local ok, colorscheme = pcall(function()
826+
return M.colorschemes[vim.env.BASE16_THEME]
827+
end)
828+
829+
if ok then
830+
vim.g.tinted_current_colorscheme = vim.env.BASE16_THEME
831+
colors = colorscheme
832+
end
833+
end
834+
835+
if vim.fn.exists('syntax_on') then
836+
vim.cmd('syntax reset')
837+
end
838+
839+
set_colors(colors)
811840
end
812841

813842
function M.available_colorschemes()

lua/tinted-live-reload.lua

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
local M = {}
2+
3+
local function check_prerequisites()
4+
local ok = pcall(require, "fwatch")
5+
if not ok then
6+
vim.notify("Required plugin rktjmp/fwatch.nvim is missing.", vim.log.levels.ERROR)
7+
return false
8+
end
9+
return true
10+
end
11+
12+
local function schedule_trigger(callback)
13+
vim.schedule(callback)
14+
end
15+
16+
local function start_watcher(callback)
17+
if vim.g.tinted_live_reload_registered then
18+
return
19+
end
20+
vim.g.tinted_live_reload_registered = true
21+
22+
local fwatch = require("fwatch")
23+
24+
-- The first line of the output is the path to the data directory.
25+
-- We need to watch the "current_scheme" file in that directory.
26+
-- The output is a list of lines, so we take the first line.
27+
-- The path is trimmed to remove any leading or trailing whitespace.
28+
-- We check if the path is not empty.
29+
local job = vim.fn.jobstart(
30+
{ "tinty", "config", "--data-dir-path" },
31+
{
32+
on_stdout = function(_, data)
33+
if data == nil or #data == 0 then
34+
return
35+
end
36+
local path = vim.fn.trim(data[1])
37+
if #path == 0 then
38+
return
39+
end
40+
local file_path = path .. "current_scheme"
41+
if not vim.fn.filereadable(file_path) then
42+
vim.notify(string.format("File %s is not readable.", file_path), vim.log.levels.ERROR)
43+
return
44+
end
45+
fwatch.watch(file_path, {
46+
on_event = function()
47+
schedule_trigger(callback)
48+
end,
49+
})
50+
end,
51+
}
52+
)
53+
end
54+
55+
M.setup_live_reload = function(callback)
56+
local ok = check_prerequisites()
57+
if not ok then
58+
-- Required plugins aren't present. Stop.
59+
return
60+
end
61+
start_watcher(callback)
62+
end
63+
64+
return M

0 commit comments

Comments
 (0)