05 Vim 기본 - 수정, 삭제 그리고 오퍼레이터

반응형

Normal Mode 오퍼레이터(모션 지정 명령)에 대한 이해

앞서 Vim Normal Mode 에서 커서를 이동시키는 방법과, Vim Insert Mode 로 진입하는 방법을 알아보았다. 이번에는 Normal Mode 의 기본 명령들에 대해서 알아보도록 한다. 

💡 이번 포스팅은 다분히 이론적일 수 있다. 하지만, Normal Mode 에서 명령어가 동작하는 원리를 이해하고 나면 훨씬 자유롭게 해당 명령어들을 응용할 수 있을 것이다. 이 포스팅이 [The Vim Way] 연재 중 가장 어려운 부분일 수 있지만, 당장은 본 포스팅의 스크린샷만 훑어보도록 하자. 구미가 당긴다면, 어렵더라도 꼭 이해하고 넘어가보도록 하자.

이 포스팅을 이해하고 나면 다음 명령어들을 활용할 수 있게 된다.

  • c - 모션을 활용하여 지정한 영역을 삭제하고 Insert Mode 로 진입
  • d - 모션을 활용하여 지정한 영역을 삭제

Vim 명령를 구분하는 기준

Vim Normal Mode 에서는 문서를 편집(문서의 내용을 변경)하기에 용이한 수정용 커맨드들을 제공한다. 이러한 수정용 커맨드들은 의미상 동일한 기능을 수행하면서도, 그 동작의 방법에 따라 크게 세 가지 기준으로 나눌 수 있다. 일단 그 기준들은 다음과 같다. 

  • 키를 누르는 즉시 수행되는지 - 모션 비지정형 커맨드(cf. 모션 지정형 커맨드 a.k.a. 오퍼레이터)
  • 특정 동작 후 insert 모드로 진입하는지 - 문자열 입력형 커맨드(cf. 문자열 비입력형 커맨드)

이 기준에 따라 명령어를 분류해두면, 동작방식이 서로 비슷하기 때문에 쉽게 기억할 수 있다. 아래서 각 기준을 상세히 설명한다.

모션 지정 여부에 따른 명령어 구분

첫번째 기준인 '키를 누르는 즉시 수행되는지'라는 기준은 그 커맨드가 키 입력 이후에 추가적으로 명령을 수행할 대상을 지정해야하는 커맨드인지 아닌지를 구분한다. 뒤에서 상술하겠지만, d 와 x 커맨드 모두 삭제라는 맥락상 동일한 명령을 수행하는데, x 는 '대상 비지정형 커맨드'이고, d 는 '오퍼레이터(대상 지정형 커맨드)'이다. 이 포스팅에서 사용할 용어인 '모션'은 Vim Normal Mode 에서 커서를 이동시키는 방법 에서 살펴본 대부분의 커서 이동법을 포함하는 vim 의 대상 지정 방법을 의미한다.

 

이렇게 분류되는 일련의 '오퍼레이터'들은 사실 간단하게 요약이 가능하다. 문장의 구조를 가져야 하기에 단일 키 입력 단독으로는 수행될 수 없는 명령들을 의미한다.

 

이후 포스팅에서 더 자세히 설명하겠지만, 먼저 삭제를 담당하는 명령어(x 와 d)를 가지고 오퍼레이터(대상 지정형 명령)과 비지정형 명령어가 동작하는 방식의 차이점을 살펴보자.

💡 이 포스팅에서만큼은, 용어 '오퍼레이터'의 모호한 의미를 명확하게 하기 위한 목적으로 '오퍼레이터(대상 지정형 명령)'으로 표현합니다. 이후 포스팅에서는 '오퍼레이터'라는 용어만을 사용하도록 합니다. 

모션 비지정형 명령어 동작 방식: Command

x 명령어를 통해서 대상 비지정형 명령어가 동작하는 방식을 확인해보자. 대상 비지정형 명령어는 다음 스크린샷으로 어렵지 않게 그 동작을 확인할 수 있다.

  • 명령어를 입력(x)한 순간 문서에 변화가 생겼으며
  • 여전히 Normal Mode 이다. (이는 곧바로 다른 명령의 입력을 대기하는 상태임)

이렇게 보면 Vim 을 사용하지 않는 일반 텍스트 편집 환경에서의 Delete 키와 별다를게 없어 보인다. 하지만 엄밀히 Normal Mode 에서 수행한 d 커맨드와 Insert Mode 에서 delete 키로 문자를 삭제하는 vim 의 관점에서는 분명한 차이가 있다. 이에 관련해서는 추후 'vim 에서의 명령 블록' 부분에서 자세히 알아본다.

vim 에서 한 글자 삭제하기 - x 는 누르는 즉시 커서 위치의 문자가 삭제된다. 추가적인 대상 지정이 필요하지 않다.

