mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-11-28 04:47:42 +03:00
use codevier when showing search results
This commit is contained in:
parent
d4d1a8e3fb
commit
396a932111
@ -1,47 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import type { ProcessedSearchResult } from '.';
|
||||
|
||||
export let processedResult: ProcessedSearchResult;
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<div class="mb-4">
|
||||
<p class="mb-2 flex text-lg">
|
||||
<span>{processedResult.searchResult.filePath}</span>
|
||||
<span class="flex-grow" />
|
||||
<span>{formatDistanceToNow(processedResult.timestamp)} ago</span>
|
||||
</p>
|
||||
<div
|
||||
class="overflow-y-auto rounded-lg border border-zinc-700 bg-[#2F2F33] text-[#EBDBB2] drop-shadow-lg"
|
||||
>
|
||||
{#each processedResult.hunks as hunk, i}
|
||||
{#if i > 0}
|
||||
<div class="border-b border-[#52525B]" />
|
||||
{/if}
|
||||
<div class="flex flex-col px-6 py-3">
|
||||
{#each hunk.lines as line}
|
||||
{#if !line.hidden}
|
||||
<div class="mb-px flex font-mono leading-4">
|
||||
<span class="w-6 flex-shrink text-[#928374]"
|
||||
>{line.lineNumber ? line.lineNumber : ''}</span
|
||||
>
|
||||
<pre
|
||||
class="flex-grow rounded-sm
|
||||
{line.operation === 'add'
|
||||
? 'bg-[#14FF00]/20'
|
||||
: line.operation === 'remove'
|
||||
? 'bg-[#FF0000]/20'
|
||||
: ''}
|
||||
">{line.contentBeforeHit}<span class="rounded-sm bg-[#AC8F2F]">{line.contentAtHit}</span
|
||||
>{line.contentAfterHit}</pre>
|
||||
</div>
|
||||
{:else}
|
||||
<!-- <span>hidden</span> -->
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,23 +0,0 @@
|
||||
export { default as RenderedSearchResult } from './RenderedSearchResult.svelte';
|
||||
|
||||
import type { SearchResult } from '$lib/search';
|
||||
|
||||
export type ProcessedSearchResultLine = {
|
||||
hidden: boolean;
|
||||
contentBeforeHit: string;
|
||||
contentAtHit: string;
|
||||
contentAfterHit: string;
|
||||
operation: string;
|
||||
lineNumber: number | undefined;
|
||||
hasKeyword: boolean;
|
||||
};
|
||||
|
||||
export type ProcessedSearchRestultHunk = {
|
||||
lines: ProcessedSearchResultLine[];
|
||||
};
|
||||
|
||||
export type ProcessedSearchResult = {
|
||||
searchResult: SearchResult;
|
||||
hunks: ProcessedSearchRestultHunk[];
|
||||
timestamp: Date;
|
||||
};
|
@ -1,135 +0,0 @@
|
||||
import { listFiles } from '$lib/sessions';
|
||||
import { list as listDeltas } from '$lib/deltas';
|
||||
import type { SearchResult } from '$lib';
|
||||
import { structuredPatch } from 'diff';
|
||||
import type { Delta } from '$lib/deltas';
|
||||
import { Operation } from '$lib/deltas';
|
||||
import type { ProcessedSearchResult, ProcessedSearchRestultHunk } from '.';
|
||||
|
||||
export const processSearchResult = async (
|
||||
searchResult: SearchResult,
|
||||
query: string
|
||||
): Promise<ProcessedSearchResult> => {
|
||||
const [files, deltas] = await Promise.all([
|
||||
listFiles({
|
||||
projectId: searchResult.projectId,
|
||||
sessionId: searchResult.sessionId,
|
||||
paths: [searchResult.filePath]
|
||||
}),
|
||||
listDeltas({
|
||||
projectId: searchResult.projectId,
|
||||
sessionId: searchResult.sessionId,
|
||||
paths: [searchResult.filePath]
|
||||
})
|
||||
]);
|
||||
const hunks = getDiffHunksWithSearchTerm(
|
||||
files[searchResult.filePath],
|
||||
deltas[searchResult.filePath],
|
||||
searchResult.index,
|
||||
query
|
||||
);
|
||||
|
||||
const processedHunks = [];
|
||||
for (let i = 0; i < hunks.length; i++) {
|
||||
const processedHunk: ProcessedSearchRestultHunk = {
|
||||
lines: processHunkLines(hunks[i].lines, hunks[i].newStart, query)
|
||||
};
|
||||
processedHunks.push(processedHunk);
|
||||
}
|
||||
|
||||
const processedSearchResult: ProcessedSearchResult = {
|
||||
searchResult: searchResult,
|
||||
hunks: processedHunks,
|
||||
timestamp: new Date(deltas[searchResult.filePath][searchResult.index].timestampMs)
|
||||
};
|
||||
return processedSearchResult;
|
||||
};
|
||||
|
||||
const applyDeltas = (text: string, deltas: Delta[]) => {
|
||||
const operations = deltas.flatMap((delta) => delta.operations);
|
||||
|
||||
operations.forEach((operation) => {
|
||||
if (Operation.isInsert(operation)) {
|
||||
text =
|
||||
text.slice(0, operation.insert[0]) + operation.insert[1] + text.slice(operation.insert[0]);
|
||||
} else if (Operation.isDelete(operation)) {
|
||||
text =
|
||||
text.slice(0, operation.delete[0]) + text.slice(operation.delete[0] + operation.delete[1]);
|
||||
}
|
||||
});
|
||||
return text;
|
||||
};
|
||||
|
||||
const getDiffHunksWithSearchTerm = (
|
||||
original: string,
|
||||
deltas: Delta[],
|
||||
idx: number,
|
||||
query: string
|
||||
) => {
|
||||
if (!original) return [];
|
||||
return structuredPatch(
|
||||
'file',
|
||||
'file',
|
||||
applyDeltas(original, deltas.slice(0, idx)),
|
||||
applyDeltas(original, [deltas[idx]]),
|
||||
'header',
|
||||
'header',
|
||||
{ context: 1 }
|
||||
).hunks.filter((hunk) => hunk.lines.some((l) => l.includes(query)));
|
||||
};
|
||||
|
||||
const processHunkLines = (lines: string[], newStart: number, query: string) => {
|
||||
const outLines = [];
|
||||
|
||||
let lineNumber = newStart;
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
|
||||
let contentBeforeHit = '';
|
||||
let querySubstring = '';
|
||||
let contentAfterHit = '';
|
||||
if (!line.includes(query)) {
|
||||
contentBeforeHit = line.slice(1);
|
||||
} else {
|
||||
const firstCharIndex = line.indexOf(query);
|
||||
const lastCharIndex = firstCharIndex + query.length - 1;
|
||||
contentBeforeHit = line.slice(1, firstCharIndex);
|
||||
querySubstring = line.slice(firstCharIndex, lastCharIndex + 1);
|
||||
contentAfterHit = line.slice(lastCharIndex + 1);
|
||||
}
|
||||
|
||||
outLines.push({
|
||||
hidden: false,
|
||||
contentBeforeHit: contentBeforeHit,
|
||||
contentAtHit: querySubstring,
|
||||
contentAfterHit: contentAfterHit,
|
||||
operation: line.startsWith('+') ? 'add' : line.startsWith('-') ? 'remove' : 'unmodified',
|
||||
lineNumber: !line.startsWith('-') ? lineNumber : undefined,
|
||||
hasKeyword: line.includes(query)
|
||||
});
|
||||
|
||||
if (!line.startsWith('-')) {
|
||||
lineNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
const out = [];
|
||||
for (let i = 0; i < outLines.length; i++) {
|
||||
const prevLine = outLines[i - 1];
|
||||
const nextLine = outLines[i + 1];
|
||||
const line = outLines[i];
|
||||
if (line.hasKeyword) {
|
||||
out.push(line);
|
||||
} else if (nextLine && nextLine.hasKeyword) {
|
||||
// One line of context before the relevant line
|
||||
out.push(line);
|
||||
} else if (prevLine && prevLine.hasKeyword) {
|
||||
// One line of context after the relevant line
|
||||
out.push(line);
|
||||
} else {
|
||||
line.hidden = true;
|
||||
out.push(line);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
};
|
@ -1,15 +1,17 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import { search } from '$lib';
|
||||
import { RenderedSearchResult, type ProcessedSearchResult } from '$lib/components/search';
|
||||
import { processSearchResult } from '$lib/components/search/process';
|
||||
import { getContext } from 'svelte';
|
||||
import type { Writable } from 'svelte/store';
|
||||
import { listFiles } from '$lib/sessions';
|
||||
import { list as listDeltas, type Delta } from '$lib/deltas';
|
||||
import { CodeViewer } from '$lib/components';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
|
||||
export let data: PageData;
|
||||
const { project } = data;
|
||||
|
||||
let processedResults = [] as ProcessedSearchResult[];
|
||||
let processedResults = [] as { doc: string; deltas: Delta[]; filepath: string }[];
|
||||
let searchTerm: Writable<string> = getContext('searchTerm');
|
||||
let stopProcessing = false;
|
||||
|
||||
@ -29,10 +31,13 @@
|
||||
stopProcessing = false;
|
||||
return;
|
||||
}
|
||||
const processedResult = await processSearchResult(r, query);
|
||||
if (processedResult.hunks && processedResult.hunks.length > 0) {
|
||||
processedResults = [...processedResults, processedResult];
|
||||
}
|
||||
console.log(r);
|
||||
const { sessionId, projectId, filePath } = r;
|
||||
const [doc, deltas] = await Promise.all([
|
||||
listFiles({ projectId, sessionId, paths: [filePath] }).then((r) => r[filePath] ?? ''),
|
||||
listDeltas({ projectId, sessionId, paths: [filePath] }).then((r) => r[filePath] ?? [])
|
||||
]);
|
||||
processedResults = [...processedResults, { doc, deltas, filepath: filePath }];
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -51,9 +56,18 @@
|
||||
{/if}
|
||||
|
||||
<ul class="flex flex-col gap-4">
|
||||
{#each processedResults as r}
|
||||
<li>
|
||||
<RenderedSearchResult processedResult={r} />
|
||||
{#each processedResults as { doc, deltas, filepath }}
|
||||
{@const timestamp = deltas[deltas.length - 1].timestampMs}
|
||||
<li class="flex flex-col gap-2">
|
||||
<p class="flex justify-between text-lg">
|
||||
<span>{filepath}</span>
|
||||
<span>{formatDistanceToNow(timestamp)} ago</span>
|
||||
</p>
|
||||
<div
|
||||
class="flex-auto overflow-auto rounded-lg border border-zinc-700 bg-[#2F2F33] text-[#EBDBB2] drop-shadow-lg"
|
||||
>
|
||||
<CodeViewer {doc} {deltas} {filepath} paddingLines={4} />
|
||||
</div>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
Loading…
Reference in New Issue
Block a user