Skip to content

Commit

Permalink
Merge pull request #32 from isfopo:issue/Add-sections
Browse files Browse the repository at this point in the history
Issue/Add-sections
  • Loading branch information
isfopo authored Jul 17, 2024
2 parents 29cfa99 + aa9d73d commit ddabad4
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 41 deletions.
14 changes: 12 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "environments",
"displayName": "Environments",
"publisher": "isfopo",
"description": "Manage your environments from your sidebar.",
"description": "Manage your environments from your sidebar",
"version": "0.0.36",
"icon": "assets/icon.png",
"type": "module",
Expand Down Expand Up @@ -32,6 +32,11 @@
"title": "Refresh",
"icon": "$(refresh)"
},
{
"command": "environments.set-preset",
"title": "Set Preset",
"icon": "$(library)"
},
{
"command": "environments.edit",
"title": "Edit",
Expand Down Expand Up @@ -80,6 +85,11 @@
"when": "viewItem == file",
"group": "inline"
},
{
"command": "environments.set-preset",
"when": "viewItem == group-has-presets",
"group": "inline"
},
{
"command": "environments.rename",
"when": "viewItem == file"
Expand Down Expand Up @@ -149,4 +159,4 @@
"typescript": "^5.5.3",
"vite": "^5.3.3"
}
}
}
26 changes: 16 additions & 10 deletions src/EnvironmentTreeviewProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { parseEnvironmentContent, replace } from "./helpers/parse";
import { EnvironmentWorkspaceFolderTreeItem } from "./classes/TreeItems/EnvironmentWorkspaceFolderTreeItem";
import { EnvironmentKeyValueTreeItem } from "./classes/TreeItems/EnvironmentKeyValueTreeItem";
import { EnvironmentFileTreeItem } from "./classes/TreeItems/EnvironmentFileTreeItem";
import { EnvironmentGroupTreeItem } from "./classes/TreeItems/EnvironmentGroupTreeItem";

export class EnvironmentTreeviewProvider
implements vscode.TreeDataProvider<vscode.TreeItem>
Expand Down Expand Up @@ -36,7 +37,7 @@ export class EnvironmentTreeviewProvider
const selected = e.selection[0];
if (selected instanceof EnvironmentKeyValueTreeItem) {
await vscode.window.showTextDocument(
await vscode.workspace.openTextDocument(selected.parent.uri)
await vscode.workspace.openTextDocument(selected.file)
);
}
});
Expand Down Expand Up @@ -114,17 +115,25 @@ export class EnvironmentTreeviewProvider
this.edit(element, element.value.value === "true" ? "false" : "true");
}

async setPreset(element: EnvironmentGroupTreeItem, preset: string) {
for (const child of element.children) {
if (child.value.presets) {
await this.edit(child, child.value.presets[preset]);
}
}
}

refresh() {
this._onDidChangeTreeData?.fire();
}

async edit(element: EnvironmentKeyValueTreeItem, input: string) {
const content = new TextDecoder().decode(
await vscode.workspace.fs.readFile(element.parent.uri)
await vscode.workspace.fs.readFile(element.file)
);

await vscode.workspace.fs.writeFile(
element.parent.uri,
element.file,
new TextEncoder().encode(replace(content, element.key, input))
);

Expand Down Expand Up @@ -160,13 +169,10 @@ export class EnvironmentTreeviewProvider
}
} else if (element instanceof EnvironmentWorkspaceFolderTreeItem) {
return this.getFileData(element.folder);
} else if (element instanceof EnvironmentGroupTreeItem) {
return element.children;
} else if (element instanceof EnvironmentFileTreeItem) {
return Promise.resolve(
Object.keys(element.content).map(
(key): EnvironmentKeyValueTreeItem =>
new EnvironmentKeyValueTreeItem(key, element.content[key], element)
)
);
return element.children;
}
}

Expand Down Expand Up @@ -194,7 +200,7 @@ export class EnvironmentTreeviewProvider
new EnvironmentFileTreeItem(
path,
fileUris[index],
parseEnvironmentContent(fileContentStrings[index])
parseEnvironmentContent(fileContentStrings[index], fileUris[index])
)
);
}
Expand Down
7 changes: 5 additions & 2 deletions src/classes/TreeItems/EnvironmentFileTreeItem.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import * as vscode from "vscode";
import type { EnvironmentContent } from "../../types";
import { EnvironmentGroupTreeItem } from "./EnvironmentGroupTreeItem";
import { EnvironmentKeyValueTreeItem } from "./EnvironmentKeyValueTreeItem";

