Add tree-sitter grammars for common languages I use.
This commit is contained in:
75
.gitmodules
vendored
75
.gitmodules
vendored
@@ -54,18 +54,87 @@
|
||||
path = libs/tree-sitter-bash
|
||||
url = https://github.com/tree-sitter/tree-sitter-bash.git
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-markdown"]
|
||||
path = libs/tree-sitter-markdown
|
||||
url = https://github.com/tree-sitter-grammars/tree-sitter-markdown
|
||||
[submodule "libs/tree-sitter-make"]
|
||||
path = libs/tree-sitter-make
|
||||
url = https://github.com/tree-sitter-grammars/tree-sitter-make
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-lua"]
|
||||
path = libs/tree-sitter-lua
|
||||
url = https://github.com/tree-sitter-grammars/tree-sitter-lua
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-fish"]
|
||||
path = libs/tree-sitter-fish
|
||||
url = https://github.com/ram02z/tree-sitter-fish
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-rust"]
|
||||
path = libs/tree-sitter-rust
|
||||
url = https://github.com/tree-sitter/tree-sitter-rust.git
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-nginx"]
|
||||
path = libs/tree-sitter-nginx
|
||||
url = https://gitlab.com/joncoole/tree-sitter-nginx
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-yaml"]
|
||||
path = libs/tree-sitter-yaml
|
||||
url = https://github.com/tree-sitter-grammars/tree-sitter-yaml.git
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-gdscript"]
|
||||
path = libs/tree-sitter-gdscript
|
||||
url = https://github.com/PrestonKnopp/tree-sitter-gdscript
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-ini"]
|
||||
path = libs/tree-sitter-ini
|
||||
url = https://github.com/justinmk/tree-sitter-ini
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-php"]
|
||||
path = libs/tree-sitter-php
|
||||
url = https://github.com/tree-sitter/tree-sitter-php
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-query"]
|
||||
path = libs/tree-sitter-query
|
||||
url = https://github.com/tree-sitter-grammars/tree-sitter-query
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-cabal"]
|
||||
path = libs/tree-sitter-cabal
|
||||
url = https://gitlab.com/magus/tree-sitter-cabal
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-go-mod"]
|
||||
path = libs/tree-sitter-go-mod
|
||||
url = https://github.com/camdencheek/tree-sitter-go-mod
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-gitattributes"]
|
||||
path = libs/tree-sitter-gitattributes
|
||||
url = https://github.com/tree-sitter-grammars/tree-sitter-gitattributes
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-gitignore"]
|
||||
path = libs/tree-sitter-gitignore
|
||||
url = https://github.com/shunsambongi/tree-sitter-gitignore
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-diff"]
|
||||
path = libs/tree-sitter-diff
|
||||
url = https://github.com/tree-sitter-grammars/tree-sitter-diff
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-regex"]
|
||||
path = libs/tree-sitter-regex
|
||||
url = https://github.com/tree-sitter/tree-sitter-regex
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-embedded-template"]
|
||||
path = libs/tree-sitter-embedded-template
|
||||
url = https://github.com/tree-sitter/tree-sitter-embedded-template
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-sql"]
|
||||
path = libs/tree-sitter-sql
|
||||
url = https://github.com/DerekStride/tree-sitter-sql.git
|
||||
ignore = dirty
|
||||
[submodule "libs/libs/tree-sitter-yaml"]
|
||||
path = libs/libs/tree-sitter-yaml
|
||||
url = https://github.com/tree-sitter-grammars/tree-sitter-yaml.git
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-toml"]
|
||||
path = libs/tree-sitter-toml
|
||||
url = https://github.com/tree-sitter-grammars/tree-sitter-toml.git
|
||||
ignore = dirty
|
||||
[submodule "libs/tree-sitter-markdown"]
|
||||
path = libs/tree-sitter-markdown
|
||||
url = https://github.com/tree-sitter-grammars/tree-sitter-markdown.git
|
||||
ignore = dirty
|
||||
|
||||
20
Makefile
20
Makefile
@@ -31,15 +31,35 @@ UNICODE_OBJ_DEBUG := $(patsubst libs/unicode_width/%.c,$(OBJ_DIR)/debug/unicode_
|
||||
UNICODE_OBJ_RELEASE := $(patsubst libs/unicode_width/%.c,$(OBJ_DIR)/release/unicode_width/%.o,$(UNICODE_SRC))
|
||||
|
||||
TREE_SITTER_LIBS := $(wildcard libs/tree-sitter-*/libtree-sitter*.a)
|
||||
|
||||
PHP_LIB := libs/tree-sitter-php/php/libtree-sitter-php.a
|
||||
|
||||
FISH_OBJ_PARSER := libs/tree-sitter-fish/build/Release/obj.target/tree_sitter_fish_binding/src/parser.o
|
||||
FISH_OBJ_SCANNER := libs/tree-sitter-fish/build/Release/obj.target/tree_sitter_fish_binding/src/scanner.o
|
||||
|
||||
NGINX_OBJ_PARSER := libs/tree-sitter-nginx/build/Release/obj.target/tree_sitter_nginx_binding/src/parser.o
|
||||
|
||||
CABAL_OBJ_PARSER := libs/tree-sitter-cabal/build/Release/obj.target/tree_sitter_cabal_binding/src/parser.o
|
||||
CABAL_OBJ_SCANNER := libs/tree-sitter-cabal/src/scanner.o
|
||||
|
||||
GITIGNORE_OBJ_PARSER := libs/tree-sitter-gitignore/build/Release/obj.target/tree_sitter_ignore_binding/src/parser.o
|
||||
|
||||
MD_OBJ_PARSER := libs/tree-sitter-markdown/build/Release/obj.target/tree_sitter_markdown_binding/tree-sitter-markdown/src/parser.o
|
||||
MD_OBJ_SCANNER := libs/tree-sitter-markdown/build/Release/obj.target/tree_sitter_markdown_binding/tree-sitter-markdown/src/scanner.o
|
||||
|
||||
LIBS := \
|
||||
libs/libgrapheme/libgrapheme.a \
|
||||
libs/tree-sitter/libtree-sitter.a \
|
||||
$(TREE_SITTER_LIBS) \
|
||||
$(PHP_LIB) \
|
||||
$(NGINX_OBJ_PARSER) \
|
||||
$(GITIGNORE_OBJ_PARSER) \
|
||||
$(FISH_OBJ_PARSER) \
|
||||
$(CABAL_OBJ_PARSER) \
|
||||
$(CABAL_OBJ_SCANNER) \
|
||||
$(FISH_OBJ_SCANNER) \
|
||||
$(MD_OBJ_PARSER) \
|
||||
$(MD_OBJ_SCANNER) \
|
||||
-lpcre2-8 -lmagic
|
||||
|
||||
SRC := $(wildcard $(SRC_DIR)/*.cc)
|
||||
|
||||
@@ -6,6 +6,7 @@ A TUI IDE.
|
||||
|
||||
# TODO
|
||||
|
||||
- [ ] Get all tree-sitter grammars needed and write down their scm files.
|
||||
- [ ] Add support for LSP & autocomplete / snippets.
|
||||
- First research
|
||||
- `textDocument/documentHighlight` - for highlighting stuff (probably tree-sitter is enough)
|
||||
|
||||
@@ -223,7 +223,8 @@ void apply_edit(std::vector<Span> &spans, uint32_t x, int64_t y);
|
||||
void apply_hook_insertion(Editor *editor, uint32_t line, uint32_t rows);
|
||||
void apply_hook_deletion(Editor *editor, uint32_t removal_start,
|
||||
uint32_t removal_end);
|
||||
Editor *new_editor(const char *filename, Coord position, Coord size);
|
||||
Editor *new_editor(const char *filename_arg, Coord position, Coord size);
|
||||
void save_file(Editor *editor);
|
||||
void free_editor(Editor *editor);
|
||||
void render_editor(Editor *editor);
|
||||
void fold(Editor *editor, uint32_t start_line, uint32_t end_line);
|
||||
|
||||
111
include/maps.h
111
include/maps.h
@@ -4,7 +4,22 @@
|
||||
#include "./lsp.h"
|
||||
#include "./pch.h"
|
||||
#include "./ts_def.h"
|
||||
#include <unordered_map>
|
||||
|
||||
static const std::unordered_map<uint8_t, LSP> kLsps = {
|
||||
{1,
|
||||
{"clangd",
|
||||
{
|
||||
"clangd",
|
||||
"--background-index",
|
||||
"--clang-tidy",
|
||||
"--completion-style=detailed",
|
||||
"--header-insertion=never",
|
||||
"--pch-storage=memory",
|
||||
"--limit-results=50",
|
||||
"--log=error",
|
||||
nullptr,
|
||||
}}},
|
||||
};
|
||||
|
||||
static const std::unordered_map<std::string, Language> kLanguages = {
|
||||
{"bash", {"bash", LANG(bash)}},
|
||||
@@ -22,29 +37,67 @@ static const std::unordered_map<std::string, Language> kLanguages = {
|
||||
{"make", {"make", LANG(make)}},
|
||||
{"python", {"python", LANG(python)}},
|
||||
{"ruby", {"ruby", LANG(ruby)}},
|
||||
};
|
||||
|
||||
static const std::unordered_map<uint8_t, LSP> kLsps = {
|
||||
{1,
|
||||
{"clangd",
|
||||
{
|
||||
"clangd",
|
||||
"--background-index",
|
||||
"--clang-tidy",
|
||||
"--completion-style=detailed",
|
||||
"--header-insertion=iwyu",
|
||||
"--log=error",
|
||||
nullptr,
|
||||
}}},
|
||||
{"diff", {"diff", LANG(diff)}},
|
||||
{"embedded_template", {"embedded_template", LANG(embedded_template)}},
|
||||
{"gdscript", {"gdscript", LANG(gdscript)}},
|
||||
{"gitattributes", {"gitattributes", LANG(gitattributes)}},
|
||||
{"gitignore", {"gitignore", LANG(gitignore)}},
|
||||
{"gomod", {"gomod", LANG(gomod)}},
|
||||
{"ini", {"ini", LANG(ini)}},
|
||||
{"markdown", {"markdown", LANG(markdown)}},
|
||||
{"nginx", {"nginx", LANG(nginx)}},
|
||||
{"php", {"php", LANG(php)}},
|
||||
{"query", {"query", LANG(query)}},
|
||||
{"regex", {"regex", LANG(regex)}},
|
||||
{"sql", {"sql", LANG(sql)}},
|
||||
{"toml", {"toml", LANG(toml)}},
|
||||
{"yaml", {"yaml", LANG(yaml)}},
|
||||
{"cabal", {"cabal", LANG(cabal)}},
|
||||
};
|
||||
|
||||
static const std::unordered_map<std::string, std::string> kExtToLang = {
|
||||
{"sh", "bash"}, {"bash", "bash"}, {"c", "c"}, {"cpp", "cpp"},
|
||||
{"cxx", "cpp"}, {"cc", "cpp"}, {"hpp", "h"}, {"hh", "h"},
|
||||
{"hxx", "h"}, {"h", "h"}, {"css", "css"}, {"fish", "fish"},
|
||||
{"go", "go"}, {"hs", "haskell"}, {"html", "html"}, {"htm", "html"},
|
||||
{"js", "javascript"}, {"json", "json"}, {"lua", "lua"}, {"mk", "make"},
|
||||
{"makefile", "make"}, {"py", "python"}, {"rb", "ruby"},
|
||||
{"sh", "bash"},
|
||||
{"bash", "bash"},
|
||||
{"c", "c"},
|
||||
{"cpp", "cpp"},
|
||||
{"cxx", "cpp"},
|
||||
{"cc", "cpp"},
|
||||
{"hpp", "h"},
|
||||
{"hh", "h"},
|
||||
{"hxx", "h"},
|
||||
{"h", "h"},
|
||||
{"css", "css"},
|
||||
{"fish", "fish"},
|
||||
{"go", "go"},
|
||||
{"hs", "haskell"},
|
||||
{"html", "html"},
|
||||
{"htm", "html"},
|
||||
{"js", "javascript"},
|
||||
{"json", "json"},
|
||||
{"lua", "lua"},
|
||||
{"mk", "make"},
|
||||
{"makefile", "make"},
|
||||
{"py", "python"},
|
||||
{"rb", "ruby"},
|
||||
{"diff", "diff"},
|
||||
{"erb", "embedded_template"},
|
||||
{"etlua", "embedded_template"},
|
||||
{"gd", "gdscript"},
|
||||
{"gitattributes", "gitattributes"},
|
||||
{"gitignore", "gitignore"},
|
||||
{"mod", "gomod"},
|
||||
{"ini", "ini"},
|
||||
{"md", "markdown"},
|
||||
{"markdown", "markdown"},
|
||||
{"conf", "nginx"},
|
||||
{"php", "php"},
|
||||
{"scm", "query"},
|
||||
{"regex", "regex"},
|
||||
{"sql", "sql"},
|
||||
{"toml", "toml"},
|
||||
{"yaml", "yaml"},
|
||||
{"yml", "yaml"},
|
||||
{"cabal", "cabal"},
|
||||
};
|
||||
|
||||
static const std::unordered_map<std::string, std::string> kMimeToLang = {
|
||||
@@ -60,6 +113,22 @@ static const std::unordered_map<std::string, std::string> kMimeToLang = {
|
||||
{"text/x-go", "go"},
|
||||
{"text/x-haskell", "haskell"},
|
||||
{"text/x-lua", "lua"},
|
||||
{"text/x-diff", "diff"},
|
||||
{"text/x-embedded-template", "embedded_template"},
|
||||
{"text/x-gdscript", "gdscript"},
|
||||
{"text/x-gitattributes", "gitattributes"},
|
||||
{"text/x-gitignore", "gitignore"},
|
||||
{"text/x-gomod", "gomod"},
|
||||
{"text/x-ini", "ini"},
|
||||
{"text/markdown", "markdown"},
|
||||
{"text/x-nginx-conf", "nginx"},
|
||||
{"application/x-php", "php"},
|
||||
{"text/x-tree-sitter-query", "query"},
|
||||
{"text/x-regex", "regex"},
|
||||
{"text/x-sql", "sql"},
|
||||
{"text/x-toml", "toml"},
|
||||
{"text/x-yaml", "yaml"},
|
||||
{"text/x-cabal", "cabal"},
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "./pch.h"
|
||||
|
||||
#define LANG(name) tree_sitter_##name
|
||||
#define TS_DEF(name) extern "C" const TSLanguage *LANG(name)();
|
||||
#define TS_DEF(name) extern "C" const TSLanguage *LANG(name)()
|
||||
|
||||
struct Language {
|
||||
std::string name;
|
||||
@@ -12,27 +12,36 @@ struct Language {
|
||||
uint8_t lsp_id = 0;
|
||||
};
|
||||
|
||||
TS_DEF(bash)
|
||||
TS_DEF(c)
|
||||
TS_DEF(cpp)
|
||||
TS_DEF(css)
|
||||
TS_DEF(fish)
|
||||
TS_DEF(go)
|
||||
TS_DEF(haskell)
|
||||
TS_DEF(html)
|
||||
TS_DEF(javascript)
|
||||
TS_DEF(json)
|
||||
TS_DEF(lua)
|
||||
TS_DEF(make)
|
||||
TS_DEF(python)
|
||||
TS_DEF(ruby)
|
||||
TS_DEF(rust)
|
||||
|
||||
// TO ADD
|
||||
// sql
|
||||
// wasm
|
||||
// conf
|
||||
// yaml, toml
|
||||
// godot
|
||||
TS_DEF(bash);
|
||||
TS_DEF(c);
|
||||
TS_DEF(cpp);
|
||||
TS_DEF(css);
|
||||
TS_DEF(fish);
|
||||
TS_DEF(go);
|
||||
TS_DEF(haskell);
|
||||
TS_DEF(html);
|
||||
TS_DEF(javascript);
|
||||
TS_DEF(json);
|
||||
TS_DEF(lua);
|
||||
TS_DEF(make);
|
||||
TS_DEF(python);
|
||||
TS_DEF(ruby);
|
||||
TS_DEF(rust);
|
||||
TS_DEF(diff);
|
||||
TS_DEF(embedded_template);
|
||||
TS_DEF(gdscript);
|
||||
TS_DEF(gitattributes);
|
||||
TS_DEF(gitignore);
|
||||
TS_DEF(gomod);
|
||||
TS_DEF(ini);
|
||||
TS_DEF(markdown);
|
||||
TS_DEF(nginx);
|
||||
TS_DEF(php);
|
||||
TS_DEF(query);
|
||||
TS_DEF(regex);
|
||||
TS_DEF(sql);
|
||||
TS_DEF(toml);
|
||||
TS_DEF(yaml);
|
||||
TS_DEF(cabal);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -52,6 +52,7 @@ struct Coord {
|
||||
bool operator>=(const Coord &other) const { return !(*this < other); }
|
||||
};
|
||||
|
||||
std::string path_abs(const std::string &path_str);
|
||||
std::string path_to_file_uri(const std::string &path_str);
|
||||
int display_width(const char *str, size_t len);
|
||||
uint32_t get_visual_col_from_bytes(const char *line, uint32_t len,
|
||||
|
||||
1
libs/tree-sitter-cabal
Submodule
1
libs/tree-sitter-cabal
Submodule
Submodule libs/tree-sitter-cabal added at d1105d9ed6
1
libs/tree-sitter-diff
Submodule
1
libs/tree-sitter-diff
Submodule
Submodule libs/tree-sitter-diff added at 2520c3f934
1
libs/tree-sitter-embedded-template
Submodule
1
libs/tree-sitter-embedded-template
Submodule
Submodule libs/tree-sitter-embedded-template added at 3499d85f0a
1
libs/tree-sitter-gdscript
Submodule
1
libs/tree-sitter-gdscript
Submodule
Submodule libs/tree-sitter-gdscript added at 89e66b6bdc
1
libs/tree-sitter-gitattributes
Submodule
1
libs/tree-sitter-gitattributes
Submodule
Submodule libs/tree-sitter-gitattributes added at 1b7af09d45
1
libs/tree-sitter-gitignore
Submodule
1
libs/tree-sitter-gitignore
Submodule
Submodule libs/tree-sitter-gitignore added at f4685bf11a
1
libs/tree-sitter-go-mod
Submodule
1
libs/tree-sitter-go-mod
Submodule
Submodule libs/tree-sitter-go-mod added at 2e88687057
1
libs/tree-sitter-ini
Submodule
1
libs/tree-sitter-ini
Submodule
Submodule libs/tree-sitter-ini added at e4018b5176
1
libs/tree-sitter-markdown
Submodule
1
libs/tree-sitter-markdown
Submodule
Submodule libs/tree-sitter-markdown added at 2dfd57f547
1
libs/tree-sitter-nginx
Submodule
1
libs/tree-sitter-nginx
Submodule
Submodule libs/tree-sitter-nginx added at f6d13cf628
1
libs/tree-sitter-php
Submodule
1
libs/tree-sitter-php
Submodule
Submodule libs/tree-sitter-php added at 7d07b41ce2
1
libs/tree-sitter-query
Submodule
1
libs/tree-sitter-query
Submodule
Submodule libs/tree-sitter-query added at a4e379d4a4
1
libs/tree-sitter-regex
Submodule
1
libs/tree-sitter-regex
Submodule
Submodule libs/tree-sitter-regex added at b2ac15e27f
1
libs/tree-sitter-sql
Submodule
1
libs/tree-sitter-sql
Submodule
Submodule libs/tree-sitter-sql added at 2d5dcd16f9
1
libs/tree-sitter-toml
Submodule
1
libs/tree-sitter-toml
Submodule
Submodule libs/tree-sitter-toml added at 64b56832c2
1
libs/tree-sitter-yaml
Submodule
1
libs/tree-sitter-yaml
Submodule
Submodule libs/tree-sitter-yaml added at 7708026449
@@ -6,12 +6,13 @@ extern "C" {
|
||||
#include "../include/main.h"
|
||||
#include "../include/utils.h"
|
||||
|
||||
Editor *new_editor(const char *filename, Coord position, Coord size) {
|
||||
Editor *new_editor(const char *filename_arg, Coord position, Coord size) {
|
||||
Editor *editor = new Editor();
|
||||
if (!editor)
|
||||
return nullptr;
|
||||
uint32_t len = 0;
|
||||
char *str = load_file(filename, &len);
|
||||
std::string filename = path_abs(filename_arg);
|
||||
char *str = load_file(filename.c_str(), &len);
|
||||
if (!str) {
|
||||
free_editor(editor);
|
||||
return nullptr;
|
||||
@@ -23,7 +24,7 @@ Editor *new_editor(const char *filename, Coord position, Coord size) {
|
||||
editor->cursor_preffered = UINT32_MAX;
|
||||
editor->root = load(str, len, optimal_chunk_size(len));
|
||||
free(str);
|
||||
Language language = language_for_file(filename);
|
||||
Language language = language_for_file(filename.c_str());
|
||||
if (language.name != "unknown" && len <= (1024 * 128)) {
|
||||
editor->ts.parser = ts_parser_new();
|
||||
editor->ts.language = language.fn();
|
||||
@@ -57,6 +58,17 @@ void free_editor(Editor *editor) {
|
||||
delete editor;
|
||||
}
|
||||
|
||||
void save_file(Editor *editor) {
|
||||
if (!editor || !editor->root)
|
||||
return;
|
||||
char *str = read(editor->root, 0, editor->root->char_count);
|
||||
if (!str)
|
||||
return;
|
||||
std::ofstream out(editor->filename);
|
||||
out.write(str, editor->root->char_count);
|
||||
free(str);
|
||||
}
|
||||
|
||||
void render_editor(Editor *editor) {
|
||||
uint32_t sel_start = 0, sel_end = 0;
|
||||
uint32_t numlen =
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "../include/main.h"
|
||||
#include "../include/ts.h"
|
||||
#include <cstdint>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
void handle_editor_event(Editor *editor, KeyEvent event) {
|
||||
static std::chrono::steady_clock::time_point last_click_time =
|
||||
@@ -294,6 +295,9 @@ void handle_editor_event(Editor *editor, KeyEvent event) {
|
||||
case ',':
|
||||
dedent_line(editor, editor->cursor.row);
|
||||
break;
|
||||
case CTRL('s'):
|
||||
save_file(editor);
|
||||
break;
|
||||
case 'p':
|
||||
uint32_t len;
|
||||
char *text = get_from_clipboard(&len);
|
||||
|
||||
@@ -21,11 +21,14 @@ static std::string percent_encode(const std::string &s) {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string path_to_file_uri(const std::string &path_str) {
|
||||
std::string path_abs(const std::string &path_str) {
|
||||
namespace fs = std::filesystem;
|
||||
fs::path p = fs::weakly_canonical(fs::absolute(fs::path(path_str)));
|
||||
std::string generic = p.generic_string();
|
||||
return "file://" + percent_encode(generic);
|
||||
return p.generic_string();
|
||||
}
|
||||
|
||||
std::string path_to_file_uri(const std::string &path_str) {
|
||||
return "file://" + percent_encode(path_abs(path_str));
|
||||
}
|
||||
|
||||
uint64_t fnv1a_64(const char *s, size_t len) {
|
||||
|
||||
Reference in New Issue
Block a user