Practical Vim 팁 요약 시리즈 - Macros

10 Feb 2017

Vim 3D

  1. CHAPTER 11. Macros
    1. Tip 65. Record and Execute a Macro
      1. Capture a Sequence of Commands by Recording a Macro
      2. Play Back a Sequence of Commands by Executing a Macro
        1. Execute the Macro in Series
        2. Execute the Macro in Parallel
    2. Tip 66. Normalize, Strike, Abort
      1. Normalize the Cursor Position
      2. Strike Your Target with a Repeatable Motion
      3. Abort When a Motion Fails
    3. Tip 67. Play Back with a Count
    4. Tip 68. Repeat a Change on Contiguous Lines
      1. Record One Unit of Work
      2. Execute Macro in Series
      3. Execute Macro in Parallel
      4. Deciding: Series or Parallel
    5. Tip 69. Append Commands to a Macro
    6. Tip 72. Edit the Contents of a Macro
      1. The Problem: Nonstandard Formatting
      2. Paste the Macro into a Document
      3. Keyboard Codes in Macros
      4. Edit the Text
      5. Yank the Macro from the Document Back into a Register
    7. 시리즈 포스트를 한 장의 페이지로도 정리합니다.

CHAPTER 11. Macros

Vim 매크로를 사용하면 레지스터에 원하는 만큼의 키 스트로크를 기록한 다음 다시 재생할 수 있다.

매크로는 일련의 행이나 문단, 파일 전체에서 반복해서 실행할 때 이상적으로 사용할 수 있다. 매크로는 일련의 파일에서 실행하 거나 병렬로 호출할 수 있다. 일련의 목표에 매크로를 실행하는 두 가지 방법이 있다. 일련의 작업을 반복 실행하거나 여러 번 병렬로 실행할 수 있다.

일련의 명령을 기록하다 보면 실수할 때도 있다. 실수한 것을 버릴 필요는 없다. 기존 매크로의 끝에 쉽게 명령을 추가할 수 있다. 더 많이 수정하려면 매크로를 문서에 붙여넣어 명령을 편집한 다음에 다시 레지스터로 복사해서 사용할 수 있다.

Tip 65. Record and Execute a Macro

Capture a Sequence of Commands by Recording a Macro

q 키는 ‘기록’과 ‘정지’ 버튼 모두로 동작한다. 키 입력의 기록을 시작하려면, q{reister}를 입력한다. register는 매크로가 저장되는 레지스터의 주소이다. 제대로 했다면 상태 줄에 ‘기록중(recording)’이라는 단어가 표시된다. 실행하는 모든 명령은 기록을 멈추기 위해 q를 다시 누를 때까지 캡처된다.

매크로 저장과 재생

qa레지스터 a에 매크로 기록을 시작한다. 첫 번째 행에서 두 가지를 변경한다: 세미콜론을 끝에 넣고 앞에 var를 추가했다. q를 눌러 매크로 기록을 끝낸다(:h q).

레지스터의 내용을 보려면 다음과 같이 한다.

:reg a
--- Registers ---
"a   A;^[Ivar ^[

