쿼리 편집기 — 자동완성 위치 버그와 목록 가독성
■ 팝업이 화면 구석으로 날아가던 문제
두 가지가 겹쳐 있었다.
1. WPF Popup 은 열려 있는 동안 Placement 를 다시 계산하지 않는다. 글자를 칠 때마다
HorizontalOffset/VerticalOffset 만 바꿔서는 처음 열린 자리에 그대로 머문다.
2. GetRectFromCharacterIndex 는 스크롤 밖이나 범위를 벗어난 위치에서 Empty 를 준다.
그대로 쓰면 좌표가 무한대가 되어 팝업이 화면 밖으로 나간다.
기준점을 커서가 아니라 <b>완성 중인 낱말의 시작</b>으로 바꾸고(글자마다 흔들리지 않는다),
그 기준점이 달라졌을 때만 닫았다 다시 연다. Empty·무한대는 캐럿 → 원점 순으로 물러선다.
■ 별칭 없이 컬럼을 칠 때 아무것도 안 뜨던 문제
select * FROM P_COMINF where comcht|
점을 찍어야만 컬럼을 제안하고 있었다. 그런데 별칭을 안 쓰는 쪽이 오히려 흔하고,
WHERE 절이야말로 컬럼 이름이 가장 많이 필요한 자리다.
이제 일반 위치에서도 이 쿼리가 참조하는 테이블(FROM/JOIN)의 컬럼을 먼저 제안한다.
FROM 뒤에 키워드가 오면 테이블로 보지 않고, 같은 테이블이 두 번 조인돼도 후보는 한 번만 만든다.
■ 치환 변수 목록 가독성
토큰이 60자가 넘고 앞 40자(M.CMM.HISOperatingInfo.bzPatientInfo.)가 모든 줄에서 똑같았다.
그대로 두 줄로 깔면 정작 다른 부분인 속성명이 오른쪽 끝에서 잘려 무엇이 무엇인지 구분되지 않는다.
설명 + 속성명 한 줄로 바꾸고 전체 토큰은 툴팁으로 옮겼다. 줄 수도 절반이 됐다.
DataRow 형태는 꼬리(.item("컬럼명"))를 빼고 속성명만 남긴다 — 컬럼 채우기라는 사실은 설명이 말해 준다.
■ 현재 줄 강조
긴 쿼리에서 지금 어디를 고치고 있는지 잃지 않도록 커서 줄에 옅은 띠를 깐다.
선택 중일 때는 끈다 — 선택 색과 겹치면 오히려 읽기 어렵다.
단위 테스트 6건 추가(별칭 없는 테이블 참조·중복 조인·FROM 뒤 키워드 배제·
짧은 형태에 클래스 이름 없음·길이 상한·DataRow 속성명).
회귀: 테스트 216/216, 편집 스모크 실패 0, 검증 실행 점검 10/10,
DB 왕복 1,271건 diff 0/예외 0, 종이 렌더 P062 바이트 동일.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
79db31cb4d
commit
f7c90979b9
@@ -6,7 +6,34 @@ namespace SheetMe.Core.Catalog;
|
||||
/// <paramref name="NeedsColumn"/> 이 true 면 컬럼명을 채워야 완성된다(DataRow 접근형).
|
||||
/// 삽입 후 사용자가 <c>컬럼명</c> 자리를 고쳐야 하므로 편집기가 그 부분을 선택해 준다.
|
||||
/// </summary>
|
||||
public sealed record QueryVariable(string Group, string Token, string Description, bool NeedsColumn = false);
|
||||
public sealed record QueryVariable(string Group, string Token, string Description, bool NeedsColumn = false)
|
||||
{
|
||||
/// <summary>
|
||||
/// 목록에 띄우는 짧은 형태 — 클래스 전체 이름을 뺀 나머지.
|
||||
///
|
||||
/// 토큰은 60자가 넘고 앞 40자가 모든 줄에서 똑같다. 그대로 늘어놓으면
|
||||
/// 정작 다른 부분(속성명)이 오른쪽 끝에서 잘려 무엇이 무엇인지 구분되지 않는다.
|
||||
/// 전체 문자열은 툴팁과 삽입 결과로 확인할 수 있다.
|
||||
/// </summary>
|
||||
public string ShortForm
|
||||
{
|
||||
get
|
||||
{
|
||||
var inner = Token.Length >= 4 ? Token[2..^2] : Token;
|
||||
var lastDot = inner.LastIndexOf('.');
|
||||
// DataRow 형태(.item("컬럼명"))는 속성명만 남긴다 —
|
||||
// 꼬리까지 붙이면 다시 길어져 오른쪽에서 잘린다. 컬럼 채우기라는 사실은 설명이 말해 준다.
|
||||
var itemAt = inner.IndexOf(".item(", StringComparison.Ordinal);
|
||||
if (itemAt > 0)
|
||||
{
|
||||
var head = inner[..itemAt];
|
||||
var propDot = head.LastIndexOf('.');
|
||||
return propDot >= 0 ? head[(propDot + 1)..] : head;
|
||||
}
|
||||
return lastDot >= 0 ? inner[(lastDot + 1)..] : inner;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MDataTable 쿼리의 치환 변수 카탈로그.
|
||||
|
||||
@@ -78,6 +78,11 @@ public static class SqlCompletion
|
||||
private static readonly Regex AliasPattern = new(
|
||||
@"\b(?:FROM|JOIN)\s+([A-Za-z_][\w$#]*)\s+(?:AS\s+)?([A-Za-z_][\w$#]*)",
|
||||
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
|
||||
/// <summary>FROM/JOIN 뒤의 테이블 이름 — 별칭이 있든 없든</summary>
|
||||
private static readonly Regex TableRefPattern = new(
|
||||
@"\b(?:FROM|JOIN)\s+([A-Za-z_][\w$#]*)",
|
||||
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
@@ -172,6 +177,31 @@ public static class SqlCompletion
|
||||
return qualifier;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이 쿼리가 참조하는 테이블 전부 — 별칭 없이 컬럼을 칠 때 후보를 어디서 가져올지 정한다.
|
||||
///
|
||||
/// <c>SELECT * FROM P_COMINF WHERE comcht|</c> 처럼 별칭을 안 쓰는 쪽이 오히려 흔하다.
|
||||
/// 점을 찍어야만 컬럼을 제안하면 정작 필요한 자리에서 아무것도 안 뜬다.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<string> ReferencedTables(string text)
|
||||
{
|
||||
var found = new List<string>();
|
||||
foreach (Match match in TableRefPattern.Matches(text))
|
||||
{
|
||||
var name = match.Groups[1].Value;
|
||||
// FROM ( 서브쿼리 처럼 이름이 아닌 것과, 키워드가 잡히는 경우를 걸러낸다
|
||||
if (SqlTokenizer.Keywords.Contains(name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!found.Contains(name, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
found.Add(name);
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 후보를 걸러 정렬한다 — 접두 일치를 부분 일치보다 앞에 둔다.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user