Skip to content

Commit 6c373a7

Browse files
committed
Update hypgrep demo to use wildchat
1 parent abd8945 commit 6c373a7

5 files changed

Lines changed: 100 additions & 54 deletions

File tree

hyparquet/package.json

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,24 @@
1414
},
1515
"dependencies": {
1616
"hightable": "0.26.4",
17-
"hyparquet": "1.25.8",
17+
"hyparquet": "1.27.1",
1818
"hyparquet-compressors": "1.1.1",
1919
"hyperparam": "0.4.14",
20-
"react": "19.2.6",
21-
"react-dom": "19.2.6"
20+
"react": "19.2.8",
21+
"react-dom": "19.2.8"
2222
},
2323
"devDependencies": {
24-
"@types/react": "19.2.14",
25-
"@types/react-dom": "19.2.3",
26-
"@vitejs/plugin-react": "6.0.2",
27-
"eslint": "9.39.4",
24+
"@types/react": "19.2.18",
25+
"@types/react-dom": "19.2.4",
26+
"@vitejs/plugin-react": "6.0.5",
27+
"eslint": "9.39.5",
2828
"eslint-plugin-react": "7.37.5",
2929
"eslint-plugin-react-hooks": "7.1.1",
30-
"eslint-plugin-react-refresh": "0.5.2",
31-
"globals": "17.6.0",
30+
"eslint-plugin-react-refresh": "0.5.3",
31+
"globals": "17.8.0",
3232
"typescript": "6.0.3",
33-
"typescript-eslint": "8.59.3",
34-
"vite": "8.0.13",
35-
"vitest": "4.1.6"
33+
"typescript-eslint": "8.65.0",
34+
"vite": "8.2.0",
35+
"vitest": "4.1.10"
3636
}
3737
}

hypgrep/package.json

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,26 @@
1515
},
1616
"dependencies": {
1717
"hightable": "0.26.4",
18-
"hyparquet": "1.26.0",
18+
"hyparquet": "1.27.1",
1919
"hyparquet-compressors": "1.1.1",
2020
"hyperparam": "0.4.14",
21-
"hypgrep": "0.2.0",
22-
"react": "19.2.6",
23-
"react-dom": "19.2.6"
21+
"hypgrep": "0.4.1",
22+
"react": "19.2.8",
23+
"react-dom": "19.2.8"
2424
},
2525
"devDependencies": {
26-
"@types/react": "19.2.15",
26+
"@types/react": "19.2.17",
2727
"@types/react-dom": "19.2.3",
28-
"@vitejs/plugin-react": "6.0.2",
29-
"@vitest/coverage-v8": "4.1.7",
28+
"@vitejs/plugin-react": "6.0.5",
29+
"@vitest/coverage-v8": "4.1.10",
3030
"eslint": "9.39.4",
3131
"eslint-plugin-react": "7.37.5",
3232
"eslint-plugin-react-hooks": "7.1.1",
33-
"eslint-plugin-react-refresh": "0.5.2",
34-
"globals": "17.6.0",
33+
"eslint-plugin-react-refresh": "0.5.3",
34+
"globals": "17.8.0",
3535
"typescript": "6.0.3",
36-
"typescript-eslint": "8.60.0",
37-
"vite": "8.0.14",
38-
"vitest": "4.1.7"
36+
"typescript-eslint": "8.65.0",
37+
"vite": "8.2.0",
38+
"vitest": "4.1.10"
3939
}
4040
}

hypgrep/src/App.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import Layout from './Layout.js'
66
import Page, { PageProps } from './Page.js'
77
import Welcome from './Welcome.js'
88

9-
const exampleUrl = 'https://s3.hyperparam.app/hypgrep/wiki_en100.parquet'
9+
// s3://hyperparam-public/hypgrep/wildchat.parquet
10+
const exampleUrl = 'https://s3.hyperparam.app/hypgrep/wildchat.parquet'
1011
const welcomeDismissedKey = 'hypgrep-welcome-dismissed'
1112

