Skip to content

Diff Viewer ko

edgar.v edited this page Feb 28, 2026 · 3 revisions

Diff 뷰어

jvim에는 스크롤 동기화, 접기 동기화, hunk 탐색이 가능한 나란히 비교 diff 뷰어가 포함되어 있습니다.

CLI 사용법

# 두 JSON 파일 비교
jvimdiff file1.json file2.json

# JSON 정규화 건너뛰기 (원본 텍스트 비교)
jvimdiff --no-normalize file1.json file2.json

# JSONL 파일 비교
jvimdiff --jsonl file1.json file2.json

jvd 단축 명령도 사용 가능합니다.

정규화 vs 포맷

기본적으로 jvim은 비교 전 두 파일을 정규화합니다:

  • JSON을 파싱하고 indent=4sort_keys=True로 재직렬화
  • 키 순서 차이는 무시됨
  • 실제 값 차이만 표시됨

--no-normalize 사용 시:

  • JSON이 indent=4포맷팅되지만 키는 정렬되지 않음
  • 키 순서 차이가 diff로 나타남
  • 키 순서가 중요한 워크플로우에 유용

Diff 알고리즘

블록 기반 최적화

반복적인 구조를 가진 대규모 JSON 파일(예: 객체 배열)에서 jvim은 블록 기반 diff 최적화를 사용합니다:

  1. 블록 감지: 양쪽 파일에서 같은 들여쓰기 수준의 반복되는 {/[ 여는 괄호를 스캔
  2. 최소 임계값: 같은 들여쓰기 수준에 최소 4개 블록이 있어야 블록 모드 활성화
  3. 세그먼트 구축: 블록 경계(여는 {/[에서 닫는 }/]까지)에서 내용을 세그먼트로 분할
  4. 세그먼트 매칭: 개별 라인 대신 전체 세그먼트(문자열로 결합)에 SequenceMatcher 사용
  5. 세그먼트 내 diff: 매칭되었지만 다른 세그먼트 내에서 라인 단위 diff 수행

다음과 같은 파일에서 diff 품질이 크게 향상됩니다:

{
    "users": [
        { "name": "Alice", "age": 30 },
        { "name": "Bob", "age": 25 },
        ...수백 개 이상...
    ]
}

대용량 파일 폴백

총 라인 수(좌 + 우)가 50,000줄을 초과하면 diff 엔진은 전체 내용을 단일 REPLACE hunk로 처리합니다. 이는 매우 큰 파일에서의 과도한 계산 시간을 방지합니다.

라인 단위 Diff

충분한 블록 구조가 없는 파일에서는 표준 라인별 SequenceMatcher diff가 사용됩니다.

색상 코딩

색상 의미
빨간 배경 (#72261a) 삭제 — 왼쪽 파일에만 존재하는 줄
초록 배경 (#1e5c34) 삽입 — 오른쪽 파일에만 존재하는 줄
회색 배경 (#6a6a6a) 변경 — 파일 간 다른 줄
어두운 배경 (#2a2a2a) 필러 — 정렬을 위해 추가된 패딩 줄

필러 줄은 좌우 패널을 수직으로 정렬하기 위해 한쪽에 삽입되는 빈 줄입니다.

스크롤 및 커서 동기화

양쪽 패널이 자동으로 함께 스크롤되고 이동합니다:

  • 포커스된 패널이 스크롤 위치, 커서 행, 커서 열을 주도
  • 비포커스 패널이 매 렌더마다 _scroll_top, cursor_row, cursor_col을 미러링
  • cursor_col은 대상 라인 길이에 맞게 클램핑되어 범위 초과 방지
  • 이산 이벤트가 아닌 실시간으로 동기화

접기 동기화

한쪽 패널의 접기 작업이 다른 쪽에 미러링됩니다:

  • za (토글), zo (열기), zc (닫기): 양쪽 패널에 적용
  • zM (모두 접기), zR (모두 펼치기): 양쪽 패널에 적용
  • 접기 상태는 _sync_folds_to_target() API를 통해 동기화

자동 접기

초기 로드 시:

  1. 모든 구조가 접힘 (_fold_all_nested())
  2. Diff 영역이 선택적으로 펼쳐짐:
    • 하나 이상의 non-EQUAL 줄을 포함하는 접기가 열림
    • diff 내용이 있는 접힌 문자열이 펼쳐짐
  3. 양쪽 패널이 같은 접기 상태를 받음

기본적으로 변경 부분만 보여주고, 변경되지 않은 섹션은 접혀 있습니다.

Hunk 탐색

동작
]c 다음 diff hunk로 이동 (마지막 이후 첫 번째로 순환)
[c 이전 diff hunk로 이동 (첫 번째에서 마지막으로 순환)

상태 바에 표시: Hunk N/M (현재 hunk / 전체 hunk).

파일이 동일하면: "Files are identical".

패널 전환

동작
Tab 좌우 패널 간 포커스 전환

포커스가 전환될 때 동기화 메커니즘을 통해 스크롤 위치가 유지됩니다. 활성 패널은 타이틀 바 색상으로 구분됩니다 — 포커스된 패널은 파란색 타이틀 바, 비활성 패널은 회색 타이틀 바로 표시됩니다.

라인 번호

Diff 뷰어는 메인 에디터와 동일한 거터 시스템을 공유합니다:

  • 왼쪽 패널: 논리적 라인 번호와 JSONL 레코드 번호(JSONL인 경우) 표시
  • 오른쪽 패널: JSONL 레코드 번호만 표시 (filler 행으로 양쪽 라인 수가 동일하므로 논리적 라인 번호 생략)

내장 JSON Diff (EJ Diff)

Diff 뷰어에서 ej는 양쪽 패널에 동시에 동작합니다:

  1. 내장 JSON 문자열이 있는 줄에 커서 위치
  2. ej 입력 — 양쪽 EJ 패널이 열림
  3. 다른 패널의 같은 행에서 내장 JSON을 확인
  4. 양쪽 모두 해당 행에 내장 JSON이 있으면:
    • 두 내장 JSON 간 diff가 계산됨
    • 양쪽 EJ 패널에 색상 코딩된 diff가 표시됨
  5. 한쪽만 내장 JSON이 있으면:
    • 해당 쪽의 EJ 패널만 열리며 내용 표시 (diff 색상 없음)

중첩 EJ Diff 스택

메인 에디터와 마찬가지로 diff 뷰어도 중첩 EJ 레벨을 지원합니다:

  • 각 쪽이 자체 EJ 스택을 유지 (_left_ej_stack, _right_ej_stack)
  • 중첩된 ej를 열면 현재 내용이 스택에 푸시
  • 닫기(:q)하면 스택을 팝하고 이전 레벨 복원
  • 동기화 유지를 위해 양쪽 스택이 함께 팝

EJ 패널 동기화

EJ 패널은 메인 패널과 독립적으로 자체 스크롤 및 접기 동기화를 가집니다.

JSONL Diff

JSONL 파일은 레코드 단위로 diff됩니다:

  1. 양쪽 파일이 레코드로 분할
  2. 각 레코드가 indent=4로 포맷팅 (정규화 시 sort_keys 포함)
  3. SequenceMatcher가 레코드를 전체 단위로 매칭
  4. 매칭되었지만 다른 레코드는 내부적으로 라인 단위 diff
  5. 레코드 사이 빈 줄로 구분하여 표시
  6. 빈 구분 줄은 주변 내용의 diff 태그를 계승

자동 감지

Diff의 JSONL 모드는 어느 한쪽 파일이 .jsonl 확장자를 가지면 자동 감지됩니다. --jsonl로 강제할 수도 있습니다.

읽기 전용 모드

Diff 뷰어는 항상 읽기 전용입니다. 메인 패널과 EJ 패널 모두 read_only=True로 생성됩니다. 탐색, 검색, 접기는 정상적으로 동작하지만 편집 작업은 비활성화됩니다.


English |

Clone this wiki locally