이와 같이 단일 키로 동작하는 명령어로는 s, c, r 정도가 되겠다. 각각 명령어들의 동작들이 특징을 갖고 있지만, 이는 추후 포스팅에서 다시 자세히 다루도록 한다.

💡 Vim 의 세계(생태계)에서는 이 포스팅에서 '모션 비지정형 명령'이라고 소개한 동작들을 단순히 'Command' 라고 명명하였습니다. 적어도 Vim 에서는 '명령'이란 해당 키 단독으로 동작하는 기능을 의미합니다.

모션 지정형 명령어 동작 방식: Operator

오퍼레이터(모션 지정형 명령어)의 대표로 d 커맨드를 살펴보자. normal mode 에서 d 를 입력하게 되면 하단 status bar 에 d 가 표시된다. 이는 vim 이 motion 을 대기하고 있음을 나타낸다. 그 다음 motion 으로 지정되지 않은 키, 가령 v 를 눌러보면 경고음과 함께 명령이 취소된다. 이로써 vim Normal Mode 에서는 d 입력 이후에 motion 이 입력되기를 기대하고 있고, 그 motion 은 한정되어있음을 의미한다.

d 명령어 이후에 해당 명령어가 작동할 범위를 지정한다.

Normal Mode 에서 d 키를 눌렀다는 것은 현재 커서가 위치한 위치에서부터 '삭제 명령을 시작'함을 vim 에게 알리는 것이다. 그럼 vim 은 해당 삭제 명령이 어디까지 적용될 것인지를 대기하고 있는 상태가 된다. 이 적용될 대상이 위 스크린샷에서처럼 Motion 에 해당한다. Motion 은 Normal Mode 에서의 이동 명령을 포함한다. 

 

기본적인 vim 의 이동방법이었던 h, j, k, l 은 motion 이 될 수 있다. 가령 dh 라는 명령은 '현재 커서의 왼쪽 문자(h)를 삭제(d)'라는 뜻이 된다. 같은 원리로 dj 라는 명령은 '현재 커서부터 아래 줄(j)을 삭제(d') 라는 명령이 된다. 영문법 순서대로 V+O(동사 이후 목적어) 형태로 이해할 수 있다.

d 키와 motion(h, j, k, l) 과의 조합

motion 은 Vim Normal Mode 에서 커서를 이동시키는 방법 에서 알아보았던 대부분의 커서 이동법을 의미한다. 마찬가지로 dw, de, db, dW, dE, dB 와 같이 이동 방법들과 조합하여 사용할 수 있다.

💡 dd 명령어로 한 줄 전체를 삭제할 수 있습니다. dd 명령에서 d 이후에 오는 d 는 모션은 아니지만, 연속된 dd 입력은 '한 줄 삭제'를 수행하도록 약속되어있습니다.

Vim Extra Motion - i & a

💡 VERY IMPORTANT! Vim 을 택스트에디터계의 혁명이라고 부른다면, 바로 이 기능 때문이라고 생각합니다. 명령어가 동작할 대상을 정확하게 보다 정확히 타겟팅 할 수 있습니다. 무엇보다 매우 '프로그래밍적'인데 프로그래머들에게는 매우 유용한데, 프로그래머들은 괄호나 따옴표를 사용하여 코드를 묶는 일이 많기 때문입니다. 괄호 안 또는 괄호를 대상으로 할 수 있는 명령을 수행할 수 있습니다.

상술했듯, Vim Normal Mode 에서 커서를 이동시키는 방법에서 소개한 컨트롤 조합키를 제외한(^B, ^F, ^U, ^D - ^는 ctrl 을 의미) 모든 커서 이동법이 Motion 에 포함된다. 이 모션들만으로는 동작할 수 없는 특별한 동작들을 위해 다음 모션들을 vim 은 추가로 지원한다. 단, 여기서 소개하는 모션은 특정 명령키 이후에만 동작한다.

 

Extra Motion 의 필요성 느껴보기

가령 다음과 같은 상황을 상상해보자. 다음 스크린샷처럼 animals 의 가운데 a 에 커서가 위치해 있는 상태에서 animals 를 지우고 싶다. 어떻게 할 수 있을까? 스크린샷처럼 커서를 단어의 맨 앞으로 이동한 뒤 dw (다음 단어 삭제) 를 입력했다. 해보면 알겠지만, 가운데 a 위치에서 dw 를 하면 anim(als) 의 괄호친 부분만 삭제되고, anim 부분만 남는다. 이 때 커서가 위치한 단어를 d 할 수 있는 방법이 있다. 다음 'i - in 모션' 을 보자

커서가 단어 중간에 위치할 때, 단어를 삭제하는 '쿨하지 않은' 방법

