Browse Source

DRY up highlighting code

Matt Rubens 1 year ago
parent
commit
5fa0272b49

+ 1 - 45
webview-ui/src/components/history/HistoryView.tsx

@@ -5,6 +5,7 @@ import { Virtuoso } from "react-virtuoso"
 import React, { memo, useMemo, useState, useEffect } from "react"
 import React, { memo, useMemo, useState, useEffect } from "react"
 import { Fzf } from "fzf"
 import { Fzf } from "fzf"
 import { formatLargeNumber } from "../../utils/format"
 import { formatLargeNumber } from "../../utils/format"
+import { highlightFzfMatch } from "../../utils/highlight"
 
 
 type HistoryViewProps = {
 type HistoryViewProps = {
 	onDone: () => void
 	onDone: () => void
@@ -464,49 +465,4 @@ const ExportButton = ({ itemId }: { itemId: string }) => (
 	</VSCodeButton>
 	</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)
 export default memo(HistoryView)

+ 2 - 46
webview-ui/src/components/settings/GlamaModelPicker.tsx

@@ -7,6 +7,7 @@ import styled from "styled-components"
 import { glamaDefaultModelId } from "../../../../src/shared/api"
 import { glamaDefaultModelId } from "../../../../src/shared/api"
 import { useExtensionState } from "../../context/ExtensionStateContext"
 import { useExtensionState } from "../../context/ExtensionStateContext"
 import { vscode } from "../../utils/vscode"
 import { vscode } from "../../utils/vscode"
+import { highlightFzfMatch } from "../../utils/highlight"
 import { ModelInfoView, normalizeApiConfiguration } from "./ApiOptions"
 import { ModelInfoView, normalizeApiConfiguration } from "./ApiOptions"
 
 
 const GlamaModelPicker: React.FC = () => {
 const GlamaModelPicker: React.FC = () => {
@@ -71,51 +72,6 @@ const GlamaModelPicker: React.FC = () => {
 		}))
 		}))
 	}, [modelIds])
 	}, [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(() => {
 	const fzf = useMemo(() => {
 		return new Fzf(searchableItems, {
 		return new Fzf(searchableItems, {
 			selector: item => item.html
 			selector: item => item.html
@@ -128,7 +84,7 @@ const GlamaModelPicker: React.FC = () => {
 		const searchResults = fzf.find(searchTerm)
 		const searchResults = fzf.find(searchTerm)
 		return searchResults.map(result => ({
 		return searchResults.map(result => ({
 			...result.item,
 			...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])
 	}, [searchableItems, searchTerm, fzf])
 
 

+ 2 - 46
webview-ui/src/components/settings/OpenAiModelPicker.tsx

@@ -5,6 +5,7 @@ import { useRemark } from "react-remark"
 import styled from "styled-components"
 import styled from "styled-components"
 import { useExtensionState } from "../../context/ExtensionStateContext"
 import { useExtensionState } from "../../context/ExtensionStateContext"
 import { vscode } from "../../utils/vscode"
 import { vscode } from "../../utils/vscode"
+import { highlightFzfMatch } from "../../utils/highlight"
 
 
 const OpenAiModelPicker: React.FC = () => {
 const OpenAiModelPicker: React.FC = () => {
 	const { apiConfiguration, setApiConfiguration, openAiModels, onUpdateApiConfig } = useExtensionState()
 	const { apiConfiguration, setApiConfiguration, openAiModels, onUpdateApiConfig } = useExtensionState()
@@ -70,51 +71,6 @@ const OpenAiModelPicker: React.FC = () => {
 		}))
 		}))
 	}, [modelIds])
 	}, [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(() => {
 	const fzf = useMemo(() => {
 		return new Fzf(searchableItems, {
 		return new Fzf(searchableItems, {
 			selector: item => item.html
 			selector: item => item.html
@@ -127,7 +83,7 @@ const OpenAiModelPicker: React.FC = () => {
 		const searchResults = fzf.find(searchTerm)
 		const searchResults = fzf.find(searchTerm)
 		return searchResults.map(result => ({
 		return searchResults.map(result => ({
 			...result.item,
 			...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])
 	}, [searchableItems, searchTerm, fzf])
 
 

+ 2 - 46
webview-ui/src/components/settings/OpenRouterModelPicker.tsx

@@ -7,6 +7,7 @@ import styled from "styled-components"
 import { openRouterDefaultModelId } from "../../../../src/shared/api"
 import { openRouterDefaultModelId } from "../../../../src/shared/api"
 import { useExtensionState } from "../../context/ExtensionStateContext"
 import { useExtensionState } from "../../context/ExtensionStateContext"
 import { vscode } from "../../utils/vscode"
 import { vscode } from "../../utils/vscode"
+import { highlightFzfMatch } from "../../utils/highlight"
 import { ModelInfoView, normalizeApiConfiguration } from "./ApiOptions"
 import { ModelInfoView, normalizeApiConfiguration } from "./ApiOptions"
 
 
 const OpenRouterModelPicker: React.FC = () => {
 const OpenRouterModelPicker: React.FC = () => {
@@ -70,51 +71,6 @@ const OpenRouterModelPicker: React.FC = () => {
 		}))
 		}))
 	}, [modelIds])
 	}, [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(() => {
 	const fzf = useMemo(() => {
 		return new Fzf(searchableItems, {
 		return new Fzf(searchableItems, {
 			selector: item => item.html
 			selector: item => item.html
@@ -127,7 +83,7 @@ const OpenRouterModelPicker: React.FC = () => {
 		const searchResults = fzf.find(searchTerm)
 		const searchResults = fzf.find(searchTerm)
 		return searchResults.map(result => ({
 		return searchResults.map(result => ({
 			...result.item,
 			...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])
 	}, [searchableItems, searchTerm, fzf])
 
 

+ 44 - 0
webview-ui/src/utils/highlight.ts

@@ -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('')
+}