<file_sep># vim-neon-dark
A dark theme for vim/neovim based on MattDMo's SublimeText [Neon-color-scheme](https://github.com/MattDMo/Neon-color-scheme).

Please note that this theme has slightly diverged from the parent theme over time as more and more specialized syntax groups were added to the original.

![neon-dark example with php and typescript](https://i.imgur.com/fTReWoj.png)

Includes improved syntax highlighting for the following languages using [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter):
- php
- phpdoc
- comment
- javascript
- typescript

Includes improved sytax  highlighting for PHP using [StanAngeloff/php.vim](https://github.com/StanAngeloff/php.vim) syntax groups. (If you're using regular vim or neovim without treesitter).

## Installation

#### Recommended

Use a plugin manager and vim should be able to use the colorscheme provided by
this repo (tested with [junegunn/vim-plug](https://github.com/junegunn/vim-plug)).

```vim
" you can select the version with the corresponding tag
Plug 'nonetallt/vim-neon-dark', { 'tag': '2.1.0' }
```

#### Manual

Copy the colorscheme file to your .vim/colors directory.

## Usage

Set the colorscheme in your `.vimrc` (vim) file or `init.vim` (neovim)

```vim
colorscheme neon-dark
```

Enable `termguicolors` if you're using a terminal that [supports the full palette](https://github.com/termstandard/colors).

```vim
set termguicolors
colorscheme neon-dark
```

## Versions

#### 2.1.0
- Add custom treesitter predicates (`none-of?` and `notmatch?`)
- Add treesitter support for comment
- Add syntax highlights for treesitter text groups: (`@text.todo`, `@text.note`, `@text.danger`, `@text.warning`)

#### 2.0.0

- Add treesitter support for php
- Add treesitter support for phpdoc
- Add treesitter support for javascript
- Add treesitter support for typescript
- Remove ctrlp.vim plugin specific highlights
- Remove `neon-dark-256`, it's now merged to `neon-dark`
- Remove discrepancies between terminal and gui colors

#### 1.0.0

The original release version.
<file_sep>#!/usr/bin/env php
<?php

if(! isset($argv[1])) {
    echo "Missing required argument 1: input";
    exit(1);
}

$filepath = $argv[1];

if(! file_exists($filepath)) {
    echo "Could not find file '$filepath'";
    exit(1);
}

function find256Color(string $hex) : int
{
    $termColors = require dirname(__DIR__) . '/php/256colors.php';
    $rgb = array_map(fn($hex2) => hexdec($hex2), str_split($hex, 2));
    $lowestDiff = PHP_INT_MAX;
    $lowestDiffNum = 0;

    foreach($termColors as $number => $color) {
        $diff = abs($rgb[0] - $color['r']) + abs($rgb[1] - $color['g']) + abs($rgb[2] - $color['b']);

        if($diff < $lowestDiff) {
            $lowestDiff = $diff;
            $lowestDiffNum = $number;
        }
    }

    return $lowestDiffNum;
}

function generateCtermColor(array $lines, string $pattern, string $selectorString) : string
{
    $content = '';
    $guiString = "gui$selectorString";
    $ctermString = "cterm$selectorString";

    foreach($lines as $line) {
        $result = preg_match($pattern, $line, $matches, PREG_OFFSET_CAPTURE);

        if($result !==1) {
            $content .= $line;
            continue;
        }

        [$guiMatch, $guiOffset] = $matches[$guiString];
        $ctermColor = find256Color(explode('#', $guiMatch)[1]);

        if(isset($matches[$ctermString])) {
            [$ctermMatch, $ctermOffset] = $matches[$ctermString];
            $line = substr_replace($line, "$ctermString=$ctermColor", $ctermOffset, strlen($ctermMatch));
        }
        else {
            $line = substr_replace($line, "$guiMatch $ctermString=$ctermColor", $guiOffset, -1);
        }

        $content .= $line;
    }

    return $content;
}

$fgPattern = '/(?<guifg>guifg=#[0-9a-fA-F]{6})(.+(?<ctermfg>ctermfg=[0-9]{1,3}))?/';
$bgPattern = '/(?<guibg>guibg=#[0-9a-fA-F]{6})(.+(?<ctermbg>ctermbg=[0-9]{1,3}))?/';
$fileContent = generateCtermColor(file($filepath), $fgPattern, 'fg');
$fileContent = generateCtermColor(array_map(fn($line) => $line . PHP_EOL, explode(PHP_EOL, $fileContent)), $bgPattern, 'bg');

file_put_contents($filepath, substr($fileContent, 0, -1));
exit(0);
<file_sep>local query = require "vim.treesitter.query"

local M = {}

local noneof = function(match, _, source, predicate)
    local node = match[predicate[2]]
    if not node then
        return false
    end
    local node_text = query.get_node_text(node, source)

    -- Since 'predicate' will not be used by callers of this function, use it
    -- to store a string set built from the list of words to check against.
    local string_set = predicate['string_set']
    if not string_set then
        string_set = {}
        for i = 3, #predicate do
            ---@diagnostic disable-next-line:no-unknown
            string_set[predicate[i]] = true
        end
        predicate['string_set'] = string_set
    end

    return not string_set[node_text]
end

local notmatch = (function()
    local magic_prefixes = { ['\\v'] = true, ['\\m'] = true, ['\\M'] = true, ['\\V'] = true }
    ---@private
    local function check_magic(str)
      if string.len(str) < 2 or magic_prefixes[string.sub(str, 1, 2)] then
        return str
      end
      return '\\v' .. str
    end

    local compiled_vim_regexes = setmetatable({}, {
      __index = function(t, pattern)
        local res = vim.regex(check_magic(pattern))
        rawset(t, pattern, res)
        return res
      end,
    })

    return function(match, _, source, pred)
      ---@cast match TSMatch
      local node = match[pred[2]]
      if not node then
        return false
      end
      ---@diagnostic disable-next-line no-unknown
      local regex = compiled_vim_regexes[pred[3]]
      return not regex:match_str(query.get_node_text(node, source))
    end
  end)()

function M.setup()
    query.add_predicate('none-of?', noneof, true)
    query.add_predicate('notmatch?', notmatch, true)
end

return M
