using System.Windows; using AxCopilot.SDK; using AxCopilot.Services; namespace AxCopilot.Handlers; /// /// L22-3: Python pip 명령 생성기 핸들러. "pip" 프리픽스로 사용합니다. /// /// 예: pip → 자주 쓰는 명령 목록 /// pip install → 패키지 설치 관련 명령 /// pip list → 목록 관련 명령 /// pip venv → 가상환경 관련 명령 /// pip conda → conda 관련 명령 /// pip <검색어> → 명령 검색 /// Enter → 명령어 클립보드 복사. /// public class PipHandler : IActionHandler { public string? Prefix => "pip"; public PluginMetadata Metadata => new( "pip 명령", "Python pip 명령 생성기 — 설치·관리·가상환경·conda", "1.0", "AX"); private sealed record PipCmd( string Pip2, string Pip3, string Description, string Category); private static readonly PipCmd[] Commands = [ // ── 설치 (install) ─────────────────────────────────────────────────── new("pip install {패키지}", "pip3 install {패키지}", "패키지 설치", "install"), new("pip install {패키지}=={버전}", "pip3 install {패키지}=={버전}", "특정 버전 설치 (예: requests==2.31.0)", "install"), new("pip install -r requirements.txt","pip3 install -r requirements.txt","requirements.txt 일괄 설치", "install"), new("pip install --upgrade {패키지}", "pip3 install --upgrade {패키지}","패키지 업그레이드", "install"), new("pip install --upgrade pip", "pip3 install --upgrade pip", "pip 자체 업그레이드", "install"), new("pip install --user {패키지}", "pip3 install --user {패키지}", "사용자 홈에 설치 (관리자 권한 불필요)", "install"), new("pip install -e .", "pip3 install -e .", "현재 폴더 패키지를 개발 모드로 설치", "install"), new("pip download {패키지}", "pip3 download {패키지}", "오프라인 설치를 위한 패키지 다운로드", "install"), // ── 제거 (uninstall) ───────────────────────────────────────────────── new("pip uninstall {패키지}", "pip3 uninstall {패키지}", "패키지 제거", "uninstall"), new("pip uninstall -y {패키지}", "pip3 uninstall -y {패키지}", "확인 없이 패키지 제거", "uninstall"), new("pip uninstall -r requirements.txt -y","pip3 uninstall -r requirements.txt -y","requirements.txt 패키지 일괄 제거", "uninstall"), // ── 목록·정보 (list) ───────────────────────────────────────────────── new("pip list", "pip3 list", "설치된 패키지 목록", "list"), new("pip list --outdated", "pip3 list --outdated", "업데이트 가능한 패키지 목록", "list"), new("pip show {패키지}", "pip3 show {패키지}", "패키지 상세 정보 (버전·위치·의존성)", "list"), new("pip freeze", "pip3 freeze", "설치 패키지 버전 고정 출력", "list"), new("pip freeze > requirements.txt", "pip3 freeze > requirements.txt", "requirements.txt 파일 생성", "list"), new("pip check", "pip3 check", "의존성 충돌 검사", "list"), // ── 검색·캐시 (search) ─────────────────────────────────────────────── new("pip cache list", "pip3 cache list", "캐시 목록 확인", "search"), new("pip cache purge", "pip3 cache purge", "캐시 전체 삭제", "search"), new("pip index versions {패키지}", "pip3 index versions {패키지}", "PyPI에서 사용 가능한 버전 목록 조회", "search"), new("pip config list", "pip3 config list", "pip 설정 목록", "search"), new("pip config set global.index-url {URL}","pip3 config set global.index-url {URL}","사내 PyPI 미러 설정", "search"), // ── 가상환경 (venv) ────────────────────────────────────────────────── new("python -m venv .venv", "python3 -m venv .venv", "가상환경 생성 (.venv 폴더)", "venv"), new(".venv\\Scripts\\activate", "source .venv/bin/activate", "가상환경 활성화 (Win / Mac·Linux)", "venv"), new("deactivate", "deactivate", "가상환경 비활성화", "venv"), new("python -m venv .venv --clear", "python3 -m venv .venv --clear", "가상환경 초기화 (재생성)", "venv"), new("pip list --local", "pip3 list --local", "현재 가상환경 패키지만 목록", "venv"), new("python -m site --user-site", "python3 -m site --user-site", "사용자 패키지 설치 경로 확인", "venv"), // ── conda ──────────────────────────────────────────────────────────── new("conda create -n {환경명} python={버전}","conda create -n {환경명} python={버전}","Conda 환경 생성 (버전 지정)", "conda"), new("conda activate {환경명}", "conda activate {환경명}", "Conda 환경 활성화", "conda"), new("conda deactivate", "conda deactivate", "Conda 환경 비활성화", "conda"), new("conda install {패키지}", "conda install {패키지}", "Conda로 패키지 설치", "conda"), new("conda update {패키지}", "conda update {패키지}", "Conda 패키지 업데이트", "conda"), new("conda list", "conda list", "현재 Conda 환경 패키지 목록", "conda"), new("conda env list", "conda env list", "전체 Conda 환경 목록", "conda"), new("conda env remove -n {환경명}", "conda env remove -n {환경명}", "Conda 환경 삭제", "conda"), new("conda env export > env.yml", "conda env export > env.yml", "환경 설정을 yml 파일로 내보내기", "conda"), new("conda env create -f env.yml", "conda env create -f env.yml", "yml 파일로 환경 복원", "conda"), ]; private static readonly (string Key, string[] Aliases, string Label)[] Categories = [ ("install", ["install", "설치", "add"], "패키지 설치"), ("uninstall", ["uninstall", "remove", "삭제"], "패키지 제거"), ("list", ["list", "목록", "show", "freeze"],"목록·정보"), ("search", ["search", "cache", "config"], "검색·캐시·설정"), ("venv", ["venv", "env", "가상환경"], "가상환경"), ("conda", ["conda", "anaconda"], "conda"), ]; public Task> GetItemsAsync(string query, CancellationToken ct) { var q = query.Trim(); var items = new List(); if (string.IsNullOrWhiteSpace(q)) { items.Add(new LauncherItem("pip 명령 생성기", "카테고리: install · uninstall · list · venv · conda", null, null, Symbol: "\uE943")); foreach (var (key, _, label) in Categories) { var cnt = Commands.Count(c => c.Category == key); items.Add(new LauncherItem($"pip {key}", $"{label} ({cnt}개 명령)", null, ("copy", $"pip {key}"), Symbol: "\uE943")); } return Task.FromResult>(items); } var kw = q.ToLowerInvariant(); // 카테고리 일치 var cat = Categories.FirstOrDefault(c => c.Aliases.Any(a => a == kw || kw.StartsWith(a + " "))); if (cat.Key != null) { var list = Commands.Where(c => c.Category == cat.Key).ToList(); items.Add(new LauncherItem($"{cat.Label} 명령 {list.Count}개", "pip2 / pip3 모두 표시 · Enter: pip3 명령 복사", null, null, Symbol: "\uE943")); foreach (var c in list) items.Add(CmdItem(c)); return Task.FromResult>(items); } // 검색 var searched = Commands.Where(c => c.Pip2.Contains(kw, StringComparison.OrdinalIgnoreCase) || c.Pip3.Contains(kw, StringComparison.OrdinalIgnoreCase) || c.Description.Contains(kw, StringComparison.OrdinalIgnoreCase)).ToList(); if (searched.Count == 0) { items.Add(new LauncherItem($"'{q}' 명령을 찾을 수 없습니다", "카테고리: install · uninstall · list · venv · conda", null, null, Symbol: "\uE783")); return Task.FromResult>(items); } items.Add(new LauncherItem($"'{q}' 검색 결과 {searched.Count}개", "Enter: pip3 명령 복사", null, null, Symbol: "\uE943")); foreach (var c in searched) items.Add(CmdItem(c)); return Task.FromResult>(items); } public Task ExecuteAsync(LauncherItem item, CancellationToken ct) { if (item.Data is ("copy", string text)) { try { System.Windows.Application.Current.Dispatcher.Invoke( () => Clipboard.SetText(text)); NotificationService.Notify("pip", "클립보드에 복사했습니다."); } catch { } } return Task.CompletedTask; } private static LauncherItem CmdItem(PipCmd c) { var title = c.Pip2 == c.Pip3 ? c.Pip3 : $"{c.Pip3}"; var sub = c.Pip2 == c.Pip3 ? c.Description : $"{c.Description} | pip2: {c.Pip2}"; return new LauncherItem(title, sub, null, ("copy", c.Pip3), Symbol: "\uE943"); } }