This commit is contained in:
Jonathan Carter 2020-12-12 05:07:05 +00:00 коммит произвёл GitHub
Родитель 7c5e7ae1e0
Коммит 982868ab15
10 изменённых файлов: 179 добавлений и 31 удалений

Просмотреть файл

@ -1,3 +1,9 @@
## v0.0.41 (12/12/2020)
- The `CodeTour` view now indicates the tours/steps that you've already taken
- The `CodeTour` view now displays an icon next to the active tour step
- The `CodeTour: Hide Markers` and `CodeTour: Show Markers` commands are now hidden from the command palette
## v0.0.40 (12/11/2020)
- Tours with titles that start with `#1 -` or `1 -` are now automatically considered the primary tour, if there isn't already a tour that's explicitly marked as being the primary.

Просмотреть файл

@ -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.40",
"version": "0.0.41",
"repository": {
"type": "git",
"url": "https://github.com/vsls-contrib/codetour"
@ -84,6 +84,15 @@
"command": "codetour.changeTourTitle",
"title": "Change Title"
},
{
"command": "codetour.resetProgress",
"title": "Reset Progress",
"category": "CodeTour"
},
{
"command": "codetour.resetTourProgress",
"title": "Reset Progress"
},
{
"command": "codetour.deleteTourStep",
"title": "Delete Step"
@ -210,10 +219,6 @@
"command": "codetour.endTour",
"when": "codetour:inTour"
},
{
"command": "codetour.hideMarkers",
"when": "codetour:hasTours && codetour:showingMarkers"
},
{
"command": "codetour.previewTour",
"when": "codetour:inTour && codetour:recording"
@ -223,12 +228,12 @@
"when": "workspaceFolderCount != 0"
},
{
"command": "codetour.resumeTour",
"when": "codetour:inTour"
"command": "codetour.resetProgress",
"when": "codetour:hasProgress"
},
{
"command": "codetour.showMarkers",
"when": "codetour:hasTours && !codetour:showingMarkers"
"command": "codetour.resumeTour",
"when": "codetour:inTour"
},
{
"command": "codetour.startTour",
@ -282,6 +287,10 @@
"command": "codetour.exportTour",
"when": "false"
},
{
"command": "codetour.hideMarkers",
"when": "false"
},
{
"command": "codetour.makeTourPrimary",
"when": "false"
@ -298,10 +307,18 @@
"command": "codetour.previousTourStep",
"when": "false"
},
{
"command": "codetour.resetTourProgress",
"when": "false"
},
{
"command": "codetour.saveTourStep",
"when": "false"
},
{
"command": "codetour.showMarkers",
"when": "false"
},
{
"command": "codetour.unmakeTourPrimary",
"when": "false"
@ -428,13 +445,8 @@
"group": "basic@1"
},
{
"command": "codetour.makeTourPrimary",
"when": "viewItem =~ /^codetour.tour(.recording)?(.active)?$/",
"group": "basic@2"
},
{
"command": "codetour.unmakeTourPrimary",
"when": "viewItem =~ /^codetour.tour.primary(.recording)?(.active)?$/",
"command": "codetour.resetTourProgress",
"when": "false",
"group": "basic@2"
},
{
@ -452,20 +464,30 @@
"when": "viewItem =~ /^codetour.tour(.primary)?(.recording)?(.active)?$/ && gitOpenRepositoryCount != 0",
"group": "change@3"
},
{
"command": "codetour.makeTourPrimary",
"when": "viewItem =~ /^codetour.tour(.recording)?(.active)?$/",
"group": "edit@1"
},
{
"command": "codetour.unmakeTourPrimary",
"when": "viewItem =~ /^codetour.tour.primary(.recording)?(.active)?$/",
"group": "edit@2"
},
{
"command": "codetour.editTour",
"when": "viewItem =~ /^codetour.tour(.primary)?(.active)?$/",
"group": "edit@1"
"group": "edit@2"
},
{
"command": "codetour.previewTour",
"when": "viewItem =~ /^codetour.tour(.primary)?.recording/",
"group": "edit@1"
"group": "edit@2"
},
{
"command": "codetour.deleteTour",
"when": "viewItem =~ /^codetour.tour(.primary)?(.recording)?(.active)?$/",
"group": "edit@2"
"group": "edit@3"
},
{
"command": "codetour.exportTour",

Просмотреть файл

@ -11,10 +11,12 @@ import { registerCompletionProvider } from "./recorder/completionProvider";
import { store } from "./store";
import { promptForTour } from "./store/actions";
import { discoverTours } from "./store/provider";
import { initializeStorage } from "./store/storage";
import { registerTreeProvider } from "./tree";
export async function activate(context: vscode.ExtensionContext) {
registerCommands();
initializeStorage(context);
// If the user has a workspace open, then attempt to discover
// the tours contained within it and optionally prompt the user.

Просмотреть файл

@ -12,6 +12,7 @@ import {
selectTour,
startCodeTour
} from "../store/actions";
import { progress } from "../store/storage";
import { CodeTourNode } from "../tree/nodes";
import { readUriContents } from "../utils";
@ -48,6 +49,22 @@ export function registerPlayerCommands() {
}
);
vscode.commands.registerCommand(
`${EXTENSION_NAME}.finishTour`,
async (title?: string) => {
await progress.update();
if (title) {
vscode.commands.executeCommand(
`${EXTENSION_NAME}.startTourByTitle`,
title
);
} else {
vscode.commands.executeCommand(`${EXTENSION_NAME}.endTour`);
}
}
);
// Purpose: Command link
vscode.commands.registerCommand(
`${EXTENSION_NAME}.navigateToStep`,
@ -254,4 +271,8 @@ export function registerPlayerCommands() {
vscode.commands.registerCommand(`${EXTENSION_NAME}.showMarkers`, () =>
setShowMarkers(true)
);
vscode.commands.registerCommand(`${EXTENSION_NAME}.resetProgress`, () =>
progress.reset()
);
}

Просмотреть файл

@ -251,9 +251,9 @@ async function renderCurrentStep() {
const argsContent = encodeURIComponent(
JSON.stringify([nextTour.title])
);
content += `${prefix}[Next Tour (${tourTitle})](command:codetour.startTourByTitle?${argsContent} "Start next tour")`;
content += `${prefix}[Next Tour (${tourTitle})](command:codetour.finishTour?${argsContent} "Start next tour")`;
} else {
content += `${prefix}[Finish Tour](command:codetour.endTour "Finish the tour")`;
content += `${prefix}[Finish Tour](command:codetour.finishTour "Finish the tour")`;
}
}
}