export class EnvironmentFileTreeItem extends vscode.TreeItem {
constructor(
public readonly name: string,
public readonly uri: vscode.Uri,
public readonly content: EnvironmentContent,
public readonly children: Array<
EnvironmentGroupTreeItem | EnvironmentKeyValueTreeItem
>,
public readonly collapsibleState: vscode.TreeItemCollapsibleState = vscode
.TreeItemCollapsibleState.Collapsed
) {
Expand Down
22 changes: 22 additions & 0 deletions src/classes/TreeItems/EnvironmentGroupTreeItem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as vscode from "vscode";
import { EnvironmentKeyValueTreeItem } from "./EnvironmentKeyValueTreeItem";

export class EnvironmentGroupTreeItem extends vscode.TreeItem {
constructor(
public readonly name: string,
public readonly presets: string[],
public readonly children: EnvironmentKeyValueTreeItem[] = [],
public readonly collapsibleState: vscode.TreeItemCollapsibleState = vscode
.TreeItemCollapsibleState.Collapsed
) {
super(name, collapsibleState);
this.presets = presets;
this.children = children;

if (presets.length > 0) {
this.contextValue = "group-has-presets";
} else {
this.contextValue = "group";
}
}
}
2 changes: 1 addition & 1 deletion src/classes/TreeItems/EnvironmentKeyValueTreeItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export class EnvironmentKeyValueTreeItem extends vscode.TreeItem {
constructor(
public readonly key: string,
public readonly value: EnvironmentKeyValue,
public readonly parent: EnvironmentFileTreeItem,
public readonly file: vscode.Uri,
public readonly collapsibleState: vscode.TreeItemCollapsibleState = vscode
.TreeItemCollapsibleState.None
) {
Expand Down
20 changes: 20 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { EnvironmentTreeviewProvider } from "./EnvironmentTreeviewProvider";
import { EnvironmentWorkspaceFolderTreeItem } from "./classes/TreeItems/EnvironmentWorkspaceFolderTreeItem";
import { EnvironmentFileTreeItem } from "./classes/TreeItems/EnvironmentFileTreeItem";
import { EnvironmentKeyValueTreeItem } from "./classes/TreeItems/EnvironmentKeyValueTreeItem";
import { EnvironmentGroupTreeItem } from "./classes/TreeItems/EnvironmentGroupTreeItem";

export function activate(context: vscode.ExtensionContext) {
const treeDataProvider = new EnvironmentTreeviewProvider(context).register();
Expand Down Expand Up @@ -39,6 +40,25 @@ export function activate(context: vscode.ExtensionContext) {
}
);

vscode.commands.registerCommand(
"environments.set-preset",
async (element: EnvironmentGroupTreeItem) => {
const preset = await vscode.window.showQuickPick(element.presets, {
placeHolder: "Select a preset",
});

if (!preset) {
return;
}

if (!element.presets.includes(preset)) {
vscode.window.showErrorMessage("Invalid preset");
} else {
await treeDataProvider.setPreset(element, preset);
}
}
);

vscode.commands.registerCommand(
"environments.add",
async (element: EnvironmentFileTreeItem) => {
Expand Down
134 changes: 109 additions & 25 deletions src/helpers/parse.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,84 @@
import * as vscode from "vscode";
import { EnvironmentGroupTreeItem } from "../classes/TreeItems/EnvironmentGroupTreeItem";
import { EnvironmentKeyValueTreeItem } from "../classes/TreeItems/EnvironmentKeyValueTreeItem";
import type { EnvironmentContent, EnvironmentKeyValueType } from "../types";

const LINE =
/(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(#.*)?(?:$|$)/gm;
/(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(#.*)?(?:$|$)|^\s*(\n###.*)$/gm;

export const parseEnvironmentContent = (lines: string): EnvironmentContent => {
const obj: EnvironmentContent = {};
export const parseEnvironmentContent = (
lines: string,
file: vscode.Uri
): EnvironmentContent => {
const items: (EnvironmentKeyValueTreeItem | EnvironmentGroupTreeItem)[] = [];
let currentGroup: EnvironmentGroupTreeItem | null = null;

// Add a new line at start of file to match first line
lines = "\n" + lines;
// Convert line breaks to same format
lines = lines.replace(/\r\n?/gm, "\n");

let match;
while ((match = LINE.exec(lines)) != null) {
const key = match[1];
if (match[4]) {
if (currentGroup && match[4].trim().endsWith("###")) {
// Group end
items.push(currentGroup);
currentGroup = null;
} else {
// Group start
currentGroup = new EnvironmentGroupTreeItem(
parseGroupName(match[4]),
parsePresets(match[4])
);
items.push(currentGroup);
}
} else {
const key = match[1];

// Default undefined or null to empty string
let value = sanitizeValue(match[2] || "");

const keyValueItem = new EnvironmentKeyValueTreeItem(
key,
{
type: inferType(value),
value,
options: parseOptions(match[3]),
presets: parsePresetValues(currentGroup?.presets, match[3]),
},
file
);

// Add to items
if (currentGroup) {
currentGroup.children.push(keyValueItem);
} else {
items.push(keyValueItem);
}
}
}

// Default undefined or null to empty string
let value = match[2] || "";
return items;
};

// Remove whitespace
value = value.trim();
export const sanitizeValue = (value: string): string => {
// Remove whitespace
value = value.trim();

// Check if double quoted
const maybeQuote = value[0];
// Check if double quoted
const maybeQuote = value[0];

// Remove surrounding quotes
value = value.replace(/^(['"`])([\s\S]*)\1$/gm, "$2");
// Remove surrounding quotes
value = value.replace(/^(['"`])([\s\S]*)\1$/gm, "$2");

// Expand newlines if double quoted
if (maybeQuote === '"') {
value = value.replace(/\\n/g, "\n");
value = value.replace(/\\r/g, "\r");
}

// Add to object
obj[key] = {
value,
type: inferType(value),
options: parseOptions(match[3]),
};
// Expand newlines if double quoted
if (maybeQuote === '"') {
value = value.replace(/\\n/g, "\n");
value = value.replace(/\\r/g, "\r");
}

return obj;
return value;
};

export const inferType = (value: string): EnvironmentKeyValueType => {
Expand All @@ -60,5 +99,50 @@ export const parseOptions = (input: string | undefined): string[] => {
return match?.[1].split(",") ?? [];
};

export const parsePresets = (input: string | undefined): string[] => {
// Create a regex that finds the key followed by a colon and captures the value
const regex = new RegExp(`presets:([^\\s]*)`, "i");

// Execute the regex on the input string
const match = input?.match(regex);

return match?.[1].split(",") ?? [];
};

export const parsePresetValues = (
presets: string[] | undefined,
input: string | undefined
): Record<string, string> => {
const result: Record<string, string> = {};

// If no presets, return empty object
if (!presets) {
return result;
}

for (const preset of presets) {
// Create a regex that finds the key followed by a colon and captures the value
const regex = new RegExp(`${preset}:([^\\s]*)`, "i");
// Execute the regex on the input string
const match = input?.match(regex);
if (match) {
result[preset] = sanitizeValue(match[1]);
}
}

return result;
};

export const replace = (content: string, key: string, value: string): string =>
content.replace(new RegExp(`(${key}="?)([^\\s"]*)`, "g"), `$1${value}`);

export const parseGroupName = (input: string): string => {
// Create a regex to capture the group name between ### and presets
const regex = /###\s*(.*?)\s*(?=presets|$)/i;

// Execute the regex on the input string
const match = input.match(regex);

// Return the captured group name or an empty string if not found
return match?.[1].trim() ?? "";
};
6 changes: 5 additions & 1 deletion src/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
export type EnvironmentContent = Record<string, EnvironmentKeyValue>;
export type EnvironmentContent = Record<
string,
EnvironmentContent | EnvironmentKeyValue
>;

export interface EnvironmentKeyValue {
value: string;
type: EnvironmentKeyValueType;
options?: string[];
presets?: Record<string, string>;
}

export type EnvironmentKeyValueType = "string" | "bool";

0 comments on commit ddabad4

Please sign in to comment.