Full Code of sunjon/Shade.nvim for AI

master 4286b5abc47d cached
3 files
14.0 KB
4.3k tokens
1 requests
Download .txt
Repository: sunjon/Shade.nvim
Branch: master
Commit: 4286b5abc47d
Files: 3
Total size: 14.0 KB

Directory structure:
gitextract_wrvkyd1r/

├── LICENSE
├── README.md
└── lua/
    └── shade.lua

================================================
FILE CONTENTS
================================================

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2021 Senghan Bright

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# shade.nvim

Shade is a Neovim plugin that dims your inactive windows, making it easier to see the active window at a glance.

<img src="https://raw.githubusercontent.com/sunjon/images/master/shade_demo.gif" alt="screenshot" width="800"/>

## Installation

### [Packer](https://github.com/wbthomason/packer.nvim) 

```
use 'sunjon/shade.nvim'
```
### [Vim-Plug](https://github.com/junegunn/vim-plug)

```
Plug 'sunjon/shade.nvim'
```

## Configuration

```
require'shade'.setup({
  overlay_opacity = 50,
  opacity_step = 1,
  keys = {
    brightness_up    = '<C-Up>',
    brightness_down  = '<C-Down>',
    toggle           = '<Leader>s',
  }
})
```

* The `keys` table above shows available actions. No mappings are defined by default.

* The color of the numbers in the brightness control popup can be customized by creating a highlight group named: `ShadeBrightnessPopup` and setting the attributes to your liking.

## License

Copyright (c) Senghan Bright. Distributed under the MIT license



================================================
FILE: lua/shade.lua
================================================
-- TODO: remove all active_overlays on tab change
local api = vim.api

local E = {}
E.DEFAULT_OVERLAY_OPACITY = 50
E.DEFAULT_OPACITY_STEP    = 1
E.DEBUG_OVERLAY_OPACITY   = 90
E.NOTIFICATION_TIMEOUT    = 1000 -- ms

local state = {}
state.active              = false
state.active_overlays     = {}
state.shade_nsid          = nil
state.notification_timer  = nil
state.notification_window = nil

-- TODO: log to file and/or nvim_echo
local function log(event, msg)
  if state.debug == false then
    return
  end

  msg = tostring(msg)
  local info = debug.getinfo(2, "Sl")
  local line_info = "[shade:" .. info.currentline .. "]"

  local timestamp = ("%s %-15s"):format(os.date("%H:%M:%S"), line_info)
  local event_msg = ("%-10s %s"):format(event, msg)
  print(timestamp .. "  : " .. event_msg)
end

--

local font = {
  0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00,   --  (0)
  0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00,   --  (1)
  0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00,   --  (2)
  0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x70, 0x00,   --  (3)
  0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,   --  (4)
  0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,   --  (5)
  0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00,   --  (6)
  0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,   --  (7)
  0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00,   --  (8)
  0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00,   --  (9)
}


local function get_digit(number, pos)
  local n  = 10 ^ pos
  local n1 = 10 ^ (pos - 1)
  return math.floor((number % n) / n1)
end

local function digitize(number)
  assert(type(number) == "number")
  local len = math.floor(math.log10(number) + 1)

  local block_chars = {[0] = " ", [1] = "▀", [2] = "▄", [3] = "█"}

  -- generate bit table
  local offset, char, row_bits, hex_val, b
  local characters = {}
  for n = 1, len do
    offset = get_digit(number, len - n + 1) * 8
    char = {}
    for row = 1, 8 do
      row_bits = {}
      hex_val = font[offset + row]
      for i = 1, 8 do
        b = bit.band(bit.rshift(hex_val, 8 - i), 1)
        row_bits[i] = b
      end
      table.insert(char, row_bits)
    end
    table.insert(characters, char)
  end

  -- generate strings
  local output = {}
  local upper, lower, combined, row_str
  for row = 1, 8, 2 do
    row_str = " "
    for _, c in ipairs(characters) do
      for col = 1, 8 do
        upper = c[row][col]
        lower = c[row + 1][col] * 2
        combined = block_chars[upper + lower]
        row_str = row_str .. combined
      end
    end
    row_str = row_str .. " "
    table.insert(output, row_str)
  end

  return output
end

--
local function filter_wininfo(wininfo)
  return {
    relative  = "editor",
    style     = "minimal",
    focusable = false,
    row    = wininfo.winrow - 1,
    col    = wininfo.wincol - 1,
    width  = wininfo.width,
    height = wininfo.height,
  }
end

--
local function create_hl_groups()
  local overlay_color
  if state.debug == true then
    overlay_color = "#77a992"
  else
    overlay_color = "None"
  end

  api.nvim_command("highlight ShadeOverlay gui='nocombine' guibg=" .. overlay_color)

  -- Link to default hl_group if not user defined
  local exists, _ = pcall(function()
    return vim.api.nvim_get_hl_by_name("ShadeBrightnessPopup", false)
  end)
  if not exists then
    api.nvim_command("highlight link ShadeBrightnessPopup Number")
  end
end

--

