현재 한 컴퓨터에서 Ubuntu와 Windows를 같이 사용중이다. 

 

지금까지 3번정도 Ubuntu 사용을 해보려고 시도했었지만 적은 사용량과 한글 문서등의 호환성 이슈 때문에 사용을 포기했었으나 지금은 그래도 꾸준히 사용을 하고 있다. 

 

이전 글에도 올렸지만 주력 text editor로 vim을 사용한지가 꽤 되었는데 아직도 Ubuntu에서는 최신 vimrc 파일을 설치해두지 않았더라. 

 

그래서 그대로 _vimrc 파일을 긁어다가 Ubuntu에 .vimrc로 넣어주었는데 이게 무슨 일! vim을 로딩할때 넘쳐나는 에러의 향연을 볼 수 있다. 

 

한 두개야 vim 버전 문제겠지하고 넘겼을 수 있었겠지만 수십개가 주르륵 나오는 것으로 바로 알아차렸다. 

 

아, 이거 100% 인코딩이나 Line ending 문제다.

 

아니나다를까 Unix-based 시스템과 DOS-based 시스템의 Line ending이 다르단다. 

 

분명 어딘가에서 읽었을 것 같은데 당시에는 Unix-based 시스템을 쓸 일이 없다고 생각했고 앵간한 상용 프로그램들은 이런 문제를 알아서 해결해주기에 'Line ending이란게 있다더라~' 하고 넘어간듯 하다. 

 

다행히 구글에서 비슷한 케이스를 바로 찾을 수 있었는데 별로 반가운 대접을 받지는 못하는 것 같다. 

(그도 그럴게 issue에 bug report 처럼 올렸으니... )

 

github.com/vim/vim/issues/6156

 

E492: Not an editor command: ^M on Linux subsystem · Issue #6156 · vim/vim

I installed Vim on Ubuntu via Linux Subsystem on Windows 10, so I can use it for work. I changed the home directory to the Windows user directory and symlinked the Ubuntu home to it. I use VimPlug ...

github.com

Solution

vim wiki에 가보니 친절한 설명이 되어있다. 

 

vim.fandom.com/wiki/File_format

 

File format

Vim recognizes three file formats (unix, dos, mac) that determine what line ending characters (line terminators) are removed from each line when a file is read, or are added to each line when a file is written. A file format problem can display ^M characte

vim.fandom.com

결국 모든 문제의 근원은 엔터를 칠 때 CR(Carriage Return)과 LF(Line Feed)(New Line이라고 하기도 함)를 자동으로 입력해주는 DOS에서 가져온 텍스트 파일을 LF만 사용해서 새 줄을 표기하는 Unix 시스템이 읽고 "CR이 뭐임?" 하는 상황 때문에 문제가 발생하는 것이다. 

 

참고로 CR은 0x0D 이며 이는 Ctrl-M과 대응된다. 

 

 

CR과 LF의 유래에 대해서는 아래 글에 자세히 나와있다.

더보기

일반적인 text 파일의 경우 해결 방법은 크게 1)CR을 지워주거나 2)CR을 무시하게 하거나 둘 중 하나이지만, vim 시작후 가장 먼저 읽어들이기 시작하는 vimrc 파일의 경우는 1)CR을 지운 버전을 사용하는 방법밖에 없는 것 같다. 

(CR을 무시하게 하는 방법이 있다면 꼭 알려주세요)

 

1. dos2unix 유틸리티 설치 후 CR을 지워주기.

sudo apt-get install dos2unix
dos2unix ~/.vimrc

 

2. vim의 substitute 기능을 사용해 CR을 지워주기.

^M 을 vim 커멘드에 입력하기 위해서는 Ctrl-v를 누른후 Ctrl-m을 눌러야 한다. 

:%s/^M//g

 

 

 

 

Posted by Knowblesse

서론

온갖 것들에 관심을 주는 성격 때문인지 한 언어의 실력을 진득히 늘리기 보다는 온갖 언어를 조금씩 하게 된 것 같다.

