gvim 설정에서 cursor 밑에 있는 파일을 새 탭으로 여는 함수 작성해줘. 이 때 파일 경로가 상대경로일 경우 현재 열려있는 파일로부터 상대 경로로 찾아야 해. 그리고 만약 파일이 없으면 input() 으로 새로 해당 파일을 만들지 질문하고 y로 답할 경우 만들고 열어줘.

아래는 gvim에서 사용할 수 있는 Vimscript 함수입니다. 커서 아래 있는 단어(파일 경로로 간주)를 새 탭으로 열되, 상대경로일 경우 현재 열려 있는 파일 기준으로 처리하고, 해당 파일이 존재하지 않으면 생성 여부를 묻는 기능을 포함하고 있습니다.

vim

function! OpenFileUnderCursorInTab()
  " 커서 아래 단어 가져오기
  let l:filename = expand('<cfile>')

  " 현재 버퍼의 디렉토리 기준으로 상대경로 처리
  let l:current_dir = expand('%:p:h')
  let l:fullpath = fnamemodify(l:filename, ':p')
  if !isdirectory(fnamemodify(l:filename, ':h'))
    let l:fullpath = resolve(l:current_dir . '/' . l:filename)
  endif

  " 파일 존재 여부 확인
  if filereadable(l:fullpath)
    " 새 탭으로 열기
    execute 'tabedit ' . fnameescape(l:fullpath)
  else
    " 파일 생성 여부 확인
    let l:answer = input("File does not exist. Create it? (y/N): ")
    if l:answer ==? 'y'
      " 디렉토리 없으면 생성
      call mkdir(fnamemodify(l:fullpath, ':h'), 'p')
      " 새 탭으로 열기 (파일 생성 포함)
      execute 'tabedit ' . fnameescape(l:fullpath)
    else
      echo "Aborted."
    endif
  endif
endfunction

" 매핑 예시 (원하는 키로 변경 가능)
nnoremap <Leader>ot :call OpenFileUnderCursorInTab()<CR>

요점 정리:

  • expand('<cfile>')을 사용하여 커서 아래 파일명 추출.

  • expand('%:p:h')로 현재 파일 기준 경로 가져와서 상대경로 처리.

  • filereadable()로 존재 여부 확인 후 tabedit로 새 탭에서 열기.

  • 없을 경우 input()으로 사용자에게 파일 생성 여부 묻기.

참고 사항:

  • 상대경로 처리에서 Vim이 :p로 풀지 못하는 경우가 있어 resolve()와 디렉토리 접합을 함께 사용함.

  • mkdir(..., 'p')는 상위 디렉토리까지 포함해 생성함.

테스트 후 의도대로 작동하지 않는 부분이 있으면 알려주세요. 삽질 없이 바로 고칠 수 있도록 도와드리겠습니다.

만들지 물을 때 절대 경로를 보여주고 물어주면 좋겠어.

아래는 요청하신 대로 파일이 없을 때 절대 경로를 보여주고 생성 여부를 묻도록 수정한 버전입니다:

vim

function! OpenFileUnderCursorInTab()
  " 커서 아래 단어 가져오기
  let l:filename = expand('<cfile>')

  " 현재 파일 기준 디렉토리에서 상대경로 처리
  let l:current_dir = expand('%:p:h')
  let l:fullpath = resolve(fnamemodify(l:current_dir . '/' . l:filename, ':p'))

  " 파일 존재 확인
  if filereadable(l:fullpath)
    execute 'tabedit ' . fnameescape(l:fullpath)
  else
    " 경고 및 절대 경로 출력
    let l:answer = input("File does not exist: " . l:fullpath . "\nCreate it? (y/N): ")
    if l:answer ==? 'y'
      " 디렉토리 없으면 생성
      call mkdir(fnamemodify(l:fullpath, ':h'), 'p')
      execute 'tabedit ' . fnameescape(l:fullpath)
    else
      echo "Aborted."
    endif
  endif
endfunction

" 예시 키 매핑
nnoremap <Leader>ot :call OpenFileUnderCursorInTab()<CR>

변경 사항 요약:

  • input() 메시지에 l:fullpath (절대 경로)를 출력함으로써 사용자가 어떤 경로에 파일을 만들게 되는지 명확하게 보여줌.

이제 실수로 엉뚱한 위치에 파일을 만드는 일은 줄어들 겁니다. 더 개선하고 싶은 점 있으시면 말씀해 주세요.

질문에 색깔을 넣을 수도 있어?

네, GVim이나 터미널 Vim에서 색깔을 넣는 건 제한적 입니다.
하지만 GVim , 특히 GUI 환경에서는 :echohl을 활용하면 색상 강조 를 넣을 수 있습니다. 단, input() 자체는 하이라이팅을 직접 지원하지 않아서 질문 전체를 색상 있게 출력하고, 입력은 따로 받는 방식 으로 우회해야 합니다.

예시 코드는 다음과 같습니다:

vim

function! OpenFileUnderCursorInTab()
  let l:filename = expand('<cfile>')
  let l:current_dir = expand('%:p:h')
  let l:fullpath = resolve(fnamemodify(l:current_dir . '/' . l:filename, ':p'))

  if filereadable(l:fullpath)
    execute 'tabedit ' . fnameescape(l:fullpath)
  else
    " 강조된 질문 메시지 출력
    echohl Question
    echon "File does not exist: "
    echohl Directory
    echon l:fullpath
    echohl Question
    echon "\nCreate it? (y/N): "
    echohl None

    " 입력은 따로 처리
    let l:answer = nr2char(getchar())

    if l:answer ==? 'y'
      call mkdir(fnamemodify(l:fullpath, ':h'), 'p')
      execute 'tabedit ' . fnameescape(l:fullpath)
    else
      echo "Aborted."
    endif
  endif
