using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; namespace MergeHub.Models { /// /// 비교 화면의 정렬 행 목록. 로 통째로 갈아 끼우고 알림은 한 번만 보낸다. /// /// /// 편집기에서 엔터를 치거나 손을 멈출 때마다 줄을 다시 정렬하는데, 예전에는 Clear 뒤 한 줄씩 Add 해서 /// 1,800줄이면 "하나 추가됨" 알림이 1,800번 가고 칸 목록 넷이 알림마다 반응했다. 재서 보니 재정렬 한 번 0.37초 가운데 /// 그 알림들이 0.33초였다(파일 비교 자체는 0.01초) - 엔터마다 화면이 0.4초씩 멈춰 "글자가 뒤따라오는" 까닭(2026-09-30). /// /// public sealed class MergeLineCollection : ObservableCollection { /// 가운데(바뀐 줄) 이보다 많으면 줄마다 빼고 넣지 않고 통째로 갈아 끼운다 - 알림이 줄 수만큼 가면 도로 느려진다. public const int PatchLimit = 200; /// /// 새 정렬 결과를 넣되, 번호 말고는 모든 값이 같은 줄은 기존 객체를 그대로 두고 번호만 고친다(2026-09-30). /// /// /// 통째로 갈아 끼우면() 줄 객체가 모두 새것이라 칸 목록이 보이는 줄 요소를 전부 다시 만든다 - /// 재정렬 뒤 화면이 다시 그려지기까지 0.15초 가운데 0.12초가 그것이었다(색칠은 0.02초). 엔터를 치면 위 · 아래 줄은 /// 그대로이고 끼운 자리 아래는 번호만 밀리므로, 앞 · 뒤로 같은 줄을 걸러 내고 가운데만 빼고 넣는다. /// 값이 하나라도 다른 줄(반영 표시 · 단어 차이 · 규칙)은 새 객체로 바꾼다 - 옛 객체에 새 값을 옮겨 적다 하나라도 빠뜨리면 틀린 색이 남는다. /// /// public void Patch(IList rows) { var oldCount = Count; var newCount = rows.Count; var head = 0; while (head < oldCount && head < newCount && this[head].SameStateExceptNumbers(rows[head])) head++; var tail = 0; while (tail < oldCount - head && tail < newCount - head && this[oldCount - 1 - tail].SameStateExceptNumbers(rows[newCount - 1 - tail])) tail++; var oldMiddle = oldCount - head - tail; var newMiddle = newCount - head - tail; if (oldMiddle + newMiddle > PatchLimit) { ReplaceAll(rows); return; } for (var i = 0; i < head; i++) this[i].TakeNumbersFrom(rows[i]); for (var k = 0; k < tail; k++) this[oldCount - 1 - k].TakeNumbersFrom(rows[newCount - 1 - k]); for (var i = 0; i < oldMiddle; i++) RemoveAt(head); for (var i = 0; i < newMiddle; i++) Insert(head + i, rows[head + i]); } public void ReplaceAll(IEnumerable rows) { CheckReentrancy(); Items.Clear(); foreach (var row in rows) Items.Add(row); OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count))); OnPropertyChanged(new PropertyChangedEventArgs("Item[]")); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } } }