vim
: try light theme
This commit is contained in:
parent
3385de5cbb
commit
e4edb18e54
10 changed files with 363 additions and 5 deletions
210
hm-imports/nvim/config/lua/dark_notify.lua
Normal file
210
hm-imports/nvim/config/lua/dark_notify.lua
Normal file
|
|
@ -0,0 +1,210 @@
|
||||||
|
-- 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 <<EOF
|
||||||
|
-- require('dark_notify').run({
|
||||||
|
-- lightline_loaders = {
|
||||||
|
-- my_colorscheme = "path_to_my_colorscheme's lightline autoload file"
|
||||||
|
-- },
|
||||||
|
-- schemes = {
|
||||||
|
-- dark = "dark colorscheme name",
|
||||||
|
-- light = { colorscheme = "light scheme name", background = "optional override, either light or dark" }
|
||||||
|
-- },
|
||||||
|
-- onchange = function(mode)
|
||||||
|
-- end,
|
||||||
|
-- })
|
||||||
|
|
@ -13,8 +13,26 @@ vim.g.maplocalleader = ','
|
||||||
-- color stuff
|
-- color stuff
|
||||||
opt.termguicolors = true -- 24bit color
|
opt.termguicolors = true -- 24bit color
|
||||||
require('gruvbox').setup({})
|
require('gruvbox').setup({})
|
||||||
|
require('tokyonight').setup({})
|
||||||
opt.background = 'dark' -- dark gruvbox
|
opt.background = 'dark' -- dark gruvbox
|
||||||
vim.cmd ':colorscheme gruvbox'
|
vim.cmd ':colorscheme gruvbox'
|
||||||
|
require('dark_notify').run({
|
||||||
|
schemes = {
|
||||||
|
light = {
|
||||||
|
colorscheme = 'tokyonight',
|
||||||
|
background = 'light',
|
||||||
|
lualine = 'tokyonight'
|
||||||
|
},
|
||||||
|
dark = {
|
||||||
|
colorscheme = 'gruvbox',
|
||||||
|
background = 'dark',
|
||||||
|
lualine = 'gruvbox'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--vimspector
|
--vimspector
|
||||||
vim.g.vimspector_base_dir = vim.env.HOME .. "/.local/share/nvim/vimspector"
|
vim.g.vimspector_base_dir = vim.env.HOME .. "/.local/share/nvim/vimspector"
|
||||||
vim.g.vimspector_enable_mappings = "HUMAN"
|
vim.g.vimspector_enable_mappings = "HUMAN"
|
||||||
|
|
@ -24,10 +42,10 @@ vim.g.copilot_no_tab_map = true
|
||||||
opt.encoding = 'utf-8'
|
opt.encoding = 'utf-8'
|
||||||
opt.number = true
|
opt.number = true
|
||||||
opt.relativenumber = true
|
opt.relativenumber = true
|
||||||
opt.undofile = true -- save undo chages even after computer restart
|
opt.undofile = true -- save undo chages even after computer restart
|
||||||
opt.showcmd = true -- show (partial) command in status line
|
opt.showcmd = true -- show (partial) command in status line
|
||||||
opt.showmatch = true -- show match brackets
|
opt.showmatch = true -- show match brackets
|
||||||
opt.wildmenu = true -- visual autocomplete for command menu
|
opt.wildmenu = true -- visual autocomplete for command menu
|
||||||
-- Splits open at the bottom and right, which is non-retarded, unlike vim defaults.
|
-- Splits open at the bottom and right, which is non-retarded, unlike vim defaults.
|
||||||
opt.splitbelow = true
|
opt.splitbelow = true
|
||||||
opt.splitright = true
|
opt.splitright = true
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ in
|
||||||
vim-tmux-navigator # tmux
|
vim-tmux-navigator # tmux
|
||||||
nnn-nvim # nnn as filebrowser
|
nnn-nvim # nnn as filebrowser
|
||||||
gruvbox-nvim # theme
|
gruvbox-nvim # theme
|
||||||
|
tokyonight-nvim # light theme
|
||||||
# complete ui overhaul
|
# complete ui overhaul
|
||||||
notify-nvim
|
notify-nvim
|
||||||
nui-nvim
|
nui-nvim
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
historyLimit = 10000;
|
historyLimit = 10000;
|
||||||
plugins = with pkgs.tmuxPlugins; [
|
plugins = with pkgs.tmuxPlugins; [
|
||||||
vim-tmux-navigator
|
vim-tmux-navigator
|
||||||
gruvbox
|
|
||||||
];
|
];
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
set -sg escape-time 0 # makes vim esc usable
|
set -sg escape-time 0 # makes vim esc usable
|
||||||
|
|
@ -17,6 +16,8 @@
|
||||||
bind c new-window -c "#{pane_current_path}"
|
bind c new-window -c "#{pane_current_path}"
|
||||||
set-option -g default-terminal "tmux-256color"
|
set-option -g default-terminal "tmux-256color"
|
||||||
set -as terminal-overrides ',xterm*:Tc:sitm=\E[3m'
|
set -as terminal-overrides ',xterm*:Tc:sitm=\E[3m'
|
||||||
|
run-shell -b '~/.config/tmux-switch-colors/start_theme_switcher.sh'
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
home.file.".config/tmux-switch-colors".source = ./tmux-switch-colors;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
50
hm-imports/tmux/tmux-switch-colors/dark.tmux
Normal file
50
hm-imports/tmux/tmux-switch-colors/dark.tmux
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
## COLORSCHEME: gruvbox dark (medium)
|
||||||
|
set-option -g status "on"
|
||||||
|
|
||||||
|
# default statusbar color
|
||||||
|
set-option -g status-style bg=colour237,fg=colour223 # bg=bg1, fg=fg1
|
||||||
|
|
||||||
|
# default window title colors
|
||||||
|
set-window-option -g window-status-style bg=colour214,fg=colour237 # bg=yellow, fg=bg1
|
||||||
|
|
||||||
|
# default window with an activity alert
|
||||||
|
set-window-option -g window-status-activity-style bg=colour237,fg=colour248 # bg=bg1, fg=fg3
|
||||||
|
|
||||||
|
# active window title colors
|
||||||
|
set-window-option -g window-status-current-style bg=red,fg=colour237 # fg=bg1
|
||||||
|
|
||||||
|
# pane border
|
||||||
|
set-option -g pane-active-border-style fg=colour250 #fg2
|
||||||
|
set-option -g pane-border-style fg=colour237 #bg1
|
||||||
|
|
||||||
|
# message infos
|
||||||
|
set-option -g message-style bg=colour239,fg=colour223 # bg=bg2, fg=fg1
|
||||||
|
|
||||||
|
# writing commands inactive
|
||||||
|
set-option -g message-command-style bg=colour239,fg=colour223 # bg=fg3, fg=bg1
|
||||||
|
|
||||||
|
# pane number display
|
||||||
|
set-option -g display-panes-active-colour colour250 #fg2
|
||||||
|
set-option -g display-panes-colour colour237 #bg1
|
||||||
|
|
||||||
|
# clock
|
||||||
|
set-window-option -g clock-mode-colour colour109 #blue
|
||||||
|
|
||||||
|
# bell
|
||||||
|
set-window-option -g window-status-bell-style bg=colour167,fg=colour235 # bg=red, fg=bg
|
||||||
|
|
||||||
|
## Theme settings mixed with colors (unfortunately, but there is no cleaner way)
|
||||||
|
set-option -g status-justify "left"
|
||||||
|
set-option -g status-left-style none
|
||||||
|
set-option -g status-left-length "80"
|
||||||
|
set-option -g status-right-style none
|
||||||
|
set-option -g status-right-length "80"
|
||||||
|
set-window-option -g window-status-separator ""
|
||||||
|
|
||||||
|
set-option -g status-left "#[bg=colour241,fg=colour248] #S #[bg=colour237,fg=colour241,nobold,noitalics,nounderscore]"
|
||||||
|
set-option -g status-right "#[bg=colour237,fg=colour239 nobold, nounderscore, noitalics]#[bg=colour239,fg=colour246] %Y-%m-%d %H:%M #[bg=colour239,fg=colour248,nobold,noitalics,nounderscore]#[bg=colour248,fg=colour237] #h "
|
||||||
|
|
||||||
|
set-window-option -g window-status-current-format "#[bg=colour214,fg=colour237,nobold,noitalics,nounderscore]#[bg=colour214,fg=colour239] #I #[bg=colour214,fg=colour239,bold] #W#{?window_zoomed_flag,*Z,} #[bg=colour237,fg=colour214,nobold,noitalics,nounderscore]"
|
||||||
|
set-window-option -g window-status-format "#[bg=colour239,fg=colour237,noitalics]#[bg=colour239,fg=colour223] #I #[bg=colour239,fg=colour223] #W #[bg=colour237,fg=colour239,noitalics]"
|
||||||
|
|
||||||
|
# vim: set ft=tmux tw=0 nowrap:
|
||||||
38
hm-imports/tmux/tmux-switch-colors/light.tmux
Normal file
38
hm-imports/tmux/tmux-switch-colors/light.tmux
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# TokyoNight colors for Tmux
|
||||||
|
|
||||||
|
set -g mode-style "fg=#2e7de9,bg=#a8aecb"
|
||||||
|
|
||||||
|
set -g message-style "fg=#2e7de9,bg=#a8aecb"
|
||||||
|
set -g message-command-style "fg=#2e7de9,bg=#a8aecb"
|
||||||
|
|
||||||
|
set -g pane-border-style "fg=#a8aecb"
|
||||||
|
set -g pane-active-border-style "fg=#2e7de9"
|
||||||
|
|
||||||
|
set -g status "on"
|
||||||
|
set -g status-justify "left"
|
||||||
|
|
||||||
|
set -g status-style "fg=#2e7de9,bg=#e9e9ec"
|
||||||
|
|
||||||
|
set -g status-left-length "100"
|
||||||
|
set -g status-right-length "100"
|
||||||
|
|
||||||
|
set -g status-left-style NONE
|
||||||
|
set -g status-right-style NONE
|
||||||
|
|
||||||
|
set -g status-left "#[fg=#e9e9ed,bg=#2e7de9,bold] #S #[fg=#2e7de9,bg=#e9e9ec,nobold,nounderscore,noitalics]"
|
||||||
|
set -g status-right "#[fg=#e9e9ec,bg=#e9e9ec,nobold,nounderscore,noitalics]#[fg=#2e7de9,bg=#e9e9ec] #{prefix_highlight} #[fg=#a8aecb,bg=#e9e9ec,nobold,nounderscore,noitalics]#[fg=#2e7de9,bg=#a8aecb] %Y-%m-%d %I:%M %p #[fg=#2e7de9,bg=#a8aecb,nobold,nounderscore,noitalics]#[fg=#e9e9ed,bg=#2e7de9,bold] #h "
|
||||||
|
if-shell '[ "$(tmux show-option -gqv "clock-mode-style")" == "24" ]' {
|
||||||
|
set -g status-right "#[fg=#e9e9ec,bg=#e9e9ec,nobold,nounderscore,noitalics]#[fg=#2e7de9,bg=#e9e9ec] #{prefix_highlight} #[fg=#a8aecb,bg=#e9e9ec,nobold,nounderscore,noitalics]#[fg=#2e7de9,bg=#a8aecb] %Y-%m-%d %H:%M #[fg=#2e7de9,bg=#a8aecb,nobold,nounderscore,noitalics]#[fg=#e9e9ed,bg=#2e7de9,bold] #h "
|
||||||
|
}
|
||||||
|
|
||||||
|
setw -g window-status-activity-style "underscore,fg=#6172b0,bg=#e9e9ec"
|
||||||
|
setw -g window-status-separator ""
|
||||||
|
setw -g window-status-style "NONE,fg=#6172b0,bg=#e9e9ec"
|
||||||
|
setw -g window-status-format "#[fg=#e9e9ec,bg=#e9e9ec,nobold,nounderscore,noitalics]#[default] #I #W #F #[fg=#e9e9ec,bg=#e9e9ec,nobold,nounderscore,noitalics]"
|
||||||
|
setw -g window-status-current-format "#[fg=#e9e9ec,bg=#a8aecb,nobold,nounderscore,noitalics]#[fg=#2e7de9,bg=#a8aecb,bold] #I #W #F #[fg=#a8aecb,bg=#e9e9ec,nobold,nounderscore,noitalics]"
|
||||||
|
|
||||||
|
# tmux-plugins/tmux-prefix-highlight support
|
||||||
|
set -g @prefix_highlight_output_prefix "#[fg=#8c6c3e]#[bg=#e9e9ec]#[fg=#e9e9ec]#[bg=#8c6c3e]"
|
||||||
|
set -g @prefix_highlight_output_suffix ""
|
||||||
9
hm-imports/tmux/tmux-switch-colors/start_theme_switcher.sh
Executable file
9
hm-imports/tmux/tmux-switch-colors/start_theme_switcher.sh
Executable file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
|
||||||
|
DN=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||||
|
|
||||||
|
$DN/theme_switcher.sh
|
||||||
9
hm-imports/tmux/tmux-switch-colors/theme_setter.sh
Executable file
9
hm-imports/tmux/tmux-switch-colors/theme_setter.sh
Executable file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
DN=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||||
|
|
||||||
|
if [[ $1 == "dark" ]]; then
|
||||||
|
tmux source-file $DN/dark.tmux
|
||||||
|
else
|
||||||
|
tmux source-file $DN/light.tmux
|
||||||
|
fi
|
||||||
21
hm-imports/tmux/tmux-switch-colors/theme_switcher.sh
Executable file
21
hm-imports/tmux/tmux-switch-colors/theme_switcher.sh
Executable file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
[[ "${TRACE-0}" =~ ^1|t|y|true|yes$ ]] && set -o xtrace
|
||||||
|
|
||||||
|
|
||||||
|
[[ ! $(type -P "dark-notify") ]] && echo "dark-notify command not found. Exiting..." && exit 0
|
||||||
|
DN=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||||
|
SCRIPT_NAME="$(basename $0)"
|
||||||
|
|
||||||
|
THEME_SETTER="$DN/theme_setter.sh"
|
||||||
|
|
||||||
|
if pgrep -qf "$SCRIPT_NAME"; then
|
||||||
|
echo "$SCRIPT_NAME is already running, nothing to do here."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
while :; do
|
||||||
|
dark-notify -c "$THEME_SETTER"
|
||||||
|
done
|
||||||
|
|
@ -15,6 +15,7 @@ with lib.my;
|
||||||
enable = true;
|
enable = true;
|
||||||
brews = [
|
brews = [
|
||||||
"pam-reattach"
|
"pam-reattach"
|
||||||
|
"cormacrelf/tap/dark-notify"
|
||||||
];
|
];
|
||||||
casks = [
|
casks = [
|
||||||
"heroic"
|
"heroic"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue