Skip to content

Commit b6cd230

Browse files
add login logout
1 parent 48398c0 commit b6cd230

12 files changed

+250
-6
lines changed

.vscode/launch.json

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// A launch configuration that compiles the extension and then opens it inside a new window
2+
{
3+
"version": "0.1.0",
4+
"configurations": [
5+
{
6+
"name": "Launch Extension",
7+
"type": "extensionHost",
8+
"request": "launch",
9+
"runtimeExecutable": "${execPath}",
10+
"args": ["--extensionDevelopmentPath=${workspaceRoot}" ],
11+
"stopOnEntry": false,
12+
"sourceMaps": true,
13+
"outFiles": [ "${workspaceRoot}/out/src/**/*.js" ],
14+
"preLaunchTask": "npm"
15+
},
16+
{
17+
"name": "Launch Tests",
18+
"type": "extensionHost",
19+
"request": "launch",
20+
"runtimeExecutable": "${execPath}",
21+
"args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ],
22+
"stopOnEntry": false,
23+
"sourceMaps": true,
24+
"outFiles": [ "${workspaceRoot}/out/test/**/*.js" ],
25+
"preLaunchTask": "npm"
26+
}
27+
]
28+
}

.vscode/settings.json

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"editor.formatOnSave": true,
3+
"editor.insertSpaces": true,
4+
"editor.tabSize": 4,
5+
"files.insertFinalNewline": true,
6+
"files.trimTrailingWhitespace": true,
7+
"search.exclude": {
8+
"out": true,
9+
"**/node_modules": true,
10+
".vscode-test": true
11+
},
12+
"tslint.autoFixOnSave": true,
13+
"tslint.ignoreDefinitionFiles": true
14+
}

.vscode/tasks.json

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"label": "npm",
6+
"type": "shell",
7+
"command": "npm",
8+
"group": {
9+
"kind": "build",
10+
"isDefault": true
11+
},
12+
"args": [
13+
"run",
14+
"compile",
15+
"--loglevel",
16+
"silent"
17+
],
18+
"isBackground": true,
19+
"presentation": {
20+
"reveal": "silent"
21+
},
22+
"problemMatcher": "$tsc-watch"
23+
},
24+
{
25+
"type": "npm",
26+
"script": "lint",
27+
"problemMatcher": {
28+
"base": "$tslint5",
29+
"fileLocation": "absolute"
30+
}
31+
}
32+
]
33+
}

package.json

+15-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "leetcode",
3-
"displayName": "Leetcode",
3+
"displayName": "LeetCode",
44
"description": "",
55
"version": "0.0.1",
66
"publisher": "ShengChen",
@@ -11,14 +11,21 @@
1111
"Other"
1212
],
1313
"activationEvents": [
14-
"onCommand:extension.sayHello"
14+
"onCommand:leetcode.signin",
15+
"onCommand:leetcode.signout"
1516
],
16-
"main": "./out/extension",
17+
"main": "./out/src/extension",
1718
"contributes": {
1819
"commands": [
1920
{
20-
"command": "extension.sayHello",
21-
"title": "Hello World"
21+
"command": "leetcode.signin",
22+
"title": "Sign in",
23+
"category": "LeetCode"
24+
},
25+
{
26+
"command": "leetcode.signout",
27+
"title": "Sign out",
28+
"category": "LeetCode"
2229
}
2330
]
2431
},
@@ -36,5 +43,8 @@
3643
"tslint": "^5.9.1",
3744
"typescript": "^2.6.1",
3845
"vscode": "^1.1.6"
46+
},
47+
"dependencies": {
48+
"leetcode-cli": "2.5.1"
3949
}
4050
}

src/commands/user.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"use strict";
2+
3+
import * as vscode from "vscode";
4+
import { leetCodeBinaryPath } from "../shared";
5+
import { executeCommand } from "../utils/cpUtils";
6+
import { DialogOptions, DialogType, promptForOpenOutputChannel } from "../utils/uiUtils";
7+
8+
export async function getSignedInAccount(): Promise<string | undefined> {
9+
try {
10+
const result = await executeCommand("node", [leetCodeBinaryPath, "user"]);
11+
return result.slice("You are now login as".length).trim();
12+
} catch (error) {
13+
const choice: vscode.MessageItem | undefined = await vscode.window.showInformationMessage(
14+
"[LeetCode] Would you like to sign in?",
15+
DialogOptions.yes,
16+
DialogOptions.no,
17+
);
18+
if (choice === DialogOptions.yes) {
19+
// sign in
20+
}
21+
return undefined;
22+
}
23+
}
24+
25+
export function signIn(terminal: vscode.Terminal): void {
26+
terminal.show();
27+
terminal.sendText(`node ${leetCodeBinaryPath} user -l`);
28+
}
29+
30+
export async function signOut(): Promise<void> {
31+
try {
32+
await executeCommand("node", [leetCodeBinaryPath, "user", "-L"]);
33+
vscode.window.showInformationMessage("Successfully signed out.");
34+
} catch (error) {
35+
await promptForOpenOutputChannel("Failed to sign out. Would you like to open output channel for detais?", DialogType.error);
36+
}
37+
}

