Skip to content
This repository was archived by the owner on Mar 8, 2022. It is now read-only.

Commit 74ab56e

Browse files
committed
Subcommand settings
Adjust options and preferences of kmdr-cli. Users can now choose a theme from a predefined list and save changes permanently into a JSON file.
1 parent c054e43 commit 74ab56e

File tree

10 files changed

+123
-65
lines changed

10 files changed

+123
-65
lines changed

src/Cli.ts

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import ora from "ora";
44
import os from "os";
55
import path from "path";
66
import pkg from "../package.json";
7-
import DefaultTheme from "./install/themes/greenway.theme.json";
8-
import ThemeManager from "./ThemeManager";
7+
import SettingsManager from "./SettingsManager";
98

109
export default abstract class CLI {
1110
get kmdrDirectoryExists() {
@@ -37,7 +36,7 @@ export default abstract class CLI {
3736
protected readonly kmdrAuthCredentials?: string;
3837
protected httpHeaders: { [key: string]: string } = {};
3938
protected readonly gqlClient: GraphQLClient;
40-
protected theme: ThemeManager;
39+
protected settingsManager: SettingsManager;
4140

4241
constructor() {
4342
this.NODE_ENV = process.env.NODE_ENV || "production";
@@ -54,18 +53,8 @@ export default abstract class CLI {
5453
this.KMDR_PATH = path.join(this.OS_HOME_PATH, ".kmdr");
5554
this.KMDR_AUTH_FILE = path.join(this.KMDR_PATH, "auth");
5655

57-
this.theme = new ThemeManager(DefaultTheme);
56+
this.settingsManager = new SettingsManager(this.KMDR_PATH);
5857

59-
// if (this.NODE_ENV === "development") {
60-
// this.KMDR_ENDPOINT_PROTOCOL = "http";
61-
// this.KMDR_ENDPOINT_HOST = "localhost";
62-
// this.KMDR_ENDPOINT_PORT = 8081;
63-
// } else {
64-
// this.KMDR_ENDPOINT_PROTOCOL = "https";
65-
// this.KMDR_ENDPOINT_HOST = "stg.api.kmdr.sh";
66-
// }
67-
68-
// this.KMDR_ENDPOINT_URI = `${this.KMDR_ENDPOINT_PROTOCOL}://${this.KMDR_ENDPOINT_HOST}`;
6958
this.KMDR_ENDPOINT_URI = process.env.KMDR_API_ENDPOINT || "https://stg.api.kmdr.sh";
7059

7160
if (this.kmdrAuthFileExists) {

src/SettingsManager.ts

Lines changed: 62 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,92 @@
11
import { parse } from "commander";
22
import fs from "fs";
33
import path from "path";
4-
import DefaultTheme from "./install/themes/greenway.theme.json";
5-
import { Settings } from "./interfaces";
4+
import DefaultTheme from "./files/themes/greenway.theme.json";
5+
import { Settings, SettingsFile, Theme } from "./interfaces";
6+
import Print from "./Print";
67
import ThemeManager from "./ThemeManager";
8+
import os from "os";
79

810
export default class SettingsManager implements Settings {
9-
// public availableThemes: Theme[];
10-
public theme: ThemeManager;
11+
public availableThemes: ThemeManager[] = [];
12+
public theme!: ThemeManager;
1113
private settingsPath: string;
1214

1315
constructor(settingsPath: string) {
1416
this.settingsPath = settingsPath;
15-
this.theme = new ThemeManager(DefaultTheme);
1617

18+
this.loadAllThemes();
1719
// If directory does not exists, use default settings
1820
if (!fs.existsSync(this.settingsPath)) {
19-
this.theme = new ThemeManager(DefaultTheme);
21+
this.loadDefault();
2022
} else {
23+
this.loadFromDisk();
24+
}
25+
}
26+
27+
public saveToDisk(newSettings: SettingsFile) {
28+
try {
2129
const filePath = path.join(this.settingsPath, "settings.json");
2230

23-
try {
24-
const file = fs.readFileSync(filePath, "utf8");
31+
fs.writeFileSync(filePath, JSON.stringify(newSettings, null, 2) + os.EOL, {
32+
encoding: "utf8",
33+
mode: 0o640,
34+
});
35+
} catch (err) {
36+
console.error(err);
37+
}
38+
}
39+
40+
private loadAllThemes() {
41+
const themesPath = path.join(path.basename(__dirname), "files", "themes");
42+
43+
const themeFiles = fs.readdirSync(themesPath);
2544

26-
if (file === "") {
27-
console.error("FIle is empty. Setting default");
28-
} else {
29-
const parsedFile = JSON.parse(file);
30-
console.log(parsedFile);
45+
for (const file of themeFiles) {
46+
const filePath = path.join(themesPath, file);
47+
48+
try {
49+
const fileContents = fs.readFileSync(filePath, { encoding: "utf-8" });
50+
const parsedContents = JSON.parse(fileContents) as Theme;
51+
const theme = new ThemeManager(parsedContents);
52+
if (theme) {
53+
this.availableThemes.push(theme);
3154
}
3255
} catch (err) {
3356
console.error(err);
3457
}
3558
}
3659
}
3760

38-
// public setup() {
39-
// if (fs.existsSync(this.settingsPath)) {
40-
// return;
41-
// }
42-
43-
// try {
44-
// fs.mkdirSync(this.settingsPath);
45-
// fs.copyFileSync("./install/settings.json", this.settingsPath);
46-
// fs.copyFileSync("./install/settings.json", this.settingsPath);
47-
// } catch (err) {
48-
// console.error(err);
49-
// }
50-
// }
61+
private loadDefault() {
62+
this.theme = new ThemeManager(DefaultTheme);
63+
}
5164

52-
// public save(settings: SettingsFile) {}
65+
private loadFromDisk() {
66+
try {
67+
const filePath = path.join(this.settingsPath, "settings.json");
5368

54-
// public loadThemes() {
55-
// const themesPath = path.join(this.settingsPath, "themes");
69+
const file = fs.readFileSync(filePath, "utf8");
5670

57-
// const dir = fs.readdirSync(themesPath);
71+
if (file === "") {
72+
throw new Error("File is empty");
73+
} else {
74+
const parsedFile = JSON.parse(file) as SettingsFile;
5875

59-
// const allJsonFiles = dir.filter((file) => {
60-
// return path.extname(file).toLowerCase() === "json";
61-
// });
76+
this.theme = this.loadTheme(parsedFile.theme) || new ThemeManager(DefaultTheme);
77+
}
78+
} catch (err) {
79+
if (err.code === "ENOENT") {
80+
console.error(err.message);
81+
}
82+
}
83+
}
6284

63-
// const validThemes = allJsonFiles.map((file) => {
64-
// try {
65-
// const fileContents = fs.readFileSync(file, { encoding: "utf-8" });
66-
// const parsedContents = JSON.parse(fileContents);
67-
// return new Theme(parsedContents);
68-
// } catch (err) {
69-
// console.error(err);
70-
// }
71-
// });
72-
// }
85+
private loadTheme(name: string) {
86+
for (const theme of this.availableThemes) {
87+
if (theme.name === name) {
88+
return theme;
89+
}
90+
}
91+
}
7392
}
File renamed without changes.

src/install/themes/dia.theme.json renamed to src/files/themes/dia.theme.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"foreground": "#50fa7b"
2121
},
2222
"program": {
23-
"foreground": "#FFC0CB"
23+
"foreground": "#224466"
2424
},
2525
"subcommand": {
2626
"foreground": "#bd93f9"
File renamed without changes.

src/interfaces.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,7 @@ export interface PaletteOptions {
143143
export interface Settings {
144144
theme: Theme;
145145
}
146+
147+
export interface SettingsFile {
148+
theme: string;
149+
}

src/subcommands/explain/index.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import CliDecorators from "../../CliDecorators";
66
import { KmdrAuthError } from "../../errors";
77
import { GetProgramAstResponse, SaveFeedbackResponse } from "../../interfaces";
88
import Print from "../../Print";
9-
import util from "util";
10-
import chalk from "chalk";
119
import { ClientError } from "graphql-request";
1210

1311
interface ExplainInputQuery {
@@ -27,7 +25,7 @@ export default class Explain extends CLI {
2725

2826
constructor() {
2927
super();
30-
this.decorators = new CliDecorators(this.theme);
28+
this.decorators = new CliDecorators(this.settingsManager.theme);
3129
}
3230

3331
public async init() {

src/subcommands/info/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export default class Info extends CLI {
1111
Print.text(`Version: ${this.PKG_VERSION}`, 4);
1212
Print.text(`Registry Endpoint: ${this.KMDR_ENDPOINT_URI}`, 4);
1313
Print.text(`Settings directory: ${this.KMDR_PATH}`, 4);
14-
Print.text(`Current Theme: ${this.theme.name}`, 4);
14+
Print.text(`Current Theme: ${this.settingsManager.theme.name}`, 4);
1515
Print.text(`Node.js:`);
1616
Print.text(`Version: ${this.NODE_VERSION}`, 4);
1717
Print.text(`Path: ${this.NODE_PATH}`, 4);

src/subcommands/login/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import EventSource from "eventsource";
44
import fs from "fs";
55
import { ClientError } from "graphql-request";
66
import fetch from "node-fetch";
7-
import ora from "ora";
7+
import os from "os";
88
import CLI from "../../cli";
99
import KmdrAuthError from "../../errors/KmdrAuthError";
1010
import { CurrentUserReponse, LoginIdResponse } from "../../interfaces";
@@ -80,7 +80,10 @@ export default class Login extends CLI {
8080
if (!this.kmdrDirectoryExists) {
8181
fs.mkdirSync(this.KMDR_PATH);
8282
}
83-
fs.writeFileSync(this.KMDR_AUTH_FILE, encodedCredentials, { encoding: "ascii", mode: 0o600 });
83+
fs.writeFileSync(this.KMDR_AUTH_FILE, encodedCredentials + +os.EOL, {
84+
encoding: "ascii",
85+
mode: 0o600,
86+
});
8487
} catch (err) {
8588
throw err;
8689
}

src/subcommands/settings/index.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,56 @@
1+
import { prompt } from "enquirer";
12
import CLI from "../../Cli";
3+
import Print from "../../Print";
4+
5+
interface ThemeChoice {
6+
theme: string;
7+
}
28

39
export default class Settings extends CLI {
410
constructor() {
511
super();
612
}
713

814
public async init() {
9-
console.log("init");
15+
try {
16+
const theme = await this.promptThemeChoice();
17+
this.settingsManager.saveToDisk({ theme });
18+
} catch (err) {
19+
Print.error("An error occurred");
20+
Print.newLine();
21+
}
22+
}
23+
24+
private async promptThemeChoice() {
25+
const availableThemeChoices = [];
26+
27+
for (const theme of this.settingsManager.availableThemes) {
28+
if (theme.name === this.settingsManager.theme.name) {
29+
console.log("See");
30+
availableThemeChoices.push({
31+
message: `${theme.name} (${theme.mode} mode)`,
32+
value: theme.name,
33+
hint: "Current Theme",
34+
});
35+
} else {
36+
availableThemeChoices.push({
37+
message: `${theme.name} (${theme.mode} mode)`,
38+
value: theme.name,
39+
});
40+
}
41+
}
42+
43+
const themeChoices = {
44+
choices: [...availableThemeChoices],
45+
message: "Choose a theme",
46+
name: "theme",
47+
type: "select",
48+
};
49+
try {
50+
const choice = await prompt<ThemeChoice>(themeChoices);
51+
return choice.theme;
52+
} catch (err) {
53+
throw err;
54+
}
1055
}
1156
}

0 commit comments

Comments
 (0)