읽는 것이 쉽지 않지만, 앞서 입력한 명령의 순서는 알 수 있을 것이다. ^[ 기호는 <Esc> 키이다.

Play Back a Sequence of Commands by Executing a Macro

@{register} 명령은 특정 레지스터의 내용을 실행한다(:h @). 가장 마지막에 실행한 매크로를 반복하려면 @@를 사용할 수도 있다.

피상적으로 이것은 Dot Formula와 닮았다. 그것은 하나의 키 입력(j)으로 움직이고 두 개의 키(@a)로 행동한다. 나쁘진 않지만 개선의 여지가 있다.

매크로를 여러 번 실행하기위한 두 가지 기법이 있다. 설정은 각 기술마다 약간씩 다르지만 더 중요한 것은 오류가 발생할 때 다르게 반응한다는 것이다. 크리스마스 트리 라이트와의 비교를 통해 차이점을 설명한다.

싸구려 파티 조명을 구입하면 직렬로 연결될 가능성이 있다. 전구 하나가 날아가면 모두 나가 버린다. 프리미엄 세트를 구입하면 병렬 연결이 가능해진다. 그것은 어떤 전구가 꺼져도, 나머지는 영향받지 않음을 뜻한다.

매크로를 여러 번 실행하는 두 가지 기술을 구별하기 위해 전자 분야의 직렬(in series)과 병렬(in parallel)을 빌렸다. 매크로를 직렬로 실행하는 기술은 약하다. 병렬로 실행하는 기술은 보다 안정적이다.

Execute the Macro in Series

매크로 기록은 하나의 단위 작업을 하도록 로봇을 프로그래밍하는 것과 같다. 마지막 단계로 로봇이 컨베이어 벨트를 움직여 다음 항목을 손에 닿도록 지시한다. 이러한 방식으로, 우리는 하나의 로봇이 유사한 아이템에 대해 일련의 반복 작업을 수행하게 할 수 있다.

이런 접근법은 예상치 않은 일이 일어나면 경보를 울리고 작업을 중단하는 결과를 낳는다. 컨베이어 벨트 위의 항목을 여전히 조작할 필요가 있을 때도 작업이 중지된다.

Execute the Macro in Parallel

매크로를 병렬로 실행하면 마치 컨베이어 벨트가 전혀 필요없는 것처럼 보인다. 대신, 우리는 같은 단순한 작업을 하도록 프로그래밍된 로봇 집단을 배치한다. 각자에게 할 일이 하나씩 주어집니다. 각 로봇은 하나의 일만 주어진다. 성공하면 아주 좋다. 실패해도 상관없다.

내부적으로 Vim은 두 기술 중 어떤 것을 사용하더라도 매크로를 순차적으로 실행한다. 병렬이라는 용어는 병렬 회로의 견고함을 유추하기 위한 것이다. Vim이 여러 변경 사항을 동시에 실행한다는 것은 아니다.

Tip 66. Normalize, Strike, Abort

매크로를 실행하면 Vim은 일련의 저장된 키 입력을 맹목적으로 반복한다. 조심하지 않으면 매크로를 재생할 때의 결과가 예상과 다를 수 있다. 그러나 더 유연한 매크로를 만들어 각 상황에 맞는 작업을 수행할 수 있다.

황금률은 매크로를 기록 할 때 모든 명령이 반복 가능한지 확인하는 것이다.

Normalize the Cursor Position

매크로 기록을 시작하자마자 다음 질문을 한다: 어디에 있고, 어디에서 왔으며, 어디로 가고 있나? 어떤 일을 하기 전에, 다음 명령이 기대한대로 작동할 수 있도록 커서가 놓여 있는지 확인한다.

이는 커서를 다음 검색 일치(n) 또는 현재 행의 시작(0) 또는 현재 파일의 첫 번째 행으로 이동시키는 것(gg)을 말하는 것일 수 있다. 항상 원점에서 시작하면 매번 올바른 대상을 쉽게 공략할 수 있다.

Strike Your Target with a Repeatable Motion

Vim은 텍스트 파일을 돌아다니는 모션 명령이 많다. 제대로 사용해야 한다.

계속 l 키만 두들기는 것 같은 일은 하지 말아야 한다. Vim은 맹목적으로 키 입력을 실행한다는 것을 기억한다. 오른쪽으로 10 문자 이동하면 매크로를 기록할 때 필요한 위치로 이동할 수 있지만 나중에 다시 재생할 때는? 다른 맥락에서, 커서를 오른쪽으로 10 칸 움직이면 마크가 넘어가버리거나 미치지 못할 수 있다.

w, b, ege와 같은 단어 단위 동작은 문자 단위 hl 동작보다 유연하다. 모션 0 다음 e가 기록되면 매크로를 실행할 때마다 일관된 결과를 기대할 수 있다. 커서가 현재 행의 첫 번째 단어의 마지막 문자로 위치한다. 단어의 문자 개수에 관계없이 한 단어 이상 포함된 행에서는 문제가 되지 않는다.

검색을 사용해 이동하고, 텍스트 개체를 사용한다. 최대한 유연하고 반복 가능한 매크로를 만들기위한 Vim의 모션을 적극적으로 활용한다. 잊지 않는다: 매크로를 기록할 때 마우스 사용은 금지!

Abort When a Motion Fails

모션이 실패할 수 있다. 예를 들어 커서가 파일의 첫 번째 행에 있으면 k 명령은 아무 것도 하지 않는다. 커서가 파일의 마지막 줄에 있을 때도 마찬가지이다. 기본적으로 동작이 실패하면 Vim에서 경고음을 울린다. ‘visualbell’ 설정으로 음소거를 할 수 있다(:h ‘visualbell’).

매크로가 실행되는 동안 모션이 실패하면 Vim은 나머지 매크로를 중단한다. 이것은 버그가 아니라 기능이라고 생각한다. 매크로를 현재 상황에서 실행해야하는지 여부에 대한 간단한 테스트로 모션을 사용할 수 있다.

이 예제를 고려해보자: 먼저 패턴을 검색한다. 문서에 10 개의 패턴일치가 있다고 가정해보자. 마지막 검색을 반복하는 n 명령으로 매크로 기록을 시작한다. 일치 항목에 커서가 이동하면 텍스트를 약간 변경하고 매크로 기록을 끝낸다. 편집을 하고나면 이 텍스트 영역은 더 이상 검색 패턴과 일치하지 않는다. 이제 문서에는 9 개의 일치 항목만 있다.

매크로를 실행하면 다음 매치로 건너 뛰고 동일한 변경을 한다. 이제 문서에는 8 개의 일치 항목만 있다. 일치 항목이 남아 있지 않을 때까지 매크로를 반복해서 실행한다. 이제 매크로를 실행하려고하면 더 이상 일치가 없으므로 n 명령이 실패한다. 매크로는 중단된다.

매크로가 a 레지스터에 저장되었다고 가정해보자. @a를 10 번 실행하는 대신 앞에 숫자를 붙인다: 10@a. 이 기술의 장점은 매크로를 몇 번이나 실행하는지에 대해 신경쓰지 않을 수 있다는 것이다. 숫자에 신경쓰지 마라. 중요치 않다! 100@a1000@a를 실행할 수 있고, 같은 결과가 나온다.

Tip 67. Play Back with a Count

Dot Formula가 작은 횟수의 반복에서 효율적인 편집 전략이 될 수 있지만, 숫자와 같이 실행할 수는 없다. 단순한 일회용 매크로를 기록하고 카운트로 다시 재생함으로써 이 한계를 넘을 수 있다.

x = "("+a+","+b+","+c+","+d+","+e+")";

Dot Formula를 배울 때와 같이 이 예제를 해결할 수 있지만, 실행 횟수를 사용할 수 없을까? 이 명령을 가장 간단하게 매크로로 전환하는 방법은 qq;.q 명령이다. qq는 이 후 입력을 q 레지스터에 기록한다. 이제 ;.을 입력하고 마지막으로 q로 기록을 종료한다. 이제 숫자와 함께 매크로를 실행한다: 11@q.;.를 11번 실행한다.

점 공식을 매크로로

; 명령은 f+ 검색을 반복한다. 커서가 행의 마지막 + 문자 뒤로 오면 ; 모션이 실패하고 매크로는 정지한다.

여기서는 매크로를 10 번 실행하려고 한다. 그러나 우리가 11 번 다시 실행해도, 마지막 실행은 중단 될 것이다. 즉, 매크로가 10 이상으로 호출되기만 하면 작업을 완료할 수 있다.

매크로를 실행해야하는 정확한 횟수를 계산하고 싶은 사람은 없을 것이다. 일을 끝내기에 충분하다고 생각하는 횟수를 주면 된다. 나는 타이핑하기 쉽기 때문에 22를 자주 사용한다. 키보드에서 @2 문자는 같은 버튼이다.

Tip 68. Repeat a Change on Contiguous Lines

매크로를 기록한 후 각 행에서 재생하는 것으로 여러 행에서 같은 변경을 반복할 수 있다. 매크로를 실행하는 두 가지 방법이 있다: 직렬 또는 병렬

Record One Unit of Work

먼저 첫 행에서 모든 변경을 기록한다.

모션이 포함된 매크로

모션의 사용에 주목하라. 0 명령으로 행의 가장 앞으로 이동하는 것으로 시작한다. 항상 같은 위치에서 시작하여 반복할 수 있는 매크로를 작성한다.

다음 모션은 f.이다. l 명령으로 한칸만 이동해도 되지만 두 개의 키입을 사용한 것은 반복 가능성 때문이다. 예제에서는 1 행부터 4 행까지만 있다. 그러나 숫자가 두 자리 이상일 때를 가정하면?

1. one
2. two
...
10. ten
11. eleven

9 번째 행까지는 0l 명령을 사용할 수 있다. 하지만 10 번째 행부터는 목표에 미치지 못한다. 반면 f.는 모든 행에서 동작하고, 세 자리 이상까지도 계속 동작한다.

f. 모션은 안전 장치도 추가한다. 현재 행에서 . 문자를 못찾는다면 오류를 발생시키고 매크로 실행이 중단된다.

Execute Macro in Series

매크로를 실행하려면 @a를 입력할 수 있다. @a 명령을 3 번 실행할 수 있지만, 3@a가 더 빠르다.

이번엔 주석을 포함한다고 가정하자.

1. one
2. two
// break up the monotony
3. three
4. four

매크로는 주석이 있는 3 번째 행에서 멈춘다.

Execute Macro in Parallel

매크로를 처음부터 다시 작성한다. 마지막 j 명령을 생략한다.

병렬 매크로

선택 영역의 각 행에서 매크로를 실행하기 위해 :normal @a 명령을 사용한다.

앞에서는 5@a 명령으로 매크로를 직렬로 5 번 반복했다. 3 번째 반복에서 매크로가 중지하였다. 이번에는 병렬로 5번 반복했다. 각 행마다 매크로의 호출은 다른 매크로와 독립적이다. 따라서 3 번째 반복에서 실패한 것은 다른 것에 영향을 주지 않는다.

Deciding: Series or Parallel

여러 항목에서 병렬로 실행하는 것은 더욱 강력하다. 그러나 매크로를 실행할 때 오류가 발생할 때 알람을 울리길 원할 수 있다. 직렬로 실행하면 오류가 언제 어디에서 발생하는지 명확히 알 수 있다.

Tip 69. Append Commands to a Macro

매크로를 기록할 때 중요한 단계를 놓치는 경우가 있다. 모든 것을 처음부터 다시 기록할 필요가 없다. 대신 기존 매크로 끝에 명령을 추가할 수 있다.

먼저 레지스터 a에 등록된 매크로를 확인한다.

:reg a
"a 0f.r)w~

qa를 입력하면 a 레지스터를 덮어쓰게 되지만, qA를 입력하면 a 레지스터의 기존 내용에 추가할 것이다.

Tip 72. Edit the Contents of a Macro

The Problem: Nonstandard Formatting

Tip. 68의 상황으로 돌아간다. 레지스터 a에 매크로가 저장되어 있다. 이제 양식이 살짝 어긋난 아래의 문서를 확인한다.

macros/mixed-lines.txt

1. One
2. Two
3. three
4. four

~ 명령 대신에 vU 명령을 사용해 매크로를 업데이트해보자. 이 명령은 현재 커서가 위치한 글자를 대문자로 변환한다(:h v_U).

Paste the Macro into a Document

레지스터 a에 저장된 매크로를 변경하려면 플레인 텍스트로 편집할 수 있도록 문서에 붙여넣어야 한다.

먼저 G를 눌러 문서의 끝으로 이동한다. 이제 레지스터 a의 내용을 새 행에 붙여넣는다. 가장 간단한 방법은 :put 명령을 사용하는 방법이다.

:put a

"ap 명령을 사용하지 않았다. p 명령은 현재 행의 커서 다음에 레지스터의 내용을 붙여 넣는다. 반면에 :put 명령은 항상 현재 행의 아래에 붙여 넣는다.

Keyboard Codes in Macros

이 예제에서는 상대적으로 단순한 레지스터를 이용했다. 이 방법은 큰 매크로를 편집할 때 사용하면 문서가 쉽게 지저분해진다. ‘Tip 70. 파일 묶음을 대상으로 작업 처리하기’에서 녹화한 매크로를 보면 그런 문제를 확인할 수 있다.

:rega
--- Registers ---
"a      Omoul<80>kb<80>kbdule Rank^[j>GGoend^[

조금 이상하지 않은가? 우선 ^[ 기호가 여러 번 나온다. <Esc><C-[> 어느 것을 누르던지 이스케이프 키를 표현하는 Vim의 방법이다.

<80>kb는 백스페이스 키이다. 키입력을 익혀라. 이 매크로를 기록 할 때 “moul”을 입력하여 시작했습니다. 실수를 알고 나서 백스페이스 키를 두 번 누른 다음 “dule”이라는 단어를 입력했다.

이 행동은 실제 결과가 아닙니다. 이러한 키 입력을 재생하면 Vim은 내 실수를 재현하고 수정한다. 최종 결과는 똑같다. 그러나 그것은 레지스터를 읽기 어렵고 편집하기 까다로워 진다.

Edit the Text

이제 매크로를 플레인 텍스트로 편집할 수 있다.

Yank the Macro from the Document Back into a Register

명령을 원하는 순서로 수정했다면 이 내용을 다시 레지스터로 붙여넣을 수 있다. 가장 간단한 방법은 "add (또는 :d a)를 실행하는 것이지만, 나중에 문제가 발생할 수 있다. dd 명령은 줄 단위 삭제를 수행한다. 레지스터에 ^J 꼬리가 생긴다.

:reg a
0f.r)wvUj^J

이 문자는 줄바꿈을 의미한다. 대부분의 상황에서 중요하지 않지만, 때때로 이 줄바꿈 꼬리은 매크로의 의미를 바꿀 수 있다. 예방 차원에서, 문자 단위 복사(yank)를 사용하여 문서에서 다시 레지스터로 가져오는 것이 더 안전한 방법이다.

0 명령 다음에 "ay$를 실행하여 개행을 제외한 모든 문자를 복사한다. 모든 내용을 a 레지스터에 저장한 후, dd로 문서의 행을 삭제한다.

Vim의 레지스터는 더 이상 단순한 텍스트 문자열의 보관함이 아니기에 Vim 스크립트를 사용하여 프로그래밍 방식으로 조작할 수도 있다. 예를 들어, substitute() 함수(이것은 :subsititute 명령과 다르다. :h substitute())를 사용하여 앞서 작성한 매크로와 동일한 작업을 다음과 같이 처리할 수 있다.

:let @a=substitute(@a, '\~', 'vU', 'g')

이 접근 방식이 흥미롭게 느껴진다면 :h function-list에서 더 자세히 살펴보자.

시리즈 포스트를 한 장의 페이지로도 정리합니다.

Share this:

comments powered by Disqus