Page MenuHomePhorge

No OneTemporary

diff --git a/lua/ivy/libivy.lua b/lua/ivy/libivy.lua
index 0b00c2f..cc162ad 100644
--- a/lua/ivy/libivy.lua
+++ b/lua/ivy/libivy.lua
@@ -1,29 +1,32 @@
local library_path = (function()
local dirname = string.sub(debug.getinfo(1).source, 2, #"/fzf_lib.lua" * -1)
return dirname .. "/../../target/release/libivyrs.so"
end)()
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 = {}
libivy.ivy_init = function(dir)
ivy_c.ivy_init(dir)
end
libivy.ivy_match = function(pattern, text)
return ivy_c.ivy_match(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
diff --git a/lua/ivy/libivy_test.lua b/lua/ivy/libivy_test.lua
index 28fb527..9ecf50a 100644
--- a/lua/ivy/libivy_test.lua
+++ b/lua/ivy/libivy_test.lua
@@ -1,9 +1,10 @@
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")
if score <= 0 then
t.error("Score should not be less than 0 found " .. score)
end
end)
diff --git a/lua/ivy/window.lua b/lua/ivy/window.lua
index addefc1..53a2ca2 100644
--- a/lua/ivy/window.lua
+++ b/lua/ivy/window.lua
@@ -1,144 +1,152 @@
+local ffi = require "ffi"
+
-- Constent options that will be used for the keymaps
local opts = { noremap = true, silent = true, nowait = true }
-- All of the base chars that will be used for an "input" operation on the
-- prompt
-- stylua: ignore
local chars = {
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W",
"X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
"u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "<", ">", "`", "@", "#", "~", "!",
"\"", "$", "%", "^", "&", "/", "(", ")", "=", "+", "*", "-", "_", ".", ",", ";", ":", "?", "\\", "|", "'", "{", "}",
"[", "]", " ",
}
local function string_to_table(lines)
local items = {}
for line in lines:gmatch "[^\r\n]+" do
table.insert(items, line)
end
return items
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] })
end
end
end
local window = {}
window.index = 0
window.origin = nil
window.window = nil
window.buffer = nil
window.initialize = function()
window.make_buffer()
end
window.make_buffer = function()
window.origin = vim.api.nvim_get_current_win()
vim.api.nvim_command "botright split new"
window.buffer = vim.api.nvim_win_get_buf(0)
window.window = vim.api.nvim_get_current_win()
vim.api.nvim_win_set_option(window.window, "number", false)
vim.api.nvim_win_set_option(window.window, "relativenumber", false)
vim.api.nvim_win_set_option(window.window, "signcolumn", "no")
vim.api.nvim_buf_set_option(window.buffer, "filetype", "ivy")
vim.api.nvim_buf_set_var(window.buffer, "bufftype", "nofile")
for index = 1, #chars do
local char = chars[index]
if char == "'" then
char = "\\'"
end
if char == "\\" then
char = "\\\\\\\\"
end
vim.api.nvim_buf_set_keymap(window.buffer, "n", chars[index], "<cmd>lua vim.ivy.input('" .. char .. "')<CR>", opts)
end
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<C-c>", "<cmd>lua vim.ivy.destroy()<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<C-u>", "<cmd>lua vim.ivy.search('')<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<C-n>", "<cmd>lua vim.ivy.next()<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<C-p>", "<cmd>lua vim.ivy.previous()<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<C-M-n>", "<cmd>lua vim.ivy.next(); vim.ivy.checkpoint()<CR>", opts)
vim.api.nvim_buf_set_keymap(
window.buffer,
"n",
"<C-M-p>",
"<cmd>lua vim.ivy.previous(); vim.ivy.checkpoint()<CR>",
opts
)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<CR>", "<cmd>lua vim.ivy.complete()<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<BS>", "<cmd>lua vim.ivy.input('BACKSPACE')<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<Left>", "<cmd>lua vim.ivy.input('LEFT')<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<Right>", "<cmd>lua vim.ivy.input('RIGHT')<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<C-w>", "<cmd>lua vim.ivy.input('DELETE_WORD')<CR>", opts)
end
window.get_current_selection = function()
local line = vim.api.nvim_buf_get_lines(window.buffer, window.index, window.index + 1, true)
if line == nil then
line = { "" }
end
return line[1]
end
window.get_buffer = function()
if window.buffer == nil then
window.make_buffer()
end
return window.buffer
end
window.update = function()
vim.api.nvim_win_set_cursor(window.window, { window.index + 1, 0 })
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)
elseif type(items) == "table" then
set_items_array(window.get_buffer(), items)
end
local line_count = vim.api.nvim_buf_line_count(window.buffer)
window.index = line_count - 1
if line_count > 10 then
line_count = 10
end
vim.api.nvim_win_set_height(window.window, line_count)
window.update()
end
window.destroy = function()
if type(window.buffer) == "number" then
vim.api.nvim_buf_delete(window.buffer, { force = true })
end
window.buffer = nil
window.window = nil
window.origin = nil
window.index = 0
end
return window
diff --git a/rust/lib.rs b/rust/lib.rs
index e2aca28..5ca802d 100644
--- a/rust/lib.rs
+++ b/rust/lib.rs
@@ -1,86 +1,90 @@
mod finder;
mod matcher;
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;
lazy_static! {
static ref GLOBAL_FILE_CACHE: Mutex<HashMap<String, Vec<String>>> = Mutex::new(HashMap::new());
}
fn to_string(input: *const c_char) -> String {
unsafe { CStr::from_ptr(input) }
.to_str()
.unwrap()
.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) {
let finder_options = finder::Options {
directory: directory.clone(),
};
cache.insert(directory.clone(), finder::find_files(finder_options));
}
return cache.get(directory).unwrap().to_vec();
}
#[no_mangle]
pub extern "C" fn ivy_init(c_base_dir: *const c_char) {
let directory = to_string(c_base_dir);
get_files(&directory);
}
#[no_mangle]
pub extern "C" fn ivy_match(c_pattern: *const c_char, c_text: *const c_char) -> c_int {
let pattern = to_string(c_pattern);
let text = to_string(c_text);
inner_match(pattern, text)
}
pub fn inner_match(pattern: String, text: String) -> i32 {
let m = matcher::Matcher::new(pattern);
m.score(text.as_str()) as 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))
}
diff --git a/rust/sorter.rs b/rust/sorter.rs
index f81f622..3009830 100644
--- a/rust/sorter.rs
+++ b/rust/sorter.rs
@@ -1,36 +1,43 @@
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,
}
impl Options {
pub fn new(pattern: String) -> Self {
Self {
pattern,
minimum_score: 25,
}
}
}
pub fn sort_strings(options: Options, strings: Vec<String>) -> Vec<Match> {
let matcher = matcher::Matcher::new(options.pattern);
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
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Sep 10, 5:07 PM (11 h, 42 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
8997
Default Alt Text
(11 KB)

Event Timeline