i 모션과 a 모션 (전치사로서의 in, a)

먼저 작동하는 모습을 직접 보자. 

vim diw 명령어 수행 동작 - i 는 in 을 의미한다. 보다 쿨하게 단어를 삭제했다.

커서가 위치한 '단어(w)' 를 전부 삭제했다. 이번엔 i 대신 a 를 사용해보도록 하자. 아래 스크린샷은 diw 와 daw 의 차이점을 보여준다.

diw 와 daw 의 차이점 - delete 'in' word & delete 'a' word

daw 도 마찬가지로 커서가 위치한 단어를 전부 지운다. 동일한 동작인가? 당신의 눈썰미가 좋다면 이미 파악했을 것이다. diw 는 단어 그 자체만을 삭제하지만, daw 는 단어 다음 공백까지 삭제했다. i 와 a 의 차이는 지워지는 대상의 범위에 차이가 있다. 각각 영어로 풀이해보면 delete 'in' word, delete 'a' word 가 된다. 적어도 vim 에서는 in 은 지정한 대상 '내부'를 의미하고, a 는 지정한 대상 '전체' 를 의미한다.

 

i 이후와 a 이후에 올 수 있는 일반 알파벳 키는 알파벳은 w, W, p, e 정도가 가능하다. "w 를 사용했으니, 다른 커서 이동 키(가령 b, e 등)도 동작하겠군." 이라고 생각할 수 있으나 그렇지는 않다. i, a 이후에 입력할 수 있는 키는 한정되어있다. 사실 여기까지는 그다지 감흥을 못느꼈을 수 있지만, 사실, i, a 모션 이후에 올 수 있는 더 강력한 대상들이 있다. 바로 브bracket-like, quote-like 키들이다. (, ), {, }, '', "", <> 이 그 대상이다. 다음을 보자.

Vim 영역지정자 모션

영역지정자 모션을 다시 풀어서 표현하자면 괄호류, 따옴표류 모션이라고 할 수 있다. 영어로는 bracket-like, quote-like 모션이라고 지칭할 수 있겠다. 역시 스크린샷을 먼저 보는 것이 이해가 빠를 것이다.

di + {영역지정자} 명령을 사용하여 영역지정자로 둘러싸인 부분을 삭제할 수 있다.

특히, 프로그래머는 코딩을 할 때 무엇인가를 감싸는 코드를 자주 다루게 된다. 위 스크린샷과 같이 영역지정자(괄호, 따옴표)로 감싸진 영역을 지정하여 명령(여기서는 삭제)을 수행할 수 있다. di' 라고 입력한다는 것은 vim 에게 "현재 커서가 위치한 따옴표('')로 감싸진 영역 내부를 삭제해"라는 의미가 된다. 마찬가지로 `di]` 라고 입력한다는 것은 어떤 의미일지 한번 추측해보자.

 

이렇게 특정 영역(괄호 영역, 따옴표 영역) 내부를 삭제할 수 있는 방법을 알아보았다. 이제 당신은 해당 영역을 감싸는 기호(괄호, 따옴표)와 함께 해당 영역을 삭제하고 싶을 수 있다. 이 때 da + {영역지정자} 모션을 사용할 수 있다. 이 또한 스크린샷으로 바로 의미를 파악해보자.

da + {영역지정자} 명령을 사용하여 지정한 대상을 영역지정자를 포함하여 삭제할 수 있다.

da] 의 의미는 'delete a (angle) bracketed range' 쯤이 되겠다. 영역지정자와 함께 해당 영역에 명령(여기서는 삭제)을 수행하고자 한다면 a 로 시작하는 모션을 사용할 수 있다.

Extra Motion 정리

이상으로, Vim 에서 i, a 가 포함된 Extra Motion 을 다루는 방법을 알아보았다. 이제 오퍼레이터(모션 지정형 커맨드)에서 모션 부분에 입력할 수 있는 모션으로는 기본 커서 이동법과 i + {영역지정자}, a + {영역지정자}  임을 알았다.

 

사실, 모션에 f, t, F, T 를 활용하여 직접 특정 문자까지 그 범위를 지정하는 것도 가능한데, 이는 추후 포스팅에서 별도로 다루도록 하겠다.

 

이와 같은 모션을 활용할 수 있는 명령어로는 d 와 함께, c, v 가 있다. 여기에 별도로 surround 라는 vim plugin 을 활용하는 경우(추후 별도 포스팅)에도 모션을 활용한다.

Vim Motions For Operator

다음은 vim 의 오퍼레이터(모션 지정형 커맨드)의 motion 으로 활용될 수 있는 대상들을 리스트업한 것이다. Vim Normal Mode 에서 차례로 {모션지정형 커맨드} + {모션} 을 입력하는 형태로 사용할 수 있다. 대표적인 오퍼레이터(모션지정형 커맨드)는 c, d, v 이며 이 명령어 이후 아래 모션을 조합하여 사용하면 된다. (e.g. cw 또는 cE 또는 dip 등) 