local function create_floatwin(config)
  local window = {}

  window.wincfg = config
  window.bufid = api.nvim_create_buf(false, true)
  window.winid = api.nvim_open_win(window.bufid, false, config)

  return window
end

--

local function map_key(mode, key, action)
  local req_module = ("<cmd>lua require'shade'.%s<CR>"):format(action)
  vim.api.nvim_set_keymap(mode, key, req_module, {noremap = true, silent = true})
end



local function shade_window(winid)
  local overlay = state.active_overlays[winid]
  if overlay then
    if api.nvim_win_is_valid(overlay.winid) then
      api.nvim_win_set_option(overlay.winid, "winblend", state.overlay_opacity)
      log("shade_window",
        ("[%d] : overlay %d ON (winblend: %d)"):format(winid, overlay.winid, state.overlay_opacity))
    end
  else
    log("shade_window", "overlay not found for " .. winid)
  end
end

local function unshade_window(winid)
  local overlay = state.active_overlays[winid]
  if overlay then
    if api.nvim_win_is_valid(overlay.winid) then
      api.nvim_win_set_option(overlay.winid, "winblend", 100)
      log("unshade_window",
        ("[%d] : overlay %d OFF (winblend: 100 [disabled])"):format(winid, overlay.winid))
    end
  else
    log("unshade_window", "overlay not found for " .. winid)
  end
end

-- shade everything on a tabpage except current window
local function shade_tabpage(winid)
  winid = winid or api.nvim_get_current_win()
  for overlay_winid, _ in pairs(state.active_overlays) do
    local diff_enabled = api.nvim_win_get_option(overlay_winid, 'diff')
    if overlay_winid ~= winid and diff_enabled == false then
      log("deactivating window", overlay_winid)
      shade_window(overlay_winid)
    end
  end
end

--

local function remove_all_overlays()
  for _, overlay in pairs(state.active_overlays) do
    api.nvim_win_close(overlay.winid, true)
  end
  state.active_overlays = {}
end


local function create_overlay_window(winid, config)
  local new_window = create_floatwin(config)
  state.active_overlays[winid] = new_window

  api.nvim_win_set_option(new_window.winid, "winhighlight", "Normal:ShadeOverlay")
  api.nvim_win_set_option(new_window.winid, "winblend", state.overlay_opacity)

  log("create overlay",
    ("[%d] : overlay %d created"):format(winid, state.active_overlays[winid].winid))
end

--
local function create_tabpage_overlays(tabid)
  local wincfg
  for _, winid in pairs(api.nvim_tabpage_list_wins(tabid)) do
    wincfg = api.nvim_call_function("getwininfo", {winid})[1]
    create_overlay_window(winid, filter_wininfo(wincfg))
  end
  unshade_window(api.nvim_get_current_win())
end

local shade = {}

-- init
shade.init = function(opts)
  state.active_overlays = {}

  opts = opts or {}
  state.debug = opts.debug or false

  state.overlay_opacity = opts.overlay_opacity or
                            (state.debug == true and E.DEBUG_OVERLAY_OPACITY or
                              E.DEFAULT_OVERLAY_OPACITY)
  state.opacity_step = opts.opacity_step or E.DEFAULT_OPACITY_STEP
  state.shade_under_float = opts.shade_under_float or true

  state.shade_nsid = api.nvim_create_namespace("shade")

  local shade_action = {
    ["brightness_up"] = "brightness_up()",
    ["brightness_down"] = "brightness_down()",
    ["toggle"] = "toggle()",
  }

  if opts.keys ~= nil then
    for action, key in pairs(opts.keys) do
      if not shade_action[action] then
        log("init:keymap", "unknown action " .. action)
      else
        map_key("n", key, shade_action[action])
      end
    end
  end

  create_hl_groups()

  api.nvim_set_decoration_provider(state.shade_nsid, {on_win = shade.event_listener})

  -- setup autocommands -- TODO: set a precalculated winid
  api.nvim_exec([[
    augroup shade
    au!
    au WinEnter,VimEnter * call v:lua.require'shade'.autocmd('WinEnter',  win_getid())
    au WinClosed         * call v:lua.require'shade'.autocmd('WinClosed', expand('<afile>'))
    au TabEnter          * call v:lua.require'shade'.autocmd('TabEnter',  win_getid())
    au OptionSet         diff call v:lua.require'shade'.autocmd('OptionSet', win_getid())
    augroup END
  ]], false)

  log("Init", "-- Shade.nvim started --")

  return true
end

--

shade.on_win_enter = function(event, winid)
  log(event, winid)
  if not state.active_overlays[winid] then
    local float_cfg = api.nvim_win_get_config(winid)
    if float_cfg["relative"] == "" then
      local wincfg = api.nvim_call_function("getwininfo", {winid})[1]
      create_overlay_window(winid, filter_wininfo(wincfg))
    else
      log(event, "floating window ignored: " .. winid)
      if not state.shade_under_float then
        return
      end
    end
  end

  -- hide the overlay on entered window
  unshade_window(winid)

  -- place overlays on all other windows
  shade_tabpage(winid)
end