그 덕에 디자인 때문에 왠지 좋아하는 Visual Studio 부터 기억도 안나는 Eclipse, 의외로 자주 열게되는 sublime text까지 다양한 IDE(Integrated Development Environment)를 사용해봤다.

 

다행히 MATALB과 python은 연구에서 쓰느라 자기 손 처럼 익숙해지기도 했는데 이 python이 정말 IDE가 골치아프다. 

인터프리터 기반 언어는 MATLAB이 처음이었는데 깔끔한 상업용 IDE에 익숙해지다 보니 python을 배울 때 정말 애를 먹었다. 메모장으로 시작해 Spyder로 잠깐 넘어갔다가 PyCharm을 발견하고 지금까지 쓰고 있다. 

 

Interpreter Environment 설정부터 git관리까지 완벽하게 해주고 중간부터는 numpy 지원을 해서 깔끔한 gui로 거의 MATLAB급의 환경을 제공해주더라. 게다가 학교에 있는 경우 professional version이 무료! 파이썬 시작한다는 사람들에게 엄청 홍보하고 다녔다. 

 

그런데, 사실 프로그래밍 할 때 IDE의 얼마나 많은 기능들을 쓰는가 싶다.리소스를 고려할만큼 무거운 것들을 돌리지 않으니 리소스 모니터도 필요 없고. 프로젝트라고 불리울만큼 여러 소스코드가 뒤섞여있지 않고, 심지어 버전관리도 따로 프로그램을 돌리기에 사용하지 않는다. 

 

내가 python을 쓸 때 메모장을 쓰지 못하는 이유 를 적어보니 아래와 같이 나오더라. 

  • 간단한 단축키로 line by line으로 프로그램 돌리기
  • 자동완성
  • syntax highlighting
  • 파일 탐색기 integration

부끄럽게도 정말 이게 다 더라. 

 

compiler 를 사용하는 언어라면 그래도 디버깅을 하며 IDE를 쓸 텐데 python을 쓸 때는 정말 살짝 좋은 메모장 이상의 기능은 쓰고 있지 않았다. 

 

그러던 와중 찐 코딩덕후들이 사용한다는 vim이 떠올랐다. 

리눅스 환경에서 코딩을 할 때 가끔 쓰고 i를 누르면 편집, :w를 누르면 저장, :q를 누르면 나가기가 된다는 정도만 알고 있었는데 이게 그렇게 배워두면 뒤로 못 돌아간다더라. 

 

emacs 도 궁금하다. 배울수록 미쳐간다는 뜻인가... ㅋㅋㅋ

키보드에 난잡하게 있는 커멘드 때문에 두번 포기하고 3번째에야 불편하지는 않을 수준으로 쓰게 되었다만 역시 쓸 일이 없으니 계속 잊을 것 같았다. 

 

그러던 어느날 친구 컴퓨터에서 코딩을 도와주다가 위로 올라가기 위해서 k를 연타하는 자신을 본 순간 깨달았다. 

 

아! 이제 Vim으로 코딩을 해도 되겠다!

 

다행히 그 명성에 걸맞는 확장성 때문에 + 인터프리터 언어의 특성 때문에 python과 vim은 상성이 아주 잘 맞는다. 

 

단지 윈도우에서 셋업을 하는데 조금 어려울 뿐이다. 

 

가장 좋은 점은 위에서 언급한 execute selected line(s), autocompletion, syntax highlighting, file explorer integration의 모든 기능들을 vim plugin들로 구현할 수 있다. 

 

기록을 남겨둘 겸 몇가지 초기 세팅을 적어두려고 한다. 

 

 

 

VIM 설치

python을 쓰는데 anaconda를 쓰지 않을 인간은 없다. 에이 설마. 적어도 연구자들은 anaconda가 안깔려 있으면 거의 100% 이제 막 파이썬을 시작한 것이더라. 그래서 anaconda로 python이 설치되어있다고 가정하고 글을 쓴다. 

 

일단 Path 안에 다른 python이 있지 않은지 확인을 해서 한 컴퓨터 안에 여러개의 python이 돌아다니는 일을 먼저 해결하고 시작해야한다. 

 

