XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
namespace XFESystem.Browser;

/// <summary>A necessary positive key in the subject compound, never a substitute for selector matching.</summary>
internal static class BrowserSelectorKey
{
    internal static (char Kind, string Value)? Find(string selector)
    {
        // Escapes, namespaces and non-ASCII identifiers stay on the general
        // path. In particular, a prefix of an escaped/Unicode name is no key.
        foreach (char c in selector) if (c == '\\' || c == '|' || c > 127) return null;
        int start = 0, brackets = 0, parentheses = 0;
        char quote = '\0';
        for (int i = 0; i < selector.Length; i++)
        {
            char c = selector[i];
            if (quote != '\0') { if (c == quote) quote = '\0'; continue; }
            if (c is '\'' or '"') { quote = c; continue; }
            if (c == '[') brackets++;
            else if (c == ']') brackets--;
            else if (brackets == 0 && c == '(') parentheses++;
            else if (brackets == 0 && c == ')') parentheses--;
            else if (brackets == 0 && parentheses == 0 && (char.IsWhiteSpace(c) || c is '>' or '+' or '~')) start = i + 1;
        }
        if (brackets != 0 || parentheses != 0 || quote != '\0') return null;
        string? tag = null, name = null;
        if (start < selector.Length && (char.IsAsciiLetter(selector[start]) || selector[start] is '_' or '-'))
        {
            int end = start;
            while (end < selector.Length && Identifier(selector[end])) end++;
            tag = selector[start..end];
        }
        for (int i = start; i < selector.Length; i++)
        {
            char c = selector[i];
            if (quote != '\0') { if (c == quote) quote = '\0'; continue; }
            if (c is '\'' or '"') { quote = c; continue; }
            if (c == '[') brackets++;
            else if (c == ']') brackets--;
            else if (brackets == 0 && c == '(') parentheses++;
            else if (brackets == 0 && c == ')') parentheses--;
            else if (brackets == 0 && parentheses == 0 && c is '#' or '.')
            {
                int end = i + 1;
                while (end < selector.Length && Identifier(selector[end])) end++;
                if (end == i + 1) return null;
                if (c == '#') return ('#', selector[(i + 1)..end]);
                name ??= selector[(i + 1)..end];
                i = end - 1;
            }
        }
        return name is not null ? ('.', name) : tag is not null ? ('t', tag) : null;
    }
    private static bool Identifier(char c) => char.IsAsciiLetterOrDigit(c) || c is '_' or '-';
}