This commit is contained in:
vector-of-bool 2017-09-24 22:03:32 -06:00
Родитель 4a34b4a683
Коммит 2a11ad5166
20 изменённых файлов: 1273 добавлений и 298 удалений

2
.vscode/launch.json поставляемый
Просмотреть файл

@ -16,7 +16,7 @@
"${workspaceRoot}/out/test/*"
],
"preLaunchTask": "npm",
"smartStep": true
"smartStep": false
},
{
"name": "Launch Tests",

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

@ -55,6 +55,8 @@ if(SPHINX_EXECUTABLE)
-j 10
"${CMAKE_CURRENT_SOURCE_DIR}/docs"
"${CMAKE_CURRENT_BINARY_DIR}/docs"
COMMAND "${YARN_EXECUTABLE}" --silent docs
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "Generating documentation"
)
endif()

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

@ -18,6 +18,11 @@ Contents:
kits
Developer Reference
===================
`Documentation for the code itself is kept within the code, and is extracted via
TypeDoc. See the developer reference documentation here <dev/index.html>`_.
Indices and tables
==================

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

@ -636,30 +636,32 @@
"vscode:prepublish": "./node_modules/.bin/tsc -p ./",
"compile": "./node_modules/.bin/tsc -watch -p ./",
"compile-once": "./node_modules/.bin/tsc -p ./",
"postinstall": "node ./node_modules/vscode/bin/install"
"postinstall": "node ./node_modules/vscode/bin/install",
"docs": "node ./node_modules/.bin/typedoc --mode modules --excludeExternals --out build/docs/dev --readme none --tsconfig tsconfig-docs.json src/"
},
"devDependencies": {
"typescript": "~2.3.0",
"@types/node": "~8.0.0",
"vscode": "~1.1.0",
"mocha": "~3.4.2",
"@types/mocha": "~2.2.41",
"@types/js-yaml": "^3.5.28",
"@types/ajv": "^0.0.3",
"@types/xml2js": "^0.0.28",
"@types/es6-promisify": "~5.0.0",
"@types/js-yaml": "^3.5.28",
"@types/mocha": "~2.2.41",
"@types/node": "~8.0.0",
"@types/rimraf": "^0.0.28",
"@types/ws": "^0.0.38",
"@types/es6-promisify": "~5.0.0"
"@types/xml2js": "^0.0.28",
"mocha": "~3.4.2",
"typedoc": "^0.8.0",
"typescript": "~2.3.0",
"vscode": "~1.1.0"
},
"dependencies": {
"open": "0.0.5",
"js-yaml": "^3.6.1",
"ajv": "^4.7.5",
"xml2js": "^0.4.17",
"rimraf": "^2.5.4",
"ws": "^1.1.1",
"Polymer": "1.6.1--",
"ajv": "^4.7.5",
"es6-promisify": "~5.0.0",
"js-yaml": "^3.6.1",
"open": "0.0.5",
"rimraf": "^2.5.4",
"rollbar": "~2.2.8",
"es6-promisify": "~5.0.0"
"ws": "^1.1.1",
"xml2js": "^0.4.17"
}
}

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