Просмотреть файл

@ -8,6 +8,7 @@ import {
getWorkspaceUri,
readUriContents
} from "../utils";
import { progress } from "./storage";
const CAN_EDIT_TOUR_KEY = `${EXTENSION_NAME}:canEditTour`;
const IN_TOUR_KEY = `${EXTENSION_NAME}:inTour`;
@ -111,7 +112,9 @@ export function moveCurrentCodeTourBackward() {
_onDidStartTour.fire([store.activeTour!.tour, store.activeTour!.step]);
}
export function moveCurrentCodeTourForward() {
export async function moveCurrentCodeTourForward() {
await progress.update();
store.activeTour!.step++;
_onDidStartTour.fire([store.activeTour!.tour, store.activeTour!.step]);

Просмотреть файл

@ -60,12 +60,15 @@ export interface ActiveTour {
tours?: CodeTour[];
}
type CodeTourProgress = [string, number[]];
export interface Store {
tours: CodeTour[];
activeTour: ActiveTour | null;
hasTours: boolean;
isRecording: boolean;
showMarkers: boolean;
progress: CodeTourProgress[];
}
export const store: Store = observable({
@ -75,5 +78,6 @@ export const store: Store = observable({
get hasTours() {
return this.tours.length > 0;
},
showMarkers: false
showMarkers: false,
progress: []
});

67
src/store/storage.ts Normal file
Просмотреть файл

@ -0,0 +1,67 @@
import { observable } from "mobx";
import { commands, ExtensionContext, Uri, workspace } from "vscode";
import { CodeTour, store } from ".";
const CODETOUR_PROGRESS_KEY = "codetour:progress";
export var progress: {
update(): void;
isComplete(tour: CodeTour, stepNumber?: number): boolean;
reset(): void;
};
function getProgress(tour: CodeTour) {
const progress = store.progress.find(([id]) => tour.id === id);
return progress?.[1] || observable([]);
}
export function initializeStorage(context: ExtensionContext) {
store.progress = context.globalState.get(CODETOUR_PROGRESS_KEY) || [];
progress = {
async update() {
const progress = store.progress.find(
([id]) => store.activeTour?.tour.id === id
);
if (progress && !progress![1].includes(store.activeTour!.step)) {
progress![1].push(store.activeTour!.step);
} else {
store.progress.push([
store.activeTour!.tour.id,
[store.activeTour!.step]
]);
}
commands.executeCommand("setContext", "codetour:hasProgress", true);
return context.globalState.update(CODETOUR_PROGRESS_KEY, store.progress);
},
isComplete(tour: CodeTour, stepNumber?: number): boolean {
const tourProgress = getProgress(tour);
if (stepNumber !== undefined) {
return tourProgress.includes(stepNumber);
} else {
return tourProgress.length >= tour.steps.length;
}
},
async reset(tour?: CodeTour) {
commands.executeCommand("setContext", "codetour:hasProgress", false);
store.progress = tour
? store.progress.filter(tourProgress => tourProgress[0] !== tour.id)
: [];
return context.globalState.update(CODETOUR_PROGRESS_KEY, store.progress);
}
};
// @ts-ignore
context.globalState.setKeysForSync([CODETOUR_PROGRESS_KEY]);
const workspaceHasProgress = store.progress.some(([id]) =>
workspace.getWorkspaceFolder(Uri.parse(id))
);
if (workspaceHasProgress) {
commands.executeCommand("setContext", "codetour:hasProgress", true);
}
}

Просмотреть файл

@ -9,7 +9,6 @@ import {
} from "vscode";
import { EXTENSION_NAME } from "../constants";
import { store } from "../store";
import { getTourTitle } from "../utils";
import { CodeTourNode, CodeTourStepNode } from "./nodes";
class CodeTourTreeProvider implements TreeDataProvider<TreeItem>, Disposable {
@ -25,6 +24,10 @@ class CodeTourTreeProvider implements TreeDataProvider<TreeItem>, Disposable {
store.tours,
store.hasTours,
store.isRecording,
store.progress.map(([id, completedSteps]) => [
id,
completedSteps.map(step => step)
]),
store.activeTour
? [
store.activeTour.tour.title,
@ -144,11 +147,6 @@ export function registerTreeProvider(extensionPath: string) {
return;
}
const title = getTourTitle(store.activeTour.tour);
treeView.message = `Current step: #${store.activeTour.step + 1} of ${
store.activeTour.tour.steps.length
} (${title})`;
revealCurrentStepNode();
} else {
// TODO: Once VS Code supports it, we want

Просмотреть файл

@ -1,6 +1,13 @@
import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from "vscode";
import {
ThemeColor,
ThemeIcon,
TreeItem,
TreeItemCollapsibleState,
Uri
} from "vscode";
import { CONTENT_URI, EXTENSION_NAME, FS_SCHEME } from "../constants";
import { CodeTour, store } from "../store";
import { progress } from "../store/storage";
import { getFileUri, getStepLabel, getWorkspaceUri } from "../utils";
function isRecording(tour: CodeTour) {
@ -11,6 +18,12 @@ function isRecording(tour: CodeTour) {
);
}
const completeIcon = new ThemeIcon(
"check",
// @ts-ignore
new ThemeColor("terminal.ansiGreen")
);
export class CodeTourNode extends TreeItem {
constructor(public tour: CodeTour, extensionPath: string) {
super(
@ -45,6 +58,8 @@ export class CodeTourNode extends TreeItem {
? new ThemeIcon("record")
: isActive
? new ThemeIcon("play-circle")
: progress.isComplete(tour)
? completeIcon
: new ThemeIcon("location");
}
}
@ -84,7 +99,17 @@ export class CodeTourStepNode extends TreeItem {
this.resourceUri = resourceUri;
if (step.directory) {
const isActive =
store.activeTour &&
tour.id === store.activeTour?.tour.id &&
store.activeTour.step === stepNumber;
if (isActive) {
this.iconPath = new ThemeIcon("play-circle");
} else if (progress.isComplete(tour, stepNumber)) {
// @ts-ignore
this.iconPath = completeIcon;
} else if (step.directory) {
this.iconPath = ThemeIcon.Folder;
} else {
this.iconPath = ThemeIcon.File;