Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
liangfung committed Dec 27, 2024
1 parent e88371c commit 8128615
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 65 deletions.
17 changes: 0 additions & 17 deletions clients/tabby-chat-panel/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,23 +67,6 @@ export interface EditorFileContext {
* If the range is not provided, the whole file is considered.
*/
range?: LineRange | PositionRange
// /**
// * The information of a jupyter notebook file
// */
// notebookCell?: {
// /**
// * numeric identifier of the cell
// */
// handle: number
// /**
// * The scheme of the notebook cell document
// * eg: 'file', 'untitled'
// */
// scheme: string
// }
/**
* The content of the file context.
*/
content: string
}

Expand Down
3 changes: 2 additions & 1 deletion clients/vscode/src/chat/WebviewHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
vscodeRangeToChatPanelPositionRange,
chatPanelLocationToVSCodeRange,
} from "./utils";
import { Schemes } from "./chat";

export class WebviewHelper {
webview?: Webview;
Expand Down Expand Up @@ -264,7 +265,7 @@ export class WebviewHelper {
}

public isSupportedSchemeForActiveSelection(scheme: string) {
const supportedSchemes = ["file", "untitled", "vscode-notebook-cell"];
const supportedSchemes: string[] = [Schemes.file, Schemes.untitled, Schemes.vscodeNotebookCell];
return supportedSchemes.includes(scheme);
}

Expand Down
7 changes: 7 additions & 0 deletions clients/vscode/src/chat/chat.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export enum Schemes {
file = 'file',
untitled = 'untitled',
vscodeNotebookCell = 'vscode-notebook-cell',
vscodeVfs = 'vscode-vfs',
vscodeUserdata = 'vscode-userdata',
}
1 change: 0 additions & 1 deletion clients/vscode/src/chat/fileContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ export async function getFileContext(
end: editor.selection.end.line + 1,
}
: undefined;

const filepath = localUriToChatPanelFilepath(editor.document.uri, gitProvider);

return {
Expand Down
78 changes: 71 additions & 7 deletions clients/vscode/src/chat/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
} from "tabby-chat-panel";
import type { GitProvider } from "../git/GitProvider";
import { getLogger } from "../logger";
import { Schemes } from "./chat";

const logger = getLogger("chat/utils");

Expand All @@ -22,8 +23,12 @@ export function localUriToChatPanelFilepath(uri: Uri, gitProvider: GitProvider):
}
const gitRemoteUrl = repo ? gitProvider.getDefaultRemoteUrl(repo) : undefined;
if (repo && gitRemoteUrl) {
const uriFilePath =
uri.scheme === "vscode-notebook-cell" ? uri.with({ scheme: "file" }).toString(true) : uri.toString(true);
let uriFilePath: string = uri.toString(true);

if (uri.scheme === Schemes.vscodeNotebookCell) {
uriFilePath = localUriToUriFilePath(uri);
}

const relativeFilePath = path.relative(repo.rootUri.toString(true), uriFilePath);
if (!relativeFilePath.startsWith("..")) {
return {
Expand All @@ -33,12 +38,26 @@ export function localUriToChatPanelFilepath(uri: Uri, gitProvider: GitProvider):
};
}
}

return {
kind: "uri",
uri: uri.toString(true),
uri: localUriToUriFilePath(uri),
};
}

function localUriToUriFilePath(uri: Uri): string {
let uriFilePath = uri.toString(true);

if (uri.scheme === Schemes.vscodeNotebookCell) {
const notebook = parseNotebookCellUri(uri);
if (notebook) {
// add fragment `#cell={number}` to filepath
uriFilePath = uri.with({ scheme: notebook.notebook.scheme, fragment: `cell=${notebook.handle}` }).toString(true);
}
}
return uriFilePath;
}

