Files
michaelschiemer/src/Framework/Console/CommandHistory.php
Michael Schiemer 5050c7d73a docs: consolidate documentation into organized structure
- Move 12 markdown files from root to docs/ subdirectories
- Organize documentation by category:
  • docs/troubleshooting/ (1 file)  - Technical troubleshooting guides
  • docs/deployment/      (4 files) - Deployment and security documentation
  • docs/guides/          (3 files) - Feature-specific guides
  • docs/planning/        (4 files) - Planning and improvement proposals

Root directory cleanup:
- Reduced from 16 to 4 markdown files in root
- Only essential project files remain:
  • CLAUDE.md (AI instructions)
  • README.md (Main project readme)
  • CLEANUP_PLAN.md (Current cleanup plan)
  • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements)

This improves:
 Documentation discoverability
 Logical organization by purpose
 Clean root directory
 Better maintainability
2025-10-05 11:05:04 +02:00

295 lines
7.6 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\Console;
use App\Framework\Filesystem\FilePath;
/**
* Command history and favorites management for console TUI
*/
final class CommandHistory
{
private array $history = [];
private array $favorites = [];
private int $maxHistorySize;
private FilePath $historyFile;
private FilePath $favoritesFile;
public function __construct(
int $maxHistorySize = 100,
?FilePath $storageDirectory = null
) {
$this->maxHistorySize = $maxHistorySize;
$storageDir = $storageDirectory ?? FilePath::create(sys_get_temp_dir() . '/console-history');
$this->historyFile = $storageDir->join('command_history.json');
$this->favoritesFile = $storageDir->join('command_favorites.json');
$this->loadHistory();
$this->loadFavorites();
}
/**
* Add a command to history
*/
public function addToHistory(string $commandName): void
{
// Remove if already exists to move to top
$this->history = array_filter($this->history, fn ($entry) => $entry['command'] !== $commandName);
// Add to beginning
array_unshift($this->history, [
'command' => $commandName,
'timestamp' => time(),
'count' => $this->getCommandCount($commandName) + 1,
]);
// Limit history size
if (count($this->history) > $this->maxHistorySize) {
$this->history = array_slice($this->history, 0, $this->maxHistorySize);
}
$this->saveHistory();
}
/**
* Add command to favorites
*/
public function addToFavorites(string $commandName): void
{
if (! $this->isFavorite($commandName)) {
$this->favorites[] = [
'command' => $commandName,
'added_at' => time(),
];
$this->saveFavorites();
}
}
/**
* Remove command from favorites
*/
public function removeFromFavorites(string $commandName): void
{
$this->favorites = array_filter(
$this->favorites,
fn ($entry) => $entry['command'] !== $commandName
);
$this->favorites = array_values($this->favorites); // Re-index
$this->saveFavorites();
}
/**
* Toggle favorite status
*/
public function toggleFavorite(string $commandName): bool
{
if ($this->isFavorite($commandName)) {
$this->removeFromFavorites($commandName);
return false;
} else {
$this->addToFavorites($commandName);
return true;
}
}
/**
* Check if command is in favorites
*/
public function isFavorite(string $commandName): bool
{
return array_reduce(
$this->favorites,
fn ($carry, $entry) => $carry || $entry['command'] === $commandName,
false
);
}
/**
* Get recent command history
*/
public function getRecentHistory(int $limit = 10): array
{
return array_slice($this->history, 0, $limit);
}
/**
* Get frequently used commands
*/
public function getFrequentCommands(int $limit = 10): array
{
$commands = $this->history;
// Sort by usage count (descending)
usort($commands, fn ($a, $b) => $b['count'] <=> $a['count']);
return array_slice($commands, 0, $limit);
}
/**
* Get all favorites
*/
public function getFavorites(): array
{
return $this->favorites;
}
/**
* Get command usage statistics
*/
public function getCommandStats(string $commandName): array
{
$entry = array_find($this->history, fn ($entry) => $entry['command'] === $commandName);
if (! $entry) {
return [
'command' => $commandName,
'count' => 0,
'last_used' => null,
'is_favorite' => $this->isFavorite($commandName),
];
}
return [
'command' => $commandName,
'count' => $entry['count'],
'last_used' => $entry['timestamp'],
'is_favorite' => $this->isFavorite($commandName),
];
}
/**
* Clear all history
*/
public function clearHistory(): void
{
$this->history = [];
$this->saveHistory();
}
/**
* Clear all favorites
*/
public function clearFavorites(): void
{
$this->favorites = [];
$this->saveFavorites();
}
/**
* Get suggestions based on partial input
*/
public function getSuggestions(string $partial, int $limit = 5): array
{
$suggestions = [];
// Add matching favorites first
foreach ($this->favorites as $favorite) {
if (str_starts_with($favorite['command'], $partial)) {
$suggestions[] = [
'command' => $favorite['command'],
'type' => 'favorite',
'score' => 1000, // High priority for favorites
];
}
}
// Add matching recent commands
foreach ($this->history as $entry) {
$command = $entry['command'];
if (str_starts_with($command, $partial) && ! $this->isFavorite($command)) {
$suggestions[] = [
'command' => $command,
'type' => 'recent',
'score' => 500 + $entry['count'], // Score based on usage count
];
}
}
// Sort by score (descending) and limit
usort($suggestions, fn ($a, $b) => $b['score'] <=> $a['score']);
return array_slice($suggestions, 0, $limit);
}
/**
* Get command count from history
*/
private function getCommandCount(string $commandName): int
{
$entry = array_find($this->history, fn ($entry) => $entry['command'] === $commandName);
return $entry ? $entry['count'] : 0;
}
/**
* Load history from file
*/
private function loadHistory(): void
{
if ($this->historyFile->exists()) {
$content = file_get_contents($this->historyFile->toString());
$decoded = json_decode($content, true);
if (is_array($decoded)) {
$this->history = $decoded;
}
}
}
/**
* Save history to file
*/
private function saveHistory(): void
{
$this->ensureDirectoryExists($this->historyFile->getDirectory());
file_put_contents(
$this->historyFile->toString(),
json_encode($this->history, JSON_PRETTY_PRINT)
);
}
/**
* Load favorites from file
*/
private function loadFavorites(): void
{
if ($this->favoritesFile->exists()) {
$content = file_get_contents($this->favoritesFile->toString());
$decoded = json_decode($content, true);
if (is_array($decoded)) {
$this->favorites = $decoded;
}
}
}
/**
* Save favorites to file
*/
private function saveFavorites(): void
{
$this->ensureDirectoryExists($this->favoritesFile->getDirectory());
file_put_contents(
$this->favoritesFile->toString(),
json_encode($this->favorites, JSON_PRETTY_PRINT)
);
}
/**
* Ensure storage directory exists
*/
private function ensureDirectoryExists(FilePath $directory): void
{
if (! $directory->exists()) {
mkdir($directory->toString(), 0755, true);
}
}
}