Browse Source

fix repo search

Nostr-Signature: e9eff432fe83e0b629e217fe4c00b19858a797127ff0dad28e248e02629d938c 573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc 47c81818e91fa1b2760ceee78da38a82698c9609df0acc7f4dfaae7c6e7025c870cf2a8c34f3ea9c09dc9110be74f4605762a903d722f8bc15d2a0a2fd7edd04
main
Silberengel 3 weeks ago
parent
commit
4428fd4f8c
  1. 1
      nostr/commit-signatures.jsonl
  2. 159
      src/lib/styles/repo.css
  3. 173
      src/routes/api/code-search/+server.ts
  4. 190
      src/routes/api/repos/[npub]/[repo]/code-search/+server.ts
  5. 33
      src/routes/repos/[npub]/[repo]/+page.svelte

1
nostr/commit-signatures.jsonl

@ -73,3 +73,4 @@
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771956701,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","implemented releases and code serach\nadd contributors to private repos\napply/merge buttons for patches and PRs\nhighlgihts and comments on patches and prs\nadded tagged downloads"]],"content":"Signed commit: implemented releases and code serach\nadd contributors to private repos\napply/merge buttons for patches and PRs\nhighlgihts and comments on patches and prs\nadded tagged downloads","id":"e822be2b0fbf3285bbedf9d8f9d1692b5503080af17a4d28941a1dc81c96187c","sig":"70c8b6e499551ce43478116cf694992102a29572d5380cbe3b070a3026bc2c9e35177587712c7414f25d1ca50038c9614479f7758bbdc48f69cc44cd52bf4842"} {"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771956701,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","implemented releases and code serach\nadd contributors to private repos\napply/merge buttons for patches and PRs\nhighlgihts and comments on patches and prs\nadded tagged downloads"]],"content":"Signed commit: implemented releases and code serach\nadd contributors to private repos\napply/merge buttons for patches and PRs\nhighlgihts and comments on patches and prs\nadded tagged downloads","id":"e822be2b0fbf3285bbedf9d8f9d1692b5503080af17a4d28941a1dc81c96187c","sig":"70c8b6e499551ce43478116cf694992102a29572d5380cbe3b070a3026bc2c9e35177587712c7414f25d1ca50038c9614479f7758bbdc48f69cc44cd52bf4842"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771958124,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","fix crash on download"]],"content":"Signed commit: fix crash on download","id":"3fdcc681cdda4b523f9c3752309b8cf740b58178ca02dcff4ef97ec714bf394c","sig":"e405612a5aafeef66818f0a3c683e322f862d1fc3c662c32f618f516fd8c11ece5f4539b94893583301d31fd2ecd3de3b6d7a953505e2696915afe10710a16d7"} {"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771958124,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","fix crash on download"]],"content":"Signed commit: fix crash on download","id":"3fdcc681cdda4b523f9c3752309b8cf740b58178ca02dcff4ef97ec714bf394c","sig":"e405612a5aafeef66818f0a3c683e322f862d1fc3c662c32f618f516fd8c11ece5f4539b94893583301d31fd2ecd3de3b6d7a953505e2696915afe10710a16d7"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771964922,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","fix page crash on download"]],"content":"Signed commit: fix page crash on download","id":"eafa232557affbacb430b467507febc201f0a8f54f4b9ecf57e315c32e51a589","sig":"53c58aabe0bfad6e432a8bb980c2046fc14bc8163825fde2ac766a449ce4418adb1049ac732c7fc7ecc7ad050539fb68c023d54f2b6c390e478616b5c0b91a31"} {"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771964922,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","fix page crash on download"]],"content":"Signed commit: fix page crash on download","id":"eafa232557affbacb430b467507febc201f0a8f54f4b9ecf57e315c32e51a589","sig":"53c58aabe0bfad6e432a8bb980c2046fc14bc8163825fde2ac766a449ce4418adb1049ac732c7fc7ecc7ad050539fb68c023d54f2b6c390e478616b5c0b91a31"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771967413,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","get rid of light theme"]],"content":"Signed commit: get rid of light theme","id":"16cc720587afa7994fdf4d1951934298d731f79d8fe4a3c5d4b9143e3b41abfd","sig":"125b3afa090a8a2679d6e2614163c8c95a42ba6d3323e9682ce94ecff387da8d1abbfffcc61d59646c6925d8e845527570387b012c194deed032fa7d43bceac0"}