export function chatPanelFilepathToLocalUri(filepath: Filepath, gitProvider: GitProvider): Uri | null {
if (filepath.kind === "uri") {
try {
Expand Down Expand Up @@ -73,10 +92,24 @@ function chatPanelFilepathToVscodeNotebookCellUri(root: Uri, filepath: FilepathI
return null;
}

const parsedUrl = new URL(filepath.filepath, "file://");
const hash = parsedUrl.hash;
const cleanPath = parsedUrl.pathname;
return Uri.joinPath(root, cleanPath).with({ scheme: "vscode-notebook-cell", fragment: hash.slice(1) });
const uri = Uri.joinPath(root, filepath.filepath);
let handle: number | undefined;
const fragment = uri.fragment;
if (fragment.startsWith("cell=")) {
const handleStr = fragment.slice("cell=".length);
const _handle = parseInt(handleStr, 10);
if (isNaN(_handle)) {
return uri;
}
}

if (typeof handle === "undefined") {
logger.warn(`Invalid handle in filepath.`, filepath.filepath);
return uri;
}

const cellUri = generateNotebookCellUri(uri, handle);
return cellUri;
}

export function vscodePositionToChatPanelPosition(position: VSCodePosition): ChatPanelPosition {
Expand Down Expand Up @@ -129,3 +162,34 @@ export function chatPanelLocationToVSCodeRange(location: Location | undefined):
logger.warn(`Invalid location params.`, location);
return null;
}

const nb_lengths = ["W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f"];
const nb_padRegexp = new RegExp(`^[${nb_lengths.join("")}]+`);
const nb_radix = 7;
export function parseNotebookCellUri(cell: Uri): { notebook: Uri; handle: number } | undefined {
if (cell.scheme !== Schemes.vscodeNotebookCell) {
return undefined;
}

const idx = cell.fragment.indexOf("s");
if (idx < 0) {
return undefined;
}

const handle = parseInt(cell.fragment.substring(0, idx).replace(nb_padRegexp, ""), nb_radix);
const _scheme = Buffer.from(cell.fragment.substring(idx + 1), "base64").toString("utf-8");
if (isNaN(handle)) {
return undefined;
}
return {
handle,
notebook: cell.with({ scheme: _scheme, fragment: "" }),
};
}

export function generateNotebookCellUri(notebook: Uri, handle: number): Uri {
const s = handle.toString(nb_radix);
const p = s.length < nb_lengths.length ? nb_lengths[s.length - 1] : "z";
const fragment = `${p}${s}s${Buffer.from(notebook.scheme).toString("base64")}`;
return notebook.with({ scheme: Schemes.vscodeNotebookCell, fragment });
}
14 changes: 0 additions & 14 deletions ee/tabby-ui/lib/types/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,6 @@ export interface FileContext {
* If the range is not provided, the whole file is considered.
*/
range?: { start: number; end: number }
// /**
// * The info of jupyter notebook cell
// */
// notebookCell?: {
// /**
// * numeric identifier of the cell
// */
// handle: number
// /**
// * The scheme of the document in notebook cell
// * eg 'file', 'untitled'
// */
// scheme: string
// }
content: string
git_url: string
}
Expand Down
47 changes: 22 additions & 25 deletions ee/tabby-ui/lib/utils/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,31 +106,29 @@ export function checkSourcesAvailability(
return { hasCodebaseSource, hasDocumentSource }
}

function parseNotebookCellFragment(fragment: string) {
/**
* url e.g: path/to/file.ipynb#handle=1
* @param uri
* @returns
*/
function parseNotebookCellUri(fragment: string) {
if (!fragment) return undefined
try {
if (!fragment.startsWith('cell=')) {
return undefined
}

const _lengths = ['W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f']
const _padRegexp = new RegExp(`^[${_lengths.join('')}]+`)
const _radix = 7
const idx = fragment.indexOf('s')
if (idx < 0) {
return undefined
}
const handle = parseInt(
fragment.substring(0, idx).replace(_padRegexp, ''),
_radix
)
const scheme = Buffer.from(fragment.substring(idx + 1), 'base64').toString(
'utf-8'
)

if (isNaN(handle)) {
const handle = parseInt(fragment.slice('cell='.length), 10)

if (isNaN(handle)) {
return undefined
}
return {
handle
}
} catch (error) {
return undefined
}
return {
handle,
scheme
}
}

export function resolveFileNameForDisplay(uri: string) {
Expand All @@ -144,10 +142,9 @@ export function resolveFileNameForDisplay(uri: string) {
const extname = filename.includes('.') ? `.${filename.split('.').pop()}` : ''
const isNotebook = extname.startsWith('.ipynb')
const hash = url.hash ? url.hash.substring(1) : ''
const notebook = parseNotebookCellFragment(hash)

if (isNotebook && notebook) {
return `${filename} · Cell ${(notebook.handle || 0) + 1}`
const cell = parseNotebookCellUri(hash)
if (isNotebook && cell) {
return `${filename} · Cell ${(cell.handle || 0) + 1}`
}
return filename
}

0 comments on commit 8128615

Please sign in to comment.