1213
function hasDismissedWelcome(): boolean {
@@ -18,9 +19,8 @@ function setWelcomeDismissed(): void {
1819
}
1920

2021
export default function App(): ReactNode {
21-
// Source parquet to grep: `?key=https://...` overrides the Wikipedia default
22-
// (e.g. a FineGrep shard in S3). The matching `.index.parquet` is inferred
23-
// downstream in Page.
22+
// Source parquet to grep: `?key=https://...` overrides the WildChat default.
23+
// The matching `.index.parquet` is inferred downstream in Page.
2424
const sourceUrl = new URLSearchParams(location.search).get('key') ?? exampleUrl
2525

2626
const [error, setError] = useState<Error>()

hypgrep/src/Page.tsx

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,31 @@ function asyncBufferFactory({ url, byteLength }: { url: string; byteLength?: num
2222
return cached
2323
}
2424

25+
const exampleQueries = ['certain', 'javascript', 'python', 'import (numpy|pandas)']
26+
27+
// A grep query with regex metacharacters that compiles is run as a RegExp;
28+
// anything else is a plain substring.
29+
function parseGrepQuery(input: string): string | RegExp {
30+
if (!/[[\](){}.*+?^$|\\]/.test(input)) return input
31+
try {
32+
return new RegExp(input)
33+
} catch {
34+
return input
35+
}
36+
}
37+
38+
function grepMatch(value: string, rawQuery: string): { index: number; length: number } | undefined {
39+
const query = parseGrepQuery(rawQuery)
40+
if (query instanceof RegExp) {
41+
const match = new RegExp(query.source, query.flags).exec(value)
42+
return match ? { index: match.index, length: match[0].length } : undefined
43+
}
44+
const index = value.toLowerCase().indexOf(rawQuery.toLowerCase())
45+
return index < 0 ? undefined : { index, length: rawQuery.length }
46+
}
47+
2548
/**
2649
* Hypgrep demo page
27-
* Try "Vongphachanh" or "gratianopolitanus" as a search term
2850
*
2951
* @param {Object} props
3052
* @returns {ReactNode}
@@ -61,7 +83,7 @@ export default function Page({ df, name, byteLength, setError }: PageProps): Rea
6183
const url = name
6284
const rowGen = parquetFind({
6385
url,
64-
query,
86+
query: parseGrepQuery(query),
6587
limit: 20,
6688
asyncBufferFactory,
6789
indexMetadata,
@@ -101,31 +123,18 @@ export default function Page({ df, name, byteLength, setError }: PageProps): Rea
101123
}, [name, setError])
102124

103125
const renderCellContent = useCallback(({ cell, stringify }: CellContentProps) => {
104-
// Find first keyword match and highlight it
105-
const queryKeys = query.split(' ').map(q => q.toLowerCase())
106126
const value: unknown = cell?.value
107-
if (typeof value === 'string' && queryKeys.length > 0) {
108-
const lowerValue = value.toLowerCase()
109-
let firstIndex = -1
110-
let firstLength = 0
111-
for (const q of queryKeys) {
112-
const index = lowerValue.indexOf(q)
113-
if (index >= 0 && (firstIndex === -1 || index < firstIndex)) {
114-
firstIndex = index
115-
firstLength = q.length
116-
}
117-
}
118-
if (firstIndex >= 0) {
119-
const truncateBefore = firstIndex > 20 ? '...' : ''
120-
return <>
121-
{truncateBefore}
122-
{value.slice(0, firstIndex).slice(-20)}
123-
<mark>{value.slice(firstIndex, firstIndex + firstLength)}</mark>
124-
{value.slice(firstIndex + firstLength)}
125-
</>
126-
}
127-
}
128-
return stringify(value)
127+
if (typeof value !== 'string') return stringify(value)
128+
const match = grepMatch(value, query)
129+
if (!match) return stringify(value)
130+
const { index, length } = match
131+
const truncateBefore = index > 20 ? '...' : ''
132+
return <>
133+
{truncateBefore}
134+
{value.slice(0, index).slice(-20)}
135+
<mark>{value.slice(index, index + length)}</mark>
136+
{value.slice(index + length)}
137+
</>
129138
}, [query])
130139

131140
return <>
@@ -147,6 +156,14 @@ export default function Page({ df, name, byteLength, setError }: PageProps): Rea
147156
/>
148157
</div>
149158
</div>
159+
{!query && <div className='examples-row'>
160+
<span className='examples-label'>Try:</span>
161+
<div className='examples'>
162+
{exampleQueries.map(example =>
163+
<button key={example} className='example-chip' onClick={() => { setQuery(example) }}>{example}</button>,
164+
)}
165+
</div>
166+
</div>}
150167
<HighTable
151168
focus={false}
152169
cacheKey={name}

hypgrep/src/index.css

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,35 @@ main {
168168
gap: 10px;
169169
}
170170

171+
.examples-row {
172+
align-items: baseline;
173+
display: flex;
174+
gap: 8px;
175+
padding: 6px 12px;
176+
}
177+
.examples-label {
178+
color: #666;
179+
font-size: 12px;
180+
}
181+
.examples {
182+
display: flex;
183+
flex-wrap: wrap;
184+
gap: 6px;
185+
}
186+
.example-chip {
187+
background: #efeaf8;
188+
border: 1px solid #d8cef0;
189+
border-radius: 14px;
190+
color: #3a276e;
191+
cursor: pointer;
192+
font-size: 12px;
193+
padding: 3px 12px;
194+
}
195+
.example-chip:hover,
196+
.example-chip:focus {
197+
background: #e1d6f5;
198+
}
199+
171200
/* welcome modal */
172201
.modal-overlay {
173202
position: fixed;

0 commit comments

Comments
 (0)