diff --git a/README.md b/README.md
index c6200ca48a80..884529ae9f01 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,21 @@
-
+
# ๐พ Tabby
[๐ Docs](https://tabby.tabbyml.com/docs/welcome/) โข [๐ฌ Slack](https://links.tabbyml.com/join-slack) โข [๐บ๏ธ Roadmap](https://tabby.tabbyml.com/docs/roadmap/)
-[](https://github.com/TabbyML/tabby/releases/latest)
-[](https://makeapullrequest.com)
-[](https://hub.docker.com/r/tabbyml/tabby)
-[](https://codecov.io/gh/TabbyML/tabby)
+[](https://github.com/TabbyML/tabby/releases/latest) [](https://makeapullrequest.com) [](https://hub.docker.com/r/tabbyml/tabby) [](https://codecov.io/gh/TabbyML/tabby)
-[English](/README.md) |
-[็ฎไฝไธญๆ](/README-zh.md) |
-[ๆฅๆฌ่ช](/README-ja.md)
+[English](/README.md) | [็ฎไฝไธญๆ](/README-zh.md) | [ๆฅๆฌ่ช](/README-ja.md)
-Tabby is a self-hosted AI coding assistant, offering an open-source and on-premises alternative to GitHub Copilot. It boasts several key features:
-* Self-contained, with no need for a DBMS or cloud service.
-* OpenAPI interface, easy to integrate with existing infrastructure (e.g Cloud IDE).
-* Supports consumer-grade GPUs.
+Contributing from India ๐ฎ๐ณ - This fork is being maintained with contributions from developers in India!
+
+> Tabby is a self-hosted AI coding assistant, offering an open-source and on-premises alternative to GitHub Copilot. It boasts several key features:
+> * Self-contained, with no need for a DBMS or cloud service.
+> * OpenAPI interface, easy to integrate with existing infrastructure (e.g Cloud IDE).
+> * Supports consumer-grade GPUs.
@@ -29,6 +26,7 @@ Tabby is a self-hosted AI coding assistant, offering an open-source and on-premi
## ๐ฅ What's New
+
* **07/02/2025** [v0.30](https://github.com/TabbyML/tabby/releases/tag/v0.30.0) supports indexing GitLab Merge Request as Context!
* **05/25/2025** ๐กInterested in joining [Agent](https://links.tabbyml.com/pochi-github-readme) private preview? DM in [X](https://x.com/getpochi) for early waitlist approval!๐ซ
* **05/20/2025** Enhance Tabby with your own documentation๐ through REST APIs in [v0.29](https://github.com/TabbyML/tabby/releases/tag/v0.29.0)! ๐
@@ -37,107 +35,10 @@ Tabby is a self-hosted AI coding assistant, offering an open-source and on-premi
* **02/05/2025** LDAP Authentication and better notification for background jobs coming in Tabby [v0.24.0](https://github.com/TabbyML/tabby/releases/tag/v0.24.0)!โจ
* **02/04/2025** [VSCode 1.20.0](https://marketplace.visualstudio.com/items/TabbyML.vscode-tabby/changelog) upgrade! @-mention files to add them as chat context, and edit inline with a new right-click option are available!
-
-
-
-
Archived
* **01/10/2025** Tabby [v0.23.0](https://github.com/TabbyML/tabby/releases/tag/v0.23.0) featuring enhanced code browser experience and chat side panel improvements!
* **12/24/2024** Introduce **Notification Box** in Tabby [v0.22.0](https://github.com/TabbyML/tabby/releases/tag/v0.22.0)!
-* **12/06/2024** Llamafile deployment integration and enhanced Answer Engine user experience are coming in Tabby [v0.21.0](https://github.com/TabbyML/tabby/releases/tag/v0.21.0)!๐
-* **11/10/2024** Switching between different backend chat models is supported in Answer Engine with Tabby [v0.20.0](https://github.com/TabbyML/tabby/releases/tag/v0.20.0)!
-* **10/30/2024** Tabby [v0.19.0](https://github.com/TabbyML/tabby/releases/tag/v0.19.0) featuring recent shared threads on the main page to improve their discoverability.
-* **07/09/2024** ๐Announce [Codestral integration in Tabby](https://tabby.tabbyml.com/blog/2024/07/09/tabby-codestral/)!
-* **07/05/2024** Tabby [v0.13.0](https://github.com/TabbyML/tabby/releases/tag/v0.13.0) introduces ***Answer Engine***, a central knowledge engine for internal engineering teams. It seamlessly integrates with dev team's internal data, delivering reliable and precise answers to empower developers.
-* **06/13/2024** [VSCode 1.7](https://marketplace.visualstudio.com/items/TabbyML.vscode-tabby/changelog) marks a significant milestone with a versatile Chat experience throughout your coding experience. Come and they the latest **chat in side-panel** and **editing via chat command**!
-* **06/10/2024** Latest ๐blogpost drop on [an enhanced code context understanding](https://tabby.tabbyml.com/blog/2024/06/11/rank-fusion-in-tabby-code-completion/) in Tabby!
-* **06/06/2024** Tabby [v0.12.0](https://github.com/TabbyML/tabby/releases/tag/v0.12.0) release brings ๐**seamless integrations** (Gitlab SSO, Self-hosted GitHub/GitLab, etc.), to โ๏ธ**flexible configurations** (HTTP API integration) and ๐**expanded capabilities** (repo-context in Code Browser)!
-* **05/22/2024** Tabby [VSCode 1.6](https://marketplace.visualstudio.com/items?itemName=TabbyML.vscode-tabby) comes with **multiple choices** in inline completion, and the **auto-generated commit messages**๐ฑ๐ป!
-* **05/11/2024** [v0.11.0](https://github.com/TabbyML/tabby/releases/tag/v0.11.0) brings significant enterprise upgrades, including ๐**storage usage** stats, ๐**GitHub & GitLab** integration, ๐**Activities** page, and the long-awaited ๐ค**Ask Tabby** feature!
-* **04/22/2024** [v0.10.0](https://github.com/TabbyML/tabby/releases/tag/v0.10.0) released, featuring the latest **Reports** tab with team-wise analytics for Tabby usage.
-* **04/19/2024** ๐ฃ Tabby now incorporates [locally relevant snippets](https://github.com/TabbyML/tabby/pull/1844)(declarations from local LSP, and recently modified code) for code completion!
-* **04/17/2024** CodeGemma and CodeQwen model series have now been added to the [official registry](https://tabby.tabbyml.com/docs/models/)!
-* **03/20/2024** [v0.9](https://github.com/TabbyML/tabby/releases/tag/v0.9.1) released, highlighting a full feature admin UI.
-* **12/23/2023** Seamlessly [deploy Tabby on any cloud](https://tabby.tabbyml.com/docs/installation/skypilot/) with [SkyServe](https://skypilot.readthedocs.io/en/latest/serving/sky-serve.html) ๐ซ from SkyPilot.
-* **12/15/2023** [v0.7.0](https://github.com/TabbyML/tabby/releases/tag/v0.7.0) released with team management and secured access!
-* **10/15/2023** RAG-based code completion is enabled by detail in [v0.3.0](https://github.com/TabbyML/tabby/releases/tag/v0.3.0)๐! Check out the [blogpost](https://tabby.tabbyml.com/blog/2023/10/16/repository-context-for-code-completion/) explaining how Tabby utilizes repo-level context to get even smarter!
-* **11/27/2023** [v0.6.0](https://github.com/TabbyML/tabby/releases/tag/v0.6.0) released!
-* **11/09/2023** [v0.5.5](https://github.com/TabbyML/tabby/releases/tag/v0.5.5) released! With a redesign of UI + performance improvement.
-* **10/24/2023** โณ๏ธ Major updates for Tabby IDE plugins across [VSCode/Vim/IntelliJ](https://tabby.tabbyml.com/docs/extensions)!
-* **10/04/2023** Check out the [model directory](https://tabby.tabbyml.com/docs/models/) for the latest models supported by Tabby.
-* **09/18/2023** Apple's M1/M2 Metal inference support has landed in [v0.1.1](https://github.com/TabbyML/tabby/releases/tag/v0.1.1)!
-* **08/31/2023** Tabby's first stable release [v0.0.1](https://github.com/TabbyML/tabby/releases/tag/v0.0.1) ๐ฅณ.
-* **08/28/2023** Experimental support for the [CodeLlama 7B](https://github.com/TabbyML/tabby/issues/370).
-* **08/24/2023** Tabby is now on [JetBrains Marketplace](https://plugins.jetbrains.com/plugin/22379-tabby)!
-
-## ๐ Getting Started
-
-You can find our documentation [here](https://tabby.tabbyml.com/docs/getting-started).
-- ๐ [Installation](https://tabby.tabbyml.com/docs/installation/)
-- ๐ป [IDE/Editor Extensions](https://tabby.tabbyml.com/docs/extensions/)
-- โ๏ธ [Configuration](https://tabby.tabbyml.com/docs/configuration)
-
-### Run Tabby in 1 Minute
-The easiest way to start a Tabby server is by using the following Docker command:
-
-```bash
-docker run -it \
- --gpus all -p 8080:8080 -v $HOME/.tabby:/data \
- tabbyml/tabby \
- serve --model StarCoder-1B --device cuda --chat-model Qwen2-1.5B-Instruct
-```
-For additional options (e.g inference type, parallelism), please refer to the [documentation page](https://tabbyml.github.io/tabby).
-
-## ๐ค Contributing
-
-Full guide at [CONTRIBUTING.md](https://github.com/TabbyML/tabby/blob/main/CONTRIBUTING.md);
-
-### Get the Code
-
-```bash
-git clone --recurse-submodules https://github.com/TabbyML/tabby
-cd tabby
-```
-
-If you have already cloned the repository, you could run the `git submodule update --recursive --init` command to fetch all submodules.
-
-### Build
-
-1. Set up the Rust environment by following this [tutorial](https://www.rust-lang.org/learn/get-started).
-
-2. Install the required dependencies:
-```bash
-# For MacOS
-brew install protobuf
-
-# For Ubuntu / Debian
-apt install protobuf-compiler libopenblas-dev
-```
-
-3. Install useful tools:
-```bash
-# For Ubuntu
-apt install make sqlite3 graphviz
-```
-
-4. Now, you can build Tabby by running the command `cargo build`.
-
-### Start Hacking!
-... and don't forget to submit a [Pull Request](https://github.com/TabbyML/tabby/compare)
-
-## ๐ Community
-- ๐ค [Twitter / X](https://twitter.com/Tabby_ML) - engage with TabbyML for all things possible
-- ๐ [LinkedIn](https://www.linkedin.com/company/tabbyml/) - follow for the latest from the community
-- ๐ [Newsletter](https://newsletter.tabbyml.com/archive) - subscribe to unlock Tabby insights and secrets
-
-### ๐ Activity
-
-
-
-### ๐ Star History
-
-[](https://star-history.com/#tabbyml/tabby&Date)
diff --git a/ee/tabby-ui/components/message-markdown/index.tsx b/ee/tabby-ui/components/message-markdown/index.tsx
index cea79800521f..9952aeba763f 100644
--- a/ee/tabby-ui/components/message-markdown/index.tsx
+++ b/ee/tabby-ui/components/message-markdown/index.tsx
@@ -1,10 +1,10 @@
+// Minor change for contribution test
import { Fragment, ReactNode, useContext, useMemo, useState } from 'react'
import { compact, flatten, isNil } from 'lodash-es'
import rehypeRaw from 'rehype-raw'
import rehypeSanitize, { defaultSchema } from 'rehype-sanitize'
import remarkGfm from 'remark-gfm'
import remarkMath from 'remark-math'
-
import {
ContextInfo,
Maybe,
@@ -34,9 +34,7 @@ import {
HoverCardTrigger
} from '@/components/ui/hover-card'
import { MemoizedReactMarkdown } from '@/components/markdown'
-
import './style.css'
-
import { FileBox, SquareFunctionIcon } from 'lucide-react'
import {
FileLocation,
@@ -45,7 +43,6 @@ import {
LookupSymbolHint,
SymbolInfo
} from 'tabby-chat-panel/index'
-
import {
CUSTOM_HTML_BLOCK_TAGS,
CUSTOM_HTML_INLINE_TAGS
@@ -57,7 +54,6 @@ import {
MARKDOWN_SOURCE_REGEX,
MARKDOWN_SYMBOL_REGEX
} from '@/lib/constants/regex'
-
import { Mention } from '../mention-tag'
import { IconFile, IconFileText } from '../ui/icons'
import { Skeleton } from '../ui/skeleton'
@@ -65,714 +61,4 @@ import { CodeElement } from './code'
import { customStripTagsPlugin } from './custom-strip-tags-plugin'
import { DocDetailView } from './doc-detail-view'
import { MessageMarkdownContext } from './markdown-context'
-
type RelevantDocItem = {
- type: 'doc'
- data: AttachmentDocItem
-}
-
-type RelevantCodeItem = {
- type: 'code'
- data: AttachmentCodeItem | MessageAttachmentClientCode
- isClient?: boolean
-}
-
-type MessageAttachments = Array
-
-export interface MessageMarkdownProps {
- message: string
- headline?: boolean
- attachmentDocs?: Maybe>
- attachmentCode?: Maybe>
- attachmentClientCode?: Maybe>
- onCopyContent?: ((value: string) => void) | undefined
- onApplyInEditor?: (
- content: string,
- opts?: { languageId: string; smart: boolean }
- ) => void
- onLookupSymbol?: (
- symbol: string,
- hints?: LookupSymbolHint[] | undefined
- ) => Promise
- openInEditor?: (target: FileLocation) => void
- onCodeCitationClick?: (code: AttachmentCodeItem) => void
- onLinkClick?: (url: string) => void
- contextInfo?: ContextInfo
- fetchingContextInfo?: boolean
- className?: string
- isStreaming?: boolean
- supportsOnApplyInEditorV2: boolean
- activeSelection?: Context
- runShell?: (command: string) => Promise
-}
-
-export function MessageMarkdown({
- message,
- headline = false,
- attachmentDocs,
- attachmentClientCode,
- attachmentCode,
- onApplyInEditor,
- onCopyContent,
- contextInfo,
- fetchingContextInfo,
- className,
- isStreaming,
- onLookupSymbol,
- openInEditor,
- supportsOnApplyInEditorV2,
- activeSelection,
- runShell,
- ...rest
-}: MessageMarkdownProps) {
- const [symbolPositionMap, setSymbolLocationMap] = useState<
- Map
- >(new Map())
- const messageAttachments: MessageAttachments = useMemo(() => {
- const docs: MessageAttachments =
- attachmentDocs?.map(item => ({
- type: 'doc',
- data: item
- })) ?? []
-
- const clientCode: MessageAttachments =
- attachmentClientCode?.map(item => ({
- type: 'code',
- data: item
- })) ?? []
-
- const code: MessageAttachments =
- attachmentCode?.map(item => ({
- type: 'code',
- data: item
- })) ?? []
- return compact([...docs, ...clientCode, ...code])
- }, [attachmentDocs, attachmentClientCode, attachmentCode])
-
- const processMessagePlaceholder = (text: string) => {
- const elements: React.ReactNode[] = []
- let lastIndex = 0
-
- type Match = {
- pattern: RegExp
- Component: (...arg: any) => ReactNode
- getProps: Function
- match: RegExpExecArray
- }
-
- const allMatches: Match[] = []
-
- const findMatches = (
- regex: RegExp,
- Component: (...arg: any) => ReactNode,
- getProps: Function
- ) => {
- regex.lastIndex = 0
- let match
- while ((match = regex.exec(text)) !== null) {
- allMatches.push({
- pattern: regex,
- Component,
- getProps,
- match
- })
- }
- }
-
- findMatches(
- MARKDOWN_CITATION_REGEX,
- CitationTag,
- (match: RegExpExecArray) => {
- const citationIndex = parseInt(match[1], 10)
- const citationSource = !isNil(citationIndex)
- ? messageAttachments?.[citationIndex - 1]
- : undefined
- const citationType = citationSource?.type
- const showcitation = citationSource && !isNil(citationIndex)
- return {
- citationIndex,
- showcitation,
- citationType,
- citationSource
- }
- }
- )
-
- findMatches(MARKDOWN_SOURCE_REGEX, SourceTag, (match: RegExpExecArray) => {
- const sourceId = match[1]
- const className = headline ? 'text-[1rem] font-semibold' : undefined
- return { sourceId, className }
- })
-
- findMatches(MARKDOWN_FILE_REGEX, FileTag, (match: RegExpExecArray) => {
- const encodedFilepath = match[1]
- try {
- return {
- encodedFilepath,
- openInEditor
- }
- } catch (e) {
- return {}
- }
- })
-
- findMatches(MARKDOWN_SYMBOL_REGEX, SymbolTag, (match: RegExpExecArray) => {
- const fullMatch = match[1]
- return {
- encodedSymbol: fullMatch,
- openInEditor
- }
- })
-
- findMatches(
- MARKDOWN_COMMAND_REGEX,
- ContextCommandTag,
- (match: RegExpExecArray) => {
- const fullMatch = match[1]
- return {
- encodedCommand: fullMatch
- }
- }
- )
-
- allMatches.sort((a, b) => a.match.index - b.match.index)
-
- for (const { match, Component, getProps } of allMatches) {
- if (match.index >= lastIndex) {
- if (match.index > lastIndex) {
- elements.push(text.slice(lastIndex, match.index))
- }
-
- elements.push()
-
- lastIndex = match.index + match[0].length
- }
- }
-
- if (lastIndex < text.length) {
- elements.push(text.slice(lastIndex))
- }
-
- return elements
- }
-
- const lookupSymbol = async (keyword: string) => {
- if (!onLookupSymbol) return
- if (symbolPositionMap.has(keyword)) return
-
- setSymbolLocationMap(map => new Map(map.set(keyword, null)))
- const hints: LookupSymbolHint[] = []
-
- attachmentClientCode?.forEach(item => {
- const code = item as AttachmentCodeItem
- hints.push({
- filepath: convertToFilepath({
- filepath: code.filepath,
- baseDir: code.baseDir,
- gitUrl: code.gitUrl,
- commit: code.commit ?? undefined
- }),
- location: getRangeFromAttachmentCode(code)
- })
- })
-
- const symbolInfo = await onLookupSymbol(keyword, hints)
- setSymbolLocationMap(map => new Map(map.set(keyword, symbolInfo)))
- }
-
- const encodedMessage = useMemo(() => {
- const formattedMessage = formatCustomHTMLBlockTags(
- message,
- CUSTOM_HTML_BLOCK_TAGS as unknown as string[]
- )
- return encodeMentionPlaceHolder(formattedMessage)
- }, [message])
-
- return (
-
- {
- return {children}
- },
- p({ children }) {
- return (
-
- {children.map((child, index) =>
- typeof child === 'string' ? (
- child.split('\n').map((line, i) => (
-
- {i > 0 &&
}
- {processMessagePlaceholder(line)}
-
- ))
- ) : (
- {child}
- )
- )}
-
- )
- },
- li({ children }) {
- if (children && children.length) {
- return (
-
- {children.map((childrenItem, index) => {
- if (typeof childrenItem === 'string') {
- return processMessagePlaceholder(childrenItem)
- }
- return {childrenItem}
- })}
-
- )
- }
- return {children}
- },
- code({ node, inline, className, children, ...props }) {
- return (
-
- {children}
-
- )
- },
- hr() {
- return null
- }
- }}
- >
- {encodedMessage}
-
-
- )
-}
-
-export function ErrorMessageBlock({
- error = 'Failed to fetch'
-}: {
- error?: string
-}) {
- const errorMessage = useMemo(() => {
- let jsonString = JSON.stringify(
- {
- error: true,
- message: error
- },
- null,
- 2
- )
- const markdownJson = '```\n' + jsonString + '\n```'
- return markdownJson
- }, [error])
- return (
-
- {children}
-
- )
- }
- }}
- >
- {errorMessage}
-
- )
-}
-
-function ThinkBlock({ children }: { children: ReactNode }): JSX.Element {
- return (
-
-
- Thinking
-
- {children}
-
- )
-}
-
-function CitationTag({
- citationIndex,
- showcitation,
- citationType,
- citationSource
-}: any) {
- return (
-
- {showcitation && (
- <>
- {citationType === 'doc' ? (
-
- ) : citationType === 'code' ? (
-
- ) : null}
- >
- )}
-
- )
-}
-
-function SourceTag({
- sourceId,
- className
-}: {
- sourceId: string | undefined
- className?: string
-}) {
- const { contextInfo, fetchingContextInfo } = useContext(
- MessageMarkdownContext
- )
-
- if (!sourceId) return null
- const source = contextInfo?.sources?.find(o => o.sourceId === sourceId)
- if (!source) return null
-
- return (
-
-
- {fetchingContextInfo ? (
-
- ) : (
-
- )}
-
-
- )
-}
-
-function FileTag({
- encodedFilepath,
- openInEditor,
- className
-}: {
- encodedFilepath: string | undefined
- className?: string
- openInEditor?: MessageMarkdownProps['openInEditor']
-}) {
- const filepath = useMemo(() => {
- if (!encodedFilepath) return null
- try {
- const decodedFilepath = decodeURIComponent(encodedFilepath)
- const filepath = JSON.parse(decodedFilepath) as Filepath
- return filepath
- } catch (e) {
- return null
- }
- }, [encodedFilepath])
-
- const filepathString = useMemo(() => {
- if (!filepath) return undefined
-
- return convertFromFilepath(filepath).filepath
- }, [filepath])
-
- const handleClick = () => {
- if (!openInEditor || !filepath) return
- openInEditor({ filepath })
- }
-
- if (!filepathString) return null
-
- return (
-
-
-
- {resolveFileNameForDisplay(filepathString)}
-
-
- )
-}
-
-function SymbolTag({
- encodedSymbol,
- openInEditor,
- className
-}: {
- encodedSymbol: string | undefined
- className?: string
- openInEditor?: MessageMarkdownProps['openInEditor']
-}) {
- const symbol = useMemo(() => {
- if (!encodedSymbol) return null
- try {
- const decodedSymbol = decodeURIComponent(encodedSymbol)
- return JSON.parse(decodedSymbol) as ListSymbolItem
- } catch (e) {
- return null
- }
- }, [encodedSymbol])
-
- const handleClick = () => {
- if (!openInEditor || !symbol) return
- openInEditor({
- filepath: symbol.filepath,
- location: symbol.range
- })
- }
-
- if (!symbol?.label) return null
-
- return (
-
-
- {symbol.label}
-
- )
-}
-
-function ContextCommandTag({
- encodedCommand,
- className
-}: {
- encodedCommand: string | undefined
- className?: string
- openInEditor?: MessageMarkdownProps['openInEditor']
-}) {
- const command = useMemo(() => {
- if (!encodedCommand) return null
- try {
- const decodedCommand = decodeURIComponent(encodedCommand)
- return decodedCommand
- } catch (e) {
- return null
- }
- }, [encodedCommand])
-
- return (
-
-
- {command}
-
- )
-}
-
-function RelevantDocumentBadge({
- relevantDocument,
- citationIndex
-}: {
- relevantDocument: AttachmentDocItem
- citationIndex: number
-}) {
- const { onLinkClick } = useContext(MessageMarkdownContext)
- const link = useMemo(() => {
- if (isAttachmentCommitDoc(relevantDocument)) {
- return undefined
- }
- if (isAttachmentIngestedDoc(relevantDocument)) {
- return relevantDocument.ingestedDocLink
- }
-
- return relevantDocument.link
- }, [relevantDocument])
-
- return (
-
-
- {
- if (link) {
- onLinkClick?.(link)
- }
- }}
- >
- {citationIndex}
-
-
-
-
-
-
- )
-}
-
-function RelevantCodeBadge({
- relevantCode,
- citationIndex
-}: {
- relevantCode: AttachmentCodeItem
- citationIndex: number
-}) {
- const { onCodeCitationClick } = useContext(MessageMarkdownContext)
-
- const context: RelevantCodeContext = useMemo(() => {
- return {
- kind: 'file',
- range: getRangeFromAttachmentCode(relevantCode),
- filepath: relevantCode.filepath || '',
- content: relevantCode.content,
- gitUrl: ''
- }
- }, [relevantCode])
-
- const isMultiLine =
- context.range &&
- !isNil(context.range?.start) &&
- !isNil(context.range?.end) &&
- context.range.start < context.range.end
- const path = resolveDirectoryPath(context.filepath)
-
- const fileName = useMemo(() => {
- return resolveFileNameForDisplay(context.filepath)
- }, [context.filepath])
-
- const rangeText = useMemo(() => {
- if (!context.range) return undefined
-
- let text = ''
- if (context.range.start) {
- text = String(context.range.start)
- }
- if (isMultiLine) {
- text += `-${context.range.end}`
- }
- return text
- }, [context.range])
-
- return (
-
-
- {
- onCodeCitationClick?.(relevantCode)
- }}
- >
- {citationIndex}
-
-
-
- onCodeCitationClick?.(relevantCode)}
- >
-
-
-
- {fileName}
- {rangeText ? (
- :{rangeText}
- ) : null}
-
-
- {!!path && (
-
- {path}
-
- )}
-
-
-
- )
-}