Path: blob/main/extensions/copilot/src/extension/prompt/node/documentContext.ts
13399 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import type * as vscode from 'vscode';6import { TextDocumentSnapshot } from '../../../platform/editing/common/textDocumentSnapshot';7import { ILanguage, getLanguage } from '../../../util/common/languages';8import { findLast } from '../../../util/vs/base/common/arraysFind';9import { Mutable } from '../../../util/vs/base/common/types';10import { ChatRequestEditorData, ChatRequestNotebookData, Range, Selection } from '../../../vscodeTypes';11import { CopilotInteractiveEditorResponse } from '../../inlineChat/node/promptCraftingTypes';12import { Turn } from '../common/conversation';1314export interface IDocumentContext {15readonly document: TextDocumentSnapshot;16readonly fileIndentInfo: vscode.FormattingOptions | undefined;17readonly language: ILanguage;18readonly wholeRange: vscode.Range;19readonly selection: vscode.Selection;20}2122export namespace IDocumentContext {23export function fromEditor(editor: vscode.TextEditor, wholeRange?: vscode.Range): IDocumentContext {24const { options, document, selection, visibleRanges } = editor;25const docSnapshot = TextDocumentSnapshot.create(document);26const fileIndentInfo = {27insertSpaces: options.insertSpaces as boolean,28tabSize: options.tabSize as number,29};30const language = getLanguage(docSnapshot);31if (!wholeRange) {32if (visibleRanges.length === 1) {33wholeRange = visibleRanges[0];34} else if (visibleRanges.length > 1) {35wholeRange = visibleRanges[0].union(visibleRanges[visibleRanges.length - 1]);36} else {37wholeRange = selection;38}39}40return {41document: docSnapshot, fileIndentInfo, language, selection, wholeRange42};4344}4546export function fromTextDocument(document: vscode.TextDocument, selection: vscode.Selection, wholeRange?: vscode.Range): IDocumentContext {47const docSnapshot = TextDocumentSnapshot.create(document);48const language = getLanguage(docSnapshot);49if (!wholeRange) {50wholeRange = selection;51}52return {53document: docSnapshot, fileIndentInfo: undefined, language, selection, wholeRange54};55}5657export function inferDocumentContext(request: vscode.ChatRequest, activeEditor: vscode.TextEditor | undefined, previousTurns: Turn[]): IDocumentContext | undefined {5859let result: Mutable<IDocumentContext> | undefined;6061if (request.location2 instanceof ChatRequestEditorData) {62const { document, wholeRange, selection } = request.location2;63const docSnapshot = TextDocumentSnapshot.create(document);64result = {65document: docSnapshot,66language: getLanguage(document),67wholeRange,68selection,69fileIndentInfo: undefined70};7172} else if (request.location2 instanceof ChatRequestNotebookData) {73const { cell } = request.location2;74const cellSnapshot = TextDocumentSnapshot.create(cell);75result = {76document: cellSnapshot,77language: getLanguage(cell),78wholeRange: new Range(0, 0, 0, 0),79selection: new Selection(0, 0, 0, 0),80fileIndentInfo: undefined81};8283} else if (activeEditor) {84result = IDocumentContext.fromEditor(activeEditor);85}8687if (result) {88const lastTurnWithInlineResponse = findLast(previousTurns, turn => Boolean(turn.getMetadata(CopilotInteractiveEditorResponse)));89const data = lastTurnWithInlineResponse?.getMetadata(CopilotInteractiveEditorResponse);90if (data && data.store && data.store.lastDocumentContent === result.document.getText()) {91result.wholeRange = data.store.lastWholeRange;92}93}9495// DEFAULT - use the active editor's indent settings if none are set yet and if the editor and context document match96if (activeEditor && activeEditor?.document.uri.toString() === result?.document.uri.toString() && !result.fileIndentInfo) {97result.fileIndentInfo = {98insertSpaces: activeEditor.options.insertSpaces as boolean,99tabSize: activeEditor.options.tabSize as number,100};101}102103return result;104}105}106107108