diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..ed561c71 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,17 @@ +[target.x86_64-apple-darwin] +rustflags = [ + "-C", "link-arg=-undefined", + "-C", "link-arg=dynamic_lookup", +] + +[target.aarch64-apple-darwin] +rustflags = [ + "-C", "link-arg=-undefined", + "-C", "link-arg=dynamic_lookup", +] + +[target.x86_64-unknown-linux-musl] +rustflags = ["-C", "target-feature=-crt-static"] + +[target.aarch64-unknown-linux-musl] +rustflags = ["-C", "target-feature=-crt-static"] diff --git a/Cargo.lock b/Cargo.lock index 861af7fc..fc7d5aa7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + [[package]] name = "bincode" version = "1.3.3" @@ -33,32 +39,30 @@ dependencies = [ name = "blink-cmp-fuzzy" version = "0.1.0" dependencies = [ - "c-marshalling", "frizbee", - "generator", "heed", "lazy_static", - "libc", - "lua-marshalling", + "mlua", "regex", "serde", ] +[[package]] +name = "bstr" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" -[[package]] -name = "c-marshalling" -version = "0.2.0" -source = "git+https://github.com/distil/rust_lua_ffi#30820cdc9282c938dbf8e7bb0a1ea31cf56b25a6" -dependencies = [ - "libc", - "quick-error", -] - [[package]] name = "cc" version = "1.1.29" @@ -68,6 +72,12 @@ dependencies = [ "shlex", ] +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "crossbeam-queue" version = "0.3.11" @@ -83,27 +93,6 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" -[[package]] -name = "derive-c-marshalling-library" -version = "0.1.0" -source = "git+https://github.com/distil/rust_lua_ffi#30820cdc9282c938dbf8e7bb0a1ea31cf56b25a6" -dependencies = [ - "libc", - "quote 0.4.2", - "syn 0.12.15", -] - -[[package]] -name = "derive-lua-marshalling" -version = "0.2.0" -source = "git+https://github.com/distil/rust_lua_ffi#30820cdc9282c938dbf8e7bb0a1ea31cf56b25a6" -dependencies = [ - "derive-c-marshalling-library", - "libc", - "quote 0.4.2", - "syn 0.12.15", -] - [[package]] name = "doxygen-rs" version = "0.4.2" @@ -131,16 +120,6 @@ dependencies = [ "smith_waterman_macro", ] -[[package]] -name = "generator" -version = "2.0.0" -source = "git+https://github.com/distil/rust_lua_ffi#30820cdc9282c938dbf8e7bb0a1ea31cf56b25a6" -dependencies = [ - "parser", - "quote 0.4.2", - "syn 0.12.15", -] - [[package]] name = "heed" version = "0.20.5" @@ -219,21 +198,55 @@ dependencies = [ ] [[package]] -name = "lua-marshalling" -version = "0.3.0" -source = "git+https://github.com/distil/rust_lua_ffi#30820cdc9282c938dbf8e7bb0a1ea31cf56b25a6" +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mlua" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d111deb18a9c9bd33e1541309f4742523bfab01d276bfa9a27519f6de9c11dc7" dependencies = [ - "c-marshalling", - "derive-lua-marshalling", - "lazy_static", - "libc", + "bstr", + "mlua-sys", + "mlua_derive", + "num-traits", + "once_cell", + "rustc-hash", ] [[package]] -name = "memchr" -version = "2.7.4" +name = "mlua-sys" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "ebe026d6bd1583a9cf9080e189030ddaea7e6f5f0deb366a8e26f8a26c4135b8" +dependencies = [ + "cc", + "cfg-if", + "pkg-config", +] + +[[package]] +name = "mlua_derive" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09697a6cec88e7f58a02c7ab5c18c611c6907c8654613df9cc0192658a4fb859" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] [[package]] name = "once_cell" @@ -251,15 +264,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "parser" -version = "0.2.0" -source = "git+https://github.com/distil/rust_lua_ffi#30820cdc9282c938dbf8e7bb0a1ea31cf56b25a6" -dependencies = [ - "quote 0.4.2", - "syn 0.12.15", -] - [[package]] name = "percent-encoding" version = "2.3.1" @@ -294,8 +298,8 @@ checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" dependencies = [ "phf_generator", "phf_shared", - "proc-macro2 1.0.87", - "quote 1.0.37", + "proc-macro2", + "quote", "syn 2.0.79", ] @@ -309,13 +313,10 @@ dependencies = [ ] [[package]] -name = "proc-macro2" -version = "0.2.3" +name = "pkg-config" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" -dependencies = [ - "unicode-xid", -] +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "proc-macro2" @@ -326,28 +327,13 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quote" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" -dependencies = [ - "proc-macro2 0.2.3", -] - [[package]] name = "quote" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ - "proc-macro2 1.0.87", + "proc-macro2", ] [[package]] @@ -394,6 +380,12 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "ryu" version = "1.0.18" @@ -415,8 +407,8 @@ version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ - "proc-macro2 1.0.87", - "quote 1.0.37", + "proc-macro2", + "quote", "syn 2.0.79", ] @@ -449,30 +441,19 @@ name = "smith_waterman_macro" version = "0.1.0" source = "git+https://github.com/saghen/frizbee#d910bec53b867ce06702520c7e05f9862bf78dd9" dependencies = [ - "proc-macro2 1.0.87", - "quote 1.0.37", + "proc-macro2", + "quote", "syn 1.0.109", ] -[[package]] -name = "syn" -version = "0.12.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5" -dependencies = [ - "proc-macro2 0.2.3", - "quote 0.4.2", - "unicode-xid", -] - [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.87", - "quote 1.0.37", + "proc-macro2", + "quote", "unicode-ident", ] @@ -482,8 +463,8 @@ version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ - "proc-macro2 1.0.87", - "quote 1.0.37", + "proc-macro2", + "quote", "unicode-ident", ] @@ -532,12 +513,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - [[package]] name = "url" version = "2.5.2" diff --git a/Cargo.toml b/Cargo.toml index e98dc4ba..1ccf2f68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,18 +4,13 @@ version = "0.1.0" edition = "2021" [lib] -path = "lua/blink/cmp/fuzzy/ffi.rs" +path = "lua/blink/cmp/fuzzy/lib.rs" crate-type = ["cdylib"] [dependencies] -libc = "0.2.20" -c-marshalling = { git = "https://github.com/distil/rust_lua_ffi" } -lua-marshalling = { git = "https://github.com/distil/rust_lua_ffi" } regex = "1.10.5" lazy_static = "1.5.0" frizbee = { git = "https://github.com/saghen/frizbee" } serde = { version = "1.0.204", features = ["derive"] } heed = "0.20.3" - -[build-dependencies] -generator = { git = "https://github.com/distil/rust_lua_ffi" } +mlua = { version = "0.9.9", features = ["module", "luajit"] } diff --git a/README.md b/README.md index ef195fee..9993456e 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,6 @@ version = 'v0.*', -- OR build from source, requires nightly: https://rust-lang.github.io/rustup/concepts/channels.html#working-with-nightly-rust -- build = 'cargo build --release', - -- On musl libc based systems you need to add this flag - -- build = 'RUSTFLAGS="-C target-feature=-crt-static" cargo build --release', -- If you use nix, you can build from source using latest nightly rust with: -- build = 'nix run .#build-plugin', diff --git a/build-ffi-bindings.sh b/build-ffi-bindings.sh deleted file mode 100755 index cbaa412b..00000000 --- a/build-ffi-bindings.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env bash -set -e -cd "$(dirname "$(realpath "$0")")" - -# shellcheck disable=SC2155 -export LD_LIBRARY_PATH="$(pwd)/target/release" -export RUST_LUA_FFI_TYPE_PREFIX=blink_cmp_fuzzy - -cat < "$(pwd)/lua/blink/cmp/fuzzy/bootstrap.lua" -local ffi = require("ffi") - -ffi.cdef([[ - char *__lua_bootstrap(); - void __free_lua_bootstrap(char *); -]]) -local rust = ffi.load(arg[1]) - -local bootstrap = rust.__lua_bootstrap() -if bootstrap == nil then - error("lua_bootstrap failed") -end -ffi.gc(bootstrap, rust.__free_lua_bootstrap) -print(ffi.string(bootstrap)) -EOF - -luajit "$(pwd)/lua/blink/cmp/fuzzy/bootstrap.lua" blink_cmp_fuzzy > "$(pwd)/lua/blink/cmp/fuzzy/ffi.lua" -rm "$(pwd)/lua/blink/cmp/fuzzy/bootstrap.lua" - -# hack: super scuffed way of getting the shared lib extension -# and rewriting the ffi.lua file to point to the correct target dir - -echo " -local function get_shared_lib_extension() - local os = jit.os:lower() - if os == 'osx' or os == 'mac' then - return '.dylib' - elseif os == 'windows' then - return '.dll' - else - return '.so' - end -end - -$(cat "$(pwd)/lua/blink/cmp/fuzzy/ffi.lua") -" > "$(pwd)/lua/blink/cmp/fuzzy/ffi.lua" - -sed -i "s|local rust = ffi\.load('blink-cmp-fuzzy')|local ok, rust = pcall(function() return ffi.load(debug.getinfo(1).source:match('@?(.*/)') .. '../../../../target/release/libblink_cmp_fuzzy' .. get_shared_lib_extension()) end)\nif not ok then\n rust = ffi.load(debug.getinfo(1).source:match('@?(.*/)') .. '../../../../target/release/blink_cmp_fuzzy' .. get_shared_lib_extension())\nend|" "$(pwd)/lua/blink/cmp/fuzzy/ffi.lua" diff --git a/build.rs b/build.rs index 1123b319..38093773 100644 --- a/build.rs +++ b/build.rs @@ -1,27 +1,4 @@ -use std::env; -use std::fs::File; -use std::io::Write; -use std::path::Path; - fn main() { - let rust_output = Path::new(&env::var("OUT_DIR").unwrap()).join("ffi.rs"); - - let output = generator::generate( - &env::current_dir() - .unwrap() - .as_path() - .join("lua/blink/cmp/fuzzy/ffi.rs"), - "blink-cmp-fuzzy", - false, - ); - - File::create(rust_output.clone()) - .unwrap() - .write_all(output.as_bytes()) - .unwrap(); - // delete existing version.txt file created by downloader let _ = std::fs::remove_file("target/release/version.txt"); - - assert!(rust_output.exists()); } diff --git a/flake.nix b/flake.nix index 9bb9f3f8..ede60a96 100644 --- a/flake.nix +++ b/flake.nix @@ -50,8 +50,6 @@ cargoLock = { lockFile = ./Cargo.lock; outputHashes = { - "c-marshalling-0.2.0" = - "sha256-eL6nkZOtuLLQ0r31X7uroUUDYZsWOJ9KNXl4NCVNRuw="; "frizbee-0.1.0" = "sha256-zO2S282DVCjnALMXu3GxmAfjCXsPNUZ7+xgiqITfGmU="; }; diff --git a/lua/blink/cmp/fuzzy/download.lua b/lua/blink/cmp/fuzzy/download.lua index 99c56c95..2059c045 100644 --- a/lua/blink/cmp/fuzzy/download.lua +++ b/lua/blink/cmp/fuzzy/download.lua @@ -59,15 +59,13 @@ end --- @param cb fun(downloaded: boolean) function download.is_downloaded(cb) vim.uv.fs_stat(download.lib_path, function(err) - if not err then - cb(true) - else - -- If not found, check without 'lib' prefix - vim.uv.fs_stat( - string.gsub(download.lib_path, 'libblink_cmp_fuzzy', 'blink_cmp_fuzzy'), - function(error) cb(not error) end - ) - end + if not err then return cb(true) end + + -- If not found, check without 'lib' prefix + vim.uv.fs_stat( + string.gsub(download.lib_path, 'libblink_cmp_fuzzy', 'blink_cmp_fuzzy'), + function(error) cb(not error) end + ) end) end @@ -100,7 +98,7 @@ function download.from_github(tag, cb) .. system_triple .. download.get_lib_extension() - vim.system({ 'curl', '--create-dirs', '-Lo', download.lib_path, url }, {}, function(out) + vim.system({ 'curl', '--create-dirs', '-fLo', download.lib_path, url }, {}, function(out) if out.code ~= 0 then cb('Failed to download pre-build binaries: ' .. out.stderr) end cb() end) diff --git a/lua/blink/cmp/fuzzy/ffi.lua b/lua/blink/cmp/fuzzy/ffi.lua deleted file mode 100644 index 24f81fd3..00000000 --- a/lua/blink/cmp/fuzzy/ffi.lua +++ /dev/null @@ -1,424 +0,0 @@ - -local function get_shared_lib_extension() - local os = jit.os:lower() - if os == 'osx' or os == 'mac' then - return '.dylib' - elseif os == 'windows' then - return '.dll' - else - return '.so' - end -end - --- Code generated by Rust Lua interface. DO NOT EDIT. - - local ffi = require("ffi") - - ffi.cdef[[ - - - -typedef struct { - const char * *ptr; - size_t len; - size_t capacity; -} blink_cmp_fuzzy__Vec___string_ptr; -typedef struct { - const blink_cmp_fuzzy__Vec___string_ptr *ptr; -} blink_cmp_fuzzy__Option_Vec___string_ptr; - -typedef struct { - const int32_t *ptr; -} blink_cmp_fuzzy__Option_int32_t; - - - - typedef struct { - const int8_t use_frecency; - const blink_cmp_fuzzy__Option_Vec___string_ptr nearby_words; - const uint16_t min_score; - const size_t max_items; - const blink_cmp_fuzzy__Vec___string_ptr sorts; - } blink_cmp_fuzzy__FuzzyOptions; - - -typedef struct { - const uint32_t *ptr; - size_t len; - size_t capacity; -} blink_cmp_fuzzy__Vec_uint32_t; -typedef struct { - const char * *ptr; -} blink_cmp_fuzzy__Option___string_ptr; - - typedef struct { - const char * label; - const blink_cmp_fuzzy__Option___string_ptr sort_text; - const blink_cmp_fuzzy__Option___string_ptr filter_text; - const uint32_t kind; - const blink_cmp_fuzzy__Option_int32_t score_offset; - const char * source; - } blink_cmp_fuzzy__LspItem; - -typedef struct { - const int32_t *ptr; - size_t len; - size_t capacity; -} blink_cmp_fuzzy__Vec_int32_t; -int32_t init_db( - const char *, - int8_t*); -int32_t __gc_init_db( - int8_t); -int32_t destroy_db( - int8_t*); -int32_t __gc_destroy_db( - int8_t); -int32_t access( - const blink_cmp_fuzzy__LspItem*, - int8_t*); -int32_t __gc_access( - int8_t); -int32_t fuzzy( - const char *, - const blink_cmp_fuzzy__Vec___string_ptr*, - const blink_cmp_fuzzy__Vec_uint32_t*, - const blink_cmp_fuzzy__Vec_int32_t*, - const blink_cmp_fuzzy__Vec___string_ptr*, - const blink_cmp_fuzzy__FuzzyOptions*, - blink_cmp_fuzzy__Vec_uint32_t**); -int32_t __gc_fuzzy( - blink_cmp_fuzzy__Vec_uint32_t*); -int32_t get_words( - const char *, - blink_cmp_fuzzy__Vec___string_ptr**); -int32_t __gc_get_words( - blink_cmp_fuzzy__Vec___string_ptr*); - - ]] - - local ok, rust = pcall(function() return ffi.load(debug.getinfo(1).source:match('@?(.*/)') .. '../../../../target/release/libblink_cmp_fuzzy' .. get_shared_lib_extension()) end) -if not ok then - rust = ffi.load(debug.getinfo(1).source:match('@?(.*/)') .. '../../../../target/release/blink_cmp_fuzzy' .. get_shared_lib_extension()) -end - - local M = {} - - - -local __const_c_typename_int32_t = ffi.typeof("const int32_t[?]") -local __c_function_argument_int32_t = ffi.typeof("int32_t[?]") -local __c_mut_function_argument_int32_t = ffi.typeof("int32_t[?]") - - -local __const_c_typename___string_ptr = ffi.typeof("const char *[?]") -local __c_function_argument___string_ptr = ffi.typeof("const char *[?]") -local __c_mut_function_argument___string_ptr = ffi.typeof("char *[?]") - - -local __typename_Vec___string_ptr = ffi.metatype("blink_cmp_fuzzy__Vec___string_ptr", {}) -local __const_c_typename_Vec___string_ptr = ffi.typeof("const blink_cmp_fuzzy__Vec___string_ptr[?]") -local __c_function_argument_Vec___string_ptr = ffi.typeof("const blink_cmp_fuzzy__Vec___string_ptr*[?]") -local __c_mut_function_argument_Vec___string_ptr = ffi.typeof("blink_cmp_fuzzy__Vec___string_ptr*[?]") - - -local __typename_Option_Vec___string_ptr = ffi.metatype("blink_cmp_fuzzy__Option_Vec___string_ptr", {}) -local __const_c_typename_Option_Vec___string_ptr = ffi.typeof("const blink_cmp_fuzzy__Option_Vec___string_ptr[?]") -local __c_function_argument_Option_Vec___string_ptr = ffi.typeof("const blink_cmp_fuzzy__Option_Vec___string_ptr*[?]") -local __c_mut_function_argument_Option_Vec___string_ptr = ffi.typeof("blink_cmp_fuzzy__Option_Vec___string_ptr*[?]") - - -local __const_c_typename_size_t = ffi.typeof("const size_t[?]") -local __c_function_argument_size_t = ffi.typeof("size_t[?]") -local __c_mut_function_argument_size_t = ffi.typeof("size_t[?]") - - -local __typename_Option_int32_t = ffi.metatype("blink_cmp_fuzzy__Option_int32_t", {}) -local __const_c_typename_Option_int32_t = ffi.typeof("const blink_cmp_fuzzy__Option_int32_t[?]") -local __c_function_argument_Option_int32_t = ffi.typeof("const blink_cmp_fuzzy__Option_int32_t*[?]") -local __c_mut_function_argument_Option_int32_t = ffi.typeof("blink_cmp_fuzzy__Option_int32_t*[?]") - - -local __const_c_typename_bool = ffi.typeof("const int8_t[?]") -local __c_function_argument_bool = ffi.typeof("int8_t[?]") -local __c_mut_function_argument_bool = ffi.typeof("int8_t[?]") - - -local __const_c_typename_uint16_t = ffi.typeof("const uint16_t[?]") -local __c_function_argument_uint16_t = ffi.typeof("uint16_t[?]") -local __c_mut_function_argument_uint16_t = ffi.typeof("uint16_t[?]") - - -local __typename_FuzzyOptions = ffi.metatype("blink_cmp_fuzzy__FuzzyOptions", {}) -local __const_c_typename_FuzzyOptions = ffi.typeof("const blink_cmp_fuzzy__FuzzyOptions[?]") -local __c_function_argument_FuzzyOptions = ffi.typeof("const blink_cmp_fuzzy__FuzzyOptions*[?]") -local __c_mut_function_argument_FuzzyOptions = ffi.typeof("blink_cmp_fuzzy__FuzzyOptions*[?]") - - -local __const_c_typename_uint32_t = ffi.typeof("const uint32_t[?]") -local __c_function_argument_uint32_t = ffi.typeof("uint32_t[?]") -local __c_mut_function_argument_uint32_t = ffi.typeof("uint32_t[?]") - - -local __typename_Vec_uint32_t = ffi.metatype("blink_cmp_fuzzy__Vec_uint32_t", {}) -local __const_c_typename_Vec_uint32_t = ffi.typeof("const blink_cmp_fuzzy__Vec_uint32_t[?]") -local __c_function_argument_Vec_uint32_t = ffi.typeof("const blink_cmp_fuzzy__Vec_uint32_t*[?]") -local __c_mut_function_argument_Vec_uint32_t = ffi.typeof("blink_cmp_fuzzy__Vec_uint32_t*[?]") - - -local __typename_Option___string_ptr = ffi.metatype("blink_cmp_fuzzy__Option___string_ptr", {}) -local __const_c_typename_Option___string_ptr = ffi.typeof("const blink_cmp_fuzzy__Option___string_ptr[?]") -local __c_function_argument_Option___string_ptr = ffi.typeof("const blink_cmp_fuzzy__Option___string_ptr*[?]") -local __c_mut_function_argument_Option___string_ptr = ffi.typeof("blink_cmp_fuzzy__Option___string_ptr*[?]") - - -local __typename_LspItem = ffi.metatype("blink_cmp_fuzzy__LspItem", {}) -local __const_c_typename_LspItem = ffi.typeof("const blink_cmp_fuzzy__LspItem[?]") -local __c_function_argument_LspItem = ffi.typeof("const blink_cmp_fuzzy__LspItem*[?]") -local __c_mut_function_argument_LspItem = ffi.typeof("blink_cmp_fuzzy__LspItem*[?]") - - -local __typename_Vec_int32_t = ffi.metatype("blink_cmp_fuzzy__Vec_int32_t", {}) -local __const_c_typename_Vec_int32_t = ffi.typeof("const blink_cmp_fuzzy__Vec_int32_t[?]") -local __c_function_argument_Vec_int32_t = ffi.typeof("const blink_cmp_fuzzy__Vec_int32_t*[?]") -local __c_mut_function_argument_Vec_int32_t = ffi.typeof("blink_cmp_fuzzy__Vec_int32_t*[?]") - -function M.init_db( - db_path) - local __typeof = __c_mut_function_argument_bool - local __ret_ptr = __typeof(1, {}) - local status = rust.init_db( - (function(value) return value end)(db_path), - __ret_ptr - ) - if status ~= 0 then - error("init_db failed with status "..status) - end - local __ret = __ret_ptr[0] - - local f = function(value) return value ~= 0 end - return f(__ret) -end - -function M.destroy_db( - ) - local __typeof = __c_mut_function_argument_bool - local __ret_ptr = __typeof(1, {}) - local status = rust.destroy_db( - __ret_ptr - ) - if status ~= 0 then - error("destroy_db failed with status "..status) - end - local __ret = __ret_ptr[0] - - local f = function(value) return value ~= 0 end - return f(__ret) -end - -function M.access( - item) - local __typeof = __c_mut_function_argument_bool - local __ret_ptr = __typeof(1, {}) - local status = rust.access( - (function(value) - return __typename_LspItem( - (function(value) return value end)(value.label), - ( -function(value) - local f = function(value) - return __const_c_typename___string_ptr(1, { value }) -end - if value ~= nil then - return __typename_Option___string_ptr(f(value)) - else - return __typename_Option___string_ptr(nil) - end -end -)(value.sort_text), - ( -function(value) - local f = function(value) - return __const_c_typename___string_ptr(1, { value }) -end - if value ~= nil then - return __typename_Option___string_ptr(f(value)) - else - return __typename_Option___string_ptr(nil) - end -end -)(value.filter_text), - (function(value) return value end)(value.kind), - ( -function(value) - local f = function(value) - return __const_c_typename_int32_t(1, { value }) -end - if value ~= nil then - return __typename_Option_int32_t(f(value)) - else - return __typename_Option_int32_t(nil) - end -end -)(value.score_offset), - (function(value) return value end)(value.source) - ) - end)(item), - __ret_ptr - ) - if status ~= 0 then - error("access failed with status "..status) - end - local __ret = __ret_ptr[0] - - local f = function(value) return value ~= 0 end - return f(__ret) -end - -function M.fuzzy( - needle, - haystack_labels, - haystack_kinds, - haystack_score_offsets, - haystack_sources, - opts) - local __typeof = __c_mut_function_argument_Vec_uint32_t - local __ret_ptr = __typeof(1, {}) - local status = rust.fuzzy( - (function(value) return value end)(needle), - ( -function(value) - if type(value) == "string" then - return __typename_Vec___string_ptr(value, #value) - else - local f = function(value) - return __const_c_typename___string_ptr(#value, value) -end - return __typename_Vec___string_ptr(f(value), #value, 0) - end -end -)(haystack_labels), - ( -function(value) - if type(value) == "string" then - return __typename_Vec_uint32_t(value, #value) - else - local f = function(value) - return __const_c_typename_uint32_t(#value, value) -end - return __typename_Vec_uint32_t(f(value), #value, 0) - end -end -)(haystack_kinds), - ( -function(value) - if type(value) == "string" then - return __typename_Vec_int32_t(value, #value) - else - local f = function(value) - return __const_c_typename_int32_t(#value, value) -end - return __typename_Vec_int32_t(f(value), #value, 0) - end -end -)(haystack_score_offsets), - ( -function(value) - if type(value) == "string" then - return __typename_Vec___string_ptr(value, #value) - else - local f = function(value) - return __const_c_typename___string_ptr(#value, value) -end - return __typename_Vec___string_ptr(f(value), #value, 0) - end -end -)(haystack_sources), - (function(value) - return __typename_FuzzyOptions( - (function(value) return value and 1 or 0 end)(value.use_frecency), - ( -function(value) - local f = -function(value) - if type(value) == "string" then - return __typename_Vec___string_ptr(value, #value) - else - local f = function(value) - return __const_c_typename___string_ptr(#value, value) -end - return __typename_Vec___string_ptr(f(value), #value, 0) - end -end - - if value ~= nil then - return __typename_Option_Vec___string_ptr(f(value)) - else - return __typename_Option_Vec___string_ptr(nil) - end -end -)(value.nearby_words), - (function(value) return value end)(value.min_score), - (function(value) return value end)(value.max_items), - ( -function(value) - if type(value) == "string" then - return __typename_Vec___string_ptr(value, #value) - else - local f = function(value) - return __const_c_typename___string_ptr(#value, value) -end - return __typename_Vec___string_ptr(f(value), #value, 0) - end -end -)(value.sorts) - ) - end)(opts), - __ret_ptr - ) - if status ~= 0 then - error("fuzzy failed with status "..status) - end - local __ret = __ret_ptr[0] - ffi.gc(__ret, rust.__gc_fuzzy) - local f = function(value) - local ret = {} - local len = tonumber(value.len) - local f = function(value) return value end - for i = 1,len do - ret[i] = f(value.ptr[i - 1]) - end - return ret -end - return f(__ret) -end - -function M.get_words( - text) - local __typeof = __c_mut_function_argument_Vec___string_ptr - local __ret_ptr = __typeof(1, {}) - local status = rust.get_words( - (function(value) return value end)(text), - __ret_ptr - ) - if status ~= 0 then - error("get_words failed with status "..status) - end - local __ret = __ret_ptr[0] - ffi.gc(__ret, rust.__gc_get_words) - local f = function(value) - local ret = {} - local len = tonumber(value.len) - local f = ffi.string - for i = 1,len do - ret[i] = f(value.ptr[i - 1]) - end - return ret -end - return f(__ret) -end - - - return M - - diff --git a/lua/blink/cmp/fuzzy/ffi.rs b/lua/blink/cmp/fuzzy/ffi.rs deleted file mode 100644 index e684e298..00000000 --- a/lua/blink/cmp/fuzzy/ffi.rs +++ /dev/null @@ -1,83 +0,0 @@ -#![feature(test)] - -mod frecency; -mod fuzzy; - -pub mod extern_ffi { - use crate::frecency::FrecencyTracker; - use crate::fuzzy::{self, FuzzyOptions, LspItem}; - use lazy_static::lazy_static; - use regex::Regex; - use std::collections::HashSet; - use std::sync::RwLock; - - lazy_static! { - static ref REGEX: Regex = Regex::new(r"[A-Za-z][A-Za-z0-9_\\-]{2,32}").unwrap(); - static ref FRECENCY: RwLock> = RwLock::new(None); - } - - pub fn init_db(db_path: String) -> bool { - let mut frecency = FRECENCY.write().unwrap(); - if frecency.is_some() { - return false; - } - *frecency = Some(FrecencyTracker::new(&db_path)); - true - } - - pub fn destroy_db() -> bool { - // todo: there should be a way to get rid of old locks - // since a crash would result in a leak - let frecency = FRECENCY.write().unwrap(); - drop(frecency); - - let mut frecency = FRECENCY.write().unwrap(); - *frecency = None; - true - } - - pub fn access(item: LspItem) -> bool { - let mut frecency_handle = FRECENCY.write().unwrap(); - let frecency = frecency_handle.as_mut().unwrap(); - frecency.access(&item).unwrap(); - true - } - - pub fn fuzzy( - needle: String, - haystack_labels: Vec, - haystack_kinds: Vec, - haystack_score_offsets: Vec, - haystack_sources: Vec, - opts: FuzzyOptions, - ) -> Vec { - let mut frecency_handle = FRECENCY.write().unwrap(); - let frecency = frecency_handle.as_mut().unwrap(); - - let haystack = (0..haystack_labels.len()) - .map(|i| LspItem { - label: haystack_labels[i].clone(), - sort_text: None, - filter_text: None, - kind: haystack_kinds[i], - score_offset: Some(haystack_score_offsets[i]), - source: haystack_sources[i].clone(), - }) - .collect::>(); - fuzzy::fuzzy(needle, haystack, frecency, opts) - .into_iter() - .map(|i| i as u32) - .collect() - } - - pub fn get_words(text: String) -> Vec { - REGEX - .find_iter(&text) - .map(|m| m.as_str().to_string()) - .collect::>() - .into_iter() - .collect() - } -} - -include!(concat!(env!("OUT_DIR"), "/ffi.rs")); diff --git a/lua/blink/cmp/fuzzy/frecency.rs b/lua/blink/cmp/fuzzy/frecency.rs index 1c93c38e..11a6bcd0 100644 --- a/lua/blink/cmp/fuzzy/frecency.rs +++ b/lua/blink/cmp/fuzzy/frecency.rs @@ -1,6 +1,7 @@ use crate::fuzzy::LspItem; use heed::types::*; use heed::{Database, Env, EnvOpenOptions}; +use mlua::Result as LuaResult; use serde::{Deserialize, Serialize}; use std::fs; use std::time::{SystemTime, UNIX_EPOCH}; @@ -22,6 +23,7 @@ impl From<&LspItem> for CompletionItemKey { } } +#[derive(Debug)] pub struct FrecencyTracker { env: Env, db: Database, SerdeBincode>>, @@ -29,38 +31,68 @@ pub struct FrecencyTracker { } impl FrecencyTracker { - pub fn new(db_path: &str) -> Self { - fs::create_dir_all(db_path).unwrap(); - let env = unsafe { EnvOpenOptions::new().open(db_path).unwrap() }; - env.clear_stale_readers().unwrap(); + pub fn new(db_path: &str) -> LuaResult { + fs::create_dir_all(db_path).map_err(|err| { + mlua::Error::RuntimeError( + "Failed to create frecency database directory: ".to_string() + &err.to_string(), + ) + })?; + let env = unsafe { + EnvOpenOptions::new().open(db_path).map_err(|err| { + mlua::Error::RuntimeError( + "Failed to open frecency database: ".to_string() + &err.to_string(), + ) + })? + }; + env.clear_stale_readers().map_err(|err| { + mlua::Error::RuntimeError( + "Failed to clear stale readers for frecency database: ".to_string() + + &err.to_string(), + ) + })?; // we will open the default unnamed database - let mut wtxn = env.write_txn().unwrap(); - let db = env.create_database(&mut wtxn, None).unwrap(); + let mut wtxn = env.write_txn().map_err(|err| { + mlua::Error::RuntimeError( + "Failed to open write transaction for frecency database: ".to_string() + + &err.to_string(), + ) + })?; + let db = env.create_database(&mut wtxn, None).map_err(|err| { + mlua::Error::RuntimeError( + "Failed to create frecency database: ".to_string() + &err.to_string(), + ) + })?; let access_thresholds = [ - (1., 1000 * 60 * 2), // 2 minutes - (0.5, 1000 * 60 * 60), // 1 hour - (0.2, 1000 * 60 * 60 * 24), // 1 day - (0.1, 1000 * 60 * 60 * 24 * 7), // 1 week + (1., 1000 * 60 * 2), // 2 minutes + (0.2, 1000 * 60 * 60), // 1 hour + (0.1, 1000 * 60 * 60 * 24), // 1 day + (0.05, 1000 * 60 * 60 * 24 * 7), // 1 week ] .to_vec(); - FrecencyTracker { + Ok(FrecencyTracker { env: env.clone(), db, access_thresholds, - } + }) } - fn get_accesses(&self, item: &LspItem) -> Option> { - let rtxn = self - .env - .read_txn() - .expect("Failed to start read transaction"); + fn get_accesses(&self, item: &LspItem) -> LuaResult>> { + let rtxn = self.env.read_txn().map_err(|err| { + mlua::Error::RuntimeError( + "Failed to start read transaction for frecency database: ".to_string() + + &err.to_string(), + ) + })?; self.db .get(&rtxn, &CompletionItemKey::from(item)) - .expect("Failed to read from database") + .map_err(|err| { + mlua::Error::RuntimeError( + "Failed to read from frecency database: ".to_string() + &err.to_string(), + ) + }) } fn get_now(&self) -> u64 { @@ -70,18 +102,37 @@ impl FrecencyTracker { .as_secs() } - pub fn access(&mut self, item: &LspItem) -> Result<(), heed::Error> { - let mut wtxn = self.env.write_txn()?; - let mut accesses = self.get_accesses(item).unwrap_or_default(); + pub fn access(&mut self, item: &LspItem) -> LuaResult<()> { + let mut wtxn = self.env.write_txn().map_err(|err| { + mlua::Error::RuntimeError( + "Failed to start write transaction for frecency database: ".to_string() + + &err.to_string(), + ) + })?; + + let mut accesses = self.get_accesses(item)?.unwrap_or_default(); accesses.push(self.get_now()); + self.db - .put(&mut wtxn, &CompletionItemKey::from(item), &accesses)?; - wtxn.commit()?; + .put(&mut wtxn, &CompletionItemKey::from(item), &accesses) + .map_err(|err| { + mlua::Error::RuntimeError( + "Failed to write to frecency database: ".to_string() + &err.to_string(), + ) + })?; + + wtxn.commit().map_err(|err| { + mlua::Error::RuntimeError( + "Failed to commit write transaction for frecency database: ".to_string() + + &err.to_string(), + ) + })?; + Ok(()) } pub fn get_score(&self, item: &LspItem) -> i64 { - let accesses = self.get_accesses(item).unwrap_or_default(); + let accesses = self.get_accesses(item).unwrap_or(None).unwrap_or_default(); let now = self.get_now(); let mut score = 0.0; 'outer: for access in &accesses { diff --git a/lua/blink/cmp/fuzzy/fuzzy.rs b/lua/blink/cmp/fuzzy/fuzzy.rs index d72a0b31..2b5c1855 100644 --- a/lua/blink/cmp/fuzzy/fuzzy.rs +++ b/lua/blink/cmp/fuzzy/fuzzy.rs @@ -1,12 +1,14 @@ // TODO: refactor this heresy use crate::frecency::FrecencyTracker; -use lua_marshalling::LuaMarshalling; +use mlua::prelude::*; +use mlua::FromLua; +use mlua::Lua; use serde::{Deserialize, Serialize}; use std::cmp::Reverse; use std::collections::HashSet; -#[derive(Clone, Serialize, Deserialize, LuaMarshalling)] +#[derive(Clone, Serialize, Deserialize, Debug)] pub struct LspItem { pub label: String, #[serde(rename = "sortText")] @@ -18,7 +20,35 @@ pub struct LspItem { pub source: String, } -#[derive(Clone, LuaMarshalling)] +impl FromLua<'_> for LspItem { + fn from_lua(value: LuaValue<'_>, _lua: &'_ Lua) -> LuaResult { + if let Some(tab) = value.as_table() { + let label: String = tab.get("label").unwrap_or_default(); + let sort_text: Option = tab.get("sortText").ok(); + let filter_text: Option = tab.get("filterText").ok(); + let kind: u32 = tab.get("kind").unwrap_or_default(); + let score_offset: Option = tab.get("score_offset").ok(); + let source: String = tab.get("source").unwrap_or_default(); + + Ok(LspItem { + label, + sort_text, + filter_text, + kind, + score_offset, + source, + }) + } else { + Err(mlua::Error::FromLuaConversionError { + from: "LuaValue", + to: "LspItem", + message: None, + }) + } + } +} + +#[derive(Clone, Serialize, Deserialize)] pub struct MatchedLspItem { label: String, kind: u32, @@ -26,15 +56,41 @@ pub struct MatchedLspItem { score: i32, } -#[derive(LuaMarshalling)] +#[derive(Clone, Serialize, Deserialize, Hash)] pub struct FuzzyOptions { use_frecency: bool, nearby_words: Option>, min_score: u16, - max_items: usize, + max_items: u32, sorts: Vec, } +impl FromLua<'_> for FuzzyOptions { + fn from_lua(value: LuaValue<'_>, _lua: &'_ Lua) -> LuaResult { + if let Some(tab) = value.as_table() { + let use_frecency: bool = tab.get("use_frecency").unwrap_or_default(); + let nearby_words: Option> = tab.get("nearby_words").ok(); + let min_score: u16 = tab.get("min_score").unwrap_or_default(); + let max_items: u32 = tab.get("max_items").unwrap_or_default(); + let sorts: Vec = tab.get("sorts").unwrap_or_default(); + + Ok(FuzzyOptions { + use_frecency, + nearby_words, + min_score, + max_items, + sorts, + }) + } else { + Err(mlua::Error::FromLuaConversionError { + from: "LuaValue", + to: "FuzzyOptions", + message: None, + }) + } + } +} + pub fn fuzzy( needle: String, haystack: Vec, @@ -60,13 +116,18 @@ pub fn fuzzy( let match_scores = matches .iter() .map(|mtch| { - (mtch.score as i32) - + frecency.get_score(&haystack[mtch.index_in_haystack]) as i32 - + nearby_words - .get(&haystack[mtch.index_in_haystack].label) - .map(|_| 2) - .unwrap_or(0) - + haystack[mtch.index_in_haystack].score_offset.unwrap_or(0) + let frecency_score = if opts.use_frecency { + frecency.get_score(&haystack[mtch.index_in_haystack]) as i32 + } else { + 0 + }; + let nearby_words_score = nearby_words + .get(&haystack[mtch.index_in_haystack].label) + .map(|_| 2) + .unwrap_or(0); + let score_offset = haystack[mtch.index_in_haystack].score_offset.unwrap_or(0); + + (mtch.score as i32) + frecency_score + nearby_words_score + score_offset }) .collect::>(); @@ -108,6 +169,6 @@ pub fn fuzzy( matches .iter() .map(|mtch| mtch.index_in_haystack) - .take(opts.max_items) + .take(opts.max_items as usize) .collect::>() } diff --git a/lua/blink/cmp/fuzzy/init.lua b/lua/blink/cmp/fuzzy/init.lua index 6066f849..b6338b5d 100644 --- a/lua/blink/cmp/fuzzy/init.lua +++ b/lua/blink/cmp/fuzzy/init.lua @@ -5,7 +5,7 @@ local fuzzy = { last_context = nil, ---@type blink.cmp.CompletionItem[]? last_items = nil, - rust = require('blink.cmp.fuzzy.ffi'), + rust = require('blink.cmp.fuzzy.rust'), } ---@param db_path string @@ -28,21 +28,8 @@ function fuzzy.get_words(lines) return fuzzy.rust.get_words(lines) end ---@param needle string ---@param items blink.cmp.CompletionItem[]? ---@return blink.cmp.CompletionItem[] -function fuzzy.filter_items(needle, items) - -- convert to table of strings - local haystack_labels = {} - local haystack_score_offsets = {} - local haystack_kinds = {} - local haystack_sources = {} - - items = items or {} - - for _, item in ipairs(items) do - table.insert(haystack_labels, item.label) - table.insert(haystack_score_offsets, item.score_offset or 0) - table.insert(haystack_kinds, item.kind) - table.insert(haystack_sources, item.source) - end +function fuzzy.filter_items(needle, haystack) + haystack = haystack or {} -- get the nearby words local cursor_row = vim.api.nvim_win_get_cursor(0)[1] @@ -53,21 +40,20 @@ function fuzzy.filter_items(needle, items) -- perform fuzzy search local filtered_items = {} - local matched_indices = - fuzzy.rust.fuzzy(needle, haystack_labels, haystack_kinds, haystack_score_offsets, haystack_sources, { - -- each matching char is worth 4 points and it receives a bonus for capitalization, delimiter and prefix - -- so this should generally be good - -- TODO: make this configurable - min_score = 6 * needle:len(), - max_items = config.fuzzy.max_items, - use_frecency = config.fuzzy.use_frecency, - use_proximity = config.fuzzy.use_proximity, - sorts = config.fuzzy.sorts, - nearby_words = nearby_words, - }) + local matched_indices = fuzzy.rust.fuzzy(needle, haystack, { + -- each matching char is worth 4 points and it receives a bonus for capitalization, delimiter and prefix + -- so this should generally be good + -- TODO: make this configurable + min_score = 6 * needle:len(), + max_items = config.fuzzy.max_items, + use_frecency = config.fuzzy.use_frecency, + use_proximity = config.fuzzy.use_proximity, + sorts = config.fuzzy.sorts, + nearby_words = nearby_words, + }) for _, idx in ipairs(matched_indices) do - table.insert(filtered_items, items[idx + 1]) + table.insert(filtered_items, haystack[idx + 1]) end return filtered_items diff --git a/lua/blink/cmp/fuzzy/lib.rs b/lua/blink/cmp/fuzzy/lib.rs new file mode 100644 index 00000000..db94d36c --- /dev/null +++ b/lua/blink/cmp/fuzzy/lib.rs @@ -0,0 +1,88 @@ +use crate::frecency::FrecencyTracker; +use crate::fuzzy::{FuzzyOptions, LspItem}; +use lazy_static::lazy_static; +use mlua::prelude::*; +use regex::Regex; +use std::collections::HashSet; +use std::sync::RwLock; + +mod frecency; +mod fuzzy; + +lazy_static! { + static ref REGEX: Regex = Regex::new(r"[A-Za-z][A-Za-z0-9_\\-]{2,32}").unwrap(); + static ref FRECENCY: RwLock> = RwLock::new(None); +} + +pub fn init_db(_: &Lua, db_path: String) -> LuaResult { + let mut frecency = FRECENCY.write().map_err(|_| { + mlua::Error::RuntimeError("Failed to acquire lock for frecency".to_string()) + })?; + if frecency.is_some() { + return Ok(false); + } + *frecency = Some(FrecencyTracker::new(&db_path)?); + Ok(true) +} + +pub fn destroy_db(_: &Lua, _: ()) -> LuaResult { + let frecency = FRECENCY.write().map_err(|_| { + mlua::Error::RuntimeError("Failed to acquire lock for frecency".to_string()) + })?; + drop(frecency); + + let mut frecency = FRECENCY.write().map_err(|_| { + mlua::Error::RuntimeError("Failed to acquire lock for frecency".to_string()) + })?; + *frecency = None; + + Ok(true) +} + +pub fn access(_: &Lua, item: LspItem) -> LuaResult { + let mut frecency_handle = FRECENCY.write().map_err(|_| { + mlua::Error::RuntimeError("Failed to acquire lock for frecency".to_string()) + })?; + let frecency = frecency_handle.as_mut().ok_or_else(|| { + mlua::Error::RuntimeError("Attempted to use frencecy before initialization".to_string()) + })?; + frecency.access(&item)?; + Ok(true) +} + +pub fn fuzzy( + _lua: &Lua, + (needle, haystack, opts): (String, Vec, FuzzyOptions), +) -> LuaResult> { + let mut frecency_handle = FRECENCY.write().map_err(|_| { + mlua::Error::RuntimeError("Failed to acquire lock for frecency".to_string()) + })?; + let frecency = frecency_handle.as_mut().ok_or_else(|| { + mlua::Error::RuntimeError("Attempted to use frencecy before initialization".to_string()) + })?; + + Ok(fuzzy::fuzzy(needle, haystack, frecency, opts) + .into_iter() + .map(|i| i as u32) + .collect()) +} + +pub fn get_words(_: &Lua, text: String) -> LuaResult> { + Ok(REGEX + .find_iter(&text) + .map(|m| m.as_str().to_string()) + .collect::>() + .into_iter() + .collect()) +} + +#[mlua::lua_module] +fn blink_cmp_fuzzy(lua: &Lua) -> LuaResult { + let exports = lua.create_table()?; + exports.set("fuzzy", lua.create_function(fuzzy)?)?; + exports.set("get_words", lua.create_function(get_words)?)?; + exports.set("init_db", lua.create_function(init_db)?)?; + exports.set("destroy_db", lua.create_function(destroy_db)?)?; + exports.set("access", lua.create_function(access)?)?; + Ok(exports) +} diff --git a/lua/blink/cmp/fuzzy/rust.lua b/lua/blink/cmp/fuzzy/rust.lua new file mode 100644 index 00000000..e2374cfc --- /dev/null +++ b/lua/blink/cmp/fuzzy/rust.lua @@ -0,0 +1,20 @@ +--- @return string +local function get_lib_extension() + if jit.os:lower() == 'mac' or jit.os:lower() == 'osx' then return '.dylib' end + if jit.os:lower() == 'windows' then return '.dll' end + return '.so' +end + +-- search for the lib in the /target/release directory with and without the lib prefix +-- since MSVC doesn't include the prefix +package.cpath = package.cpath + .. ';' + .. debug.getinfo(1).source:match('@?(.*/)') + .. '../../../../target/release/lib?' + .. get_lib_extension() + .. ';' + .. debug.getinfo(1).source:match('@?(.*/)') + .. '../../../../target/release/?' + .. get_lib_extension() + +return require('blink_cmp_fuzzy') diff --git a/lua/blink/cmp/sources/buffer.lua b/lua/blink/cmp/sources/buffer.lua index 584d51d4..8ce24963 100644 --- a/lua/blink/cmp/sources/buffer.lua +++ b/lua/blink/cmp/sources/buffer.lua @@ -53,7 +53,7 @@ local function run_sync(buf_text, callback) callback(words_to_items(require('bli local function run_async(buf_text, callback) local worker = uv.new_work( -- must use ffi directly since the normal one requires the config which isnt present - function(items) return table.concat(require('blink.cmp.fuzzy.ffi').get_words(items), '\n') end, + function(items) return table.concat(require('blink.cmp.fuzzy.rust').get_words(items), '\n') end, function(words) local items = words_to_items(vim.split(words, '\n')) vim.schedule(function() callback(items) end)