Skip to content

Commit

Permalink
Fix md rename when file does not exist
Browse files Browse the repository at this point in the history
Fixes #148147

- Don't try renaming non-existent files
- Also fixes a bug where renaming in untitled files would insert `untitled:`
  • Loading branch information
mjbvz authored and aeschli committed May 2, 2022
1 parent 0b96919 commit 80c552a
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,10 @@ export class MdRenameProvider extends Disposable implements vscode.RenameProvide
}

// First rename the file
fileRenames.push({ from: targetUri, to: resolvedNewFilePath });
edit.renameFile(targetUri, resolvedNewFilePath);
if (await this.workspaceContents.fileExists(targetUri)) {
fileRenames.push({ from: targetUri, to: resolvedNewFilePath });
edit.renameFile(targetUri, resolvedNewFilePath);
}

// Then update all refs to it
for (const ref of allRefsInfo.references) {
Expand All @@ -181,9 +183,14 @@ export class MdRenameProvider extends Disposable implements vscode.RenameProvide
const root = resolveDocumentLink('/', ref.link.source.resource);
newPath = '/' + path.relative(root.toString(true), rawNewFilePath.toString(true));
} else {
newPath = path.relative(URI.Utils.dirname(ref.link.source.resource).toString(true), rawNewFilePath.toString(true));
if (newName.startsWith('./') && !newPath.startsWith('../') || newName.startsWith('.\\') && !newPath.startsWith('..\\')) {
newPath = './' + newPath;
const rootDir = URI.Utils.dirname(ref.link.source.resource);
if (rootDir.scheme === rawNewFilePath.scheme && rootDir.scheme !== 'untitled') {
newPath = path.relative(rootDir.toString(true), rawNewFilePath.toString(true));
if (newName.startsWith('./') && !newPath.startsWith('../') || newName.startsWith('.\\') && !newPath.startsWith('..\\')) {
newPath = './' + newPath;
}
} else {
newPath = newName;
}
}
edit.replace(ref.link.source.resource, this.getFilePathRange(ref), encodeURI(newPath.replace(/\\/g, '/')));
Expand Down Expand Up @@ -262,3 +269,4 @@ export class MdRenameProvider extends Disposable implements vscode.RenameProvide
return this.cachedRefs;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export class InMemoryWorkspaceMarkdownDocuments implements MdWorkspaceContents {
return this._documents.get(this.getKey(resource));
}

public async fileExists(resource: vscode.Uri): Promise<boolean> {
return this._documents.has(this.getKey(resource));
}

private readonly _onDidChangeMarkdownDocumentEmitter = new vscode.EventEmitter<SkinnyTextDocument>();
public onDidChangeMarkdownDocument = this._onDidChangeMarkdownDocumentEmitter.event;

Expand Down
45 changes: 24 additions & 21 deletions extensions/markdown-language-features/src/test/rename.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,19 +458,19 @@ suite('markdown: rename', () => {
doc1,
doc2
]));
assertEditsEqual(edit!, {
originalUri: workspacePath('images', 'more', 'image.png'),
newUri: workspacePath('img', 'test', 'new.png'),
}, {
uri: uri1, edits: [
new vscode.TextEdit(new vscode.Range(0, 7, 0, 29), '/img/test/new.png'),
new vscode.TextEdit(new vscode.Range(2, 7, 2, 29), '/img/test/new.png'),
]
}, {
uri: uri2, edits: [
new vscode.TextEdit(new vscode.Range(0, 7, 0, 29), '/img/test/new.png'),
]
});
assertEditsEqual(edit!,
// Should not have file edits since the files don't exist here
{
uri: uri1, edits: [
new vscode.TextEdit(new vscode.Range(0, 7, 0, 29), '/img/test/new.png'),
new vscode.TextEdit(new vscode.Range(2, 7, 2, 29), '/img/test/new.png'),
]
},
{
uri: uri2, edits: [
new vscode.TextEdit(new vscode.Range(0, 7, 0, 29), '/img/test/new.png'),
]
});
});

test('Path rename should use .md extension on extension-less link', async () => {
Expand Down Expand Up @@ -550,24 +550,27 @@ suite('markdown: rename', () => {
test('Path rename should resolve on links without prefix', async () => {
const uri1 = workspacePath('sub', 'doc.md');
const doc1 = new InMemoryDocument(uri1, joinLines(
`![text](images/cat.gif)`,
`![text](sub2/doc3.md)`,
));

const uri2 = workspacePath('doc2.md');
const doc2 = new InMemoryDocument(uri2, joinLines(
`![text](sub/images/cat.gif)`,
`![text](sub/sub2/doc3.md)`,
));

const edit = await getRenameEdits(doc1, new vscode.Position(0, 10), 'img/cat.gif', new InMemoryWorkspaceMarkdownDocuments([
doc1, doc2,
const uri3 = workspacePath('sub', 'sub2', 'doc3.md');
const doc3 = new InMemoryDocument(uri3, joinLines());

const edit = await getRenameEdits(doc1, new vscode.Position(0, 10), 'sub2/cat.md', new InMemoryWorkspaceMarkdownDocuments([
doc1, doc2, doc3
]));
assertEditsEqual(edit!, {
originalUri: workspacePath('sub', 'images', 'cat.gif'),
newUri: workspacePath('sub', 'img', 'cat.gif'),
originalUri: workspacePath('sub', 'sub2', 'doc3.md'),
newUri: workspacePath('sub', 'sub2', 'cat.md'),
}, {
uri: uri1, edits: [new vscode.TextEdit(new vscode.Range(0, 8, 0, 22), 'img/cat.gif')]
uri: uri1, edits: [new vscode.TextEdit(new vscode.Range(0, 8, 0, 20), 'sub2/cat.md')]
}, {
uri: uri2, edits: [new vscode.TextEdit(new vscode.Range(0, 8, 0, 26), 'sub/img/cat.gif')]
uri: uri2, edits: [new vscode.TextEdit(new vscode.Range(0, 8, 0, 24), 'sub/sub2/cat.md')]
});
});

Expand Down
12 changes: 12 additions & 0 deletions extensions/markdown-language-features/src/workspaceContents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ export interface MdWorkspaceContents {

getMarkdownDocument(resource: vscode.Uri): Promise<SkinnyTextDocument | undefined>;

fileExists(resource: vscode.Uri): Promise<boolean>;

readonly onDidChangeMarkdownDocument: vscode.Event<SkinnyTextDocument>;
readonly onDidCreateMarkdownDocument: vscode.Event<SkinnyTextDocument>;
readonly onDidDeleteMarkdownDocument: vscode.Event<vscode.Uri>;
Expand Down Expand Up @@ -143,4 +145,14 @@ export class VsCodeMdWorkspaceContents extends Disposable implements MdWorkspace
return undefined;
}
}

public async fileExists(target: vscode.Uri): Promise<boolean> {
let targetResourceStat: vscode.FileStat | undefined;
try {
targetResourceStat = await vscode.workspace.fs.stat(target);
} catch {
return false;
}
return targetResourceStat.type === vscode.FileType.File;
}
}

0 comments on commit 80c552a

Please sign in to comment.