vim auto-completion for Pebble programming

auto-completion-using-vim-for-pebble

It is noticed that CloudPebble now supports code completion, syntax checking and ability to “go to definition” 1. But you can also get all these benefits by using vim and ctags in console. I will describe brief explanation for those who are already using vim as their primary developing tool for developing pebble application.

 

You need ctags and remap C language files

Install ctags first, and check out the mapping list for C definition.

1
2
3
$ ctags --list-maps=C

C        *.c *.h

 

If you find different output for *.h files, you need to remap as follow. To avoid specify same option on every command to build tags file, add the below line to your ~/.ctags file.  Make new one if it doesn’t exist.

1
--langmap=C:.c.h

 

Install YouCompleteMe plugin for vim and follow its instruction to gear up.

Most case, you need nothing  to do but just install plugin and compile the C-components.

Github: https://github.com/Valloric/YouCompleteMe 2

 

Add or apply the below to your existing .vimrc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
"search tags file recursively from working directory until reach '/' directory.
set tags=./tags;

"automatic update/create tags file

au BufWritePost *.c,*.h silent! !ctags --fields=+l --C-kinds=+p -R % &

"Plugin: YouCompleteMe {{{


let g:ycm_global_ycm_extra_conf = "~/.vim/ycm_extra_conf.py"
let g:ycm_confirm_extra_conf = 0
let g:ycm_min_num_of_chars_for_completion = 2
let g:ycm_auto_trigger = 1
let g:ycm_collect_identifiers_from_tags_files = 1
let g:ycm_seed_identifiers_with_syntax = 1
let g:ycm_add_preview_to_completeopt = 1
let g:ycm_autoclose_preview_window_after_completion = 1
let g:ycm_key_invoke_completion = ''

"define as you want

nnoremap jd :YcmCompleter GoTo;

" }}}

 

Add or apply the below to your existing ycm_extra_conf.py. If it is not exist, copy from ~/.vim/bundle/YouCompleteMe/third_party/ycmd/examples/.ycm_extra_conf.py into ~/.vim/ycm_extra_conf.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import os
import ycm_core

flags = [
'-Wall',
'-Wextra',
'-Werror',
'-Wno-long-long',
'-Wno-variadic-macros',
'-fexceptions',
'-std=c11',
'-x', 'c',
'-I.',
'-I', '/Users/andrwj/pebble-dev/PebbleSDK-current/arm-cs-tools/arm-none-eabi/include',
'-I', '/Users/andrwj/pebble-dev/PebbleSDK-current/Pebble/include'
]
#...
#...

 

Build tags file for Pebble SDK

I assume that users already installed Pebble SDK at ~/pebble-dev/PebbleSDK-current

 

1
2
3
4
5
6
7
8
9
10
11
$ cd ~/pebble-dev/PebbleSDK-current
$  rm -f tags
$ ctags -R \
--fields=+l \
--C-kinds=+p \
--exclude=~/pebble-dev/PebbleSDK-current/arm-cs-tools/arm-none-eabi/include/c++ \
~/pebble-dev/PebbleSDK-current/arm-cs-tools/arm-none-eabi/include \
~/pebble-dev/PebbleSDK-current/Pebble/include

$ ls -lah tags
-rw-r--r--  1 andrwj  staff   2.3M 10 15 14:39 tags

 

 Install syntax plugin for Pebble

We need this plugin because to seed identifiers of Pebble API from syntax file.

Github: https://github.com/ZDBioHazard/pebble-vim-syntax 3

 

As described in author’s README.md, don’t forget to add the below line:

