Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F132299
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/.gitignore b/.gitignore
index 88eb5a1..e138ae8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
build
+target
.cache
compile_commands.json
.luacheckcache
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..6c62469
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,196 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "bstr"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "fuzzy-matcher"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94"
+dependencies = [
+ "thread_local",
+]
+
+[[package]]
+name = "globset"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a"
+dependencies = [
+ "aho-corasick",
+ "bstr",
+ "fnv",
+ "log",
+ "regex",
+]
+
+[[package]]
+name = "ignore"
+version = "0.4.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d"
+dependencies = [
+ "crossbeam-utils",
+ "globset",
+ "lazy_static",
+ "log",
+ "memchr",
+ "regex",
+ "same-file",
+ "thread_local",
+ "walkdir",
+ "winapi-util",
+]
+
+[[package]]
+name = "ivy"
+version = "0.0.1"
+dependencies = [
+ "fuzzy-matcher",
+ "ignore",
+ "lazy_static",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "log"
+version = "0.4.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "memchr"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+
+[[package]]
+name = "once_cell"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
+
+[[package]]
+name = "regex"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "walkdir"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
+dependencies = [
+ "same-file",
+ "winapi",
+ "winapi-util",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..cd601b6
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "ivy"
+version = "0.0.1"
+edition = "2021"
+
+[lib]
+name = "ivyrs"
+crate-type = ["cdylib"]
+path = "rust/lib.rs"
+
+[dependencies]
+ignore = "0.4"
+fuzzy-matcher = "0.3.7"
+lazy_static = "1.4.0"
+
+[profile.release]
+opt-level = 3
diff --git a/lua/ivy/libivy.lua b/lua/ivy/libivy.lua
index d6222fa..0b00c2f 100644
--- a/lua/ivy/libivy.lua
+++ b/lua/ivy/libivy.lua
@@ -1,29 +1,29 @@
local library_path = (function()
local dirname = string.sub(debug.getinfo(1).source, 2, #"/fzf_lib.lua" * -1)
- return dirname .. "/../../build/Release/lib/libivy.so"
+ return dirname .. "/../../target/release/libivyrs.so"
end)()
local ffi = require "ffi"
local ivy_c = ffi.load(library_path)
ffi.cdef [[
void ivy_init(const char*);
int ivy_match(const char*, const char*);
char* 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))
end
return libivy
diff --git a/rust/finder.rs b/rust/finder.rs
new file mode 100644
index 0000000..4a3ccf5
--- /dev/null
+++ b/rust/finder.rs
@@ -0,0 +1,26 @@
+use ignore::WalkBuilder;
+use std::fs;
+
+pub struct Options {
+ pub directory: String,
+}
+
+pub fn find_files(options: Options) -> Vec<String> {
+ let mut files: Vec<String> = Vec::new();
+ let base_path = &fs::canonicalize(options.directory).unwrap();
+
+ let mut builder = WalkBuilder::new(base_path);
+ builder.ignore(true).hidden(true);
+
+ for result in builder.build() {
+ let absolute_candidate = result.unwrap();
+ let candidate_path = absolute_candidate.path().strip_prefix(base_path).unwrap();
+ if candidate_path.is_dir() {
+ continue;
+ }
+
+ files.push(candidate_path.to_str().unwrap().to_string());
+ }
+
+ return files;
+}
diff --git a/rust/lib.rs b/rust/lib.rs
new file mode 100644
index 0000000..52b861d
--- /dev/null
+++ b/rust/lib.rs
@@ -0,0 +1,68 @@
+mod matcher;
+mod finder;
+mod sorter;
+mod thread_pool;
+
+use std::sync::Mutex;
+use std::collections::HashMap;
+use std::os::raw::{c_int, c_char};
+use std::ffi::CString;
+use std::ffi::CStr;
+
+#[macro_use]
+extern crate lazy_static;
+
+lazy_static! {
+ static ref GLOBAL_FILE_CACHE: Mutex<HashMap<String, Vec<String>>> = return Mutex::new(HashMap::new()) ;
+}
+
+fn to_string(input: *const c_char) -> String {
+ return unsafe { CStr::from_ptr(input) }.to_str().unwrap().to_string();
+}
+
+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() {}
+
+#[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);
+
+ let m = matcher::Matcher{ pattern };
+ return m.score(text) as i32;
+}
+
+#[no_mangle]
+pub extern "C" fn ivy_files(c_pattern: *const c_char, c_base_dir: *const c_char) -> *const c_char {
+ let pattern = to_string(c_pattern);
+ let directory = to_string(c_base_dir);
+
+ // Bail out early if the pattern is empty its never going to find anything
+ if pattern.is_empty() {
+ return CString::new("").unwrap().into_raw()
+ }
+
+ let files = get_files(&directory);
+
+ let mut output = String::new();
+ let sorter_options = sorter::Options::new(pattern);
+
+ let files = sorter::sort_strings(sorter_options, files);
+ for file in files.lock().unwrap().iter() {
+ output.push_str(&file.content);
+ output.push('\n');
+ }
+
+ return CString::new(output).unwrap().into_raw()
+}
+
diff --git a/rust/matcher.rs b/rust/matcher.rs
new file mode 100644
index 0000000..43d364d
--- /dev/null
+++ b/rust/matcher.rs
@@ -0,0 +1,18 @@
+use fuzzy_matcher::FuzzyMatcher;
+use fuzzy_matcher::skim::SkimMatcherV2;
+
+pub struct Matcher {
+ /// The search pattern that we want to match against some text
+ pub pattern: String,
+}
+
+impl Matcher {
+ pub fn score(self: &Self, text: String) -> i64 {
+ let matcher = SkimMatcherV2::default();
+ if let Some((score, _indices)) = matcher.fuzzy_indices(&text, &self.pattern) {
+ return score;
+ }
+
+ return 0;
+ }
+}
diff --git a/rust/sorter.rs b/rust/sorter.rs
new file mode 100644
index 0000000..3bb5c47
--- /dev/null
+++ b/rust/sorter.rs
@@ -0,0 +1,48 @@
+use super::matcher;
+use super::thread_pool;
+
+
+use std::sync::Mutex;
+use std::sync::Arc;
+
+pub struct Match {
+ pub score: i64,
+ pub content: String,
+}
+
+pub struct Options {
+ pub pattern: String,
+ pub minimun_score: i64,
+}
+
+impl Options {
+ pub fn new(pattern: String) -> Self {
+ return Self { pattern, minimun_score: 20 };
+ }
+}
+
+pub fn sort_strings(options: Options, strings: Vec<String>) -> Arc<Mutex<Vec<Match>>> {
+ let matches: Arc<Mutex<Vec<Match>>> = Arc::new(Mutex::new(Vec::new()));
+ let matcher = Arc::new(Mutex::new(matcher::Matcher{ pattern: options.pattern }));
+
+ let pool = thread_pool::ThreadPool::new(std::thread::available_parallelism().unwrap().get());
+
+ for string in strings {
+ let thread_matcher = Arc::clone(&matcher);
+ let thread_matches = Arc::clone(&matches);
+ pool.execute(move || {
+ let score = thread_matcher.lock().unwrap().score(string.to_string());
+ if score > 25 {
+ let mut tmp = thread_matches.lock().unwrap();
+ let content = string.clone();
+ tmp.push(Match{ score, content });
+ }
+ })
+ }
+
+ drop(pool);
+
+ matches.lock().unwrap().sort_by(|a, b| a.score.cmp(&b.score));
+ return matches;
+}
+
diff --git a/rust/thread_pool.rs b/rust/thread_pool.rs
new file mode 100644
index 0000000..df49872
--- /dev/null
+++ b/rust/thread_pool.rs
@@ -0,0 +1,87 @@
+use std::sync::mpsc;
+use std::sync::Arc;
+use std::sync::Mutex;
+use std::thread;
+
+enum Message {
+ NewJob(Job),
+ Terminate,
+}
+
+pub struct ThreadPool {
+ jobs: mpsc::Sender<Message>,
+ threads: Vec<Worker>,
+}
+
+trait FnBox {
+ fn call_box(self: Box<Self>);
+}
+
+impl<F: FnOnce()> FnBox for F {
+ fn call_box(self: Box<F>) {
+ (*self)()
+ }
+}
+
+type Job = Box<dyn FnBox + Send + 'static>;
+
+impl ThreadPool {
+ pub fn new(thread_count: usize) -> Self {
+ let (jobs, receiver) = mpsc::channel();
+ let receiver = Arc::new(Mutex::new(receiver));
+
+ let mut threads: Vec<Worker> = Vec::new();
+ for id in 1..thread_count {
+ threads.push(Worker::new(id, Arc::clone(&receiver)));
+ }
+
+ return ThreadPool { jobs, threads };
+ }
+
+ pub fn execute<F>(&self, f: F)
+ where
+ F: FnOnce() + Send + 'static,
+ {
+ let job = Box::new(f);
+ self.jobs.send(Message::NewJob(job)).unwrap();
+ }
+}
+
+impl Drop for ThreadPool {
+ fn drop(&mut self) {
+ for _ in &mut self.threads {
+ self.jobs.send(Message::Terminate).unwrap();
+ }
+
+ for worker in &mut self.threads {
+ if let Some(thread) = worker.thread.take() {
+ thread.join().unwrap();
+ }
+ }
+ }
+}
+
+struct Worker {
+ id: usize,
+ thread: Option<thread::JoinHandle<()>>,
+}
+
+impl Worker {
+ fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
+ let thread = thread::spawn(move || loop {
+ let message = receiver.lock().unwrap().recv().unwrap();
+
+ match message {
+ Message::NewJob(job) => job.call_box(),
+ Message::Terminate => {
+ break;
+ }
+ }
+ });
+
+ return Worker {
+ id,
+ thread: Some(thread),
+ };
+ }
+}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, May 8, 9:59 PM (1 w, 5 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
9044
Default Alt Text
(13 KB)
Attached To
Mode
R1 ivy.nvim
Attached
Detach File
Event Timeline
Log In to Comment