텍스트 오브젝트

vim의 가장 독특한 기능 중 하나를 꼽으라면 “텍스트 오브젝트”를 취급하는 기능입니다. 예를 들어 di) 같은 명령으로 괄호 내부의 텍스트를 삭제하거나, dd 를 사용하여 한 줄 전체를 지우는 것 등이 있습니다. 이러한 동작을 커스텀 함수를 통해서 사용할 수 있을까요?

예를 들어 \u 라는 키 맵을 URL을 브라우저로 여는 동작으로 만든다고 칩시다. 그렇다면 \ui] 를 사용해서 대괄호로 둘러싸인 내부의 URL을 브라우저로 열 수 있다면 좋겠습니다. \u$ 를 써서 현재 커서 위치로부터 줄 끝까지를 URL로 잡을 수도 있겠고, 혹은 \uu를 사용하여 한 줄 전체를 사용할 수 있겠죠.

how it works

텍스트 오브젝트를 사용하는 노멀 명령은 흔히 ‘연산자’라고 부릅니다. d3w 라는 명령은 delete 3 * word 로 해석되어 커서 위치로부터 3개의 단어를 삭제한다는 뜻이지요. 텍스트 오브젝트를 피연산자로 보는 이 관점은 다시 연산자와 오브젝트가 각각 카운트 값을 가지는 형태로 정말이지 온갖 방법으로 확장 가능해집니다. 이러한 연산자에는 다음과 같은 것들이 있습니다.

  • c (변경), d (삭제), y (복사)
  • ~ (대소문자 반전) g~(대소문자 반전) gu(소문자화) gU(대문자화)
  • gq(텍스트 포맷) gw(텍스트 포맷, 커서 이동 안함)
  • >(들여쓰기) <(내어쓰기)
  • zf(폴드 정의하기)
  • g@(커스텀 동작)

커스텀 동작은 'operatorfunc' 옵션이 있는 경우, 이 옵션의 값을 사용해서 텍스트 오브젝트를 조작할 수 있게 합니다. operatorfunc( 줄여서 'opfunc') 옵션의 값은 다름 아닌 함수가 됩니다. 특정한 사용자 정의 함수를 작성하고, 함수를 이 옵션의 값으로 지정해 놓으면 “g@” 명령을 사용해서 조작합니다.

  1. opfunc 옵션으로 지정된 함수는 텍스트 오브젝트의 ‘타입’을 인자로 받습니다. 이는 텍스트 오브젝트가 글자 단위인지, 줄단위인지, 비주얼블럭 단위인지 등을 나타냅니다.
  2. 함수 내에서 텍스트 오브젝트의 시작과 끝은 각각, '[, '] 마커로 참조할 수 있습니다.

이러한 기능을 주로 키맵에 연결하고, 여러 기능이 이런식으로 작동하려면 결국 키 맵에서 opfunc를 설정하고 g@ 를 실행하도록 해야 합니다.1g@ 명령은 ‘operatorfunc’ 옵션에서 지정한 함수를 호출하는 명령입니다. 이를 위해 키맵이 어떤 함수를 실행하면서 함수 내에서 normal g@ 를 쓰는 방법도 있겠지만, expression 키 맵을 쓰는 것이 가장 깔끔합니다.

간단한 예제를 하나 보겠습니다. 아래 s:objfunc() 함수는 텍스트 오브젝트를 처리하는 연산자로 작동하는 기능입니다. 예제에서는 이 함수를 <F5> 키를 누를 때 발동하는 것으로 설정합니다.

이 설정 아래에서 <F5>iw를 누르게 되면 다음과 같이 작동하게 됩니다.

  1. 우선 <F5> 를 누르는 시점에 키 맵에 의해 s:objfunc() 가 인자 없이 먼저 호출됩니다. 이 동작에서는 함수 내부에서 'operatorfunc' 옵션에 s:objcfunc 함수를 세팅하고 'g@' 를 리턴합니다.
  2. 표현식 키맵의 결과로, <F5> 키를 누르고 나면 g@ 를 누른 것과 같은 효과가 납니다. 이 상태에서는 연산할 텍스트 오브젝트 입력을 기다립니다.
  3. iw 가 입력됩니다. 결과적으로는 g@iw 가 입력된 것이니 <SID>objfunc(type='char') 가 호출되는 셈입니다.

아래는 예제 코드입니다. 대부분의 텍스트 오브젝트 연산자는 이 방식대로 만들게 됩니다.

function s:txtobj(type='')
    if a:type == ''
        let &operatorfunc = expand('<SID>') .. 'txtobj'
        return 'g@'
    endif
    call popup_dialog('triggered: ' .. a:type, #{time: 1000})
endfunction


nnoremap <expr> <F5> <SID>txtobj()

Read more

워드프레스에서 고스트로 이전

워드프레스에서 고스트로 이전

이 글을 쓰면서도 믿기 힘든 사실인데, 블로그라는 걸 처음 시작한지가 20년이 되었습니다. 이글루스에서 처음 시작했다가, SK컴즈가 인수한다고 발표함과 동시에 워드프레스로 플랫폼을 옮겼죠. 워드프레스오 옮긴 이후에는 호스팅 환경을 이리 저리 옮기긴 했지만 거의 18년 가까이 워드프레스를 사용해온 것 같습니다. 그 동안 워드프레스는 블로깅 툴에서 명실상부한 범용CMS로 발전했습니다. 사실 웬만한 홈페이지들은 이제

By sooop
띄어쓰기에 대한 생각

띄어쓰기에 대한 생각

업무 메일을 쓸 때 가장 많이 쓰는 말 중에 하나가 메일 말미에 ‘업무에 참고 부탁 드립니다.‘인데요, 어느 날부터 아웃룩에서 이 ‘부탁 드립니다’가 틀렸다고 맞춤법 지적을 하기 시작했습니다. 맞는 말은 ‘부탁드립니다’라고 붙여 쓰는 거라고. 사실 아래아한글 시절부터 이전의 MS워드까지, 워드프로세서들의 한국어 맞춤법 검사 실력은 거의 있으나 마나 한

By sooop

구글 포토에서 아이클라우드로 탈출한 후기

한 때 구글 포토가 백업 용량을 무제한으로 제공해 주겠다고해서, 구글 포토를 사용해서 사진을 백업해왔습니다. 물론 이 이야기의 결말은 저나 이 글을 읽고 있는 여러분이나 모두 알고 있습니다. 사실 AI에게 학습 시킬 이미지 데이터를 모으기 위한 것일 뿐이라거나 하는 이야기는 그 당시에도 있었습니다만, 에이 그래도 구글인데 용량은 넉넉하게 주겠지…하는 순진한

By sooop

Julia의 함수 사용팁

연산자의 함수적 표기 Julia의 연산자는 기본적으로 함수이며, 함수 호출 표기와 같은 방식으로 호출하는 것이 가능합니다. 또한 그 자체로 함수이기 때문에 filter(), map() 과 같이 함수를 인자로 받는 함수에도 연산자를 그대로 적용하는 것이 가능합니다. 특히 + 연산자는 sum() 함수와 같이 여러 인자를 받아 인자들의 합을 구할 수 있습니다. 2 + 3 # = 5 +(2,

By sooop