Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get current file untitled support #2841

Merged
merged 6 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 18 additions & 13 deletions core/config/promptFile.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import Handlebars from "handlebars";
import path from "path";
import * as YAML from "yaml";
import type { IDE, SlashCommand } from "..";
import type { ChatHistory, ChatHistoryItem, ChatMessage, ContextItem, ContinueSDK, IContextProvider, IDE, SlashCommand } from "..";
import { walkDir } from "../indexing/walkDir";
import { stripImages } from "../llm/images";
import { renderTemplatedString } from "../promptFiles/renderTemplatedString";
import { getBasename } from "../util/index";
import { BaseContextProvider } from "../context";

export const DEFAULT_PROMPTS_FOLDER = ".prompts";

Expand Down Expand Up @@ -147,28 +148,32 @@ function extractUserInput(input: string, commandName: string): string {
return input;
}

async function renderPrompt(prompt: string, context: any, userInput: string) {
async function renderPrompt(prompt: string, context: ContinueSDK, userInput: string) {
const helpers = getContextProviderHelpers(context);

// A few context providers that don't need to be in config.json to work in .prompt files
const diff = await context.ide.getDiff(false);
const currentFilePath = await context.ide.getCurrentFile();
const currentFile = currentFilePath
? await context.ide.readFile(currentFilePath)
: undefined;
const currentFile = await context.ide.getCurrentFile();
const inputData: Record<string, string> = {
diff,
input: userInput,
};
if (currentFile) {
inputData.currentFile = currentFile.path;
}

return renderTemplatedString(
prompt,
context.ide.readFile.bind(context.ide),
{ diff, currentFile, input: userInput },
inputData,
helpers,
);
}

function getContextProviderHelpers(
context: any,
context: ContinueSDK,
): Array<[string, Handlebars.HelperDelegate]> | undefined {
return context.config.contextProviders?.map((provider: any) => [
return context.config.contextProviders?.map((provider: IContextProvider) => [
provider.description.title,
async (helperContext: any) => {
const items = await provider.getContextItems(helperContext, {
Expand All @@ -182,16 +187,16 @@ function getContextProviderHelpers(
selectedCode: context.selectedCode,
});

items.forEach((item: any) =>
items.forEach((item) =>
context.addContextItem(createContextItem(item, provider)),
);

return items.map((item: any) => item.content).join("\n\n");
return items.map((item) => item.content).join("\n\n");
},
]);
}

function createContextItem(item: any, provider: any) {
function createContextItem(item: ContextItem, provider: IContextProvider) {
return {
...item,
id: {
Expand All @@ -202,7 +207,7 @@ function createContextItem(item: any, provider: any) {
}

function updateChatHistory(
history: any[],
history: ChatMessage[],
commandName: string,
renderedPrompt: string,
systemMessage?: string,
Expand Down
6 changes: 5 additions & 1 deletion core/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,11 @@ declare global {
stepIndex: number,
): Promise<void>;
getOpenFiles(): Promise<string[]>;
getCurrentFile(): Promise<string | undefined>;
getCurrentFile(): Promise<undefined | {
isUntitled: boolean
path: string
contents: string
}>;
getPinnedFiles(): Promise<string[]>;
getSearchResults(query: string): Promise<string>;
subprocess(command: string): Promise<[string, string]>;
Expand Down
12 changes: 5 additions & 7 deletions core/context/providers/CurrentFileContextProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,15 @@ class CurrentFileContextProvider extends BaseContextProvider {
if (!currentFile) {
return [];
}
const contents = await ide.readFile(currentFile);
const baseName = getBasename(currentFile.path);
return [
{
description: currentFile,
content: `This is the currently open file:\n\n\`\`\`${getBasename(
currentFile,
)}\n${contents}\n\`\`\``,
name: getBasename(currentFile),
description: currentFile.path,
content: `This is the currently open file:\n\n\`\`\`${baseName}\n${currentFile.contents}\n\`\`\``,
name: baseName,
uri: {
type: "file",
value: currentFile,
value: currentFile.path,
},
},
];
Expand Down
6 changes: 5 additions & 1 deletion core/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,11 @@ export interface IDE {
stepIndex: number,
): Promise<void>;
getOpenFiles(): Promise<string[]>;
getCurrentFile(): Promise<string | undefined>;
getCurrentFile(): Promise<undefined | {
isUntitled: boolean
path: string
contents: string
}>;
getPinnedFiles(): Promise<string[]>;
getSearchResults(query: string): Promise<string>;
subprocess(command: string, cwd?: string): Promise<[string, string]>;
Expand Down
4 changes: 2 additions & 2 deletions core/promptFiles/handlebarUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export function registerHelpers(
export async function prepareTemplateAndData(
template: string,
readFile: (filepath: string) => Promise<string>,
inputData: any,
inputData: Record<string, string>,
ctxProviderNames: string[],
): Promise<[string, any]> {
const [newTemplate, vars] = replaceFilepaths(template, ctxProviderNames);
Expand All @@ -95,7 +95,7 @@ export async function prepareTemplateAndData(
return [newTemplate, data];
}

export function compileAndRenderTemplate(template: string, data: any): string {
export function compileAndRenderTemplate(template: string, data: Record<string, string>): string {
const templateFn = Handlebars.compile(template);
return templateFn(data);
}
Expand Down
2 changes: 1 addition & 1 deletion core/promptFiles/renderTemplatedString.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
export async function renderTemplatedString(
template: string,
readFile: (filepath: string) => Promise<string>,
inputData: any,
inputData: Record<string, string>,
availableHelpers?: Array<[string, Handlebars.HelperDelegate]>,
): Promise<string> {
const helperPromises = availableHelpers
Expand Down
18 changes: 9 additions & 9 deletions core/promptFiles/slashCommandFromPromptFile.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SlashCommand } from "..";
import { ContinueSDK, SlashCommand } from "..";
import { stripImages } from "../llm/images";
import { getContextProviderHelpers } from "./getContextProviderHelpers";
import { renderTemplatedString } from "./renderTemplatedString";
Expand Down Expand Up @@ -37,18 +37,18 @@ export function extractUserInput(input: string, commandName: string): string {
return input;
}

export async function getDefaultVariables(context: any, userInput: string) {
const currentFilePath = await context.ide.getCurrentFile();
const currentFile = currentFilePath
? await context.ide.readFile(currentFilePath)
: undefined;

return { currentFile, input: userInput };
export async function getDefaultVariables(context: ContinueSDK, userInput: string): Promise<Record<string, string>> {
const currentFile = await context.ide.getCurrentFile();
const vars: Record<string, string> = { input: userInput };
if (currentFile) {
vars.currentFile = currentFile.path;
}
return vars;
}

export async function renderPrompt(
prompt: string,
context: any,
context: ContinueSDK,
userInput: string,
) {
const helpers = getContextProviderHelpers(context);
Expand Down
6 changes: 5 additions & 1 deletion core/protocol/ide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ export type ToIdeFromWebviewOrCoreProtocol = {
];
getProblems: [{ filepath: string }, Problem[]];
getOpenFiles: [undefined, string[]];
getCurrentFile: [undefined, string | undefined];
getCurrentFile: [undefined, undefined | {
isUntitled: boolean;
path: string;
contents: string;
}];
getPinnedFiles: [undefined, string[]];
showLines: [{ filepath: string; startLine: number; endLine: number }, void];
readRangeInFile: [{ filepath: string; range: Range }, string];
Expand Down
10 changes: 5 additions & 5 deletions core/util/filesystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { GetGhTokenArgs } from "../protocol/ide.js";
import { getContinueGlobalPath } from "./paths.js";

class FileSystemIde implements IDE {
constructor(private readonly workspaceDir: string) {}
constructor(private readonly workspaceDir: string) { }
showToast(
type: ToastType,
message: string,
Expand Down Expand Up @@ -205,6 +205,10 @@ class FileSystemIde implements IDE {
});
}

getCurrentFile(): Promise<undefined> {
return Promise.resolve(undefined);
}

showDiff(
filepath: string,
newContents: string,
Expand All @@ -221,10 +225,6 @@ class FileSystemIde implements IDE {
return Promise.resolve([]);
}

getCurrentFile(): Promise<string | undefined> {
return Promise.resolve("");
}

getPinnedFiles(): Promise<string[]> {
return Promise.resolve([]);
}
Expand Down
2 changes: 1 addition & 1 deletion core/util/messageIde.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ export class MessageIde implements IDE {
return this.request("getOpenFiles", undefined);
}

getCurrentFile(): Promise<string | undefined> {
getCurrentFile() {
return this.request("getCurrentFile", undefined);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1006,11 +1006,17 @@ class IdeProtocolClient(
// return openFiles.intersect(pinnedFiles).toList()
}

private fun currentFile(): String? {
private fun currentFile(): Map<String, Any?>? {
val fileEditorManager = FileEditorManager.getInstance(project)
val editor = fileEditorManager.selectedTextEditor
val virtualFile = editor?.document?.let { FileDocumentManager.getInstance().getFile(it) }
return virtualFile?.path
return virtualFile?.let {
mapOf(
"path" to it.path,
"contents" to editor.document.text,
"isUntitled" to false
)
}
}

suspend fun showToast(type: String, content: String, buttonTexts: Array<String> = emptyArray()): String? =
Expand Down
2 changes: 1 addition & 1 deletion extensions/vscode/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

63 changes: 59 additions & 4 deletions extensions/vscode/src/VsCodeIde.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { exec } from "node:child_process";
import * as path from "node:path";

import type {

Check warning on line 5 in extensions/vscode/src/VsCodeIde.ts

View workflow job for this annotation

GitHub Actions / tsc-check

There should be at least one empty line between import groups

Check warning on line 5 in extensions/vscode/src/VsCodeIde.ts

View workflow job for this annotation

GitHub Actions / tsc-check

`core` type import should occur after import of `./webviewProtocol`
ContinueRcJson,
FileType,
IDE,
Expand All @@ -23,7 +23,7 @@
getConfigJsonPath,
getContinueGlobalPath,
} from "core/util/paths";
import * as vscode from "vscode";

Check warning on line 26 in extensions/vscode/src/VsCodeIde.ts

View workflow job for this annotation

GitHub Actions / tsc-check

There should be at least one empty line between import groups
import { executeGotoProvider } from "./autocomplete/lsp";
import { DiffManager } from "./diff/horizontal";
import { Repository } from "./otherExtensions/git";
Expand Down Expand Up @@ -255,6 +255,7 @@

return tags;
}

getIdeInfo(): Promise<IdeInfo> {
return Promise.resolve({
ideType: "vscode",
Expand All @@ -266,6 +267,7 @@
.version,
});
}

readRangeInFile(filepath: string, range: Range): Promise<string> {
return this.ideUtils.readRangeInFile(
filepath,
Expand Down Expand Up @@ -342,7 +344,7 @@
type === vscode.FileType.SymbolicLink) &&
filename === ".continuerc.json"
) {
const contents = await this.ideUtils.readFile(
const contents = await this.readFile(
vscode.Uri.joinPath(workspaceDir, filename).fsPath,
);
configs.push(JSON.parse(contents));
Expand Down Expand Up @@ -421,8 +423,55 @@
async saveFile(filepath: string): Promise<void> {
await this.ideUtils.saveFile(filepath);
}

private static MAX_BYTES = 100000;

Check warning on line 427 in extensions/vscode/src/VsCodeIde.ts

View workflow job for this annotation

GitHub Actions / tsc-check

Class Property name `MAX_BYTES` must match one of the following formats: camelCase

async readFile(filepath: string): Promise<string> {
return await this.ideUtils.readFile(filepath);
try {
filepath = this.ideUtils.getAbsolutePath(filepath);
const uri = uriFromFilePath(filepath);

// First, check whether it's a notebook document
// Need to iterate over the cells to get full contents
const notebook =
vscode.workspace.notebookDocuments.find(
(doc) => doc.uri.toString() === uri.toString(),
) ??
(uri.fsPath.endsWith("ipynb")
? await vscode.workspace.openNotebookDocument(uri)
: undefined);
if (notebook) {
return notebook
.getCells()
.map((cell) => cell.document.getText())
.join("\n\n");
}

// Check whether it's an open document
const openTextDocument = vscode.workspace.textDocuments.find(
(doc) => doc.uri.fsPath === uri.fsPath,
);
if (openTextDocument !== undefined) {
return openTextDocument.getText();
}

const fileStats = await vscode.workspace.fs.stat(
uriFromFilePath(filepath),
);
if (fileStats.size > 10 * VsCodeIde.MAX_BYTES) {
return "";
}

const bytes = await vscode.workspace.fs.readFile(uri);

// Truncate the buffer to the first MAX_BYTES
const truncatedBytes = bytes.slice(0, VsCodeIde.MAX_BYTES);
const contents = new TextDecoder().decode(truncatedBytes);
return contents;
} catch (e) {
console.warn("Error reading file", e);
return "";
}
}
async showDiff(
filepath: string,
Expand All @@ -436,8 +485,13 @@
return await this.ideUtils.getOpenFiles();
}

async getCurrentFile(): Promise<string | undefined> {
return vscode.window.activeTextEditor?.document.uri.fsPath;
async getCurrentFile() {
if (!vscode.window.activeTextEditor) return undefined

Check warning on line 489 in extensions/vscode/src/VsCodeIde.ts

View workflow job for this annotation

GitHub Actions / tsc-check

Expected { after 'if' condition

Check warning on line 489 in extensions/vscode/src/VsCodeIde.ts

View workflow job for this annotation

GitHub Actions / tsc-check

Missing semicolon
return {
isUntitled: vscode.window.activeTextEditor.document.isUntitled,
path: vscode.window.activeTextEditor.document.uri.fsPath,
contents: vscode.window.activeTextEditor.document.getText()
}

Check warning on line 494 in extensions/vscode/src/VsCodeIde.ts

View workflow job for this annotation

GitHub Actions / tsc-check

Missing semicolon
}

async getPinnedFiles(): Promise<string[]> {
Expand Down Expand Up @@ -572,3 +626,4 @@
}

export { VsCodeIde };

5 changes: 2 additions & 3 deletions extensions/vscode/src/extension/VsCodeExtension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ export class VsCodeExtension {
// Reindex the workspaces
this.core.invoke("index/forceReIndex", undefined);
} else {
// Reindex the file
// Reindex the filex
RomneyDa marked this conversation as resolved.
Show resolved Hide resolved
const indexer = await this.core.codebaseIndexerPromise;
indexer.refreshFile(filepath);
}
Expand Down Expand Up @@ -329,8 +329,7 @@ export class VsCodeExtension {

// Register a content provider for the readonly virtual documents
const documentContentProvider = new (class
implements vscode.TextDocumentContentProvider
{
implements vscode.TextDocumentContentProvider {
// emitter and its event
onDidChangeEmitter = new vscode.EventEmitter<vscode.Uri>();
onDidChange = this.onDidChangeEmitter.event;
Expand Down
Loading
Loading