Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions resources/flashgrep/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ Place the prebuilt `flashgrep` daemon binary in this directory.

Expected filenames:

- macOS/Linux: `flashgrep`
- Windows: `flashgrep.exe`
- macOS x86_64: `flashgrep-x86_64-apple-darwin`
- macOS arm64: `flashgrep-aarch64-apple-darwin`
- Linux x86_64: `flashgrep-x86_64-unknown-linux-gnu`
- Linux arm64: `flashgrep-aarch64-unknown-linux-gnu`
- Windows x86_64: `flashgrep-x86_64-pc-windows-msvc.exe`
- Windows arm64: `flashgrep-aarch64-pc-windows-msvc.exe`

BitFun dev/build scripts load the daemon from this repository-relative path.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added resources/flashgrep/flashgrep-x86_64-apple-darwin
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed resources/flashgrep/flashgrep.exe
Binary file not shown.
51 changes: 37 additions & 14 deletions scripts/dev.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -544,26 +544,49 @@ async function startDesktopPreview() {
await new Promise(() => {});
}

function flashgrepBinaryName() {
return process.platform === 'win32' ? 'flashgrep.exe' : 'flashgrep';
function flashgrepBinaryNames() {
if (process.platform === 'win32' && process.arch === 'x64') {
return ['flashgrep-x86_64-pc-windows-msvc.exe'];
}
if (process.platform === 'win32' && process.arch === 'arm64') {
return ['flashgrep-aarch64-pc-windows-msvc.exe'];
}
if (process.platform === 'darwin' && process.arch === 'x64') {
return ['flashgrep-x86_64-apple-darwin'];
}
if (process.platform === 'darwin' && process.arch === 'arm64') {
return ['flashgrep-aarch64-apple-darwin'];
}
if (process.platform === 'linux' && process.arch === 'x64') {
return ['flashgrep-x86_64-unknown-linux-gnu'];
}
if (process.platform === 'linux' && process.arch === 'arm64') {
return ['flashgrep-aarch64-unknown-linux-gnu'];
}
return [process.platform === 'win32' ? 'flashgrep.exe' : 'flashgrep'];
}

function flashgrepBinaryPath() {
return path.join(ROOT_DIR, 'resources', 'flashgrep', flashgrepBinaryName());
function flashgrepBinaryName() {
return flashgrepBinaryNames()[0];
}

function ensureFlashgrepBinary() {
const binaryPath = flashgrepBinaryPath();
if (!fs.existsSync(binaryPath)) {
return {
ok: false,
error: new Error(
`flashgrep binary not found: ${binaryPath}. Put the prebuilt daemon binary at resources/flashgrep/${flashgrepBinaryName()}`
),
};
for (const binaryName of flashgrepBinaryNames()) {
const binaryPath = path.join(ROOT_DIR, 'resources', 'flashgrep', binaryName);
if (!fs.existsSync(binaryPath)) {
continue;
}
return { ok: true, binaryPath };
}

return { ok: true, binaryPath };
return {
ok: false,
error: new Error(
`flashgrep binary not found for ${process.platform}/${process.arch}. Expected one of: ${flashgrepBinaryNames()
.map((name) => `resources/flashgrep/${name}`)
.join(', ')}`
),
};
}

async function ensureFlashgrepBundleResource() {
Expand Down Expand Up @@ -685,7 +708,7 @@ async function main() {
if (mode === 'desktop') {
await ensureDesktopOpenSslIfNeeded();
const desktopDir = path.join(ROOT_DIR, 'src/apps/desktop');
const tauriConfig = path.join(desktopDir, 'tauri.conf.json');
const tauriConfig = path.join(desktopDir, 'tauri.dev.conf.json');
if (process.platform === 'win32') {
// Running the generated .cmd shim directly via spawn is flaky on Windows.
// Use cmd.exe with an explicit args array so the desktop app directory
Expand Down
48 changes: 38 additions & 10 deletions scripts/prepare-flashgrep-resource.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,52 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, '..');
const RESOURCE_DIR = join(ROOT, 'resources', 'flashgrep');

export function flashgrepBinaryNames() {
if (process.platform === 'win32' && process.arch === 'x64') {
return ['flashgrep-x86_64-pc-windows-msvc.exe'];
}
if (process.platform === 'win32' && process.arch === 'arm64') {
return ['flashgrep-aarch64-pc-windows-msvc.exe'];
}
if (process.platform === 'darwin' && process.arch === 'x64') {
return ['flashgrep-x86_64-apple-darwin'];
}
if (process.platform === 'darwin' && process.arch === 'arm64') {
return ['flashgrep-aarch64-apple-darwin'];
}
if (process.platform === 'linux' && process.arch === 'x64') {
return ['flashgrep-x86_64-unknown-linux-gnu'];
}
if (process.platform === 'linux' && process.arch === 'arm64') {
return ['flashgrep-aarch64-unknown-linux-gnu'];
}
return [process.platform === 'win32' ? 'flashgrep.exe' : 'flashgrep'];
}

export function flashgrepBinaryName() {
return process.platform === 'win32' ? 'flashgrep.exe' : 'flashgrep';
return flashgrepBinaryNames()[0];
}

export function flashgrepBinaryPath() {
return join(RESOURCE_DIR, flashgrepBinaryName());
}

export function ensureFlashgrepBinary() {
const binaryPath = flashgrepBinaryPath();
if (!existsSync(binaryPath)) {
throw new Error(
`flashgrep binary not found: ${binaryPath}. Put the prebuilt daemon binary at resources/flashgrep/${flashgrepBinaryName()}`
);
}
for (const binaryName of flashgrepBinaryNames()) {
const binaryPath = join(RESOURCE_DIR, binaryName);
if (!existsSync(binaryPath)) {
continue;
}

if (process.platform !== 'win32') {
chmodSync(binaryPath, statSync(binaryPath).mode | 0o111);
if (process.platform !== 'win32') {
chmodSync(binaryPath, statSync(binaryPath).mode | 0o111);
}
return binaryPath;
}
return binaryPath;

throw new Error(
`flashgrep binary not found for ${process.platform}/${process.arch}. Expected one of: ${flashgrepBinaryNames()
.map((name) => `resources/flashgrep/${name}`)
.join(', ')}`
);
}
48 changes: 32 additions & 16 deletions src/apps/desktop/src/api/search_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use crate::api::app_state::AppState;
use bitfun_core::infrastructure::{FileSearchResult, FileSearchResultGroup, SearchMatchType};
use bitfun_core::service::remote_ssh::workspace_state::is_remote_path;
use bitfun_core::service::search::{
ContentSearchResult, WorkspaceSearchBackend, WorkspaceSearchRepoPhase,
workspace_search_daemon_available, workspace_search_feature_enabled, ContentSearchResult,
WorkspaceSearchBackend, WorkspaceSearchRepoPhase,
};
use serde::{Deserialize, Serialize};
use tauri::State;
Expand All @@ -24,8 +25,31 @@ pub struct SearchMetadataResponse {
pub matched_occurrences: usize,
}

async fn workspace_search_unavailable_message(root_path: &str) -> Option<String> {
if is_remote_path(root_path.trim()).await {
return Some(
"Remote workspace search status is not managed by BitFun workspace search".to_string(),
);
}

if !workspace_search_feature_enabled().await {
return Some(
"Workspace search is disabled. Enable it in Settings > Session Config to use accelerated workspace search.".to_string(),
);
}

if !workspace_search_daemon_available() {
return Some(
"Workspace search daemon is unavailable. BitFun will continue using legacy search."
.to_string(),
);
}

None
}

pub(crate) async fn should_use_workspace_search(root_path: &str) -> bool {
!is_remote_path(root_path.trim()).await
workspace_search_unavailable_message(root_path).await.is_none()
}

pub(crate) async fn search_file_contents_via_workspace_search(
Expand Down Expand Up @@ -113,10 +137,8 @@ pub async fn search_get_repo_status(
state: State<'_, AppState>,
request: SearchRepoIndexRequest,
) -> Result<serde_json::Value, String> {
if !should_use_workspace_search(&request.root_path).await {
return Err(
"Remote workspace search status is not managed by BitFun workspace search".to_string(),
);
if let Some(message) = workspace_search_unavailable_message(&request.root_path).await {
return Err(message);
}

state
Expand All @@ -132,11 +154,8 @@ pub async fn search_build_index(
state: State<'_, AppState>,
request: SearchRepoIndexRequest,
) -> Result<serde_json::Value, String> {
if !should_use_workspace_search(&request.root_path).await {
return Err(
"Remote workspace search indexing is not managed by BitFun workspace search"
.to_string(),
);
if let Some(message) = workspace_search_unavailable_message(&request.root_path).await {
return Err(message);
}

state
Expand All @@ -152,11 +171,8 @@ pub async fn search_rebuild_index(
state: State<'_, AppState>,
request: SearchRepoIndexRequest,
) -> Result<serde_json::Value, String> {
if !should_use_workspace_search(&request.root_path).await {
return Err(
"Remote workspace search indexing is not managed by BitFun workspace search"
.to_string(),
);
if let Some(message) = workspace_search_unavailable_message(&request.root_path).await {
return Err(message);
}

state
Expand Down
2 changes: 2 additions & 0 deletions src/apps/desktop/src/api/workspace_activation.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::api::app_state::AppState;
use bitfun_core::service::search::workspace_search_runtime_available;
use bitfun_core::service::remote_ssh::workspace_state::is_remote_path;
use bitfun_core::service::workspace::{WorkspaceInfo, WorkspaceKind};
use log::{debug, info, warn};
Expand Down Expand Up @@ -70,6 +71,7 @@ async fn warm_workspace_background_services(

if workspace_info.workspace_kind != WorkspaceKind::Remote
&& is_workspace_active(&workspace_path, &target_path).await
&& workspace_search_runtime_available().await
{
let search_started_at = Instant::now();
match workspace_search_service.open_repo(&target_path).await {
Expand Down
Loading
Loading