모션으로 활용가능한 기본 커서 이동 명령

  • h, j, k, l
  • w, W, b, B, e, E
  • gg, G
  • 0, ^, $

글을 구성하는 단위를 활용한 모션

  • iw, iW, ip, ie
  • aw, aW, ap, ae

영역지정자를 활용한 모션

  • a), a], a}, a>, a', a"
  • i), i], i}, i>, i', i"

(괄호는 닫히는 부분만으로 표시했지만, 열리는 부분으로도 사용 가능)

Insert Mode 진입 여부에 따른 명령어 구분

💡 이 문단에서 설명하는 '명령'이란 Vim 에서의 Command(키 단독 수행)와 Operator(모션 지정 필요)를 모두 포함합니다. 

명령이 수행된 이후에 insert mode 모드로 진입하는지의 여부에 따라서 명령을 구분할 수 있다. 그렇지 않은 명령은 명령어 수행 후 그대로 normal mode 에 남아있게 된다. 앞서 Vim Insert Mode 로 진입하는 방법 에서 살펴보았던 방법 중에 o 커맨드는 사실 '명령어 수행 뒤 insert 모드로 진입하는 - typing type' 커맨드에 해당한다. 실제로, 문서의 변경이 발생(커서 아래 새 줄 삽입)한 이후에 insert mode 로 진입했기 때문이다. 이것은 해당 명령이 사용자로부터 특정 문자열을 입력받아 처리된다는 것을 의미한다. 

 

앞서 Insert Mode 로 진입하는 가장 기본적인 방법인 i, a, I, A 에 대해서 알아보았다. 이 명령들이 동작하는 모습을 보고 싶다면 Vim Insert Mode 로 진입하는 방법을 참고하자. 해당 링크에서 다루는 Insert Mode 진입법은 다음과 같다.

 

  • i - 커서 바로 왼쪽에 입력하기
  • a - 커서 바로 오른쪽에 입력하기
  • I - 줄의 맨 앞에 입력하기
  • A - 줄의 맨 뒤에 입력하기
  • o - 아래 줄에 새 줄을 삽입한 뒤 입력하기
  • O - 위 줄에 새 줄을 삽입한 뒤 입력하기 
  • s - 삭제하고 입력하기
  • S - 현재 줄을 전부 삭제하고 입력하기
  • C - 현재 커서의 오른쪽 전부를 삭제하고 입력하기

위 리스트를 살펴보면 모두 소문자와 대문자가 대응되는 리스트가 존재하는 것을 알 수 있는데, c 만 그렇지 않다. c 가 바로 위에서 장황하게 설명한 바로 오퍼레이터(모션 지정형 커맨드)이고, 이에 대한 별도의 설명이 필요하기에 앞선 포스팅에서 다룰 수 없었다. 바로 아래에서 c 명령에 대해 알아보자.

c - 모션 지정하여 삭제 후 입력하기

말이 필요 없다. 여기도 스크린샷부터 보도록 하자.

ci + {영역지정자} 명령으로 영역지정자 내부에 해당하는 부분을 삭제한 뒤, 바로 insert mode 로 진입한다.

따옴표 안의 문자들을 한꺼번에 삭제하고, 대체하고자 하는 내용으로 변경하였다. 다음과 같은 응용도 가능하다.

ca + {영역지정자] 명령으로 영역지정자를 포함한 영역을 삭제 후 바로 insert mode 로 진입한다.

굳이 위 응용을 보여준 이유는 단 하나다, 이제 모션을 이해했으니, 무궁무진한 응용이 가능할 것이다.

💡 cc 명령어로 한 줄 전체를 삭제한 뒤 insert mode 로 진입할 수 있습니다. dd 명령과 마찬가지로 cc 에서 c 이후에 오는 c 는 모션은 아니지만, 연속된 cc 입력은 '한 줄 삭제 후 insert mode 로 진입'을 수행하도록 약속되어있습니다.

emacs 나 다른 편집기에 비해 러닝커브가 낮다라고는 하지만, 필자와 같은 범인들에게는 이조차 어찌보면 넘기 힘든 산일 수도 있겠다싶은 생각이 든다. 하지만, 오퍼레이터(motion 지정형 명령)는 c, d, v 임과, 이 오퍼레이터 이후에는 '모션'이 온다는 것, 그리고 모션은 일반 커서 이동과 i + {영역지정자}, a + {영역지정자} 임을 기억한다면, 이번 포스팅의 목적을 달성한 셈이다.

 

다음에는 Vim 의 Visual Mode 에 대해서 알아보도록 하자.

반응형

Designed by JB FACTORY