From d555f31b4a5286f4b21450ed2e71f9b61099c5e3 Mon Sep 17 00:00:00 2001 From: Keegan Carruthers-Smith Date: Fri, 3 May 2024 15:51:30 +0200 Subject: [PATCH] noodle: add ContextItemHistory type This is built on top of the explain history PR to introduce a type for history. Right now it is hacked in as pretend terminal output and doesn't work that well. This is the start of presenting the context more clearly. This is still early, so is a draft. Test Plan: CI --- lib/shared/src/codebase-context/messages.ts | 15 ++++++++++- lib/shared/src/index.ts | 1 + vscode/src/commands/context/git-log.ts | 20 +++++++------- .../nodes/ContextItemMentionNode.ts | 27 ++++++++++--------- .../plugins/atMentions/OptionsList.tsx | 2 +- 5 files changed, 40 insertions(+), 25 deletions(-) diff --git a/lib/shared/src/codebase-context/messages.ts b/lib/shared/src/codebase-context/messages.ts index 7bea5ccb05..e91c7a3382 100644 --- a/lib/shared/src/codebase-context/messages.ts +++ b/lib/shared/src/codebase-context/messages.ts @@ -97,7 +97,7 @@ export enum ContextItemSource { /** * An item (such as a file or symbol) that is included as context in a chat message. */ -export type ContextItem = ContextItemFile | ContextItemSymbol | ContextItemPackage +export type ContextItem = ContextItemFile | ContextItemSymbol | ContextItemPackage | ContextItemHistory /** * A file (or a subset of a file given by a range) that is included as context in a chat message. @@ -147,6 +147,19 @@ export interface ContextItemSymbol extends ContextItemCommon { /** The valid kinds of a symbol. */ export type SymbolKind = 'class' | 'function' | 'method' +/** + * The output of source control history for a file. + * + * Note: Currently this is only used for the "Explain History" action which runs + * on a symbol. + */ +export interface ContextItemHistory extends ContextItemCommon { + type: 'history' + + /** The symbol name we asked history for, used for presentation only (not semantically meaningful). */ + symbolName: string +} + /** {@link ContextItem} with the `content` field set to the content. */ export type ContextItemWithContent = ContextItem & Required> diff --git a/lib/shared/src/index.ts b/lib/shared/src/index.ts index 12b3d32ca2..b1307e28e8 100644 --- a/lib/shared/src/index.ts +++ b/lib/shared/src/index.ts @@ -52,6 +52,7 @@ export type { export { type ContextItem, type ContextItemFile, + type ContextItemHistory, ContextItemSource, type ContextItemWithContent, type ContextItemSymbol, diff --git a/vscode/src/commands/context/git-log.ts b/vscode/src/commands/context/git-log.ts index aa95b9ed6c..32ada1c20b 100644 --- a/vscode/src/commands/context/git-log.ts +++ b/vscode/src/commands/context/git-log.ts @@ -2,11 +2,11 @@ import { type SpawnOptionsWithoutStdio, spawn } from 'node:child_process' import path from 'node:path' import { type ContextItem, + type ContextItemHistory, ContextItemSource, type FileURI, wrapInActiveSpan, } from '@sourcegraph/cody-shared' -import * as vscode from 'vscode' export async function getContextFileFromGitLog( file: FileURI, @@ -45,15 +45,15 @@ export async function getContextFileFromGitLog( throw new Error(`git log failed with exit code ${result.code}: ${result.stderr}`) } - return [ - { - type: 'file', - content: result.stdout, - title: 'Terminal Output', - uri: vscode.Uri.file('terminal-output'), - source: ContextItemSource.History, - }, - ] + const contextItem: ContextItemHistory = { + type: 'history', + content: result.stdout, + title: `history for ${options.funcname}`, + uri: file, + symbolName: options.funcname, + source: ContextItemSource.History, + } + return [contextItem] }) } diff --git a/vscode/webviews/promptEditor/nodes/ContextItemMentionNode.ts b/vscode/webviews/promptEditor/nodes/ContextItemMentionNode.ts index b4a5d3599c..9915cb54e2 100644 --- a/vscode/webviews/promptEditor/nodes/ContextItemMentionNode.ts +++ b/vscode/webviews/promptEditor/nodes/ContextItemMentionNode.ts @@ -4,6 +4,7 @@ import styles from './ContextItemMentionNode.module.css' import { type ContextItem, type ContextItemFile, + type ContextItemHistory, type ContextItemPackage, type ContextItemSymbol, displayLineRange, @@ -33,6 +34,7 @@ export type SerializedContextItem = { uri: string; title?: string; content?: und | Omit | Omit | Omit + | Omit ) export function serializeContextItem( @@ -180,20 +182,19 @@ export function contextItemMentionNodeDisplayText(contextItem: SerializedContext // range needs to go to the start (0th character) of line 5. Also, `RangeData` is 0-indexed but // display ranges are 1-indexed. const rangeText = contextItem.range?.start ? `:${displayLineRange(contextItem.range)}` : '' - if (contextItem.type === 'file') { - if (contextItem.provider && contextItem.title) { - return `@${contextItem.title}` - } - return `@${decodeURIComponent(displayPath(URI.parse(contextItem.uri)))}${rangeText}` - } - if (contextItem.type === 'symbol') { - return `@${displayPath(URI.parse(contextItem.uri))}${rangeText}#${contextItem.symbolName}` - } - if (contextItem.type === 'package') { - return `@${contextItem.ecosystem}:${contextItem.name}` + switch (contextItem.type) { + case 'file': + if (contextItem.provider && contextItem.title) { + return `@${contextItem.title}` + } + return `@${decodeURIComponent(displayPath(URI.parse(contextItem.uri)))}${rangeText}` + case 'symbol': + return `@${displayPath(URI.parse(contextItem.uri))}${rangeText}#${contextItem.symbolName}` + case 'package': + return `@${contextItem.ecosystem}:${contextItem.name}` + case 'history': + return `@history:${contextItem.symbolName}:${displayPath(URI.parse(contextItem.uri))}` } - // @ts-ignore - throw new Error(`unrecognized context item type ${contextItem.type}`) } export function $createContextItemMentionNode( diff --git a/vscode/webviews/promptEditor/plugins/atMentions/OptionsList.tsx b/vscode/webviews/promptEditor/plugins/atMentions/OptionsList.tsx index 642974d7d0..830a9cc884 100644 --- a/vscode/webviews/promptEditor/plugins/atMentions/OptionsList.tsx +++ b/vscode/webviews/promptEditor/plugins/atMentions/OptionsList.tsx @@ -105,7 +105,7 @@ const Item: FunctionComponent<{ const isFileType = item.type === 'file' const isPackageType = item.type === 'package' const icon = - isFileType || isPackageType ? null : item.kind === 'class' ? 'symbol-structure' : 'symbol-method' + item.type === 'symbol' ? (item.kind === 'class' ? 'symbol-structure' : 'symbol-method') : null const title = item.title ?? (isFileType || isPackageType ? displayPathBasename(item.uri) : item.symbolName)