shade.event_listener = function(_, winid, _, _, _)
  local cached = state.active_overlays[winid]
  if not cached then
    return
  end

  -- check if window dims match cache
  local current_wincfg = vim.api.nvim_call_function("getwininfo", {winid})[1]
  local resize_metrics = {"width", "height", "wincol", "winrow"}
  for _, m in pairs(resize_metrics) do
    if current_wincfg[m] ~= cached.wincfg[m] then
      log("event_listener: resized", winid)
      state.active_overlays[winid].wincfg = current_wincfg
      api.nvim_win_set_config(cached.winid, filter_wininfo(current_wincfg))
      goto continue
    end
  end
  ::continue::
end

--
-- destroy overlay window on WinClosed
shade.on_win_closed = function(event, winid)
  winid = tonumber(winid) -- TODO: when did winid become a string?
  local overlay = state.active_overlays[winid]
  if overlay == nil then
    log(event, "no overlay to close")
  else
    api.nvim_win_close(overlay.winid, false)
    log(event, ("[%d] : overlay %d destroyed"):format(winid, overlay.winid))
    state.active_overlays[winid] = nil
  end
end

shade.change_brightness = function(level)
  local curr_winid = api.nvim_get_current_win()
  state.overlay_opacity = level
  for id, w in pairs(state.active_overlays) do
    if id ~= curr_winid then
      log("winblend: winid" .. w.winid, level)
      api.nvim_win_set_option(w.winid, "winblend", level)
    end
  end

  local status_opts = {
    relative = "editor",
    style = "minimal",
    focusable = false,
    row       = 1,
    col       = vim.o.columns - 18,
    width     = 18,
    height    = 4,
  }

  if state.notification_window == nil then
    state.notification_window = create_floatwin(status_opts)
    api.nvim_win_set_option(state.notification_window.winid, "winhighlight",
      "Normal:ShadeBrightnessPopup")
    api.nvim_win_set_option(state.notification_window.winid, "winblend", 10)
    log("notification", "popup created")
  end

  local output_lines = digitize(level)
  api.nvim_buf_set_lines(state.notification_window.bufid, 0, 7, false, output_lines)

  if state.notification_timer ~= nil then
    state.notification_timer:stop()
    state.notification_timer = nil
    log("notification", "timer aborted")
  end
  state.notification_timer = vim.loop.new_timer()
  state.notification_timer:start(E.NOTIFICATION_TIMEOUT, 0, vim.schedule_wrap(
    function()
      if api.nvim_win_is_valid(state.notification_window.winid) then
        api.nvim_win_close(state.notification_window.winid, true)
        state.notification_window = nil
        log("notification", "timer ended")
        log("notification", "popup closed")
      end
    end))

end

-- Main
local M = {}

M.setup = function(opts)
  if state.active == true then
    return
  end
  shade.init(opts)
  state.active = true
end

M.brightness_up = function()
  if not state.active then
    return
  end

  local adjusted = state.overlay_opacity + state.opacity_step
  if adjusted > 99 then
    adjusted = 99
  end
  shade.change_brightness(adjusted)
end

M.brightness_down = function()
  if not state.active then
    return
  end

  local adjusted = state.overlay_opacity - state.opacity_step
  if adjusted < 0 then
    adjusted = 0
  end
  shade.change_brightness(adjusted)
end

M.toggle = function()
  if state.active then
    remove_all_overlays()
    print("off")
    state.active = false
  else
    create_tabpage_overlays(0)
    print("on")
    state.active = true
  end
end

M.autocmd = function(event, winid)
  if not state.active then
    return
  end
  log("AutoCmd: " .. event .. " : " .. winid)

  local event_fn = {
    ["WinEnter"] = function()
      shade.on_win_enter(event, winid)
    end,
    ["WinClosed"] = function()
      shade.on_win_closed(event, winid)
    end,
    ["TabEnter"] = function()
      remove_all_overlays()
      create_tabpage_overlays(0)
    end,
    ["OptionSet"] = function()
     local diff_enabled = api.nvim_get_vvar('option_new')
     if diff_enabled then
       unshade_window(winid)
       shade_tabpage(winid)
     end
    end
  }

  local fn = event_fn[event]
  if fn then
    fn()
  end
end

return M
Download .txt
gitextract_wrvkyd1r/

├── LICENSE
├── README.md
└── lua/
    └── shade.lua
Condensed preview — 3 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (15K chars).
[
  {
    "path": "LICENSE",
    "chars": 1071,
    "preview": "MIT License\n\nCopyright (c) 2021 Senghan Bright\n\nPermission is hereby granted, free of charge, to any person obtaining a "
  },
  {
    "path": "README.md",
    "chars": 997,
    "preview": "# shade.nvim\n\nShade is a Neovim plugin that dims your inactive windows, making it easier to see the active window at a g"
  },
  {
    "path": "lua/shade.lua",
    "chars": 12317,
    "preview": "-- TODO: remove all active_overlays on tab change\nlocal api = vim.api\n\nlocal E = {}\nE.DEFAULT_OVERLAY_OPACITY = 50\nE.DEF"
  }
]

About this extraction

This page contains the full source code of the sunjon/Shade.nvim GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 3 files (14.0 KB), approximately 4.3k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!