159
src/lib/styles/repo.css

@ -934,7 +934,8 @@
.discussions-sidebar, .discussions-sidebar,
.docs-sidebar, .docs-sidebar,
.history-sidebar, .history-sidebar,
.tags-sidebar { .tags-sidebar,
.code-search-sidebar {
width: 100% !important; width: 100% !important;
max-width: 100% !important; max-width: 100% !important;
height: 100%; height: 100%;
@ -955,6 +956,7 @@
.docs-header, .docs-header,
.history-header, .history-header,
.tags-header, .tags-header,
.code-search-header,
.file-tree-header { .file-tree-header {
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;
@ -987,7 +989,8 @@
.discussions-sidebar.hide-on-mobile, .discussions-sidebar.hide-on-mobile,
.docs-sidebar.hide-on-mobile, .docs-sidebar.hide-on-mobile,
.history-sidebar.hide-on-mobile, .history-sidebar.hide-on-mobile,
.tags-sidebar.hide-on-mobile { .tags-sidebar.hide-on-mobile,
.code-search-sidebar.hide-on-mobile {
display: none !important; display: none !important;
} }
@ -995,7 +998,8 @@
.prs-content.hide-on-mobile, .prs-content.hide-on-mobile,
.patches-content.hide-on-mobile, .patches-content.hide-on-mobile,
.discussions-content.hide-on-mobile, .discussions-content.hide-on-mobile,
.docs-content.hide-on-mobile { .docs-content.hide-on-mobile,
.code-search-content.hide-on-mobile {
display: none !important; display: none !important;
} }
@ -1438,7 +1442,8 @@ span.clone-more {
.prs-sidebar, .prs-sidebar,
.patches-sidebar, .patches-sidebar,
.discussions-sidebar, .discussions-sidebar,
.docs-sidebar { .docs-sidebar,
.code-search-sidebar {
width: 300px; width: 300px;
border-right: 1px solid var(--border-color); border-right: 1px solid var(--border-color);
background: var(--bg-secondary); background: var(--bg-secondary);
@ -1460,7 +1465,8 @@ span.clone-more {
.prs-header, .prs-header,
.docs-header, .docs-header,
.patches-header, .patches-header,
.discussions-header { .discussions-header,
.code-search-header {
padding: 1rem; padding: 1rem;
border-bottom: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);
display: flex; display: flex;
@ -1487,10 +1493,12 @@ span.clone-more {
.prs-header h2, .prs-header h2,
.issues-header h2, .issues-header h2,
.history-header h2, .history-header h2,
.tags-header h2 { .tags-header h2,
.code-search-header h2 {
margin: 0; margin: 0;
white-space: nowrap; white-space: nowrap;
flex-shrink: 0; flex-shrink: 0;
color: var(--text-primary); /* Ensure proper contrast in dark themes */
} }
.issues-content, .issues-content,
@ -1499,12 +1507,149 @@ span.clone-more {
.discussions-content, .discussions-content,
.tags-content, .tags-content,
.docs-content, .docs-content,
.commits-content { .commits-content,
.code-search-content {
padding: 1rem; padding: 1rem;
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
} }
/* Code Search Form */
.code-search-form {
margin-bottom: 1.5rem;
}
.search-input-group {
display: flex;
gap: 0.75rem;
align-items: center;
flex-wrap: wrap;
}
.code-search-input {
flex: 1;
min-width: 200px;
padding: 0.5rem 0.75rem;
border: 1px solid var(--border-color);
border-radius: 0.375rem;
background: var(--input-bg);
color: var(--text-primary);
font-size: 0.875rem;
font-family: 'IBM Plex Mono', monospace;
}
.code-search-input:focus {
outline: none;
border-color: var(--input-focus);
box-shadow: 0 0 0 2px var(--focus-ring);
}
.code-search-scope {
padding: 0.5rem 0.75rem;
border: 1px solid var(--border-color);
border-radius: 0.375rem;
background: var(--input-bg);
color: var(--text-primary);
font-size: 0.875rem;
cursor: pointer;
}
.code-search-scope:focus {
outline: none;
border-color: var(--input-focus);
box-shadow: 0 0 0 2px var(--focus-ring);
}
.search-button {
padding: 0.5rem 1rem;
background: var(--button-primary);
color: var(--accent-text, #ffffff);
border: none;
border-radius: 0.375rem;
font-size: 0.875rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.search-button:hover:not(:disabled) {
background: var(--button-primary-hover);
transform: translateY(-1px);
}
.search-button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
/* Code Search Results */
.code-search-results {
margin-top: 1rem;
}
.code-search-results h3 {
margin: 0 0 1rem 0;
color: var(--text-primary);
font-size: 1.1rem;
font-weight: 600;
}
.code-search-result-item {
margin-bottom: 1.5rem;
padding: 1rem;
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 0.375rem;
transition: all 0.2s ease;
}
.code-search-result-item:hover {
border-color: var(--accent);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.result-header {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 0.75rem;
flex-wrap: wrap;
}
.result-file {
font-weight: 600;
color: var(--text-primary);
font-family: 'IBM Plex Mono', monospace;
font-size: 0.9rem;
}
.result-line {
color: var(--text-secondary);
font-size: 0.85rem;
font-family: 'IBM Plex Mono', monospace;
}
.result-repo {
color: var(--text-muted);
font-size: 0.85rem;
font-family: 'IBM Plex Mono', monospace;
}
.result-content {
margin: 0;
padding: 0.75rem;
background: var(--bg-tertiary);
border: 1px solid var(--border-color);
border-radius: 0.25rem;
overflow-x: auto;
font-family: 'IBM Plex Mono', monospace;
font-size: 0.85rem;
line-height: 1.5;
color: var(--text-primary);
white-space: pre-wrap;
word-wrap: break-word;
}
.patch-header, .patch-header,
.issue-header { .issue-header {
display: flex; display: flex;

173
src/routes/api/code-search/+server.ts

@ -17,6 +17,7 @@ import { readdir, stat } from 'fs/promises';
import { join } from 'path'; import { join } from 'path';
import { existsSync } from 'fs'; import { existsSync } from 'fs';
import { simpleGit } from 'simple-git'; import { simpleGit } from 'simple-git';
import { fileManager } from '$lib/services/service-registry.js';
const repoRoot = typeof process !== 'undefined' && process.env?.GIT_REPO_ROOT const repoRoot = typeof process !== 'undefined' && process.env?.GIT_REPO_ROOT
? process.env.GIT_REPO_ROOT ? process.env.GIT_REPO_ROOT
@ -168,60 +169,156 @@ async function searchInRepo(
try { try {
const branches = await git.branchLocal(); const branches = await git.branchLocal();
branch = branches.current || 'HEAD'; branch = branches.current || 'HEAD';
// If no current branch, try common defaults
if (!branch || branch === 'HEAD') {
const allBranches = branches.all.map(b => b.replace(/^remotes\/origin\//, '').replace(/^remotes\//, ''));
branch = allBranches.find(b => b === 'main') || allBranches.find(b => b === 'master') || allBranches[0] || 'main';
}
} catch { } catch {
// Use HEAD if we can't get branch branch = 'main';
} }
const searchQuery = query.trim(); // For bare repositories, we need to use a worktree or search the index
const gitArgs = ['grep', '-n', '-I', '--break', '--heading', searchQuery, branch]; let worktreePath: string | null = null;
try { try {
const grepOutput = await git.raw(gitArgs); // Get the actual branch name (resolve HEAD if needed)
let actualBranch = branch;
if (!grepOutput || !grepOutput.trim()) { if (branch === 'HEAD') {
return []; actualBranch = 'main';
} }
const lines = grepOutput.split('\n'); // Get or create worktree
let currentFile = ''; worktreePath = await fileManager.getWorktree(repoPath, actualBranch, npub, repo);
} catch (worktreeError) {
for (const line of lines) { logger.debug({ error: worktreeError, npub, repo, branch }, 'Could not create worktree, trying git grep with tree reference');
if (!line.trim()) { // Fall back to searching the index
continue; }
}
const searchQuery = query.trim();
// If we have a worktree, search in the worktree
if (worktreePath && existsSync(worktreePath)) {
try {
const worktreeGit = simpleGit(worktreePath);
const gitArgs = ['grep', '-n', '-I', '--break', '--heading', searchQuery];
const grepOutput = await worktreeGit.raw(gitArgs);
if (!line.includes(':')) { if (!grepOutput || !grepOutput.trim()) {
currentFile = line.trim(); return [];
continue;
} }
// Parse git grep output
const lines = grepOutput.split('\n');
let currentFile = '';
const colonIndex = line.indexOf(':'); for (const line of lines) {
if (colonIndex > 0 && currentFile) { if (!line.trim()) {
const lineNumber = parseInt(line.substring(0, colonIndex), 10); continue;
const content = line.substring(colonIndex + 1); }
if (!isNaN(lineNumber) && content) { // Check if this is a filename (no colon)
results.push({ if (!line.includes(':')) {
repo, currentFile = line.trim();
npub, continue;
file: currentFile, }
line: lineNumber,
content: content.trim(), // Parse line:content format
branch: branch === 'HEAD' ? 'HEAD' : branch const colonIndex = line.indexOf(':');
}); if (colonIndex > 0 && currentFile) {
const lineNumber = parseInt(line.substring(0, colonIndex), 10);
const content = line.substring(colonIndex + 1);
if (results.length >= limit) { if (!isNaN(lineNumber) && content) {
break; // Make file path relative to repo root
const relativeFile = currentFile.replace(worktreePath + '/', '').replace(/^\.\//, '');
results.push({
repo,
npub,
file: relativeFile,
line: lineNumber,
content: content.trim(),
branch: branch === 'HEAD' ? 'HEAD' : branch
});
if (results.length >= limit) {
break;
}
} }
} }
} }
} catch (grepError: any) {
// git grep returns exit code 1 when no matches found
if (grepError.message && grepError.message.includes('exit code 1')) {
return [];
}
throw grepError;
} }
} catch (grepError: any) { } else {
// git grep returns exit code 1 when no matches found // Fallback: search in the index using git grep with tree reference
if (grepError.message && grepError.message.includes('exit code 1')) { try {
return []; // Get the tree for the branch
let treeRef = branch;
if (branch === 'HEAD') {
try {
const branchInfo = await git.branch(['-a']);
treeRef = branchInfo.current || 'HEAD';
} catch {
treeRef = 'HEAD';
}
}
// Use git grep with tree reference for bare repos
const gitArgs = ['grep', '-n', '-I', '--break', '--heading', searchQuery, treeRef];
const grepOutput = await git.raw(gitArgs);
if (!grepOutput || !grepOutput.trim()) {
return [];
}
// Parse git grep output
const lines = grepOutput.split('\n');
let currentFile = '';
for (const line of lines) {
if (!line.trim()) {
continue;
}
// Check if this is a filename (no colon)
if (!line.includes(':')) {
currentFile = line.trim();
continue;
}
// Parse line:content format
const colonIndex = line.indexOf(':');
if (colonIndex > 0 && currentFile) {
const lineNumber = parseInt(line.substring(0, colonIndex), 10);
const content = line.substring(colonIndex + 1);
if (!isNaN(lineNumber) && content) {
results.push({
repo,
npub,
file: currentFile,
line: lineNumber,
content: content.trim(),
branch: branch === 'HEAD' ? 'HEAD' : branch
});
if (results.length >= limit) {
break;
}
}
}
}
} catch (grepError: any) {
// git grep returns exit code 1 when no matches found
if (grepError.message && grepError.message.includes('exit code 1')) {
return [];
}
throw grepError;
} }
throw grepError;
} }
} catch (err) { } catch (err) {
logger.debug({ error: err, npub, repo, query }, 'Error searching in repo'); logger.debug({ error: err, npub, repo, query }, 'Error searching in repo');

190
src/routes/api/repos/[npub]/[repo]/code-search/+server.ts

@ -13,6 +13,7 @@ import { join } from 'path';
import { existsSync } from 'fs'; import { existsSync } from 'fs';
import logger from '$lib/services/logger.js'; import logger from '$lib/services/logger.js';
import { simpleGit } from 'simple-git'; import { simpleGit } from 'simple-git';
import { readFile } from 'fs/promises';
const repoRoot = typeof process !== 'undefined' && process.env?.GIT_REPO_ROOT const repoRoot = typeof process !== 'undefined' && process.env?.GIT_REPO_ROOT
? process.env.GIT_REPO_ROOT ? process.env.GIT_REPO_ROOT
@ -48,80 +49,155 @@ export const GET: RequestHandler = createRepoGetHandler(
const git = simpleGit(repoPath); const git = simpleGit(repoPath);
const results: CodeSearchResult[] = []; const results: CodeSearchResult[] = [];
// Use git grep to search file contents // For bare repositories, we need to use a worktree or search the index
// git grep -n -I --break --heading -i "query" branch // First, try to get or create a worktree for the branch
// -n: show line numbers let worktreePath: string | null = null;
// -I: ignore binary files
// --break: add blank line between matches from different files
// --heading: show filename before matches
// -i: case-insensitive (optional, we'll make it configurable)
const searchQuery = query.trim();
const gitArgs = ['grep', '-n', '-I', '--break', '--heading', searchQuery, branch];
try { try {
const grepOutput = await git.raw(gitArgs); // Get the actual branch name (resolve HEAD if needed)
let actualBranch = branch;
if (!grepOutput || !grepOutput.trim()) { if (branch === 'HEAD') {
return json([]); try {
const branchInfo = await git.branch(['-a']);
actualBranch = branchInfo.current || 'main';
// If no current branch, try common defaults
if (!actualBranch || actualBranch === 'HEAD') {
const allBranches = branchInfo.all.map(b => b.replace(/^remotes\/origin\//, '').replace(/^remotes\//, ''));
actualBranch = allBranches.find(b => b === 'main') || allBranches.find(b => b === 'master') || allBranches[0] || 'main';
}
} catch {
actualBranch = 'main';
}
} }
// Parse git grep output // Get or create worktree
// Format: worktreePath = await fileManager.getWorktree(repoPath, actualBranch, context.npub, context.repo);
// filename } catch (worktreeError) {
// line:content logger.debug({ error: worktreeError, npub: context.npub, repo: context.repo, branch }, 'Could not create worktree, trying git grep with --cached');
// line:content // Fall back to searching the index
// }
// filename2
// line:content const searchQuery = query.trim();
const lines = grepOutput.split('\n'); // If we have a worktree, search in the worktree
let currentFile = ''; if (worktreePath && existsSync(worktreePath)) {
try {
for (const line of lines) { const worktreeGit = simpleGit(worktreePath);
if (!line.trim()) { const gitArgs = ['grep', '-n', '-I', '--break', '--heading', searchQuery];
continue; // Skip empty lines const grepOutput = await worktreeGit.raw(gitArgs);
if (!grepOutput || !grepOutput.trim()) {
return json([]);
} }
// Parse git grep output
const lines = grepOutput.split('\n');
let currentFile = '';
// Check if this is a filename (no colon, or starts with a path) for (const line of lines) {
if (!line.includes(':') || line.startsWith('/') || line.match(/^[a-zA-Z0-9_\-./]+$/)) { if (!line.trim()) {
// This might be a filename continue;
// Git grep with --heading shows filename on its own line }
// But we need to be careful - it could also be content with a colon
// If it doesn't have a colon and looks like a path, it's a filename // Check if this is a filename (no colon)
if (!line.includes(':')) { if (!line.includes(':')) {
currentFile = line.trim(); currentFile = line.trim();
continue; continue;
} }
// Parse line:content format
const colonIndex = line.indexOf(':');
if (colonIndex > 0 && currentFile) {
const lineNumber = parseInt(line.substring(0, colonIndex), 10);
const content = line.substring(colonIndex + 1);
if (!isNaN(lineNumber) && content) {
// Make file path relative to repo root
const relativeFile = currentFile.replace(worktreePath + '/', '').replace(/^\.\//, '');
results.push({
file: relativeFile,
line: lineNumber,
content: content.trim(),
branch: branch === 'HEAD' ? 'HEAD' : branch
});
if (results.length >= limit) {
break;
}
}
}
} }
} catch (grepError: any) {
// git grep returns exit code 1 when no matches found
if (grepError.message && grepError.message.includes('exit code 1')) {
return json([]);
}
throw grepError;
}
} else {
// Fallback: search in the index using git grep --cached
try {
// Get the tree for the branch
let treeRef = branch;
if (branch === 'HEAD') {
try {
const branchInfo = await git.branch(['-a']);
treeRef = branchInfo.current || 'HEAD';
} catch {
treeRef = 'HEAD';
}
}
// Use git grep with --cached to search the index
// For bare repos, we can search a specific tree
const gitArgs = ['grep', '-n', '-I', '--break', '--heading', searchQuery, treeRef];
const grepOutput = await git.raw(gitArgs);
// Parse line:content format if (!grepOutput || !grepOutput.trim()) {
const colonIndex = line.indexOf(':'); return json([]);
if (colonIndex > 0 && currentFile) { }
const lineNumber = parseInt(line.substring(0, colonIndex), 10);
const content = line.substring(colonIndex + 1); // Parse git grep output
const lines = grepOutput.split('\n');
let currentFile = '';
for (const line of lines) {
if (!line.trim()) {
continue;
}
// Check if this is a filename (no colon)
if (!line.includes(':')) {
currentFile = line.trim();
continue;
}
if (!isNaN(lineNumber) && content) { // Parse line:content format
results.push({ const colonIndex = line.indexOf(':');
file: currentFile, if (colonIndex > 0 && currentFile) {
line: lineNumber, const lineNumber = parseInt(line.substring(0, colonIndex), 10);
content: content.trim(), const content = line.substring(colonIndex + 1);
branch: branch === 'HEAD' ? 'HEAD' : branch
});
if (results.length >= limit) { if (!isNaN(lineNumber) && content) {
break; results.push({
file: currentFile,
line: lineNumber,
content: content.trim(),
branch: branch === 'HEAD' ? 'HEAD' : branch
});
if (results.length >= limit) {
break;
}
} }
} }
} }
} catch (grepError: any) {
// git grep returns exit code 1 when no matches found
if (grepError.message && grepError.message.includes('exit code 1')) {
return json([]);
}
throw grepError;
} }
} catch (grepError: any) {
// git grep returns exit code 1 when no matches found, which is not an error
if (grepError.message && grepError.message.includes('exit code 1')) {
// No matches found, return empty array
return json([]);
}
throw grepError;
} }
return json(results); return json(results);

33
src/routes/repos/[npub]/[repo]/+page.svelte

@ -4565,22 +4565,37 @@
error = null; error = null;
try { try {
// Get current branch for repo-specific search
const branchParam = codeSearchScope === 'repo' && currentBranch
? `&branch=${encodeURIComponent(currentBranch)}`
: '';
// For "All Repositories", don't pass repo filter - let it search all repos
const url = codeSearchScope === 'repo' const url = codeSearchScope === 'repo'
? `/api/repos/${npub}/${repo}/code-search?q=${encodeURIComponent(codeSearchQuery.trim())}` ? `/api/repos/${npub}/${repo}/code-search?q=${encodeURIComponent(codeSearchQuery.trim())}${branchParam}`
: `/api/code-search?q=${encodeURIComponent(codeSearchQuery.trim())}&repo=${encodeURIComponent(`${npub}/${repo}`)}`; : `/api/code-search?q=${encodeURIComponent(codeSearchQuery.trim())}`;
const response = await fetch(url, { const response = await fetch(url, {
headers: buildApiHeaders() headers: buildApiHeaders()
}); });
if (response.ok) { if (response.ok) {
codeSearchResults = await response.json(); const data = await response.json();
codeSearchResults = Array.isArray(data) ? data : [];
} else { } else {
const errorData = await response.json(); let errorMessage = 'Failed to search code';
throw new Error(errorData.message || 'Failed to search code'); try {
const errorData = await response.json();
errorMessage = errorData.message || errorMessage;
} catch {
errorMessage = `Search failed: ${response.status} ${response.statusText}`;
}
throw new Error(errorMessage);
} }
} catch (err) { } catch (err) {
error = err instanceof Error ? err.message : 'Failed to search code'; const errorMessage = err instanceof Error ? err.message : 'Failed to search code';
console.error('[Code Search] Error:', err);
error = errorMessage;
codeSearchResults = []; codeSearchResults = [];
} finally { } finally {
loadingCodeSearch = false; loadingCodeSearch = false;
@ -6097,7 +6112,11 @@
</div> </div>
{:else if codeSearchQuery.trim() && !loadingCodeSearch} {:else if codeSearchQuery.trim() && !loadingCodeSearch}
<div class="empty-state"> <div class="empty-state">
<p>No results found</p> {#if error}
<p class="error-message">Error: {error}</p>
{:else}
<p>No results found</p>
{/if}
</div> </div>
{/if} {/if}
</div> </div>

Loading…
Cancel
Save