기본 옵션으로 anaconda를 설치했으면 cmd 창에서는 python이 실행이 안된다. 요즘은 python이 없는 상태로 커멘드를 입력하면 Microsoft store로 연결해주던데 귀찮게 시리. 

 

Python을 실행하려면 anaconda prompt를 켜서 그 안에서 실행을 해야한다. 그러면 해당 가상 환경에 걸맞는 파이썬이 로드될 것이다. 

 

때문에 vim을 실핼할 때도 cmd로 실행하는 것이 아니라 anaconda prompt 내에서 실행을 해야한다. 

 

지나가다가 보기로는 가상 환경 지원도 해주는 것 같던데 일단 오늘은 기본 (base)에서 돌아가게 하는 것을 전제로 한다. 

 

Window 버전 설치 링크는 다음과 같다. 

 

github.com/vim/vim-win32-installer/releases

 

Releases · vim/vim-win32-installer

Vim Win32 Installer. Contribute to vim/vim-win32-installer development by creating an account on GitHub.

github.com

 

그리고 아주 중요한 것.

VIM을 설치할 때는 꼭! anaconda의 32-bit / 64-bit 버전과 맞는 것을 설치해야 한다. 

 

이것 때문에 1시간을 버렸다. 만약 이것을 지키지 않으면 나중에 아래의 메시지를 보게 될 것이다. 

E370: Could not load library python38.dll
E370: python38.dll 라이브러리를 로드할 수 없습니다.
E263: Sorry, this command is disabled, the Python library could not be loaded
E263: 미안합니다, 이 명령은 사용할 수 없습니다, 파이썬 라이브러리를 로딩할 수 없습니다.

설치할 때 다른 옵션은 그대로 두고 설치해도 좋다. 그냥 다음 다음 다음 클릭. 

 

Vundle설치 이제는 Vundle 보다는 Vim-Plug를 더 많이 쓰는 것 같다.

더보기

vim의 pip과 같은 Plugin 설치에 있어서 착한 기능을 하는 친구가 vundle이다. 

이것도 윈도우에서 설치시 에러사항이 있는데 instruction을 따라서 3번이나 설치해봐도 항상 똑같이 제대로 설치가 안되더라. 내가 3번 다 메뉴얼을 잘못 읽었을 가능성도 있다. 어느 누가 풀리퀘를 걸지 않았으려나. 

 

여튼, 내가 한 방법은 다음과 같다. 

 

먼저 git for windows를 설치한다. 

 

anaconda prompt에서 git 입력시 반응이 나타나면 넘어가도 좋다. 

 

설치 링크는 아래와 같다. 

 

git-scm.com/download/win

 

Git - Downloading Package

Downloading Git Now What? Now that you have downloaded Git, it's time to start using it.

git-scm.com

공식 페이지 설명을 보면 curl도 필요하다고 하는데 win10은 같이 딸려나온다고 하니 신경쓰지 않아도 될 듯하다.

 

리눅스 유저라면 헷갈릴수도 있는게 window 용 vim은 .vimrc 대신 _vimrc, ~/.vim 대신 ~/vimfiles 를 사용한다.

 

그리고 공식 설명에서는 아래의 코드를 그대로 쓰면 된다고 하지만 왜인지 내 cmd는 ~를 홈으로 인식하지 않는다.

 

powershell을 쓴다면 아래의 코드를 그대로 쓰고

git clone https://github.com/VundleVim/Vundle.vim.git ~/vimfiles/bundle/Vundle.vim

검은창이 익숙하다면 유저명을 적절히 바꿔서 넣고 아래를 쓰자.

git clone https://github.com/VundleVim/Vundle.vim.git C:/Users/유저명/vimfiles/bundle/Vundle.vim

마지막으로 vim을 실행한 후 아래 커멘드를 입력해주면 된다.

:PluginInstall

 

Vim-Plug 설치

이 글을 작성하는 와중에 알게 되었는데 Vundle 보다는 Vim-Plug가 더 깔끔하고 gui 같은 그래픽을 만들어 놓은 것이 기특하다. Plug를 쓰는 것이 더 좋을 듯 하다.

 

설치는 정말 간단하다. powershell에서 아래 코드를 실행하자.

