├── .github ├── FUNDING.yml └── workflows │ ├── ci.yml │ └── linter.yml ├── .gitignore ├── .luacheckrc ├── LICENSE ├── Makefile ├── README.md ├── colors ├── boo.lua ├── crimson_moonlight.lua ├── forest_stream.lua ├── radioactive_waste.lua └── sunset_cloud.lua ├── lua ├── boo-colorscheme.lua ├── colors.lua └── style.lua ├── stylua.toml └── tests ├── boo-colorscheme_spec.lua └── minimal_init.vim /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: rockerBOO 4 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | permissions: read-all 10 | 11 | jobs: 12 | appimage-ubuntu: 13 | name: Appimage-ubuntu 14 | runs-on: ubuntu-24.04 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 18 | 19 | - name: Set today's date 20 | run: date +%F > todays-date 21 | 22 | - name: Restore cache for today nightly. 23 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 24 | with: 25 | path: | 26 | build 27 | key: ${{ runner.os }}-appimage-${{ hashFiles('todays-date') }} 28 | 29 | - name: Prepare 30 | run: | 31 | test -d build || { 32 | mkdir -p build 33 | wget https://github.com/neovim/neovim/releases/download/nightly/nvim-linux-x86_64.appimage 34 | chmod +x nvim-linux-x86_64.appimage 35 | mv nvim-linux-x86_64.appimage ./build/nvim 36 | } 37 | mkdir -p ~/.local/share/nvim/site/pack/vendor/start 38 | git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim 39 | ln -s "$(pwd)" ~/.local/share/nvim/site/pack/vendor/start 40 | 41 | - name: Run tests 42 | run: | 43 | export PATH="${PWD}/build/:${PATH}" 44 | make test 45 | -------------------------------------------------------------------------------- /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | ################################# 2 | ################################# 3 | ## Super Linter GitHub Actions ## 4 | ################################# 5 | ################################# 6 | name: Lint Code Base 7 | 8 | # 9 | # Documentation: 10 | # https://help.github.com/en/articles/workflow-syntax-for-github-actions 11 | # 12 | 13 | ############################# 14 | # Start the job on all push # 15 | ############################# 16 | on: 17 | push: 18 | pull_request: 19 | branches: [main] 20 | 21 | permissions: read-all 22 | 23 | ############### 24 | # Set the Job # 25 | ############### 26 | jobs: 27 | build: 28 | # Name the Job 29 | name: Lint Code Base 30 | # Set the agent to run on 31 | runs-on: ubuntu-24.04 32 | 33 | ################## 34 | # Load all steps # 35 | ################## 36 | steps: 37 | ########################## 38 | # Checkout the code base # 39 | ########################## 40 | - name: Checkout Code 41 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 42 | with: 43 | # Full git history is needed to get a proper 44 | # list of changed files within `super-linter` 45 | fetch-depth: 0 46 | 47 | ################################ 48 | # Run Linter against code base # 49 | ################################ 50 | - name: Lint Code Base 51 | uses: github/super-linter/slim@12150456a73e248bdc94d0794898f94e23127c88 52 | env: 53 | VALIDATE_ALL_CODEBASE: false 54 | DEFAULT_BRANCH: main 55 | LINTER_RULES_PATH: / 56 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .luarc.json 3 | -------------------------------------------------------------------------------- /.luacheckrc: -------------------------------------------------------------------------------- 1 | cache = true 2 | 3 | std = luajit 4 | 5 | self = false 6 | 7 | globals = {"vim"} 8 | 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Dave Lage (rockerBOO) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | nvim --headless -c 'PlenaryBustedDirectory tests/' 3 | 4 | lint: 5 | luacheck lua/ 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Boo 2 | 3 | Sorry, didn't mean to scare you. 4 | 5 | Boo is a colorscheme for Neovim with handcrafted-artisanal support for LSP, Treesitter. 6 | 7 | ![Full Screen](https://user-images.githubusercontent.com/15027/178179115-3e238800-8c53-4160-962f-90b9d1ad3747.png) 8 | 9 | [![Action Status](https://github.com/rockerBOO/boo-colorscheme-nvim/workflows/Tests/badge.svg)](https://github.com/rockerBOO/boo-colorscheme-nvim/actions) 10 | 11 | ## Goal 12 | 13 | - To use subtle changes in colors to help lessen the syntax noise. 14 | - Brightness range on syntax to ramp up to values and variables. 15 | 16 | ## Requirements 17 | 18 | - Neovim 0.4 19 | - `termguicolors` required (`:h 'termguicolors'`) 20 | 21 | `vimscript` 22 | 23 | ```vimscript 24 | if (has("termguicolors")) 25 | set termguicolors 26 | endif 27 | ``` 28 | 29 | `lua` 30 | 31 | ```lua 32 | if vim.fn.has("termguicolors") then 33 | vim.opt.termguicolors = true 34 | end 35 | ``` 36 | 37 | ## Install 38 | 39 | ### Plug 40 | 41 | ```vimscript 42 | Plug 'rockerBOO/boo-colorscheme-nvim' 43 | ``` 44 | 45 | ### Packer 46 | 47 | ```lua 48 | use 'rockerBOO/boo-colorscheme-nvim' 49 | ``` 50 | 51 | Then in your `init.vim` or `init.lua` you can set it to use it as your color scheme. 52 | 53 | ```vimscript 54 | colorscheme boo 55 | ``` 56 | 57 | Or in lua with the use function. This allows you to pass options like `{ theme = "radioactive_waste" }`. 58 | 59 | ```lua 60 | require("boo-colorscheme").use({}) 61 | ``` 62 | 63 | ## Options 64 | 65 | ```lua 66 | require("boo-colorscheme").use({ 67 | italic = true, -- toggle italics 68 | theme = "boo" 69 | }) 70 | ``` 71 | 72 | or in vimscript 73 | 74 | ```vimscript 75 | let g:boo_colorscheme_italic = true 76 | ``` 77 | 78 | ## Themes 79 | 80 | - [`sunset_cloud`](#sunset_cloud) 81 | - [`radioactive_waste`](#radioactive_waste) 82 | - [`forest_stream`](#forest_stream) 83 | - [`crimson_moonlight`](#crimson_moonlight) 84 | 85 | These are full colorschemes so you can call them directly 86 | 87 | ```vimscript 88 | colorscheme sunset_cloud 89 | ``` 90 | 91 | or 92 | 93 | ```lua 94 | require('boo-colorscheme').use({ theme = 'sunset_cloud' }) 95 | ``` 96 | 97 | or set in combination with the `colorscheme boo` and the following 98 | 99 | ```vimscript 100 | let g:boo_colorscheme_theme = 'sunset_cloud' 101 | ``` 102 | 103 | ### `sunset_cloud` 104 | 105 | ![Screenshot of the source code showing sunset_cloud](https://user-images.githubusercontent.com/15027/162499722-a703531e-e9ac-461e-befb-dc9040234869.png) 106 | 107 | ### `radioactive_waste` 108 | 109 | ![Screenshot of the source code showing radioactive waste](https://user-images.githubusercontent.com/15027/178177587-620c2623-c31a-469a-944f-e2c5bbc1bea6.png) 110 | 111 | ### `forest_stream` 112 | 113 | ![Screenshot of the source code showing forest stream](https://user-images.githubusercontent.com/15027/178177588-cfe53f8c-08a3-49af-b44a-6667574b1fda.png) 114 | 115 | ### `crimson_moonlight` 116 | 117 | ![Screenshot of the source code showing crimson_moonlight](https://user-images.githubusercontent.com/15027/178177589-bcfe7280-9c43-4d41-abf4-f40e56be9803.png) 118 | 119 | ## Support 120 | 121 | ### Typescript/TSX/JSX 122 | 123 | ![typescript](https://user-images.githubusercontent.com/15027/178179116-15203812-037b-458c-b27e-3ce3f1663a51.png) 124 | 125 | ### Rust 126 | 127 | ![rust](https://user-images.githubusercontent.com/15027/178296453-9b0cc27b-417f-46e4-8bc1-a4d47d49788e.png) 128 | 129 | ### Go 130 | 131 | ![go](https://user-images.githubusercontent.com/15027/197879409-cd019366-4ac3-480a-a130-233f1977496b.png) 132 | 133 | ### Telescope 134 | 135 | ![telescope](https://user-images.githubusercontent.com/15027/197878218-9d976b7d-2c47-4242-b5ca-1fb4db5ac803.png) 136 | 137 | ## Colors 138 | 139 | ![Colors Used](https://user-images.githubusercontent.com/15027/112667058-321a6900-8e33-11eb-9c06-7c15ab5b7b18.png) 140 | 141 | ## Development 142 | 143 | ### Tests 144 | 145 | Requires a busted supported test runner. 146 | 147 | - `make test` - 148 | -------------------------------------------------------------------------------- /colors/boo.lua: -------------------------------------------------------------------------------- 1 | require("boo-colorscheme").use({ }) 2 | -------------------------------------------------------------------------------- /colors/crimson_moonlight.lua: -------------------------------------------------------------------------------- 1 | require("boo-colorscheme").use({ theme = "crimson_moonlight" }) 2 | -------------------------------------------------------------------------------- /colors/forest_stream.lua: -------------------------------------------------------------------------------- 1 | require("boo-colorscheme").use({ theme = "forest_stream" }) 2 | -------------------------------------------------------------------------------- /colors/radioactive_waste.lua: -------------------------------------------------------------------------------- 1 | require("boo-colorscheme").use({ theme = "radioactive_waste" }) 2 | -------------------------------------------------------------------------------- /colors/sunset_cloud.lua: -------------------------------------------------------------------------------- 1 | require("boo-colorscheme").use({ theme = "sunset_cloud" }) 2 | -------------------------------------------------------------------------------- /lua/boo-colorscheme.lua: -------------------------------------------------------------------------------- 1 | -- Colorscheme 2 | -- with Treesitter, Typescript, LSP supported 3 | -- colors from colorsx cloud (defunct website) 4 | local colors = require("colors") 5 | local s = require("style") 6 | 7 | -- Merge a list of list-like tables togeter 8 | -- { {'x'}, {'y'} } -> {'x', 'y'} 9 | local merge = function(list) 10 | local acc = {} 11 | 12 | for _, result in ipairs(list) do 13 | if result ~= nil then 14 | vim.list_extend(acc, result) 15 | end 16 | end 17 | 18 | return acc 19 | end 20 | 21 | -- param groups table list of Groups to apply the highlights 22 | local highlight_to_groups = function(highlight) 23 | -- param highlight table 3 element table { fg colorbuddy.Color, bg colorbuddy.Color, styles colorbuddy.Styles } 24 | return function(groups) 25 | local acc = {} 26 | 27 | for _, name in ipairs(groups) do 28 | if type(name) == "table" then 29 | -- name 30 | -- { "TSName", link = "@name" } 31 | table.insert(acc, { name[0], highlight[1], highlight[2], highlight[3], link = name["link"] }) 32 | else 33 | -- name 34 | -- "TSName" 35 | table.insert(acc, { name, highlight[1], highlight[2], highlight[3] }) 36 | end 37 | end 38 | 39 | return acc 40 | end 41 | end 42 | 43 | -- Used in tuning colors to be more base 16 based 44 | -- This will allow us to have our scheme work with base 16 colors that could 45 | -- be dynamically added 46 | local default = function() 47 | return { 48 | "#282a2e", -- 0 49 | "#a54242", 50 | "#8c9440", 51 | "#de935f", 52 | "#5f819d", -- 4 53 | "#85678f", 54 | "#5e8d87", 55 | "#707880", 56 | "#373b41", -- 8 57 | "#cc6666", 58 | "#b5bd68", 59 | "#f0c674", 60 | "#81a2be", -- 12 61 | "#b294bb", 62 | "#8abeb7", 63 | "#c5c8c6", -- 15 64 | } 65 | end 66 | 67 | local boo_lora = function() 68 | return { 69 | "#08413f", -- 0 #08413f 70 | "#9e1f0a", -- #9e1f0a 71 | "#074c0e", -- #074c0e 72 | "#c2ef36", -- #c2ef36 73 | "#142d5a", -- 4 #142d5a 74 | "#4a1f61", -- #4a1f61 75 | "#23d1c5", -- #23d1c5 76 | "#064341", -- #064341 77 | "#373b41", -- 8 78 | "#a32d2e", -- #a32d2e 79 | "#17bb20", -- #17bb20 80 | "#c1ff92", -- #c1ff92 81 | "#f0c674", -- 12 #07262e 82 | "#5c1847", -- #5c1847 83 | "#19d190", -- #19d190 84 | "#13cdc6", -- 15 #13cdc6 85 | } 86 | end 87 | 88 | -- Cloud colors 89 | local cloud = function() 90 | return { 91 | "#222827", -- 0 92 | "#d5a8e4", 93 | "#9c75dd", 94 | "#9898ae", 95 | "#654a96", -- 4 96 | "#625566", 97 | "#a9d1df", 98 | "#e6ebe5", 99 | "#5d6f74", -- 8 100 | "#cd749c", 101 | "#63b0b0", 102 | "#c0c0dd", 103 | "#5786bc", -- 12 104 | "#3f3442", 105 | "#849da2", 106 | "#d9d6cf", -- 15 107 | } 108 | end 109 | 110 | local forest_stream = function() 111 | return { 112 | "#0d1f0f", 113 | "#caade1", 114 | "#7a77cd", 115 | "#2f594c", 116 | "#42647f", 117 | "#3e4d45", 118 | "#89d9d0", 119 | "#e8f4e7", 120 | "#3c7153", 121 | "#c7566f", 122 | "#41b193", 123 | "#a5c1cd", 124 | "#3788a2", 125 | "#243528", 126 | "#609f83", 127 | "#f0f4e7", 128 | } 129 | end 130 | 131 | local crimson_moonlight = function() 132 | return { 133 | "#201c1c", 134 | "#fca2ae", 135 | "#e15774", 136 | "#bc969a", 137 | "#714e75", 138 | "#6c494d", 139 | "#e9bfc4", 140 | "#f9f1f2", 141 | "#796769", 142 | "#dd5571", 143 | "#d19299", 144 | "#dfb8bc", 145 | "#b96a76", 146 | "#473234", 147 | "#ab9295", 148 | "#f9f2f3", 149 | } 150 | end 151 | 152 | local sunset_cloud = function() 153 | return { 154 | "#262904", 155 | "#cd6d91", 156 | "#947fbc", 157 | "#8d9a59", 158 | "#655a7c", 159 | "#5e4531", 160 | "#71d17c", 161 | "#e0ec7a", 162 | "#5d6f74", 163 | "#bc5050", 164 | "#4eae6e", 165 | "#bbc373", 166 | "#40719c", 167 | "#3c2e1a", 168 | "#809d7b", 169 | "#dad36d", 170 | } 171 | end 172 | 173 | local radioactive = function() 174 | return { 175 | "#282822", 176 | "#e3e3a8", 177 | "#56417a", 178 | "#aeae98", 179 | "#7b6c97", 180 | "#666655", 181 | "#dfdfa9", 182 | "#a39778", 183 | "#74745d", 184 | "#cd749c", 185 | "#a38c78", 186 | "#bbbc57", 187 | "#bbbc57", 188 | "#424234", 189 | "#a2a284", 190 | "#d9d9cf", 191 | } 192 | end 193 | 194 | local vimscript = function(c) 195 | return { 196 | { "vimcommand", c.cloud4 }, 197 | { "vimmap", c.cloud4 }, 198 | { "vimbracket", c.cloud10 }, 199 | { "vimmapmodkey", c.cloud6 }, 200 | { "vimnotation", c.cloud6 }, 201 | { "vimmaplhs", c.cloud10 }, 202 | { "vimiscommand", c.cloud10:light() }, 203 | { "vimFilter", c.cloud7 }, 204 | { "vimMapRhs", c.cloud15:dark(0.1) }, 205 | { "vimMapRhsExtend", c.cloud15:dark(0.1) }, 206 | 207 | { "vimlet", c.cloud4:dark() }, 208 | { "vimnotfunc", c.cloud4:dark() }, 209 | { "vimAutoCmdSfxList", c.cloud6 }, 210 | { "vimUserFunc", c.cloud10 }, 211 | { "vimSetEqual", c.cloud6 }, 212 | } 213 | end 214 | 215 | local diagnostics = function(c) 216 | return { 217 | { "DiagnosticHint", c.cloud13:saturate(0.05):light(0.1), c.cloud13:dark(0.9) }, 218 | { 219 | "DiagnosticError", 220 | c.cloud1:saturate(0.05):lighten_to(0.7), 221 | c.none, 222 | }, 223 | { 224 | "DiagnosticWarn", 225 | c.cloud11, 226 | c.none, 227 | }, 228 | { "DiagnosticInfo", c.fg }, 229 | -- { 230 | -- "DiagnosticUnderlineHint", 231 | -- c.none, 232 | -- c.none, 233 | -- s.underline, 234 | -- c.cloud13:saturate(0.05):lighten_to(0.2), 235 | -- }, 236 | -- { 237 | -- "DiagnosticUnderlineError", 238 | -- c.none, 239 | -- c.none, 240 | -- s.underline, 241 | -- c.cloud1:saturate(0.05):lighten_to(0.9), 242 | -- }, 243 | -- { 244 | -- "DiagnosticUnderlineWarn", 245 | -- c.none, 246 | -- c.none, 247 | -- s.underline, 248 | -- c.cloud6:lighten_to(0.9), 249 | -- }, 250 | -- { 251 | -- "DiagnosticUnderlineInfo", 252 | -- c.none, 253 | -- c.none, 254 | -- s.underline, 255 | -- c.fg:lighten_to(0.1), 256 | -- }, 257 | } 258 | end 259 | 260 | local diff = function(c) 261 | return { 262 | { "diffAdded", c.none, c.cloud6:lighten_to(0.1):desaturate_to(0.2) }, 263 | { "diffRemoved", c.none, c.cloud1:lighten_to(0.1):desaturate_to(0.2) }, 264 | { "diffChanged", c.none, c.cloud2:lighten_to(0.1):desaturate_to(0.2) }, 265 | { "DiffAdd", c.none, c.cloud6:lighten_to(0.1):desaturate_to(0.2) }, 266 | { "DiffDelete", c.none, c.cloud1:lighten_to(0.1):desaturate_to(0.2) }, 267 | { "DiffChange", c.none, c.cloud2:lighten_to(0.1):desaturate_to(0.2) }, 268 | { "DiffText", c.cloud7 }, 269 | } 270 | end 271 | 272 | local lsp = function(c) 273 | return { 274 | { "LspReferenceText", c.cloud6:lighten_to(0.9):desaturate_to(0.5) }, 275 | { "LspReferenceRead", c.none, c.cloud12:lighten_to(0.1) }, 276 | { "LspReferenceWrite", c.none, c.cloud12:lighten_to(0.1) }, 277 | 278 | { "LspInlayHint", c.cloud12:lighten_to(0.3):desaturate_to(0.3) }, 279 | } 280 | end 281 | 282 | local lsp_semantic_tokens = function() 283 | return { 284 | { "LspParameter", nil, nil, s.italic }, 285 | } 286 | end 287 | 288 | local cmp = function(c) 289 | return { 290 | { "CmpItemMenu", c.cloud0:dark(0.01) }, 291 | { "CmpItemAbbr", c.cloud4 }, 292 | { "CmpItemAbbrMatch", c.cloud2 }, 293 | { "CmpItemAbbrMatchFuzzy", c.cloud2 }, 294 | { "CmpItemKind", c.cloud0:dark(0.01) }, 295 | } 296 | end 297 | 298 | local telescope = function(c) 299 | return { 300 | { "TelescopeBorder", c.bg:lighten_to(0.3) }, 301 | { "TelescopeNormal", c.cloud0:light(0.3) }, 302 | { "TelescopePromptPrefix", c.cloud10:dark(0.2) }, 303 | 304 | { "TelescopeSelection", c.cloud10:light(), c.cloud8:dark(0.2), s.bold }, 305 | { "TelescopeMatching", c.cloud4:light() }, 306 | } 307 | end 308 | 309 | local markdown = function(c) 310 | local to_groups = highlight_to_groups({ c.cloud5:lighten_by(1), c.cloud5:lighten_to(0.2) }) 311 | local delimiters = to_groups({ 312 | "markdownH1Delimiter", 313 | "markdownH2Delimiter", 314 | "markdownH3Delimiter", 315 | "markdownH4Delimiter", 316 | "markdownH5Delimiter", 317 | "markdownH6Delimiter", 318 | }) 319 | 320 | local hbg = c.cloud0:lighten_by(1) 321 | 322 | return merge({ 323 | delimiters, 324 | { 325 | { "markdownh1", c.cloud6:light():saturate(0.7), hbg, s.bold }, 326 | { "markdownh2", c.cloud6:saturate(0.7), hbg, s.bold }, 327 | { "markdownh3", c.cloud6:dark(), hbg, s.bold }, 328 | { "markdownh4", c.cloud6:dark(), hbg, s.bold }, 329 | { "markdownh5", c.cloud6:dark(), hbg, s.bold }, 330 | 331 | { "markdownCodeDelimiter", c.cloud8:dark(), c.cloud0:dark(0.1) }, 332 | { "markdownCode", c.cloud4, c.cloud0:dark(0.1) }, 333 | { "markdownUrl", c.cloud14 }, 334 | { "markdownLinkText", c.cloud10 }, 335 | 336 | { "markdownLinkTextDelimiter", c.cloud8 }, 337 | { "markdownLinkDelimiter", c.cloud8 }, 338 | }, 339 | }) 340 | end 341 | 342 | local symbols_outline = function(c) 343 | return { 344 | { "FocusedSymbol", c.none, c.cloud10:dark(0.4):desaturate_to(0.1), s.bold }, 345 | } 346 | end 347 | 348 | local nvim_dap_virtual_text = function(c) 349 | return { 350 | 351 | { "NvimDapVirtualText", c.cloud4:lighten_to(0.4), c.none, s.italic }, 352 | } 353 | end 354 | 355 | local nvim_dap_ui = function(c) 356 | return { 357 | { "DapUIValue", "@variable" }, 358 | { "DapUIFrameName", "Normal" }, 359 | { "DapUIVariable", "@variable" }, 360 | 361 | { "DapUIScope", c.cloud14:light(0.1) }, 362 | { "DapUIType", c.cloud13:lighten_to(0.4) }, 363 | { "DapUIModifiedValue", c.cloud14:light(0.1), c.none, s.bold }, 364 | { "DapUIDecoration", c.cloud14:light(0.1) }, 365 | { "DapUIThread", c.cloud11 }, 366 | { "DapUIStoppedThread", c.cloud14 }, 367 | { "DapUISource", c.cloud13 }, 368 | { "DapUILineNumber", c.cloud14:light(0.1) }, 369 | { "DapUIFloatBorder", c.cloud14:light(0.1) }, 370 | { "DapUIWatchesEmpty", c.cloud9 }, 371 | { "DapUIWatchesValue", c.cloud10 }, 372 | { "DapUIWatchesError", c.cloud9 }, 373 | { "DapUIBreakpointsPath", c.cloud14:light(0.1) }, 374 | { "DapUIBreakpointsInfo", c.cloud10 }, 375 | { "DapUIBreakpointsCurrentLine", c.cloud10, c.none, s.bold }, 376 | { "DapUIBreakpointsDisabledLine", c.cloud15 }, 377 | 378 | { "DapUIBreakpointsLine", "DapUILineNumber" }, 379 | } 380 | end 381 | 382 | local harpoon = function(c) 383 | return { 384 | { "HarpoonBorder", c.bg:lighten_to(0.3) }, 385 | } 386 | end 387 | 388 | local llama = function(c) 389 | return { 390 | { "llama_hl_hint", c.cloud12:lighten_to(0.3):desaturate_to(0.3) }, 391 | } 392 | end 393 | 394 | local notify_plugin = function(c) 395 | -- NotifyBackground xxx links to Normal 396 | -- NotifyERRORBorder xxx guifg=#8a1f1f 397 | -- NotifyWARNBorder xxx guifg=#79491d 398 | -- NotifyINFOBorder xxx guifg=#4f6752 399 | -- NotifyDEBUGBorder xxx guifg=#8b8b8b 400 | -- NotifyTRACEBorder xxx guifg=#4f3552 401 | -- NotifyERRORIcon xxx guifg=#f70067 402 | -- NotifyWARNIcon xxx guifg=#f79000 403 | -- NotifyINFOIcon xxx guifg=#a9ff68 404 | -- NotifyDEBUGIcon xxx guifg=#8b8b8b 405 | -- NotifyTRACEIcon xxx guifg=#d484ff 406 | -- NotifyERRORTitle xxx guifg=#f70067 407 | -- NotifyWARNTitle xxx guifg=#f79000 408 | -- NotifyINFOTitle xxx guifg=#a9ff68 409 | -- NotifyDEBUGTitle xxx guifg=#8b8b8b 410 | -- NotifyTRACETitle xxx guifg=#d484ff 411 | -- NotifyERRORBody xxx links to Normal 412 | -- NotifyWARNBody xxx links to Normal 413 | -- NotifyINFOBody xxx links to Normal 414 | -- NotifyDEBUGBody xxx links to Normal 415 | -- NotifyTRACEBody xxx links to Normal 416 | -- NotifyLogTime xxx links to Comment 417 | -- NotifyLogTitle xxx links to Special 418 | return { 419 | { "NotifyINFOBorder", c.bg, c.none, s.none }, 420 | { "NotifyINFOTitle", c.cloud12, c.none, s.none }, 421 | { "NotifyINFOIcon", c.cloud12:lighten_by(1.1), c.none, s.none }, 422 | { "NotifyINFOBody", c.cloud12, c.none, s.none }, 423 | } 424 | end 425 | 426 | local treesitter = function(c) 427 | local error = { "TSError" } 428 | 429 | local punctuation = { 430 | "TSPunctDelimiter", 431 | "TSPunctBracket", 432 | "TSPunctSpecial", 433 | "@punctuation.delimiter", 434 | "@punctuation.bracket", 435 | "@punctuation.special", 436 | } 437 | 438 | local constants = { 439 | "TSConstant", 440 | "TSConstBuiltin", 441 | "TSConstMacro", 442 | "@constant", 443 | "@constant.builtin", 444 | "@constant.macro", 445 | } 446 | 447 | local constructors = { "TSConstructor", "@constructor" } 448 | 449 | local string = { 450 | "TSStringRegex", 451 | "TSString", 452 | "TSStringEscape", 453 | "TSStringSpecial", 454 | "@string.regex", 455 | "@string", 456 | "@string.escape", 457 | "@string.special", 458 | } 459 | 460 | local boolean = { "TSBoolean", "@boolean" } 461 | 462 | local functions = { 463 | "TSFunction", 464 | "TSFuncBuiltin", 465 | "TSFuncMacro", 466 | "@function", 467 | "@function.builtin", 468 | "@function.macro", 469 | } 470 | 471 | local function_calls = { "@function.call" } 472 | 473 | local attributes = { "@attribute" } 474 | 475 | local methods = { "TSMethod", "@method", "@method.call" } 476 | -- 477 | -- local fields = { "TSField", "TSProperty", "@field", "@property" } 478 | -- 479 | -- local number = { "TSNumber", "TSFloat", "@number", "@float" } 480 | 481 | local parameters = { "TSParameter", "TSParameterReference", "@parameter", "@parameter.reference" } 482 | 483 | -- local operators = { "TSOperator", "@operator" } 484 | 485 | local forwords = { "TSConditional", "TSRepeat", "@conditional", "@repeat" } 486 | 487 | local keyword = { 488 | "TSKeyword", 489 | "TSKeywordFunction", 490 | "TSKeywordReturn", 491 | "TSKeywordOperator", 492 | "@keyword", 493 | "@keyword.function", 494 | "@keyword.operator", 495 | "@keyword.return", 496 | } 497 | 498 | -- local labels = { "TSLabel", "@label" } 499 | 500 | local types = { "TSType", "TSTypeBuiltin", "@type", "@type.builtin", "@type.qualifier", "@type.defintion" } 501 | 502 | local namespaces = { "TSNamespace", "@namespace" } 503 | 504 | local includes = { "TSInclude", "@include" } 505 | 506 | local variables = { "TSVariable", "TSVariableBuiltin", "@variable", "@variable.builtin" } 507 | 508 | local tags = { "TSTag", "TSTagDelimiter", "@tag" } 509 | 510 | local tag_punctuation = { "@tag.delimiter" } 511 | local tag_fields = { "@tag.attribute" } 512 | 513 | local text = { 514 | "TSText", 515 | "TSStrong", 516 | "TSEmphasis", 517 | "TSUnderline", 518 | "TSLiteral", 519 | "TSURI", 520 | "@text", 521 | "@text.string", 522 | "@text.emphassis", 523 | "@text.underline", 524 | "@text.strike", 525 | "@text.title", 526 | "@text.literal", 527 | "@text.math", 528 | "@text.reference", 529 | "@text.environment", 530 | "@text.environment.name", 531 | } 532 | 533 | local uri = { "@text.uri" } 534 | 535 | local title = { "TSTitle" } 536 | 537 | local groups = { 538 | { attributes, c.cloud7:lighten_to(0.4):desaturate(0.3) }, 539 | { error, c.cloud1:light(), c.cloud9:dark(0.5), s.none }, 540 | { punctuation, c.cloud3:lighten_to(0.4):desaturate(0.1) }, 541 | { constants, c.cloud5:light(0.1) }, 542 | { string, c.cloud10:lighten_to(0.9):desaturate_to(0.5) }, 543 | { uri, c.cloud10:lighten_to(0.4):desaturate_to(0.3) }, 544 | { boolean, c.cloud2:light(0.1) }, 545 | { functions, c.cloud14:desaturate_to(0.2) }, 546 | { { "@function" }, c.cloud14:desaturate_to(0.2), c.none, s.italic }, 547 | { function_calls, c.cloud14:lighten_to(0.5):desaturate_to(0.4), c.none, s.italic }, 548 | 549 | { methods, c.cloud14:lighten_to(0.5):desaturate_to(0.4), c.none, s.italic }, 550 | -- { fields, c.cloud10:lighten_to(0.5):desaturate_to(0.1) }, 551 | -- { number, c.cloud6:lighten_to(0.8):desaturate_to(0.1) }, 552 | { parameters, c.cloud6:dark() }, 553 | -- { operators, c.cloud3:lighten_to(0.4):desaturate(0.1) }, 554 | { forwords, c.cloud8:saturate(0.1), c.none }, 555 | { keyword, c.cloud4:lighten_to(0.45), c.none, s.italic }, 556 | { { "@keyword.function" }, c.cloud4:lighten_to(0.45), c.none, s.italic }, 557 | 558 | { constructors, c.cloud10 }, 559 | { types, c.cloud10 }, 560 | { includes, c.cloud4 }, 561 | -- { labels, c.cloud4 }, 562 | { namespaces, c.cloud14:light(0.1) }, 563 | { variables, c.cloud6:lighten_to(0.7):desaturate_to(0.4) }, 564 | { tags, c.cloud10:light(0.1) }, 565 | { tag_punctuation, c.cloud3:lighten_to(0.4):desaturate(0.1) }, 566 | { tag_fields, c.cloud10:lighten_to(0.5):desaturate_to(0.1) }, 567 | { text, c.fg }, 568 | { title, c.cloud10:desaturate_to(0.1) }, 569 | } 570 | 571 | local highlights = {} 572 | 573 | -- Apply grouping to each color group 574 | for _, group in ipairs(groups) do 575 | highlights = merge({ highlights, highlight_to_groups({ group[2], group[3], group[4] })(group[1]) }) 576 | end 577 | 578 | return merge({ 579 | highlights, 580 | { 581 | { "@punctuation.delimiter", c.cloud3:desaturate_to(0.05):lighten_to(0.4) }, 582 | { "@punctuation.special", c.cloud12:desaturate_to(0.1):lighten_to(0.5) }, 583 | { "@tag.delimiter", c.cloud8:dark(0.15) }, 584 | { "@variable.builtin", c.cloud6:dark(), c.none, s.bold }, 585 | { "@constant.builtin", c.cloud6:dark(0.3), c.none, s.bold }, 586 | 587 | { "@function.builtin", c.cloud10:dark(0.2), c.none, s.bold }, 588 | { "@type.builtin", c.cloud8:light(0.1), c.none, s.bold }, 589 | 590 | { "@variable.builtin", c.cloud12:lighten_to(0.4) }, 591 | -- { "@field", c.cloud7 }, 592 | 593 | { "TSPunctDelimiter", "@punctuation.delimiter" }, 594 | { "TSPunctSpecial", "@punctuation.special" }, 595 | 596 | { "TSTagDelimiter", "@tag.delimiter" }, 597 | 598 | { "TSConstBuiltin", "@constant.builtin" }, 599 | { "TSVariableBuiltin", "@variable.builtin" }, 600 | 601 | { "TSFuncBuiltin", "@function.builtin" }, 602 | { "TSTypeBuiltin", "@type.builtin" }, 603 | 604 | { "TSVariableBuiltin", "@variable.builtin" }, 605 | 606 | -- { "TSField", "@field" }, 607 | 608 | -- { "TSNodeKey", c.cloud10 }, 609 | -- { "TSNodeUnmatched", c.cloud8:dark(0.2) }, 610 | }, 611 | }) 612 | end 613 | 614 | --[[ How this works: 615 | -- We create a data structure that is a list of 4 item tables 616 | -- { { group, fg, bg, styles }, ... } 617 | --]] 618 | local colorscheme = function(c) 619 | local vim_groups = { 620 | { "Normal", c.fg:dark(0.01), c.bg:light(0.01) }, 621 | 622 | -- Conceal 623 | { "Conceal", c.cloud3:light() }, 624 | 625 | { "VertSplit", c.cloud0 }, 626 | 627 | { "Function", c.cloud8, c.none, s.bold }, 628 | 629 | { "Error", c.cloud9, c.none, s.bold }, 630 | { "ErrorMsg", c.cloud1:dark():saturate(0.1), c.cloud1:dark(0.7):saturate(0.1):dark(0.05) }, 631 | 632 | { 633 | "WarningMsg", 634 | c.cloud11, 635 | -- c.cloud12:dark(0.3) 636 | }, 637 | { "Exception", c.cloud9 }, 638 | 639 | { "Boolean", c.cloud2:dark() }, 640 | { "Character", c.cloud14 }, 641 | { "Comment", c.cloud14:desaturate_to(0.2):lighten_to(0.5) }, 642 | { "Conditional", c.cloud10 }, 643 | { "Constant", c.cloud4 }, 644 | 645 | { "Float", c.cloud4 }, 646 | 647 | { "NormalFloat", c.cloud6:desaturate_to(0.8), c.cloud0:lighten_to(0.05):desaturate_to(0.0) }, 648 | 649 | -- Search 650 | { "IncSearch", c.cloud10:light(), c.cloud10:dark(0.5), s.italic }, 651 | { "Search", c.none, c.cloud10:dark(0.4):desaturate_to(0.1), s.bold }, 652 | 653 | -- Numbers 654 | { "Number", c.cloud4 }, 655 | 656 | { "Define", c.cloud10 }, 657 | 658 | { "Delimiter", c.cloud3:dark():dark():saturate(0.1) }, 659 | 660 | { "Directory", c.cloud4 }, 661 | 662 | { "Function", c.cloud8 }, 663 | 664 | -- Folds 665 | { "Folded", c.cloud3:dark(0.3) }, 666 | { "FoldColumn", c.cloud3:light() }, 667 | 668 | -- Diff 669 | { "DiffAdd", c.none, c.cloud10 }, 670 | { "DiffChange", c.none, c.cloud12 }, 671 | { "DiffDelete", c.none, c.cloud9 }, 672 | { "DiffText", c.none, c.cloud3 }, 673 | 674 | { "Identifier", c.cloud14 }, 675 | { "Structure", c.cloud10 }, 676 | 677 | { "Include", c.cloud10 }, 678 | 679 | { "Keyword", c.cloud4, c.none, s.italic }, 680 | 681 | { "Label", c.cloud10, c.none, s.italic }, 682 | 683 | { "Operator", c.cloud3:lighten_to(0.4):desaturate(0.1) }, 684 | 685 | { "PreProc", c.cloud10 }, 686 | 687 | { "Repeat", c.cloud12:dark() }, 688 | 689 | { "Statement", c.cloud10 }, 690 | { "StorageClass", c.cloud10 }, 691 | { "String", c.cloud14 }, 692 | { "Tag", c.cloud4 }, 693 | 694 | { "Title", c.cloud4, c.none }, 695 | 696 | { "Quote", c.cloud3:lighten_to(0.4):desaturate(0.1) }, 697 | 698 | { "Todo", c.cloud13 }, 699 | 700 | { "Type", c.cloud10:light(), c.none, s.italic }, 701 | { "Typedef", c.cloud10 }, 702 | 703 | -- Side Column 704 | { "CursorColumn", c.cloud4:desaturate_to(0.1), c.none, s.NONE, "20" }, 705 | { "LineNr", c.cloud10:desaturate_to(0.05):lighten_to(0.3) }, 706 | { "CursorLineNr", c.cloud5 }, 707 | { "Line", c.cloud12 }, 708 | { "SignColumn", c.none }, 709 | 710 | { "ColorColumn", c.none, c.cloud4:desaturate_to(0.1):lighten_to(0.1) }, 711 | { "Cursor", c.cloud0, c.cloud4 }, 712 | { "CursorLine", c.none, c.cloud0 }, 713 | { "iCursor", c.cloud0, c.cloud4 }, 714 | 715 | { "EndOfBuffer", c.cloud3, c.none }, 716 | 717 | { "MatchParen", c.none, c.cloud13:dark() }, 718 | 719 | { "NonText", c.bg:light(0.1), c.none }, 720 | { "Whitespace", c.bg:light(0.1), c.none }, 721 | 722 | -- Popup Menu 723 | { "PMenu", c.cloud2:light(), c.cloud5:dark(0.3) }, 724 | { "PmenuSbar", c.cloud4, c.cloud0:dark() }, 725 | { "PMenuSel", c.none, c.cloud0:lighten_to(0.15) }, 726 | { "PmenuThumb", c.cloud8, c.cloud3 }, 727 | 728 | -- Special 729 | { "Special", c.cloud4 }, 730 | { "SpecialChar", c.cloud13 }, 731 | { "SpecialKey", c.cloud13 }, 732 | { "SpecialComment", c.cloud8 }, 733 | 734 | -- Spell 735 | { "SpellBad", c.cloud11, c.none, s.undercurl }, 736 | { "SpellCap", c.cloud13, c.none, s.undercurl }, 737 | { "SpellLocal", c.cloud5, c.none, s.undercurl }, 738 | { "SpellRare", c.cloud6, c.none, s.undercurl }, 739 | 740 | -- Statusline 741 | { "StatusLine", c.cloud10, c.cloud8:dark(0.2) }, 742 | { "StatusLineNC", c.cloud4, c.cloud8:dark(0.3) }, 743 | 744 | -- Tabline 745 | { "TabLine", c.cloud2, c.cloud0:dark() }, 746 | { "TabLineSel", c.cloud10:light(), c.cloud13, s.bold }, 747 | { "TabLineFill", c.cloud2, c.cloud0:dark() }, 748 | 749 | { "Question", c.cloud10, c.none, s.bold }, 750 | 751 | -- Visual 752 | -- possible foreground colors 753 | -- { "Visual", c.cloud4:lighten_to(0.8):desaturate_to(0.9), c.cloud6:lighten_to(0.15) }, 754 | -- { "VisualNOS", c.cloud4:lighten_to(0.8):desaturate_to(0.9), c.cloud6:lighten_to(0.15) }, 755 | 756 | { "Visual", c.none, c.cloud6:lighten_to(0.15) }, 757 | { "VisualNOS", c.none, c.cloud6:lighten_to(0.15) }, 758 | 759 | { "WildMenu", c.none, c.cloud4 }, 760 | 761 | { "WinSeparator", c.cloud12:lighten_to(0.2) }, 762 | } 763 | 764 | return merge({ 765 | vim_groups, 766 | lsp(c), 767 | lsp_semantic_tokens(), 768 | diagnostics(c), 769 | treesitter(c), 770 | markdown(c), 771 | vimscript(c), 772 | cmp(c), 773 | telescope(c), 774 | harpoon(c), 775 | symbols_outline(c), 776 | nvim_dap_virtual_text(c), 777 | nvim_dap_ui(c), 778 | diff(c), 779 | notify_plugin(c), 780 | llama(c), 781 | }) 782 | end 783 | 784 | local M = {} 785 | 786 | -- TODO: Simplify what happens at this stage if we are using nvim_set_hi 787 | -- we can define the styles, fg, bg and others by their name 788 | M.apply = function(c) 789 | -- local cmd = string.format("highlight %s guifg=%s guibg=%s gui=%s guisp=%s", c[1], c[2], c[3], c[4], c[5]) 790 | -- if c[6] then 791 | -- cmd = string.format("%s blend=%s", cmd, c[6]) 792 | -- end 793 | -- vim.cmd(cmd) 794 | local val = {} 795 | 796 | if c[2] ~= nil and c[2] ~= "none" then 797 | -- are we using a link or a color? 798 | -- links are discovered by being a string currently 799 | if type(c[2]) == "string" then 800 | val["link"] = c[2] 801 | else 802 | val["fg"] = c[2]:to_rgb() 803 | end 804 | end 805 | 806 | if c[3] ~= nil and c[3] ~= "none" then 807 | val["bg"] = c[3]:to_rgb() 808 | end 809 | 810 | if c[4] ~= nil and c[4] ~= "none" then 811 | val[c[4]] = true 812 | end 813 | 814 | if c[5] ~= nil and c[5] ~= "none" then 815 | if type(c[5]) ~= "string" then 816 | val["sp"] = c[5]:to_rgb() 817 | end 818 | end 819 | 820 | if c[6] ~= nil and c[6] ~= "none" then 821 | val["blend"] = c[6]:to_rgb() 822 | end 823 | 824 | for k, v in pairs(val) do 825 | if type(v) == "string" and #v > 7 then 826 | val[k] = nil 827 | end 828 | end 829 | 830 | if c["link"] ~= nil and c["link"] ~= "none" then 831 | val["link"] = c["link"] 832 | end 833 | 834 | -- invalid data coming in 835 | if c[1] == nil then 836 | return 837 | end 838 | 839 | vim.api.nvim_set_hl(0, c[1], val) 840 | end 841 | 842 | -- Use this function in your config 843 | -- @param opts table 844 | M.use = function(opts) 845 | vim.g.termguicolors = true 846 | vim.g.colors_name = "boo" 847 | local colormap = M.setup(opts) 848 | 849 | for _, group in ipairs(colormap) do 850 | local check_none = function(none_resp) 851 | return function(x) 852 | return not x and none_resp or x 853 | end 854 | end 855 | 856 | local cNone = check_none("none") 857 | local sNone = check_none(s.none) 858 | 859 | if sNone(group[4]) == s.italic and opts.italic == false or vim.g.boo_colorscheme_italic == false then 860 | group[4] = s.none 861 | end 862 | 863 | M.apply({ group[1], cNone(group[2]), cNone(group[3]), sNone(group[4]), cNone(group[5]) }) 864 | end 865 | 866 | -- treesitter_migrate() 867 | end 868 | 869 | local find_theme_colors = function(opts) 870 | if opts ~= nil and opts["theme"] ~= nil then 871 | if opts["theme"] == "sunset_cloud" then 872 | return sunset_cloud 873 | end 874 | 875 | if opts["theme"] == "radioactive_waste" then 876 | return radioactive 877 | end 878 | 879 | if opts["theme"] == "forest_stream" then 880 | return forest_stream 881 | end 882 | 883 | if opts["theme"] == "crimson_moonlight" then 884 | return crimson_moonlight 885 | end 886 | 887 | if opts["theme"] == "default" then 888 | return default 889 | end 890 | 891 | if opts["theme"] == "boo_lora" then 892 | return boo_lora 893 | end 894 | end 895 | 896 | if vim.g.boo_colorscheme_theme == "sunset_cloud" then 897 | return sunset_cloud 898 | end 899 | 900 | if vim.g.boo_colorscheme_theme == "radioactive_waste" then 901 | return radioactive 902 | end 903 | 904 | if vim.g.boo_colorscheme_theme == "forest_stream" then 905 | return forest_stream 906 | end 907 | 908 | if vim.g.boo_colorscheme_theme == "crimson_moonlight" then 909 | return crimson_moonlight 910 | end 911 | 912 | if vim.g.boo_colorscheme_theme == "default" then 913 | return default 914 | end 915 | 916 | if vim.g.boo_colorscheme_theme == "boo_lora" then 917 | return boo_lora 918 | end 919 | 920 | return cloud 921 | end 922 | 923 | M.setup = function(opts) 924 | local cloud_map = find_theme_colors(opts)() 925 | 926 | local color_map = { none = "none" } 927 | 928 | -- cloud0 to cloud16 for all the available colors. 929 | for i, c in ipairs(cloud_map) do 930 | color_map["cloud" .. i - 1] = colors(c) 931 | end 932 | 933 | color_map["fg"] = colors("#e4dcec") 934 | color_map["bg"] = colors("#111113"):lighten_to(0.05) 935 | 936 | if opts ~= nil and opts["theme"] ~= nil and opts["theme"] == "sunset_cloud" then 937 | color_map["fg"] = colors("#ffffcf") 938 | color_map["bg"] = colors("#0e0f06") 939 | end 940 | 941 | if opts ~= nil and opts["theme"] ~= nil and opts["theme"] == "forest_stream" then 942 | color_map["fg"] = colors("#e3f5e7") 943 | color_map["bg"] = colors("#0b0c0b") 944 | end 945 | 946 | if opts ~= nil and opts["theme"] ~= nil and opts["theme"] == "crimson_moonlight" then 947 | color_map["fg"] = colors("#f9f2f3") 948 | color_map["bg"] = colors("#0f0e0e") 949 | end 950 | 951 | if opts ~= nil and opts["theme"] ~= nil and opts["theme"] == "default" then 952 | color_map["fg"] = colors("#c5c8c6") 953 | color_map["bg"] = colors("#1d1f21") 954 | end 955 | 956 | if opts ~= nil and opts["theme"] ~= nil and opts["theme"] == "boo_lora" then 957 | color_map["fg"] = colors("#e4dcec") 958 | color_map["bg"] = colors("#111113"):lighten_to(0.05) 959 | end 960 | 961 | return colorscheme(color_map) 962 | end 963 | 964 | return M 965 | -------------------------------------------------------------------------------- /lua/colors.lua: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------- 2 | -- Provides support for color manipulation in HSL color space. 3 | -- 4 | -- http://sputnik.freewisdom.org/lib/colors/ 5 | -- 6 | -- License: MIT/X 7 | -- 8 | -- (c) 2008 Yuri Takhteyev (yuri@freewisdom.org) * 9 | -- 10 | -- * rgb_to_hsl() implementation was contributed by Markus Fleck-Graffe. 11 | ----------------------------------------------------------------------------- 12 | 13 | local M = {} 14 | 15 | local Color = {} 16 | local Color_mt = { __metatable = {}, __index = Color } 17 | 18 | local rgb_string_to_hsl -- defined below 19 | 20 | ----------------------------------------------------------------------------- 21 | -- Instantiates a new "color". 22 | -- 23 | -- @param H hue (0-360) _or_ an RGB string ("#930219") 24 | -- @param S saturation (0.0-1.0) 25 | -- @param L lightness (0.0-1.0) 26 | -- @return an instance of Color 27 | ----------------------------------------------------------------------------- 28 | local function new(h, s, l) 29 | if type(h) == "string" and h:sub(1, 1) == "#" and h:len() == 7 then 30 | h, s, l = rgb_string_to_hsl(h) 31 | end 32 | assert(Color_mt) 33 | return setmetatable({ h = h, s = s, l = l }, Color_mt) 34 | end 35 | M.new = new 36 | 37 | M.from_hex = function(hex) 38 | local h, s, l = rgb_string_to_hsl(hex) 39 | 40 | return new(h, s, l) 41 | end 42 | 43 | ----------------------------------------------------------------------------- 44 | -- Converts an HSL triplet to RGB 45 | -- (see http://homepages.cwi.nl/~steven/css/hsl.html). 46 | -- 47 | -- @param H hue (0-360) 48 | -- @param S saturation (0.0-1.0) 49 | -- @param L lightness (0.0-1.0) 50 | -- @return an R, G, and B component of RGB 51 | ----------------------------------------------------------------------------- 52 | 53 | local function hsl_to_rgb(h, s, l) 54 | h = h / 360 55 | local q, p 56 | if l <= 0.5 then 57 | q = l * (s + 1) 58 | else 59 | q = l + s - l * s 60 | end 61 | p = l * 2 - q 62 | 63 | local function _h2rgb(m1, m2, m3) 64 | if m3 < 0 then 65 | m3 = m3 + 1 66 | end 67 | if m3 > 1 then 68 | m3 = m3 - 1 69 | end 70 | if m3 * 6 < 1 then 71 | return m1 + (m2 - m1) * m3 * 6 72 | elseif m3 * 2 < 1 then 73 | return m2 74 | elseif m3 * 3 < 2 then 75 | return m1 + (m2 - m1) * (2 / 3 - m3) * 6 76 | else 77 | return m1 78 | end 79 | end 80 | 81 | return _h2rgb(p, q, h + 1 / 3), _h2rgb(p, q, h), _h2rgb(p, q, h - 1 / 3) 82 | end 83 | M.hsl_to_rgb = hsl_to_rgb 84 | 85 | ----------------------------------------------------------------------------- 86 | -- Converts an RGB triplet to HSL. 87 | -- (see http://easyrgb.com) 88 | -- 89 | -- @param r red (0.0-1.0) 90 | -- @param g green (0.0-1.0) 91 | -- @param b blue (0.0-1.0) 92 | -- @return corresponding H, S and L components 93 | ----------------------------------------------------------------------------- 94 | 95 | local function rgb_to_hsl(r, g, b) 96 | --r, g, b = r/255, g/255, b/255 97 | local min = math.min(r, g, b) 98 | local max = math.max(r, g, b) 99 | local delta = max - min 100 | 101 | local h, s, l = 0, 0, ((min + max) / 2) 102 | 103 | if l > 0 and l < 0.5 then 104 | s = delta / (max + min) 105 | end 106 | if l >= 0.5 and l < 1 then 107 | s = delta / (2 - max - min) 108 | end 109 | 110 | if delta > 0 then 111 | if max == r and max ~= g then 112 | h = h + (g - b) / delta 113 | end 114 | if max == g and max ~= b then 115 | h = h + 2 + (b - r) / delta 116 | end 117 | if max == b and max ~= r then 118 | h = h + 4 + (r - g) / delta 119 | end 120 | h = h / 6 121 | end 122 | 123 | if h < 0 then 124 | h = h + 1 125 | end 126 | if h > 1 then 127 | h = h - 1 128 | end 129 | 130 | return h * 360, s, l 131 | end 132 | M.rgb_to_hsl = rgb_to_hsl 133 | 134 | -- already local, see at the bottom 135 | function rgb_string_to_hsl(rgb) 136 | return rgb_to_hsl( 137 | tonumber(rgb:sub(2, 3), 16) / 256, 138 | tonumber(rgb:sub(4, 5), 16) / 256, 139 | tonumber(rgb:sub(6, 7), 16) / 256 140 | ) 141 | end 142 | M.rgb_string_to_hsl = rgb_string_to_hsl 143 | 144 | ----------------------------------------------------------------------------- 145 | -- Converts the color to an RGB string. 146 | -- 147 | -- @return a 6-digit RGB representation of the color prefixed 148 | -- with "#" (suitable for inclusion in HTML) 149 | ----------------------------------------------------------------------------- 150 | 151 | function Color:to_rgb() 152 | -- local r, g, b = hsl_to_rgb(self.h, self.s, self.l) 153 | local rgb = { hsl_to_rgb(self.h, self.s, self.l) } 154 | local buffer = "#" 155 | for _, v in ipairs(rgb) do 156 | buffer = buffer .. string.format("%02x", math.floor(v * 256 + 0.5)) 157 | end 158 | return buffer 159 | end 160 | 161 | ----------------------------------------------------------------------------- 162 | -- Creates a new color with hue different by delta. 163 | -- 164 | -- @param delta a delta for hue. 165 | -- @return a new instance of Color. 166 | ----------------------------------------------------------------------------- 167 | function Color:hue_offset(delta) 168 | return new((self.h + delta) % 360, self.s, self.l) 169 | end 170 | 171 | ----------------------------------------------------------------------------- 172 | -- Creates a complementary color. 173 | -- 174 | -- @return a new instance of Color 175 | ----------------------------------------------------------------------------- 176 | function Color:complementary() 177 | return self:hue_offset(180) 178 | end 179 | 180 | ----------------------------------------------------------------------------- 181 | -- Creates two neighboring colors (by hue), offset by "angle". 182 | -- 183 | -- @param angle the difference in hue between this color and the 184 | -- neighbors 185 | -- @return two new instances of Color 186 | ----------------------------------------------------------------------------- 187 | function Color:neighbors(angle) 188 | angle = angle or 30 189 | return self:hue_offset(angle), self:hue_offset(360 - angle) 190 | end 191 | 192 | ----------------------------------------------------------------------------- 193 | -- Creates two new colors to make a triadic color scheme. 194 | -- 195 | -- @return two new instances of Color 196 | ----------------------------------------------------------------------------- 197 | function Color:triadic() 198 | return self:neighbors(120) 199 | end 200 | 201 | ----------------------------------------------------------------------------- 202 | -- Creates two new colors, offset by angle from this colors complementary. 203 | -- 204 | -- @param angle the difference in hue between the complementary and 205 | -- the returned colors 206 | -- @return two new instances of Color 207 | ----------------------------------------------------------------------------- 208 | function Color:split_complementary(angle) 209 | return self:neighbors(180 - (angle or 30)) 210 | end 211 | 212 | ----------------------------------------------------------------------------- 213 | -- Creates a new color with saturation set to a new value. 214 | -- 215 | -- @param saturation the new saturation value (0.0 - 1.0) 216 | -- @return a new instance of Color 217 | ----------------------------------------------------------------------------- 218 | function Color:desaturate_to(saturation) 219 | return new(self.h, saturation, self.l) 220 | end 221 | 222 | ----------------------------------------------------------------------------- 223 | -- Creates a new color with saturation set to a old saturation times r. 224 | -- 225 | -- @param r the multiplier for the new saturation 226 | -- @return a new instance of Color 227 | ----------------------------------------------------------------------------- 228 | function Color:desaturate_by(r) 229 | return new(self.h, self.s * r, self.l) 230 | end 231 | 232 | function Color:saturate(r) 233 | return new(self.h, self.s + r, self.l) 234 | end 235 | 236 | function Color:desaturate(r) 237 | return new(self.h, self.s - r, self.l) 238 | end 239 | 240 | ----------------------------------------------------------------------------- 241 | -- Creates a new color with lightness set to a new value. 242 | -- 243 | -- @param lightness the new lightness value (0.0 - 1.0) 244 | -- @return a new instance of Color 245 | ----------------------------------------------------------------------------- 246 | function Color:lighten_to(lightness) 247 | return new(self.h, self.s, lightness) 248 | end 249 | 250 | ----------------------------------------------------------------------------- 251 | -- Creates a new color with lightness set to a old lightness times r. 252 | -- 253 | -- @param r the multiplier for the new lightness 254 | -- @return a new instance of Color 255 | ----------------------------------------------------------------------------- 256 | function Color:lighten_by(r) 257 | return new(self.h, self.s, self.l * r) 258 | end 259 | 260 | function Color:dark(r) 261 | r = r or 0 262 | return new(self.h, self.s, self.l - r) 263 | end 264 | 265 | function Color:light(r) 266 | r = r or 0 267 | return new(self.h, self.s, self.l + r) 268 | end 269 | 270 | ----------------------------------------------------------------------------- 271 | -- Creates n variations of this color using supplied function and returns 272 | -- them as a table. 273 | -- 274 | -- @param f the function to create variations 275 | -- @param n the number of variations 276 | -- @return a table with n values containing the new colors 277 | ----------------------------------------------------------------------------- 278 | function Color:variations(f, n) 279 | n = n or 5 280 | local results = {} 281 | for i = 1, n do 282 | table.insert(results, f(self, i, n)) 283 | end 284 | return results 285 | end 286 | 287 | ----------------------------------------------------------------------------- 288 | -- Creates n tints of this color and returns them as a table 289 | -- 290 | -- @param number the number of tints 291 | -- @return a table with n values containing the new colors 292 | ----------------------------------------------------------------------------- 293 | function Color:tints(number) 294 | local f = function(color, i, n) 295 | return color:lighten_to(color.L + (1 - color.L) / n * i) 296 | end 297 | return self:variations(f, number) 298 | end 299 | 300 | ----------------------------------------------------------------------------- 301 | -- Creates n shades of this color and returns them as a table 302 | -- 303 | -- @param number the number of shades 304 | -- @return a table with n values containing the new colors 305 | ----------------------------------------------------------------------------- 306 | function Color:shades(number) 307 | local f = function(color, i, n) 308 | return color:lighten_to(color.L - color.L / n * i) 309 | end 310 | return self:variations(f, number) 311 | end 312 | 313 | function Color:tint(r) 314 | return self:lighten_to(self.l + (1 - self.l) * r) 315 | end 316 | 317 | function Color:shade(r) 318 | return self:lighten_to(self.l - self.l * r) 319 | end 320 | 321 | Color_mt.__tostring = Color.to_rgb 322 | 323 | -- allow to use `colors(...)` instead of `colors.new(...)` 324 | setmetatable(M, { 325 | __call = function(_, ...) 326 | return new(...) 327 | end, 328 | }) 329 | 330 | return M 331 | -------------------------------------------------------------------------------- /lua/style.lua: -------------------------------------------------------------------------------- 1 | local styles = { 2 | none = "none", 3 | underline = "underline", 4 | undercurl = "undercurl", 5 | reverse = "reverse", 6 | inverse = "inverse", 7 | italic = "italic", 8 | standout = "standout", 9 | } 10 | 11 | return styles 12 | -------------------------------------------------------------------------------- /stylua.toml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockerBOO/boo-colorscheme-nvim/5700bbeb7ea32fe6df0b2dcfc5769b15fd4bfdda/stylua.toml -------------------------------------------------------------------------------- /tests/boo-colorscheme_spec.lua: -------------------------------------------------------------------------------- 1 | local cs = require("boo-colorscheme") 2 | 3 | describe("colorscheme", function() 4 | it("should not error", function() 5 | assert.has_no.errors(cs.setup) 6 | end) 7 | end) 8 | -------------------------------------------------------------------------------- /tests/minimal_init.vim: -------------------------------------------------------------------------------- 1 | 2 | set rtp=. 3 | runtime plugin/plenary.vim 4 | 5 | --------------------------------------------------------------------------------