diff --git a/package.json b/package.json index 2e6731f1..598cf0c4 100644 --- a/package.json +++ b/package.json @@ -479,7 +479,8 @@ }, "objectscript.conn.docker-compose": { "description": "Connect to server running in docker-compose", - "type": "object" + "type": "object", + "scope": "resource" }, "objectscript.conn.docker-compose.service": { "description": "Name of service in docker-compose", diff --git a/src/api/index.ts b/src/api/index.ts index 63917bd4..1891442d 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -20,18 +20,6 @@ export class AtelierAPI { return this.namespace || this.config.ns; } - private get apiVersion(): number { - return workspaceState.get(this.workspaceFolder + ":apiVersion", DEFAULT_API_VERSION); - } - - private get port(): number { - return workspaceState.get(this.workspaceFolder + ":port", this.config.port); - } - - private get password(): string { - return workspaceState.get(this.workspaceFolder + ":password", this.config.password); - } - private get iris(): boolean { return workspaceState.get(this.workspaceFolder + ":iris", false); } @@ -74,14 +62,12 @@ export class AtelierAPI { } public xdebugUrl(): string { - const { host, username, https } = this.config; - const port = this.port; - const password = this.password; + const { host, username, https, port, password, apiVersion } = this.config; const proto = https ? "wss" : "ws"; const auth = this.iris ? `IRISUsername=${username}&IRISPassword=${password}` : `CacheUserName=${username}&CachePassword=${password}`; - return `${proto}://${host}:${port}/api/atelier/v${this.apiVersion}/%25SYS/debug?${auth}`; + return `${proto}://${host}:${port}/api/atelier/v${apiVersion}/%25SYS/debug?${auth}`; } public updateCookies(newCookies: string[]): Promise { @@ -102,8 +88,11 @@ export class AtelierAPI { this.workspaceFolder = workspaceFolderName; const conn = config("conn", workspaceFolderName); this.config = conn; - const { name, host } = this.config; - const port = this.port; + this.config.port = workspaceState.get(this.workspaceFolder + ":port", this.config.port); + this.config.password = workspaceState.get(this.workspaceFolder + ":password", this.config.password); + this.config.apiVersion = workspaceState.get(this.workspaceFolder + ":apiVersion", DEFAULT_API_VERSION); + + const { name, host, port } = this.config; this.cache = new Cache(extensionContext, `API:${name}:${host}:${port}`); } @@ -115,14 +104,15 @@ export class AtelierAPI { params?: any, headers?: any ): Promise { - if (minVersion > this.apiVersion) { - return Promise.reject(`${path} not supported by API version ${this.apiVersion}`); + const { active, apiVersion, host, username, https, port, password } = this.config; + if (!active) { + return Promise.reject(); } - if (minVersion && minVersion > 0) { - path = `v${this.apiVersion}/${path}`; + if (minVersion > apiVersion) { + return Promise.reject(`${path} not supported by API version ${apiVersion}`); } - if (!this.config.active) { - return Promise.reject(); + if (minVersion && minVersion > 0) { + path = `v${apiVersion}/${path}`; } headers = { ...headers, @@ -149,9 +139,6 @@ export class AtelierAPI { } headers["Cache-Control"] = "no-cache"; - const { host, username, https } = this.config; - const port = this.port; - const password = this.password; const proto = this.config.https ? "https" : "http"; const http: any = this.config.https ? httpsModule : httpModule; const agent = new http.Agent({ diff --git a/src/commands/compile.ts b/src/commands/compile.ts index 7ef4f30d..125a0beb 100644 --- a/src/commands/compile.ts +++ b/src/commands/compile.ts @@ -77,7 +77,10 @@ async function compile(docs: CurrentFile[], flags?: string): Promise { }, () => api - .actionCompile(docs.map(el => el.name), flags) + .actionCompile( + docs.map(el => el.name), + flags + ) .then(data => { const info = docs.length > 1 ? "" : `${docs[0].name}: `; if (data.status && data.status.errors && data.status.errors.length) { diff --git a/src/debug/debugSession.ts b/src/debug/debugSession.ts index 57a39626..59c3f6e3 100644 --- a/src/debug/debugSession.ts +++ b/src/debug/debugSession.ts @@ -85,7 +85,7 @@ export class ObjectScriptDebugSession extends LoggingDebugSession { private _evalResultProperties = new Map(); public constructor() { - super("mock-debug.txt"); + super(); const api = new AtelierAPI(); this._namespace = api.ns; diff --git a/src/extension.ts b/src/extension.ts index a167fac8..fafd0374 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -9,6 +9,7 @@ export const OBJECTSCRIPTXML_FILE_SCHEMA = "objectscriptxml"; export const FILESYSTEM_SCHEMA = "isfs"; export const schemas = [OBJECTSCRIPT_FILE_SCHEMA, OBJECTSCRIPTXML_FILE_SCHEMA, FILESYSTEM_SCHEMA]; +import * as url from "url"; import WebSocket = require("ws"); import { importAndCompile, @@ -76,6 +77,25 @@ export const config = (setting?: string, workspaceFolderName?: string): any => { if (["conn", "export"].includes(setting)) { if (workspaceFolderName && workspaceFolderName !== "") { + if (workspaceFolderName.match(/.+:\d+$/)) { + const { port, hostname: host, auth, query } = url.parse("http://" + workspaceFolderName, true); + const { ns = "USER", https = false } = query; + const [username, password] = (auth || "_SYSTEM:SYS").split(":"); + if (setting == "conn") { + return { + active: true, + https, + ns, + host, + port, + username, + password, + }; + } else if (setting == "export") { + return {}; + } + } + const workspaceFolder = vscode.workspace.workspaceFolders.find( el => el.name.toLowerCase() === workspaceFolderName.toLowerCase() ); @@ -101,6 +121,8 @@ export function getXmlUri(uri: vscode.Uri): vscode.Uri { } let reporter: TelemetryReporter; +let connectionSocket: WebSocket; + export const checkConnection = (clearCookies = false): void => { const conn = config("conn"); let connInfo = `${conn.host}:${conn.port}[${conn.ns}]`; @@ -112,7 +134,7 @@ export const checkConnection = (clearCookies = false): void => { return; } workspaceState.update(currentWorkspaceFolder() + ":port", undefined); - const { port: dockerPort, docker: withDocker } = portFromDockerCompose(config("conn.docker-compose"), conn.port); + const { port: dockerPort, docker: withDocker } = portFromDockerCompose(); workspaceState.update(currentWorkspaceFolder() + ":docker", withDocker); if (withDocker) { terminalWithDocker(); @@ -126,6 +148,9 @@ export const checkConnection = (clearCookies = false): void => { if (clearCookies) { api.clearCookies(); } + if (connectionSocket && connectionSocket.url == api.xdebugUrl() && connectionSocket.OPEN) { + return; + } api .serverInfo() .then(info => { @@ -135,11 +160,11 @@ export const checkConnection = (clearCookies = false): void => { healthshare: hasHS ? "yes" : "no", }); /// Use xdebug's websocket, to catch when server disconnected - const socket = new WebSocket(api.xdebugUrl()); - socket.onopen = () => { + connectionSocket = new WebSocket(api.xdebugUrl()); + connectionSocket.onopen = () => { panel.text = `${connInfo} - Connected`; }; - socket.onclose = event => { + connectionSocket.onclose = event => { panel.text = `${connInfo} - Disconnected`; }; }) diff --git a/src/providers/DocumentContentProvider.ts b/src/providers/DocumentContentProvider.ts index 85392fa5..f281d8a6 100644 --- a/src/providers/DocumentContentProvider.ts +++ b/src/providers/DocumentContentProvider.ts @@ -31,9 +31,16 @@ export class DocumentContentProvider implements vscode.TextDocumentContentProvid const wFolderUri = workspaceFolderUri(workspaceFolder); let uri: vscode.Uri; if (wFolderUri.scheme === FILESYSTEM_SCHEMA) { + const fileExt = name.split(".").pop(); + const fileName = name + .split(".") + .slice(0, -1) + .join(fileExt.match(/cls/i) ? "/" : "."); + name = fileName + "." + fileExt; uri = wFolderUri.with({ path: `/${name}`, }); + vfs = true; } else { const found = this.getAsFile(name, workspaceFolder); if (found) { diff --git a/src/providers/ObjectScriptDiagnosticProvider.ts b/src/providers/ObjectScriptDiagnosticProvider.ts index 63fd8a0d..398d32e2 100644 --- a/src/providers/ObjectScriptDiagnosticProvider.ts +++ b/src/providers/ObjectScriptDiagnosticProvider.ts @@ -47,7 +47,7 @@ export class ObjectScriptDiagnosticProvider { } const memberMatch = text.match( - /^(Class|Property|Relationship|Index|ClassMethod|Method|XData|Query|Trigger|ForeignKey|Projection|Parameter)\s(\b[^ (]+\b)/i + /^(Class|Property|Relationship|Index|(?:(?:Client)?(?:Class)?Method)|ClientClassMethod|Method|XData|Query|Trigger|ForeignKey|Projection|Parameter)\s(\b[^ (]+\b)/i ); if (memberMatch) { const [fullMatch, type, name] = memberMatch; @@ -222,9 +222,11 @@ export class ObjectScriptDiagnosticProvider { const [, found] = functionsMatch; const pos = functionsMatch.index; const range = new vscode.Range(new vscode.Position(i, pos), new vscode.Position(i, pos + found.length)); - const systemFunction = [...systemFunctions, ...systemVariables, ...structuredSystemVariables].find(el => - el.alias.includes(found.toUpperCase()) - ); + const systemFunction: CompletionModel = [ + ...systemFunctions, + ...systemVariables, + ...structuredSystemVariables, + ].find(el => el.alias.includes(found.toUpperCase())); if (!systemFunction) { result.push({ range, diff --git a/src/providers/WorkspaceSymbolProvider.ts b/src/providers/WorkspaceSymbolProvider.ts index 6646c077..1a19704b 100644 --- a/src/providers/WorkspaceSymbolProvider.ts +++ b/src/providers/WorkspaceSymbolProvider.ts @@ -11,9 +11,11 @@ export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider { if (query.length < 3) { return null; } - return Promise.all([this.byClasses(query), this.byRoutines(query), this.byMethods(query)]).then( - ([classes, routines, methods]) => [...classes, ...routines, ...methods] - ); + return Promise.all([ + this.byClasses(query), + this.byRoutines(query), + this.byMethods(query), + ]).then(([classes, routines, methods]) => [...classes, ...routines, ...methods]); } public async byClasses(query: string): Promise { diff --git a/src/providers/completion/model.ts b/src/providers/completion/model.ts new file mode 100644 index 00000000..884c4216 --- /dev/null +++ b/src/providers/completion/model.ts @@ -0,0 +1,8 @@ +interface CompletionModel { + label: string; + alias: string[]; + deprecated?: boolean; + documentation: string[]; + link?: string; + code?: string; +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 46ae8ac4..702c46b0 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -32,7 +32,10 @@ export function currentFile(document?: vscode.TextDocument): CurrentFile { const uri = document.uri; const fileName = document.fileName; const content = document.getText(); - const fileExt = fileName.match(/\.(\w+)$/)[1].toLowerCase(); + const fileExt = fileName + .split(".") + .pop() + .toLowerCase(); let name = ""; let ext = ""; const { query } = url.parse(decodeURIComponent(uri.toString()), true); @@ -42,13 +45,11 @@ export function currentFile(document?: vscode.TextDocument): CurrentFile { } else if (fileExt === "cls") { const match = content.match(/^Class (%?\w+(?:\.\w+)+)/im); if (match) { - name = match[1]; - ext = "cls"; + [, name, ext = "cls"] = match; } } else { const match = content.match(/^ROUTINE ([^\s]+)(?:\s+\[.*Type=([a-z]{3,}))?/i); - name = match[1]; - ext = match[2] || "mac"; + [, name, ext = "mac"] = match; } if (!name) { return null; @@ -107,8 +108,9 @@ export function currentWorkspaceFolder(document?: vscode.TextDocument): string { } export function workspaceFolderUri(workspaceFolder: string = currentWorkspaceFolder()): vscode.Uri { - return vscode.workspace.workspaceFolders.find( - (el): boolean => el.name.toLowerCase() === workspaceFolder.toLowerCase() + return ( + vscode.workspace.workspaceFolders.find((el): boolean => el.name.toLowerCase() === workspaceFolder.toLowerCase()) || + vscode.workspace.workspaceFolders.find((el): boolean => el.uri.authority == workspaceFolder) ).uri; } @@ -123,12 +125,10 @@ export function notNull(el: any): boolean { return el !== null; } -export function portFromDockerCompose(options, defaultPort: number): { port: number; docker: boolean } { +export function portFromDockerCompose(): { port: number; docker: boolean } { + const { "docker-compose": dockerCompose, port: defaultPort } = config("conn"); const result = { port: defaultPort, docker: false }; - if (!options) { - return result; - } - const { file = "docker-compose.yml", service, internalPort = 52773 } = options; + const { service, file = "docker-compose.yml", internalPort = 52773 } = dockerCompose; if (!internalPort || !file || !service || service === "") { return result; } @@ -155,13 +155,16 @@ export function portFromDockerCompose(options, defaultPort: number): { port: num } export function terminalWithDocker() { - const { ns } = config("conn"); - const { service } = config("conn.docker-compose"); + const { ns, "docker-compose": dockerCompose } = config("conn"); + const { service, file = "docker-compose.yml" } = dockerCompose; + const workspace = currentWorkspaceFolder(); - const terminalName = `ObjectScript:${service}`; + const terminalName = `ObjectScript:${workspace}`; let terminal = vscode.window.terminals.find(el => el.name === terminalName); if (!terminal) { terminal = vscode.window.createTerminal(terminalName, "docker-compose", [ + "-f", + file, "exec", service, "/bin/bash", diff --git a/src/vscode.proposed.d.ts b/src/vscode.proposed.d.ts index 5d3ae613..3637da92 100644 --- a/src/vscode.proposed.d.ts +++ b/src/vscode.proposed.d.ts @@ -3,392 +3,1644 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -// This is the place for API experiments and proposal. - -declare module "vscode" { - //#region Rob: search provider - - /** - * The parameters of a query for text search. - */ - export interface TextSearchQuery { - /** - * The text pattern to search for. - */ - pattern: string; - - /** - * Whether or not `pattern` should match multiple lines of text. - */ - isMultiline?: boolean; - - /** - * Whether or not `pattern` should be interpreted as a regular expression. - */ - isRegExp?: boolean; - - /** - * Whether or not the search should be case-sensitive. - */ - isCaseSensitive?: boolean; - - /** - * Whether or not to search for whole word matches only. - */ - isWordMatch?: boolean; - } - - /** - * A file glob pattern to match file paths against. - * TODO@roblou - merge this with the GlobPattern docs/definition in vscode.d.ts. - * @see [GlobPattern](#GlobPattern) - */ - export type GlobString = string; - - /** - * Options common to file and text search - */ - export interface SearchOptions { - /** - * The root folder to search within. - */ - folder: Uri; - - /** - * Files that match an `includes` glob pattern should be included in the search. - */ - includes: GlobString[]; - - /** - * Files that match an `excludes` glob pattern should be excluded from the search. - */ - excludes: GlobString[]; - - /** - * Whether external files that exclude files, like .gitignore, should be respected. - * See the vscode setting `"search.useIgnoreFiles"`. - */ - useIgnoreFiles: boolean; - - /** - * Whether symlinks should be followed while searching. - * See the vscode setting `"search.followSymlinks"`. - */ - followSymlinks: boolean; - - /** - * Whether global files that exclude files, like .gitignore, should be respected. - * See the vscode setting `"search.useGlobalIgnoreFiles"`. - */ - useGlobalIgnoreFiles: boolean; - } - - /** - * Options to specify the size of the result text preview. - * These options don't affect the size of the match itself, just the amount of preview text. - */ - export interface TextSearchPreviewOptions { - /** - * The maximum number of lines in the preview. - * Only search providers that support multiline search will ever return more than one line in the match. - */ - matchLines: number; - - /** - * The maximum number of characters included per line. - */ - charsPerLine: number; - } - - /** - * Options that apply to text search. - */ - export interface TextSearchOptions extends SearchOptions { - /** - * The maximum number of results to be returned. - */ - maxResults: number; - - /** - * Options to specify the size of the result text preview. - */ - previewOptions?: TextSearchPreviewOptions; - - /** - * Exclude files larger than `maxFileSize` in bytes. - */ - maxFileSize?: number; - - /** - * Interpret files using this encoding. - * See the vscode setting `"files.encoding"` - */ - encoding?: string; - - /** - * Number of lines of context to include before each match. - */ - beforeContext?: number; - - /** - * Number of lines of context to include after each match. - */ - afterContext?: number; - } - - /** - * Information collected when text search is complete. - */ - export interface TextSearchComplete { - /** - * Whether the search hit the limit on the maximum number of search results. - * `maxResults` on [`TextSearchOptions`](#TextSearchOptions) specifies the max number of results. - * - If exactly that number of matches exist, this should be false. - * - If `maxResults` matches are returned and more exist, this should be true. - * - If search hits an internal limit which is less than `maxResults`, this should be true. - */ - limitHit?: boolean; - } - - /** - * The parameters of a query for file search. - */ - export interface FileSearchQuery { - /** - * The search pattern to match against file paths. - */ - pattern: string; - } - - /** - * Options that apply to file search. - */ - export interface FileSearchOptions extends SearchOptions { - /** - * The maximum number of results to be returned. - */ - maxResults?: number; - - /** - * A CancellationToken that represents the session for this search query. If the provider chooses to, this object can be used as the key for a cache, - * and searches with the same session object can search the same cache. When the token is cancelled, the session is complete and the cache can be cleared. - */ - session?: CancellationToken; - } - - /** - * A preview of the text result. - */ - export interface TextSearchMatchPreview { - /** - * The matching lines of text, or a portion of the matching line that contains the match. - */ - text: string; - - /** - * The Range within `text` corresponding to the text of the match. - * The number of matches must match the TextSearchMatch's range property. - */ - matches: Range | Range[]; - } - - /** - * A match from a text search - */ - export interface TextSearchMatch { - /** - * The uri for the matching document. - */ - uri: Uri; - - /** - * The range of the match within the document, or multiple ranges for multiple matches. - */ - ranges: Range | Range[]; - - /** - * A preview of the text match. - */ - preview: TextSearchMatchPreview; - } - - /** - * A line of context surrounding a TextSearchMatch. - */ - export interface TextSearchContext { - /** - * The uri for the matching document. - */ - uri: Uri; - - /** - * One line of text. - * previewOptions.charsPerLine applies to this - */ - text: string; - - /** - * The line number of this line of context. - */ - lineNumber: number; - } - - export type TextSearchResult = TextSearchMatch | TextSearchContext; - - /** - * A FileSearchProvider provides search results for files in the given folder that match a query string. It can be invoked by quickopen or other extensions. - * - * A FileSearchProvider is the more powerful of two ways to implement file search in VS Code. Use a FileSearchProvider if you wish to search within a folder for - * all files that match the user's query. - * - * The FileSearchProvider will be invoked on every keypress in quickopen. When `workspace.findFiles` is called, it will be invoked with an empty query string, - * and in that case, every file in the folder should be returned. - */ - export interface FileSearchProvider { - /** - * Provide the set of files that match a certain file path pattern. - * @param query The parameters for this query. - * @param options A set of options to consider while searching files. - * @param token A cancellation token. - */ - provideFileSearchResults( - query: FileSearchQuery, - options: FileSearchOptions, - token: CancellationToken - ): ProviderResult; - } - - /** - * A TextSearchProvider provides search results for text results inside files in the workspace. - */ - export interface TextSearchProvider { - /** - * Provide results that match the given text pattern. - * @param query The parameters for this query. - * @param options A set of options to consider while searching. - * @param progress A progress callback that must be invoked for all results. - * @param token A cancellation token. - */ - provideTextSearchResults( - query: TextSearchQuery, - options: TextSearchOptions, - progress: Progress, - token: CancellationToken - ): ProviderResult; - } - - /** - * Options that can be set on a findTextInFiles search. - */ - export interface FindTextInFilesOptions { - /** - * A [glob pattern](#GlobPattern) that defines the files to search for. The glob pattern - * will be matched against the file paths of files relative to their workspace. Use a [relative pattern](#RelativePattern) - * to restrict the search results to a [workspace folder](#WorkspaceFolder). - */ - include?: GlobPattern; - - /** - * A [glob pattern](#GlobPattern) that defines files and folders to exclude. The glob pattern - * will be matched against the file paths of resulting matches relative to their workspace. When `undefined` only default excludes will - * apply, when `null` no excludes will apply. - */ - exclude?: GlobPattern | null; - - /** - * The maximum number of results to search for - */ - maxResults?: number; - - /** - * Whether external files that exclude files, like .gitignore, should be respected. - * See the vscode setting `"search.useIgnoreFiles"`. - */ - useIgnoreFiles?: boolean; - - /** - * Whether global files that exclude files, like .gitignore, should be respected. - * See the vscode setting `"search.useGlobalIgnoreFiles"`. - */ - useGlobalIgnoreFiles?: boolean; - - /** - * Whether symlinks should be followed while searching. - * See the vscode setting `"search.followSymlinks"`. - */ - followSymlinks?: boolean; - - /** - * Interpret files using this encoding. - * See the vscode setting `"files.encoding"` - */ - encoding?: string; - - /** - * Options to specify the size of the result text preview. - */ - previewOptions?: TextSearchPreviewOptions; - - /** - * Number of lines of context to include before each match. - */ - beforeContext?: number; - - /** - * Number of lines of context to include after each match. - */ - afterContext?: number; - } - - export namespace workspace { - /** - * Register a search provider. - * - * Only one provider can be registered per scheme. - * - * @param scheme The provider will be invoked for workspace folders that have this file scheme. - * @param provider The provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. - */ - export function registerFileSearchProvider(scheme: string, provider: FileSearchProvider): Disposable; - - /** - * Register a text search provider. - * - * Only one provider can be registered per scheme. - * - * @param scheme The provider will be invoked for workspace folders that have this file scheme. - * @param provider The provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. - */ - export function registerTextSearchProvider(scheme: string, provider: TextSearchProvider): Disposable; - - /** - * Search text in files across all [workspace folders](#workspace.workspaceFolders) in the workspace. - * @param query The query parameters for the search - the search string, whether it's case-sensitive, or a regex, or matches whole words. - * @param callback A callback, called for each result - * @param token A token that can be used to signal cancellation to the underlying search engine. - * @return A thenable that resolves when the search is complete. - */ - export function findTextInFiles( - query: TextSearchQuery, - callback: (result: TextSearchResult) => void, - token?: CancellationToken - ): Thenable; - - /** - * Search text in files across all [workspace folders](#workspace.workspaceFolders) in the workspace. - * @param query The query parameters for the search - the search string, whether it's case-sensitive, or a regex, or matches whole words. - * @param options An optional set of query options. Include and exclude patterns, maxResults, etc. - * @param callback A callback, called for each result - * @param token A token that can be used to signal cancellation to the underlying search engine. - * @return A thenable that resolves when the search is complete. - */ - export function findTextInFiles( - query: TextSearchQuery, - options: FindTextInFilesOptions, - callback: (result: TextSearchResult) => void, - token?: CancellationToken - ): Thenable; - } +/** + * This is the place for API experiments and proposals. + * These API are NOT stable and subject to change. They are only available in the Insiders + * distribution and CANNOT be used in published extensions. + * + * To test these API in local environment: + * - Use Insiders release of VS Code. + * - Add `"enableProposedApi": true` to your package.json. + * - Copy this file to your project. + */ + +declare module 'vscode' { + + // #region auth provider: https://github.com/microsoft/vscode/issues/88309 + + export interface AuthenticationSession { + id: string; + accessToken(): Promise; + accountName: string; + scopes: string[] + } + + /** + * An [event](#Event) which fires when an [AuthenticationProvider](#AuthenticationProvider) is added or removed. + */ + export interface AuthenticationProvidersChangeEvent { + /** + * The ids of the [authenticationProvider](#AuthenticationProvider)s that have been added. + */ + readonly added: string[]; + + /** + * The ids of the [authenticationProvider](#AuthenticationProvider)s that have been removed.. + */ + readonly removed: string[]; + } + + export interface AuthenticationProvider { + /** + * Used as an identifier for extensions trying to work with a particular + * provider: 'Microsoft', 'GitHub', etc. id must be unique, registering + * another provider with the same id will fail. + */ + readonly id: string; + readonly displayName: string; + + /** + * A [enent](#Event) which fires when the array of sessions has changed, or data + * within a session has changed. + */ + readonly onDidChangeSessions: Event; + + /** + * Returns an array of current sessions. + */ + getSessions(): Promise>; + + /** + * Prompts a user to login. + */ + login(scopes: string[]): Promise; + logout(sessionId: string): Promise; + } + + export namespace authentication { + export function registerAuthenticationProvider(provider: AuthenticationProvider): Disposable; + + /** + * Fires with the provider id that was registered or unregistered. + */ + export const onDidChangeAuthenticationProviders: Event; + + export const providers: ReadonlyArray; + } + + //#endregion + + //#region Alex - resolvers + + export interface RemoteAuthorityResolverContext { + resolveAttempt: number; + } + + export class ResolvedAuthority { + readonly host: string; + readonly port: number; + + constructor(host: string, port: number); + } + + export interface ResolvedOptions { + extensionHostEnv?: { [key: string]: string | null }; + } + + export interface TunnelOptions { + remoteAddress: { port: number, host: string }; + // The desired local port. If this port can't be used, then another will be chosen. + localAddressPort?: number; + label?: string; + } + + export interface TunnelDescription { + remoteAddress: { port: number, host: string }; + //The complete local address(ex. localhost:1234) + localAddress: string; + } + + export interface Tunnel extends TunnelDescription { + // Implementers of Tunnel should fire onDidDispose when dispose is called. + onDidDispose: Event; + dispose(): void; + } + + /** + * Used as part of the ResolverResult if the extension has any candidate, + * published, or forwarded ports. + */ + export interface TunnelInformation { + /** + * Tunnels that are detected by the extension. The remotePort is used for display purposes. + * The localAddress should be the complete local address (ex. localhost:1234) for connecting to the port. Tunnels provided through + * detected are read-only from the forwarded ports UI. + */ + environmentTunnels?: TunnelDescription[]; + + } + + export type ResolverResult = ResolvedAuthority & ResolvedOptions & TunnelInformation; + + export class RemoteAuthorityResolverError extends Error { + static NotAvailable(message?: string, handled?: boolean): RemoteAuthorityResolverError; + static TemporarilyNotAvailable(message?: string): RemoteAuthorityResolverError; + + constructor(message?: string); + } + + export interface RemoteAuthorityResolver { + resolve(authority: string, context: RemoteAuthorityResolverContext): ResolverResult | Thenable; + /** + * Can be optionally implemented if the extension can forward ports better than the core. + * When not implemented, the core will use its default forwarding logic. + * When implemented, the core will use this to forward ports. + */ + tunnelFactory?: (tunnelOptions: TunnelOptions) => Thenable | undefined; + + /** + * Provides filtering for candidate ports. + */ + showCandidatePort?: (host: string, port: number, detail: string) => Thenable; + } + + export namespace workspace { + /** + * Forwards a port. If the current resolver implements RemoteAuthorityResolver:forwardPort then that will be used to make the tunnel. + * By default, openTunnel only support localhost; however, RemoteAuthorityResolver:tunnelFactory can be used to support other ips. + * @param tunnelOptions The `localPort` is a suggestion only. If that port is not available another will be chosen. + */ + export function openTunnel(tunnelOptions: TunnelOptions): Thenable; + + /** + * Gets an array of the currently available tunnels. This does not include environment tunnels, only tunnels that have been created by the user. + * Note that these are of type TunnelDescription and cannot be disposed. + */ + export let tunnels: Thenable; + + /** + * Fired when the list of tunnels has changed. + * @deprecated use onDidChangeTunnels instead + */ + // TODO@alexr + // eslint-disable-next-line vscode-dts-event-naming + export const onDidTunnelsChange: Event; + /** + * Fired when the list of tunnels has changed. + */ + export const onDidChangeTunnels: Event; + } + + export interface ResourceLabelFormatter { + scheme: string; + authority?: string; + formatting: ResourceLabelFormatting; + } + + export interface ResourceLabelFormatting { + label: string; // myLabel:/${path} + // TODO@isi + // eslint-disable-next-line vscode-dts-literal-or-types + separator: '/' | '\\' | ''; + tildify?: boolean; + normalizeDriveLetter?: boolean; + workspaceSuffix?: string; + authorityPrefix?: string; + } + + export namespace workspace { + export function registerRemoteAuthorityResolver(authorityPrefix: string, resolver: RemoteAuthorityResolver): Disposable; + export function registerResourceLabelFormatter(formatter: ResourceLabelFormatter): Disposable; + } + + //#endregion + + //#region Semantic tokens: https://github.com/microsoft/vscode/issues/86415 + + export class SemanticTokensLegend { + public readonly tokenTypes: string[]; + public readonly tokenModifiers: string[]; + + constructor(tokenTypes: string[], tokenModifiers: string[]); + } + + export class SemanticTokensBuilder { + constructor(); + push(line: number, char: number, length: number, tokenType: number, tokenModifiers: number): void; + build(): Uint32Array; + } + + export class SemanticTokens { + /** + * The result id of the tokens. + * + * This is the id that will be passed to `DocumentSemanticTokensProvider.provideDocumentSemanticTokensEdits` (if implemented). + */ + readonly resultId?: string; + readonly data: Uint32Array; + + constructor(data: Uint32Array, resultId?: string); + } + + export class SemanticTokensEdits { + /** + * The result id of the tokens. + * + * This is the id that will be passed to `DocumentSemanticTokensProvider.provideDocumentSemanticTokensEdits` (if implemented). + */ + readonly resultId?: string; + readonly edits: SemanticTokensEdit[]; + + constructor(edits: SemanticTokensEdit[], resultId?: string); + } + + export class SemanticTokensEdit { + readonly start: number; + readonly deleteCount: number; + readonly data?: Uint32Array; + + constructor(start: number, deleteCount: number, data?: Uint32Array); + } + + /** + * The document semantic tokens provider interface defines the contract between extensions and + * semantic tokens. + */ + export interface DocumentSemanticTokensProvider { + /** + * A file can contain many tokens, perhaps even hundreds of thousands of tokens. Therefore, to improve + * the memory consumption around describing semantic tokens, we have decided to avoid allocating an object + * for each token and we represent tokens from a file as an array of integers. Furthermore, the position + * of each token is expressed relative to the token before it because most tokens remain stable relative to + * each other when edits are made in a file. + * + * --- + * In short, each token takes 5 integers to represent, so a specific token `i` in the file consists of the following array indices: + * - at index `5*i` - `deltaLine`: token line number, relative to the previous token + * - at index `5*i+1` - `deltaStart`: token start character, relative to the previous token (relative to 0 or the previous token's start if they are on the same line) + * - at index `5*i+2` - `length`: the length of the token. A token cannot be multiline. + * - at index `5*i+3` - `tokenType`: will be looked up in `SemanticTokensLegend.tokenTypes`. We currently ask that `tokenType` < 65536. + * - at index `5*i+4` - `tokenModifiers`: each set bit will be looked up in `SemanticTokensLegend.tokenModifiers` + * + * --- + * ### How to encode tokens + * + * Here is an example for encoding a file with 3 tokens in a uint32 array: + * ``` + * { line: 2, startChar: 5, length: 3, tokenType: "property", tokenModifiers: ["private", "static"] }, + * { line: 2, startChar: 10, length: 4, tokenType: "type", tokenModifiers: [] }, + * { line: 5, startChar: 2, length: 7, tokenType: "class", tokenModifiers: [] } + * ``` + * + * 1. First of all, a legend must be devised. This legend must be provided up-front and capture all possible token types. + * For this example, we will choose the following legend which must be passed in when registering the provider: + * ``` + * tokenTypes: ['property', 'type', 'class'], + * tokenModifiers: ['private', 'static'] + * ``` + * + * 2. The first transformation step is to encode `tokenType` and `tokenModifiers` as integers using the legend. Token types are looked + * up by index, so a `tokenType` value of `1` means `tokenTypes[1]`. Multiple token modifiers can be set by using bit flags, + * so a `tokenModifier` value of `3` is first viewed as binary `0b00000011`, which means `[tokenModifiers[0], tokenModifiers[1]]` because + * bits 0 and 1 are set. Using this legend, the tokens now are: + * ``` + * { line: 2, startChar: 5, length: 3, tokenType: 0, tokenModifiers: 3 }, + * { line: 2, startChar: 10, length: 4, tokenType: 1, tokenModifiers: 0 }, + * { line: 5, startChar: 2, length: 7, tokenType: 2, tokenModifiers: 0 } + * ``` + * + * 3. The next step is to represent each token relative to the previous token in the file. In this case, the second token + * is on the same line as the first token, so the `startChar` of the second token is made relative to the `startChar` + * of the first token, so it will be `10 - 5`. The third token is on a different line than the second token, so the + * `startChar` of the third token will not be altered: + * ``` + * { deltaLine: 2, deltaStartChar: 5, length: 3, tokenType: 0, tokenModifiers: 3 }, + * { deltaLine: 0, deltaStartChar: 5, length: 4, tokenType: 1, tokenModifiers: 0 }, + * { deltaLine: 3, deltaStartChar: 2, length: 7, tokenType: 2, tokenModifiers: 0 } + * ``` + * + * 4. Finally, the last step is to inline each of the 5 fields for a token in a single array, which is a memory friendly representation: + * ``` + * // 1st token, 2nd token, 3rd token + * [ 2,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] + * ``` + */ + provideDocumentSemanticTokens(document: TextDocument, token: CancellationToken): ProviderResult; + + /** + * Instead of always returning all the tokens in a file, it is possible for a `DocumentSemanticTokensProvider` to implement + * this method (`updateSemanticTokens`) and then return incremental updates to the previously provided semantic tokens. + * + * --- + * ### How tokens change when the document changes + * + * Let's look at how tokens might change. + * + * Continuing with the above example, suppose a new line was inserted at the top of the file. + * That would make all the tokens move down by one line (notice how the line has changed for each one): + * ``` + * { line: 3, startChar: 5, length: 3, tokenType: "property", tokenModifiers: ["private", "static"] }, + * { line: 3, startChar: 10, length: 4, tokenType: "type", tokenModifiers: [] }, + * { line: 6, startChar: 2, length: 7, tokenType: "class", tokenModifiers: [] } + * ``` + * The integer encoding of the tokens does not change substantially because of the delta-encoding of positions: + * ``` + * // 1st token, 2nd token, 3rd token + * [ 3,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] + * ``` + * It is possible to express these new tokens in terms of an edit applied to the previous tokens: + * ``` + * [ 2,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] // old tokens + * [ 3,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] // new tokens + * + * edit: { start: 0, deleteCount: 1, data: [3] } // replace integer at offset 0 with 3 + * ``` + * + * Furthermore, let's assume that a new token has appeared on line 4: + * ``` + * { line: 3, startChar: 5, length: 3, tokenType: "property", tokenModifiers: ["private", "static"] }, + * { line: 3, startChar: 10, length: 4, tokenType: "type", tokenModifiers: [] }, + * { line: 4, startChar: 3, length: 5, tokenType: "property", tokenModifiers: ["static"] }, + * { line: 6, startChar: 2, length: 7, tokenType: "class", tokenModifiers: [] } + * ``` + * The integer encoding of the tokens is: + * ``` + * // 1st token, 2nd token, 3rd token, 4th token + * [ 3,5,3,0,3, 0,5,4,1,0, 1,3,5,0,2, 2,2,7,2,0, ] + * ``` + * Again, it is possible to express these new tokens in terms of an edit applied to the previous tokens: + * ``` + * [ 3,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] // old tokens + * [ 3,5,3,0,3, 0,5,4,1,0, 1,3,5,0,2, 2,2,7,2,0, ] // new tokens + * + * edit: { start: 10, deleteCount: 1, data: [1,3,5,0,2,2] } // replace integer at offset 10 with [1,3,5,0,2,2] + * ``` + * + * *NOTE*: When doing edits, it is possible that multiple edits occur until VS Code decides to invoke the semantic tokens provider. + * *NOTE*: If the provider cannot compute `SemanticTokensEdits`, it can "give up" and return all the tokens in the document again. + * *NOTE*: All edits in `SemanticTokensEdits` contain indices in the old integers array, so they all refer to the previous result state. + */ + provideDocumentSemanticTokensEdits?(document: TextDocument, previousResultId: string, token: CancellationToken): ProviderResult; + } + + /** + * The document range semantic tokens provider interface defines the contract between extensions and + * semantic tokens. + */ + export interface DocumentRangeSemanticTokensProvider { + /** + * See [provideDocumentSemanticTokens](#DocumentSemanticTokensProvider.provideDocumentSemanticTokens). + */ + provideDocumentRangeSemanticTokens(document: TextDocument, range: Range, token: CancellationToken): ProviderResult; + } + + export namespace languages { + /** + * Register a semantic tokens provider for a whole document. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their [score](#languages.match) and the best-matching provider is used. Failure + * of the selected provider will cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A document semantic tokens provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDocumentSemanticTokensProvider(selector: DocumentSelector, provider: DocumentSemanticTokensProvider, legend: SemanticTokensLegend): Disposable; + + /** + * Register a semantic tokens provider for a document range. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their [score](#languages.match) and the best-matching provider is used. Failure + * of the selected provider will cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A document range semantic tokens provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDocumentRangeSemanticTokensProvider(selector: DocumentSelector, provider: DocumentRangeSemanticTokensProvider, legend: SemanticTokensLegend): Disposable; + } + + //#endregion + + //#region editor insets: https://github.com/microsoft/vscode/issues/85682 + + export interface WebviewEditorInset { + readonly editor: TextEditor; + readonly line: number; + readonly height: number; + readonly webview: Webview; + readonly onDidDispose: Event; + dispose(): void; + } + + export namespace window { + export function createWebviewTextEditorInset(editor: TextEditor, line: number, height: number, options?: WebviewOptions): WebviewEditorInset; + } + + //#endregion + + //#region read/write in chunks: https://github.com/microsoft/vscode/issues/84515 + + export interface FileSystemProvider { + open?(resource: Uri, options: { create: boolean }): number | Thenable; + close?(fd: number): void | Thenable; + read?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): number | Thenable; + write?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): number | Thenable; + } + + //#endregion + + //#region TextSearchProvider: https://github.com/microsoft/vscode/issues/59921 + + /** + * The parameters of a query for text search. + */ + export interface TextSearchQuery { + /** + * The text pattern to search for. + */ + pattern: string; + + /** + * Whether or not `pattern` should match multiple lines of text. + */ + isMultiline?: boolean; + + /** + * Whether or not `pattern` should be interpreted as a regular expression. + */ + isRegExp?: boolean; + + /** + * Whether or not the search should be case-sensitive. + */ + isCaseSensitive?: boolean; + + /** + * Whether or not to search for whole word matches only. + */ + isWordMatch?: boolean; + } + + /** + * A file glob pattern to match file paths against. + * TODO@roblou - merge this with the GlobPattern docs/definition in vscode.d.ts. + * @see [GlobPattern](#GlobPattern) + */ + export type GlobString = string; + + /** + * Options common to file and text search + */ + export interface SearchOptions { + /** + * The root folder to search within. + */ + folder: Uri; + + /** + * Files that match an `includes` glob pattern should be included in the search. + */ + includes: GlobString[]; + + /** + * Files that match an `excludes` glob pattern should be excluded from the search. + */ + excludes: GlobString[]; + + /** + * Whether external files that exclude files, like .gitignore, should be respected. + * See the vscode setting `"search.useIgnoreFiles"`. + */ + useIgnoreFiles: boolean; + + /** + * Whether symlinks should be followed while searching. + * See the vscode setting `"search.followSymlinks"`. + */ + followSymlinks: boolean; + + /** + * Whether global files that exclude files, like .gitignore, should be respected. + * See the vscode setting `"search.useGlobalIgnoreFiles"`. + */ + useGlobalIgnoreFiles: boolean; + } + + /** + * Options to specify the size of the result text preview. + * These options don't affect the size of the match itself, just the amount of preview text. + */ + export interface TextSearchPreviewOptions { + /** + * The maximum number of lines in the preview. + * Only search providers that support multiline search will ever return more than one line in the match. + */ + matchLines: number; + + /** + * The maximum number of characters included per line. + */ + charsPerLine: number; + } + + /** + * Options that apply to text search. + */ + export interface TextSearchOptions extends SearchOptions { + /** + * The maximum number of results to be returned. + */ + maxResults: number; + + /** + * Options to specify the size of the result text preview. + */ + previewOptions?: TextSearchPreviewOptions; + + /** + * Exclude files larger than `maxFileSize` in bytes. + */ + maxFileSize?: number; + + /** + * Interpret files using this encoding. + * See the vscode setting `"files.encoding"` + */ + encoding?: string; + + /** + * Number of lines of context to include before each match. + */ + beforeContext?: number; + + /** + * Number of lines of context to include after each match. + */ + afterContext?: number; + } + + /** + * Information collected when text search is complete. + */ + export interface TextSearchComplete { + /** + * Whether the search hit the limit on the maximum number of search results. + * `maxResults` on [`TextSearchOptions`](#TextSearchOptions) specifies the max number of results. + * - If exactly that number of matches exist, this should be false. + * - If `maxResults` matches are returned and more exist, this should be true. + * - If search hits an internal limit which is less than `maxResults`, this should be true. + */ + limitHit?: boolean; + } + + /** + * A preview of the text result. + */ + export interface TextSearchMatchPreview { + /** + * The matching lines of text, or a portion of the matching line that contains the match. + */ + text: string; + + /** + * The Range within `text` corresponding to the text of the match. + * The number of matches must match the TextSearchMatch's range property. + */ + matches: Range | Range[]; + } + + /** + * A match from a text search + */ + export interface TextSearchMatch { + /** + * The uri for the matching document. + */ + uri: Uri; + + /** + * The range of the match within the document, or multiple ranges for multiple matches. + */ + ranges: Range | Range[]; + + /** + * A preview of the text match. + */ + preview: TextSearchMatchPreview; + } + + /** + * A line of context surrounding a TextSearchMatch. + */ + export interface TextSearchContext { + /** + * The uri for the matching document. + */ + uri: Uri; + + /** + * One line of text. + * previewOptions.charsPerLine applies to this + */ + text: string; + + /** + * The line number of this line of context. + */ + lineNumber: number; + } + + export type TextSearchResult = TextSearchMatch | TextSearchContext; + + /** + * A TextSearchProvider provides search results for text results inside files in the workspace. + */ + export interface TextSearchProvider { + /** + * Provide results that match the given text pattern. + * @param query The parameters for this query. + * @param options A set of options to consider while searching. + * @param progress A progress callback that must be invoked for all results. + * @param token A cancellation token. + */ + provideTextSearchResults(query: TextSearchQuery, options: TextSearchOptions, progress: Progress, token: CancellationToken): ProviderResult; + } + + //#endregion + + //#region FileSearchProvider: https://github.com/microsoft/vscode/issues/73524 + + /** + * The parameters of a query for file search. + */ + export interface FileSearchQuery { + /** + * The search pattern to match against file paths. + */ + pattern: string; + } + + /** + * Options that apply to file search. + */ + export interface FileSearchOptions extends SearchOptions { + /** + * The maximum number of results to be returned. + */ + maxResults?: number; + + /** + * A CancellationToken that represents the session for this search query. If the provider chooses to, this object can be used as the key for a cache, + * and searches with the same session object can search the same cache. When the token is cancelled, the session is complete and the cache can be cleared. + */ + session?: CancellationToken; + } + + /** + * A FileSearchProvider provides search results for files in the given folder that match a query string. It can be invoked by quickopen or other extensions. + * + * A FileSearchProvider is the more powerful of two ways to implement file search in VS Code. Use a FileSearchProvider if you wish to search within a folder for + * all files that match the user's query. + * + * The FileSearchProvider will be invoked on every keypress in quickopen. When `workspace.findFiles` is called, it will be invoked with an empty query string, + * and in that case, every file in the folder should be returned. + */ + export interface FileSearchProvider { + /** + * Provide the set of files that match a certain file path pattern. + * @param query The parameters for this query. + * @param options A set of options to consider while searching files. + * @param token A cancellation token. + */ + provideFileSearchResults(query: FileSearchQuery, options: FileSearchOptions, token: CancellationToken): ProviderResult; + } + + export namespace workspace { + /** + * Register a search provider. + * + * Only one provider can be registered per scheme. + * + * @param scheme The provider will be invoked for workspace folders that have this file scheme. + * @param provider The provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerFileSearchProvider(scheme: string, provider: FileSearchProvider): Disposable; + + /** + * Register a text search provider. + * + * Only one provider can be registered per scheme. + * + * @param scheme The provider will be invoked for workspace folders that have this file scheme. + * @param provider The provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerTextSearchProvider(scheme: string, provider: TextSearchProvider): Disposable; + } + + //#endregion + + //#region findTextInFiles: https://github.com/microsoft/vscode/issues/59924 + + /** + * Options that can be set on a findTextInFiles search. + */ + export interface FindTextInFilesOptions { + /** + * A [glob pattern](#GlobPattern) that defines the files to search for. The glob pattern + * will be matched against the file paths of files relative to their workspace. Use a [relative pattern](#RelativePattern) + * to restrict the search results to a [workspace folder](#WorkspaceFolder). + */ + include?: GlobPattern; + + /** + * A [glob pattern](#GlobPattern) that defines files and folders to exclude. The glob pattern + * will be matched against the file paths of resulting matches relative to their workspace. When `undefined` only default excludes will + * apply, when `null` no excludes will apply. + */ + exclude?: GlobPattern | null; + + /** + * The maximum number of results to search for + */ + maxResults?: number; + + /** + * Whether external files that exclude files, like .gitignore, should be respected. + * See the vscode setting `"search.useIgnoreFiles"`. + */ + useIgnoreFiles?: boolean; + + /** + * Whether global files that exclude files, like .gitignore, should be respected. + * See the vscode setting `"search.useGlobalIgnoreFiles"`. + */ + useGlobalIgnoreFiles?: boolean; + + /** + * Whether symlinks should be followed while searching. + * See the vscode setting `"search.followSymlinks"`. + */ + followSymlinks?: boolean; + + /** + * Interpret files using this encoding. + * See the vscode setting `"files.encoding"` + */ + encoding?: string; + + /** + * Options to specify the size of the result text preview. + */ + previewOptions?: TextSearchPreviewOptions; + + /** + * Number of lines of context to include before each match. + */ + beforeContext?: number; + + /** + * Number of lines of context to include after each match. + */ + afterContext?: number; + } + + export namespace workspace { + /** + * Search text in files across all [workspace folders](#workspace.workspaceFolders) in the workspace. + * @param query The query parameters for the search - the search string, whether it's case-sensitive, or a regex, or matches whole words. + * @param callback A callback, called for each result + * @param token A token that can be used to signal cancellation to the underlying search engine. + * @return A thenable that resolves when the search is complete. + */ + export function findTextInFiles(query: TextSearchQuery, callback: (result: TextSearchResult) => void, token?: CancellationToken): Thenable; + + /** + * Search text in files across all [workspace folders](#workspace.workspaceFolders) in the workspace. + * @param query The query parameters for the search - the search string, whether it's case-sensitive, or a regex, or matches whole words. + * @param options An optional set of query options. Include and exclude patterns, maxResults, etc. + * @param callback A callback, called for each result + * @param token A token that can be used to signal cancellation to the underlying search engine. + * @return A thenable that resolves when the search is complete. + */ + export function findTextInFiles(query: TextSearchQuery, options: FindTextInFilesOptions, callback: (result: TextSearchResult) => void, token?: CancellationToken): Thenable; + } + + //#endregion + + //#region diff command: https://github.com/microsoft/vscode/issues/84899 + + /** + * The contiguous set of modified lines in a diff. + */ + export interface LineChange { + readonly originalStartLineNumber: number; + readonly originalEndLineNumber: number; + readonly modifiedStartLineNumber: number; + readonly modifiedEndLineNumber: number; + } + + export namespace commands { + + /** + * Registers a diff information command that can be invoked via a keyboard shortcut, + * a menu item, an action, or directly. + * + * Diff information commands are different from ordinary [commands](#commands.registerCommand) as + * they only execute when there is an active diff editor when the command is called, and the diff + * information has been computed. Also, the command handler of an editor command has access to + * the diff information. + * + * @param command A unique identifier for the command. + * @param callback A command handler function with access to the [diff information](#LineChange). + * @param thisArg The `this` context used when invoking the handler function. + * @return Disposable which unregisters this command on disposal. + */ + export function registerDiffInformationCommand(command: string, callback: (diff: LineChange[], ...args: any[]) => any, thisArg?: any): Disposable; + } + + //#endregion + + //#region file-decorations: https://github.com/microsoft/vscode/issues/54938 + + export class Decoration { + letter?: string; + title?: string; + color?: ThemeColor; + priority?: number; + bubble?: boolean; + } + + export interface DecorationProvider { + onDidChangeDecorations: Event; + provideDecoration(uri: Uri, token: CancellationToken): ProviderResult; + } + + export namespace window { + export function registerDecorationProvider(provider: DecorationProvider): Disposable; + } + + //#endregion + + //#region Debug: + + // deprecated + + export interface DebugConfigurationProvider { + /** + * Deprecated, use DebugAdapterDescriptorFactory.provideDebugAdapter instead. + * @deprecated Use DebugAdapterDescriptorFactory.createDebugAdapterDescriptor instead + */ + debugAdapterExecutable?(folder: WorkspaceFolder | undefined, token?: CancellationToken): ProviderResult; + } + + //#endregion + + //#region LogLevel: https://github.com/microsoft/vscode/issues/85992 + + /** + * The severity level of a log message + */ + export enum LogLevel { + Trace = 1, + Debug = 2, + Info = 3, + Warning = 4, + Error = 5, + Critical = 6, + Off = 7 + } + + export namespace env { + /** + * Current logging level. + */ + export const logLevel: LogLevel; + + /** + * An [event](#Event) that fires when the log level has changed. + */ + export const onDidChangeLogLevel: Event; + } + + //#endregion + + //#region Joao: SCM validation + + /** + * Represents the validation type of the Source Control input. + */ + export enum SourceControlInputBoxValidationType { + + /** + * Something not allowed by the rules of a language or other means. + */ + Error = 0, + + /** + * Something suspicious but allowed. + */ + Warning = 1, + + /** + * Something to inform about but not a problem. + */ + Information = 2 + } + + export interface SourceControlInputBoxValidation { + + /** + * The validation message to display. + */ + readonly message: string; + + /** + * The validation type. + */ + readonly type: SourceControlInputBoxValidationType; + } + + /** + * Represents the input box in the Source Control viewlet. + */ + export interface SourceControlInputBox { + + /** + * A validation function for the input box. It's possible to change + * the validation provider simply by setting this property to a different function. + */ + validateInput?(value: string, cursorPosition: number): ProviderResult; + } + + //#endregion + + //#region Joao: SCM selected provider + + export interface SourceControl { + + /** + * Whether the source control is selected. + */ + readonly selected: boolean; + + /** + * An event signaling when the selection state changes. + */ + readonly onDidChangeSelection: Event; + } + + //#endregion + + //#region Joao: SCM Input Box + + /** + * Represents the input box in the Source Control viewlet. + */ + export interface SourceControlInputBox { + + /** + * Controls whether the input box is visible (default is `true`). + */ + visible: boolean; + } + + //#endregion + + //#region Terminal data write event https://github.com/microsoft/vscode/issues/78502 + + export interface TerminalDataWriteEvent { + /** + * The [terminal](#Terminal) for which the data was written. + */ + readonly terminal: Terminal; + /** + * The data being written. + */ + readonly data: string; + } + + namespace window { + /** + * An event which fires when the terminal's pty slave pseudo-device is written to. In other + * words, this provides access to the raw data stream from the process running within the + * terminal, including VT sequences. + */ + export const onDidWriteTerminalData: Event; + } + + //#endregion + + //#region Terminal exit status https://github.com/microsoft/vscode/issues/62103 + + export interface TerminalExitStatus { + /** + * The exit code that a terminal exited with, it can have the following values: + * - Zero: the terminal process or custom execution succeeded. + * - Non-zero: the terminal process or custom execution failed. + * - `undefined`: the user forcibly closed the terminal or a custom execution exited + * without providing an exit code. + */ + readonly code: number | undefined; + } + + export interface Terminal { + /** + * The exit status of the terminal, this will be undefined while the terminal is active. + * + * **Example:** Show a notification with the exit code when the terminal exits with a + * non-zero exit code. + * ```typescript + * window.onDidCloseTerminal(t => { + * if (t.exitStatus && t.exitStatus.code) { + * vscode.window.showInformationMessage(`Exit code: ${t.exitStatus.code}`); + * } + * }); + * ``` + */ + readonly exitStatus: TerminalExitStatus | undefined; + } + + //#endregion + + //#region Terminal dimensions property and change event https://github.com/microsoft/vscode/issues/55718 + + /** + * An [event](#Event) which fires when a [Terminal](#Terminal)'s dimensions change. + */ + export interface TerminalDimensionsChangeEvent { + /** + * The [terminal](#Terminal) for which the dimensions have changed. + */ + readonly terminal: Terminal; + /** + * The new value for the [terminal's dimensions](#Terminal.dimensions). + */ + readonly dimensions: TerminalDimensions; + } + + namespace window { + /** + * An event which fires when the [dimensions](#Terminal.dimensions) of the terminal change. + */ + export const onDidChangeTerminalDimensions: Event; + } + + export interface Terminal { + /** + * The current dimensions of the terminal. This will be `undefined` immediately after the + * terminal is created as the dimensions are not known until shortly after the terminal is + * created. + */ + readonly dimensions: TerminalDimensions | undefined; + } + + //#endregion + + //#region Joh -> exclusive document filters + + export interface DocumentFilter { + exclusive?: boolean; + } + + //#endregion + + //#region Alex - OnEnter enhancement + export interface OnEnterRule { + /** + * This rule will only execute if the text above the this line matches this regular expression. + */ + oneLineAboveText?: RegExp; + } + //#endregion + + //#region Tree View: https://github.com/microsoft/vscode/issues/61313 + /** + * Label describing the [Tree item](#TreeItem) + */ + export interface TreeItemLabel { + + /** + * A human-readable string describing the [Tree item](#TreeItem). + */ + label: string; + + /** + * Ranges in the label to highlight. A range is defined as a tuple of two number where the + * first is the inclusive start index and the second the exclusive end index + */ + highlights?: [number, number][]; + + } + + export class TreeItem2 extends TreeItem { + /** + * Label describing this item. When `falsy`, it is derived from [resourceUri](#TreeItem.resourceUri). + */ + label?: string | TreeItemLabel | /* for compilation */ any; + + /** + * @param label Label describing this item + * @param collapsibleState [TreeItemCollapsibleState](#TreeItemCollapsibleState) of the tree item. Default is [TreeItemCollapsibleState.None](#TreeItemCollapsibleState.None) + */ + constructor(label: TreeItemLabel, collapsibleState?: TreeItemCollapsibleState); + } + //#endregion + + //#region CustomExecution: https://github.com/microsoft/vscode/issues/81007 + /** + * A task to execute + */ + export class Task2 extends Task { + detail?: string; + } + + export class CustomExecution2 extends CustomExecution { + /** + * Constructs a CustomExecution task object. The callback will be executed the task is run, at which point the + * extension should return the Pseudoterminal it will "run in". The task should wait to do further execution until + * [Pseudoterminal.open](#Pseudoterminal.open) is called. Task cancellation should be handled using + * [Pseudoterminal.close](#Pseudoterminal.close). When the task is complete fire + * [Pseudoterminal.onDidClose](#Pseudoterminal.onDidClose). + * @param callback The callback that will be called when the task is started by a user. + */ + constructor(callback: (resolvedDefinition?: TaskDefinition) => Thenable); + } + //#endregion + + //#region Task presentation group: https://github.com/microsoft/vscode/issues/47265 + export interface TaskPresentationOptions { + /** + * Controls whether the task is executed in a specific terminal group using split panes. + */ + group?: string; + } + //#endregion + + //#region Status bar item with ID and Name: https://github.com/microsoft/vscode/issues/74972 + + export namespace window { + + /** + * Options to configure the status bar item. + */ + export interface StatusBarItemOptions { + + /** + * A unique identifier of the status bar item. The identifier + * is for example used to allow a user to show or hide the + * status bar item in the UI. + */ + id: string; + + /** + * A human readable name of the status bar item. The name is + * for example used as a label in the UI to show or hide the + * status bar item. + */ + name: string; + + /** + * The alignment of the status bar item. + */ + alignment?: StatusBarAlignment; + + /** + * The priority of the status bar item. Higher value means the item should + * be shown more to the left. + */ + priority?: number; + } + + /** + * Creates a status bar [item](#StatusBarItem). + * + * @param options The options of the item. If not provided, some default values + * will be assumed. For example, the `StatusBarItemOptions.id` will be the id + * of the extension and the `StatusBarItemOptions.name` will be the extension name. + * @return A new status bar item. + */ + export function createStatusBarItem(options?: StatusBarItemOptions): StatusBarItem; + } + + //#endregion + + //#region Custom editors: https://github.com/microsoft/vscode/issues/77131 + + /** + * Defines the editing functionality of a webview editor. This allows the webview editor to hook into standard + * editor events such as `undo` or `save`. + * + * @param EditType Type of edits. + */ + interface WebviewCustomEditorEditingDelegate { + /** + * Save a resource. + * + * @param resource Resource being saved. + * + * @return Thenable signaling that the save has completed. + */ + save(resource: Uri): Thenable; + + /** + * Save an existing resource at a new path. + * + * @param resource Resource being saved. + * @param targetResource Location to save to. + * + * @return Thenable signaling that the save has completed. + */ + saveAs(resource: Uri, targetResource: Uri): Thenable; + + /** + * Event triggered by extensions to signal to VS Code that an edit has occurred. + */ + // TODO@matt + // eslint-disable-next-line vscode-dts-event-naming + readonly onEdit: Event<{ readonly resource: Uri, readonly edit: EditType }>; + + /** + * Apply a set of edits. + * + * Note that is not invoked when `onEdit` is called as `onEdit` implies also updating the view to reflect the edit. + * + * @param resource Resource being edited. + * @param edit Array of edits. Sorted from oldest to most recent. + * + * @return Thenable signaling that the change has completed. + */ + applyEdits(resource: Uri, edits: readonly EditType[]): Thenable; + + /** + * Undo a set of edits. + * + * This is triggered when a user undoes an edit or when revert is called on a file. + * + * @param resource Resource being edited. + * @param edit Array of edits. Sorted from most recent to oldest. + * + * @return Thenable signaling that the change has completed. + */ + undoEdits(resource: Uri, edits: readonly EditType[]): Thenable; + + /** + * Back up `resource` in its current state. + * + * Backups are used for hot exit and to prevent data loss. Your `backup` method should persist the resource in + * its current state, i.e. with the edits applied. Most commonly this means saving the resource to disk in + * the `ExtensionContext.storagePath`. When VS Code reloads and your custom editor is opened for a resource, + * your extension should first check to see if any backups exist for the resource. If there is a backup, your + * extension should load the file contents from there instead of from the resource in the workspace. + * + * `backup` is triggered whenever an edit it made. Calls to `backup` are debounced so that if multiple edits are + * made in quick succession, `backup` is only triggered after the last one. `backup` is not invoked when + * `auto save` is enabled (since auto save already persists resource ). + * + * @param resource The resource to back up. + * @param cancellation Token that signals the current backup since a new backup is coming in. It is up to your + * extension to decided how to respond to cancellation. If for example your extension is backing up a large file + * in an operation that takes time to complete, your extension may decide to finish the ongoing backup rather + * than cancelling it to ensure that VS Code has some valid backup. + */ + backup?(resource: Uri, cancellation: CancellationToken): Thenable; + } + + export interface WebviewCustomEditorProvider { + /** + * Resolve a webview editor for a given resource. + * + * To resolve a webview editor, a provider must fill in its initial html content and hook up all + * the event listeners it is interested it. The provider should also take ownership of the passed in `WebviewPanel`. + * + * @param resource Resource being resolved. + * @param webview Webview being resolved. The provider should take ownership of this webview. + * + * @return Thenable indicating that the webview editor has been resolved. + */ + resolveWebviewEditor( + resource: Uri, + webview: WebviewPanel, + ): Thenable; + + /** + * Controls the editing functionality of a webview editor. This allows the webview editor to hook into standard + * editor events such as `undo` or `save`. + * + * WebviewEditors that do not have `editingCapability` are considered to be readonly. Users can still interact + * with readonly editors, but these editors will not integrate with VS Code's standard editor functionality. + */ + readonly editingDelegate?: WebviewCustomEditorEditingDelegate; + } + + namespace window { + /** + * Register a new provider for webview editors of a given type. + * + * @param viewType Type of the webview editor provider. + * @param provider Resolves webview editors. + * @param options Content settings for a webview panels the provider is given. + * + * @return Disposable that unregisters the `WebviewCustomEditorProvider`. + */ + export function registerWebviewCustomEditorProvider( + viewType: string, + provider: WebviewCustomEditorProvider, + options?: WebviewPanelOptions, + ): Disposable; + } + + //#endregion + + + //#region allow QuickPicks to skip sorting: https://github.com/microsoft/vscode/issues/73904 + + export interface QuickPick extends QuickInput { + /** + * An optional flag to sort the final results by index of first query match in label. Defaults to true. + */ + sortByLabel: boolean; + } + + //#endregion + + //#region Surfacing reasons why a code action cannot be applied to users: https://github.com/microsoft/vscode/issues/85160 + + export interface CodeAction { + /** + * Marks that the code action cannot currently be applied. + * + * Disabled code actions will be surfaced in the refactor UI but cannot be applied. + */ + disabled?: { + /** + * Human readable description of why the code action is currently disabled. + * + * This is displayed in the UI. + */ + reason: string; + }; + } + + //#endregion + + //#region Allow theme icons in hovers: https://github.com/microsoft/vscode/issues/84695 + + export interface MarkdownString { + + /** + * Indicates that this markdown string can contain [ThemeIcons](#ThemeIcon), e.g. `$(zap)`. + */ + readonly supportThemeIcons?: boolean; + } + + //#endregion + + //#region color theme access + + /** + * Represents a color theme kind. + */ + export enum ColorThemeKind { + Light = 1, + Dark = 2, + HighContrast = 3 + } + + /** + * Represents a color theme. + */ + export interface ColorTheme { + + /** + * The kind of this color theme: light, dark or high contrast. + */ + readonly kind: ColorThemeKind; + } + + export namespace window { + /** + * The currently active color theme as configured in the settings. The active + * theme can be changed via the `workbench.colorTheme` setting. + */ + export let activeColorTheme: ColorTheme; + + /** + * An [event](#Event) which fires when the active theme changes or one of it's colors chnage. + */ + export const onDidChangeActiveColorTheme: Event; + } + + //#endregion + + + //#region https://github.com/microsoft/vscode/issues/39441 + + export interface CompletionItem { + /** + * Will be merged into CompletionItem#label + */ + label2?: CompletionItemLabel; + } + + export interface CompletionItemLabel { + /** + * The function or variable. Rendered leftmost. + */ + name: string; + + /** + * The signature without the return type. Render after `name`. + */ + signature?: string; + + /** + * The fully qualified name, like package name or file path. Rendered after `signature`. + */ + qualifier?: string; + + /** + * The return-type of a function or type of a property/variable. Rendered rightmost. + */ + type?: string; + } + + //#endregion + + + //#region https://github.com/microsoft/vscode/issues/77728 + + export interface WorkspaceEditMetadata { + needsConfirmation: boolean; + label: string; + description?: string; + iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon; + } + + export interface WorkspaceEdit { + + insert(uri: Uri, position: Position, newText: string, metadata?: WorkspaceEditMetadata): void; + delete(uri: Uri, range: Range, metadata?: WorkspaceEditMetadata): void; + replace(uri: Uri, range: Range, newText: string, metadata?: WorkspaceEditMetadata): void; + + createFile(uri: Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean }, metadata?: WorkspaceEditMetadata): void; + deleteFile(uri: Uri, options?: { recursive?: boolean, ignoreIfNotExists?: boolean }, metadata?: WorkspaceEditMetadata): void; + renameFile(oldUri: Uri, newUri: Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean }, metadata?: WorkspaceEditMetadata): void; + } + + //#endregion + + //#region Diagnostic links https://github.com/microsoft/vscode/issues/11847 + + export interface Diagnostic { + /** + * Will be merged into `Diagnostic#code` + */ + code2?: { + /** + * A code or identifier for this diagnostic. + * Should be used for later processing, e.g. when providing [code actions](#CodeActionContext). + */ + value: string | number; + + /** + * A link to a URI with more information about the diagnostic error. + */ + link: Uri; + } + } + + //#endregion + + //#region eamodio - timeline: https://github.com/microsoft/vscode/issues/84297 + + export class TimelineItem { + /** + * A timestamp (in milliseconds since 1 January 1970 00:00:00) for when the timeline item occurred. + */ + timestamp: number; + + /** + * A human-readable string describing the timeline item. + */ + label: string; + + /** + * Optional id for the timeline item. + */ + /** + * Optional id for the timeline item that has to be unique across your timeline source. + * + * If not provided, an id is generated using the timeline item's label. + */ + id?: string; + + /** + * The icon path or [ThemeIcon](#ThemeIcon) for the timeline item. + */ + iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon; + + /** + * A human readable string describing less prominent details of the timeline item. + */ + description?: string; + + /** + * The tooltip text when you hover over the timeline item. + */ + detail?: string; + + /** + * The [command](#Command) that should be executed when the timeline item is selected. + */ + command?: Command; + + /** + * Context value of the timeline item. This can be used to contribute specific actions to the item. + * For example, a timeline item is given a context value as `commit`. When contributing actions to `timeline/item/context` + * using `menus` extension point, you can specify context value for key `timelineItem` in `when` expression like `timelineItem == commit`. + * ``` + * "contributes": { + * "menus": { + * "timeline/item/context": [ + * { + * "command": "extension.copyCommitId", + * "when": "timelineItem == commit" + * } + * ] + * } + * } + * ``` + * This will show the `extension.copyCommitId` action only for items where `contextValue` is `commit`. + */ + contextValue?: string; + + /** + * @param label A human-readable string describing the timeline item + * @param timestamp A timestamp (in milliseconds since 1 January 1970 00:00:00) for when the timeline item occurred + */ + constructor(label: string, timestamp: number); + } + + export interface TimelineChangeEvent { + /** + * The [uri](#Uri) of the resource for which the timeline changed. + * If the [uri](#Uri) is `undefined` that signals that the timeline source for all resources changed. + */ + uri?: Uri; + } + + export interface TimelineProvider { + /** + * An optional event to signal that the timeline for a source has changed. + * To signal that the timeline for all resources (uris) has changed, do not pass any argument or pass `undefined`. + */ + onDidChange?: Event; + + /** + * An identifier of the source of the timeline items. This can be used to filter sources. + */ + id: string; + + /** + * A human-readable string describing the source of the timeline items. This can be used as the display label when filtering sources. + */ + label: string; + + /** + * Provide [timeline items](#TimelineItem) for a [Uri](#Uri). + * + * @param uri The [uri](#Uri) of the file to provide the timeline for. + * @param token A cancellation token. + * @return An array of timeline items or a thenable that resolves to such. The lack of a result + * can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideTimeline(uri: Uri, token: CancellationToken): ProviderResult; + } + + export namespace workspace { + /** + * Register a timeline provider. + * + * Multiple providers can be registered. In that case, providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A timeline provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerTimelineProvider(selector: DocumentSelector, provider: TimelineProvider): Disposable; + } + + //#endregion + + + //#region https://github.com/microsoft/vscode/issues/90208 + + export interface ExtensionContext { + /** + * Get the uri of a resource contained in the extension. + * + * @param relativePath A relative path to a resource contained in the extension. + * @return The uri of the resource. + */ + asExtensionUri(relativePath: string): Uri; + } + + //#endregion }