[Phase L21] TOML·Log·PS·Key 핸들러 4종 추가 + L21~L23 로드맵 계획 수립
TomlHandler (prefix=toml, 290줄, partial class):
- 외부 라이브러리 없는 경량 TOML 파서
- [section]/[[array-of-tables]] 파싱, 스칼라(bool/int/float/string)/배열/인라인 테이블
- toml validate·keys·sections·get <key.path>·stats·flat 서브커맨드
- 점 표기법 경로 조회(GetByPath), 재귀 평탄화(FlattenTable)
- CS8602 null 경고 수정(table![s] 명시)
LogHandler (prefix=log, 290줄, partial class):
- ERROR/WARN/INFO/DEBUG 레벨 자동 감지(키워드 기반)
- 클립보드 자동 읽기 또는 log <파일경로> 직접 입력
- error·warn·info·debug·last <n>·head <n>·grep <키워드>·stats·exceptions·today 서브커맨드
- 날짜별 분포 통계(yyyy-MM-dd 패턴), 스택트레이스 블록 추출
- [GeneratedRegex] DatePattern, using System.Text 누락 수정
PsHandler (prefix=ps, 200줄):
- 68개 PowerShell 명령 내장(file/process/service/network/registry/string/date/pipe 8개 카테고리)
- ps <카테고리> 전체 목록, ps <키워드> 전체 검색
- ps run <명령> → Windows Terminal / PowerShell 터미널 직접 실행
- Enter 클립보드 복사, 카테고리 오버뷰 표시
KeyHandler (prefix=key, 190줄):
- Windows(26개)·VS Code(29개)·Chrome/Edge(22개)·Vim(23개)·Excel(20개)·Windows Terminal(13개)
- 총 133개 단축키 내장
- key <앱> 카테고리 조회, key <키워드> 전체 앱 통합 검색
- Enter → 단축키 클립보드 복사
LAUNCHER_ROADMAP.md:
- Phase L21~L23 계획 추가(L22: proc·geo·cargo·pip, L23: k8s·gh·choco·cmp)
- L21 모든 항목 ✅ 완료 표시
- 빌드: 경고 0, 오류 0
This commit is contained in:
289
src/AxCopilot/Handlers/KeyHandler.cs
Normal file
289
src/AxCopilot/Handlers/KeyHandler.cs
Normal file
@@ -0,0 +1,289 @@
|
||||
using System.Windows;
|
||||
using AxCopilot.SDK;
|
||||
using AxCopilot.Services;
|
||||
using AxCopilot.Themes;
|
||||
|
||||
namespace AxCopilot.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// L21-4: 키보드 단축키 참조 사전 핸들러. "key" 프리픽스로 사용합니다.
|
||||
///
|
||||
/// 예: key → 앱 카테고리 목록
|
||||
/// key win → Windows 단축키
|
||||
/// key vscode → VS Code 단축키
|
||||
/// key chrome → Chrome/Edge 단축키
|
||||
/// key vim → Vim 명령
|
||||
/// key excel → Excel 단축키
|
||||
/// key terminal → Windows Terminal 단축키
|
||||
/// key <키워드> → 전체 단축키에서 키워드 검색 (예: key 찾기, key find)
|
||||
/// Enter → 단축키 복사.
|
||||
/// </summary>
|
||||
public class KeyHandler : IActionHandler
|
||||
{
|
||||
public string? Prefix => "key";
|
||||
|
||||
public PluginMetadata Metadata => new(
|
||||
"Key",
|
||||
"키보드 단축키 참조 사전 — Windows·VS Code·Chrome·Vim·Excel",
|
||||
"1.0",
|
||||
"AX");
|
||||
|
||||
private record Shortcut(string Keys, string Description, string App);
|
||||
|
||||
private static readonly Shortcut[] All =
|
||||
[
|
||||
// Windows
|
||||
new("Win + D", "바탕화면 보기/복원", "win"),
|
||||
new("Win + E", "파일 탐색기 열기", "win"),
|
||||
new("Win + L", "PC 잠금", "win"),
|
||||
new("Win + R", "실행 대화상자", "win"),
|
||||
new("Win + S", "Windows 검색", "win"),
|
||||
new("Win + V", "클립보드 히스토리", "win"),
|
||||
new("Win + X", "빠른 링크 메뉴 (전원 메뉴)", "win"),
|
||||
new("Win + Tab", "작업 보기(가상 데스크톱)", "win"),
|
||||
new("Win + Ctrl + D", "새 가상 데스크톱 추가", "win"),
|
||||
new("Win + Ctrl + →/←", "가상 데스크톱 전환", "win"),
|
||||
new("Win + ↑", "창 최대화", "win"),
|
||||
new("Win + ↓", "창 최소화/복원", "win"),
|
||||
new("Win + ←/→", "창 좌/우 절반 스냅", "win"),
|
||||
new("Win + Shift + S", "화면 부분 캡처 (Snipping Tool)", "win"),
|
||||
new("Alt + Tab", "실행 중인 앱 전환", "win"),
|
||||
new("Alt + F4", "현재 창 닫기", "win"),
|
||||
new("Ctrl + Shift + Esc", "작업 관리자 직접 열기", "win"),
|
||||
new("Ctrl + Alt + Del", "보안 옵션 화면", "win"),
|
||||
new("F2", "선택 항목 이름 변경", "win"),
|
||||
new("F5", "새로고침", "win"),
|
||||
new("F11", "전체화면 토글", "win"),
|
||||
new("Win + . (점)", "이모지 피커", "win"),
|
||||
new("Win + P", "프로젝션 모드 선택 (다중 모니터)", "win"),
|
||||
new("Win + I", "Windows 설정", "win"),
|
||||
new("PrtSc", "전체 화면 캡처 → 클립보드", "win"),
|
||||
new("Alt + PrtSc", "현재 창 캡처 → 클립보드", "win"),
|
||||
|
||||
// VS Code
|
||||
new("Ctrl + P", "파일 빠른 열기", "vscode"),
|
||||
new("Ctrl + Shift + P", "명령 팔레트", "vscode"),
|
||||
new("Ctrl + `", "통합 터미널 열기/닫기", "vscode"),
|
||||
new("Ctrl + B", "사이드바 토글", "vscode"),
|
||||
new("Ctrl + J", "패널 토글(터미널·출력)", "vscode"),
|
||||
new("Ctrl + F", "파일 내 찾기", "vscode"),
|
||||
new("Ctrl + H", "파일 내 찾아 바꾸기", "vscode"),
|
||||
new("Ctrl + Shift + F", "전체 검색", "vscode"),
|
||||
new("Ctrl + Shift + H", "전체 찾아 바꾸기", "vscode"),
|
||||
new("Ctrl + G", "줄 이동", "vscode"),
|
||||
new("Ctrl + /", "줄 주석 토글", "vscode"),
|
||||
new("Alt + ↑/↓", "현재 줄 위/아래 이동", "vscode"),
|
||||
new("Alt + Shift + ↑/↓","현재 줄 위/아래 복사", "vscode"),
|
||||
new("Ctrl + D", "다음 동일 단어 선택", "vscode"),
|
||||
new("Ctrl + Shift + L", "동일 단어 모두 선택", "vscode"),
|
||||
new("Ctrl + Shift + K", "현재 줄 삭제", "vscode"),
|
||||
new("Ctrl + Enter", "아래에 새 줄 추가", "vscode"),
|
||||
new("Ctrl + Shift + Enter", "위에 새 줄 추가", "vscode"),
|
||||
new("F12", "정의로 이동", "vscode"),
|
||||
new("Alt + F12", "정의 미리보기", "vscode"),
|
||||
new("Shift + F12", "모든 참조 찾기", "vscode"),
|
||||
new("F2", "기호 이름 변경(리팩터링)", "vscode"),
|
||||
new("Ctrl + .", "빠른 수정 (Quick Fix)", "vscode"),
|
||||
new("Ctrl + K Ctrl + F","선택 영역 포맷", "vscode"),
|
||||
new("Shift + Alt + F", "전체 파일 포맷", "vscode"),
|
||||
new("Ctrl + Z / Y", "실행 취소 / 다시 실행", "vscode"),
|
||||
new("Ctrl + W", "현재 탭 닫기", "vscode"),
|
||||
new("Ctrl + Tab", "에디터 탭 전환", "vscode"),
|
||||
new("Ctrl + \\", "에디터 분할", "vscode"),
|
||||
new("Ctrl + 1/2/3", "에디터 그룹 포커스", "vscode"),
|
||||
|
||||
// Chrome / Edge
|
||||
new("Ctrl + T", "새 탭 열기", "chrome"),
|
||||
new("Ctrl + W", "현재 탭 닫기", "chrome"),
|
||||
new("Ctrl + Shift + T", "닫은 탭 다시 열기", "chrome"),
|
||||
new("Ctrl + Tab", "다음 탭으로 이동", "chrome"),
|
||||
new("Ctrl + Shift + Tab","이전 탭으로 이동", "chrome"),
|
||||
new("Ctrl + 1~8", "번호로 탭 이동", "chrome"),
|
||||
new("Ctrl + L", "주소창 포커스", "chrome"),
|
||||
new("Ctrl + D", "현재 페이지 북마크", "chrome"),
|
||||
new("Ctrl + F", "페이지 내 찾기", "chrome"),
|
||||
new("Ctrl + H", "방문 기록", "chrome"),
|
||||
new("Ctrl + J", "다운로드 목록", "chrome"),
|
||||
new("Ctrl + Shift + J", "개발자 도구 콘솔", "chrome"),
|
||||
new("F12", "개발자 도구 토글", "chrome"),
|
||||
new("F5 / Ctrl + R", "페이지 새로고침", "chrome"),
|
||||
new("Ctrl + Shift + R", "캐시 무시 새로고침", "chrome"),
|
||||
new("Ctrl + +/-", "페이지 확대/축소", "chrome"),
|
||||
new("Ctrl + 0", "확대/축소 기본값 복원", "chrome"),
|
||||
new("Alt + ← / →", "뒤로/앞으로", "chrome"),
|
||||
new("Ctrl + N", "새 창 열기", "chrome"),
|
||||
new("Ctrl + Shift + N", "시크릿 창", "chrome"),
|
||||
new("Ctrl + Shift + B", "북마크 바 토글", "chrome"),
|
||||
new("Ctrl + U", "페이지 소스 보기", "chrome"),
|
||||
|
||||
// Vim
|
||||
new("i", "삽입 모드 진입", "vim"),
|
||||
new("Esc", "노멀 모드로 복귀", "vim"),
|
||||
new(":w", "저장", "vim"),
|
||||
new(":q", "종료", "vim"),
|
||||
new(":wq / :x", "저장 후 종료", "vim"),
|
||||
new(":q!", "저장 없이 강제 종료", "vim"),
|
||||
new("h/j/k/l", "좌/하/상/우 이동", "vim"),
|
||||
new("w / b", "단어 앞/뒤로 이동", "vim"),
|
||||
new("gg / G", "파일 처음 / 끝으로 이동", "vim"),
|
||||
new("0 / $", "줄 처음 / 끝으로 이동", "vim"),
|
||||
new("dd", "현재 줄 삭제", "vim"),
|
||||
new("yy", "현재 줄 복사(yank)", "vim"),
|
||||
new("p / P", "붙여넣기 (다음/현재 위치)", "vim"),
|
||||
new("u / Ctrl + R", "실행 취소 / 다시 실행", "vim"),
|
||||
new("/keyword", "앞으로 검색", "vim"),
|
||||
new("n / N", "다음/이전 검색 결과", "vim"),
|
||||
new(":%s/old/new/g", "전체 치환", "vim"),
|
||||
new("v / V", "비주얼 모드 (문자/줄)", "vim"),
|
||||
new("Ctrl + V", "비주얼 블록 모드", "vim"),
|
||||
new(":split / :vsplit", "수평/수직 창 분할", "vim"),
|
||||
new("Ctrl + W + W", "다음 창으로 포커스 이동", "vim"),
|
||||
new(":noh", "검색 하이라이트 제거", "vim"),
|
||||
new(">> / <<", "들여쓰기 추가/제거", "vim"),
|
||||
|
||||
// Excel
|
||||
new("Ctrl + Arrow", "데이터 끝으로 이동", "excel"),
|
||||
new("Ctrl + Shift + Arrow","데이터 끝까지 선택", "excel"),
|
||||
new("Ctrl + Home / End","셀 A1 / 마지막 셀로 이동", "excel"),
|
||||
new("Ctrl + Space", "열 전체 선택", "excel"),
|
||||
new("Shift + Space", "행 전체 선택", "excel"),
|
||||
new("Ctrl + Shift + +", "행/열 삽입", "excel"),
|
||||
new("Ctrl + -", "행/열 삭제", "excel"),
|
||||
new("Ctrl + D", "아래로 채우기", "excel"),
|
||||
new("Ctrl + R", "오른쪽으로 채우기", "excel"),
|
||||
new("Alt + =", "SUM 자동 합계", "excel"),
|
||||
new("F4", "참조 절대/상대 전환 ($)", "excel"),
|
||||
new("Ctrl + 1", "셀 서식 창", "excel"),
|
||||
new("Ctrl + ;", "현재 날짜 입력", "excel"),
|
||||
new("Ctrl + Shift + ;", "현재 시간 입력", "excel"),
|
||||
new("F2", "셀 편집 모드", "excel"),
|
||||
new("Alt + Enter", "셀 내 줄바꿈", "excel"),
|
||||
new("Ctrl + Z / Y", "실행 취소 / 다시 실행", "excel"),
|
||||
new("Ctrl + F", "찾기", "excel"),
|
||||
new("Ctrl + H", "찾아 바꾸기", "excel"),
|
||||
new("Ctrl + Shift + L", "필터 자동 설정 토글", "excel"),
|
||||
|
||||
// Windows Terminal
|
||||
new("Ctrl + Shift + T", "새 탭 열기", "terminal"),
|
||||
new("Ctrl + Shift + W", "탭 닫기", "terminal"),
|
||||
new("Ctrl + Tab", "다음 탭 이동", "terminal"),
|
||||
new("Ctrl + Shift + 1~9","번호 탭으로 이동", "terminal"),
|
||||
new("Ctrl + Shift + D", "창 복제", "terminal"),
|
||||
new("Alt + Shift + D", "창 분할 (자동 방향)", "terminal"),
|
||||
new("Alt + Shift + +", "수평 분할", "terminal"),
|
||||
new("Alt + Shift + -", "수직 분할", "terminal"),
|
||||
new("Alt + Arrow", "분할된 창 간 포커스 이동", "terminal"),
|
||||
new("Ctrl + +/-", "폰트 크기 변경", "terminal"),
|
||||
new("Ctrl + F", "터미널 내 텍스트 검색", "terminal"),
|
||||
new("Ctrl + Shift + P", "명령 팔레트", "terminal"),
|
||||
new("Ctrl + Shift + F", "전체 화면 토글", "terminal"),
|
||||
];
|
||||
|
||||
public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
|
||||
{
|
||||
var q = query.Trim();
|
||||
var items = new List<LauncherItem>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(q))
|
||||
{
|
||||
items.Add(new LauncherItem("키보드 단축키 참조 사전",
|
||||
"key win / vscode / chrome / vim / excel / terminal / key <키워드 검색>",
|
||||
null, null, Symbol: "\uE92E"));
|
||||
AddAppOverview(items);
|
||||
return Task.FromResult<IEnumerable<LauncherItem>>(items);
|
||||
}
|
||||
|
||||
var parts = q.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
var sub = parts[0].ToLowerInvariant();
|
||||
|
||||
// 앱 카테고리 조회
|
||||
var catKeys = new Dictionary<string, string[]>
|
||||
{
|
||||
["win"] = ["win", "windows"],
|
||||
["vscode"] = ["vscode", "code", "vs"],
|
||||
["chrome"] = ["chrome", "edge", "browser"],
|
||||
["vim"] = ["vim", "vi", "neovim"],
|
||||
["excel"] = ["excel", "spreadsheet"],
|
||||
["terminal"] = ["terminal", "wt"],
|
||||
};
|
||||
|
||||
foreach (var (cat, aliases) in catKeys)
|
||||
{
|
||||
if (aliases.Contains(sub))
|
||||
{
|
||||
var catItems = All.Where(s => s.App == cat).ToList();
|
||||
var catName = cat switch
|
||||
{
|
||||
"win" => "Windows",
|
||||
"vscode" => "VS Code",
|
||||
"chrome" => "Chrome / Edge",
|
||||
"vim" => "Vim",
|
||||
"excel" => "Excel",
|
||||
"terminal" => "Windows Terminal",
|
||||
_ => cat
|
||||
};
|
||||
items.Add(new LauncherItem($"{catName} 단축키 {catItems.Count}개", "", null, null, Symbol: "\uE92E"));
|
||||
foreach (var s in catItems)
|
||||
items.Add(new LauncherItem(s.Keys, s.Description, null, ("copy", s.Keys), Symbol: "\uE92E"));
|
||||
return Task.FromResult<IEnumerable<LauncherItem>>(items);
|
||||
}
|
||||
}
|
||||
|
||||
// 키워드 검색 (전체)
|
||||
var keyword = string.Join(" ", parts);
|
||||
var found = All.Where(s =>
|
||||
s.Keys.Contains(keyword, StringComparison.OrdinalIgnoreCase) ||
|
||||
s.Description.Contains(keyword, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
|
||||
if (found.Count > 0)
|
||||
{
|
||||
items.Add(new LauncherItem($"'{keyword}' 검색 결과: {found.Count}개", "", null, null, Symbol: "\uE92E"));
|
||||
foreach (var s in found)
|
||||
{
|
||||
var appLabel = s.App.ToUpperInvariant();
|
||||
items.Add(new LauncherItem(s.Keys, $"[{appLabel}] {s.Description}",
|
||||
null, ("copy", s.Keys), Symbol: "\uE92E"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
items.Add(new LauncherItem($"'{keyword}' 결과 없음",
|
||||
"key win / vscode / chrome / vim / excel / terminal",
|
||||
null, null, Symbol: "\uE783"));
|
||||
AddAppOverview(items);
|
||||
}
|
||||
|
||||
return Task.FromResult<IEnumerable<LauncherItem>>(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("Key", "클립보드에 복사했습니다.");
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static void AddAppOverview(List<LauncherItem> items)
|
||||
{
|
||||
var apps = new (string Key, string Label, int Count)[]
|
||||
{
|
||||
("win", "Windows 단축키", All.Count(s => s.App == "win")),
|
||||
("vscode", "VS Code 단축키", All.Count(s => s.App == "vscode")),
|
||||
("chrome", "Chrome / Edge 단축키", All.Count(s => s.App == "chrome")),
|
||||
("vim", "Vim 명령", All.Count(s => s.App == "vim")),
|
||||
("excel", "Excel 단축키", All.Count(s => s.App == "excel")),
|
||||
("terminal", "Windows Terminal 단축키", All.Count(s => s.App == "terminal")),
|
||||
};
|
||||
foreach (var (key, label, count) in apps)
|
||||
items.Add(new LauncherItem($"key {key}", $"{label} ({count}개)",
|
||||
null, null, Symbol: "\uE92E"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user