AX Commander 비교본 런처 기능 대량 이식
변경 목적: Agent Compare 아래 비교본의 개발 문서와 런처 소스를 기준으로 현재 AX Commander에 빠져 있던 신규 런처 기능을 동일한 흐름으로 옮겨, 비교본 수준의 기능 폭을 현재 제품에 반영했습니다. 핵심 수정사항: 비교본의 신규 런처 핸들러 다수를 src/AxCopilot/Handlers로 이식하고 App.xaml.cs 등록 흐름에 연결했습니다. 빠른 링크, 파일 태그, 알림 센터, 포모도로, 파일 브라우저, 핫키 관리, OCR, 세션/스케줄/매크로, Git/정규식/네트워크/압축/해시/UUID/JWT/QR 등 AX Commander 기능을 추가했습니다. 핵심 수정사항: 신규 기능이 실제 동작하도록 AppSettings 확장, SchedulerService/FileTagService/NotificationCenterService/IconCacheService/UrlTemplateEngine/PomodoroService 추가, 배치 이름변경/세션/스케줄/매크로 편집 창 추가, NotificationService와 Symbols 보강, QR/OCR용 csproj 의존성과 Windows 타겟 프레임워크를 반영했습니다. 문서 반영: README.md와 docs/DEVELOPMENT.md에 비교본 기반 런처 기능 이식 이력과 검증 결과를 업데이트했습니다. 검증 결과: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ 실행 기준 경고 0개, 오류 0개를 확인했습니다.
This commit is contained in:
@@ -0,0 +1,427 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Windows;
|
||||
using AxCopilot.SDK;
|
||||
using AxCopilot.Services;
|
||||
using AxCopilot.Themes;
|
||||
|
||||
namespace AxCopilot.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// L18-4: IT·개발 약어 사전 핸들러. "abbr" 프리픽스로 사용합니다.
|
||||
///
|
||||
/// 예: abbr → 주요 약어 목록
|
||||
/// abbr api → API 뜻 + 설명
|
||||
/// abbr crud → CRUD 약어 풀이
|
||||
/// abbr rest → REST 설명
|
||||
/// abbr http → HTTP 약어 목록
|
||||
/// Enter → 약어 또는 뜻을 클립보드에 복사.
|
||||
/// </summary>
|
||||
public class AbbrHandler : IActionHandler
|
||||
{
|
||||
public string? Prefix => "abbr";
|
||||
|
||||
public PluginMetadata Metadata => new(
|
||||
"Abbr",
|
||||
"IT·개발 약어 사전 — API · CRUD · REST · HTTP · SQL 등 내장",
|
||||
"1.0",
|
||||
"AX");
|
||||
|
||||
private record AbbrEntry(string Short, string Full, string Description, string Category);
|
||||
|
||||
// ── 내장 약어 사전 (~150개) ───────────────────────────────────────────────
|
||||
private static readonly AbbrEntry[] Entries =
|
||||
[
|
||||
// 웹/네트워크
|
||||
new("API", "Application Programming Interface", "소프트웨어 간 통신 규격", "웹/네트워크"),
|
||||
new("REST", "Representational State Transfer", "HTTP 기반 아키텍처 스타일", "웹/네트워크"),
|
||||
new("HTTP", "HyperText Transfer Protocol", "웹 통신 프로토콜", "웹/네트워크"),
|
||||
new("HTTPS", "HTTP Secure", "TLS/SSL로 암호화된 HTTP", "웹/네트워크"),
|
||||
new("HTML", "HyperText Markup Language", "웹 페이지 마크업 언어", "웹/네트워크"),
|
||||
new("CSS", "Cascading Style Sheets", "웹 스타일 시트 언어", "웹/네트워크"),
|
||||
new("URL", "Uniform Resource Locator", "인터넷 자원 주소", "웹/네트워크"),
|
||||
new("URI", "Uniform Resource Identifier", "자원 식별자 (URL의 상위 개념)", "웹/네트워크"),
|
||||
new("DNS", "Domain Name System", "도메인 ↔ IP 변환 시스템", "웹/네트워크"),
|
||||
new("IP", "Internet Protocol", "인터넷 패킷 전송 프로토콜", "웹/네트워크"),
|
||||
new("TCP", "Transmission Control Protocol", "신뢰성 연결형 전송 프로토콜", "웹/네트워크"),
|
||||
new("UDP", "User Datagram Protocol", "비연결형 전송 프로토콜", "웹/네트워크"),
|
||||
new("SSH", "Secure Shell", "원격 보안 접속 프로토콜", "웹/네트워크"),
|
||||
new("FTP", "File Transfer Protocol", "파일 전송 프로토콜", "웹/네트워크"),
|
||||
new("SMTP", "Simple Mail Transfer Protocol", "이메일 전송 프로토콜", "웹/네트워크"),
|
||||
new("CDN", "Content Delivery Network", "콘텐츠 분산 배포 네트워크", "웹/네트워크"),
|
||||
new("VPN", "Virtual Private Network", "가상 사설 네트워크", "웹/네트워크"),
|
||||
new("NAT", "Network Address Translation", "사설↔공인 IP 주소 변환", "웹/네트워크"),
|
||||
new("CORS", "Cross-Origin Resource Sharing", "브라우저 교차 출처 리소스 공유", "웹/네트워크"),
|
||||
new("SSE", "Server-Sent Events", "서버→클라이언트 단방향 스트림", "웹/네트워크"),
|
||||
new("WebSocket","WebSocket Protocol", "양방향 실시간 통신 프로토콜", "웹/네트워크"),
|
||||
new("gRPC", "Google Remote Procedure Call", "프로토콜 버퍼 기반 RPC 프레임워크", "웹/네트워크"),
|
||||
new("GraphQL", "Graph Query Language", "API 쿼리 언어 (Facebook 개발)", "웹/네트워크"),
|
||||
new("SOAP", "Simple Object Access Protocol", "XML 기반 웹 서비스 프로토콜", "웹/네트워크"),
|
||||
new("WSDL", "Web Services Description Language", "웹 서비스 인터페이스 설명 언어", "웹/네트워크"),
|
||||
new("TLS", "Transport Layer Security", "암호화 통신 프로토콜 (SSL 후속)", "웹/네트워크"),
|
||||
new("SSL", "Secure Sockets Layer", "암호화 통신 프로토콜 (TLS의 전신)", "웹/네트워크"),
|
||||
new("OAuth", "Open Authorization", "위임 인증 표준 프로토콜", "웹/네트워크"),
|
||||
new("MIME", "Multipurpose Internet Mail Extensions", "이메일·웹 콘텐츠 타입 표준", "웹/네트워크"),
|
||||
|
||||
// 개발/프로그래밍
|
||||
new("CRUD", "Create Read Update Delete", "기본 데이터 처리 4가지 연산", "개발"),
|
||||
new("OOP", "Object-Oriented Programming", "객체 지향 프로그래밍", "개발"),
|
||||
new("SOLID", "Single responsibility Open/closed Liskov Interface-segregation Dependency-inversion",
|
||||
"객체지향 5가지 설계 원칙", "개발"),
|
||||
new("DRY", "Don't Repeat Yourself", "코드 중복 최소화 원칙", "개발"),
|
||||
new("KISS", "Keep It Simple, Stupid", "단순하게 유지하라 원칙", "개발"),
|
||||
new("YAGNI", "You Aren't Gonna Need It", "필요할 때만 구현하라 원칙", "개발"),
|
||||
new("TDD", "Test-Driven Development", "테스트 주도 개발 방법론", "개발"),
|
||||
new("BDD", "Behavior-Driven Development", "행동 주도 개발 방법론", "개발"),
|
||||
new("DDD", "Domain-Driven Design", "도메인 주도 설계", "개발"),
|
||||
new("MVC", "Model-View-Controller", "UI 아키텍처 패턴", "개발"),
|
||||
new("MVP", "Model-View-Presenter", "MVC의 변형, Presenter가 View와 Model 중재", "개발"),
|
||||
new("MVVM", "Model-View-ViewModel", "WPF·모바일 아키텍처 패턴", "개발"),
|
||||
new("SRP", "Single Responsibility Principle", "단일 책임 원칙 (SOLID의 S)", "개발"),
|
||||
new("OCP", "Open/Closed Principle", "개방/폐쇄 원칙 (SOLID의 O)", "개발"),
|
||||
new("LSP", "Liskov Substitution Principle", "리스코프 치환 원칙 (SOLID의 L)", "개발"),
|
||||
new("ISP", "Interface Segregation Principle", "인터페이스 분리 원칙 (SOLID의 I)", "개발"),
|
||||
new("DIP", "Dependency Inversion Principle", "의존성 역전 원칙 (SOLID의 D)", "개발"),
|
||||
new("IoC", "Inversion of Control", "제어 역전 (프레임워크 핵심 개념)", "개발"),
|
||||
new("DI", "Dependency Injection", "의존성 주입 패턴", "개발"),
|
||||
new("AOP", "Aspect-Oriented Programming", "관점 지향 프로그래밍", "개발"),
|
||||
new("FP", "Functional Programming", "함수형 프로그래밍", "개발"),
|
||||
new("DSL", "Domain-Specific Language", "특정 도메인 전용 언어", "개발"),
|
||||
new("SDK", "Software Development Kit", "소프트웨어 개발 도구 모음", "개발"),
|
||||
new("IDE", "Integrated Development Environment", "통합 개발 환경", "개발"),
|
||||
new("CLI", "Command Line Interface", "명령줄 인터페이스", "개발"),
|
||||
new("GUI", "Graphical User Interface", "그래픽 사용자 인터페이스", "개발"),
|
||||
new("UI", "User Interface", "사용자 인터페이스", "개발"),
|
||||
new("UX", "User Experience", "사용자 경험", "개발"),
|
||||
new("SPA", "Single Page Application", "단일 페이지 애플리케이션", "개발"),
|
||||
new("SSR", "Server-Side Rendering", "서버 사이드 렌더링", "개발"),
|
||||
new("CSR", "Client-Side Rendering", "클라이언트 사이드 렌더링", "개발"),
|
||||
new("PWA", "Progressive Web App", "프로그레시브 웹 앱", "개발"),
|
||||
new("CDK", "Cloud Development Kit", "클라우드 인프라 코드 개발 도구", "개발"),
|
||||
new("ORM", "Object-Relational Mapping", "객체-관계형 데이터베이스 매핑", "개발"),
|
||||
new("REPL", "Read-Eval-Print Loop", "대화형 프로그래밍 환경", "개발"),
|
||||
new("GC", "Garbage Collection", "자동 메모리 회수", "개발"),
|
||||
new("JIT", "Just-In-Time Compilation", "실행 시점 컴파일", "개발"),
|
||||
new("AOT", "Ahead-Of-Time Compilation", "사전 컴파일", "개발"),
|
||||
new("WASM", "WebAssembly", "브라우저용 바이너리 형식", "개발"),
|
||||
new("AST", "Abstract Syntax Tree", "추상 구문 트리", "개발"),
|
||||
new("LSP", "Language Server Protocol", "언어 분석 서버 표준 프로토콜", "개발"),
|
||||
|
||||
// 데이터베이스
|
||||
new("SQL", "Structured Query Language", "관계형 DB 쿼리 언어", "DB"),
|
||||
new("NoSQL", "Not Only SQL", "비관계형 데이터베이스 총칭", "DB"),
|
||||
new("ACID", "Atomicity Consistency Isolation Durability", "DB 트랜잭션 4가지 성질", "DB"),
|
||||
new("CAP", "Consistency Availability Partition-tolerance","분산 DB 설계 이론 (셋 중 2개만 보장)", "DB"),
|
||||
new("ETL", "Extract Transform Load", "데이터 추출·변환·적재 프로세스", "DB"),
|
||||
new("OLTP", "Online Transaction Processing", "트랜잭션 처리 중심 DB", "DB"),
|
||||
new("OLAP", "Online Analytical Processing", "분석 처리 중심 DB (데이터 웨어하우스)", "DB"),
|
||||
new("DDL", "Data Definition Language", "DB 구조 정의 SQL (CREATE/ALTER/DROP)", "DB"),
|
||||
new("DML", "Data Manipulation Language", "데이터 조작 SQL (SELECT/INSERT/UPDATE/DELETE)", "DB"),
|
||||
new("DCL", "Data Control Language", "접근 권한 SQL (GRANT/REVOKE)", "DB"),
|
||||
|
||||
// 보안
|
||||
new("JWT", "JSON Web Token", "JSON 기반 인증 토큰 표준", "보안"),
|
||||
new("RBAC", "Role-Based Access Control", "역할 기반 접근 제어", "보안"),
|
||||
new("ABAC", "Attribute-Based Access Control", "속성 기반 접근 제어", "보안"),
|
||||
new("MFA", "Multi-Factor Authentication", "다중 인증", "보안"),
|
||||
new("2FA", "Two-Factor Authentication", "이중 인증", "보안"),
|
||||
new("XSS", "Cross-Site Scripting", "악성 스크립트 삽입 공격", "보안"),
|
||||
new("CSRF", "Cross-Site Request Forgery", "교차 사이트 요청 위조 공격", "보안"),
|
||||
new("SQL Injection", "SQL Injection Attack", "SQL 쿼리 삽입 공격", "보안"),
|
||||
new("OWASP", "Open Web Application Security Project", "웹 보안 가이드라인 기관", "보안"),
|
||||
new("CVE", "Common Vulnerabilities and Exposures", "공개 보안 취약점 DB", "보안"),
|
||||
new("HTTPS", "HTTP Secure", "TLS로 암호화된 HTTP", "보안"),
|
||||
new("AES", "Advanced Encryption Standard", "대칭키 암호화 표준 (128/192/256bit)", "보안"),
|
||||
new("RSA", "Rivest–Shamir–Adleman", "공개키 비대칭 암호화 알고리즘", "보안"),
|
||||
new("HMAC", "Hash-based Message Authentication Code", "해시 기반 메시지 인증 코드", "보안"),
|
||||
new("PKI", "Public Key Infrastructure", "공개키 인프라", "보안"),
|
||||
|
||||
// 클라우드/인프라
|
||||
new("AWS", "Amazon Web Services", "아마존 클라우드 서비스", "클라우드"),
|
||||
new("GCP", "Google Cloud Platform", "구글 클라우드 서비스", "클라우드"),
|
||||
new("SaaS", "Software as a Service", "구독형 소프트웨어 서비스", "클라우드"),
|
||||
new("PaaS", "Platform as a Service", "플랫폼 서비스", "클라우드"),
|
||||
new("IaaS", "Infrastructure as a Service", "인프라 서비스", "클라우드"),
|
||||
new("FaaS", "Function as a Service", "서버리스 함수 서비스", "클라우드"),
|
||||
new("K8s", "Kubernetes", "컨테이너 오케스트레이션 플랫폼", "클라우드"),
|
||||
new("CI/CD", "Continuous Integration/Continuous Delivery","지속적 통합/배포 파이프라인", "클라우드"),
|
||||
new("IaC", "Infrastructure as Code", "코드로 관리하는 인프라", "클라우드"),
|
||||
new("VPC", "Virtual Private Cloud", "가상 사설 클라우드 네트워크", "클라우드"),
|
||||
new("SLA", "Service Level Agreement", "서비스 수준 계약 (가용성 보장)", "클라우드"),
|
||||
new("SLO", "Service Level Objective", "서비스 수준 목표", "클라우드"),
|
||||
new("RTO", "Recovery Time Objective", "복구 목표 시간", "클라우드"),
|
||||
new("RPO", "Recovery Point Objective", "복구 목표 지점", "클라우드"),
|
||||
new("CDN", "Content Delivery Network", "콘텐츠 분산 배포 네트워크", "클라우드"),
|
||||
new("ECS", "Elastic Container Service", "AWS 컨테이너 관리 서비스", "클라우드"),
|
||||
new("ECR", "Elastic Container Registry", "AWS 컨테이너 이미지 저장소", "클라우드"),
|
||||
new("EKS", "Elastic Kubernetes Service", "AWS 관리형 Kubernetes", "클라우드"),
|
||||
|
||||
// AI/ML
|
||||
new("AI", "Artificial Intelligence", "인공지능", "AI/ML"),
|
||||
new("ML", "Machine Learning", "머신러닝", "AI/ML"),
|
||||
new("DL", "Deep Learning", "딥러닝", "AI/ML"),
|
||||
new("LLM", "Large Language Model", "대규모 언어 모델", "AI/ML"),
|
||||
new("NLP", "Natural Language Processing", "자연어 처리", "AI/ML"),
|
||||
new("CNN", "Convolutional Neural Network", "합성곱 신경망", "AI/ML"),
|
||||
new("RNN", "Recurrent Neural Network", "순환 신경망", "AI/ML"),
|
||||
new("GAN", "Generative Adversarial Network", "생성적 적대 신경망", "AI/ML"),
|
||||
new("RAG", "Retrieval-Augmented Generation", "검색 증강 생성 (LLM + 검색)", "AI/ML"),
|
||||
new("RLHF", "Reinforcement Learning from Human Feedback","인간 피드백 강화학습", "AI/ML"),
|
||||
new("GPT", "Generative Pre-trained Transformer", "생성형 사전학습 변환기 (OpenAI)", "AI/ML"),
|
||||
new("BERT", "Bidirectional Encoder Representations from Transformers","양방향 트랜스포머 언어 모델", "AI/ML"),
|
||||
new("SFT", "Supervised Fine-Tuning", "지도 학습 파인튜닝", "AI/ML"),
|
||||
new("LoRA", "Low-Rank Adaptation", "저순위 행렬 파인튜닝 기법", "AI/ML"),
|
||||
new("MCP", "Model Context Protocol", "LLM 외부 도구 연결 표준 프로토콜", "AI/ML"),
|
||||
new("CoT", "Chain of Thought", "사고 단계 명시 프롬프팅", "AI/ML"),
|
||||
|
||||
// 데이터 형식
|
||||
new("JSON", "JavaScript Object Notation", "경량 데이터 교환 형식", "데이터형식"),
|
||||
new("XML", "Extensible Markup Language", "확장 가능 마크업 언어", "데이터형식"),
|
||||
new("YAML", "YAML Ain't Markup Language", "사람이 읽기 쉬운 데이터 직렬화 형식", "데이터형식"),
|
||||
new("TOML", "Tom's Obvious, Minimal Language", "설정 파일 전용 경량 형식", "데이터형식"),
|
||||
new("CSV", "Comma-Separated Values", "쉼표 구분 데이터 형식", "데이터형식"),
|
||||
new("TSV", "Tab-Separated Values", "탭 구분 데이터 형식", "데이터형식"),
|
||||
new("Protobuf","Protocol Buffers", "구글 이진 직렬화 형식", "데이터형식"),
|
||||
new("Avro", "Apache Avro", "Hadoop 생태계 이진 직렬화", "데이터형식"),
|
||||
new("Parquet", "Apache Parquet", "열 지향 이진 데이터 형식", "데이터형식"),
|
||||
new("Base64", "Base 64 encoding", "이진 데이터 텍스트 인코딩 (64진수)", "데이터형식"),
|
||||
|
||||
// 버전 관리/협업
|
||||
new("VCS", "Version Control System", "버전 관리 시스템", "협업"),
|
||||
new("SCM", "Source Code Management", "소스 코드 관리", "협업"),
|
||||
new("PR", "Pull Request", "코드 병합 요청 (GitHub 용어)", "협업"),
|
||||
new("MR", "Merge Request", "코드 병합 요청 (GitLab 용어)", "협업"),
|
||||
new("LGTM", "Looks Good To Me", "코드 리뷰 승인 표현", "협업"),
|
||||
new("WIP", "Work In Progress", "진행 중 작업", "협업"),
|
||||
new("RFC", "Request for Comments", "의견 요청 문서 (표준화 프로세스)", "협업"),
|
||||
new("POC", "Proof of Concept", "개념 검증", "협업"),
|
||||
new("MVP", "Minimum Viable Product", "최소 기능 제품", "협업"),
|
||||
new("KPI", "Key Performance Indicator", "핵심 성과 지표", "협업"),
|
||||
new("OKR", "Objectives and Key Results", "목표 및 핵심 결과", "협업"),
|
||||
new("SOP", "Standard Operating Procedure", "표준 운영 절차", "협업"),
|
||||
];
|
||||
|
||||
private static readonly string[] Categories = Entries.Select(e => e.Category).Distinct().ToArray();
|
||||
|
||||
// ── 커스텀 약어 ───────────────────────────────────────────────────────────
|
||||
private static readonly string CustomPath = System.IO.Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"AxCopilot", "abbr_custom.json");
|
||||
|
||||
private sealed class CustomAbbr
|
||||
{
|
||||
[JsonPropertyName("short")] public string Short { get; set; } = "";
|
||||
[JsonPropertyName("full")] public string Full { get; set; } = "";
|
||||
[JsonPropertyName("desc")] public string Description { get; set; } = "";
|
||||
[JsonPropertyName("cat")] public string Category { get; set; } = "사용자정의";
|
||||
}
|
||||
|
||||
private static List<CustomAbbr> LoadCustom()
|
||||
{
|
||||
try {
|
||||
if (System.IO.File.Exists(CustomPath))
|
||||
return JsonSerializer.Deserialize<List<CustomAbbr>>(
|
||||
System.IO.File.ReadAllText(CustomPath)) ?? [];
|
||||
} catch { }
|
||||
return [];
|
||||
}
|
||||
|
||||
private static void SaveCustom(List<CustomAbbr> list)
|
||||
{
|
||||
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(CustomPath)!);
|
||||
System.IO.File.WriteAllText(CustomPath, JsonSerializer.Serialize(list,
|
||||
new JsonSerializerOptions { WriteIndented = true,
|
||||
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping }));
|
||||
}
|
||||
|
||||
public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
|
||||
{
|
||||
var q = query.Trim();
|
||||
var items = new List<LauncherItem>();
|
||||
|
||||
// ── 서브커맨드 처리 ───────────────────────────────────────────────────
|
||||
// abbr custom → 사용자 정의 약어 목록
|
||||
if (q.Equals("custom", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var customList = LoadCustom();
|
||||
if (customList.Count == 0)
|
||||
{
|
||||
items.Add(new LauncherItem("사용자 정의 약어 없음",
|
||||
"abbr add <약어> <풀이> [설명] 으로 추가하세요",
|
||||
null, null, Symbol: "\uE82D"));
|
||||
}
|
||||
else
|
||||
{
|
||||
items.Add(new LauncherItem($"사용자 정의 약어 {customList.Count}개", "", null, null, Symbol: "\uE82D"));
|
||||
foreach (var c in customList)
|
||||
items.Add(new LauncherItem(c.Short,
|
||||
$"{c.Full} · {c.Description}",
|
||||
null, ("copy", $"{c.Short}: {c.Full}"), Symbol: "\uE82D"));
|
||||
}
|
||||
return Task.FromResult<IEnumerable<LauncherItem>>(items);
|
||||
}
|
||||
|
||||
// abbr add <약어> <풀이> [설명]
|
||||
if (q.StartsWith("add ", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var rest = q[4..].Trim();
|
||||
var parts = rest.Split(' ', 3, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length < 2)
|
||||
{
|
||||
items.Add(new LauncherItem("사용법: abbr add <약어> <풀이> [설명]",
|
||||
"예: abbr add ROI 투자수익률 Return on Investment",
|
||||
null, null, Symbol: "\uE82D"));
|
||||
return Task.FromResult<IEnumerable<LauncherItem>>(items);
|
||||
}
|
||||
var abbr = parts[0].ToUpper();
|
||||
var full = parts[1];
|
||||
var desc = parts.Length > 2 ? parts[2] : "";
|
||||
var encoded = $"{abbr}|{full}|{desc}";
|
||||
items.Add(new LauncherItem($"약어 추가: {abbr} = {full}",
|
||||
desc.Length > 0 ? desc : "Enter: 저장",
|
||||
null, ("add", encoded), Symbol: "\uE82D"));
|
||||
return Task.FromResult<IEnumerable<LauncherItem>>(items);
|
||||
}
|
||||
|
||||
// abbr del <약어>
|
||||
if (q.StartsWith("del ", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var abbr = q[4..].Trim().ToUpper();
|
||||
if (string.IsNullOrEmpty(abbr))
|
||||
{
|
||||
items.Add(new LauncherItem("사용법: abbr del <약어>",
|
||||
"예: abbr del ROI",
|
||||
null, null, Symbol: "\uE82D"));
|
||||
return Task.FromResult<IEnumerable<LauncherItem>>(items);
|
||||
}
|
||||
items.Add(new LauncherItem($"약어 삭제: {abbr}",
|
||||
"Enter: 삭제 확인",
|
||||
null, ("del", abbr), Symbol: "\uE82D"));
|
||||
return Task.FromResult<IEnumerable<LauncherItem>>(items);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(q))
|
||||
{
|
||||
items.Add(new LauncherItem($"IT·개발 약어 사전 {Entries.Length}개",
|
||||
"abbr <약어> 예: abbr api / abbr crud / abbr jwt",
|
||||
null, null, Symbol: "\uE82D"));
|
||||
// 커스텀 약어 추가 안내
|
||||
items.Add(new LauncherItem("abbr add <약어> <풀이> — 나만의 약어 추가",
|
||||
"예: abbr add ROI 투자수익률",
|
||||
null, null, Symbol: "\uE82D"));
|
||||
items.Add(new LauncherItem("── 카테고리 ──", "", null, null, Symbol: "\uE82D"));
|
||||
foreach (var cat in Categories)
|
||||
{
|
||||
var cnt = Entries.Count(e => e.Category == cat);
|
||||
items.Add(new LauncherItem(cat, $"{cnt}개 · abbr {cat}로 목록 보기",
|
||||
null, null, Symbol: "\uE82D"));
|
||||
}
|
||||
// 자주 쓰는 약어 샘플
|
||||
items.Add(new LauncherItem("── 자주 쓰는 약어 ──", "", null, null, Symbol: "\uE82D"));
|
||||
var popular = new[] { "API", "CRUD", "REST", "JWT", "SQL", "CI/CD", "TDD", "OOP" };
|
||||
foreach (var p in popular)
|
||||
{
|
||||
var e = Entries.FirstOrDefault(x => x.Short.Equals(p, StringComparison.OrdinalIgnoreCase));
|
||||
if (e != null)
|
||||
items.Add(MakeAbbrItem(e));
|
||||
}
|
||||
return Task.FromResult<IEnumerable<LauncherItem>>(items);
|
||||
}
|
||||
|
||||
// 카테고리 검색
|
||||
if (Categories.Any(c => c.Equals(q, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
var catEntries = Entries.Where(e => e.Category.Equals(q, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
items.Add(new LauncherItem($"{q} {catEntries.Count}개", "", null, null, Symbol: "\uE82D"));
|
||||
foreach (var e in catEntries)
|
||||
items.Add(MakeAbbrItem(e));
|
||||
return Task.FromResult<IEnumerable<LauncherItem>>(items);
|
||||
}
|
||||
|
||||
// 약어 검색 (정확 일치 우선, 그 다음 부분 일치) — 내장 + 커스텀 통합
|
||||
var customSearch = LoadCustom();
|
||||
var customEntries = customSearch.Select(c => new AbbrEntry(c.Short, c.Full, c.Description, c.Category)).ToList();
|
||||
var allEntries = Entries.Concat(customEntries).ToList();
|
||||
|
||||
var exact = allEntries.Where(e =>
|
||||
e.Short.Equals(q, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
|
||||
var partial = allEntries.Where(e =>
|
||||
!exact.Contains(e) &&
|
||||
(e.Short.Contains(q, StringComparison.OrdinalIgnoreCase) ||
|
||||
e.Full.Contains(q, StringComparison.OrdinalIgnoreCase) ||
|
||||
e.Description.Contains(q, StringComparison.OrdinalIgnoreCase))).ToList();
|
||||
|
||||
var all = exact.Concat(partial).ToList();
|
||||
|
||||
if (all.Count == 0)
|
||||
{
|
||||
items.Add(new LauncherItem($"'{q}' 약어를 찾을 수 없습니다",
|
||||
"카테고리: " + string.Join(", ", Categories),
|
||||
null, null, Symbol: "\uE946"));
|
||||
return Task.FromResult<IEnumerable<LauncherItem>>(items);
|
||||
}
|
||||
|
||||
if (exact.Count == 1)
|
||||
{
|
||||
// 정확 일치 1개 → 상세 표시
|
||||
var e = exact[0];
|
||||
items.Add(new LauncherItem($"{e.Short} = {e.Full}",
|
||||
e.Description, null, ("copy", $"{e.Short}: {e.Full}"), Symbol: "\uE82D"));
|
||||
items.Add(new LauncherItem("약어", e.Short, null, ("copy", e.Short), Symbol: "\uE82D"));
|
||||
items.Add(new LauncherItem("원문", e.Full, null, ("copy", e.Full), Symbol: "\uE82D"));
|
||||
items.Add(new LauncherItem("설명", e.Description, null, ("copy", e.Description), Symbol: "\uE82D"));
|
||||
items.Add(new LauncherItem("카테고리",e.Category, null, null, Symbol: "\uE82D"));
|
||||
}
|
||||
else
|
||||
{
|
||||
items.Add(new LauncherItem($"'{q}' 검색 결과 {all.Count}개", "", null, null, Symbol: "\uE82D"));
|
||||
foreach (var e in all.Take(30))
|
||||
items.Add(MakeAbbrItem(e));
|
||||
}
|
||||
|
||||
return Task.FromResult<IEnumerable<LauncherItem>>(items);
|
||||
}
|
||||
|
||||
public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
|
||||
{
|
||||
switch (item.Data)
|
||||
{
|
||||
case ("copy", string text):
|
||||
try
|
||||
{
|
||||
System.Windows.Application.Current.Dispatcher.Invoke(
|
||||
() => Clipboard.SetText(text));
|
||||
NotificationService.Notify("Abbr", "클립보드에 복사했습니다.");
|
||||
}
|
||||
catch { }
|
||||
break;
|
||||
|
||||
case ("add", string encoded):
|
||||
var parts = encoded.Split('|', 3);
|
||||
var custom = LoadCustom();
|
||||
custom.RemoveAll(c => c.Short.Equals(parts[0], StringComparison.OrdinalIgnoreCase));
|
||||
custom.Add(new CustomAbbr {
|
||||
Short = parts[0].ToUpper(),
|
||||
Full = parts.Length > 1 ? parts[1] : "",
|
||||
Description = parts.Length > 2 ? parts[2] : "",
|
||||
});
|
||||
SaveCustom(custom);
|
||||
NotificationService.Notify("약어", $"{parts[0].ToUpper()} 등록 완료");
|
||||
break;
|
||||
|
||||
case ("del", string abbr):
|
||||
var customDel = LoadCustom();
|
||||
customDel.RemoveAll(c => c.Short.Equals(abbr, StringComparison.OrdinalIgnoreCase));
|
||||
SaveCustom(customDel);
|
||||
NotificationService.Notify("약어", $"{abbr.ToUpper()} 삭제 완료");
|
||||
break;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static LauncherItem MakeAbbrItem(AbbrEntry e) =>
|
||||
new(e.Short,
|
||||
$"{e.Full} · {e.Description}",
|
||||
null, ("copy", $"{e.Short}: {e.Full}"), Symbol: "\uE82D");
|
||||
}
|
||||
Reference in New Issue
Block a user