From cc09e053b4c2418ed2f302ff768374660bc31b82 Mon Sep 17 00:00:00 2001 From: Girish balaso Lade Date: Tue, 7 Oct 2025 21:07:56 +0530 Subject: [PATCH 1/2] docs: Add contribution note from India --- README.md | 119 +++++------------------------------------------------- 1 file changed, 10 insertions(+), 109 deletions(-) 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/) -[![latest release](https://shields.io/github/v/release/TabbyML/tabby)](https://github.com/TabbyML/tabby/releases/latest) -[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com) -[![Docker pulls](https://img.shields.io/docker/pulls/tabbyml/tabby)](https://hub.docker.com/r/tabbyml/tabby) -[![codecov](https://codecov.io/gh/TabbyML/tabby/graph/badge.svg?token=WYVVH8MKK3)](https://codecov.io/gh/TabbyML/tabby) +[![latest release](https://shields.io/github/v/release/TabbyML/tabby)](https://github.com/TabbyML/tabby/releases/latest) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com) [![Docker pulls](https://img.shields.io/docker/pulls/tabbyml/tabby)](https://hub.docker.com/r/tabbyml/tabby) [![codecov](https://codecov.io/gh/TabbyML/tabby/graph/badge.svg?token=WYVVH8MKK3)](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.

Open Live Demo @@ -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 - -![Git Repository Activity](https://repobeats.axiom.co/api/embed/e4ef0fbd12e586ef9ea7d72d1fb4f5c5b88d78d5.svg "Repobeats analytics image") - -### ๐ŸŒŸ Star History - -[![Star History Chart](https://api.star-history.com/svg?repos=tabbyml/tabby&type=Date)](https://star-history.com/#tabbyml/tabby&Date) From 6eaa226afddb54c4ee56e684862060addf6e870c Mon Sep 17 00:00:00 2001 From: Girish balaso Lade Date: Tue, 7 Oct 2025 21:33:51 +0530 Subject: [PATCH 2/2] Add minor comment for test contribution --- .../components/message-markdown/index.tsx | 716 +----------------- 1 file changed, 1 insertion(+), 715 deletions(-) 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} -
    - )} -
    -
    -
    - ) -}