iwr -useb https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim |`
    ni $HOME/vimfiles/autoload/plug.vim -Force

 

 

(현명하게도) 주인장을 믿지 못한다면 공식 페이지 설치법을 체크하자

github.com/junegunn/vim-plug

 

junegunn/vim-plug

:hibiscus: Minimalist Vim Plugin Manager. Contribute to junegunn/vim-plug development by creating an account on GitHub.

github.com

ctags 설치 (옵션)

다른 프로그래머들의 _vimrc 파일을 구경하다가 Vista 라는 Plugin을 찾았는데 이게 상당히 쓸만한 친구인것 같다.

 

약간 고급 IDE의 프로젝트 브라우져 같은 것인데 어떤 함수가 어디에서 정의되어 있는지 현재 정의한 변수는 무엇인지 등을 알려준다. 

 

이정도면 그냥 Visual Studio나 PyCharm을 하나 만드는 것 같은데..???

 

설치방법은 아래와 같다. 

 

이 링크에서 최신 release에 들어간 뒤, 설치한 빔 버전에 맞는 (32/64) release 파일을 받는다. 

 

github.com/universal-ctags/ctags-win32/releases

 

Releases · universal-ctags/ctags-win32

Universal Ctags Win32 daily builds. Contribute to universal-ctags/ctags-win32 development by creating an account on GitHub.

github.com

이후 압축을 풀고 시스템 경로의 Path 안에 포함되어 있는 아무 폴더에 .exe 파일 두 개를 넣어주면 된다. 

 

나는 vim 커멘드를 쓰기에 그냥 vim.exe 파일이 있는 C:\Program Files\Vim\vim82 안에 넣어두었다. 

 

기타 Plugin 설치

설치할 플러그인은 아래와 같다. 

  • Vim-sensible : 설명을 읽어봐도 모르겠으나 다들 설치하더라(?)
  • vim-vuftabline : 버퍼에 넣은 텍스트를 탭으로 보이게 해준다
  • nerdtree : 파일 탐색기
  • vim-nerdtree-tabs
  • vim-gitgutter : git 연동
  • nerdtree-git-plugin
  • Jedi-vim : 자동완성
  • supertab : 자동완성시 tab 사용 가능
  • ale : 에러 체크
  • vista : ctags를 사용하는 프로젝트 익스플로러st 한 기능
  • lightline : 하단 상태바
  • onedark : 어두운 colorscheme
  • Vim-monokai-tasty : 모노카이가 아니면 코딩을 못하는 병에 걸렸다

이는 _vimrc(.vimrc) 변경후 아래의 커멘드를 실행해주면 된다.

:PlugInstall

Vista.vim 에러 해결

Vista.vim을 까는 중에 아래의 에러가 발생하였다.

17 줄:
E696: List에 콤마 누락: ??])
E116: 함수 get(g:, 'vista_fold_toggle_icons', ['??, '??])(으)로 잘못된 인자가

이 역시 반복되는 재설치, 플러그인 정리로 한참을 시간을 보낸 뒤에야 원인을 알게 되었다.

 

.vim 파일을 뜯어보니 아이콘을 사용하기 위해서 ▼▶ 기호를 쓰는데 아무래도 망할 인코딩 문제인듯 했다.

 

_vimrc 파일에 앞에 인코딩 부분을 설정해주니 문제 없이 작동한다.

 

" sane text files
set fileformat=unix
set encoding=utf-8
set fileencoding=utf-8

첨부한 _vimrc에는 반영이 되어 있으니 그대로 실행하면 된다. 

 

Python 연결

사실 여기까지 실행하면 아래 기능들이 끝난 것이다. 

 

  • 간단한 단축키로 line by line으로 프로그램 돌리기
  • 자동완성
  • syntax highlighting
  • 파일 탐색기 integration

안타깝게도 아직 line by line으로 python을 돌리는 것을 찾아내지 못했다. 

 

일단 vim 내부에서 Anaconda Python을 연동시키기 위해서는 무엇보다 vim 자체를 anaconda prompt에서 실행하는 것이 제일 먼저고 _vimrc 파일안에 아래의 라인이 필요하다.

set pythonthreehome=~\anaconda3\
set pythonthreedll=~\anaconda3\python37.dll

아무래도 저게 없으면 python을 쓰는 jedi plugin의 기능이 먹통이 된다. 

Anaconda로 python을 설치하면 경로를 못찾아서 그런지 저런 오류가 발생하는 듯 하다. 

 

Anaconda의 경로가 다른 경우 거기에 맞춰서 스크립트를 적절히 수정하기 바란다. 

 

또한 이것 역시 설치한 python의 아키텍쳐 버전과(32/64) vim의 버전이 맞아야 실행이 된다는 점을 기억하자.

 

 

 

vim에서 python을 사용하는 방식은 크게 두 가지 이다. 

 

1. !로 콘솔 커멘드에서 python을 실행시키기

:1,5w !python

위의 예시는 첫 줄 부터 5줄까지 쓰고, (원래는 파일에 쓰는 것이겠지만 이번은 python에 통쨰로 코드를 넘겨주는 것이다.) 이를 외부에서 python를 사용해 실행시키는 방식이다. 

 

권장되는 방법이며 한번 실행이 된 스크립트는 실행 후 결과를 표시한 뒤, 종료된다. 따라서 데이터가 남지 않는다. 

 

2. py3 커멘드로 vim 내부에서 python을 실행시키기

:py3 print("hello world")

위의 예시는 즉각 뒤에 오는 string을 python으로 실행시킨다. 

 

:py3 로 실행하는 스크립트는 vim과 연동된 스크립트라 vim에서 데이터 입출력이 가능하며, vim이 종료되지 않는 이상 이전 실행 결과과 유지도니다. 

 

하지만 이 커멘드는 아직 파일내 영역을 지정해서 실행하는 방법을 찾지 못했다. 

 

doc string을 읽어보면 범위 옵션이 있긴 한데 열심히 커뮤니티를 찾아봐도 알아내기 힘들었다. 

 

방법을 알아낸다면 블로그지기에게 알려주시고 블로그지기가 먼저 알아낸다면 수정해서 올리겠다. 

 

Code snippet execution (Python)

 

블로그지기는 인터프리터 계열 언어를 사용할 때 창을 두 개 띄워두고 한 창에서 한 줄 한 줄 코드를 실행시키면서 테스트를 한 뒤 이를 다른 창에 옮겨 이를 나중에 활용한다. 

 

예를 들어 1)데이터 로드 -> 2)전처리 -> 3)분석 구조의 스크립트를 짤 때 매번 전체 스크립트를 실행시키지 않고 1)을 끝내두었으면 1) 까지를 실행시켜둔 콘솔에서 2)를 중간중간에 콘솔에 넘겨 실행시켜본다. 

 

컴파일러 계열 언어라면 전체를 돌리고 그 안에서 breakpoint를 넣어가며 디버깅을 해야겠다만 인터프리터라면 왜 굳이.. 그런데 이게 일반적인 방법이 아닌가보다. 코딩을 혼자 배우면 이렇게 된다

 

때문에 이미 짜둔 스크립트의 일부를 콘솔에 옮겨서 실행해야할 경우가 빈번히 발생하는데, 고급 IDE에서는 현재 줄 실행, 선택 영역 실행 등의 기능이 있어서 단축키를 등록해두고 자주 사용해왔다. 

 

그런데 이게 vim에 없다! 

거의 5시간은 찾았는데 플러그인은 커녕 누가 시도한 것을 찾지도 못했다!

세상에.. 그나마 비슷한 것은 https://vim.fandom.com/wiki/Evaluate_current_line_using_Python 이 팁인데 이것은 한 줄만 실행이 가능한 미완성 상태로 남아있다. 

 

심지어 이번에 처음 알았는데 python의 eval 함수는 'a=3' 등의 대입문을 처리하지 못한다더라. 

 

그래서 어찌저찌 하나를 만들었다. vim 을 사용한지 누적 5시간도 안되는 뉴비가 만든 것임을 인지해주기를 바란다. 

 

다음의 코드를 _vimrc에 넣고 vim에서 :Eval을 실행하면 된다. 

 

"Python execute selected line script
python3 << EOL
import vim

def ExecuteSelectedLine(l1, l2):
    for i in range(l1-1,l2):
        print(">>" + vim.current.buffer[i])
        exec(vim.current.buffer[i],globals())
EOL
command! -range Eval <line1>,<line2> python3 ExecuteSelectedLine(<line1>, <line2>)
  • :Eval : 현재 줄 실행
  • :1,3Eval : 1~3째 줄 실행
  • '<,'> : visual 모드로 선택된 영역 실행

다음은 _vimrc 파일의 예시이다. 

" vim runtime config file
" Written by Knowblesse 2020
" Adapted from miguelgrinberg/.vimrc

" sane text files
set fileformat=unix
set encoding=utf-8
set fileencoding=utf-8

call plug#begin()
Plug 'tpope/vim-sensible'

"buffer lists instead of tab
Plug 'ap/vim-buftabline'

"NERD
Plug 'preservim/nerdtree'
Plug 'jistr/vim-nerdtree-tabs'

"Git
Plug 'airblade/vim-gitgutter'
Plug 'Xuyuanp/nerdtree-git-plugin'

"Coding
Plug 'davidhalter/jedi-vim'
Plug 'ervandew/supertab'
Plug 'dense-analysis/ale'
Plug 'liuchengxu/vista.vim'
Plug 'itchyny/lightline.vim'

"Color theme
Plug 'flazz/vim-colorschemes'
Plug 'joshdick/onedark.vim'

call plug#end()

set tabstop=4
set shiftwidth=4
set softtabstop=4
set colorcolumn=100
set expandtab

"HighLight SEARCH result
set hlsearch
set pythonthreehome=~\Anaconda3\
set pythonthreedll=~\Anaconda3\python37.dll


autocmd FileType python setlocal completeopt-=preview
set guifont=Bitstream\ Vera\ Sans\ Mono:h14

" indent/unindent with tab/shift-tab
nmap <Tab> >>
nmap <S-tab> <<

" color scheme
syntax on
colorscheme Monokai
filetype on
filetype plugin indent on


" lightline
set noshowmode
let g:lightline = { 'colorscheme': 'onedark' }


let g:nerdtree_open = 0
map <leader>t :call NERDTreeToggle()<CR>
function NERDTreeToggle()
    NERDTreeTabsToggle
    if g:nerdtree_open == 1
        let g:nerdtree_open = 0
    else
        let g:nerdtree_open = 1
        wincmd p
    endif
endfunction

function! StartUp()
    if 0 == argc()
        NERDTree
    end
endfunction
autocmd VimEnter * call StartUp()

"Python execute selected line script
python3 << EOL
import vim

def ExecuteSelectedLine(l1, l2):
    for i in range(l1-1,l2):
        print(">>" + vim.current.buffer[i])
        exec(vim.current.buffer[i],globals())
EOL
command! -range Eval <line1>,<line2> python3 ExecuteSelectedLine(<line1>, <line2>)

_vimrc
0.00MB

정리가 잘 안된 감이 있지만 언젠가 더 vim에 익숙해지면 깔끔하게 정리하겠지.

 

마지막으로 아래 커맨드를 실행을 잊지 않는다

:PlugInstall

 

마치며

피곤하다. 

완성된 IDE에 벌써 정이가는데 이렇게 배우는데 시간을 들인만큼 생산성도 같이 올라가면 좋을 듯 하다. 

 

깔끔한 책 구성으로 vim을 쉽게 배우는데 도움을 주신 김선영 선생님께 감사의 말씀을 멀리서 전하고 싶다. 

 

정말 추천하는 책이다. 

 

www.aladin.co.kr/shop/wproduct.aspx?ItemId=11228613

 

손에 잡히는 Vim

Vim의 필수 기능들을 친절한 그림과 함께 차근차근 설명하여, ‘배우기 어려운 에디터’라는 고정관념을 깨뜨린다. 리눅스를 공부하는 학생이나 터미널 창에서 작업하는 서버 관리자, 키보드에

www.aladin.co.kr

 

Posted by Knowblesse