Fixing step deletion
This commit is contained in:
Родитель
54169ee0fb
Коммит
9ab64d7136
|
@ -1,6 +1,7 @@
|
|||
## v0.0.8 (03/14/2020)
|
||||
|
||||
- Added the ability to associate a tour with a specific Git tag and/or commit, in order to enable it to be resilient to code changes
|
||||
- Updated the tour recorder so that tours are automatically saved upon creation, and on each step/change
|
||||
|
||||
## v0.0.7 (03/14/2020)
|
||||
|
||||
|
|
48
package.json
48
package.json
|
@ -3,7 +3,7 @@
|
|||
"displayName": "CodeTour",
|
||||
"description": "VS Code extension that allows you to record and playback guided tours of codebases, directly within the editor",
|
||||
"publisher": "vsls-contrib",
|
||||
"version": "0.0.7",
|
||||
"version": "0.0.8",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vsls-contrib/codetour"
|
||||
|
@ -110,13 +110,6 @@
|
|||
"title": "Resume Tour",
|
||||
"category": "CodeTour"
|
||||
},
|
||||
{
|
||||
"command": "codetour.saveTour",
|
||||
"title": "Save Tour",
|
||||
"category": "CodeTour",
|
||||
"icon": "$(save)",
|
||||
"enablement": "!commentThreadIsEmpty"
|
||||
},
|
||||
{
|
||||
"command": "codetour.saveTourStep",
|
||||
"title": "Save Step"
|
||||
|
@ -138,10 +131,6 @@
|
|||
"command": "codetour.resumeTour",
|
||||
"when": "codetour:inTour"
|
||||
},
|
||||
{
|
||||
"command": "codetour.saveTour",
|
||||
"when": "codetour:recording"
|
||||
},
|
||||
{
|
||||
"command": "codetour.startTour",
|
||||
"when": "codetour:hasTours"
|
||||
|
@ -202,20 +191,15 @@
|
|||
"group": "inline@2",
|
||||
"when": "commentController == codetour && commentThread =~ /hasNext/"
|
||||
},
|
||||
{
|
||||
"command": "codetour.editTour",
|
||||
"group": "inline@3",
|
||||
"when": "commentController == codetour && !codetour:recording"
|
||||
},
|
||||
{
|
||||
"command": "codetour.saveTour",
|
||||
"group": "inline@3",
|
||||
"when": "commentController == codetour && codetour:recording"
|
||||
},
|
||||
{
|
||||
"command": "codetour.endTour",
|
||||
"group": "inline@4",
|
||||
"group": "inline@3",
|
||||
"when": "commentController == codetour"
|
||||
},
|
||||
{
|
||||
"command": "codetour.editTour",
|
||||
"group": "inline@4",
|
||||
"when": "commentController == codetour && !codetour:recording"
|
||||
}
|
||||
],
|
||||
"comments/commentThread/context": [
|
||||
|
@ -262,35 +246,25 @@
|
|||
}
|
||||
],
|
||||
"view/item/context": [
|
||||
{
|
||||
"command": "codetour.saveTour",
|
||||
"when": "viewItem =~ /codetour.tour.recording/",
|
||||
"group": "inline@1"
|
||||
},
|
||||
{
|
||||
"command": "codetour.endTour",
|
||||
"when": "viewItem =~ /codetour.tour(.recording)?.active/",
|
||||
"group": "inline@2"
|
||||
"group": "inline@1"
|
||||
},
|
||||
{
|
||||
"command": "codetour.startTour",
|
||||
"when": "viewItem == codetour.tour",
|
||||
"group": "inline@3"
|
||||
},
|
||||
{
|
||||
"command": "codetour.saveTour",
|
||||
"when": "viewItem =~ /codetour.tour.recording/",
|
||||
"group": "active@1"
|
||||
"group": "inline@2"
|
||||
},
|
||||
{
|
||||
"command": "codetour.resumeTour",
|
||||
"when": "viewItem =~ /codetour.tour(.recording)?.active$/",
|
||||
"group": "active@2"
|
||||
"group": "active@1"
|
||||
},
|
||||
{
|
||||
"command": "codetour.endTour",
|
||||
"when": "viewItem =~ /codetour.tour(.recording)?.active$/",
|
||||
"group": "active@3"
|
||||
"group": "active@2"
|
||||
},
|
||||
{
|
||||
"command": "codetour.startTour",
|
||||
|
|
125
src/commands.ts
125
src/commands.ts
|
@ -77,6 +77,29 @@ export function registerCommands() {
|
|||
resumeCurrentCodeTour
|
||||
);
|
||||
|
||||
async function writeTourFile(title: string, ref?: string): Promise<CodeTour> {
|
||||
const file = title
|
||||
.toLocaleLowerCase()
|
||||
.replace(/\s/g, "-")
|
||||
.replace(/[^\w\d-_]/g, "");
|
||||
|
||||
const workspaceRoot = vscode.workspace.workspaceFolders![0].uri.toString();
|
||||
const uri = vscode.Uri.parse(`${workspaceRoot}/.vscode/tours/${file}.json`);
|
||||
|
||||
const tour = { title, steps: [] };
|
||||
if (ref && ref !== "HEAD") {
|
||||
(tour as any).ref = ref;
|
||||
}
|
||||
|
||||
const tourContent = JSON.stringify(tour, null, 2);
|
||||
await vscode.workspace.fs.writeFile(uri, new Buffer(tourContent));
|
||||
|
||||
(tour as any).id = uri.toString();
|
||||
|
||||
// @ts-ignore
|
||||
return tour as CodeTour;
|
||||
}
|
||||
|
||||
vscode.commands.registerCommand(`${EXTENSION_NAME}.recordTour`, async () => {
|
||||
const title = await vscode.window.showInputBox({
|
||||
prompt: "Specify the title of the tour"
|
||||
|
@ -86,9 +109,10 @@ export function registerCommands() {
|
|||
return;
|
||||
}
|
||||
|
||||
const description = await vscode.window.showInputBox({
|
||||
prompt: "(Optional) Specify the description of the tour"
|
||||
});
|
||||
const ref = await promptForTourRef();
|
||||
const tour = await writeTourFile(title, ref);
|
||||
|
||||
startCodeTour(tour);
|
||||
|
||||
store.isRecording = true;
|
||||
await vscode.commands.executeCommand(
|
||||
|
@ -97,19 +121,15 @@ export function registerCommands() {
|
|||
true
|
||||
);
|
||||
|
||||
startCodeTour({
|
||||
id: "",
|
||||
title,
|
||||
description,
|
||||
steps: []
|
||||
});
|
||||
|
||||
if (
|
||||
await vscode.window.showInformationMessage(
|
||||
"Code tour recording started. Start creating steps by clicking the + button to the left of each line of code.",
|
||||
"Cancel"
|
||||
)
|
||||
) {
|
||||
const uri = vscode.Uri.parse(tour.id);
|
||||
vscode.workspace.fs.delete(uri);
|
||||
|
||||
endCurrentCodeTour();
|
||||
store.isRecording = false;
|
||||
vscode.commands.executeCommand("setContext", "codetour:recording", false);
|
||||
|
@ -139,6 +159,8 @@ export function registerCommands() {
|
|||
|
||||
tour.steps.splice(stepNumber, 0, step);
|
||||
|
||||
saveTour(tour);
|
||||
|
||||
let label = `Step #${stepNumber + 1} of ${tour.steps.length}`;
|
||||
|
||||
const contextValues = [];
|
||||
|
@ -202,6 +224,8 @@ export function registerCommands() {
|
|||
store.activeTour!.step
|
||||
].description = content;
|
||||
|
||||
saveTour(store.activeTour!.tour);
|
||||
|
||||
comment.parent.comments = comment.parent.comments.map(cmt => {
|
||||
if ((cmt as CodeTourComment).id === comment.id) {
|
||||
cmt.mode = vscode.CommentMode.Preview;
|
||||
|
@ -212,13 +236,15 @@ export function registerCommands() {
|
|||
}
|
||||
);
|
||||
|
||||
function saveTourIfNeccessary(tour: CodeTour) {
|
||||
if (tour.id) {
|
||||
const uri = vscode.Uri.parse(tour.id);
|
||||
delete tour.id;
|
||||
const tourContent = JSON.stringify(tour, null, 2);
|
||||
vscode.workspace.fs.writeFile(uri, new Buffer(tourContent));
|
||||
}
|
||||
async function saveTour(tour: CodeTour) {
|
||||
const uri = vscode.Uri.parse(tour.id);
|
||||
const newTour = {
|
||||
...tour
|
||||
};
|
||||
delete newTour.id;
|
||||
const tourContent = JSON.stringify(newTour, null, 2);
|
||||
|
||||
return vscode.workspace.fs.writeFile(uri, new Buffer(tourContent));
|
||||
}
|
||||
|
||||
async function updateTourProperty(tour: CodeTour, property: string) {
|
||||
|
@ -235,7 +261,7 @@ export function registerCommands() {
|
|||
// @ts-ignore
|
||||
tour[property] = propertyValue;
|
||||
|
||||
saveTourIfNeccessary(tour);
|
||||
saveTour(tour);
|
||||
}
|
||||
|
||||
function moveStep(
|
||||
|
@ -260,13 +286,13 @@ export function registerCommands() {
|
|||
// the tour play along with it as well.
|
||||
if (
|
||||
store.activeTour &&
|
||||
tour.id === store.activeTour.id &&
|
||||
tour.id === store.activeTour.tour.id &&
|
||||
stepNumber === store.activeTour.step
|
||||
) {
|
||||
store.activeTour.step += movement;
|
||||
}
|
||||
|
||||
saveTourIfNeccessary(tour);
|
||||
saveTour(tour);
|
||||
}
|
||||
|
||||
vscode.commands.registerCommand(
|
||||
|
@ -292,8 +318,7 @@ export function registerCommands() {
|
|||
vscode.commands.registerCommand(
|
||||
`${EXTENSION_NAME}.changeTourRef`,
|
||||
async (node: CodeTourNode) => {
|
||||
const uri = vscode.Uri.parse(node.tour.id!);
|
||||
const ref = await promptForTourRef(uri);
|
||||
const ref = await promptForTourRef();
|
||||
if (ref) {
|
||||
if (ref === "HEAD") {
|
||||
delete node.tour.ref;
|
||||
|
@ -302,7 +327,7 @@ export function registerCommands() {
|
|||
}
|
||||
}
|
||||
|
||||
saveTourIfNeccessary(node.tour);
|
||||
saveTour(node.tour);
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -353,19 +378,16 @@ export function registerCommands() {
|
|||
|
||||
tour.steps.splice(step, 1);
|
||||
|
||||
if (
|
||||
store.activeTour &&
|
||||
tour.title === store.activeTour.tour.title &&
|
||||
step === store.activeTour.step
|
||||
) {
|
||||
if (tour.steps.length === 0) {
|
||||
store.activeTour!.step = -1;
|
||||
} else if (step > 0) {
|
||||
if (store.activeTour && store.activeTour.tour.id === tour.id) {
|
||||
if (
|
||||
step <= store.activeTour!.step &&
|
||||
(store.activeTour!.step > 0 || tour.steps.length === 0)
|
||||
) {
|
||||
store.activeTour!.step--;
|
||||
}
|
||||
}
|
||||
|
||||
saveTourIfNeccessary(tour);
|
||||
saveTour(tour);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -374,9 +396,8 @@ export function registerCommands() {
|
|||
ref?: string;
|
||||
}
|
||||
|
||||
async function promptForTourRef(
|
||||
uri: vscode.Uri
|
||||
): Promise<string | undefined> {
|
||||
async function promptForTourRef(): Promise<string | undefined> {
|
||||
const uri = vscode.workspace.workspaceFolders![0].uri;
|
||||
const repository = api.getRepository(uri);
|
||||
if (!repository) {
|
||||
return;
|
||||
|
@ -430,38 +451,4 @@ export function registerCommands() {
|
|||
return response.ref;
|
||||
}
|
||||
}
|
||||
|
||||
vscode.commands.registerCommand(`${EXTENSION_NAME}.saveTour`, async () => {
|
||||
const file = store
|
||||
.activeTour!.tour.title.toLocaleLowerCase()
|
||||
.replace(/\s/g, "-")
|
||||
.replace(/[^\w\d-_]/g, "");
|
||||
|
||||
const tour = store.activeTour!.tour;
|
||||
delete tour.id;
|
||||
|
||||
const workspaceRoot = vscode.workspace.workspaceFolders![0].uri.toString();
|
||||
const uri = vscode.Uri.parse(`${workspaceRoot}/.vscode/tours/${file}.json`);
|
||||
|
||||
const ref = await promptForTourRef(uri);
|
||||
if (ref && ref !== "HEAD") {
|
||||
tour.ref = ref;
|
||||
}
|
||||
|
||||
const tourContent = JSON.stringify(tour, null, 2);
|
||||
|
||||
vscode.workspace.fs.writeFile(uri, new Buffer(tourContent));
|
||||
|
||||
vscode.commands.executeCommand("setContext", "codetour:recording", false);
|
||||
store.isRecording = false;
|
||||
|
||||
vscode.window.showInformationMessage(
|
||||
`The "${
|
||||
store.activeTour!.tour.title
|
||||
}" code tour was saved to to ".vscode/tours/${file}.json"`
|
||||
);
|
||||
store.activeTour!.thread!.dispose();
|
||||
store.activeTour = null;
|
||||
endCurrentCodeTour();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -142,7 +142,6 @@ export function startCodeTour(tour: CodeTour, stepNumber?: number) {
|
|||
};
|
||||
|
||||
store.activeTour = {
|
||||
id: tour.id,
|
||||
tour,
|
||||
step: stepNumber ? stepNumber : tour.steps.length ? 0 : -1,
|
||||
thread: null
|
||||
|
@ -151,24 +150,10 @@ export function startCodeTour(tour: CodeTour, stepNumber?: number) {
|
|||
commands.executeCommand("setContext", IN_TOUR_KEY, true);
|
||||
}
|
||||
|
||||
const KEEP_RECORDING_RESPONSE = "Continue Recording";
|
||||
export async function endCurrentCodeTour() {
|
||||
if (
|
||||
store.isRecording &&
|
||||
store.activeTour &&
|
||||
store.activeTour.tour.steps.length > 0
|
||||
) {
|
||||
const response = await window.showInformationMessage(
|
||||
"Are you sure you want to exit the current recording?",
|
||||
"Exit",
|
||||
KEEP_RECORDING_RESPONSE
|
||||
);
|
||||
if (response === KEEP_RECORDING_RESPONSE) {
|
||||
return;
|
||||
} else {
|
||||
store.isRecording = false;
|
||||
commands.executeCommand("setContext", "codetour:recording", false);
|
||||
}
|
||||
if (store.isRecording) {
|
||||
store.isRecording = false;
|
||||
commands.executeCommand("setContext", "codetour:recording", false);
|
||||
}
|
||||
|
||||
if (store.activeTour?.thread) {
|
||||
|
|
|
@ -20,10 +20,6 @@ export interface CodeTour {
|
|||
}
|
||||
|
||||
export interface ActiveTour {
|
||||
// When a tour is being recorded, and hasn't
|
||||
// been saved yet, it won't have an ID
|
||||
id?: string;
|
||||
|
||||
tour: CodeTour;
|
||||
step: number;
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import { store } from ".";
|
|||
import { VSCODE_DIRECTORY, EXTENSION_NAME } from "../constants";
|
||||
import { endCurrentCodeTour } from "./actions";
|
||||
import { set } from "mobx";
|
||||
import { comparer } from "mobx";
|
||||
|
||||
const MAIN_TOUR_FILES = [
|
||||
`${EXTENSION_NAME}.json`,
|
||||
|
@ -26,12 +27,14 @@ export async function discoverTours(workspaceRoot: string): Promise<void> {
|
|||
store.tours = tours.sort((a, b) => a.title.localeCompare(b.title));
|
||||
|
||||
if (store.activeTour) {
|
||||
const tour = tours.find(tour => tour.id === store.activeTour!.id);
|
||||
const tour = tours.find(tour => tour.id === store.activeTour!.tour.id);
|
||||
|
||||
if (tour) {
|
||||
// Since the active tour could be already observed,
|
||||
// we want to update it in place with the new properties.
|
||||
set(store.activeTour.tour, tour);
|
||||
if (!comparer.structural(store.activeTour.tour, tour)) {
|
||||
// Since the active tour could be already observed,
|
||||
// we want to update it in place with the new properties.
|
||||
set(store.activeTour.tour, tour);
|
||||
}
|
||||
} else {
|
||||
// The user deleted the tour
|
||||
// file that's associated with
|
||||
|
|
|
@ -48,7 +48,7 @@ class CodeTourTreeProvider implements TreeDataProvider<TreeItem>, Disposable {
|
|||
const isRecording =
|
||||
store.isRecording &&
|
||||
store.activeTour &&
|
||||
store.activeTour.id === tour.id;
|
||||
store.activeTour.tour.id === tour.id;
|
||||
return new CodeTourNode(tour, this.extensionPath, isRecording!);
|
||||
});
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ export class CodeTourNode extends TreeItem {
|
|||
contextValues.push("recording");
|
||||
}
|
||||
|
||||
const isActive = store.activeTour && tour.id === store.activeTour?.id;
|
||||
const isActive = store.activeTour && tour.id === store.activeTour?.tour.id;
|
||||
if (isActive) {
|
||||
contextValues.push("active");
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче