chore: better ffi
This commit is contained in:
parent
39febd82e2
commit
75bd90ab4a
5 changed files with 50 additions and 27 deletions
|
|
@ -7,9 +7,12 @@ local ffi = require "ffi"
|
||||||
local ivy_c = ffi.load(library_path)
|
local ivy_c = ffi.load(library_path)
|
||||||
|
|
||||||
ffi.cdef [[
|
ffi.cdef [[
|
||||||
|
typedef struct { int score; const char* content; } match;
|
||||||
|
typedef struct { int len; match* matches; } match_list;
|
||||||
|
|
||||||
void ivy_init(const char*);
|
void ivy_init(const char*);
|
||||||
int ivy_match(const char*, const char*);
|
int ivy_match(const char*, const char*);
|
||||||
char* ivy_files(const char*, const char*);
|
match_list* ivy_files(const char*, const char*);
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local libivy = {}
|
local libivy = {}
|
||||||
|
|
@ -23,7 +26,7 @@ libivy.ivy_match = function(pattern, text)
|
||||||
end
|
end
|
||||||
|
|
||||||
libivy.ivy_files = function(pattern, base_dir)
|
libivy.ivy_files = function(pattern, base_dir)
|
||||||
return ffi.string(ivy_c.ivy_files(pattern, base_dir))
|
return ivy_c.ivy_files(pattern, base_dir)
|
||||||
end
|
end
|
||||||
|
|
||||||
return libivy
|
return libivy
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
local libivy = require "ivy.libivy"
|
local libivy = require "ivy.libivy"
|
||||||
|
local ffi = require "ffi"
|
||||||
|
|
||||||
it("should run a simple match", function(t)
|
it("should run a simple match", function(t)
|
||||||
local score = libivy.ivy_match("term", "I am a serch term")
|
local score = libivy.ivy_match("term", "I am a serch term")
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
local ffi = require "ffi"
|
||||||
|
|
||||||
-- Constent options that will be used for the keymaps
|
-- Constent options that will be used for the keymaps
|
||||||
local opts = { noremap = true, silent = true, nowait = true }
|
local opts = { noremap = true, silent = true, nowait = true }
|
||||||
|
|
||||||
|
|
@ -22,12 +24,12 @@ local function string_to_table(lines)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function set_items_string(buffer, lines)
|
local function set_items_string(buffer, lines)
|
||||||
vim.api.nvim_buf_set_lines(buffer, 0, 9999, false, string_to_table(lines))
|
vim.api.nvim_buf_set_lines(buffer, 0, -1, false, string_to_table(lines))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function set_items_array(buffer, lines)
|
local function set_items_array(buffer, lines)
|
||||||
if type(lines[1]) == "string" then
|
if type(lines[1]) == "string" then
|
||||||
vim.api.nvim_buf_set_lines(buffer, 0, 9999, false, lines)
|
vim.api.nvim_buf_set_lines(buffer, 0, -1, false, lines)
|
||||||
else
|
else
|
||||||
for i = 1, #lines do
|
for i = 1, #lines do
|
||||||
vim.api.nvim_buf_set_lines(buffer, i - 1, 9999, false, { lines[i][2] })
|
vim.api.nvim_buf_set_lines(buffer, i - 1, 9999, false, { lines[i][2] })
|
||||||
|
|
@ -112,7 +114,13 @@ window.update = function()
|
||||||
end
|
end
|
||||||
|
|
||||||
window.set_items = function(items)
|
window.set_items = function(items)
|
||||||
if #items == 0 then
|
vim.api.nvim_buf_set_lines(window.get_buffer(), 0, -1, false, {})
|
||||||
|
|
||||||
|
if items.len ~= nil then
|
||||||
|
for i = 0, items.len - 1 do
|
||||||
|
vim.api.nvim_buf_set_lines(window.get_buffer(), i - 1, -1, false, { ffi.string(items.matches[i].content) })
|
||||||
|
end
|
||||||
|
elseif #items == 0 then
|
||||||
vim.api.nvim_buf_set_lines(window.get_buffer(), 0, 9999, false, { "-- No Items --" })
|
vim.api.nvim_buf_set_lines(window.get_buffer(), 0, 9999, false, { "-- No Items --" })
|
||||||
elseif type(items) == "string" then
|
elseif type(items) == "string" then
|
||||||
set_items_string(window.get_buffer(), items)
|
set_items_string(window.get_buffer(), items)
|
||||||
|
|
|
||||||
38
rust/lib.rs
38
rust/lib.rs
|
|
@ -4,9 +4,15 @@ mod sorter;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::ffi::CString;
|
|
||||||
use std::os::raw::{c_char, c_int};
|
use std::os::raw::{c_char, c_int};
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct FFiMatchList {
|
||||||
|
len: c_int,
|
||||||
|
matches: *mut sorter::Match
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
@ -22,6 +28,15 @@ fn to_string(input: *const c_char) -> String {
|
||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_ffi_match_list(mut list: Vec<sorter::Match>) -> *const FFiMatchList {
|
||||||
|
list.shrink_to_fit();
|
||||||
|
let matches = list.as_mut_ptr();
|
||||||
|
let len: c_int = list.len().try_into().unwrap();
|
||||||
|
mem::forget(list);
|
||||||
|
|
||||||
|
return Box::into_raw(Box::new(FFiMatchList { len, matches }))
|
||||||
|
}
|
||||||
|
|
||||||
fn get_files(directory: &String) -> Vec<String> {
|
fn get_files(directory: &String) -> Vec<String> {
|
||||||
let mut cache = GLOBAL_FILE_CACHE.lock().unwrap();
|
let mut cache = GLOBAL_FILE_CACHE.lock().unwrap();
|
||||||
if !cache.contains_key(directory) {
|
if !cache.contains_key(directory) {
|
||||||
|
|
@ -55,32 +70,21 @@ pub fn inner_match(pattern: String, text: String) -> i32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn ivy_files(c_pattern: *const c_char, c_base_dir: *const c_char) -> *const c_char {
|
pub extern "C" fn ivy_files(c_pattern: *const c_char, c_base_dir: *const c_char) -> *const FFiMatchList {
|
||||||
let pattern = to_string(c_pattern);
|
let pattern = to_string(c_pattern);
|
||||||
let directory = to_string(c_base_dir);
|
let directory = to_string(c_base_dir);
|
||||||
|
|
||||||
let output = inner_files(pattern, directory);
|
return inner_files(pattern, directory);
|
||||||
|
|
||||||
CString::new(output).unwrap().into_raw()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner_files(pattern: String, base_dir: String) -> String {
|
pub fn inner_files(pattern: String, base_dir: String) -> *const FFiMatchList {
|
||||||
let mut output = String::new();
|
|
||||||
|
|
||||||
// Bail out early if the pattern is empty; it's never going to find anything
|
// Bail out early if the pattern is empty; it's never going to find anything
|
||||||
if pattern.is_empty() {
|
if pattern.is_empty() {
|
||||||
return output;
|
return to_ffi_match_list(Vec::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
let files = get_files(&base_dir);
|
let files = get_files(&base_dir);
|
||||||
|
|
||||||
let sorter_options = sorter::Options::new(pattern);
|
let sorter_options = sorter::Options::new(pattern);
|
||||||
|
to_ffi_match_list(sorter::sort_strings(sorter_options, files))
|
||||||
let files = sorter::sort_strings(sorter_options, files);
|
|
||||||
for file in files.iter() {
|
|
||||||
output.push_str(&file.content);
|
|
||||||
output.push('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,18 @@
|
||||||
use super::matcher;
|
use super::matcher;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
use std::os::raw::{c_char, c_int};
|
||||||
|
use std::ffi::CString;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
pub struct Match {
|
pub struct Match {
|
||||||
pub score: i64,
|
pub score: c_int,
|
||||||
pub content: String,
|
pub content: *const c_char
|
||||||
|
// pub score: i64,
|
||||||
|
// pub content: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for Match {}
|
||||||
|
|
||||||
pub struct Options {
|
pub struct Options {
|
||||||
pub pattern: String,
|
pub pattern: String,
|
||||||
pub minimum_score: i64,
|
pub minimum_score: i64,
|
||||||
|
|
@ -26,10 +33,10 @@ pub fn sort_strings(options: Options, strings: Vec<String>) -> Vec<Match> {
|
||||||
let mut matches = strings
|
let mut matches = strings
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.map(|candidate| Match {
|
.map(|candidate| Match {
|
||||||
score: matcher.score(candidate.as_str()),
|
score: matcher.score(candidate.as_str()) as i32,
|
||||||
content: candidate,
|
content: CString::new(candidate.clone().to_string()).unwrap().into_raw(),
|
||||||
})
|
})
|
||||||
.filter(|m| m.score > options.minimum_score)
|
.filter(|m| m.score > options.minimum_score as i32)
|
||||||
.collect::<Vec<Match>>();
|
.collect::<Vec<Match>>();
|
||||||
matches.par_sort_unstable_by(|a, b| a.score.cmp(&b.score));
|
matches.par_sort_unstable_by(|a, b| a.score.cmp(&b.score));
|
||||||
matches
|
matches
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue