Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto suggest environment variables using l2 --env <path> command #10

Merged
merged 9 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "Lama2",
"displayName": "Lama2",
"description": "Nifty VSCode UI for Lama2, the plain-text powered API client",
"version": "2.3.0",
"version": "2.6.0",
"publisher": "Hexmos",
"license": "SEE LICENSE IN LICENSE",
"icon": "lama2.png",
Expand Down
16 changes: 11 additions & 5 deletions src/executeCurrentFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,17 @@ class ExecuteCurrentFile {
let windowsBasePath = "C:\\ProgramData\\.lama2"
let randomNameBase = this.generateRandomName(8)
let currentFilePath = vscode.window.activeTextEditor?.document.fileName

if (process.platform === "win32") {
if (!fs.existsSync(windowsBasePath)) {
fs.mkdirSync(windowsBasePath)
}
randomNameFlag = `${windowsBasePath}\\${randomNameBase}.flag`
randomNameFile = `${windowsBasePath}\\${randomNameBase}.json`
cmd = `powershell l2 -o ${randomNameFile} ${currentFilePath}; New-Item -Path ${randomNameFlag}`
}else {
randomNameFlag = `/tmp/${randomNameBase}.flag`
randomNameFile = `/tmp/${randomNameBase}.json`
} else {
randomNameFlag = `/tmp/${randomNameBase}.flag`
randomNameFile = `/tmp/${randomNameBase}.json`
cmd = `l2 -o ${randomNameFile} ${currentFilePath}; touch ${randomNameFlag}`
}
return {
Expand Down Expand Up @@ -257,4 +257,10 @@ class ExecuteCurrentFile {

}

export default ExecuteCurrentFile
export function execCurL2File(context: vscode.ExtensionContext) {
let executeCurrentFile = new ExecuteCurrentFile(context);
return vscode.commands.registerCommand("lama2.ExecuteCurrentFile", () =>
executeCurrentFile.execFile()
);
}

279 changes: 24 additions & 255 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,279 +1,48 @@
import * as vscode from "vscode";
import * as fs from "fs";
import * as path from "path";
import ExecuteCurrentFile from "./executeCurrentFile";
import GenerateCodeSnippet from "./generateCodeSnippet";
import GetRemoteURL from "./getRemoteUrl";
import LanguagesData from "./languages";
import { exec } from 'child_process';
import triggers from "./triggers";

let examplesJSONStr =
'{"0006_cookies.l2":"POST \\nhttps://httpbin.org/post\\n\\n# HEADERS\\nCookie:\\"sessionid=foo;another-cookie=bar\\"\\n\\nHeader1:value1\\nHeader2: Value2\\n\\n# DATA\\nhello=world","0002_sample_post.l2":"POST\\nhttps://httpbin.org/post\\n\\n{\\n \\"a\\": \\"b\\",\\n \\"c\\": \\"d\\"\\n}","0005_headers_simple.l2":"POST \\nhttps://httpbin.org/post\\n\\n# HEADERS\\nX-Parse-Application-Id:\'helloworld\'\\nX-Parse-REST-API-Key:\\"byeworld\\"\\n\\n# DATA\\na=\\"b\\" # double-quoted string\\n\'c\'=d # single-quoted & unquoted strings","0008_base64_image":{"0008_base64_image.l2":"POST\\nhttp://httpbin.org/post\\n\\n{\\n\\t\\"imageb64_field\\": \\"\'${PHOTO}\'\\",\\n}","l2.env":"\\nexport PHOTO=`base64 image.jpeg`"},"0001_sample_post_varjson.l2":"POST\\nhttps://httpbin.org/post\\n\\na=b\\nc=d","0007_multipart_file":{"0007_multipart_file.l2":"POST\\nMULTIPART\\nhttp://httpbin.org/post\\n\\n\'X-Parse-Application-Id\':helloworld \\nX-Parse-REST-API-Key:\\"helloworld\\"\\n\\n# DATA\\nfirst=second\\n\\n# FILES\\nmyfile@./image.jpeg"},"0004_env_switch_root":{"0004_env_switch_root.l2":"POST\\n${REMOTE}/post\\n\\n{\\n \\"lorem\\": \\"ipsum\\"\\n}","l2.env":"export LOCAL=\\"http://localhost:8000\\"\\nexport REMOTE=\\"http://httpbin.org\\""},"0003_comment.l2":"# Pound symbol signifies a comment\\nPOST\\nhttps://httpbin.org/post\\n\\na=b # Comments may start at the end of lines as well\\nc=d\\n\\n# Comments work even after the payload","0000_sample_get.l2":"GET\\nhttps://httpbin.org/get","0009_processor_basic":{"0009_processor_basic.l2":"url = \\"http://google.com\\"\\n---\\n# stage 1\\n\\nPOST\\n${REMOTE_COORD}/anything\\n\\n{\\n \\"username\\": \\"admin\\",\\n \\"password\\": \\"Password@123\\",\\n \\"from\\": \\"${LOCAL_COORD}/anything\\",\\n \\"url\\": \\"${url}\\",\\n \\"Token\\": \\"MySuperSecretToken\\"\\n}\\n\\n---\\n\\n// filtering, store in var\\nconsole.log(\\"@@Result\\", result)\\nlet TOKEN = result[\\"json\\"][\\"Token\\"]\\nconsole.log(TOKEN)\\n\\n---\\n\\n# stage 2\\nGET\\n${REMOTE_COORD}/bearer\\n\\nAuthorization: \'Bearer ${TOKEN}\'\\n\\n{}","l2.env":"\\nexport LOCAL_COORD=\\"http://localhost:8080\\"\\nexport REMOTE_COORD=\\"http://httpbin.org\\""}}';
let examplesJSON = JSON.parse(examplesJSONStr);
let specificExGlobal = "";
let subSpecificExGlobal = "";

interface LanguageData {
info: {
key: string;
title: string;
extname: string;
default: string;
};
clientsById: Record<string, null>;
}

interface LanguagesData {
[key: string]: LanguageData;
}
import { genCodeSnip } from "./generateCodeSnippet";
import { getRemoteUrl } from "./getRemoteUrl";
import { replaceTextAfterEnvSelected, suggestENVs } from "./suggestEnvironmentVars";
import { genLama2Examples } from "./genLama2Examples";
import { execCurL2File } from "./executeCurrentFile";
import { prettifyL2File } from "./prettifyL2File";

export function activate(context: vscode.ExtensionContext) {
console.log('>>> Congratulations, your extension "Lama2" is now active!');

// Level1 command pallette
let getremoteUrl = new GetRemoteURL(context);
let getremoteUrlFileDisposable = vscode.commands.registerCommand(
"lama2.GetRemoteURL",
() => getremoteUrl.findURL()
);
context.subscriptions.push(getremoteUrlFileDisposable);

// Level1 command pallette
let executeCurrentFile = new ExecuteCurrentFile(context);

let executeCurrentFileDisposable = vscode.commands.registerCommand(
"lama2.ExecuteCurrentFile",
() => executeCurrentFile.execFile()
);

let executeCurrentFileDisposable = execCurL2File(context);
context.subscriptions.push(executeCurrentFileDisposable);
console.log(">>> executeCurrentFileDisposable is now active!");

// Level1 command pallette
let getremoteUrlFileDisposable = getRemoteUrl(context);
context.subscriptions.push(getremoteUrlFileDisposable);
console.log(">>> getremoteUrlFileDisposable is now active!");

let prettifyCurrentFileDisposable = vscode.commands.registerCommand(
"lama2.PrettifyCurrentFile",
() => {
console.log("Executing prettify command");
exec(`l2 -b ${vscode.window.activeTextEditor?.document.fileName}`);
}
);
// Level1 command pallette
let prettifyCurrentFileDisposable = prettifyL2File();
context.subscriptions.push(prettifyCurrentFileDisposable);

let generateCodeSnippet = new GenerateCodeSnippet();
let lama2Examples = vscode.commands.registerCommand(
"lama2.Lama2Examples",
async () => {
let specificEx: string | undefined = await vscode.window.showQuickPick(
Object.keys(examplesJSON)
);

if (specificEx) {
specificExGlobal = specificEx;
if (specificEx.endsWith(".env") || specificEx.endsWith(".l2")) {
vscode.window.activeTextEditor?.edit((builder) => {
const doc = vscode.window.activeTextEditor?.document;
builder.replace(
new vscode.Range(
doc!.lineAt(0).range.start,
doc!.lineAt(doc!.lineCount - 1).range.end
),
examplesJSON[specificExGlobal]
);
});
return;
}

let subSpecificEx: string | undefined =
await vscode.window.showQuickPick(
Object.keys(examplesJSON[specificEx])
);

if (subSpecificEx) {
subSpecificExGlobal = subSpecificEx;
vscode.window.activeTextEditor?.edit((builder) => {
const doc = vscode.window.activeTextEditor?.document;
builder.replace(
new vscode.Range(
doc!.lineAt(0).range.start,
doc!.lineAt(doc!.lineCount - 1).range.end
),
examplesJSON[specificExGlobal][subSpecificExGlobal]
);
});
return;
}
}
}
);
console.log(">>> prettifyCurrentFileDisposable is now active!");

// Level1 command pallette
let generateCodeSnippetDisposable = vscode.commands.registerCommand(
"lama2.GenerateCodeSnippet",
async () => {
const langkwys = Object.keys(LanguagesData);
let languageOptions: { [key: string]: string } = {};
for (let i = 0; i < langkwys.length; i++) {
const key = langkwys[i] as keyof typeof LanguagesData;
const languageData = LanguagesData[key];
languageOptions[languageData.info.title] = languageData.info.key;
}
let lama2Examples = genLama2Examples();
console.log(">>> lama2Examples is now active!");

const languageKeys = Object.keys(LanguagesData);

// Level2 command pallette
let language: string | undefined = await vscode.window.showQuickPick(
Object.keys(languageOptions)
);

if (language) {
language = languageOptions[language];
const languageKey = languageKeys.find(
(key) =>
LanguagesData[key as keyof typeof LanguagesData].info.key ===
language
)!;

const clientsById =
LanguagesData[languageKey as keyof typeof LanguagesData].clientsById;
const defaultClient =
LanguagesData[languageKey as keyof typeof LanguagesData].info.default;

const clientKeys = Object.keys(clientsById);

if (clientKeys.length === 1) {
const client = clientKeys[0];
generateCodeSnippet.execFile(language, client);
} else {
// Level3 command pallette
const selection:
| {
label: string;
language: string;
client: string;
}
| undefined = await vscode.window.showQuickPick(
clientKeys
.sort((a, b) =>
a === defaultClient ? -1 : b === defaultClient ? 1 : 0
)
.map((client) => ({
label: `${language ?? ""}: ${client} ${isDefault(
defaultClient,
client
)}`,
language: language ?? "",
client: client,
})),
{ placeHolder: "Select a client" }
);

if (selection) {
generateCodeSnippet.execFile(selection.language, selection.client);
}
}
}
}
);
// Level1 command pallette
let generateCodeSnippetDisposable = genCodeSnip();
context.subscriptions.push(generateCodeSnippetDisposable);
console.log(">>> generateCodeSnippetDisposable is now active!");

let envVariables = [] as string[];
const activeTextEditor = vscode.window.activeTextEditor;
if (activeTextEditor) {
const activeFilePath = activeTextEditor.document.uri.fsPath;
const envFilePath = path.join(path.dirname(activeFilePath), "l2.env");
fs.readFile(envFilePath, "utf8", (err, data) => {
if (err) {
console.error(err);
return;
}

envVariables = data
.split("\n")
.filter((line) => line.startsWith("export"))
.map((line) => line.split("=")[0].replace("export ", ""));
console.log("envVariables -> ", envVariables);
});
}
let cursorPosition: any;
let linePosition: any;



let suggestEnvVariables = vscode.languages.registerCompletionItemProvider(
{ language: "lama2", scheme: "file" },
{
// eslint-disable-next-line no-unused-vars
provideCompletionItems(document, position, token, context) {
// get all text until the `position` and check if it reads `${`

const linePrefix = document
.lineAt(position)
.text.substring(0, position.character);
if (!linePrefix.endsWith("${")) {
return undefined;
}
let createSuggestion = (text: string) => {
let item = new vscode.CompletionItem(
text,
vscode.CompletionItemKind.Text
);
item.range = new vscode.Range(position, position);
item.command = {
title: "",
command: "options",
};
return item;
};
const suggestionsArray = envVariables.map((item, index) => {
return createSuggestion(item);
});

return suggestionsArray;
},
...triggers, // trigger
resolveCompletionItem(
item: vscode.CompletionItem,
token: vscode.CancellationToken
) {
const editor = vscode.window.activeTextEditor;
if (editor) {
const position = editor.selection.active;
cursorPosition = position.character;
linePosition = position.line;
}
return item;
},
}
);
let suggestEnvVariables = suggestENVs();
context.subscriptions.push(
suggestEnvVariables,
vscode.commands.registerCommand("options", () => {
const editor = vscode.window.activeTextEditor;
if (editor) {
const position = editor.selection.active;
const bracketPosition = editor.document
.lineAt(position.line)
.text.indexOf("{");
const start = new vscode.Position(linePosition, bracketPosition + 1); // start position
const end = new vscode.Position(linePosition, cursorPosition); // end position
const range = new vscode.Range(start, end); // create range object
const replaceText = "";
const edit = new vscode.WorkspaceEdit();
edit.replace(editor.document.uri, range, replaceText);
vscode.workspace.applyEdit(edit);
}
vscode.commands.registerCommand("envoptions", () => {
// This method is activated when the user selects a suggested env variable.
replaceTextAfterEnvSelected();
})
);
}

// this method is called when your extension is deactivated
export function deactivate() {}

function isDefault(defaultClient: string, client: string) {
if (defaultClient == client) {
return "(Default)";
} else {
return "";
}
}
export function deactivate() { }
Loading