@ -1,34 +1,90 @@
/**
* This module defines the external API for the extension. Other
* extensions can access this API via the exports instance for the extension.
*
* Look at the `CMakeToolsAPI` interface for the actual exported API.
*
* Copy the `api.ts` source file into your project to use it.
*/ /** */
import {DiagnosticCollection, Disposable, Event, TextEditor} from 'vscode';
/**
* The result of executing a program.
*/
export interface ExecutionResult {
/**
* The return code of the program.
*/
retc: number;
stdout: string|null;
stderr: string|null;
/**
* The full standard output of the program. May be `null` if standard out
* was not captured.
*/
stdout: string | null;
/**
* Standard error output of the program. May be `null` if standard error was
* not captured
*/
stderr: string | null;
}
export interface ExecuteOptions {
/**
* Options for executing a command.
*/
export interface ExecutionOptions {
/**
* Whether output from the command should be suppressed from CMake Tools'
* output channel.
*/
silent: boolean;
environment: {[key: string]: string};
/**
* Additional environment variables to define when executing the command.
*/
environment: {[key: string] : string};
/**
* Whether we should collect output from the command.
*
* @note All output from the command is collected into a single string, so
* commands which emit a lot of output may consume a lot of memory if
* `collectOutput` is set to `true`.
*/
collectOutput?: boolean;
/**
* The working directory for the command. The default directory is
* unspecified.
*/
workingDirectory?: string;
}
/**
* Raw, unprocessed compilation information on a source file. This is what
* would be found in a compilation database, `compile_commands.json`.
*/
export interface RawCompilationInfo {
file: string;
directory: string;
command: string;
}
/**
* Nicer, cleaner compilation information on a source file. This would be
* provided by CMake Server.
*/
export interface CompilationInfo {
file: string;
compile?: RawCompilationInfo;
includeDirectories: {path: string; isSystem: boolean;}[];
compileDefinitions: {[define: string]: string | null};
includeDirectories: {path : string; isSystem : boolean;}[];
compileDefinitions: {[define: string] : string | null};
compileFlags: string[];
compiler?: string;
}
export enum EntryType {
/**
* The type of a CMake cache entry
*/
export enum CacheEntryType {
Bool = 0,
String = 1,
Path = 2,
@ -38,33 +94,66 @@ export enum EntryType {
Static = 6,
}
/**
* Information about a CTest test
*/
export interface Test {
id: number;
name: string;
}
/**
* The properties of a CMake cache entry.
*/
export interface CacheEntryProperties {
type: EntryType;
type: CacheEntryType;
helpString: string;
/** The name of the cache entry */
key: string;
/** The entry's value. Type depends on `type`. */
value: any;
/** Whether this entry is ADVANCED, meaning it hidden from the user. */
advanced: boolean;
}
export interface CacheEntry extends CacheEntryProperties { as<T>(): T; }
/**
* A cache entry from a CMake cache.
*/
export interface CacheEntry extends CacheEntryProperties {
/**
* Return the value as a `T` instance. Does no actual conversion. It's up to
* you to check the value of `CacheEntryProperties.type`.
*/
as<T>(): T;
}
/**
* Description of an executable CMake target, defined via `add_executable()`.
*/
export interface ExecutableTarget {
/**
* The name of the target.
*/
name: string;
/**
* The absolute path to the build output.
*/
path: string;
}
export interface VariantKeywordSettings { [key: string]: string; }
/**
* A target with a name, but no output. This may be created via `add_custom_command()`.
*/
export interface NamedTarget {
type: 'named';
name: string;
}
/**
* A target with a name, path, and type.
*/
export interface RichTarget {
type: 'rich';
name: string;
@ -74,72 +163,214 @@ export interface RichTarget {
export type Target = NamedTarget | RichTarget;
/**
* The CMake Tools extension API obtained via `getExtension().exports`
*/
export interface CMakeToolsAPI extends Disposable {
// Get the root source directory
constructor(): never;
/**
* The source directory, containing the root of the project
*/
readonly sourceDir: Promise<string>;
// Get the main CMake File
/**
* The `CMakeLists.txt` at to the root of the project
*/
readonly mainListFile: Promise<string>;
// Get the binary directory for the project
/**
* The root build directory for the project. May change based on build
* configuration.
*/
readonly binaryDir: Promise<string>;
// Get the path to the CMake cache
/**
* The path to the `CMakeCache.txt for the project.
*/
readonly cachePath: Promise<string>;
// Targets which are executable
/**
* List of CMake targets created via `add_executable()`.
*/
readonly executableTargets: Promise<ExecutableTarget[]>;
// Diagnostics obtained from configure/build
/**
* CMake code diagnostics. Includes warnings and errors, etc.
*/
readonly diagnostics: Promise<DiagnosticCollection>;
// Targets available for building
/**
* All targets available to be built
*/
readonly targets: Promise<Target[]>;
// Event fired when configure completes
/**
* Event fired when the configure/generate stage completes
*/
readonly reconfigured: Event<void>;
// Event fired when the default build target changes
/**
* Event fired when the active target changes.
*/
readonly targetChangedEvent: Event<void>;
// Execute a command using the CMake executable
executeCMakeCommand(args: string[], options?: ExecuteOptions): Promise<ExecutionResult>;
/**
* Execute a command using the CMake executable.
*
* @param args Arguments to CMake
* @param options Additional execution options
* @returns The result of execution.
*/
executeCMakeCommand(args: string[], options?: ExecutionOptions): Promise<ExecutionResult>;
// Execute an arbitrary program in the active environments
execute(program: string, args: string[], options?: ExecuteOptions): Promise<ExecutionResult>;
/**
* Execute an arbitrary program.
*
* @param program Path to an executable binary
* @param args List of command-line arguments to the program
* @param options Additional execution options
* @returns The result of execution
*
* ## Why you should use this API:
*
* You can execute a program on your own, but if it requires access to
* environment variables that CMake Tools knows about, such as Visual C++
* environment variables, this is the most reliable way to ensure that you
* execute in the context that the user is expecting.
*/
execute(program: string, args: string[], options?: ExecutionOptions): Promise<ExecutionResult>;
// Get the compilation information for a file
/**
* Get the compilation information for a file
*
* @param filepath The source file in question
* @returns New compilation info, or `null` if no compilation info was found
* for the named file.
*/
compilationInfoForFile(filepath: string): Promise<CompilationInfo | null>;
// Configure the project. Returns the return code from CMake.
/**
* Configure the project.
*
* @param extraArgs Extra arguments to pass on the CMake command line
* @param runPreBuild Run any pre-build/configure tasks
* @returns The exit code of CMake
*/
configure(extraArgs?: string[], runPreBuild?: boolean): Promise<number>;
// Build the project. Returns the return code from the build
/**
* Build the project
*
* @param target The target to build. If not provided, will build the user's
* active build target.
* @returns the exit code of the build command
*/
build(target?: string): Promise<number>;
// Install the project. Returns the return code from CMake
/**
* Installs the project
* @returns The exit code from CMake
*/
install(): Promise<number>;
// Open the CMake Cache file in a text editor
/**
* Open a text editor to the CMake cache file.
*
* @returns A new text editor, or `null` if the file could not be opened.
*/
jumpToCacheFile(): Promise<TextEditor | null>;
// Clean the build output
/**
* Clean the build output. Runs the `clean` target.
*
* @returns The exit code from the build command
*/
clean(): Promise<number>;
/**
* Clean up old configuration and reconfigure.
*
* @returns The exit code from CMake
*
* @note This is *not* the same as running `clean`, then `configure`.
* Cleaning up configure includes removing the CMake cache file and any
* intermediate configuration files.
*/
// Remove cached build settings and rerun the configuration
cleanConfigure(): Promise<number>;
// Clean the build output and rebuild
/**
* Clean the build output and rebuild
*
* @returns The exit code from the build command.
*/
cleanRebuild(): Promise<number>;
// Build a target selected by the user
/**
* Asks the user to select a target, then builds that target.
*
* @returns The exit code from the build command.
*/
buildWithTarget(): Promise<number>;
// Show a selector for the user to set the default build target
/**
* Open up a QuickPick where the user can select a target to build.
*/
setDefaultTarget(): Promise<void>;
// Set the active build variant
/**
* Set the new build type.
*
* @returns The exit code from running CMake configure
*/
setBuildType(): Promise<number>;
// Execute CTest
/**
* Execute CTest
*
* @returns The exit code from CTest
*/
ctest(): Promise<number>;
// Stop the currently running build/configure/test/install process
/**
* Stop the currently running command.
*
* @returns `true` on success. `false` otherwise.
*/
stop(): Promise<boolean>;
// Show a quickstart
/**
* Run the CMake project quickstart.
*
* @returns The exit code from running CMake configure
*/
quickStart(): Promise<number>;
// Start the executable target without a debugger
/**
* Start the active target without a debugger.
*/
launchTarget(): Promise<void>;
// Start the debugger with the selected build target
/**
* Start the active target with a debugger.
*/
debugTarget(): Promise<void>;
// Get the path to the active debugging target
/**
* Get the path to the active launch target
*/
launchTargetProgramPath(): Promise<string | null>;
// Allow the user to select target to debug
/**
* Show a QuickPick to select a new target to launch.
*/
selectLaunchTarget(): Promise<string | null>;
// Show the environment selection quickpick
/**
* Show a QuickPick to select a build environment
*/
selectEnvironments(): Promise<void>;
// Sets the variant based on keyword settings
/**
* Select the active variant combination
*/
setActiveVariantCombination(settings: VariantKeywordSettings): Promise<void>;
// Toggle code coverage view on/off
/**
* Toggle test coverage decorations
*/
toggleCoverageDecorations(): void;
}

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

@ -1,32 +1,54 @@
/**
* Module for reading from the CMake cache
*/ /** */
import * as api from './api';
// import * as async from './async';
import * as util from './util';
// import {log} from "./logging";
import {fs} from './pr';
/**
* Implements access to CMake cache entries. See `api.CacheEntry` for more
* information. This type is immutable.
*/
export class Entry implements api.CacheEntry {
private _type: api.EntryType = api.EntryType.Uninitialized;
private _type: api.CacheEntryType = api.CacheEntryType.Uninitialized;
private _docs: string = '';
private _key: string = '';
private _value: any = null;
private _advanced: boolean = false;
public get type() { return this._type; }
get type() { return this._type; }
public get helpString() { return this._docs; }
get helpString() { return this._docs; }
public get key() { return this._key; }
get key() { return this._key; }
public get value() { return this._value; }
get value() { return this._value; }
public as<T>(): T { return this.value as T; }
as<T>(): T { return this.value as T; }
public get advanced() { return this._advanced; }
get advanced() { return this._advanced; }
constructor(key: string, value: string, type: api.EntryType, docs: string, advanced: boolean) {
/**
* Create a new Cache Entry instance. Doesn't modify any files. You probably
* want to get these from the `CMakeCache` object instead.
* @param key The name of the entry
* @param value The actual value of the entry. Always a string.
* @param type The actual type of `value`
* @param docs The `DOC` string in the cache
* @param advanced Whether the entry is `ADVANCED`
*/
constructor(key: string,
value: string,
type: api.CacheEntryType,
docs: string,
advanced: boolean) {
this._key = key;
this._type = type;
if (type === api.EntryType.Bool) {
if (type === api.CacheEntryType.Bool) {
this._value = util.isTruthy(value);
} else {
this._value = value;
@ -36,10 +58,20 @@ export class Entry implements api.CacheEntry {
}
};
/**
* Reads a CMake cache file. This class is immutable.
*/
export class CMakeCache {
private _entries: Map<string, Entry>;
public static async fromPath(path: string): Promise<CMakeCache> {
/**
* Read the contents of a CMakeCache.txt file.
* @param path Path to a CMakeCache.txt-format file
* @returns The CMake cache.
*
* @note The cache *may* not exist. In that case, the entries is empty and
* the `exists` property is `false`. Creating or modifying the file named by
* `path` has no effect on existing instance of this class.
*/
static async fromPath(path: string): Promise<CMakeCache> {
const exists = await fs.exists(path);
if (exists) {
const content = await fs.readFile(path);
@ -50,23 +82,44 @@ export class CMakeCache {
}
}
allEntries(): Entry[] { return Array.from(this._entries.values()); }
/** Get a list of all cache entries */
get allEntries(): Entry[] { return Array.from(this._entries.values()); }
constructor(path: string, exists: boolean, entries: Map<string, Entry>) {
this._entries = entries;
this._path = path;
this._exists = exists;
}
/**
* Create a new instance. This is **private**. You may only create an instance
* via the `fromPath` static method.
* @param _path Path to the cache
* @param _exists Whether the file exists
* @param _entries Entries in the cache
*/
private constructor(private readonly _path: string,
private readonly _exists: boolean,
private readonly _entries: Map<string, Entry>) {}
private _exists: boolean = false;
public get exists() { return this._exists; }
/**
* `true` if the file exists when this instance was created.
* `false` otherwise.
*/
get exists() { return this._exists; }
private _path: string = '';
public get path() { return this._path; }
/**
* The path to the cache file, which may not exist
*/
get path() { return this._path; }
public getReloaded(): Promise<CMakeCache> { return CMakeCache.fromPath(this.path); }
/**
* Reload the cache file and return a new instance. This will not modify this
* instance.
* @returns A **new instance**.
*/
getReloaded(): Promise<CMakeCache> { return CMakeCache.fromPath(this.path); }
public static parseCache(content: string): Map<string, Entry> {
/**
* Parse the contents of a CMake cache file.
* @param content The contents of a CMake cache file.
* @returns A map from the cache keys to the entries in the cache.
*/
static parseCache(content: string): Map<string, Entry> {
const lines = content.split(/\r\n|\n|\r/)
.filter(line => !!line.length)
.filter(line => !/^\s*#/.test(line));
@ -90,15 +143,15 @@ export class CMakeCache {
} else {
const key = name;
const typemap = {
BOOL: api.EntryType.Bool,
STRING: api.EntryType.String,
PATH: api.EntryType.Path,
FILEPATH: api.EntryType.FilePath,
INTERNAL: api.EntryType.Internal,
UNINITIALIZED: api.EntryType.Uninitialized,
STATIC: api.EntryType.Static,
} as { [type: string]: api.EntryType };
const type: api.EntryType = typemap[typename];
BOOL : api.CacheEntryType.Bool,
STRING : api.CacheEntryType.String,
PATH : api.CacheEntryType.Path,
FILEPATH : api.CacheEntryType.FilePath,
INTERNAL : api.CacheEntryType.Internal,
UNINITIALIZED : api.CacheEntryType.Uninitialized,
STATIC : api.CacheEntryType.Static,
} as{[type: string] : api.CacheEntryType};
const type: api.CacheEntryType = typemap[typename];
const docs = docs_acc.trim();
docs_acc = '';
if (type === undefined) {
@ -113,7 +166,10 @@ export class CMakeCache {
return entries;
}
public get(key: string): Entry | null {
return this._entries.get(key) || null;
}
}
/**
* Get an entry from the cache
* @param key The name of a cache entry
* @returns The cache entry, or `null` if the cache entry is not present.
*/
get(key: string): Entry | null { return this._entries.get(key) || null; }
}

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

@ -1,15 +1,21 @@
/**
* Root of the extension
*/
import * as vscode from 'vscode';
import {RollbarController} from './rollbar';
import rollbar from './rollbar';
import {KitManager, Kit} from './kit';
import {StateManager} from './state';
import {CMakeDriver} from './driver';
import {LegacyCMakeDriver} from './legacy-driver';
export class CMakeProject implements vscode.Disposable {
// Let's us submit rollbar messages
private _rollbar = new RollbarController(this.extensionContext);
/**
* Class implementing the extension. It's all here!
*/
export class CMakeTools implements vscode.Disposable {
/**
* The state manager for the class
*/
private _stateManager = new StateManager(this.extensionContext);
/**
@ -17,7 +23,11 @@ export class CMakeProject implements vscode.Disposable {
* to it for kit changes.
*/
private _kitManager = new KitManager(this._stateManager);
// We store the active kit here
/**
* Store the active kit. We keep it around in case we need to restart the
* CMake driver.
*/
private _activeKit: Kit | null = null;
/**
@ -25,10 +35,16 @@ export class CMakeProject implements vscode.Disposable {
*/
private _cmakeDriver: CMakeDriver;
/**
* Construct a new instance. The instance isn't ready, and must be initalized.
* @param extensionContext The extension context
*
* This is private. You must call `create` to get an instance.
*/
private constructor(readonly extensionContext: vscode.ExtensionContext) {
// Handle the active kit changing. We want to do some updates and teardown
this._kitManager.onActiveKitChanged(kit => {
this._rollbar.invokeAsync('Changing CMake kit', async() => {
rollbar.invokeAsync('Changing CMake kit', async() => {
this._activeKit = kit;
if (kit) {
await this._cmakeDriver.setKit(kit);
@ -37,9 +53,11 @@ export class CMakeProject implements vscode.Disposable {
});
}
// Teardown
/**
* Dispose the extension
*/
dispose() {
this._rollbar.invoke('Root dispose', () => {
rollbar.invoke('Root dispose', () => {
this._kitManager.dispose();
if (this._cmakeDriver) {
this._cmakeDriver.dispose();
@ -54,17 +72,19 @@ export class CMakeProject implements vscode.Disposable {
if (this._cmakeDriver) {
await this._cmakeDriver.asyncDispose();
}
this._cmakeDriver = await LegacyCMakeDriver.create(this._rollbar);
this._cmakeDriver = await LegacyCMakeDriver.create();
if (this._activeKit) {
await this._cmakeDriver.setKit(this._activeKit);
}
}
// Two-phase initialize
/**
* Two-phase init. Called by `create`.
*/
private async _init() {
await this._rollbar.invokeAsync('Root init', async() => {
await rollbar.invokeAsync('Root init', async() => {
// First, start up Rollbar
await this._rollbar.requestPermissions();
await rollbar.requestPermissions(this.extensionContext);
// Now start the CMake driver
await this._reloadCMakeDriver();
// Start up the kit manager. This will also inject the current kit into
@ -73,26 +93,47 @@ export class CMakeProject implements vscode.Disposable {
});
}
// Static creation, because we never want to hand-out an uninitialized
// instance
static async create(ctx: vscode.ExtensionContext): Promise<CMakeProject> {
const inst = new CMakeProject(ctx);
/**
* Create an instance asynchronously
* @param ctx The extension context
*
* The purpose of making this the only way to create an instance is to prevent
* us from creating uninitialized instances of the CMake Tools extension.
*/
static async create(ctx: vscode.ExtensionContext): Promise<CMakeTools> {
const inst = new CMakeTools(ctx);
await inst._init();
return inst;
}
// Extension command implementations
/**
* Implementation of `cmake.editKits`
*/
editKits() {
return this._rollbar.invokeAsync('editKits', () => this._kitManager.openKitsEditor());
return this._kitManager.openKitsEditor();
}
/**
* Implementation of `cmake.scanForKits`
*/
scanForKits() {
return this._rollbar.invokeAsync('scanForKits', () => this._kitManager.rescanForKits());
return this._kitManager.rescanForKits();
}
selectKit() { return this._rollbar.invokeAsync('selectKit', () => this._kitManager.selectKit()); }
/**
* Implementation of `cmake.selectKit`
*/
selectKit() { return this._kitManager.selectKit(); }
/**
* Implementation of `cmake.configure`
*/
async configure() {
while (!this._activeKit) {
await this.selectKit();
}
return this._rollbar.invokeAsync('configure', () => this._cmakeDriver.configure());
return this._cmakeDriver.configure();
}
}
export default CMakeTools;

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

@ -1,15 +1,65 @@
/**
* Provides a typed interface to CMake Tools' configuration options. You'll want
* to import the `config` default export, which is an instance of the
* `ConfigurationReader` class.
*/ /** */
import * as os from 'os';
import * as path from 'path';
import * as vscode from 'vscode';
import * as util from './util';
import rollbar from './rollbar';
export class ConfigurationReader {
public readConfig<T>(key: string, default_: T | null = null): T | null {
const config = vscode.workspace.getConfiguration('cmake');
const value = config.get(key);
return (value !== undefined) ? value as T : default_;
/**
* Read a config value from `settings.json`
* @param key The configuration setting name
* @param default_ The default value to return, if the setting is missing
*/
function readConfig<T>(key: string): T | null;
function readConfig<T>(key: string, default_: T): T;
function readConfig<T>(key: string, default_?: T): T | null {
const config = vscode.workspace.getConfiguration('cmake');
const value = config.get(key) as T | undefined;
if (value === undefined) {
if (default_ === undefined) {
return null;
} else {
return default_;
}
} else {
return value;
}
}
/**
* Read a config value from `settings.json`, which may be prefixed by the
* platform name.
* @param key The configuration setting name
*/
function readPrefixedConfig<T>(key: string): T | null;
function readPrefixedConfig<T>(key: string, default_: T): T;
function readPrefixedConfig<T>(key: string, default_?: T): T | null {
const platmap = {
win32 : 'windows',
darwin : 'osx',
linux : 'linux',
} as{[k: string] : string};
const platform = platmap[process.platform];
if (default_ === undefined) {
return readConfig(`${platform}.${key}`, readConfig<T>(`${key}`));
} else {
return readConfig(`${platform}.${key}`, readConfig<T>(`${key}`, default_));
}
}
/**
* This class exposes a number of readonly properties which can be used to
* access configuration options. Each property corresponds to a value in
* `settings.json`. See `package.json` for CMake Tools to see the information
* on each property. An underscore in a property name corresponds to a dot `.`
* in the setting name.
*/
class ConfigurationReader {
private _escapePaths(obj: {[k: string] : any}) {
return Object.getOwnPropertyNames(obj).reduce(
(acc, key: string) => {
@ -19,68 +69,58 @@ export class ConfigurationReader {
{} as typeof obj);
}
private _readPrefixed<T>(key: string): T | null {
const platmap = {
win32 : 'windows',
darwin : 'osx',
linux : 'linux',
} as{[k: string] : string};
const platform = platmap[process.platform];
return this.readConfig<T>(`${platform}.${key}`, this.readConfig<T>(`${key}`));
}
get buildDirectory(): string { return readPrefixedConfig<string>('buildDirectory') !; }
get buildDirectory(): string { return this._readPrefixed<string>('buildDirectory') !; }
get installPrefix(): string | null { return readPrefixedConfig<string>('installPrefix') !; }
get installPrefix(): string | null { return this._readPrefixed<string>('installPrefix') !; }
get sourceDirectory(): string { return readPrefixedConfig<string>('sourceDirectory') as string; }
get sourceDirectory(): string { return this._readPrefixed<string>('sourceDirectory') as string; }
get buildBeforeRun(): boolean { return !!readPrefixedConfig<boolean>('buildBeforeRun'); }
get buildBeforeRun(): boolean { return !!this._readPrefixed<boolean>('buildBeforeRun'); }
get saveBeforeBuild(): boolean { return !!this._readPrefixed<boolean>('saveBeforeBuild'); }
get saveBeforeBuild(): boolean { return !!readPrefixedConfig<boolean>('saveBeforeBuild'); }
get clearOutputBeforeBuild(): boolean {
return !!this._readPrefixed<boolean>('clearOutputBeforeBuild');
return !!readPrefixedConfig<boolean>('clearOutputBeforeBuild');
}
get configureSettings(): any { return this._readPrefixed<Object>('configureSettings'); }
get configureSettings(): any { return readPrefixedConfig<Object>('configureSettings'); }
get initialBuildType(): string | null { return this._readPrefixed<string>('initialBuildType'); }
get initialBuildType(): string | null { return readPrefixedConfig<string>('initialBuildType'); }
get preferredGenerators(): string[] {
return this._readPrefixed<string[]>('preferredGenerators') || [];
return readPrefixedConfig<string[]>('preferredGenerators', []);
}
get generator(): string | null { return this._readPrefixed<string>('generator'); }
get generator(): string | null { return readPrefixedConfig<string>('generator'); }
get toolset(): string | null { return this._readPrefixed<string>('toolset'); }
get toolset(): string | null { return readPrefixedConfig<string>('toolset'); }
get platform(): string | null { return this._readPrefixed<string>('platform'); }
get platform(): string | null { return readPrefixedConfig<string>('platform'); }
get configureArgs(): string[] { return this._readPrefixed<string[]>('configureArgs') !; }
get configureArgs(): string[] { return readPrefixedConfig<string[]>('configureArgs') !; }
get buildArgs(): string[] { return this._readPrefixed<string[]>('buildArgs') !; }
get buildArgs(): string[] { return readPrefixedConfig<string[]>('buildArgs') !; }
get buildToolArgs(): string[] { return this._readPrefixed<string[]>('buildToolArgs') !; }
get buildToolArgs(): string[] { return readPrefixedConfig<string[]>('buildToolArgs') !; }
get parallelJobs(): number | null { return this._readPrefixed<number>('parallelJobs'); }
get parallelJobs(): number | null { return readPrefixedConfig<number>('parallelJobs'); }
get ctest_parallelJobs(): number | null {
return this._readPrefixed<number>('ctest.parallelJobs');
return readPrefixedConfig<number>('ctest.parallelJobs');
}
get parseBuildDiagnostics(): boolean {
return !!this._readPrefixed<boolean>('parseBuildDiagnostics');
return !!readPrefixedConfig<boolean>('parseBuildDiagnostics');
}
get enableOutputParsers(): string[] | null {
return this._readPrefixed<string[]>('enableOutputParsers');
return readPrefixedConfig<string[]>('enableOutputParsers');
}
get cmakePath(): string { return this._readPrefixed<string>('cmakePath') || 'cmake'; }
get cmakePath(): string { return readPrefixedConfig<string>('cmakePath', 'cmake'); }
get ctestPath(): string {
const ctest_path = this._readPrefixed<string>('ctestPath');
const ctest_path = readPrefixedConfig<string>('ctestPath');
if (!ctest_path) {
const cmake = this.cmakePath;
if (cmake === 'cmake' || cmake === 'cmake.exe') {
@ -92,33 +132,32 @@ export class ConfigurationReader {
}
}
get debugConfig(): any { return this._readPrefixed<any>('debugConfig'); }
get debugConfig(): any { return readPrefixedConfig<any>('debugConfig'); }
get environment() {
return this._escapePaths(this._readPrefixed<{[key: string] : string}>('environment') || {});
return this._escapePaths(readPrefixedConfig<{[key: string] : string}>('environment', {}));
}
get configureEnvironment() {
return this._escapePaths(this._readPrefixed<{[key: string] : string}>('configureEnvironment')
|| {});
return this._escapePaths(
readPrefixedConfig<{[key: string] : string}>('configureEnvironment', {}));
}
get buildEnvironment() {
return this._escapePaths(this._readPrefixed<{[key: string] : string}>('buildEnvironment')
|| {});
return this._escapePaths(readPrefixedConfig<{[key: string] : string}>('buildEnvironment', {}));
}
get testEnvironment() {
return this._escapePaths(this._readPrefixed<{[key: string] : string}>('testEnvironment') || {});
return this._escapePaths(readPrefixedConfig<{[key: string] : string}>('testEnvironment', {}));
}
get defaultVariants(): Object { return this._readPrefixed<Object>('defaultVariants') || {}; }
get defaultVariants(): Object { return readPrefixedConfig<Object>('defaultVariants', {}); }
get ctestArgs(): string[] { return this._readPrefixed<string[]>('ctestArgs') || []; }
get ctestArgs(): string[] { return readPrefixedConfig<string[]>('ctestArgs', []); }
get useCMakeServer(): boolean { return this._readPrefixed<boolean>('useCMakeServer') || false; }
get useCMakeServer(): boolean { return readPrefixedConfig<boolean>('useCMakeServer', true); }
public get numJobs(): number {
get numJobs(): number {
const jobs = this.parallelJobs;
if (!!jobs) {
return jobs;
@ -126,7 +165,7 @@ export class ConfigurationReader {
return os.cpus().length + 2;
}
public get numCTestJobs(): number {
get numCTestJobs(): number {
const ctest_jobs = this.ctest_parallelJobs;
if (!ctest_jobs) {
return this.numJobs;
@ -134,14 +173,31 @@ export class ConfigurationReader {
return ctest_jobs;
}
public get mingwSearchDirs(): string[] {
return this._readPrefixed<string[]>('mingwSearchDirs') || [];
get mingwSearchDirs(): string[] { return readPrefixedConfig<string[]>('mingwSearchDirs', []); }
get emscriptenSearchDirs(): string[] {
return readPrefixedConfig<string[]>('emscriptenSearchDirs', []);
}
public get emscriptenSearchDirs(): string[] {
return this._readPrefixed<string[]>('emscriptenSearchDirs') || [];
/**
* Watch for changes on a particular setting
* @param setting The name of the setting to watch
* @param cb A callback when the setting changes
*/
onChange<K extends keyof ConfigurationReader>(setting: K,
cb: (value: ConfigurationReader[K]) => void) {
const state = {value : this[setting]};
return vscode.workspace.onDidChangeConfiguration(_ => {
rollbar.invoke(`Callback changing setting: cmake.${setting}`, () => {
const new_value = this[setting];
if (new_value !== state.value) {
state.value = new_value;
cb(new_value);
}
});
});
}
}
export const config = new ConfigurationReader();
const config = new ConfigurationReader();
export default config;

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

@ -1,18 +1,41 @@
/**
* This module defines important directories and paths to the extension
*/ /** */
import * as path from 'path';
export function userHome(): string { return process.env['HOME'] || process.env['PROFILE'] !; }
/**
* Directory class.
*/
class Dirs {
/**
* The current user's home directory
*/
get userHome(): string { return process.env['HOME'] || process.env['PROFILE'] !; }
export function userLocalDir(): string {
if (process.platform == 'win32') {
return process.env['AppData'] !;
} else {
const xdg_dir = process.env["XDG_DATA_HOME"];
if (xdg_dir) {
return xdg_dir;
/**
* The user-local data directory. This is where user-specific persistent
* application data should be stored.
*/
get userLocalDir(): string {
if (process.platform == 'win32') {
return process.env['AppData'] !;
} else {
const xdg_dir = process.env["XDG_DATA_HOME"];
if (xdg_dir) {
return xdg_dir;
}
const home = this.userHome;
return path.join(home, '.local/share');
}
const home = userHome();
return path.join(home, '.local/share');
}
/**
* The directory where CMake Tools should store user-specific persistent
* data.
*/
get dataDir(): string { return path.join(this.userLocalDir, 'CMakeTools'); }
}
export function dataDir(): string { return path.join(userLocalDir(), 'CMakeTools'); }
const dirs = new Dirs();
export default dirs;

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

@ -1,47 +1,117 @@
/**
* Defines base class for CMake drivers
*/ /** */
import * as path from 'path';
import * as vscode from 'vscode';
import * as api from './api';
import {RollbarController} from './rollbar';
import rollbar from './rollbar';
import {Kit, CompilerKit, ToolchainKit, VSKit} from './kit';
import {CMakeCache} from './cache';
import * as util from './util';
import {config} from './config';
import config from './config';
import {fs} from './pr';
/**
* Base class for CMake drivers.
*
* CMake drivers are separated because different CMake version warrant different
* communication methods. Older CMake versions need to be driven by the command
* line, but newer versions may be controlled via CMake server, which provides
* a much richer interface.
*
* This class defines the basis for what a driver must implement to work.
*/
export abstract class CMakeDriver implements vscode.Disposable {
/**
* Do the configuration process for the current project.
*
* @returns The exit code from CMake
*/
abstract configure(): Promise<number>;
/**
* Do any necessary disposal for the driver. For the CMake Server driver,
* this entails shutting down the server process and closing the open pipes.
*
* The reason this is separate from the regular `dispose()` is so that the
* driver shutdown may be `await`ed on to ensure full shutdown.
*/
abstract asyncDispose(): Promise<void>;
constructor(protected readonly _rollbar: RollbarController) {}
/**
* Construct the driver. Concrete instances should provide their own creation
* routines.
*/
protected constructor() {}
// We just call the async disposal method
/**
* Dispose the driver. This disposes some things synchronously, but also
* calls the `asyncDispose()` method to start any asynchronous shutdown.
*/
dispose() {
this._rollbar.invokeAsync('Async disposing CMake driver', async () => this.asyncDispose());
rollbar.invokeAsync('Async disposing CMake driver', async() => this.asyncDispose());
this._cacheWatcher.dispose();
}
/// The current kit
protected _kit: Kit | null = null;
/// Get the current kit as a compiler kit
/**
* The current Kit. Starts out `null`, but once set, is never `null` again.
* We do some separation here to protect ourselves: The `_baseKit` property
* is `private`, so derived classes cannot change it, except via
* `_setBaseKit`, which only allows non-null kits. This prevents the derived
* classes from resetting the kit back to `null`.
*/
private _baseKit: Kit | null = null;
/**
* Sets the kit on the base class.
* @param k The new kit
*/
protected _setBaseKit(k: Kit) { this._baseKit = k; }
/**
* Get the current kit. Once non-`null`, the kit is never `null` again.
*/
protected get _kit() { return this._baseKit; }
/**
* Get the current kit as a `CompilerKit`.
*
* @precondition `this._kit` is non-`null` and `this._kit.type` is `compilerKit`.
* Guarded with an `assert`
*/
protected get _compilerKit() {
console.assert(this._kit && this._kit.type == 'compilerKit', JSON.stringify(this._kit));
return this._kit as CompilerKit;
}
/// Get the current kit as a toolchain kit
/**
* Get the current kit as a `ToolchainKit`.
*
* @precondition `this._kit` is non-`null` and `this._kit.type` is `toolchainKit`.
* Guarded with an `assert`
*/
protected get _toolchainFileKit() {
console.assert(this._kit && this._kit.type == 'toolchainKit', JSON.stringify(this._kit));
return this._kit as ToolchainKit;
}
/// Get the current kit as a VS kit
/**
* Get the current kit as a `VSKit`.
*
* @precondition `this._kit` is non-`null` and `this._kit.type` is `vsKit`.
* Guarded with an `assert`
*/
protected get _vsKit() {
console.assert(this._kit && this._kit.type == 'vsKit', JSON.stringify(this._kit));
return this._kit as VSKit;
}
/**
* Determine if we need to wipe the build directory if we change to `kit`
* Determine if we need to wipe the build directory if we change adopt `kit`
* @param kit The new kit
* @returns `true` if the new kit requires a clean reconfigure.
*/
protected _kitChangeNeedsClean(kit: Kit): boolean {
if (!this._kit) {
@ -71,17 +141,24 @@ export abstract class CMakeDriver implements vscode.Disposable {
}
}
}
/**
* Change the current kit. This lets the driver reload, if necessary.
* @param kit The new kit
*/
abstract setKit(kit: Kit): Promise<void>;
/// Are we busy?
/**
* Is the driver busy? ie. running a configure/build/test
*/
get isBusy() { return this._isBusy; }
protected _isBusy: boolean = false;
/**
* The source directory, where the root CMakeLists.txt lives
* The source directory, where the root CMakeLists.txt lives.
*
* @note This is distinct from the config values, since we do variable
* substitution.
*/
get sourceDir(): string {
const dir = util.replaceVars(config.sourceDirectory);
@ -166,31 +243,58 @@ export abstract class CMakeDriver implements vscode.Disposable {
return true;
}
private _cmakeCache: CMakeCache | null;
/**
* The CMake cache for the driver.
*
* Will be automatically reloaded when the file on disk changes.
*/
get cmakeCache() { return this._cmakeCache; }
private _cmakeCache: Promise<CMakeCache | null> = Promise.resolve(null);
/**
* Watcher for the CMake cache file on disk.
*/
private _cacheWatcher = vscode.workspace.createFileSystemWatcher(this.cachePath);
allCacheEntries(): api.CacheEntryProperties[] {
return !this.cmakeCache ? [] : this.cmakeCache.allEntries().map(e => ({
type : e.type,
key : e.key,
value : e.value,
advanced : e.advanced,
helpString : e.helpString,
}));
/**
* Get all cache entries
*/
get allCacheEntries() { return this._allCacheEntries(); }
private async _allCacheEntries(): Promise<api.CacheEntryProperties[]> {
const cache = await this.cmakeCache;
if (!cache) {
return [];
} else {
return cache.allEntries.map(e => ({
type : e.type,
key : e.key,
value : e.value,
advanced : e.advanced,
helpString : e.helpString,
}));
}
}
/**
* Asynchronous initialization. Should be called by base classes during
* their initialization.
*/
protected async _init() {
if (await fs.exists(this.cachePath)) {
this._cmakeCache = await CMakeCache.fromPath(this.cachePath);
this._cmakeCache = CMakeCache.fromPath(this.cachePath);
}
this._cacheWatcher.onDidChange(() => {
this._rollbar.invokeAsync('Reloading CMake Cache', async() => {
this._cmakeCache = await CMakeCache.fromPath(this.cachePath);
rollbar.invokeAsync('Reloading CMake Cache', async() => {
this._cmakeCache = CMakeCache.fromPath(this.cachePath);
// Force await here so that any errors are thrown into rollbar
await this._cmakeCache;
});
});
}
/**
* Get the list of command line flags that should be passed to CMake
*/
protected _cmakeFlags(): string[] {
const settings = Object.assign({}, config.configureSettings);
@ -217,7 +321,6 @@ export abstract class CMakeDriver implements vscode.Disposable {
};
const settings_flags
= util.objectPairs(settings).map(([ key, value ]) => _makeFlag(key, value));
// = Object.getOwnPropertyNames(settings).map(key => _makeFlag(key, settings[key]));
const flags = [ '--no-warn-unused-cli' ];
return flags.concat(settings_flags);
}

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

@ -1,3 +1,7 @@
/**
* Extension startup/teardown
*/ /** */
'use strict';
import * as vscode from 'vscode';
@ -6,27 +10,39 @@ import * as vscode from 'vscode';
// import { log } from './logging';
// import { outputChannels } from "./util";
import {CMakeProject} from './project';
import CMakeTools from './cmake-tools';
import rollbar from './rollbar';
export async function activate(context: vscode.ExtensionContext): Promise<CMakeProject> {
/**
* Starts up the extension.
* @param context The extension context
* @returns A promise that will resolve when the extension is ready for use
*/
export async function activate(context: vscode.ExtensionContext): Promise<CMakeTools> {
// log.initialize(context);
const pr = await CMakeProject.create(context);
// Create a new instance and initailize.
const cmt = await CMakeTools.create(context);
context.subscriptions.push(pr);
// Push it so we get clean teardown.
context.subscriptions.push(cmt);
function register(name: keyof CMakeProject) {
const fn = (pr[name] as Function).bind(pr);
return vscode.commands.registerCommand('cmake.' + name, _ => fn());
// A register function helps us bind the commands to the extension
function register<K extends keyof CMakeTools>(name: K) {
const fn = (cmt[name] as Function).bind(cmt);
return vscode.commands.registerCommand('cmake.' + name, () => {
return rollbar.invokeAsync(name, fn);
});
}
const funs : (keyof CMakeProject)[] =
// List of functions that will be bound commands
const funs : (keyof CMakeTools)[] =
[
'editKits',
'scanForKits',
'selectKit',
'configure',
// 'build',
// 'build',
// 'install',
// 'jumpToCacheFile',
// 'clean',
@ -45,9 +61,12 @@ export async function activate(context: vscode.ExtensionContext): Promise<CMakeP
// 'selectEnvironments',
// 'toggleCoverageDecorations',
];
// Bind them all!
for (const key of funs) { context.subscriptions.push(register(key));}
return pr;
// Return that promise
return cmt;
}
// this method is called when your extension is deactivated

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

@ -1,15 +1,24 @@
/**
* Module for controlling and working with Kits.
*/ /** */
import * as vscode from 'vscode';
import * as path from 'path';
import * as proc from './proc';
import * as dirs from './dirs';
import dirs from './dirs';
import {StateManager} from './state';
import {fs} from './pr';
/**
* Base of all kits. Just has a name.
*/
export interface BaseKit { name: string; }
export interface BaseKit {
/**
* The name of the kit
*/
name: string;
}
/**
* CompilerKits list compilers for each language. This will be used on platforms
@ -17,6 +26,13 @@ export interface BaseKit { name: string; }
*/
export interface CompilerKit extends BaseKit {
type: 'compilerKit';
/**
* The language compilers.
*
* The key `lang` is the language, as in `CMAKE_<lang>_COMPILER`.
* The corresponding value is a path to a compiler for that language.
*/
compilers: {[lang: string] : string}
}
@ -26,7 +42,18 @@ export interface CompilerKit extends BaseKit {
*/
export interface VSKit extends BaseKit {
type: 'vsKit';
/**
* The visual studio name. This corresponds to a name returned by `vswhere`,
* and is used to look up the path to the VS installation when the user
* selects this kit
*/
visualStudio: string;
/**
* The architecture for the kit. This is used when asking for the architecture
* from the dev environment batch file.
*/
visualStudioArchitecture: string;
}
@ -35,24 +62,31 @@ export interface VSKit extends BaseKit {
*/
export interface ToolchainKit extends BaseKit {
type: 'toolchainKit';
/**
* Path to a CMake toolchain file.
*/
toolchainFile: string;
}
/// Kits are a sum type of the above interface
/**
* Tagged union of all the kit types
*/
export type Kit = CompilerKit | VSKit | ToolchainKit;
/**
* Convert a binary (by path) to a CompilerKit. This checks if the named binary
* is a GCC or Clang compiler and gets its version. If it is not a compiler,
* returns null.
* returns `null`.
* @param bin Path to a binary
* @returns A CompilerKit, or null if `bin` is not a known compiler
*/
async function kitIfCompiler(bin: string):
Promise<CompilerKit | null> {
const fname = path.basename(bin);
const gcc_regex = /^gcc(-\d+(\.\d+(\.\d+)?)?)?$/;
const clang_regex = /^clang(-\d+(\.\d+(\.\d+)?)?)?$/;
// Check by filename what the compiler might be. This is just heuristic.
const gcc_regex = /^gcc(-\d+(\.\d+(\.\d+)?)?)?(\\.exe)?$/;
const clang_regex = /^clang(-\d+(\.\d+(\.\d+)?)?)?(\\.exe)?$/;
const gcc_res = gcc_regex.exec(fname);
const clang_res = clang_regex.exec(fname);
if (gcc_res) {
@ -166,7 +200,7 @@ async function scanDirForCompilerKits(dir: string) {
* @returns A list of Kits.
*/
async function
scanForKits() {
scanForKits() {
// Search directories on `PATH` for compiler binaries
const pathvar = process.env['PATH'] !;
const sep = process.platform === 'win32' ? ';' : ':';
@ -179,7 +213,11 @@ async function
return kits;
}
function _descriptionForKit(kit: Kit) {
/**
* Generates a string description of a kit. This is shown to the user.
* @param kit The kit to generate a description for
*/
function descriptionForKit(kit: Kit) {
switch (kit.type) {
case 'toolchainKit': {
return `Kit for toolchain file ${kit.toolchainFile}`;
@ -194,12 +232,39 @@ function _descriptionForKit(kit: Kit) {
}
}
/**
* Class that manages and tracks Kits
*/
export class KitManager implements vscode.Disposable {
/**
* The known kits
*/
private _kits = [] as Kit[];
/**
* The path to the `cmake-kits.json` file
*/
private get _kitsPath(): string { return path.join(dirs.dataDir, 'cmake-kits.json'); }
/**
* Watches the file at `_kitsPath`.
*/
private _kitsWatcher = vscode.workspace.createFileSystemWatcher(this._kitsPath);
/**
* Event emitted when the Kit changes. This can be via user action, by the
* available kits changing, or on initial load when the prior workspace kit
* is reloaded.
*/
get onActiveKitChanged() { return this._activeKitChangedEmitter.event; }
private _activeKitChangedEmitter = new vscode.EventEmitter<Kit | null>();
readonly onActiveKitChanged = this._activeKitChangedEmitter.event;
/**
* Change the current kit. Commits the current kit name to workspace-local
* persistent state so that the same kit is reloaded when the user opens
* the workspace again.
* @param kit The new Kit
*/
private _setActiveKit(kit: Kit | null) {
if (kit) {
this.stateManager.activeKitName = kit.name;
@ -209,10 +274,15 @@ export class KitManager implements vscode.Disposable {
this._activeKitChangedEmitter.fire(kit);
}
// The status bar shows the currently selected kit, and allows the user
// to select a new kit
/**
* Shows teh currently selected kit and allows the user to select a new one.
*/
private _statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 3);
/**
* Create a new kit manager.
* @param stateManager The workspace state manager
*/
constructor(readonly stateManager: StateManager) {
// Re-read the kits file when it is changed
this._kitsWatcher.onDidChange(_e => this._rereadKits());
@ -229,14 +299,22 @@ export class KitManager implements vscode.Disposable {
this._statusItem.show();
}
/**
* Dispose the kit manager
*/
dispose() {
this._kitsWatcher.dispose();
this._activeKitChangedEmitter.dispose();
this._statusItem.dispose();
}
private get _kitsPath(): string { return path.join(dirs.dataDir(), 'cmake-kits.json'); }
/**
* Shows a QuickPick that lets the user select a new kit.
* @returns The selected Kit, or `null` if the user cancelled the selection
* @note The user cannot reset the active kit to `null`. If they make no
* selection, the current kit is kept. The only way it can reset to `null` is
* if the active kit becomes somehow unavailable.
*/
async selectKit(): Promise<Kit | null> {
interface KitItem extends vscode.QuickPickItem {
kit: Kit
@ -244,7 +322,7 @@ export class KitManager implements vscode.Disposable {
const items = this._kits.map((kit): KitItem => {
return {
label : kit.name,
description : _descriptionForKit(kit),
description : descriptionForKit(kit),
kit : kit,
};
});
@ -261,6 +339,12 @@ export class KitManager implements vscode.Disposable {
}
}
/**
* Rescan the system for kits.
*
* This will update the `cmake-kits.json` file with any newly discovered kits,
* and rewrite any previously discovered kits with the new data.
*/
async rescanForKits() {
// clang-format off
const old_kits_by_name = this._kits.reduce(
@ -296,6 +380,10 @@ export class KitManager implements vscode.Disposable {
await fs.writeFile(this._kitsPath, JSON.stringify(sorted_kits, null, 2));
}
/**
* Reread the `cmake-kits.json` file. This will be called if we write the
* file in `rescanForKits`, or if the user otherwise edits the file manually.
*/
private async _rereadKits() {
const content_str = await fs.readFile(this._kitsPath);
const content = JSON.parse(content_str.toLocaleString()) as object[];
@ -344,6 +432,9 @@ export class KitManager implements vscode.Disposable {
this._setActiveKit(already_active_kit || null);
}
/**
* Initialize the kits manager. Must be called before using an instance.
*/
async initialize() {
if (await fs.exists(this._kitsPath)) {
// Load up the list of kits that we've saved
@ -367,8 +458,11 @@ export class KitManager implements vscode.Disposable {
}
}
/**
* Opens a text editor with the user-local `cmake-kits.json` file.
*/
async openKitsEditor() {
const text = await vscode.workspace.openTextDocument(this._kitsPath);
return vscode.window.showTextDocument(text);
}
}
}

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

@ -1,21 +1,29 @@
import {CMakeDriver} from './driver';
import {RollbarController} from './rollbar';
/**
* Module for the legacy driver. Talks to pre-CMake Server versions of CMake.
* Can also talk to newer versions of CMake via the command line.
*/ /** */
import { CMakeDriver } from './driver';
// import rollbar from './rollbar';
import {Kit} from './kit';
import {fs} from './pr';
import {config} from './config';
import config from './config';
import * as util from './util';
import * as proc from './proc';
// import * as proc from './proc';
/**
* The legacy driver.
*/
export class LegacyCMakeDriver extends CMakeDriver {
private constructor(rb: RollbarController) { super(rb); }
private constructor() { super(); }
async setKit(kit: Kit): Promise<void> {
const need_clean = this._kitChangeNeedsClean(kit);
if (need_clean) {
await fs.rmdir(this.binaryDir);
}
this._kit = kit;
this._setBaseKit(kit);
}
// Legacy disposal does nothing
@ -57,8 +65,8 @@ export class LegacyCMakeDriver extends CMakeDriver {
return res.retc;
}
static async create(rb: RollbarController): Promise<LegacyCMakeDriver> {
const inst = new LegacyCMakeDriver(rb);
static async create(): Promise<LegacyCMakeDriver> {
const inst = new LegacyCMakeDriver();
await inst._init();
return inst;
}

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

@ -1,3 +1,8 @@
/**
* This module promise-ifies some NodeJS APIs that are frequently used in this
* ext.
*/ /** */
import promisify_ = require('es6-promisify');
import * as util from 'util';
// VSCode doesn't ship with util.promisify yet, but we do have type definitions for it, so we'll
@ -6,10 +11,14 @@ const promisify = promisify_ as typeof util.promisify;
import * as fs_ from 'fs';
import * as path from 'path';
import * as crypto from 'crypto';
import * as rimraf from 'rimraf';
/**
* Wrappers for the `fs` module.
*
* Also has a few utility functions
*/
export namespace fs {
export function exists(fspath: string): Promise<boolean> {
@ -36,6 +45,11 @@ export namespace fs {
export const unlink = promisify(fs_.unlink);
/**
* Creates a directory and all parent directories recursively. If the file
* already exists, and is not a directory, just return.
* @param fspath The directory to create
*/
export async function mkdir_p(fspath: string): Promise<void> {
const parent = path.dirname(fspath);
if (!await exists(parent)) {
@ -54,6 +68,11 @@ export namespace fs {
}
}
/**
* Copy a file from one location to another.
* @param inpath The input file
* @param outpath The output file
*/
export function copyFile(inpath: string, outpath: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
const reader = fs_.createReadStream(inpath);
@ -69,21 +88,10 @@ export namespace fs {
});
}
export function hexHash(filepath: string): Promise<string> {
return new Promise<string>((resolve, reject) => {
const hash = crypto.createHash('md5');
const reader = fs_.createReadStream(filepath);
reader.on('error', e => reject(e));
reader.on('open', _fd => {
reader.pipe(hash);
reader.on('close', () => {
hash.end();
resolve((hash.read() as Buffer).toString('hex'));
});
});
});
}
/**
* Remove a directory recursively. **DANGER DANGER!**
* @param dirpath Directory to remove
*/
export function rmdir(dirpath: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
rimraf(dirpath, err => {

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

@ -1,27 +1,32 @@
/**
* Wrappers and utilities around the NodeJS `child_process` module.
*/ /** */
import * as proc from 'child_process';
export interface ExecutionResult {
retc: number;
stdout: string;
stderr: string;
}
import {ExecutionResult} from './api';
export function execute(command: string, args: string[], options?: proc.SpawnOptions): Promise<ExecutionResult> {
return new Promise<ExecutionResult>((resolve, reject) => {
const child = proc.spawn(command, args, options);
child.on('error', (err) => {
reject(err);
});
let stdout_acc = '';
let stderr_acc = '';
child.stdout.on('data', (data: Uint8Array) => {
stdout_acc += data.toString();
});
child.stderr.on('data', (data: Uint8Array) => {
stderr_acc += data.toString();
});
child.on('close', (retc) => {
resolve({retc: retc, stdout: stdout_acc, stderr: stderr_acc});
});
});
/**
* Execute a command and return the result
* @param command The binary to execute
* @param args The arguments to pass to the binary
* @param options Additional execution options
*
* @note Output from the command is accumulated into a single buffer: Commands
* which produce a lot of output should be careful about memory constraints.
*/
export function execute(command: string, args: string[], options?: proc.SpawnOptions):
Promise<ExecutionResult> {
return new Promise<ExecutionResult>((resolve, reject) => {
const child = proc.spawn(command, args, options);
child.on('error', (err) => { reject(err); });
let stdout_acc = '';
let stderr_acc = '';
child.stdout.on('data', (data: Uint8Array) => { stdout_acc += data.toString(); });
child.stderr.on('data', (data: Uint8Array) => { stderr_acc += data.toString(); });
// Don't stop until the child stream is closed, otherwise we might not read
// the whole output of the command.
child.on('close',
(retc) => { resolve({retc : retc, stdout : stdout_acc, stderr : stderr_acc}); });
});
}

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

@ -1,41 +1,70 @@
/**
* Wrapper around Rollbar, for error reporting.
*/ /** */
import * as vscode from 'vscode';
import Rollbar = require('rollbar');
/**
* The wrapper around Rollbar. Presents a nice functional API.
*/
class RollbarController {
/**
* The payload to send with any messages. Can be updated via `updatePayload`.
*/
private readonly _payload: object = {platform : 'client'};
export class RollbarController {
/**
* The Rollbar client instance we use to communicate.
*/
private _rollbar = new Rollbar({
accessToken : '14d411d713be4a5a9f9d57660534cac7',
reportLevel : 'error',
payload : {
platform : 'client',
},
payload : this._payload,
});
/**
* If `true`, we will send messages. We must get the user's permission first!
*/
private _enabled = false;
constructor(readonly extensionContext: vscode.ExtensionContext) {}
async requestPermissions() {
/**
* Request permission to use Rollbar from the user. This will show a message
* box at the top of the window on first permission request.
* @param extensionContext Extension context, where we use a memento to
* remember our permission
*/
async requestPermissions(extensionContext: vscode.ExtensionContext): Promise<void> {
// The memento key where we store permission. Update this to ask again.
const key = 'rollbar-optin3';
const optin = this.extensionContext.globalState.get(key);
const optin = extensionContext.globalState.get(key);
if (optin === true) {
this._enabled = true;
} else if (optin == false) {
this._enabled = false;
} else if (optin === undefined) {
// We haven't asked yet. Ask them now:
const item = await vscode.window.showInformationMessage(
"Would you like to opt-in to send anonymous error and exception data to help improve CMake Tools?",
{ title: 'Yes!', isCloseAffordance: false, } as vscode.MessageItem,
{ title: 'No Thanks', isCloseAffordance: true, } as vscode.MessageItem);
if (item === undefined) {
// We didn't get an answer
return;
}
this.extensionContext.globalState.update(key, !item.isCloseAffordance);
extensionContext.globalState.update(key, !item.isCloseAffordance);
this._enabled = !item.isCloseAffordance
}
}
/**
* Log an exception with Rollbar.
* @param what A message about what we were doing when the exception happened
* @param exception The exception object
* @param additional Additional items in the payload
* @returns The LogResult if we are enabled. `null` otherwise.
*/
exception(what: string, exception: Error, additional: object = {}): Rollbar.LogResult | null {
if (this._enabled) {
return this._rollbar.error(what, exception, additional);
@ -43,25 +72,57 @@ export class RollbarController {
return null;
}
/**
* Log an error with Rollbar
* @param what A message about what we were doing when the error happened
* @param additional Additional items in the payload
* @returns The LogResult if we are enabled. `null` otherwise.
*/
error(what: string, additional: object = {}): Rollbar.LogResult | null {
if (this._enabled) {
return this._rollbar.error(what, additional);
const stack = new Error().stack;
return this._rollbar.error(what, additional, {stack: stack});
}
return null;
}
invokeAsync<T>(what: string, func: () => Promise<T>): Promise<T>;
/**
* Update the content of the Rollbar payload with additional context
* information.
* @param data Daya to merge into the payload
*/
updatePayload(data: object) {
Object.assign(this._payload, data);
this._rollbar.configure({payload : this._payload});
}
/**
* Invoke an asynchronous function, and catch any promise rejects.
* @param what Message about what we are doing
* @param additional Additional data to log
* @param func The block to call
*/
invokeAsync<T>(what: string, additional: object, func: () => Promise<T>): Promise<T>;
invokeAsync<T>(what: string, func: () => Promise<T>): Promise<T>;
invokeAsync<T>(what: string, additional: object, func?: () => Promise<T>): Promise<T> {
if (!func) {
func = additional as() => Promise<T>;
additional = {};
}
return func().catch(e => { this.exception('Unhandled Promise rejection: ' + what, e, additional); });
return func().catch(e => {
this.exception('Unhandled Promise rejection: ' + what, e, additional);
throw e;
});
}
invoke<T>(what: string, func: () => T): T;
/**
* Invoke a synchronous function, and catch and log any unhandled exceptions
* @param what Message about what we are doing
* @param additional Additional data to log
* @param func The block to call
*/
invoke<T>(what: string, additional: object, func: () => T): T;
invoke<T>(what: string, func: () => T): T;
invoke<T>(what: string, additional: object, func?: () => T): T {
if (!func) {
func = additional as() => T;
@ -75,3 +136,6 @@ export class RollbarController {
}
}
}
const rollbar = new RollbarController();
export default rollbar;

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

@ -13,7 +13,9 @@ import * as vscode from 'vscode';
export class StateManager {
constructor(readonly extensionContext: vscode.ExtensionContext) {}
// The kit
/**
* The name of the workspace-local active kit.
*/
public get activeKitName(): string | null {
const kit = this.extensionContext.workspaceState.get<string>('activeKitName');
return kit || null;

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

@ -2,7 +2,7 @@ import * as path from 'path';
import * as vscode from 'vscode';
import {config} from './config';
import config from './config';
/**
* Escape a string so it can be used as a regular expression
@ -86,6 +86,11 @@ export function isTruthy(value: (boolean | string | null | undefined | number))
return !!value;
}
/**
* Generate an array of key-value pairs from an object using
* `getOwnPropertyNames`
* @param obj The object to iterate
*/
export function objectPairs<V>(obj: {[key: string] : V}): [ string, V ][] {
return Object.getOwnPropertyNames(obj).map(key => ([ key, obj[key] ] as[string, V]));
}

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

@ -1,7 +1,7 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"target": "es2017",
"outDir": "out",
"lib": [
"es6"
@ -13,7 +13,8 @@
"strictNullChecks": true,
"experimentalDecorators": true,
"noUnusedLocals": true,
"noUnusedParameters": true
"noUnusedParameters": true,
"noImplicitThis": true
},
"exclude": [
"node_modules",

256
yarn.lock
Просмотреть файл

@ -10,10 +10,47 @@
version "5.0.0"
resolved "https://registry.yarnpkg.com/@types/es6-promisify/-/es6-promisify-5.0.0.tgz#f4ed22257f54c4e4af4d2f498766ef055db7a728"
"@types/fs-extra@^4.0.0":
version "4.0.2"
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-4.0.2.tgz#7b9b1bbf85962cbe029b5a83c9b530d7c75af3ba"
dependencies:
"@types/node" "*"
"@types/glob@*":
version "5.0.32"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-5.0.32.tgz#aec5cfe987c72f099fdb1184452986aa506d5e8f"
dependencies:
"@types/minimatch" "*"
"@types/node" "*"
"@types/handlebars@^4.0.31":
version "4.0.36"
resolved "https://registry.yarnpkg.com/@types/handlebars/-/handlebars-4.0.36.tgz#ff57c77fa1ab6713bb446534ddc4d979707a3a79"
"@types/highlight.js@^9.1.8":
version "9.1.10"
resolved "https://registry.yarnpkg.com/@types/highlight.js/-/highlight.js-9.1.10.tgz#b621f809cd9573b80992b90cffc5788208e3069c"
"@types/js-yaml@^3.5.28":
version "3.9.1"
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.9.1.tgz#2f3c142771bb345829ce690c5838760b6b9ba553"
"@types/lodash@^4.14.37":
version "4.14.74"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.74.tgz#ac3bd8db988e7f7038e5d22bd76a7ba13f876168"
"@types/marked@0.0.28":
version "0.0.28"
resolved "https://registry.yarnpkg.com/@types/marked/-/marked-0.0.28.tgz#44ba754e9fa51432583e8eb30a7c4dd249b52faa"
"@types/minimatch@*":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.1.tgz#b683eb60be358304ef146f5775db4c0e3696a550"
"@types/minimatch@^2.0.29":
version "2.0.29"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-2.0.29.tgz#5002e14f75e2d71e564281df0431c8c1b4a2a36a"
"@types/mocha@~2.2.41":
version "2.2.43"
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.43.tgz#03c54589c43ad048cbcbfd63999b55d0424eec27"
@ -26,6 +63,13 @@
version "0.0.28"
resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06"
"@types/shelljs@^0.7.0":
version "0.7.4"
resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.7.4.tgz#137b5f31306eaff4de120ffe5b9d74b297809cfc"
dependencies:
"@types/glob" "*"
"@types/node" "*"
"@types/ws@^0.0.38":
version "0.0.38"
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-0.0.38.tgz#42106fff4b422ca956734e29f0d73a6d893194d3"
@ -56,6 +100,18 @@ ajv@^5.1.0:
json-schema-traverse "^0.3.0"
json-stable-stringify "^1.0.1"
align-text@^0.1.1, align-text@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
dependencies:
kind-of "^3.0.2"
longest "^1.0.1"
repeat-string "^1.5.2"
amdefine@>=0.0.4:
version "1.0.1"
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
@ -114,6 +170,10 @@ assert-plus@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
async@^1.4.0:
version "1.5.2"
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
async@~1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/async/-/async-1.2.1.tgz#a4816a17cd5ff516dfa2c7698a453369b9790de0"
@ -195,6 +255,10 @@ buffer-crc32@~0.2.3:
version "0.2.13"
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
camelcase@^1.0.2:
version "1.2.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
caseless@~0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
@ -203,6 +267,13 @@ caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
center-align@^0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
dependencies:
align-text "^0.1.3"
lazy-cache "^1.0.3"
chalk@^1.0.0, chalk@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
@ -213,6 +284,14 @@ chalk@^1.0.0, chalk@^1.1.1:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
cliui@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
dependencies:
center-align "^0.1.1"
right-align "^0.1.1"
wordwrap "0.0.2"
clone-buffer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
@ -317,6 +396,10 @@ decache@^3.0.5:
dependencies:
find "^0.2.4"
decamelize@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
deep-assign@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/deep-assign/-/deep-assign-1.0.0.tgz#b092743be8427dc621ea0067cdec7e70dd19f37b"
@ -509,6 +592,14 @@ from@~0:
version "0.1.7"
resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe"
fs-extra@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b"
dependencies:
graceful-fs "^4.1.2"
jsonfile "^4.0.0"
universalify "^0.1.0"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@ -592,7 +683,7 @@ glob@^5.0.3:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.0.5, glob@^7.1.1:
glob@^7.0.0, glob@^7.0.5, glob@^7.1.1:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
dependencies:
@ -609,7 +700,7 @@ glogg@^1.0.0:
dependencies:
sparkles "^1.0.0"
graceful-fs@^4.0.0, graceful-fs@^4.1.2:
graceful-fs@^4.0.0, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
@ -724,6 +815,16 @@ gulplog@^1.0.0:
dependencies:
glogg "^1.0.0"
handlebars@^4.0.6:
version "4.0.10"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f"
dependencies:
async "^1.4.0"
optimist "^0.6.1"
source-map "^0.4.4"
optionalDependencies:
uglify-js "^2.6"
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
@ -782,6 +883,10 @@ he@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
highlight.js@^9.0.0:
version "9.12.0"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e"
hoek@2.x.x:
version "2.16.3"
resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
@ -817,6 +922,10 @@ inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
interpret@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0"
is-buffer@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
@ -967,6 +1076,12 @@ json3@3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
optionalDependencies:
graceful-fs "^4.1.6"
jsonify@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
@ -996,6 +1111,10 @@ kind-of@^4.0.0:
dependencies:
is-buffer "^1.1.5"
lazy-cache@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
lazystream@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
@ -1108,6 +1227,14 @@ lodash.templatesettings@^3.0.0:
lodash._reinterpolate "^3.0.0"
lodash.escape "^3.0.0"
lodash@^4.13.1:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
longest@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
lru-cache@~2.2.1:
version "2.2.4"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.2.4.tgz#6c658619becf14031d0d0b594b16042ce4dc063d"
@ -1116,6 +1243,10 @@ map-stream@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194"
marked@^0.3.5:
version "0.3.6"
resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.6.tgz#b2c6c618fccece4ef86c4fc6cb8a7cbf5aeda8d7"
merge-stream@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1"
@ -1164,6 +1295,10 @@ minimist@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
minimist@~0.0.1:
version "0.0.10"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
@ -1267,6 +1402,13 @@ open@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/open/-/open-0.0.5.tgz#42c3e18ec95466b6bf0dc42f3a2945c3f0cad8fc"
optimist@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
dependencies:
minimist "~0.0.1"
wordwrap "~0.0.2"
options@>=0.0.5:
version "0.0.6"
resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f"
@ -1295,6 +1437,10 @@ path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
path-parse@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
pause-stream@0.0.11:
version "0.0.11"
resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
@ -1327,6 +1473,10 @@ process-nextick-args@^1.0.6, process-nextick-args@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
progress@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f"
punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
@ -1386,6 +1536,12 @@ readable-stream@~1.1.9:
isarray "0.0.1"
string_decoder "~0.10.x"
rechoir@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
dependencies:
resolve "^1.1.6"
regex-cache@^0.4.2:
version "0.4.4"
resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"
@ -1474,6 +1630,18 @@ requires-port@1.0.x:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
resolve@^1.1.6:
version "1.4.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86"
dependencies:
path-parse "^1.0.5"
right-align@^0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
dependencies:
align-text "^0.1.1"
rimraf@2, rimraf@^2.5.4:
version "2.6.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
@ -1508,6 +1676,14 @@ semver@^5.3.0:
version "5.4.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
shelljs@^0.7.0:
version "0.7.8"
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3"
dependencies:
glob "^7.0.0"
interpret "^1.0.0"
rechoir "^0.6.2"
sntp@1.x.x:
version "1.0.9"
resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
@ -1526,7 +1702,13 @@ source-map-support@^0.4.11:
dependencies:
source-map "^0.5.6"
source-map@^0.5.6:
source-map@^0.4.4:
version "0.4.4"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
dependencies:
amdefine ">=0.0.4"
source-map@^0.5.6, source-map@~0.5.1:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
@ -1696,10 +1878,53 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
typedoc-default-themes@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/typedoc-default-themes/-/typedoc-default-themes-0.5.0.tgz#6dc2433e78ed8bea8e887a3acde2f31785bd6227"
typedoc@^0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.8.0.tgz#d7172bc6a29964f451b7609c005beadadefe2361"
dependencies:
"@types/fs-extra" "^4.0.0"
"@types/handlebars" "^4.0.31"
"@types/highlight.js" "^9.1.8"
"@types/lodash" "^4.14.37"
"@types/marked" "0.0.28"
"@types/minimatch" "^2.0.29"
"@types/shelljs" "^0.7.0"
fs-extra "^4.0.0"
handlebars "^4.0.6"
highlight.js "^9.0.0"
lodash "^4.13.1"
marked "^0.3.5"
minimatch "^3.0.0"
progress "^2.0.0"
shelljs "^0.7.0"
typedoc-default-themes "^0.5.0"
typescript "2.4.1"
typescript@2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.4.1.tgz#c3ccb16ddaa0b2314de031e7e6fee89e5ba346bc"
typescript@~2.3.0:
version "2.3.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.4.tgz#3d38321828231e434f287514959c37a82b629f42"
uglify-js@^2.6:
version "2.8.29"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
dependencies:
source-map "~0.5.1"
yargs "~3.10.0"
optionalDependencies:
uglify-to-browserify "~1.0.0"
uglify-to-browserify@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
ultron@1.0.x:
version "1.0.2"
resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa"
@ -1711,6 +1936,10 @@ unique-stream@^2.0.2:
json-stable-stringify "^1.0.0"
through2-filter "^2.0.0"
universalify@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7"
url-parse@^1.1.9:
version "1.1.9"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.9.tgz#c67f1d775d51f0a18911dd7b3ffad27bb9e5bd19"
@ -1825,6 +2054,18 @@ vscode@~1.1.0:
url-parse "^1.1.9"
vinyl-source-stream "^1.1.0"
window-size@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
wordwrap@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
wordwrap@~0.0.2:
version "0.0.3"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
@ -1851,6 +2092,15 @@ xmlbuilder@~9.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
yargs@~3.10.0:
version "3.10.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
dependencies:
camelcase "^1.0.2"
cliui "^2.1.0"
decamelize "^1.0.0"
window-size "0.1.0"
yauzl@^2.2.1:
version "2.8.0"
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.8.0.tgz#79450aff22b2a9c5a41ef54e02db907ccfbf9ee2"