diff --git a/.eslintrc.js b/.eslintrc.js index c83464ab..2cc83488 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -25,6 +25,10 @@ module.exports = { '!.*rc.*', '!*.config.js', '!*.d.ts', + + // Ignore, since this file is vendored from VSCode and should not be changed. + // See `CONTRIBUTING.md`. + 'src/types/git.d.ts', ], rules: { /* diff --git a/CHANGELOG.md b/CHANGELOG.md index ba680795..5ed2219f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,6 @@ - use more subtle styling when a reaction involves the local radicle identity (italic text vs border & background) - show "you" instead of local identity's alias - on hover show the truncated DId next to each identity -- **settings:** add config to toggle excluding temporary files created by the extension, e.g. those used to produce the diff of a patch's changed files, from the list of recently opened files. This is enabled by default. This currently works only partly, but should automatically be fully working when [the underlying VS Code bug](https://github.com/microsoft/vscode/issues/157395#issuecomment-2080293320) is fixed. ([#94](https://github.com/cytechmobile/radicle-vscode-extension/issues/94)) - **patch-list:** show diff for copied and moved files of a patch too when available ([#100](https://github.com/cytechmobile/radicle-vscode-extension/issues/100)) - **patch-list:** show path to containing directory for each changed file of a patch ([#100](https://github.com/cytechmobile/radicle-vscode-extension/issues/100)) - **patch-list:** feat(patch-list): increase count of fetched patches per status to 500 ([#100](https://github.com/cytechmobile/radicle-vscode-extension/issues/100)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0fe87540..76af61ea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -89,3 +89,16 @@ If necessary, specific code shared between extension and webviews should be extr ### Getting user input Use custom wrapper `askUser()` instead of the native [InputBox API](https://code.visualstudio.com/api/references/vscode-api#InputBox) which would result in procedural, verbose and brittle client code. + +## Vendored Dependencies + +Types for the [Git integration for VSCode](https://github.com/microsoft/vscode/tree/main/extensions/git) are vendored at [`src/types/git.d.ts`](src/types/git.d.ts). + +To update those, proceed as follows: + +```sh +$ export VSCODE_TAG="1.88.1" # Adjust this to match desired version of VSCode. +$ git remote add vscode "https://github.com/microsoft/vscode.git" +$ git fetch --depth 1 vscode "$VSCODE_TAG" +$ git show $(git ls-remote --refs --tags vscode "$VSCODE_TAG" | cut -d$'\t' -f1):extensions/git/src/api/git.d.ts > src/types/git.d.ts +``` diff --git a/package.json b/package.json index d02b1ae8..6f89d73f 100644 --- a/package.json +++ b/package.json @@ -506,6 +506,9 @@ "ts-xor": "^1.3.0", "typescript": "^5.3.3" }, + "extensionDependencies": [ + "vscode.git" + ], "simple-git-hooks": { "pre-commit": "npm run lint" }, diff --git a/src/constants.ts b/src/constants.ts deleted file mode 100644 index 552a29ec..00000000 --- a/src/constants.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { sep } from 'node:path' -import { tmpdir } from 'node:os' - -export const extTempDir = `${tmpdir()}${sep}radicle` diff --git a/src/helpers/command.ts b/src/helpers/command.ts index 7cbc47ea..f756436a 100644 --- a/src/helpers/command.ts +++ b/src/helpers/command.ts @@ -1,4 +1,4 @@ -import { type TextDocumentShowOptions, Uri, commands, window } from 'vscode' +import { type TextDocumentShowOptions, type Uri, commands, window } from 'vscode' import { getExtensionContext, usePatchStore } from '../stores' import { exec, log, showLog } from '../utils' import { @@ -116,8 +116,8 @@ export function registerAllCommands(): void { registerVsCodeCmd( 'radicle.openOriginalVersionOfPatchedFile', async (node: FilechangeNode | undefined) => { - if (node?.oldVersionUrl) { - await commands.executeCommand('vscode.open', Uri.file(node.oldVersionUrl)) + if (node?.oldVersionUri) { + await commands.executeCommand('vscode.open', node.oldVersionUri) commands.executeCommand('workbench.action.files.setActiveEditorReadonlyInSession') } else { log( @@ -131,8 +131,8 @@ export function registerAllCommands(): void { registerVsCodeCmd( 'radicle.openChangedVersionOfPatchedFile', async (node: FilechangeNode | undefined) => { - if (node?.newVersionUrl) { - await commands.executeCommand('vscode.open', Uri.file(node.newVersionUrl)) + if (node?.newVersionUri) { + await commands.executeCommand('vscode.open', node.newVersionUri) commands.executeCommand('workbench.action.files.setActiveEditorReadonlyInSession') } else { log( diff --git a/src/helpers/config.ts b/src/helpers/config.ts index 75e9d936..a07df37a 100644 --- a/src/helpers/config.ts +++ b/src/helpers/config.ts @@ -13,7 +13,6 @@ export interface ExtensionConfig { 'radicle.advanced.pathToRadBinary': string 'radicle.advanced.pathToNodeHome': string 'radicle.advanced.httpApiEndpoint': string - 'radicle.hideTempFiles': boolean } /** @@ -33,10 +32,7 @@ export function getConfig( case 'radicle.advanced.httpApiEndpoint': // if the config has the value of the empty string (default) then return `undefined` // @ts-expect-error - // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call return config.get(configKey)?.trim() || undefined - case 'radicle.hideTempFiles': - return config.get(configKey) default: return assertUnreachable(configKey) } @@ -56,8 +52,6 @@ export function setConfig( case 'radicle.advanced.pathToNodeHome': case 'radicle.advanced.httpApiEndpoint': return config.update(configKey, value, ConfigurationTarget.Global) - case 'radicle.hideTempFiles': - return config.update(configKey, value, ConfigurationTarget.Global) default: return assertUnreachable(configKey) } diff --git a/src/helpers/configWatcher.ts b/src/helpers/configWatcher.ts index 4d227904..bba7f18d 100644 --- a/src/helpers/configWatcher.ts +++ b/src/helpers/configWatcher.ts @@ -1,6 +1,5 @@ import { workspace } from 'vscode' import { - validateHideTempFilesConfigAlignment, validateHttpdConnection, validateRadCliInstallation, validateRadicleIdentityAuthentication, @@ -52,11 +51,6 @@ const configWatchers = [ usePatchStore().resetAllPatches() }, }, - { - configKey: 'radicle.hideTempFiles', - onConfigChange: validateHideTempFilesConfigAlignment, - onBeforeWatcherRegistration: validateHideTempFilesConfigAlignment, - }, ] satisfies OnConfigChangeParam[] /** @@ -65,7 +59,6 @@ const configWatchers = [ */ export function registerAllConfigWatchers(): void { configWatchers.forEach((cw) => { - cw.onBeforeWatcherRegistration?.() onConfigChange(cw.configKey, cw.onConfigChange) }) } diff --git a/src/types/git.d.ts b/src/types/git.d.ts new file mode 100644 index 00000000..680f172a --- /dev/null +++ b/src/types/git.d.ts @@ -0,0 +1,349 @@ +/* --------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *-------------------------------------------------------------------------------------------- */ + +import type { Disposable, Event, ProviderResult, Uri } from 'vscode' + +export { ProviderResult } from 'vscode' + +export interface Git { + readonly path: string +} + +export interface InputBox { + value: string +} + +export const enum ForcePushMode { + Force, + ForceWithLease, +} + +export const enum RefType { + Head, + RemoteHead, + Tag, +} + +export interface Ref { + readonly type: RefType + readonly name?: string + readonly commit?: string + readonly remote?: string +} + +export interface UpstreamRef { + readonly remote: string + readonly name: string +} + +export interface Branch extends Ref { + readonly upstream?: UpstreamRef + readonly ahead?: number + readonly behind?: number +} + +export interface Commit { + readonly hash: string + readonly message: string + readonly parents: string[] + readonly authorDate?: Date + readonly authorName?: string + readonly authorEmail?: string + readonly commitDate?: Date +} + +export interface Submodule { + readonly name: string + readonly path: string + readonly url: string +} + +export interface Remote { + readonly name: string + readonly fetchUrl?: string + readonly pushUrl?: string + readonly isReadOnly: boolean +} + +export const enum Status { + INDEX_MODIFIED, + INDEX_ADDED, + INDEX_DELETED, + INDEX_RENAMED, + INDEX_COPIED, + + MODIFIED, + DELETED, + UNTRACKED, + IGNORED, + INTENT_TO_ADD, + + ADDED_BY_US, + ADDED_BY_THEM, + DELETED_BY_US, + DELETED_BY_THEM, + BOTH_ADDED, + BOTH_DELETED, + BOTH_MODIFIED, +} + +export interface Change { + /** + * Returns either `originalUri` or `renameUri`, depending + * on whether this change is a rename change. When + * in doubt always use `uri` over the other two alternatives. + */ + readonly uri: Uri + readonly originalUri: Uri + readonly renameUri: Uri | undefined + readonly status: Status +} + +export interface RepositoryState { + readonly HEAD: Branch | undefined + readonly refs: Ref[] + readonly remotes: Remote[] + readonly submodules: Submodule[] + readonly rebaseCommit: Commit | undefined + + readonly mergeChanges: Change[] + readonly indexChanges: Change[] + readonly workingTreeChanges: Change[] + + readonly onDidChange: Event +} + +export interface RepositoryUIState { + readonly selected: boolean + readonly onDidChange: Event +} + +/** + * Log options. + */ +export interface LogOptions { + /** Max number of log entries to retrieve. If not specified, the default is 32. */ + readonly maxEntries?: number + readonly path?: string +} + +export interface CommitOptions { + all?: boolean | 'tracked' + amend?: boolean + signoff?: boolean + signCommit?: boolean + empty?: boolean + noVerify?: boolean + requireUserConfig?: boolean +} + +export interface FetchOptions { + remote?: string + ref?: string + all?: boolean + prune?: boolean + depth?: number +} + +export interface BranchQuery { + readonly remote?: boolean + readonly pattern?: string + readonly count?: number + readonly contains?: string +} + +export interface Repository { + readonly rootUri: Uri + readonly inputBox: InputBox + readonly state: RepositoryState + readonly ui: RepositoryUIState + + getConfigs(): Promise<{ key: string; value: string }[]> + getConfig(key: string): Promise + setConfig(key: string, value: string): Promise + getGlobalConfig(key: string): Promise + + getObjectDetails( + treeish: string, + path: string, + ): Promise<{ mode: string; object: string; size: number }> + detectObjectType(object: string): Promise<{ mimetype: string; encoding?: string }> + buffer(ref: string, path: string): Promise + show(ref: string, path: string): Promise + getCommit(ref: string): Promise + + add(paths: string[]): Promise + clean(paths: string[]): Promise + + apply(patch: string, reverse?: boolean): Promise + diff(cached?: boolean): Promise + diffWithHEAD(): Promise + diffWithHEAD(path: string): Promise + diffWith(ref: string): Promise + diffWith(ref: string, path: string): Promise + diffIndexWithHEAD(): Promise + diffIndexWithHEAD(path: string): Promise + diffIndexWith(ref: string): Promise + diffIndexWith(ref: string, path: string): Promise + diffBlobs(object1: string, object2: string): Promise + diffBetween(ref1: string, ref2: string): Promise + diffBetween(ref1: string, ref2: string, path: string): Promise + + hashObject(data: string): Promise + + createBranch(name: string, checkout: boolean, ref?: string): Promise + deleteBranch(name: string, force?: boolean): Promise + getBranch(name: string): Promise + getBranches(query: BranchQuery): Promise + setBranchUpstream(name: string, upstream: string): Promise + + getMergeBase(ref1: string, ref2: string): Promise + + tag(name: string, upstream: string): Promise + deleteTag(name: string): Promise + + status(): Promise + checkout(treeish: string): Promise + + addRemote(name: string, url: string): Promise + removeRemote(name: string): Promise + renameRemote(name: string, newName: string): Promise + + fetch(options?: FetchOptions): Promise + fetch(remote?: string, ref?: string, depth?: number): Promise + pull(unshallow?: boolean): Promise + push( + remoteName?: string, + branchName?: string, + setUpstream?: boolean, + force?: ForcePushMode, + ): Promise + + blame(path: string): Promise + log(options?: LogOptions): Promise + + commit(message: string, opts?: CommitOptions): Promise +} + +export interface RemoteSource { + readonly name: string + readonly description?: string + readonly url: string | string[] +} + +export interface RemoteSourceProvider { + readonly name: string + readonly icon?: string // codicon name + readonly supportsQuery?: boolean + getRemoteSources(query?: string): ProviderResult + getBranches?(url: string): ProviderResult + publishRepository?(repository: Repository): Promise +} + +export interface RemoteSourcePublisher { + readonly name: string + readonly icon?: string // codicon name + publishRepository(repository: Repository): Promise +} + +export interface Credentials { + readonly username: string + readonly password: string +} + +export interface CredentialsProvider { + getCredentials(host: Uri): ProviderResult +} + +export interface PushErrorHandler { + handlePushError( + repository: Repository, + remote: Remote, + refspec: string, + error: Error & { gitErrorCode: GitErrorCodes }, + ): Promise +} + +export type APIState = 'uninitialized' | 'initialized' + +export interface PublishEvent { + repository: Repository + branch?: string +} + +export interface API { + readonly state: APIState + readonly onDidChangeState: Event + readonly onDidPublish: Event + readonly git: Git + readonly repositories: Repository[] + readonly onDidOpenRepository: Event + readonly onDidCloseRepository: Event + + toGitUri(uri: Uri, ref: string): Uri + getRepository(uri: Uri): Repository | null + init(root: Uri): Promise + openRepository(root: Uri): Promise + + registerRemoteSourcePublisher(publisher: RemoteSourcePublisher): Disposable + registerRemoteSourceProvider(provider: RemoteSourceProvider): Disposable + registerCredentialsProvider(provider: CredentialsProvider): Disposable + registerPushErrorHandler(handler: PushErrorHandler): Disposable +} + +export interface GitExtension { + readonly enabled: boolean + readonly onDidChangeEnablement: Event + + /** + * Returns a specific API version. + * + * Throws error if git extension is disabled. You can listed to the + * [GitExtension.onDidChangeEnablement](#GitExtension.onDidChangeEnablement) event + * to know when the extension becomes enabled/disabled. + * + * @param version Version number. + * @returns API instance + */ + getAPI(version: 1): API +} + +export const enum GitErrorCodes { + BadConfigFile = 'BadConfigFile', + AuthenticationFailed = 'AuthenticationFailed', + NoUserNameConfigured = 'NoUserNameConfigured', + NoUserEmailConfigured = 'NoUserEmailConfigured', + NoRemoteRepositorySpecified = 'NoRemoteRepositorySpecified', + NotAGitRepository = 'NotAGitRepository', + NotAtRepositoryRoot = 'NotAtRepositoryRoot', + Conflict = 'Conflict', + StashConflict = 'StashConflict', + UnmergedChanges = 'UnmergedChanges', + PushRejected = 'PushRejected', + RemoteConnectionError = 'RemoteConnectionError', + DirtyWorkTree = 'DirtyWorkTree', + CantOpenResource = 'CantOpenResource', + GitNotFound = 'GitNotFound', + CantCreatePipe = 'CantCreatePipe', + PermissionDenied = 'PermissionDenied', + CantAccessRemote = 'CantAccessRemote', + RepositoryNotFound = 'RepositoryNotFound', + RepositoryIsLocked = 'RepositoryIsLocked', + BranchNotFullyMerged = 'BranchNotFullyMerged', + NoRemoteReference = 'NoRemoteReference', + InvalidBranchName = 'InvalidBranchName', + BranchAlreadyExists = 'BranchAlreadyExists', + NoLocalChanges = 'NoLocalChanges', + NoStashFound = 'NoStashFound', + LocalChangesOverwritten = 'LocalChangesOverwritten', + NoUpstreamBranch = 'NoUpstreamBranch', + IsInSubmodule = 'IsInSubmodule', + WrongCase = 'WrongCase', + CantLockRef = 'CantLockRef', + CantRebaseMultipleBranches = 'CantRebaseMultipleBranches', + PatchDoesNotApply = 'PatchDoesNotApply', + NoPathFound = 'NoPathFound', + UnknownPath = 'UnknownPath', +} diff --git a/src/types/index.ts b/src/types/index.ts index d40d9662..09409a5e 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -3,3 +3,4 @@ export * from './httpd-augmented' export * from './httpd' export * from './prettify' export * from './webviewInjectedState' +export type { API as GitExtensionAPI, GitExtension } from './git.d.ts' diff --git a/src/utils/git.ts b/src/utils/git.ts index 285474c0..62ef1047 100644 --- a/src/utils/git.ts +++ b/src/utils/git.ts @@ -1,3 +1,4 @@ +import type { GitExtensionAPI } from '../types' import { exec } from '.' /** @@ -34,3 +35,15 @@ export function getCurrentGitBranch(): string | undefined { return currentBranch } + +// TODO(lorenzleutgeb): Get some typings for vscode! +// eslint-disable-next-line @typescript-eslint/no-explicit-any +declare const vscode: any + +export function getGitExtensionAPI(): GitExtensionAPI { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + const gitExtension = vscode.extensions.getExtension('vscode.git').exports + + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + return gitExtension.getAPI(1) as GitExtensionAPI +} diff --git a/src/ux/patchesView.ts b/src/ux/patchesView.ts index 42f6d295..29e602eb 100644 --- a/src/ux/patchesView.ts +++ b/src/ux/patchesView.ts @@ -1,5 +1,4 @@ import Path, { sep } from 'node:path' -import * as fs from 'node:fs/promises' import { EventEmitter, MarkdownString, @@ -11,28 +10,20 @@ import { TreeItemCollapsibleState, Uri, } from 'vscode' -import { extTempDir } from '../constants' import { usePatchStore } from '../stores' import { debouncedClearMemoizedGetCurrentProjectIdCache, fetchFromHttpd, memoizedGetCurrentProjectId, } from '../helpers' -import { - type AugmentedPatch, - type Patch, - type Unarray, - isCopiedOrMovedFilechangeWithDiff, - isMovedFilechangeWithoutDiff, - isPatch, -} from '../types' +import { type AugmentedPatch, type Patch, type Unarray, isPatch } from '../types' import { assertUnreachable, capitalizeFirstLetter, getFirstAndLatestRevisions, getIdentityAliasOrId, + getRepoRoot, getTimeAgo, - log, shortenHash, } from '../utils' @@ -45,8 +36,8 @@ let timesPatchListFetchErroredConsecutively = 0 export interface FilechangeNode { relativeInRepoUrl: string - oldVersionUrl?: string - newVersionUrl?: string + oldVersionUri?: Uri + newVersionUri?: Uri patch: AugmentedPatch getTreeItem: () => ReturnType<(typeof patchesTreeDataProvider)['getTreeItem']> } @@ -147,6 +138,12 @@ export const patchesTreeDataProvider: TreeDataProvider< const oldVersionCommitSha = latestRevision.base const newVersionCommitSha = latestRevision.oid + // TODO(lorenzleutgeb): Instead of talking to radicle-httpd, + // use the Git Extension, and in particular + // + // Repository.diffBetween(ref1: string, ref2: string): Promise + // + // which should give us all we need. const { data: diffResponse, error } = await fetchFromHttpd( `/projects/${rid}/diff/${oldVersionCommitSha}/${newVersionCommitSha}`, ) @@ -154,20 +151,6 @@ export const patchesTreeDataProvider: TreeDataProvider< return ['Patch details could not be resolved due to an error!'] } - // create a placeholder empty file used to diff added or removed files - const emptyFileUrl = `${extTempDir}${sep}empty` - - try { - await fs.mkdir(Path.dirname(emptyFileUrl), { recursive: true }) - await fs.writeFile(emptyFileUrl, '') - } catch (error) { - log( - "Failed saving placeholder empty file to enable diff for Patch's changed files.", - 'error', - (error as Partial)?.message, - ) - } - const filechangeNodes: FilechangeNode[] = diffResponse.diff.files .map((filechange) => { const filePath = @@ -176,26 +159,33 @@ export const patchesTreeDataProvider: TreeDataProvider< : filechange.path const fileDir = Path.dirname(filePath) const filename = Path.basename(filePath) - - const oldVersionUrl = `${extTempDir}${sep}${shortenHash( - oldVersionCommitSha, - )}${sep}${fileDir}${sep}${filename}` - // TODO: should the newVersionUrl be just the filechange.path (with full path to the actual file on the fs) if the current git commit is same as newVersionCommitSha and the file isn't on the git (un-)staged changes? - const newVersionUrl = `${extTempDir}${sep}${shortenHash( - newVersionCommitSha, - )}${sep}${fileDir}${sep}${filename}` + const absPath = `${getRepoRoot()}${sep}${filePath}` + + /* + TODO(lorenzleutgeb): Instead of constructing GitUris ourselves, use API of Git Extension. + const gitExtensionApi: GitExtensionAPI = getGitExtensionAPI() + const mkUri = (ref: string) => gitExtensionApi.toGitUri(Uri.from({ scheme: 'file', path: absPath }), ref); + */ + + const mkUri = (ref: string) => + Uri.from({ + scheme: 'git', + path: absPath, + query: JSON.stringify({ + path: absPath, + ref, + }), + }) + + const oldVersionUri = mkUri(oldVersionCommitSha) + const newVersionUri = mkUri(newVersionCommitSha) const node: FilechangeNode = { relativeInRepoUrl: filePath, - oldVersionUrl, - newVersionUrl, + oldVersionUri, + newVersionUri, patch, - getTreeItem: async () => { - // god forgive me for I have sinned due to httpd's glorious schema... - type FileChangeWithOldAndNew = Extract< - Unarray<(typeof diffResponse)['diff']['files']>, - { old: NonNullable; new: NonNullable } - > + getTreeItem: () => { type FilechangeWithDiff = Extract< Unarray<(typeof diffResponse)['diff']['files']>, { diff: NonNullable } @@ -204,69 +194,6 @@ export const patchesTreeDataProvider: TreeDataProvider< Unarray<(typeof diffResponse)['diff']['files']>, { current: NonNullable } > - type FileContent = (typeof diffResponse)['files'][string]['content'] - - try { - switch (filechange.state) { - case 'added': - await fs.mkdir(Path.dirname(newVersionUrl), { recursive: true }) - await fs.writeFile( - newVersionUrl, - diffResponse.files[filechange.new.oid]?.content as FileContent, - ) - break - case 'deleted': - await fs.mkdir(Path.dirname(oldVersionUrl), { recursive: true }) - await fs.writeFile( - oldVersionUrl, - diffResponse.files[filechange.old.oid]?.content as FileContent, - ) - break - case 'modified': - case 'copied': - case 'moved': - await Promise.all([ - fs.mkdir(Path.dirname(oldVersionUrl), { recursive: true }), - fs.mkdir(Path.dirname(newVersionUrl), { recursive: true }), - ]) - - if ( - filechange.state === 'modified' || - isCopiedOrMovedFilechangeWithDiff(filechange) - ) { - await Promise.all([ - fs.writeFile( - oldVersionUrl, - diffResponse.files[filechange.old.oid]?.content as FileContent, - ), - fs.writeFile( - newVersionUrl, - diffResponse.files[filechange.new.oid]?.content as FileContent, - ), - ]) - } else if (isMovedFilechangeWithoutDiff(filechange)) { - await Promise.all([ - fs.writeFile( - oldVersionUrl, - diffResponse.files[filechange.current.oid]?.content as FileContent, - ), - fs.writeFile( - newVersionUrl, - diffResponse.files[filechange.current.oid]?.content as FileContent, - ), - ]) - } - break - default: - assertUnreachable(filechange) - } - } catch (error) { - log( - `Failed saving temp files to enable diff for ${filePath}.`, - 'error', - (error as Partial)?.message, - ) - } const filechangeTreeItem: TreeItem = { id: `${patch.id} ${oldVersionCommitSha}..${newVersionCommitSha} ${filePath}`, @@ -294,20 +221,8 @@ export const patchesTreeDataProvider: TreeDataProvider< tooltip: `Show this file's changes between its \ before-the-Patch version and its latest version committed in the Radicle Patch`, arguments: [ - Uri.file( - (filechange as Partial).old?.oid || - (filechange as FilechangeWithoutDiffButDiffViewerRegardless) - .current - ? oldVersionUrl - : emptyFileUrl, - ), - Uri.file( - (filechange as Partial).new?.oid || - (filechange as FilechangeWithoutDiffButDiffViewerRegardless) - .current - ? newVersionUrl - : emptyFileUrl, - ), + oldVersionUri, + newVersionUri, `${filename} (${shortenHash(oldVersionCommitSha)} ⟷ ${shortenHash( newVersionCommitSha, )}) ${capitalizeFirstLetter(filechange.state)}`, diff --git a/src/ux/settings.ts b/src/ux/settings.ts index ddf13dfa..eb76ffa0 100644 --- a/src/ux/settings.ts +++ b/src/ux/settings.ts @@ -1,8 +1,5 @@ -import { sep } from 'node:path' -import { ConfigurationTarget, commands, workspace } from 'vscode' -import { extTempDir } from '../constants' -import { getConfig } from '../helpers' -import { log } from '../utils' +import { commands, workspace } from 'vscode' +import type { getConfig } from '../helpers' /** * Opens the Settings UI with the options filtered to show only the specified config @@ -19,48 +16,3 @@ export function openSettingsFocusedAtConfig(config: Parameters config, ) } - -/** - * Checks extension config for user's desired behaviour and ensure's the - * native vscode config is set to match. - */ -export function validateHideTempFilesConfigAlignment() { - const excludeGlob = `${extTempDir}${sep}**` - - const shouldExclude = getConfig('radicle.hideTempFiles') - - const searchExcludeConfigKey = 'search.exclude' - const searchExcludeConfig = workspace.getConfiguration().get(searchExcludeConfigKey) - - if (!searchExcludeConfig) { - log( - `Didn't find any configuration for key "${searchExcludeConfigKey}". Bailing validation of config alignment.`, - 'warn', - ) - - return - } - - const isAlreadyConfigedToExclude = Boolean( - Object.entries(searchExcludeConfig).find( - ([key, value]) => key === excludeGlob && value === true, - ), - ) - - if (shouldExclude && !isAlreadyConfigedToExclude) { - const newSearchExcludeConfig = { ...searchExcludeConfig, [excludeGlob]: true } - workspace - .getConfiguration() - .update(searchExcludeConfigKey, newSearchExcludeConfig, ConfigurationTarget.Global) - } else if (!shouldExclude && isAlreadyConfigedToExclude) { - // @ts-expect-error Type '{}' has no matching index signature for type 'string'. - const { [excludeGlob]: _, ...searchExcludeConfigWithoutExcludeGlob } = searchExcludeConfig - workspace - .getConfiguration() - .update( - searchExcludeConfigKey, - searchExcludeConfigWithoutExcludeGlob, - ConfigurationTarget.Global, - ) - } -}