src/extension.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
"use strict";
22

33
import * as vscode from "vscode";
4+
import * as user from "./commands/user";
45

56
export function activate(context: vscode.ExtensionContext) {
6-
7+
const terminal: vscode.Terminal = vscode.window.createTerminal("LeetCode");
8+
context.subscriptions.push(
9+
terminal,
10+
vscode.commands.registerCommand("leetcode.signin", () => user.signIn(terminal)),
11+
vscode.commands.registerCommand("leetcode.signout", () => user.signOut()),
12+
);
713
}
814

915
// tslint:disable-next-line:no-empty

src/leetCodeChannel.ts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"use strict";
2+
3+
import * as vscode from "vscode";
4+
5+
export interface ILeetCodeChannel {
6+
appendLine(message: any, title?: string): void;
7+
append(message: any): void;
8+
show(): void;
9+
}
10+
11+
class LeetCodeChannel implements ILeetCodeChannel {
12+
private readonly channel: vscode.OutputChannel = vscode.window.createOutputChannel("LeetCode");
13+
14+
public appendLine(message: any, title?: string): void {
15+
if (title) {
16+
const simplifiedTime = (new Date()).toISOString().replace(/z|t/gi, " ").trim(); // YYYY-MM-DD HH:mm:ss.sss
17+
const hightlightingTitle = `[${title} ${simplifiedTime}]`;
18+
this.channel.appendLine(hightlightingTitle);
19+
}
20+
this.channel.appendLine(message);
21+
}
22+
23+
public append(message: any): void {
24+
this.channel.append(message);
25+
}
26+
27+
public show(): void {
28+
this.channel.show();
29+
}
30+
}
31+
32+
export const leetcodeChannel: ILeetCodeChannel = new LeetCodeChannel();

src/leetCodeTerminal.ts

Whitespace-only changes.

src/shared.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"use strict";
2+
3+
import * as path from "path";
4+
5+
export const leetCodeBinaryPath: string = path.join(__dirname, "..", "..", "node_modules", "leetcode-cli", "bin", "leetcode");

src/utils/cpUtils.ts

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"use strict";
2+
3+
import * as cp from "child_process";
4+
import { leetcodeChannel } from "../leetcodeChannel";
5+
6+
export async function executeCommand(command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise<string> {
7+
return new Promise((resolve: (res: string) => void, reject: (e: Error) => void): void => {
8+
let result: string = "";
9+
const childProc: cp.ChildProcess = cp.spawn(command, args, options);
10+
11+
childProc.stdout.on("data", (data: string | Buffer) => {
12+
data = data.toString();
13+
result = result.concat(data);
14+
leetcodeChannel.append(data);
15+
});
16+
17+
childProc.stderr.on("data", (data: string | Buffer) => leetcodeChannel.append(data.toString()));
18+
19+
childProc.on("error", reject);
20+
childProc.on("close", (code: number) => {
21+
if (code !== 0 || result.indexOf("ERROR") > -1) {
22+
reject(new Error(`Command "${command} ${args.toString()}" failed with exit code "${code}".`));
23+
} else {
24+
resolve(result);
25+
}
26+
});
27+
});
28+
}

src/utils/nodeUtils.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
"use strict";
2+
3+
import { executeCommand } from "./cpUtils";
4+
5+
export namespace mavenUtils {
6+
const nodeCommand: string = "node";
7+
export async function validateMavenInstalled(): Promise<void> {
8+
try {
9+
await executeCommand(nodeCommand, ["-v"]);
10+
} catch (error) {
11+
throw new Error('Failed to find "maven" on path.');
12+
}
13+
}
14+
}

src/utils/uiUtils.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"use strict";
2+
3+
import * as vscode from "vscode";
4+
import { leetcodeChannel } from "../leetCodeChannel";
5+
6+
export namespace DialogOptions {
7+
export const open: vscode.MessageItem = { title: "Open" };
8+
export const yes: vscode.MessageItem = { title: "Yes" };
9+
export const no: vscode.MessageItem = { title: "No", isCloseAffordance: true };
10+
}
11+
12+
export async function promptForOpenOutputChannel(message: string, type: DialogType): Promise<void> {
13+
let result: vscode.MessageItem | undefined;
14+
switch (type) {
15+
case DialogType.info:
16+
result = await vscode.window.showInformationMessage(message, DialogOptions.open, DialogOptions.no);
17+
break;
18+
case DialogType.warning:
19+
result = await vscode.window.showWarningMessage(message, DialogOptions.open, DialogOptions.no);
20+
break;
21+
case DialogType.error:
22+
result = await vscode.window.showErrorMessage(message, DialogOptions.open, DialogOptions.no);
23+
break;
24+
default:
25+
break;
26+
}
27+
28+
if (result === DialogOptions.open) {
29+
leetcodeChannel.show();
30+
}
31+
}
32+
33+
export enum DialogType {
34+
info = "info",
35+
warning = "warning",
36+
error = "error",
37+
}

0 commit comments

Comments
 (0)