Skip to content

Commit

Permalink
refactoring an bug fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
dgtlntv committed Jul 9, 2024
1 parent 65d1c08 commit 72d21c2
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 51 deletions.
68 changes: 49 additions & 19 deletions src/commands.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,33 @@
"commands": {
"hello": {
"description": "Prints a greeting",
"action": "Hello, world!\nWelcome to the terminal!",
"color": "green",
"flags": {
"--name": {
"description": "Specify a name for a personalized greeting",
"requiresValue": true,
"aliases": ["-n"]
"type": "string",
"aliases": ["-n"],
"required": true
},
"--uppercase": {
"description": "Print the greeting in uppercase",
"type": "boolean",
"aliases": ["-u"]
}
},
"action": [
{
"if": "flags['--name']",
"then": "Hello, {{flags['--name']}}!\nWelcome to the terminal!",
"else": "Hello, world!\nWelcome to the terminal!"
"then": "Hello, {{flags['--name']}}{{flags['--uppercase'] ? '!' : '.'}}",
"else": "Hello, world{{flags['--uppercase'] ? '!' : '.'}}"
},
{
"if": "flags['--uppercase']",
"then": {
"text": "WELCOME TO THE TERMINAL!",
"color": "green"
},
"else": "Welcome to the terminal."
}
]
},
Expand All @@ -28,12 +41,18 @@
"subcommands": {
"commit": {
"description": "Record changes to the repository",
"action": "Changes committed successfully.",
"action": [
{
"if": "flags['--message']",
"then": "Changes commited successfully: {{flags['--message']}}.",
"else": "Changes commited successfully."
}
],
"flags": {
"--message": {
"description": "Commit message",
"requiresValue": true,
"aliases": ["-m"]
"aliases": ["-m"],
"type": "string"
}
}
},
Expand Down Expand Up @@ -73,7 +92,9 @@
"flags": {
"--environment": {
"description": "Deployment environment",
"requiresValue": true
"required": true,
"type": "string",
"aliases": ["-e"]
}
},
"action": [
Expand All @@ -91,20 +112,29 @@
},
"status": {
"description": "Show system status",
"action": {
"data": {
"cpu": "25%",
"memory": "4GB",
"disk": "120GB"
},
"format": "table"
}
"action": [
"You have the following system status:",
{
"data": [
["cpu", "memory", "disk"],
["25%", "4GB", "120GB"],
["25%", "4GB", "120GB"],
["25%", "4GB", "120GB"],
["25%", "412312312GB", "120GB"]
],
"format": "table"
}
]
},
"setup": {
"description": "Set up the development environment",
"action": [
"Installing dependencies...",
{ "command": "echo", "args": ["Dependencies installed."] },
{
"type": "spinner",
"text": "Installing dependencies...",
"duration": 5000
},
"Dependencies installed.",
{
"text": "Configuring settings...",
"delay": 1000
Expand Down
78 changes: 57 additions & 21 deletions src/commands/customCommands.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { interpolate } from "../utils/interpolation.js"
import { writeColoredText } from "../utils/writeToTerminal/writeColoredText.js"
import writeTable from "../utils/writeToTerminal/writeTable.js"
import { showProgressBar } from "../components/ProgressBar.js"
import { showSpinner } from "../components/Spinner.js"
import { handleUserPrompts } from "../components/Prompt.js"
Expand All @@ -22,29 +23,40 @@ export async function executeCustomCommand(term, command, args) {
return
}

const { flags, positionalArgs } = parseArgs(args, cmd)
const { flags, positionalArgs, errors } = parseArgs(args, cmd)

if (flags["--help"] || flags["-h"]) {
showCommandHelp(term, command)
return
}

if (errors.length > 0) {
errors.forEach((error) => term.writeln(`\x1b[31m${error}\x1b[0m`))
term.writeln(`Type '${command} --help' for usage information.`)
return
}

const context = { flags, args: positionalArgs }

if (cmd.subcommands && positionalArgs.length > 0) {
const subcommand = cmd.subcommands[positionalArgs[0]]
if (subcommand) {
await executeAction(term, subcommand.action, flags, positionalArgs.slice(1))
await executeAction(term, subcommand.action, context)
return
}
}

if (cmd.prompts) {
const promptResults = await handleUserPrompts(term, cmd.prompts)
Object.assign(flags, promptResults)
await executeAction(term, cmd.action, flags, positionalArgs)
Object.assign(context.flags, promptResults)
}

if (cmd.action === undefined) {
showCommandHelp(term, command)
return
}

await executeAction(term, cmd.action, flags, positionalArgs)
await executeAction(term, cmd.action, context)
}

function getCommand(command) {
Expand All @@ -57,32 +69,48 @@ function getCommand(command) {
function parseArgs(args, cmd) {
const flags = {}
const positionalArgs = []
const flagAliases = createFlagAliasMap(cmd.flags)
const flagDefs = {
"--help": { type: "boolean", description: "Show help for this command", aliases: ["-h"] },
...(cmd.flags || {}),
}
const aliasMap = createFlagAliasMap(flagDefs)
const errors = []

for (let i = 0; i < args.length; i++) {
const arg = args[i]
if (arg.startsWith("-")) {
const flagName = flagAliases[arg]
const flagName = aliasMap[arg]
if (flagName) {
const flagDetails = cmd.flags[flagName]
if (flagDetails.requiresValue && i + 1 < args.length) {
flags[flagName] = args[++i]
} else {
const flagDef = flagDefs[flagName]
if (flagDef.type === "boolean") {
flags[flagName] = true
} else if (flagDef.type === "string") {
if (i + 1 < args.length) {
flags[flagName] = args[++i]
} else {
errors.push(`Error: Flag ${arg} expects a value but none was provided.`)
}
}
} else {
errors.push(`Error: Unknown flag ${arg}`)
}
} else {
positionalArgs.push(arg)
}
}

return { flags, positionalArgs }
// Check for required flags
Object.entries(flagDefs).forEach(([flagName, flagDef]) => {
if (flagDef.required && !(flagName in flags)) {
errors.push(`Error: Required flag ${flagName} was not provided.`)
}
})

return { flags, positionalArgs, errors }
}

function createFlagAliasMap(flags) {
const aliasMap = {}
if (!flags) return aliasMap

Object.entries(flags).forEach(([flag, details]) => {
aliasMap[flag] = flag
if (details.aliases) {
Expand All @@ -91,7 +119,6 @@ function createFlagAliasMap(flags) {
})
}
})

return aliasMap
}

Expand Down Expand Up @@ -123,9 +150,7 @@ function showCommandHelp(term, command) {
}
}

async function executeAction(term, action, flags, args) {
const context = { flags, args }

async function executeAction(term, action, context) {
if (Array.isArray(action)) {
for (const item of action) {
await processActionItem(term, item, context)
Expand All @@ -145,11 +170,22 @@ async function processActionItem(term, item, context) {
} else if (typeof item === "object") {
if (item.if) {
const condition = interpolate(item.if, context)
if (eval(condition)) {
await executeAction(term, item.then, context.flags, context.args)
let result
try {
result = new Function("context", `with(context) { return ${condition}; }`)(context)
} catch (error) {
console.error("Error evaluating condition:", error)
result = false
}
if (result) {
await executeAction(term, item.then, context)
} else if (item.else) {
await executeAction(term, item.else, context.flags, context.args)
await executeAction(term, item.else, context)
}
} else if (item.format === "table") {
const data = interpolate(JSON.stringify(item.data), context)
const parsedData = JSON.parse(data)
writeTable(term, parsedData)
} else if (item.type === "progressBar") {
await showProgressBar(term, interpolate(item.text, context), item.duration)
} else if (item.type === "spinner") {
Expand Down
1 change: 0 additions & 1 deletion src/components/Prompt.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export async function handleUserPrompts(term, userPrompts) {
for (const userPrompt of userPrompts) {
results[userPrompt.name] = await getUserInput(term, userPrompt)
}
console.log(results)
return results
}

Expand Down
6 changes: 3 additions & 3 deletions src/utils/keyboard/handleArrowDown.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import writeHistoryCommand from "../writeToTerminal/writeHistoryCommand"
import writeHistoryCommand from "../writeToTerminal/writeHistoryCommand.js"

export default function handleArrowDown(term, historyIndex, commandHistory, prefixLength) {
export default function handleArrowDown(term, historyIndex, commandHistory) {
if (historyIndex > -1) {
historyIndex--
const command = historyIndex >= 0 ? commandHistory[historyIndex] : ""
writeHistoryCommand(term, command, prefixLength)
writeHistoryCommand(term, command)
}
return historyIndex
}
6 changes: 3 additions & 3 deletions src/utils/keyboard/handleArrowUp.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import writeHistoryCommand from "../writeToTerminal/writeHistoryCommand"
import writeHistoryCommand from "../writeToTerminal/writeHistoryCommand.js"

export default function handleArrowUp(term, historyIndex, commandHistory, prefixLength) {
export default function handleArrowUp(term, historyIndex, commandHistory) {
if (historyIndex < commandHistory.length - 1) {
historyIndex++
const command = commandHistory[historyIndex]
writeHistoryCommand(term, command, prefixLength)
writeHistoryCommand(term, command)
}
return historyIndex
}
13 changes: 9 additions & 4 deletions src/utils/writeToTerminal/writeHistoryCommand.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
export default function writeHistoryCommand(term, command, prefixLength) {
import { getCommandLinePrefix } from "../../config/commandLineConfig.js"
import { writeColoredText } from "./writeColoredText.js"

export default function writeHistoryCommand(term, command) {
term.write("\x1b[2K\r")
term.write(" ".repeat(prefixLength))
term.write("\r")
term.write(" ".repeat(prefixLength) + command)
const prefix = getCommandLinePrefix()
prefix.forEach((part) => {
writeColoredText(term, part.text, part.color, true)
})
term.write(command)
}
38 changes: 38 additions & 0 deletions src/utils/writeToTerminal/writeTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export default function writeTable(term, data) {
if (!Array.isArray(data) || data.length === 0) {
term.writeln("No data to display")
return
}

const headers = data[0]
const rows = data.slice(1)

// Calculate column widths
const columnWidths = headers.map((header, index) => {
const maxWidth = Math.max(header.length, ...rows.map((row) => String(row[index]).length))
return maxWidth + 2 // Add padding
})

// Print headers
let headerRow = "│"
headers.forEach((header, index) => {
headerRow += ` ${header.padEnd(columnWidths[index])}│`
})
const separator = "─".repeat(headerRow.length)

term.writeln(separator)
term.writeln(headerRow)
term.writeln(separator)

// Print rows
rows.forEach((row) => {
let rowString = "│"
row.forEach((cell, index) => {
rowString += ` ${String(cell).padEnd(columnWidths[index])}│`
})
term.writeln(rowString)
})

term.writeln(separator)
term.write("\r\n")
}

0 comments on commit 72d21c2

Please sign in to comment.