endfunction

설명:

  • echohl은 특정 하이라이트 그룹으로 색상을 바꿉니다.

  • Question, Directory 같은 기본 하이라이트 그룹을 사용했지만, :highlight로 사용자 지정도 가능함.

  • echon은 개행 없이 출력합니다. getchar()로 입력을 따로 받아야 input() 없이 색상 출력이 가능합니다.

참고:

  • 터미널 Vim에서는 색이 보이지 않거나 제한될 수 있습니다. GVim이나 색상 지원 터미널에서 확인하세요.

  • 원하는 색감이 아니면 :highlight Question 등의 명령어로 색상 조정 가능합니다.

필요하시면 사용자 정의 색상까지 설정하는 방법도 알려드릴게요.

파일 경로가 /로 시작하면 절대 경로니깐 상대 경로로 찾지 말아줘

네, 그게 맞습니다. 파일 경로가 /로 시작하면 이미 절대 경로이므로, 상대 경로 계산을 피해야 합니다. 이를 반영한 전체 코드를 아래에 정리해 드리겠습니다:

vim

function! OpenFileUnderCursorInTab()
  let l:filename = expand('<cfile>')

  " 절대 경로 여부 확인
  if fnamemodify(l:filename, ':p') ==# l:filename
    let l:fullpath = resolve(l:filename)
  else
    let l:current_dir = expand('%:p:h')
    let l:fullpath = resolve(fnamemodify(l:current_dir . '/' . l:filename, ':p'))
  endif

  " 파일 존재 여부 확인
  if filereadable(l:fullpath)
    execute 'tabedit ' . fnameescape(l:fullpath)
  else
    " 강조된 메시지 출력 (GVim 또는 컬러 터미널에서 유효)
    echohl Question
    echon "File does not exist: "
    echohl Directory
    echon l:fullpath
    echohl Question
    echon "\nCreate it? (y/N): "
    echohl None

    let l:answer = nr2char(getchar())

    if l:answer ==? 'y'
      call mkdir(fnamemodify(l:fullpath, ':h'), 'p')
      execute 'tabedit ' . fnameescape(l:fullpath)
    else
      echo "Aborted."
    endif
  endif
endfunction

" 키 매핑 예시
nnoremap <Leader>ot :call OpenFileUnderCursorInTab()<CR>

핵심 변경 사항:

  • fnamemodify(..., ':p') ==# ... 비교로 절대 경로 여부를 판단함.

  • 절대 경로일 경우 상대 경로 붙이지 않고 그대로 resolve()만 적용.

  • 상대 경로일 경우에만 현재 버퍼 기준으로 조합.

  • 질문 메시지는 하이라이트(echohl)로 컬러 출력하며 getchar()로 직접 입력 받음.

이제 절대 경로와 상대 경로 모두 정확히 처리됩니다.
필요하면 하이라이트 색상도 커스터마이즈해서 시각적으로 더 분명하게 만들 수 있습니다.

절대 경로 여부 판단 원리가 뭐야? "./abcd"라고하면 상대경로로 인식해야할 것 같은데 절대 경로로 인식하는 것 같음

좋은 지적입니다. Vim의 fnamemodify({fname}, ':p')상대 경로를 절대 경로로 변환 해주기 때문에, 아래와 같은 판단:

vim

if fnamemodify(l:filename, ':p') ==# l:filename

은 사실 절대 경로 판별로는 부정확합니다. 예를 들어:

  • "./abcd"fnamemodify(..., ':p') 결과는 /현재경로/abcd → 절대 경로처럼 보임

  • "abcd" → 마찬가지로 절대 경로로 변환됨

  • "/etc/passwd" → 애초에 절대 경로임

결국 위 조건은 "./abcd" 같은 상대 경로도 절대 경로로 인식해버리는 문제가 있습니다.


정확한 절대 경로 판단 방법은?

Vim에서는 파일 이름이 루트(/)로 시작하는지 직접 판단하는 것이 더 정확합니다:

vim

if l:filename =~ '^/'
  " 절대 경로
else
  " 상대 경로
endif

수정된 코드 (절대 경로 판별 정확하게 반영):

vim

function! OpenFileUnderCursorInTab()
  let l:filename = expand('<cfile>')

  " 절대 경로 여부: 슬래시로 시작하면 절대 경로
  if l:filename =~ '^/'
    let l:fullpath = resolve(l:filename)
  else
    let l:current_dir = expand('%:p:h')
    let l:fullpath = resolve(fnamemodify(l:current_dir . '/' . l:filename, ':p'))
  endif

  if filereadable(l:fullpath)
    execute 'tabedit ' . fnameescape(l:fullpath)
  else
    echohl Question
    echon "File does not exist: "
    echohl Directory
    echon l:fullpath
    echohl Question
    echon "\nCreate it? (y/N): "
    echohl None

    let l:answer = nr2char(getchar())

    if l:answer ==? 'y'
      call mkdir(fnamemodify(l:fullpath, ':h'), 'p')
      execute 'tabedit ' . fnameescape(l:fullpath)
    else
      echo "Aborted."
    endif
  endif
endfunction

결론:

  • fnamemodify(..., ':p') == ...는 절대 경로 판별용으로 틀림.

  • 파일 경로가 /로 시작하는지를 직접 정규식(^/)으로 검사하는 게 정확하고 신뢰할 수 있는 방법 입니다.

의심을 잘 하셨습니다. 이 부분에서 실수하는 경우 많습니다.

Categories:

Updated: