chore: better ffi

This commit is contained in:
Ade Attwood 2022-08-28 17:05:14 +01:00
parent 39febd82e2
commit 75bd90ab4a
5 changed files with 50 additions and 27 deletions

View file

@ -7,9 +7,12 @@ local ffi = require "ffi"
local ivy_c = ffi.load(library_path)
ffi.cdef [[
typedef struct { int score; const char* content; } match;
typedef struct { int len; match* matches; } match_list;
void ivy_init(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 = {}
@ -23,7 +26,7 @@ libivy.ivy_match = function(pattern, text)
end
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
return libivy

View file

@ -1,4 +1,5 @@
local libivy = require "ivy.libivy"
local ffi = require "ffi"
it("should run a simple match", function(t)
local score = libivy.ivy_match("term", "I am a serch term")

View file

@ -1,3 +1,5 @@
local ffi = require "ffi"
-- Constent options that will be used for the keymaps
local opts = { noremap = true, silent = true, nowait = true }
@ -22,12 +24,12 @@ local function string_to_table(lines)
end
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
local function set_items_array(buffer, lines)
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
for i = 1, #lines do
vim.api.nvim_buf_set_lines(buffer, i - 1, 9999, false, { lines[i][2] })
@ -112,7 +114,13 @@ window.update = function()
end
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 --" })
elseif type(items) == "string" then
set_items_string(window.get_buffer(), items)

View file

@ -4,9 +4,15 @@ mod sorter;
use std::collections::HashMap;
use std::ffi::CStr;
use std::ffi::CString;
use std::os::raw::{c_char, c_int};
use std::sync::Mutex;
use std::mem;
#[repr(C)]
pub struct FFiMatchList {
len: c_int,
matches: *mut sorter::Match
}
#[macro_use]
extern crate lazy_static;
@ -22,6 +28,15 @@ fn to_string(input: *const c_char) -> 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> {
let mut cache = GLOBAL_FILE_CACHE.lock().unwrap();
if !cache.contains_key(directory) {
@ -55,32 +70,21 @@ pub fn inner_match(pattern: String, text: String) -> i32 {
}
#[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 directory = to_string(c_base_dir);
let output = inner_files(pattern, directory);
CString::new(output).unwrap().into_raw()
return inner_files(pattern, directory);
}
pub fn inner_files(pattern: String, base_dir: String) -> String {
let mut output = String::new();
pub fn inner_files(pattern: String, base_dir: String) -> *const FFiMatchList {
// Bail out early if the pattern is empty; it's never going to find anything
if pattern.is_empty() {
return output;
return to_ffi_match_list(Vec::new());
}
let files = get_files(&base_dir);
let sorter_options = sorter::Options::new(pattern);
let files = sorter::sort_strings(sorter_options, files);
for file in files.iter() {
output.push_str(&file.content);
output.push('\n');
}
output
to_ffi_match_list(sorter::sort_strings(sorter_options, files))
}

View file

@ -1,11 +1,18 @@
use super::matcher;
use rayon::prelude::*;
use std::os::raw::{c_char, c_int};
use std::ffi::CString;
#[repr(C)]
pub struct Match {
pub score: i64,
pub content: String,
pub score: c_int,
pub content: *const c_char
// pub score: i64,
// pub content: String,
}
unsafe impl Send for Match {}
pub struct Options {
pub pattern: String,
pub minimum_score: i64,
@ -26,10 +33,10 @@ pub fn sort_strings(options: Options, strings: Vec<String>) -> Vec<Match> {
let mut matches = strings
.into_par_iter()
.map(|candidate| Match {
score: matcher.score(candidate.as_str()),
content: candidate,
score: matcher.score(candidate.as_str()) as i32,
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>>();
matches.par_sort_unstable_by(|a, b| a.score.cmp(&b.score));
matches