Initial commit to new repository
This commit is contained in:
141
src/AxCopilot/Handlers/RecentFilesHandler.cs
Normal file
141
src/AxCopilot/Handlers/RecentFilesHandler.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
using System.IO;
|
||||
using AxCopilot.SDK;
|
||||
using AxCopilot.Services;
|
||||
using AxCopilot.Themes;
|
||||
|
||||
namespace AxCopilot.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 최근 파일 핸들러. "recent" 프리픽스로 사용합니다.
|
||||
/// Windows Recent 폴더(%APPDATA%\Microsoft\Windows\Recent)의 .lnk 파일을
|
||||
/// 최근 수정 순으로 나열합니다.
|
||||
/// 예: recent → 최근 20개 파일 목록
|
||||
/// recent 보고서 → 이름에 "보고서" 포함 파일 필터
|
||||
/// </summary>
|
||||
public class RecentFilesHandler : IActionHandler
|
||||
{
|
||||
public string? Prefix => "recent";
|
||||
|
||||
public PluginMetadata Metadata => new(
|
||||
"RecentFiles",
|
||||
"최근 파일 — recent 뒤에 검색어 입력",
|
||||
"1.0",
|
||||
"AX");
|
||||
|
||||
private static readonly string RecentFolder = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
@"Microsoft\Windows\Recent");
|
||||
|
||||
// 간단한 캐시: 10초간 유효
|
||||
private static (DateTime At, List<(string Name, string LinkPath, DateTime Modified)> Files)? _cache;
|
||||
private static readonly TimeSpan CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
||||
public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
|
||||
{
|
||||
var q = query.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(q))
|
||||
{
|
||||
// 힌트만 표시
|
||||
}
|
||||
|
||||
var files = GetRecentFiles();
|
||||
IEnumerable<(string Name, string LinkPath, DateTime Modified)> filtered = files;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(q))
|
||||
{
|
||||
filtered = files.Where(f =>
|
||||
f.Name.Contains(q, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
var items = filtered.Take(20).Select(f => new LauncherItem(
|
||||
f.Name,
|
||||
$"{f.Modified:yyyy-MM-dd HH:mm} · Enter로 열기",
|
||||
null,
|
||||
f.LinkPath,
|
||||
Symbol: GetSymbol(f.Name))).ToList();
|
||||
|
||||
if (!items.Any())
|
||||
{
|
||||
items.Add(new LauncherItem(
|
||||
string.IsNullOrWhiteSpace(q) ? "최근 파일 없음" : "검색 결과 없음",
|
||||
string.IsNullOrWhiteSpace(q)
|
||||
? "Windows Recent 폴더가 비어 있습니다"
|
||||
: $"'{q}' 파일을 최근 목록에서 찾을 수 없습니다",
|
||||
null, null, Symbol: Symbols.Info));
|
||||
}
|
||||
|
||||
return Task.FromResult<IEnumerable<LauncherItem>>(items);
|
||||
}
|
||||
|
||||
public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
|
||||
{
|
||||
if (item.Data is string linkPath && File.Exists(linkPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
System.Diagnostics.Process.Start(
|
||||
new System.Diagnostics.ProcessStartInfo(linkPath)
|
||||
{ UseShellExecute = true });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Warn($"최근 파일 열기 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
// ─── 내부 ─────────────────────────────────────────────────────────────────
|
||||
|
||||
private static List<(string Name, string LinkPath, DateTime Modified)> GetRecentFiles()
|
||||
{
|
||||
// 캐시 유효 확인
|
||||
if (_cache.HasValue && (DateTime.Now - _cache.Value.At) < CacheTtl)
|
||||
return _cache.Value.Files;
|
||||
|
||||
var result = new List<(string, string, DateTime)>();
|
||||
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(RecentFolder))
|
||||
return result;
|
||||
|
||||
var lnkFiles = Directory
|
||||
.GetFiles(RecentFolder, "*.lnk")
|
||||
.Select(p => (Path: p, Info: new FileInfo(p)))
|
||||
.OrderByDescending(f => f.Info.LastWriteTime)
|
||||
.Take(100)
|
||||
.ToList();
|
||||
|
||||
foreach (var (path, info) in lnkFiles)
|
||||
{
|
||||
var name = Path.GetFileNameWithoutExtension(info.Name);
|
||||
result.Add((name, path, info.LastWriteTime));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Warn($"최근 파일 목록 읽기 실패: {ex.Message}");
|
||||
}
|
||||
|
||||
_cache = (DateTime.Now, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string GetSymbol(string name)
|
||||
{
|
||||
var ext = Path.GetExtension(name).ToLowerInvariant();
|
||||
return ext switch
|
||||
{
|
||||
".exe" or ".msi" => Symbols.App,
|
||||
".xlsx" or ".xls" or ".csv" => Symbols.File,
|
||||
".docx" or ".doc" => Symbols.File,
|
||||
".pptx" or ".ppt" => Symbols.File,
|
||||
".pdf" => Symbols.File,
|
||||
".txt" or ".md" or ".log" => Symbols.Text,
|
||||
".jpg" or ".jpeg" or ".png" or ".gif" or ".webp" or ".bmp" => Symbols.Picture,
|
||||
_ => Symbols.File
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user