1
autocmd BufNewFile,BufRead ~/pebble-dev/*.{c,h} set syntax=pebble

 

OK,  one last.

In order to use auto-completion for Pebble API, you need to place pebble-project files somewhere of ~/pebble-dev/ Because YouCompleteMe plugin seeks tags file recursively from current working directory until reach /.   The plugin refers ~/pebble-dev/PebbleSDK-current/tags file for auto-completion.

 

As you type, identifiers will be shown up. then you press <CTRL-Space> to auto-complete. You can also jump to the definition of constants, functions, macros by pressing <leader>jd or CTRL-].

 

Good luck!

 

  1. https://developer.getpebble.com/blog/2014/10/09/CloudPebble-code-completion/  
  2. https://github.com/Valloric/YouCompleteMe  
  3. https://github.com/ZDBioHazard/pebble-vim-syntax  

JavaScript로 설명한 C의 더블 포인터

이전 게시물에서 얘기한 내용의 예시로써,  C언어의 더블 포인터를 어떻게 써야할지 이해하지 못한 학습자를 위해 JavaScript코드로 설명하였다.   이글은 JavaScript에 대해 초급지식을 가지고 있는 C학습자를 대상으로 한다.

 

 


 

변수에 값을 넣는 것을 할당(assign)이라 하고 JavaScript 변수에 할당하는 값의 종류에는 크기가 고정된 Primitive type과  고정되지 않은 Reference type 두가지 종류가 있다. 1 Number, Boolean, undefined, null 은 Primitive Type이고 그외 배열, 객체, 함수 등은 Reference Type이다.

 

Reference Type 값은 모두 실행시간에 그 크기가 동적으로 변한다. C언어적으로 말하자면 malloc() 받는다고 할 수 있으며 Reference Type의 값을 담고 있는 변수는 그 값자체가 아니라  그 값의 메모리 주소를 담고 있다. 즉, C언어의 포인터 변수인 것이다.

 

Reference Type의 값을 가진 변수에 대해, 넣어진 값을 꺼내보거나 사용하는 것을 참조한다(refer) 라고 표현하자.  아래 JavaScript 코드에서는 변수 target에  Reference Type의 값 [1,2,3]이 할당되고  변수 A, B에는  변수 target의 복사된 값이 할당된다:

1
2
3
4
5
6
7
function doSomething(A, B) {
console.log(A);
console.log(B);
}

var target = [1,2,3];
doSomething(target, target);

 

target, A, B 세 변수는 이름만 다를뿐 모두 같은 값인 [1,2,3]의 주소를 가지고 있다(pointing).  몇몇 학습자는  A, B 두 변수는 target을 가리키는 변수 라고 생각할 수 도 있겠으나 틀린 생각이다. 변수를 가리키는 변수는 JavaScript 에서 지원하지 않기 때문이다.  만약 지원한다면 target은 Reference Type의 값을 가지고 있으니 C언어로 표현될 때 포인터 변수이며 A,B는 포인터 변수를 가리키고 있으므로 더블 포인터 변수가 될것이다. 

 

배열은 Reference Type Value이므로, 함수의 인자로 전달되어 그 함수에서 배열에 가해진 변경사항은 target 변수에서도 동일하게 보여진다:

1
2
3
4
5
6
function doSomething(A) {
A[2]  = 5;
}

var target = [1,2,3];
doSomething(target); //세번째 요소의 값이 3에서 5로 변한다.

 

이런 뻔한 소리를 하는 이유는, 거의 모든 JavaScript 개발자들이 C언어에서 말하는 포인터변수와 동일한 Reference Type Value를 가진 변수조작을 아무런 어려움없이 해내고 있다는 것을 말하고 싶어서이다.

 

JavaScript에서는 포인터 변수에 해당하는 것을 쓰더라도 C언어 포인터변수의 선언과 값 할당에 사용하는 * (Asterisk sign)  기호를 사용하지 않기 때문에  그럴수도 있고 포인터 값을 사용할때 (referencing) ->표기를 하지 않아 덜 복잡해 보이기 때문일수도 있다.  원인이 무엇이든 상관없이 모든 초급 C학습자는 포인터 개념을 모르는게 아니며 분명히 어떻게 사용해야할지 스스로 알고있다.  Reference Type으로 값을 함수에 전달하는 것이 프로그램 실행속도에 더 나은 선택이며 효율적인 코드를 작성할 수 있다는 것은 말하지 않아도 안다.

 

그런데,, 더블 포인터라는 말이 나오면 일단 머리가 띵~해지려고 한다. 도대체 왜 그딴 것을 쓰는지 언제 써야하는지 도대체 모르겠다는 것이다.  더블 포인터가 얼마나 간단한 개념인지 체감하기 위해, 여기서 문제를 내겠다. 반드시 고민해서 답을 달려고 해보자. 고민하지 않고 그냥 글을 읽어내려가면 A-HAAA~! 라는 깨달음이 덜 느껴질지도 ..

 

 

문제:

위의 예제에서 보이는 doSomething() 함수내에서 target 변수의 값이 undefined 가 되도록 해보라. 단 doSomething() 함수내에서 target이라는 변수 이름을 직접적으로 사용할 수는 없다.

 


 

 

 

……………

 

 

 

 

 

 

 

…….

 

 

 

 

………………..

 

 

 

 

 

………..

 

 

 

 

 

 

…………….

 

 

 

 

 

 

…….

 

 

고민해보았는가?

 

 

……..

 

 

 

 

………….

 

 

 

 

 

..

 

 

 

 

 

 

 

 

변수 target을 직접적으로 사용할 수 없으므로 여러분은 그 변수의 값을 빈 배열로 만들 수는 있어도 undefined가 되게 하는 것은 힘들다는 것을 알았을 것이다.

예시코드: http://jsbin.com/fasebijepuri/1/edit#javascript,console

1
2
3
4
5
6
7
function doSomething(A) {
while(A.pop());
}

var target=[1,2,3];
doSomething(target);
console.log(target); // 'undefined'가 아닌  '[ ]'

 

이 문제를 해결하기 위해서 프로그래밍 언어가 무엇을 지원해야하는지 생각해보자…

 

만약, 해당 변수와 다른 이름이지만 그 변수와 동일하게 취급받는 변수를 만들 수 있다면 가능하지 않겠는가?   즉, 변수를 가리키는 변수 같은 종류라면 가능할 것이다.  더 쉬운 말로 변수의 별명(Alias) 이라 표현할 수 있다.  

 

JavaScript에서 위의 문제를 해결하기 힘든 것은 Reference Type Value를 담는 변수는 C언어로 표현할 때 single pointer 변수 이기 때문이다. 즉, 값을 가리킬뿐 변수를 가리키지는 않는다.   이 점을 기억하고 C언어적인 해결방법을 얘기하자.  단도직입적으로 이 문제의 해법으로 더블 포인터 변수를 사용할 수 있다.

 

다음과 같이 main() 함수내에서 메모리를 할당하고 doSomething()함수내에서 그 변수에 할당된 메모리를 해제하는 코드를 보자. 코드의 복잡성에 신경쓰지 말고 main() 함수내의 변수를 main()함수 밖에서 어떻게 조작하는지에 대한 것만 신경쓰자:

1
2
3
4
5
6
7
8
9
10
11
void doSomething(void **A) {       // double pointer
free(*A);       // A==&amp;target 이고 *A==target 이다
*A=0;
}

int main(void) {
void *target = malloc( 8 );          //(의미없는) 8바이트 메모리를 동적으로 할당하여 포인터 변수에 넣는다.
doSomething(&amp;target);   //포인터의 주소를 인자로 넘긴다.
if(target==0) printf("empty\n");     //main()함수 밖에서 직접 target 변수를 조작하였다. 따라서 출력은 <code>0</code>
return 0;
}

 

A==&target 이고 *A==target 이므로 *A 코드로써 target 변수 이름을 직접 쓰지 않고 main() 함수 밖에서 main()함수내의 변수에 할당된 메모리를 해제하고 0을 직접 넣었다!

 

이처럼 변수에  askterisk(*) 가 두개나 붙어서 복잡해 보여도 더블 포인터는 단순히 별명이라고 생각하면 어떻게 활용해야하며 무엇을 해야할지 굳이 일일이 나열하지 않아도 어느정도는 감을 잡을 수 있다.  더블포인터 떡칠했다고 머리 아퍼할 이유도 없다.

 

연습을 통해 자신있게 사용할 수 있게되는 것은 시간문제일 것이다. Good Luck!

  1. http://docstore.mik.ua/orelly/webprog/jscript/ch04_04.htm  

유통기한에 이르려면 아직 멀었다

C언어 의미론으로 보면 자바 변수는 모조리 포인터이지만 학습자는 C의 포인터에 대한 설명을 들으면 무슨 소리를 하는지 바로 이해하지 못하는 반면  Java 변수를 사용하는 것은 쉽고 직관적이라 여기는 글을 종종 본다. Java 변수의 타입은 이해한다고 생각할지 모르지만 C에서의 타입은 난해하게 여긴다.

 

바보시리즈(Learn XXX for Dummy) 나 쉽게 설명한.. 서적의 설명으로 이해했다고 착각하지만 실상 그것들이 머리속에 자리잡고 올바른 개념을 쫒아낸다는 것을 말해줘도 그냥 흘려버리는 것 같다. 결국, 이건 어떻게 설명해도 학습자가 수준이 낮다는 것 외엔 달리 설명할 방법이 없는듯싶다.

 

포인터에 대한 온갖 종류의 예를 보더라도 학습자가 한번에 이해하는 모습은 보질 못했다.  도대체 왜 그럴까?.. 온갖예를 들고있는 책의 저자는 분명히 포인터를 알고있고 그걸 알려주려고 그 많은 예를 들고 있는건데 왜 학습자는 그걸 한방에 알지 못할까? 왜 태어났는가에 대한 대답같은게 아니라 그저 포인터가 무엇이고 왜 써야하고 어떻게 쓴다라는 일차원적인 사항을 수십페이지에 걸쳐 설명하고 있는데 왜 그토록 이해하기 힘들어하는가?

 

혹시… 학습자의 물려받은 DNA가 구려터졌거나, 눈알이 상했거나, 단 몇분도 집중못하는 붕어급 기억력때문일까?  그렇지 않다면 왜 몇달 혹은 그 이상의 시간이 걸려도 이해하기 힘들어하고 해마다 생겨나는 C학습자는 똑같은 루틴을 반복할까..?

 

열팽창 계수, 마찰계수, 가속도 공식등.. 물리학이나 수학을 총동원해서 설명한다고 스케이트보드를 잘탈 수 있는게 아니듯 C의 포인터는 무엇이고 더블 포인터는 포인터를 가리키는 포인터라는 신생아급 설명을 해준다고 포인터를 잘 사용할 수 있는게 아님에도 불구하고 인터넷을 통해 좋다고 클릭질하며 유통되는 자료의 대부분이 다 그모양이다.

 

제발 의심을 해보길 바란다. 자신의 머리가 유통기간이 지난 상한 제품이 아니라고 믿고있는데도 불구하고 방금읽은 혹은 이전에 읽었던 서적이나 인터넷상의 설명을 듣고도 도대체가 뭔지 모르겠다면 읽는이의 지능이나 머리가 문제가 아니라 그 설명이 구려터진 것이고 엉터리일 가능성이 크다고 말이다.

 

포인터하나 제대로 이해하지 못했다고 모조리 저능아처럼 행동하거나 말한다는게 아니다. 프로그래밍질의 최대 피해는 아마도 이분법적인 사고의 강화가 아닌가 싶다. 이것 아니면 저것. 둘중 하나만 있는 상태를 규정하는 짓인 프로그래밍을 하면 할수록 인간적인 것이 무엇인지 잊고 살게되는 심각한 부작용이 있다고 생각한다.

 

내가 말하고 싶은 것은 포인터 따위의 이해여부에 따라 차등을 먹이는 것이 아니라 자신을 믿으라는 것이다.  어떤 개념을 들어 즉시 이해하지 못했다고 스스로가 프로그래밍에 자질이 적다거나 적성에 맞지 않는다고 생각할 것이 아니라, 그 개념설명이 어딘가 오류가 있지않나 의심하고 스스로 실험해 보라는 것이다.

 

사람의 판단이 착각의 연속이며 셀수없는 오류로 점철되어 있는지 이해해야만 프로그래밍을 잘 할 수 있는 것은 아니다. 그러나 분명한 것은 그럴듯해 보이는 글이나 설명을 들으면 의심없이 받아들인후 잘못된 것이라는 점을 깨달으려면 보고 들었던 시간의 몇천배에 해당하는 시간이 걸릴수도 있다는 것이다.

 

누군가 멋진 결과물을 한번 내놓았다고해서 모든 결과물이 훌륭하진 않다. 글을 많이 쓴다고 모든 글이 다 쓸모있진 않다. 모든 것을 잘하는 듯 보여도 사람의 쓰지 않는 재능은 후퇴한다. 처음엔 잘 못해도 시간을 들이면 결국 누구나 다 제대로 한다.  그 시간을 날로 먹으려하지만 않으면 누구나 다 어떤 목표치에 다 도달할 수 있다.  그러나 학습자가 스스로를 믿지않고 자신이 잘 이해하지 못하는 근본에 대해 의심하지 않으면 병든 닭처럼 뱅뱅 돌뿐이다.