add really janky rip-grep support

plugins
Patrick Cleavelin 2024-01-02 22:46:45 -06:00
parent a7fa2f6b1d
commit 3d0017134e
10 changed files with 819 additions and 6 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
bin/
lib-rg/target

View File

@ -1,4 +1,7 @@
all: editor
editor: src/*.odin
editor: src/*.odin rg
odin build src/ -out:bin/editor -lld
rg:
cargo b --manifest-path=lib-rg/Cargo.toml

View File

@ -33,6 +33,24 @@
"type": "github"
}
},
"flake-utils_3": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1681202837,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixgl": {
"inputs": {
"flake-utils": "flake-utils_2",
@ -83,11 +101,47 @@
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1681358109,
"narHash": "sha256-eKyxW4OohHQx9Urxi7TQlFBTDWII+F+x2hklDOQPB50=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "96ba1c52e54e74c3197f4d43026b3f3d92e83ff9",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixgl": "nixgl",
"nixpkgs": "nixpkgs_2"
"nixpkgs": "nixpkgs_2",
"rust-overlay": "rust-overlay"
}
},
"rust-overlay": {
"inputs": {
"flake-utils": "flake-utils_3",
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1704075545,
"narHash": "sha256-L3zgOuVKhPjKsVLc3yTm2YJ6+BATyZBury7wnhyc8QU=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "a0df72e106322b67e9c6e591fe870380bd0da0d5",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"systems": {
@ -104,6 +158,21 @@
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",

View File

@ -3,15 +3,19 @@
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
nixgl.url = "github:guibou/nixGL";
rust-overlay.url = "github:oxalica/rust-overlay";
};
outputs = { self, nixpkgs, flake-utils, nixgl, ... }:
outputs = { self, nixpkgs, flake-utils, nixgl, rust-overlay, ... }:
flake-utils.lib.eachDefaultSystem (system:
let
overlays = [ nixgl.overlay ];
overlays = [ nixgl.overlay (import rust-overlay) ];
pkgs = import nixpkgs {
inherit system overlays;
};
local-rust = (pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain).override {
extensions = [ "rust-analysis" ];
};
fixed-odin = pkgs.odin.overrideAttrs (finalAttrs: prevAttr: rec {
src = /Users/temp/Documents/personal/Odin;
LLVM_CONFIG = "${pkgs.llvmPackages_17.llvm.dev}/bin/llvm-config";
@ -48,6 +52,8 @@
devShell = pkgs.mkShell {
buildInputs = with pkgs; (if pkgs.system == "aarch64-darwin" || pkgs.system == "x86_64-darwin" then [
fixed-odin
local-rust
rust-analyzer
darwin.apple_sdk.frameworks.CoreData
darwin.apple_sdk.frameworks.Kernel
darwin.apple_sdk.frameworks.CoreVideo
@ -59,6 +65,8 @@
pkg-config
binutils
odin
local-rust
rust-analyzer
libGL
xorg.libX11
xorg.libXi

329
lib-rg/Cargo.lock generated Normal file
View File

@ -0,0 +1,329 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
[[package]]
name = "bstr"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc"
dependencies = [
"memchr",
"regex-automata",
"serde",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "encoding_rs"
version = "0.8.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
dependencies = [
"cfg-if",
]
[[package]]
name = "encoding_rs_io"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cc3c5651fb62ab8aa3103998dade57efdd028544bd300516baa31840c252a83"
dependencies = [
"encoding_rs",
]
[[package]]
name = "globset"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
dependencies = [
"aho-corasick",
"bstr",
"log",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "grep"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e2b024ec1e686cb64d78beb852030b0e632af93817f1ed25be0173af0e94939"
dependencies = [
"grep-cli",
"grep-matcher",
"grep-printer",
"grep-regex",
"grep-searcher",
]
[[package]]
name = "grep-cli"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea40788c059ab8b622c4d074732750bfb3bd2912e2dd58eabc11798a4d5ad725"
dependencies = [
"bstr",
"globset",
"libc",
"log",
"termcolor",
"winapi-util",
]
[[package]]
name = "grep-matcher"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47a3141a10a43acfedc7c98a60a834d7ba00dfe7bec9071cbfc19b55b292ac02"
dependencies = [
"memchr",
]
[[package]]
name = "grep-printer"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "743c12a03c8aee38b6e5bd0168d8ebb09345751323df4a01c56e792b1f38ceb2"
dependencies = [
"bstr",
"grep-matcher",
"grep-searcher",
"log",
"serde",
"serde_json",
"termcolor",
]
[[package]]
name = "grep-regex"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f748bb135ca835da5cbc67ca0e6955f968db9c5df74ca4f56b18e1ddbc68230d"
dependencies = [
"bstr",
"grep-matcher",
"log",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "grep-searcher"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba536ae4f69bec62d8839584dd3153d3028ef31bb229f04e09fb5a9e5a193c54"
dependencies = [
"bstr",
"encoding_rs",
"encoding_rs_io",
"grep-matcher",
"log",
"memchr",
"memmap2",
]
[[package]]
name = "itoa"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "libc"
version = "0.2.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "memchr"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
[[package]]
name = "memmap2"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45fd3a57831bf88bc63f8cebc0cf956116276e97fef3966103e96416209f7c92"
dependencies = [
"libc",
]
[[package]]
name = "proc-macro2"
version = "1.0.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2de98502f212cfcea8d0bb305bd0f49d7ebdd75b64ba0a68f937d888f4e0d6db"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex-automata"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "rg"
version = "0.1.0"
dependencies = [
"grep",
"termcolor",
"walkdir",
]
[[package]]
name = "ryu"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
[[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 = "serde"
version = "1.0.194"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.194"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.110"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fbd975230bada99c8bb618e0c365c2eefa219158d5c6c29610fd09ff1833257"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "2.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89456b690ff72fddcecf231caedbe615c59480c93358a93dfae7fc29e3ebbf0e"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "termcolor"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
dependencies = [
"winapi-util",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "walkdir"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
dependencies = [
"same-file",
"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.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
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"

13
lib-rg/Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "rg"
version = "0.1.0"
edition = "2021"
publish = false
[lib]
crate-type = ["cdylib"]
[dependencies]
grep = "0.3.1"
termcolor = "1.4.0"
walkdir = "2.4.0"

220
lib-rg/src/lib.rs Normal file
View File

@ -0,0 +1,220 @@
use std::{
error::Error,
ffi::{CStr, OsString},
os::raw::c_char,
str::FromStr,
};
use grep::{
regex::RegexMatcher,
searcher::{BinaryDetection, SearcherBuilder, Sink, SinkError},
};
use walkdir::WalkDir;
#[derive(Debug)]
pub enum SimpleSinkError {
StandardError,
NoLine,
BadString,
}
impl SinkError for SimpleSinkError {
fn error_message<T: std::fmt::Display>(message: T) -> Self {
eprintln!("{message}");
Self::StandardError
}
}
#[repr(C)]
pub struct UnsafeMatch {
text_str: *mut u8,
text_len: usize,
text_cap: usize,
path_str: *mut u8,
path_len: usize,
path_cap: usize,
line_number: u64,
column: u64,
}
impl From<Match> for UnsafeMatch {
fn from(value: Match) -> Self {
let mut text_boxed = Box::new(value.text);
let text_str = text_boxed.as_mut_ptr();
let text_len = text_boxed.len();
let text_cap = text_boxed.capacity();
Box::leak(text_boxed);
let mut path_boxed = Box::new(value.path);
let path_str = path_boxed.as_mut_ptr();
let path_len = path_boxed.len();
let path_cap = path_boxed.capacity();
Box::leak(path_boxed);
Self {
text_str,
text_len,
text_cap,
path_str,
path_len,
path_cap,
line_number: value.line_number.unwrap_or_default(),
column: value.column,
}
}
}
struct Match {
text: Vec<u8>,
path: String,
line_number: Option<u64>,
column: u64,
}
impl Match {
fn from_sink_match_with_path(
value: &grep::searcher::SinkMatch<'_>,
path: Option<String>,
) -> Result<Self, SimpleSinkError> {
let line = value
.lines()
.next()
.ok_or(SimpleSinkError::NoLine)?
.to_vec();
let column = value.bytes_range_in_buffer().len() as u64;
Ok(Self {
text: line,
path: path.unwrap_or_default(),
line_number: value.line_number(),
column,
})
}
}
#[derive(Default)]
struct SimpleSink {
current_path: Option<String>,
matches: Vec<Match>,
}
impl Sink for SimpleSink {
type Error = SimpleSinkError;
fn matched(
&mut self,
_searcher: &grep::searcher::Searcher,
mat: &grep::searcher::SinkMatch<'_>,
) -> Result<bool, Self::Error> {
self.matches.push(Match::from_sink_match_with_path(
mat,
self.current_path.clone(),
)?);
Ok(true)
}
}
#[repr(C)]
pub struct UnsafeMatchArray {
matches: *mut UnsafeMatch,
len: usize,
capacity: usize,
}
impl Default for UnsafeMatchArray {
fn default() -> Self {
Self {
matches: std::ptr::null_mut(),
len: 0,
capacity: 0,
}
}
}
impl From<SimpleSink> for UnsafeMatchArray {
fn from(value: SimpleSink) -> Self {
let matches: Vec<UnsafeMatch> = value.matches.into_iter().map(Into::into).collect();
let mut boxed_vec = Box::new(matches);
let ptr = boxed_vec.as_mut_ptr();
let len = boxed_vec.len();
let capacity = boxed_vec.capacity();
Box::leak(boxed_vec);
Self {
matches: ptr,
len,
capacity,
}
}
}
/// # Safety
/// Who knows what'll happen if you don't pass valid strings
#[no_mangle]
pub unsafe extern "C" fn rg_search(
pattern: *const c_char,
path: *const c_char,
) -> UnsafeMatchArray {
let pattern = CStr::from_ptr(pattern);
let path = CStr::from_ptr(path);
if let (Ok(path), Ok(pattern)) = (path.to_str(), pattern.to_str()) {
if let Ok(path) = OsString::from_str(path) {
return match search(pattern, &[path]) {
Ok(sink) => sink.into(),
Err(err) => {
eprintln!("rg search failed: {}", err);
Default::default()
}
};
}
}
Default::default()
}
/// # Safety
/// Who knows what'll happen if you don't pass back the same vec
#[no_mangle]
pub unsafe extern "C" fn drop_match_array(match_array: UnsafeMatchArray) {
let matches = Vec::from_raw_parts(match_array.matches, match_array.len, match_array.capacity);
for mat in matches {
let _ = String::from_raw_parts(mat.text_str, mat.text_len, mat.text_cap);
let _ = String::from_raw_parts(mat.path_str, mat.path_len, mat.path_cap);
}
}
fn search(pattern: &str, paths: &[OsString]) -> Result<SimpleSink, Box<dyn Error>> {
let matcher = RegexMatcher::new_line_matcher(pattern)?;
let mut searcher = SearcherBuilder::new()
.binary_detection(BinaryDetection::quit(b'\x00'))
.line_number(true)
.build();
let mut sink = SimpleSink::default();
for path in paths {
for result in WalkDir::new(path) {
let dent = match result {
Ok(dent) => dent,
Err(err) => {
eprintln!("{}", err);
continue;
}
};
if !dent.file_type().is_file() {
continue;
}
sink.current_path = Some(dent.path().to_string_lossy().into());
let result = searcher.search_path(&matcher, dent.path(), &mut sink);
if let Err(err) = result {
eprintln!("{}: {:?}", dent.path().display(), err);
}
}
}
Ok(sink)
}

1
rust-toolchain Executable file
View File

@ -0,0 +1 @@
stable

View File

@ -370,6 +370,8 @@ update_file_buffer_index_from_cursor :: proc(buffer: ^FileBuffer) {
// FIXME: just swap cursors
buffer.cursor.index = before_it.cursor.index;
update_file_buffer_scroll(buffer);
}
file_buffer_line_length :: proc(buffer: ^FileBuffer, index: FileBufferIndex) -> int {

View File

@ -1,15 +1,84 @@
package ui;
@(extra_linker_flags="-L./lib-rg/target/debug/")
foreign import rg "system:rg"
ExternMatch :: struct {
text_ptr: [^]u8,
text_len: int,
text_cap: int,
path_ptr: [^]u8,
path_len: int,
path_cap: int,
line: u64,
col: u64
}
ExternMatchArray :: struct {
matches: [^]ExternMatch,
len: uint,
capacity: uint,
}
foreign rg {
rg_search :: proc (pattern: cstring, path: cstring) -> ExternMatchArray ---
drop_match_array :: proc(match_array: ExternMatchArray) ---
}
import "core:math"
import "core:fmt"
import "core:runtime"
import "core:strings"
import "vendor:raylib"
import "../core"
import "../theme"
GrepMatch :: struct {
text: string,
path: string,
line: int,
col: int,
}
transmute_extern_matches :: proc(extern_matches: ExternMatchArray, dest: ^[dynamic]GrepMatch) {
if extern_matches.matches != nil {
for i in 0..<extern_matches.len {
match := &extern_matches.matches[i];
path: string = "";
if match.path_ptr != nil && match.path_len > 0 {
path = strings.string_from_ptr(match.path_ptr, match.path_len);
}
text: string = "";
if match.text_ptr != nil && match.text_len > 0 {
text = strings.string_from_ptr(match.text_ptr, match.text_len);
}
cloned := GrepMatch {
text = text,
path = path,
line = int(match.line),
col = int(match.col)
};
append(dest, cloned);
}
}
}
GrepWindow :: struct {
using window: core.Window,
input_buffer: core.FileBuffer,
selected_match: int,
extern_matches: ExternMatchArray,
matches: [dynamic]GrepMatch,
}
create_grep_window :: proc() -> ^GrepWindow {
@ -18,13 +87,55 @@ create_grep_window :: proc() -> ^GrepWindow {
core.register_key_action(&input_map, .ENTER, proc(state: ^core.State) {
win := cast(^GrepWindow)(state.window);
core.request_window_close(state);
if win.matches != nil && len(win.matches) > 0 {
buffer, err := core.new_file_buffer(context.allocator, strings.clone(win.matches[win.selected_match].path));
if err.type != .None {
fmt.println("Failed to create file buffer:", err);
} else {
runtime.append(&state.buffers, buffer);
state.current_buffer = len(state.buffers)-1;
buffer := &state.buffers[state.current_buffer];
buffer.cursor.line = win.matches[win.selected_match].line-1;
buffer.cursor.col = 0;
buffer.glyph_buffer_height = math.min(256, int((state.screen_height - state.source_font_height*2) / state.source_font_height)) + 1;
buffer.glyph_buffer_width = math.min(256, int((state.screen_width - state.source_font_width) / state.source_font_width));
core.update_file_buffer_index_from_cursor(buffer);
core.request_window_close(state);
}
}
}, "jump to location");
core.register_key_action(&input_map, .I, proc(state: ^core.State) {
state.mode = .Insert;
}, "enter insert mode");
core.register_key_action(&input_map, .T, proc(state: ^core.State) {
win := cast(^GrepWindow)(state.window);
grep_files(win, state);
}, "example search");
core.register_key_action(&input_map, .K, proc(state: ^core.State) {
win := cast(^GrepWindow)(state.window);
if win.selected_match > 0 {
win.selected_match -= 1;
} else {
win.selected_match = len(win.matches)-1;
}
}, "move selection up");
core.register_key_action(&input_map, .J, proc(state: ^core.State) {
win := cast(^GrepWindow)(state.window);
if win.selected_match >= len(win.matches)-1 {
win.selected_match = 0;
} else {
win.selected_match += 1;
}
}, "move selection down");
grep_window := new(GrepWindow);
grep_window^ = GrepWindow {
window = core.Window {
@ -35,6 +146,7 @@ create_grep_window :: proc() -> ^GrepWindow {
},
input_buffer = core.new_virtual_file_buffer(context.allocator),
matches = make([dynamic]GrepMatch),
};
return grep_window;
@ -43,6 +155,14 @@ create_grep_window :: proc() -> ^GrepWindow {
free_grep_window :: proc(win: ^core.Window, state: ^core.State) {
win := cast(^GrepWindow)(win);
if win.extern_matches.matches != nil {
drop_match_array(win.extern_matches);
win.extern_matches.matches = nil;
win.extern_matches.len = 0;
win.extern_matches.capacity = 0;
}
delete(win.matches);
core.free_file_buffer(&win.input_buffer);
}
@ -54,7 +174,32 @@ grep_window_get_buffer :: proc(win: ^core.Window) -> ^core.FileBuffer {
@private
grep_files :: proc(win: ^core.Window, state: ^core.State) {
// TODO: use rip-grep to search through files
win := cast(^GrepWindow)(win);
if win.extern_matches.matches != nil {
drop_match_array(win.extern_matches);
win.extern_matches.matches = nil;
win.extern_matches.len = 0;
win.extern_matches.capacity = 0;
}
if win.matches != nil {
clear_dynamic_array(&win.matches);
} else {
win.matches = make([dynamic]GrepMatch);
}
builder := strings.builder_make();
it := core.new_file_buffer_iter(&win.input_buffer);
for character in core.iterate_file_buffer(&it) {
if character == '\n' { break; }
strings.write_rune(&builder, rune(character));
}
pattern := strings.clone_to_cstring(strings.to_string(builder));
win.extern_matches = rg_search(pattern, "./src");
transmute_extern_matches(win.extern_matches, &win.matches);
}
draw_grep_window :: proc(win: ^core.Window, state: ^core.State) {
@ -94,4 +239,26 @@ draw_grep_window :: proc(win: ^core.Window, state: ^core.State) {
int(win_rec.y + win_rec.height - win_margin.y * 2),
state.font,
show_line_numbers = false);
for match, index in win.matches {
text := raylib.TextFormat("%s:%d:%d: %s", match.path, match.line, match.col, match.text);
text_width := raylib.MeasureTextEx(state.font, text, f32(state.source_font_height), 0);
if index == win.selected_match {
raylib.DrawRectangle(
i32(win_rec.x + win_margin.x),
i32(win_rec.y + win_margin.y) + i32(index * state.source_font_height),
i32(text_width.x),
i32(state.source_font_height),
theme.get_palette_raylib_color(.Background2));
}
raylib.DrawTextEx(
state.font,
text,
raylib.Vector2 { win_rec.x + win_margin.x, win_rec.y + win_margin.y + f32(index * state.source_font_height) },
f32(state.source_font_height),
0,
theme.get_palette_raylib_color(.Foreground2));
}
}