mdsaad-cli
Version:
🚀 A powerful CLI toolkit with 20+ commands: AI chat, weather, math calculations, ASCII art, currency conversion, and more - all without API keys required!
603 lines (519 loc) • 16.8 kB
JavaScript
/**
* Show Command
* Comprehensive ASCII art display system with animations, colors, and search functionality
*/
const chalk = require('chalk');
const readline = require('readline');
const asciiArtDb = require('../services/ascii-art-db');
const animationService = require('../services/ascii-animation');
const i18n = require('../services/i18n');
const loggerService = require('../services/logger');
class ShowCommand {
constructor() {
this.colorSchemes = {
default: 'white',
rainbow: ['red', 'yellow', 'green', 'cyan', 'blue', 'magenta'],
fire: ['red', 'brightRed', 'yellow', 'brightYellow'],
ocean: ['blue', 'brightBlue', 'cyan', 'brightCyan'],
forest: ['green', 'brightGreen', 'yellow', 'brightYellow'],
sunset: ['red', 'yellow', 'magenta', 'brightYellow'],
monochrome: ['white', 'gray', 'brightWhite', 'dim'],
};
this.animations = {
typewriter: 'Typewriter effect (character by character)',
fadein: 'Fade in effect (gradual appearance)',
slidein: 'Slide in from specified direction',
matrix: 'Matrix digital rain effect',
pulse: 'Pulsing color effect',
wave: 'Wavy movement effect',
};
}
/**
* Execute show command with comprehensive art display system
*/
async execute(artName, options = {}) {
try {
// Initialize ASCII art database
if (!asciiArtDb.isInitialized()) {
console.log(chalk.yellow('🎨 Initializing ASCII art database...'));
await asciiArtDb.initialize();
}
// Handle special commands
if (await this.handleSpecialCommands(artName, options)) {
return;
}
// Search and display art
await this.displayArt(artName, options);
} catch (error) {
this.handleError(error);
}
}
/**
* Handle special commands (list, search, random, etc.)
*/
async handleSpecialCommands(artName, options) {
const command = artName?.toLowerCase();
switch (command) {
case 'help':
case '?':
this.showHelp();
return true;
case 'list':
await this.listArt(options.category);
return true;
case 'categories':
case 'cats':
this.showCategories();
return true;
case 'search':
if (options.query) {
await this.searchArt(options.query, options);
} else {
console.log(
chalk.red('❌ Please specify search query: --query "search term"')
);
}
return true;
case 'random':
await this.showRandomArt(options);
return true;
case 'popular':
await this.showPopularArt(options);
return true;
case 'stats':
case 'statistics':
this.showStatistics();
return true;
case 'colors':
this.showColorSchemes();
return true;
case 'animations':
this.showAnimations();
return true;
default:
return false;
}
}
/**
* Display ASCII art with specified options
*/
async displayArt(artName, options) {
// Search for the art
const searchResults = asciiArtDb.searchArt(artName, {
category: options.category,
limit: 1,
fuzzy: true,
});
if (searchResults.length === 0) {
console.log(chalk.red(`❌ ASCII art "${artName}" not found`));
console.log(chalk.gray('Use "mdsaad show list" to see available art'));
console.log(
chalk.gray('Use "mdsaad show search --query <term>" to search')
);
return;
}
const result = searchResults[0];
const art = result.artData;
console.log(
chalk.cyan(`🎨 Displaying: ${chalk.white(art.name)} (${art.category})`)
);
if (result.description) {
console.log(chalk.gray(`📝 ${result.description}`));
}
console.log();
// Adjust art for terminal width if needed
let content = art.content;
if (options.width) {
content = this.adjustWidth(content, parseInt(options.width));
}
// Apply display options
const displayOptions = {
color: options.color || this.colorSchemes.default,
animated: options.animated,
animation: options.animation || 'typewriter',
speed: parseInt(options.speed) || 100,
colorScheme: options.colorScheme || 'default',
};
// Display art
await this.renderArt(content, displayOptions);
// Show art metadata
console.log();
this.showArtMetadata(art, result);
}
/**
* Render ASCII art with animations and colors
*/
async renderArt(content, options) {
const { animated, animation, color, colorScheme, speed } = options;
// Prepare color scheme
let colors;
if (colorScheme && this.colorSchemes[colorScheme]) {
colors = Array.isArray(this.colorSchemes[colorScheme])
? this.colorSchemes[colorScheme]
: [this.colorSchemes[colorScheme]];
} else {
colors = [color];
}
if (animated && animation) {
// Handle animations
switch (animation.toLowerCase()) {
case 'typewriter':
await animationService.animateTypewriter(content, {
speed: speed,
color: colors[0],
});
break;
case 'fadein':
await animationService.animateFadeIn(content, {
speed: speed * 2,
color: colors[0],
});
break;
case 'slidein':
await animationService.animateSlideIn(content, {
direction: options.direction || 'right',
speed: speed,
color: colors[0],
});
break;
case 'matrix':
await animationService.animateMatrixRain(content, {
duration: 3000,
speed: speed,
color: 'green',
});
break;
case 'pulse':
await animationService.animatePulse(content, {
cycles: 3,
speed: speed * 3,
colors: colors,
});
break;
case 'wave':
await animationService.animateWave(content, {
cycles: 2,
speed: speed,
color: colors[0],
});
break;
default:
animationService.displayStatic(content, { color: colors[0] });
}
} else {
// Static display with color scheme
if (colors.length > 1) {
await this.displayWithColorScheme(content, colors);
} else {
animationService.displayStatic(content, { color: colors[0] });
}
}
}
/**
* Display art with multi-color scheme
*/
async displayWithColorScheme(content, colors) {
const lines = content.split('\n');
lines.forEach((line, index) => {
const colorIndex = index % colors.length;
const color = colors[colorIndex];
process.stdout.write(chalk[color](line) + '\n');
});
}
/**
* List available ASCII art
*/
async listArt(category = null) {
console.log(chalk.yellow('🎨 Available ASCII Art'));
console.log();
if (category) {
const art = asciiArtDb.getCategory(category);
if (art.length === 0) {
console.log(chalk.red(`❌ Category "${category}" not found or empty`));
return;
}
console.log(
chalk.cyan(`📂 ${category.toUpperCase()}: (${art.length} items)`)
);
art.forEach(item => {
console.log(
` ${chalk.white(item.name)} - ${chalk.gray(item.lines)} lines, ${chalk.gray(item.width)} chars wide`
);
});
} else {
const categories = asciiArtDb.getCategories();
for (const cat of categories) {
const art = asciiArtDb.getCategory(cat);
console.log(
chalk.cyan(`📂 ${cat.toUpperCase()}: (${art.length} items)`)
);
art.forEach(item => {
console.log(
` ${chalk.white(item.name)} - ${chalk.gray(item.lines)} lines, ${chalk.gray(item.width)} chars wide`
);
});
console.log();
}
}
}
/**
* Show available categories
*/
showCategories() {
console.log(chalk.yellow('📂 Available Categories'));
console.log();
const categories = asciiArtDb.getCategories();
categories.forEach(category => {
const art = asciiArtDb.getCategory(category);
console.log(
`${chalk.cyan(category)} - ${chalk.white(art.length)} artworks`
);
});
console.log();
console.log(
chalk.gray(
'Use "mdsaad show list --category <name>" to list art in a category'
)
);
}
/**
* Search for ASCII art
*/
async searchArt(query, options = {}) {
console.log(chalk.yellow(`🔍 Searching for: "${query}"`));
console.log();
const results = asciiArtDb.searchArt(query, {
category: options.category,
limit: options.limit || 10,
fuzzy: true,
});
if (results.length === 0) {
console.log(chalk.red('❌ No matching ASCII art found'));
console.log(
chalk.gray(
'Try different search terms or browse categories with "mdsaad show categories"'
)
);
return;
}
console.log(chalk.green(`✅ Found ${results.length} result(s):`));
console.log();
results.forEach((result, index) => {
const { name, category, description, score } = result;
console.log(
`${chalk.white(`${index + 1}.`)} ${chalk.cyan(name)} (${chalk.gray(category)})`
);
console.log(` ${chalk.gray(description)}`);
console.log(` ${chalk.gray('Match score:')} ${chalk.white(score)}`);
console.log();
});
console.log(
chalk.gray('Use "mdsaad show <name>" to display any of these artworks')
);
}
/**
* Show random ASCII art
*/
async showRandomArt(options) {
console.log(chalk.yellow('🎲 Random ASCII Art'));
console.log();
const art = asciiArtDb.getRandomArt(options.category);
if (!art) {
console.log(chalk.red('❌ No art available'));
return;
}
// Display the random art
await this.displayArt(art.name, options);
}
/**
* Show popular ASCII art
*/
async showPopularArt(options) {
console.log(chalk.yellow('⭐ Popular ASCII Art'));
console.log();
const popularArt = asciiArtDb.getPopularArt(
options.limit || 5,
options.category
);
if (popularArt.length === 0) {
console.log(chalk.red('❌ No popular art available'));
return;
}
popularArt.forEach((item, index) => {
console.log(
`${chalk.white(`${index + 1}.`)} ${chalk.cyan(item.name)} (${chalk.gray(item.category)})`
);
console.log(` ${chalk.gray(item.description)}`);
console.log(
` ${chalk.gray('Popularity:')} ${chalk.white(item.popularity)}/100`
);
console.log();
});
console.log(
chalk.gray('Use "mdsaad show <name>" to display any of these artworks')
);
}
/**
* Show ASCII art database statistics
*/
showStatistics() {
console.log(chalk.yellow('📊 ASCII Art Database Statistics'));
console.log();
const stats = asciiArtDb.getStatistics();
console.log(
`${chalk.cyan('Total Artworks:')} ${chalk.white(stats.totalArt)}`
);
console.log(
`${chalk.cyan('Categories:')} ${chalk.white(stats.categories)}`
);
console.log(
`${chalk.cyan('Average Size:')} ${chalk.white(stats.averageSize)} characters`
);
console.log();
console.log(chalk.cyan('Category Breakdown:'));
Object.entries(stats.categoryBreakdown).forEach(([category, count]) => {
console.log(` ${chalk.white(category)}: ${chalk.gray(count)} artworks`);
});
console.log();
if (stats.largestArt) {
console.log(
`${chalk.cyan('Largest Artwork:')} ${chalk.white(stats.largestArt.name)} (${stats.largestArt.size} chars)`
);
}
if (stats.smallestArt) {
console.log(
`${chalk.cyan('Smallest Artwork:')} ${chalk.white(stats.smallestArt.name)} (${stats.smallestArt.size} chars)`
);
}
}
/**
* Show available color schemes
*/
showColorSchemes() {
console.log(chalk.yellow('🎨 Available Color Schemes'));
console.log();
Object.entries(this.colorSchemes).forEach(([name, colors]) => {
const colorList = Array.isArray(colors) ? colors.join(', ') : colors;
console.log(`${chalk.cyan(name)}: ${chalk.gray(colorList)}`);
});
console.log();
console.log(
chalk.gray('Use --color-scheme <name> to apply a color scheme')
);
}
/**
* Show available animations
*/
showAnimations() {
console.log(chalk.yellow('🎬 Available Animations'));
console.log();
Object.entries(this.animations).forEach(([name, description]) => {
console.log(`${chalk.cyan(name)}: ${chalk.gray(description)}`);
});
console.log();
console.log(
chalk.gray('Use --animated --animation <name> to apply an animation')
);
}
/**
* Show art metadata
*/
showArtMetadata(art, metadata) {
console.log(chalk.gray('─'.repeat(60)));
console.log(
chalk.gray(
`📏 Size: ${art.lines} lines × ${art.width} chars (${art.size} total)`
)
);
if (metadata.tags && metadata.tags.length > 0) {
console.log(chalk.gray(`🏷️ Tags: ${metadata.tags.join(', ')}`));
}
if (metadata.difficulty) {
console.log(chalk.gray(`⭐ Complexity: ${metadata.difficulty}/10`));
}
console.log(chalk.gray(`📁 Category: ${art.category}`));
}
/**
* Adjust ASCII art width to fit terminal
*/
adjustWidth(content, maxWidth) {
const lines = content.split('\n');
return lines
.map(line => {
if (line.length <= maxWidth) {
return line;
}
return line.substring(0, maxWidth - 3) + '...';
})
.join('\n');
}
/**
* Show comprehensive help
*/
showHelp() {
console.log(chalk.yellow('🎨 ASCII Art Display System Help'));
console.log();
console.log(chalk.cyan('Basic Usage:'));
console.log(' mdsaad show <artname> → Display ASCII art');
console.log(
' mdsaad show batman → Show Batman ASCII art'
);
console.log(
' mdsaad show superman --animated → Animated Superman art'
);
console.log();
console.log(chalk.cyan('Art Management:'));
console.log(
' mdsaad show list → List all available art'
);
console.log(' mdsaad show list --category logos → List art in category');
console.log(' mdsaad show categories → Show all categories');
console.log(' mdsaad show search --query hero → Search for art');
console.log(' mdsaad show random → Display random art');
console.log(' mdsaad show popular → Show popular art');
console.log();
console.log(chalk.cyan('Display Options:'));
console.log(' -a, --animated → Enable animations');
console.log(
' --animation <type> → Animation type (typewriter, fadein, etc.)'
);
console.log(' -c, --color <color> → Set text color');
console.log(' --color-scheme <scheme> → Apply color scheme');
console.log(
' -w, --width <number> → Maximum display width'
);
console.log(
' --speed <ms> → Animation speed (milliseconds)'
);
console.log();
console.log(chalk.cyan('Information:'));
console.log(
' mdsaad show stats → Show database statistics'
);
console.log(' mdsaad show colors → List color schemes');
console.log(' mdsaad show animations → List animation types');
console.log();
console.log(chalk.cyan('Examples:'));
console.log(' mdsaad show batman --animated --animation typewriter');
console.log(' mdsaad show mdsaad --color-scheme rainbow');
console.log(' mdsaad show cat --animated --animation wave --speed 50');
console.log(' mdsaad show search --query "super" --category superheroes');
}
/**
* Handle errors with user-friendly messages
*/
handleError(error) {
console.log(chalk.red('❌ ASCII art display failed:'), error.message);
if (error.message.includes('not initialized')) {
console.log(
chalk.yellow('💡 Try restarting the command or check file permissions')
);
} else if (error.message.includes('not found')) {
console.log(
chalk.yellow('💡 Use "mdsaad show list" to see available art')
);
}
console.log(chalk.gray('Use "mdsaad show help" for usage information'));
}
}
module.exports = new ShowCommand();