DRY up highlighting code

This commit is contained in:
Matt Rubens
2025-01-15 02:57:33 -05:00
parent ff9b8c33e1
commit 5fa0272b49
5 changed files with 51 additions and 183 deletions

View File

@@ -5,6 +5,7 @@ import { Virtuoso } from "react-virtuoso"
import React, { memo, useMemo, useState, useEffect } from "react"
import { Fzf } from "fzf"
import { formatLargeNumber } from "../../utils/format"
import { highlightFzfMatch } from "../../utils/highlight"
type HistoryViewProps = {
onDone: () => void
@@ -464,49 +465,4 @@ const ExportButton = ({ itemId }: { itemId: string }) => (
</VSCodeButton>
)
const highlightFzfMatch = (text: string, positions: number[], highlightClassName: string = "history-item-highlight") => {
if (!positions.length) return text
const parts: { text: string; highlight: boolean }[] = []
let lastIndex = 0
// Sort positions to ensure we process them in order
positions.sort((a, b) => a - b)
positions.forEach((pos) => {
// Add non-highlighted text before this position
if (pos > lastIndex) {
parts.push({
text: text.substring(lastIndex, pos),
highlight: false
})
}
// Add highlighted character
parts.push({
text: text[pos],
highlight: true
})
lastIndex = pos + 1
})
// Add any remaining text
if (lastIndex < text.length) {
parts.push({
text: text.substring(lastIndex),
highlight: false
})
}
// Build final string
return parts
.map(part =>
part.highlight
? `<span class="${highlightClassName}">${part.text}</span>`
: part.text
)
.join('')
}
export default memo(HistoryView)

View File

@@ -7,6 +7,7 @@ import styled from "styled-components"
import { glamaDefaultModelId } from "../../../../src/shared/api"
import { useExtensionState } from "../../context/ExtensionStateContext"
import { vscode } from "../../utils/vscode"
import { highlightFzfMatch } from "../../utils/highlight"
import { ModelInfoView, normalizeApiConfiguration } from "./ApiOptions"
const GlamaModelPicker: React.FC = () => {
@@ -71,51 +72,6 @@ const GlamaModelPicker: React.FC = () => {
}))
}, [modelIds])
const highlightFzfMatch = (text: string, positions: number[]) => {
if (!positions.length) return text
const parts: { text: string; highlight: boolean }[] = []
let lastIndex = 0
// Sort positions to ensure we process them in order
positions.sort((a, b) => a - b)
positions.forEach((pos) => {
// Add non-highlighted text before this position
if (pos > lastIndex) {
parts.push({
text: text.substring(lastIndex, pos),
highlight: false
})
}
// Add highlighted character
parts.push({
text: text[pos],
highlight: true
})
lastIndex = pos + 1
})
// Add any remaining text
if (lastIndex < text.length) {
parts.push({
text: text.substring(lastIndex),
highlight: false
})
}
// Build final string
return parts
.map(part =>
part.highlight
? `<span class="model-item-highlight">${part.text}</span>`
: part.text
)
.join('')
}
const fzf = useMemo(() => {
return new Fzf(searchableItems, {
selector: item => item.html
@@ -128,7 +84,7 @@ const GlamaModelPicker: React.FC = () => {
const searchResults = fzf.find(searchTerm)
return searchResults.map(result => ({
...result.item,
html: highlightFzfMatch(result.item.html, Array.from(result.positions))
html: highlightFzfMatch(result.item.html, Array.from(result.positions), "model-item-highlight")
}))
}, [searchableItems, searchTerm, fzf])

View File

@@ -5,6 +5,7 @@ import { useRemark } from "react-remark"
import styled from "styled-components"
import { useExtensionState } from "../../context/ExtensionStateContext"
import { vscode } from "../../utils/vscode"
import { highlightFzfMatch } from "../../utils/highlight"
const OpenAiModelPicker: React.FC = () => {
const { apiConfiguration, setApiConfiguration, openAiModels, onUpdateApiConfig } = useExtensionState()
@@ -70,51 +71,6 @@ const OpenAiModelPicker: React.FC = () => {
}))
}, [modelIds])
const highlightFzfMatch = (text: string, positions: number[]) => {
if (!positions.length) return text
const parts: { text: string; highlight: boolean }[] = []
let lastIndex = 0
// Sort positions to ensure we process them in order
positions.sort((a, b) => a - b)
positions.forEach((pos) => {
// Add non-highlighted text before this position
if (pos > lastIndex) {
parts.push({
text: text.substring(lastIndex, pos),
highlight: false
})
}
// Add highlighted character
parts.push({
text: text[pos],
highlight: true
})
lastIndex = pos + 1
})
// Add any remaining text
if (lastIndex < text.length) {
parts.push({
text: text.substring(lastIndex),
highlight: false
})
}
// Build final string
return parts
.map(part =>
part.highlight
? `<span class="model-item-highlight">${part.text}</span>`
: part.text
)
.join('')
}
const fzf = useMemo(() => {
return new Fzf(searchableItems, {
selector: item => item.html
@@ -127,7 +83,7 @@ const OpenAiModelPicker: React.FC = () => {
const searchResults = fzf.find(searchTerm)
return searchResults.map(result => ({
...result.item,
html: highlightFzfMatch(result.item.html, Array.from(result.positions))
html: highlightFzfMatch(result.item.html, Array.from(result.positions), "model-item-highlight")
}))
}, [searchableItems, searchTerm, fzf])

View File

@@ -7,6 +7,7 @@ import styled from "styled-components"
import { openRouterDefaultModelId } from "../../../../src/shared/api"
import { useExtensionState } from "../../context/ExtensionStateContext"
import { vscode } from "../../utils/vscode"
import { highlightFzfMatch } from "../../utils/highlight"
import { ModelInfoView, normalizeApiConfiguration } from "./ApiOptions"
const OpenRouterModelPicker: React.FC = () => {
@@ -70,51 +71,6 @@ const OpenRouterModelPicker: React.FC = () => {
}))
}, [modelIds])
const highlightFzfMatch = (text: string, positions: number[]) => {
if (!positions.length) return text
const parts: { text: string; highlight: boolean }[] = []
let lastIndex = 0
// Sort positions to ensure we process them in order
positions.sort((a, b) => a - b)
positions.forEach((pos) => {
// Add non-highlighted text before this position
if (pos > lastIndex) {
parts.push({
text: text.substring(lastIndex, pos),
highlight: false
})
}
// Add highlighted character
parts.push({
text: text[pos],
highlight: true
})
lastIndex = pos + 1
})
// Add any remaining text
if (lastIndex < text.length) {
parts.push({
text: text.substring(lastIndex),
highlight: false
})
}
// Build final string
return parts
.map(part =>
part.highlight
? `<span class="model-item-highlight">${part.text}</span>`
: part.text
)
.join('')
}
const fzf = useMemo(() => {
return new Fzf(searchableItems, {
selector: item => item.html
@@ -127,7 +83,7 @@ const OpenRouterModelPicker: React.FC = () => {
const searchResults = fzf.find(searchTerm)
return searchResults.map(result => ({
...result.item,
html: highlightFzfMatch(result.item.html, Array.from(result.positions))
html: highlightFzfMatch(result.item.html, Array.from(result.positions), "model-item-highlight")
}))
}, [searchableItems, searchTerm, fzf])

View File

@@ -0,0 +1,44 @@
export function highlightFzfMatch(text: string, positions: number[], highlightClassName: string = "history-item-highlight") {
if (!positions.length) return text
const parts: { text: string; highlight: boolean }[] = []
let lastIndex = 0
// Sort positions to ensure we process them in order
positions.sort((a, b) => a - b)
positions.forEach((pos) => {
// Add non-highlighted text before this position
if (pos > lastIndex) {
parts.push({
text: text.substring(lastIndex, pos),
highlight: false
})
}
// Add highlighted character
parts.push({
text: text[pos],
highlight: true
})
lastIndex = pos + 1
})
// Add any remaining text
if (lastIndex < text.length) {
parts.push({
text: text.substring(lastIndex),
highlight: false
})
}
// Build final string
return parts
.map(part =>
part.highlight
? `<span class="${highlightClassName}">${part.text}</span>`
: part.text
)
.join('')
}