Updating tour tree
This commit is contained in:
Родитель
c65cf94aad
Коммит
19e0723466
|
@ -1,12 +1,11 @@
|
|||
## v0.0.16 (03/30/2020)
|
||||
|
||||
- Fixed some bugs with the `CodeTour` tree
|
||||
- Updated the `CodeTour` tree to display the currently active tour, regardless how it was started (e.g. you open a tour file).
|
||||
|
||||
## v0.0.15 (03/29/2020)
|
||||
|
||||
- Updated the `CodeTour` tree to only display if the currently open workspace has any tours, or if the user is currently taking a tour. That way, it isn't obtrusive to users that aren't currently using it.
|
||||
- Updated the `CodeTour: Refresh Tours` command to only show up when the currently opened workspace has any tours.
|
||||
- Updated the `CodeTour` tree to display the currently active tour, regardless how it was started.
|
||||
|
||||
## v0.0.14 (03/26/2020)
|
||||
|
||||
|
|
26
package.json
26
package.json
|
@ -51,19 +51,13 @@
|
|||
"command": "codetour.changeTourTitle",
|
||||
"title": "Change Title"
|
||||
},
|
||||
{
|
||||
"command": "codetour.deleteTour",
|
||||
"title": "Delete Tour"
|
||||
},
|
||||
{
|
||||
"command": "codetour.deleteTourStep",
|
||||
"title": "Delete Step"
|
||||
},
|
||||
{
|
||||
"command": "codetour.editTour",
|
||||
"title": "Edit Tour",
|
||||
"category": "CodeTour",
|
||||
"icon": "$(edit)"
|
||||
"command": "codetour.deleteTour",
|
||||
"title": "Delete Tour"
|
||||
},
|
||||
{
|
||||
"command": "codetour.editTourAtStep",
|
||||
|
@ -73,6 +67,12 @@
|
|||
"command": "codetour.editTourStep",
|
||||
"title": "Edit Step"
|
||||
},
|
||||
{
|
||||
"command": "codetour.editTour",
|
||||
"title": "Edit Tour",
|
||||
"category": "CodeTour",
|
||||
"icon": "$(edit)"
|
||||
},
|
||||
{
|
||||
"command": "codetour.endTour",
|
||||
"title": "End Tour",
|
||||
|
@ -83,16 +83,16 @@
|
|||
"command": "codetour.exportTour",
|
||||
"title": "Export Tour..."
|
||||
},
|
||||
{
|
||||
"command": "codetour.moveTourStepBack",
|
||||
"title": "Move Up",
|
||||
"icon": "$(arrow-up)"
|
||||
},
|
||||
{
|
||||
"command": "codetour.moveTourStepForward",
|
||||
"title": "Move Down",
|
||||
"icon": "$(arrow-down)"
|
||||
},
|
||||
{
|
||||
"command": "codetour.moveTourStepBack",
|
||||
"title": "Move Up",
|
||||
"icon": "$(arrow-up)"
|
||||
},
|
||||
{
|
||||
"command": "codetour.nextTourStep",
|
||||
"title": "Next",
|
||||
|
|
|
@ -5,9 +5,7 @@ import {
|
|||
endCurrentCodeTour,
|
||||
moveCurrentCodeTourBackward,
|
||||
moveCurrentCodeTourForward,
|
||||
startCodeTour,
|
||||
resumeCurrentCodeTour,
|
||||
CodeTourComment
|
||||
startCodeTour
|
||||
} from "./store/actions";
|
||||
import { discoverTours } from "./store/provider";
|
||||
import { CodeTourNode, CodeTourStepNode } from "./tree/nodes";
|
||||
|
@ -16,6 +14,7 @@ import { api, RefType } from "./git";
|
|||
import * as path from "path";
|
||||
import { getStepFileUri } from "./utils";
|
||||
import { workspace } from "vscode";
|
||||
import { focusPlayer, CodeTourComment } from "./player";
|
||||
interface CodeTourQuickPickItem extends vscode.QuickPickItem {
|
||||
tour: CodeTour;
|
||||
}
|
||||
|
@ -33,7 +32,7 @@ export function registerCommands() {
|
|||
return startCodeTour(targetTour, stepNumber, workspaceRoot);
|
||||
}
|
||||
|
||||
let items: CodeTourQuickPickItem[] = store.tours.map(tour => ({
|
||||
const items: CodeTourQuickPickItem[] = store.tours.map(tour => ({
|
||||
label: tour.title!,
|
||||
tour: tour,
|
||||
detail: tour.description
|
||||
|
@ -78,10 +77,7 @@ export function registerCommands() {
|
|||
}
|
||||
);
|
||||
|
||||
vscode.commands.registerCommand(
|
||||
`${EXTENSION_NAME}.resumeTour`,
|
||||
resumeCurrentCodeTour
|
||||
);
|
||||
vscode.commands.registerCommand(`${EXTENSION_NAME}.resumeTour`, focusPlayer);
|
||||
|
||||
function getTourFileUri(title: string) {
|
||||
const file = title
|
||||
|
@ -225,6 +221,7 @@ export function registerCommands() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
vscode.commands.registerCommand(
|
||||
`${EXTENSION_NAME}.addTourStep`,
|
||||
(reply: vscode.CommentReply) => {
|
||||
|
@ -460,10 +457,7 @@ export function registerCommands() {
|
|||
"Delete Tour"
|
||||
)
|
||||
) {
|
||||
if (
|
||||
store.activeTour &&
|
||||
node.tour.title === store.activeTour.tour.title
|
||||
) {
|
||||
if (store.activeTour && node.tour.id === store.activeTour.tour.id) {
|
||||
await endCurrentCodeTour();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,46 +1,35 @@
|
|||
import * as vscode from "vscode";
|
||||
import { registerCommands } from "./commands";
|
||||
import { EXTENSION_NAME } from "./constants";
|
||||
import { registerFileSystemProvider } from "./fileSystem";
|
||||
import { initializeGitApi } from "./git";
|
||||
import { registerStatusBar } from "./status";
|
||||
import { store } from "./store";
|
||||
import {
|
||||
endCurrentCodeTour,
|
||||
promptForTour,
|
||||
startCodeTour
|
||||
} from "./store/actions";
|
||||
import { discoverTours } from "./store/provider";
|
||||
import { registerTreeProvider } from "./tree";
|
||||
import { initializeGitApi } from "./git";
|
||||
import { startCodeTour, endCurrentCodeTour } from "./store/actions";
|
||||
import { registerFileSystemProvider } from "./fileSystem";
|
||||
|
||||
async function promptForTour(
|
||||
workspaceRoot: string,
|
||||
globalState: vscode.Memento
|
||||
) {
|
||||
const key = `${EXTENSION_NAME}:${workspaceRoot}`;
|
||||
if (store.hasTours && !globalState.get(key)) {
|
||||
globalState.update(key, true);
|
||||
|
||||
if (
|
||||
await vscode.window.showInformationMessage(
|
||||
"This workspace has guided tours you can take to get familiar with the codebase.",
|
||||
"Start CodeTour"
|
||||
)
|
||||
) {
|
||||
vscode.commands.executeCommand(`${EXTENSION_NAME}.startTour`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function activate(context: vscode.ExtensionContext) {
|
||||
registerCommands();
|
||||
|
||||
// If the user has a workspace open, then attempt to discover
|
||||
// the tours contained within it and optionally prompt the user.
|
||||
if (vscode.workspace.workspaceFolders) {
|
||||
const workspaceRoot = vscode.workspace.workspaceFolders[0].uri.toString();
|
||||
await discoverTours(workspaceRoot);
|
||||
|
||||
registerTreeProvider(context.extensionPath);
|
||||
promptForTour(workspaceRoot, context.globalState);
|
||||
|
||||
initializeGitApi();
|
||||
}
|
||||
|
||||
// Regardless if the user has a workspace open,
|
||||
// we still need to register the following items
|
||||
// in order to support opening tour files and/or
|
||||
// enabling other extensions to start a tour.
|
||||
registerTreeProvider(context.extensionPath);
|
||||
registerFileSystemProvider();
|
||||
registerStatusBar();
|
||||
|
||||
|
|
|
@ -11,19 +11,15 @@ import {
|
|||
Uri,
|
||||
workspace
|
||||
} from "vscode";
|
||||
import { store, CodeTour, CodeTourStep } from "../store";
|
||||
import { FS_SCHEME } from "../constants";
|
||||
import { CodeTour, CodeTourStep, store } from "../store";
|
||||
|
||||
export class CodeTourFileSystemProvider implements FileSystemProvider {
|
||||
private count = 0;
|
||||
|
||||
private _onDidChangeFile = new EventEmitter<FileChangeEvent[]>();
|
||||
public readonly onDidChangeFile: Event<FileChangeEvent[]> = this
|
||||
._onDidChangeFile.event;
|
||||
|
||||
getCurrentTourStep(): [CodeTour, CodeTourStep] {
|
||||
const tour = store.activeTour?.tour!;
|
||||
return [tour, tour?.steps[store.activeTour!.step]!];
|
||||
const tour = store.activeTour!.tour;
|
||||
return [tour, tour.steps[store.activeTour!.step]];
|
||||
}
|
||||
|
||||
updateTour(tour: CodeTour) {
|
||||
|
@ -72,13 +68,19 @@ export class CodeTourFileSystemProvider implements FileSystemProvider {
|
|||
this.updateTour(tour);
|
||||
}
|
||||
|
||||
// Unimplemented members
|
||||
|
||||
private _onDidChangeFile = new EventEmitter<FileChangeEvent[]>();
|
||||
public readonly onDidChangeFile: Event<FileChangeEvent[]> = this
|
||||
._onDidChangeFile.event;
|
||||
|
||||
async copy?(
|
||||
source: Uri,
|
||||
destination: Uri,
|
||||
options: { overwrite: boolean }
|
||||
): Promise<void> {
|
||||
throw FileSystemError.NoPermissions(
|
||||
"CodeTour doesn't support copying files"
|
||||
"CodeTour doesn't support copying files."
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -90,9 +92,10 @@ export class CodeTourFileSystemProvider implements FileSystemProvider {
|
|||
|
||||
async delete(uri: Uri, options: { recursive: boolean }): Promise<void> {
|
||||
throw FileSystemError.NoPermissions(
|
||||
"CodeTour doesn't support deleting files"
|
||||
"CodeTour doesn't support deleting files."
|
||||
);
|
||||
}
|
||||
|
||||
async readDirectory(uri: Uri): Promise<[string, FileType][]> {
|
||||
throw FileSystemError.NoPermissions("CodeTour doesnt support directories.");
|
||||
}
|
||||
|
|
|
@ -1,137 +1,11 @@
|
|||
import {
|
||||
commands,
|
||||
Comment,
|
||||
CommentAuthorInformation,
|
||||
CommentMode,
|
||||
comments,
|
||||
CommentThread,
|
||||
CommentThreadCollapsibleState,
|
||||
MarkdownString,
|
||||
Range,
|
||||
TextEditorRevealType,
|
||||
Uri,
|
||||
window,
|
||||
workspace,
|
||||
TextDocument,
|
||||
CommentController,
|
||||
Selection
|
||||
} from "vscode";
|
||||
import { commands, Memento, Uri, window } from "vscode";
|
||||
import { CodeTour, store } from ".";
|
||||
import { EXTENSION_NAME, FS_SCHEME } from "../constants";
|
||||
import { reaction } from "mobx";
|
||||
import { getStepFileUri } from "../utils";
|
||||
import { startPlayer, stopPlayer } from "../player";
|
||||
|
||||
const CAN_EDIT_TOUR_KEY = `${EXTENSION_NAME}:canEditTour`;
|
||||
const IN_TOUR_KEY = `${EXTENSION_NAME}:inTour`;
|
||||
|
||||
const CONTROLLER_ID = "codetour";
|
||||
const CONTROLLER_LABEL = "CodeTour";
|
||||
const CONTROLLER_ICON = Uri.parse(
|
||||
"https://cdn.jsdelivr.net/gh/vsls-contrib/code-tour/images/icon.png"
|
||||
);
|
||||
|
||||
let id = 0;
|
||||
export class CodeTourComment implements Comment {
|
||||
public id: string = (++id).toString();
|
||||
public contextValue: string = "";
|
||||
public mode: CommentMode = CommentMode.Preview;
|
||||
public author: CommentAuthorInformation = {
|
||||
name: CONTROLLER_LABEL,
|
||||
iconPath: CONTROLLER_ICON
|
||||
};
|
||||
|
||||
constructor(
|
||||
public body: string | MarkdownString,
|
||||
public label: string = "",
|
||||
public parent: CommentThread
|
||||
) {}
|
||||
}
|
||||
|
||||
let controller: CommentController;
|
||||
|
||||
async function showDocument(uri: Uri, range: Range, selection?: Selection) {
|
||||
const document =
|
||||
window.visibleTextEditors.find(
|
||||
editor => editor.document.uri.toString() === uri.toString()
|
||||
) || (await window.showTextDocument(uri, { preserveFocus: true }));
|
||||
|
||||
// TODO: Figure out how to force focus when navigating
|
||||
// to documents which are already open.
|
||||
|
||||
if (selection) {
|
||||
document.selection = selection;
|
||||
}
|
||||
|
||||
document.revealRange(range, TextEditorRevealType.InCenter);
|
||||
}
|
||||
|
||||
async function renderCurrentStep() {
|
||||
if (store.activeTour!.thread) {
|
||||
store.activeTour!.thread.dispose();
|
||||
}
|
||||
|
||||
const currentTour = store.activeTour!.tour;
|
||||
const currentStep = store.activeTour!.step;
|
||||
|
||||
const step = currentTour!.steps[currentStep];
|
||||
|
||||
if (!step) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Adjust the line number, to allow the user to specify
|
||||
// them in 1-based format, not 0-based
|
||||
const line = step.line ? step.line - 1 : 2000;
|
||||
const range = new Range(line, 0, line, 0);
|
||||
let label = `Step #${currentStep + 1} of ${currentTour!.steps.length}`;
|
||||
|
||||
if (currentTour.title) {
|
||||
label += ` (${currentTour.title})`;
|
||||
}
|
||||
|
||||
const workspaceRoot = store.activeTour!.workspaceRoot
|
||||
? store.activeTour!.workspaceRoot.toString()
|
||||
: workspace.workspaceFolders
|
||||
? workspace.workspaceFolders[0].uri.toString()
|
||||
: "";
|
||||
|
||||
const uri = await getStepFileUri(step, workspaceRoot, currentTour.ref);
|
||||
store.activeTour!.thread = controller.createCommentThread(uri, range, []);
|
||||
store.activeTour!.thread.comments = [
|
||||
new CodeTourComment(step.description, label, store.activeTour!.thread!)
|
||||
];
|
||||
|
||||
const contextValues = [];
|
||||
if (currentStep > 0) {
|
||||
contextValues.push("hasPrevious");
|
||||
}
|
||||
|
||||
if (currentStep < currentTour.steps.length - 1) {
|
||||
contextValues.push("hasNext");
|
||||
}
|
||||
|
||||
store.activeTour!.thread.contextValue = contextValues.join(".");
|
||||
store.activeTour!.thread.collapsibleState =
|
||||
CommentThreadCollapsibleState.Expanded;
|
||||
|
||||
let selection;
|
||||
if (step.selection) {
|
||||
// Adjust the 1-based positions
|
||||
// to the 0-based positions that
|
||||
// VS Code's editor uses.
|
||||
selection = new Selection(
|
||||
step.selection.start.line - 1,
|
||||
step.selection.start.character - 1,
|
||||
step.selection.end.line - 1,
|
||||
step.selection.end.character - 1
|
||||
);
|
||||
} else {
|
||||
selection = new Selection(range.start, range.end);
|
||||
}
|
||||
|
||||
showDocument(uri, range, selection);
|
||||
}
|
||||
|
||||
export function startCodeTour(
|
||||
tour: CodeTour,
|
||||
stepNumber?: number,
|
||||
|
@ -139,26 +13,7 @@ export function startCodeTour(
|
|||
startInEditMode: boolean = false,
|
||||
canEditTour: boolean = true
|
||||
) {
|
||||
if (controller) {
|
||||
controller.dispose();
|
||||
}
|
||||
|
||||
controller = comments.createCommentController(
|
||||
CONTROLLER_ID,
|
||||
CONTROLLER_LABEL
|
||||
);
|
||||
|
||||
// TODO: Correctly limit the commenting ranges
|
||||
// to files within the workspace root
|
||||
controller.commentingRangeProvider = {
|
||||
provideCommentingRanges: (document: TextDocument) => {
|
||||
if (store.isRecording) {
|
||||
return [new Range(0, 0, document.lineCount, 0)];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
startPlayer();
|
||||
|
||||
store.activeTour = {
|
||||
tour,
|
||||
|
@ -182,14 +37,7 @@ export async function endCurrentCodeTour() {
|
|||
commands.executeCommand("setContext", "codetour:recording", false);
|
||||
}
|
||||
|
||||
if (store.activeTour?.thread) {
|
||||
store.activeTour!.thread.dispose();
|
||||
store.activeTour!.thread = null;
|
||||
}
|
||||
|
||||
if (controller) {
|
||||
controller.dispose();
|
||||
}
|
||||
stopPlayer();
|
||||
|
||||
store.activeTour = null;
|
||||
commands.executeCommand("setContext", IN_TOUR_KEY, false);
|
||||
|
@ -209,27 +57,21 @@ export function moveCurrentCodeTourForward() {
|
|||
store.activeTour!.step++;
|
||||
}
|
||||
|
||||
export function resumeCurrentCodeTour() {
|
||||
showDocument(store.activeTour!.thread!.uri, store.activeTour!.thread!.range);
|
||||
}
|
||||
export async function promptForTour(
|
||||
workspaceRoot: string,
|
||||
globalState: Memento
|
||||
) {
|
||||
const key = `${EXTENSION_NAME}:${workspaceRoot}`;
|
||||
if (store.hasTours && !globalState.get(key)) {
|
||||
globalState.update(key, true);
|
||||
|
||||
reaction(
|
||||
() => [
|
||||
store.activeTour
|
||||
? [
|
||||
store.activeTour.step,
|
||||
store.activeTour.tour.title,
|
||||
store.activeTour.tour.steps.map(step => [
|
||||
step.title,
|
||||
step.description,
|
||||
step.line
|
||||
])
|
||||
]
|
||||
: null
|
||||
],
|
||||
() => {
|
||||
if (store.activeTour) {
|
||||
renderCurrentStep();
|
||||
if (
|
||||
await window.showInformationMessage(
|
||||
"This workspace has guided tours you can take to get familiar with the codebase.",
|
||||
"Start CodeTour"
|
||||
)
|
||||
) {
|
||||
commands.executeCommand(`${EXTENSION_NAME}.startTour`);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import { comparer, runInAction, set } from "mobx";
|
||||
import * as vscode from "vscode";
|
||||
import { CodeTour } from ".";
|
||||
import { store } from ".";
|
||||
import { VSCODE_DIRECTORY, EXTENSION_NAME } from "../constants";
|
||||
import { CodeTour, store } from ".";
|
||||
import { EXTENSION_NAME, VSCODE_DIRECTORY } from "../constants";
|
||||
import { endCurrentCodeTour } from "./actions";
|
||||
import { set, runInAction } from "mobx";
|
||||
import { comparer } from "mobx";
|
||||
|
||||
const MAIN_TOUR_FILES = [
|
||||
`${EXTENSION_NAME}.json`,
|
||||
|
@ -17,11 +15,11 @@ const SUB_TOUR_DIRECTORY = `${VSCODE_DIRECTORY}/tours`;
|
|||
const HAS_TOURS_KEY = `${EXTENSION_NAME}:hasTours`;
|
||||
|
||||
export async function discoverTours(workspaceRoot: string): Promise<void> {
|
||||
const mainTour = await discoverMainTour(workspaceRoot);
|
||||
const mainTours = await discoverMainTours(workspaceRoot);
|
||||
const tours = await discoverSubTours(workspaceRoot);
|
||||
|
||||
if (mainTour) {
|
||||
tours.push(mainTour);
|
||||
if (mainTours) {
|
||||
tours.push(...mainTours);
|
||||
}
|
||||
|
||||
runInAction(() => {
|
||||
|
@ -39,7 +37,7 @@ export async function discoverTours(workspaceRoot: string): Promise<void> {
|
|||
} else {
|
||||
// The user deleted the tour
|
||||
// file that's associated with
|
||||
// the active tour
|
||||
// the active tour, so end it
|
||||
endCurrentCodeTour();
|
||||
}
|
||||
}
|
||||
|
@ -48,22 +46,22 @@ export async function discoverTours(workspaceRoot: string): Promise<void> {
|
|||
vscode.commands.executeCommand("setContext", HAS_TOURS_KEY, store.hasTours);
|
||||
}
|
||||
|
||||
async function discoverMainTour(
|
||||
workspaceRoot: string
|
||||
): Promise<CodeTour | null> {
|
||||
for (const tourFile of MAIN_TOUR_FILES) {
|
||||
try {
|
||||
const uri = vscode.Uri.parse(`${workspaceRoot}/${tourFile}`);
|
||||
const mainTourContent = (
|
||||
await vscode.workspace.fs.readFile(uri)
|
||||
).toString();
|
||||
const tour = JSON.parse(mainTourContent);
|
||||
tour.id = uri.toString();
|
||||
return tour;
|
||||
} catch {}
|
||||
}
|
||||
async function discoverMainTours(workspaceRoot: string): Promise<CodeTour[]> {
|
||||
const tours = await Promise.all(
|
||||
MAIN_TOUR_FILES.map(async tourFile => {
|
||||
try {
|
||||
const uri = vscode.Uri.parse(`${workspaceRoot}/${tourFile}`);
|
||||
const mainTourContent = (
|
||||
await vscode.workspace.fs.readFile(uri)
|
||||
).toString();
|
||||
const tour = JSON.parse(mainTourContent);
|
||||
tour.id = uri.toString();
|
||||
return tour;
|
||||
} catch {}
|
||||
})
|
||||
);
|
||||
|
||||
return null;
|
||||
return tours.filter(tour => tour);
|
||||
}
|
||||
|
||||
async function discoverSubTours(workspaceRoot: string): Promise<CodeTour[]> {
|
||||
|
@ -89,15 +87,15 @@ async function discoverSubTours(workspaceRoot: string): Promise<CodeTour[]> {
|
|||
}
|
||||
}
|
||||
|
||||
const watcher = vscode.workspace.createFileSystemWatcher(
|
||||
"**/.vscode/tours/*.json"
|
||||
);
|
||||
|
||||
function updateTours() {
|
||||
const workspaceRoot = vscode.workspace.workspaceFolders![0].uri.toString();
|
||||
discoverTours(workspaceRoot);
|
||||
}
|
||||
|
||||
const watcher = vscode.workspace.createFileSystemWatcher(
|
||||
"**/.vscode/tours/*.json"
|
||||
);
|
||||
|
||||
watcher.onDidChange(updateTours);
|
||||
watcher.onDidCreate(updateTours);
|
||||
watcher.onDidDelete(updateTours);
|
||||
|
|
|
@ -7,9 +7,9 @@ import {
|
|||
TreeItem,
|
||||
window
|
||||
} from "vscode";
|
||||
import { EXTENSION_NAME } from "../constants";
|
||||
import { store } from "../store";
|
||||
import { CodeTourNode, CodeTourStepNode, RecordTourNode } from "./nodes";
|
||||
import { EXTENSION_NAME } from "../constants";
|
||||
|
||||
class CodeTourTreeProvider implements TreeDataProvider<TreeItem>, Disposable {
|
||||
private _disposables: Disposable[] = [];
|
||||
|
@ -48,9 +48,9 @@ class CodeTourTreeProvider implements TreeDataProvider<TreeItem>, Disposable {
|
|||
if (!store.hasTours && !store.activeTour) {
|
||||
return [new RecordTourNode()];
|
||||
} else {
|
||||
const tours = store.tours.map(tour => {
|
||||
return new CodeTourNode(tour, this.extensionPath);
|
||||
});
|
||||
const tours = store.tours.map(
|
||||
tour => new CodeTourNode(tour, this.extensionPath)
|
||||
);
|
||||
|
||||
if (
|
||||
store.activeTour &&
|
||||
|
@ -107,10 +107,7 @@ export function registerTreeProvider(extensionPath: string) {
|
|||
() => {
|
||||
if (store.activeTour) {
|
||||
treeView.reveal(
|
||||
new CodeTourStepNode(store.activeTour.tour, store.activeTour!.step),
|
||||
{
|
||||
focus: true
|
||||
}
|
||||
new CodeTourStepNode(store.activeTour.tour, store.activeTour!.step)
|
||||
);
|
||||
} else {
|
||||
// TODO: Once VS Code supports it, we want
|
||||
|
|
Загрузка…
Ссылка в новой задаче