Fork me on GitHub

11/23/2012

[Android] Pack 3rd-party shared library .jar/.so into apk by Android.mk

When building android application package by Eclipse, the shared library placed in libs/armeabi* will be packed into apk automatically.
If the building process is from android source tree, the Android.mk needs to be written. So, how to pack 3rd-party shared library .jar/.so into apk by Android.mk?
For .jar
# the name is just a name, it will map to real .jar later
LOCAL_STATIC_JAVA_LIBRARIES := refJar1 \
                               refJar2

# here maps to actual .jar location
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := refJar1 :libs/oooo.jar\
                                        refJar2 :libs/xxxx.jar
For .so
# Put .so to out/target/product/***/obj/lib
$(shell cp $(wildcard $(LOCAL_PATH)/libs/armeabi/*.so) $(TARGET_OUT_INTERMEDIATE_LIBRARIES)) 

LOCAL_JNI_SHARED_LIBRARIES := libs/libxxxx

References

  1. 在apk裡打包進.so文件的方法: http://blog.csdn.net/androidboy365/article/details/6772890
  2. Android build system分析: http://blog.csdn.net/ccskyer/article/details/6122963
  3. android 內置app編譯方法及Android.mk中的系統變量說明: http://bbs.ancode.org/forum.php?mod=viewthread&tid=86
  4. Android NDK開發指南---Android.mk文件: http://hualang.iteye.com/blog/1140414
  5. Android Application, Android Libraries and Jar Libraries: http://devmaze.wordpress.com/2011/05/22/android-application-android-libraries-and-jar-libraries/

11/06/2012

[OpenGL] RedBook example environment setup on Mac

This post records how to setup the OpenGL programming guide source example environment on Mac.

  • Install XCode OpenGL and GLUT come with the OS and Xcode installations. To verify, check for
     /System/Library/Frameworks/{OpenGL,GLUT}.framework
    
  • In your OpenGL source files, include the following line

      #include <OpenGL/gl.h>
      #include <OpenGL/glu.h>
      #include <GLUT/glut.h>
    
  • To make a GLUT application on the command line, use the following linker options:

     -framework OpenGL -framework GLUT
    

For Ubuntu, you can refer this: Setting up an OpenGL development environment in Ubuntu Linux

--EOF--

[SimpleCV] SimpleCV environment setup on Mac

This post records the process to setup the SimepleCV environment on MacOSX 10.8.2. The source code of SimpleCV is hosted on the Github. Below steps mostly refers to this project.
  • Install Xcode (remember to install Command-Line Tools)
  • Install Homebrew
    $ ruby -e "$(curl -fsSkL raw.github.com/mxcl/homebrew/go)"  
    
    // Add the Homebrew directory to your system path  
    _export PATH=/usr/local/bin:$PATH_ to .bash_profile
    
  • Install Python
    $ brew install python --framework --universal 
    
    // Add /usr/local/share/python to your system path   
    export PATH=/usr/local/share/python:$PATH  
    
    // change Lion's symlink to point at your new Python install  
    $ cd /System/Library/Frameworks/Python.framework/Versions  
    $ sudo rm Current  
    $ ln -s /usr/local/Cellar/python/2.7.3/Frameworks/Python.framework/Versions/Current  
    
    // To verify that your installation went as planned, type which python at the command line. You should see /usr/local/bin/python in response
  • Use Homebrew to install git, opencv
    $ brew install git  
    $ brew install opencv
    
  • Install the dependent libraries
    $ brew install sdl sdl_image sdl_mixer sdl_ttf smpeg portmidi  
    $ ARCHFLAGS="-arch i386 -arch x86_64" brew install PIL
    
  • Make symbolic links
    $ sudo ln -s /usr/local/lib/python2.7/site-packages/cv.so /Library/Python/2.7/site-packages/cv.so
    
    $ sudo ln -s /usr/local/lib/python2.7/site-packages/PIL /Library/Python/2.7/site-packages/PIL
    
    $ sudo ln -s /usr/local/lib/python2.7/site-packages/cv2.so /Library/Python/2.7/site-packages/cv2.so
    
    $ sudo ln -s /usr/local/lib/python2.7/site-packages/cv.py /Library/Python/2.7/site-packages/cv.py
    
  • Install pip (pip installs packages)
    $ sudo easy_install pip
    
  • Install NumPy, SciPy, IPython
    $ pip install numpy
    
    $ brew install gfortran
    $ pip install -e git+https://github.com/scipy/scipy#egg=scipy-dev  
    
    $ pip install ipython
    
  • Intall Mercurial
    $ brew install mercurial
    
  • Install PyGame
    $ sudo pip install hg+http://bitbucket.org/pygame/pygame
    
  • Install SimpleCV
    $ pip install https://github.com/ingenuitas/SimpleCV/zipball/master 
    
  • Install readline
    $ sudo easy_install readline
    
  • Start the SimpleCV shell
    $ simplecv
    

--EOF--

8/11/2012

[Linux] tweak process priority

在 debug vsync 的過程中,發現 CPU scheduling 對於 vsync accuracy 有影響,因此需要針對 vsync 所在的 process 修改其 process priority.
過程中發現利用 pthread 的 pthread_attr_t 並沒有辦法更動 priority,以下整理了網路上關於 process priority 的資料,目前猜測原因應該是:
Setting a priority under the default scheduling policy (SCHED_OTHER) isn't valid. The default Linux scheduling policy is SCHED_OTHER, which have no priority choice but a nice level to tweak inside the policy
由上面節錄的敘述中可以發現兩個陌生的東西:"scheduling policy" 和 "nice value". 來認識他們:
All Linux threads have one of the following scheduling policies:
  1. 'Normal' scheduling policies: ranging from 100 (highest priority) to 139 (lowest priority)
    SCHED_OTHER   the standard round-robin time-sharing policy;
    SCHED_BATCH   for "batch" style execution of processes; and
    SCHED_IDLE    for running very low priority background jobs.
    
  2. Real-time scheduling policies: ranging from 1 (lowest priority) to 99 (higest priority)
    SCHED_FIFO    a first-in, first-out policy
    SCHED_RR      a round-robin policy
    
Real-time scheduling 有什麼特性呢,簡單理解應該就是擁有比 Normal scheduling 更不可被搶佔的特性:
SCHED_FIFO can't be preempted (context switched to another process) unless another process of higher priority shows up in the execution queue.

SCHED_RR can be preempted by a time quantum (delay given to a process to execute).
一般的 process 沒有特別指定 default 應該都是 SCHED_OTHER 所以沒辦法透過 pthread_attr_t 設定其 priority,不過還有另外一個方法就是使用其 nice value.
Conventional process's static priority = (120 + Nice value)
因為 Normal scheduling policies 的 priority range 是從 100 ~ 139,那麼從上面可以推得,nice value 的 range 是 -20(highest priority) ~ 19(lowest priority).
至於設定 nice value 的方式似乎不只一種,經過試驗,setpriority 這個 function 是有效的。

Ref

  1. How to increase thread priority in pthreads?
  2. how to increase the priority of a child pthread relative to the parent thread
  3. Understanding Linux CPU scheduling priority
-- EOF --

7/29/2012

[C++] Nested Class

A nested class is declared within the scope of another class. The name of a nested class is local to its enclosing class. Unless you use explicit pointers, references, or object names, declarations in a nested class can only use visible constructs, including type names, static members, and enumerators from the enclosing class and global variables.

A nested class is a member and as such has the same access rights as any other member. The members of an enclosing class have no special access to members of a nested class; the usual access rules shall be obeyed.

class E 
{
    int x;
    class B { };

    class I 
    {
        B b; // OK: E::I can access E::B
            int y;
        void f(E* p , int i)
        {
            p->x = i; // OK: E::I can access E::x
        }
    };

    int g(I* p)
    {
        return p->y; // error: I::y is private
    }
};

Ref

  1. The inner class idiom
  2. http://www.csie.ntu.edu.tw/~b90102/homework/Java/
  3. http://blog.csdn.net/jemmy/article/details/1638296

– EOF –

6/20/2012

[Android] oprofile 使用步驟

This post records the basic flow to use oprofile tool on Android

OProfile consists of a Kernel driver and a daemon for collecting data. It makes use of the hardware performance counters provided on Intel, AMD, and other processors. OProfile is capable of profiling all code including the Kernel, Kernel modules, Kernel interrupt handlers, system shared libraries, and other applications.

Modern processors support profiling through the hardware by performance counters. Depending on the processor, there can be many counters and each of these can be programmed with an event to count. Each counter has a value which determines how often a sample is taken. The lower the value, the more often it is used.

During the post-processing step, all information is collected and instruction addresses are mapped to a function name.

Here we go ~

  1. Add config, re-build kernel then flash into device

    CONFIG_OPROFILE_ARMV7=y
    CONFIG_OPROFILE=y
    CONFIG_PROFILING=y
    CONFIG_HAVE_OPROFILE=y
    CONFIG_TRACEPOINTS=y
    
  2. Build oprofile tool

    $ source setbuildenv
    $ cd {root}/external/oprofile
    $ mm
    
    The output will be at "out/host/linux-x86/bin/"
    
  3. Copy needed file

    $ cp {root}/external/oprofile/events/arm/* /usr/local/share/oprofile/arm
    
  4. Copy vmlinux into device (Optional, if you want to profile kernel)

    $ adb push ${OUT}/obj/KERNEL/arch/arm/boot/compressed/vmlinux data/
    
  5. Setup oprofile

    opcontrol --setup --event=CPU_CYCLES:1500000
    opcontrol --setup --vmlinux=/data/vmlinux --kernel-range=0xc00xxxxx,0xc0xxxxxx --event=CPU_CYCLES:1500000 (profile kernel)
    
    The option --kernel-range can be obtained from /proc/kallsyms.
    $ (adb shell cat /proc/kallsyms) | grep " _text" 
    $ (adb shell cat /proc/kallsyms) | grep " _etext" 
    
    or you could query System.map file
    $ grep " _text" System.map
    
  6. Check status

    opcontrol --status
    
  7. Start profiling

    opcontrol --start
    
  8. Stop profiling

    opcontrol --stop
    
  9. Get profiling result

    $ cd {root}/external/oprofile
    $ ./opimport_pull <result path>
    
  10. Get a simple report

    $ cd {root}/out/host/linux-x86/bin/
    $ ./opreport --session-dir <result-path> -m all
    $ ./opreport -g -l -p <path-to-symbols> --session-dir <result-path>
    
  11. Get annotated report

    $ ./opannotate -p <path-to-symbols> -s -d <path-to-source-files-e.g.-mydroid> --session-dir <result-path>
    
  12. Profiling based on thread

    opcontrol --setup --event=CPU_CYCLES:1500000 --separate=thread // profiling based on thread
    $ ./opimport_pull <result-path>
    $ ./opreport --session-dir <result-path> -l tgid:[pid you want]
    

References

  1. OProfile manual
  2. Profiling the Android kernel and native applications using OProfile
  3. Profiling Tools - ftrace, perf, and oprofile
  4. how-to to oprofile 0xdroid
  5. oprofile 使用步驟 測試程序中各函數運行時間
  6. OProfile—System-Wide Profiler

--EOF--

6/14/2012

[Linux] Unbalanced irq

中斷算是 kernel 開發過程中經常遇到問題的部份,最近在 log 當中經常看到 Unbalanced irq 的訊息,雖然只是 Warning,還是想研究一下怎麼把它弄掉!

搜尋後整理一些網路上關於 irq 使用的資訊摘要如下:

  1. enable_irq unbalanced messages 是無害的

     unbalanced 這個問題只會發生在 enalbe_irq 函數中,這裡要提到一個變量disable_depth,這是一個標志中斷禁止與否的變量,如果調用 disabled,這個變量會 ++,成正數,表示禁止中斷; 如果是 enable,這個變量會 --,表示允許。
    
     而如果這個變量本身就是 0,再去 enable 它的時候,表示你這個中斷本來就是打開的,你現在再去打開沒有必要,這就是 unbalanced 了
    
  2. request_irq 的調用應該放到所有的准備工作都完成後再進行

     我們應該確保只有在有能力處理中斷的時候在去註冊中斷!因為只要 request_irq 正確返回就意味著可以響應中斷了。
    
     想要在該註冊函數返回後立刻調用 disable_irq 來暫時屏蔽中斷,然後在後面的某個時刻在 enable 中斷是不對的。因為在你 disable_irq 之前可能中斷已經發生並且調用了中斷處理函數!
    
     一般對中斷的注冊都放在 probe 的最後一步來做!這樣可以避免一些中斷過早被調用的問題!
    
     一般我們會在中斷處理函數進去的時候 disable 一個 irq,並在中斷處理函數退出的時候 enable 這個 irq。這樣做當然能讓 disable 和enable 匹配的很好。
    
     但有的時候你可能想把 disable 放到中斷當中,而把 enable 放到下半部去完成。這就要慎重了,需要仔細檢查下半部的代碼是否一定會在你需要的時候被執行,稍有不慎你可能就會造成下半部的 enable 未被執行。導致缺少一次匹配的 enable,進而導致中斷失效。
    
  3. 中斷有可能在不那麼容易被注意到的時機被觸發

     引述 Reference 中的例子:
    
     在設計這個電容屏的驅動時,我的設計為在其 suspend 函數中直接切斷電容屏的電源以省電,然後在 resume 函數中再從新上電。中斷觸發方式為下降沿觸發方式。測試發現,當在 suspend 中調用斷電操作後總會導致一個 I2C 讀取動作發生,而這個讀取動作是我在中斷處理函數的底半部中實現的動作。僅僅是電容屏的一個斷電動作怎麼會導致這個動作發生呢?
    
     降沿觸發嘛~~  當電容屏斷電後當然沒有誰去保持那個中斷引腳為高電平了,它當然會恢復為默認的低電平了(該平台的中斷默認為電平)。顯然這個過程會導致一個下降沿發生,這便會引起中斷處理函數被調用,從而引起底半部的工作隊列被執行,然後 I2C 讀取動作便發生了。可是這時候電容屏都斷電了,讀取當然要出錯了!
    
     現在的問題就是如何讓這個下降沿不要發生,那就只能想辦法讓系統不要理會這個下降沿。簡單,斷電前先 disable 中斷,resume 完成後重新 enable 這個中斷就好了
    
  4. request_irq 之後沒有 disable 過的 irq 如果 enable_irq 都會造成 Unbalanced irq 的 warning

References

  1. linux中斷的unbalanced問題
  2. request_irq的執行時機 關鍵字: irq INT 底半部 unbalanced 工作隊列
  3. unbalanced enable irq 問題的解決 以及共享的gpio中斷引起的問題
  4. Linux 中斷學習之小試牛刀篇

6/07/2012

[Android] wake lock

"wake lock" was a set of patches to the Linux kernel to allow a caller to prevent the system from going to low power state.

所以,在 kernel 下,可以運用這種機制,讓系統不要進入 suspend。

  1. 加入必要 header

    #include <linux/wakelock.h>
    
  2. 初始化 wake lock

    wake_lock_init(&wlock, WAKE_LOCK_SUSPEND, "hdmi_active");
    
    
    通常在 module init 函數或是 probe 函數當中進行這個動作。第二個參數可設定為 WAKE_LOCK_IDLE / WAKE_LOCK_SUSPEND
    
  3. 鎖住 wake lock

    wake_lock(&wlock);
    
  4. 釋放 wake lock

    wake_unlock(&wlock);
    
  5. 註銷 wake lock

    wake_lock_destroy(&wlock);
    

在程式碼中完成後,如何驗證 wake lock 是否正確的被 lock/unlock 呢?可以利用不斷 cat proc/wakelocks 這個 node,觀察其變化。如果已經被 unlock 了,那麼 time 的欄位就會停止變動。

watch -n 1 'adb shell "cat proc/wakelocks" | grep usb_udc_lock' 

Ref.

  1. Android Power Management
  2. Android wakelock的申請和釋放

4/20/2012

[Linux] Use Debugfs on Android

Android 在 user space 可以在 run-time 的時候透過 adb shell getprop/setprop 來動態讀寫變數。所以,kernel 開發的過程中,我在想有沒有類似的東西讓我可以動態的存取變數,這樣 debug 會方便許多。

於是,發現了 Linux 其實已經有提供一個 light-weight 的 filesystem 叫做 Debugfs, 正好可以滿足我的需求,紀錄一下使用方式。

  1. Enable Debug FileSystem

    Kernel hacking
        [*] Debug filesystem
    
    mount -t debugfs none /sys/kernel/debug // Do this manually
    
  2. Include header

    #include <linux/debugfs.h>
    
  3. Call the API to create dir and file, then put them into the module init func

    struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
    struct dentry *debugfs_create_u8(const char *name, mode_t mode, struct dentry *parent, u8 *value)
    
    static struct dentry *dbg_entry_dir, *dbg_entry_test;                                           
    u8 dbg_print_test = 0;
    
    static int debugfs_init(void) {
        dbg_entry_dir = debugfs_create_dir("test_debugfs", NULL);
        if (!dbg_entry_dir)
            return -1;
    
        dbg_entry_test = debugfs_create_u8("print_test", 0644, dbg_entry_dir, &dbg_print_test);
        if (!dbg_entry_test)
            return -1;
    
        return 0;
    }
    
  4. Remember to remove after module remove

    void debugfs_remove(struct dentry *dentry)
    
    debugfs_remove(dbg_entry_dir); // Put this in module remove func
    
  5. Use the filenode you create to debug

    adb shell cat sys/kernel/debug/test_debugfs/print_test
    
    adb shell;
    echo 1 > sys/kernel/debug/test_debugfs/print_test
    

Reference

Linux Debugfs文件系統介紹及使用

Debugfs

Linux内核里的DebugFS

Debugfs

Kernel debugging

-- EOF --

4/07/2012

[C] variable/function scope in C

習慣 C++ 後換到 C 這種更精簡的語言,反而不是很清楚變數的生命週期,以及在不同程式單元共用的方式,所以 Google 了一篇 Scope and Storage Classes in C,在此筆記一下!

總而言之,4 scope, 4 specifier, 2 modifier

4 scope

Block
所謂 block 就是 { 和 } 包圍起來的區域,block scope 就是指自變數宣告處一直到 } 的生命週期。

Function
在 { 和 } 內都存活的生命週期。In C, only the goto label has function scope。

File
即 static + (program scope variable)

Program
當變數在函數以外宣告則為 program scope,也就是所謂的全域變數。全域變數欲在其他檔案存取時,需以 extern 關鍵字 declare 一次。

4 specifier

auto
只有在 block scope 的變數可以使用這個 specifier,但是 block scope 的變數本來就是 temp 的,所以這個很少用。

static
static 可以用在 block scope 或 program scope,當用在 block scope 時,指稱該變數具有 permanent duration,也就是出了該 block 該變數仍存在的意思;當用在 program scope 時,也就是用來修飾全域變數時,即把 program scope 縮小為 file scope,除了該檔案其他檔案無法使用。

register
建議 compiler 將變數儲存到 CPU 暫存器的修飾子。

extern
欲在另一檔案中使用某檔案之 program scope 變數,需要在該檔案 file scope 內搭配 extern 再宣告一次欲使用之變數。

2 modifier

const
const 變數宣告即必須初始化,並且之後不能再被賦值。

volatile
When the C compiler optimizes your program automatically, it intends to not update the value held by the variable unless the variable is on the left side of an assignment operator (=).

volatile 變數 tells the compiler not to optimize any expressions of the variable because the value saved by the variable may be changed without execution of any explicit assignment statement.

以上是變數的生命週期,另外函數的 scope 則相對簡單,沒有修飾子的函數即為全域函數,如果在前面加上 static 修飾子,就變成 file scope。如果另外一個檔案要使用 file scope 的函式,則需加上 extern 修飾子聲明。

接下來一定會有一個疑問,就是在 C 的世界裡面,要怎麼實現 private function 呢?在 C 裡頭並沒有強的 module 概念,可以參考 Ref2 當中的 translation unit,一個 translation unit 就是 source file 加上他包含的 header file (包括巢狀 include 當中的)。

所以,如果要實現 private function 的話,一樣也是用 static 關鍵字,將 function scope 縮小至 file scope,然後需要調用該函數的內部函數記得將 declaration 加到 header file 當中即可。

References

  1. How to implement a “private/restricted” function in C?
  2. Concept of modules in c

-– EOF --

2/09/2012

[Git] How to combine multiple commits to only one patch

one commit for one goal 是一個好習慣,不過往往會在 local branch 新增許多 commits。等到 feature 完成,有時候會希望可以將這些 commits 全部整理成一個 patch,方便 forward 給別人 或是 apply 回 master branch,這時該怎麼做呢?

假設你從 branch master checkout 一出一個 branch feature 做開發,然後在 branch feature 上面提交了一些 commits。現在你希望將這些 commits 弄成一個單一的 patch,然後 apply 到 branch master 上面。

首先,先回到 branch master,建立一個跟 master 一樣的 temp branch tmpsquash

git checkout -b tmpsquash

在 branch tmpsquash 上以 --squash 的方式 merge 到 branch feature

git merge --squash feature

於是你就會看到,branch feature 那些 commits 的內容全變成了 branch tmpsquash 的 diff。這時候你就可以把它弄成一個 commit。

git commit -a -m "My squashed commits"

最後,將他打包成一個 patch

git format-patch master

Reference

  1. How do you squash commits into one patch with git format-patch?

-- EOF --

1/14/2012

tmux - A powerful terminal multiplexer

tmux 顧名思義 terminal multiplexer 是一個終端多工器,什麼時候會需要呢?

  1. 當你需要開啟多個終端視窗,但是又不希望底下的視窗列被擠得滿滿
  2. 階層的概念讓你可以將終端依照任務的需求群組起來 (Session -> Window -> Pane)
  3. 使用 ssh 連入主機時,可以方便 user 不需要開啟多個 ssh 連線也可以開啟多個終端視窗

以下就紀錄一下這幾天下來的一些使用心得和筆記

Installation

sudo apt-get install tmux

Hierachy

Session 可以把他想像成 task 的概念,要完成一個 task 可能會需要開啟很多的終端。例如: 開啟 vim 的終端、開啟 git 的終端、開啟 grep 的終端, 等等...。這一個個的終端在 tmux 當中就是一個一個的 Window。所以,Window 算是一個終端基本單元,而 Session 就是 Window 的容器。

tmux 的功能鍵有一個前綴,預設是 Ctrl + b,但是改成 Ctrl + a 應該會比較方便, 下面用 Prefix 表示

tmux new -s <session-name>          // 創建一個 session, 然後進入該 session
tmux kill-session -t <session-name> // 刪除 session

當你建立了一個 session,你可以在任意時間離開它,然後在任意時間回到這個 session 而不遺失任何你離開前開啟的 window。

<Prefix> + d                    // 離開 session, d: detach
<Prefix> + s                    // 列出所有 session, 並可以跳轉
tmux attach -t <session-name>   // 回到 session 

在學會 attach/detach 以後,接著就是如何在 session 裡頭建立 Window

tmux neww -n <window-name>      // 建立新 window
<Prefix> + ,                    // 更改 window 名稱
<Prefix> + 數字鍵                // 跳轉 window
<Prefix> + x                    // 刪除 window

tmux.conf

以上就是一些 tmux 的簡單操作,此外 tmux 有一個 tmux.conf 可以讓使用者將 tmux.conf 客製化成更稱手的兵器。

// remap prefix to Control + a
set -g prefix C-a
unbind C-b
bind C-a send-prefix

// set window start from 1
set -g base-index 1

// scrollback buffer n lines
set -g history-limit 5000

// C-a C-a for the last active window
bind-key C-a last-window

// Highlight active window
set-window-option -g window-status-current-bg red

// Default colors
set -g status-bg black
set -g status-fg white

// Left side of status bar
set -g status-left-length 20
set -g status-left '#[fg=green][#[bg=black,fg=cyan]#S#[bg=black,fg=blue,dim]#[fg=green]]'

// <Prefix> - 水平分割視窗
bind - split-window -v
// <Prefix> - 垂直分割視窗
bind | split-window -h

Reference

  1. Practical Tmux
  2. How do I scroll in tmux
  3. Tmux試用感想

-- EOF --

1/08/2012

My Vim Configuration

Title: 我的 vim 進化史 Tags: vim

工具這種東西就是需要用到的時候就去查,然後記錄下來每次要用就看一下,用久了就熟了。分享也順便記錄一下目前 vim 所用到的一些筆記和設定。

vim note

  • Edit

      u           // Undo
      <Cr-R>      // Redo
    
      "dy                     // put this copy into buffer "d"
      Insert mode: <Cr-R>d    // paste from buffer "d"
    
      "ayw        // 複製一個字到 buffer a
      "ap         // 貼上 buffer a 當中的字
      /<Cr-R>a    // 搜尋 buffer a 當中的字
    
      :e          // 在 vim 當中開啟同資料夾下的其他檔案
      :bufdo e!   // refresh all files in buffers
    
      yaw         // yank around word
      ci"         // change inside quote
      ctX         // change till X
    
  • Search

      n           // Find next
      N           // Find previous
    
      *           // Go to next occurrence of word under cursor
      \#          // Go to previous occurrence of word under cursor
    
  • Move

      16G         // 跳到第16行
      1G          // 跳到第1行
      G           // 跳到最後一行
    
      <Cr> E      // 往下捲動一行
      <Cr> Y      // 往上捲動一行
      <Cr> F      // 往下捲動半頁
      <Cr> B      // 往上捲動半頁
    
      <Cr> O      // previous cursor location
      <Cr> I      // next cursor location
    
      gf          // 在當前視窗打開游標下的檔案
      <Cr-W> gf   // 在新的Tab打開游標下的檔案
      gt          // next tab
    
  • Window

      vsp <file.path>     // vertical split window
      :set scrollbind     // set current window scroll bind
    
  • Ctags

      <Cr> ]      // go to definition
      <Cr> t      // previous step
    
  • Cscope

      // 建立 Cscope 資料庫
      find . -name "*.h" -o -name "*.c" -o -name "*.cc" -o -name "*.cpp" -o -name "*.hpp"  > cscope.files
      cscope -Rbkq
    
      :cs find <parameter> <search-item>
    

vimrc

  • General (一般設定)

      syntax on
      filetype on
    
      set nu
      set confirm
      set modeline
      set showcmd
      set nobackup    
      set hlsearch
      set autoindent
      set noswapfile
      set smartindent
      set nocompatible
    
      set ls=2
      set tabstop=4
      set backspace=2
      set shiftwidth=4
      set encoding=utf-8
      set fileencodings=utf-8,cp950
    
  • Appearance (外觀設定)

      "set textwidth=90
      "set expandtab
      colorscheme desert
    
      " status line appearance (狀態列的設定)
      set statusline=
      set statusline +=\ %n\             "buffer number
      set statusline +=%{&ff}            "file format
      set statusline +=%y%*              "file type
      set statusline +=\ %<%F            "full path
      set statusline +=%m                "modified flag
      set statusline +=%=%5l             "current line
      set statusline +=/%L               "total lines
      set statusline +=%4c\              "column number
      set statusline +=0x%04B\           "character under cursor
    
  • Keys Mapping (快捷鍵設定)

    • Split window (分割視窗)
      用法:按 vv 垂直分割,ss 水平分割

        nnoremap <silent> vv <C-w>v
        nnoremap <silent> ss <C-w>s
      
    • Toggle cursorline/cursorcolumn or center line
      功能:trace code 的時候如果有開輔助線,比較容易跟上游標
      用法:按 F12 一次顯示底線,兩次顯示垂直線,三次兩者都顯示

          nmap <F12> zz
          if version >= 700 " NONE turns off underlining
              highlight CursorLine NONE ctermbg=Yellow
              highlight CursorColumn NONE ctermbg=Yellow
              let s:lico=0
              function LiCo()
                  let s:lico=s:lico>2 ?0 :s:lico+1
                  let &cursorline=s:lico % 2
                  let &cursorcolumn=s:lico / 2
              endfun
              nmap <silent> <F12> :call LiCo()<cr>
          endif
          imap <F12> <c-o><F12>
          vmap <F12> <c-c><F12>gv
      
    • Insert blank line without into insert mode
      功能:每次要新增一個空行,要按 o 再按 Esc 還蠻麻煩的
      用法:按 Enter 在下方新增一個空行, Shift+Enter 則在上方

        map <S-Enter> O<Esc>
        map <CR> o<ESc>k
      
    • Copy/Paste cross session
      功能:在多個開啟的 vim 視窗間複製貼上
      用法:Ctrl+V 選取欲複製之區段, Shift+Y 複製, 跳到另外一個 session 按 Shift+P貼上

        "custom copy'n'paste
        "copy the current visual selection to ~/.vbuf
        vmap <S-y> :w! ~/.vbuf<CR>
        "copy the current line to the buffer file if no visual selection
        nmap <S-y> :.w! ~/.vbuf<CR>
        "paste the contents of the buffer file
        nmap <S-p> :r ~/.vbuf<CR>
      
    • Mark redundant spaces
      功能:移除多餘的 trailing space
      用法:按 F3 標示出多餘空白, 持續按 N 向下搜尋, 按 X 刪除

        function ShowSpaces(...)
            let @/='\v(\s+$)|( +\ze\t)'
            let oldhlsearch=&hlsearch
            if !a:0
            let &hlsearch=!&hlsearch
            else
            let &hlsearch=a:1
            end
            return oldhlsearch
        endfunction
      
        function TrimSpaces() range
            let oldhlsearch=ShowSpaces(1)
            execute a:firstline.",".a:lastline."substitute ///gec"
            let &hlsearch=oldhlsearch
        endfunction
      
        command -bar -nargs=? ShowSpaces call ShowSpaces(<args>)
        command -bar -nargs=0 -range=% TrimSpaces <line1>,<line2>call TrimSpaces()
        nnoremap <F3>     :ShowSpaces 1<CR>
      
    • Show function name
      功能:函數 body 有時候太過龐大,可以不用按 [+{ 就看到函數名稱
      用法:按 , + f 顯示游標所在函數名稱

        fun! ShowFuncName()
          let lnum = line(".")
          let col = col(".")
          echohl ModeMsg
          echo getline(search("^[^ \t#/]\\{2}.*[^:]\s*$", 'bW'))
          echohl None
          call search("\\%" . lnum . "l" . "\\%" . col . "c")
        endfun
        map f :call ShowFuncName() <CR>
      

Plugin

  • Pathogen: 管理套件的套件

    如果你的工作環境會切換不同的電腦的話,那麼實現 vim 套件同步就是一個大問題了,因為總不能每換一次電腦就要重新安裝所有套件吧,那實在太累了。

    概念很簡單,想到同步,那麼會想到利用 git 來管理 .vim 目錄,那麼只要把你的 .vim 放到 github,在不同電腦上就可以 sync 同樣的設定。

    一般安裝許多 plugin 後,檔案會散落在各處,造成 .vim 目錄看起來一團混亂,這時候就是 Pathogen 派上用場的時刻了。

    利用 git submodule 搭配 Pathogen 套件,將每一個套件當做 submodule 管理,在 vim 啟動時透過 Pathogen 將套件載入,乾淨俐落。更詳細的作法可以參閱 Synchronizing plugins with git submodules and pathogen

  • SuperTab: 不需要什麼設定,也不用產生 tags 檔案,裝好即用的自動補完套件

    SuperTab 補齊所使用的關鍵字是藉由搜尋所有被開啟檔案的內容,所以不需先建立 tags 檔。當你打字打到一半需要它幫你補齊時就按下 Tab 鍵,它就幫你把剩下的字補齊。

    因為,一般需要補齊的東西蠻多都是 local 變數的,所以這個套件相當好用。如果你的意圖是真的要一個 indent 而不是自動補齊,那麼就用 Ctrl+V 再按 Tab。

    另外,如果需要更強大的補齊套件,C/C++ 語言的話,可以參考 OmniCppComplete

  • MinibufExplorer: 簡單好用的 vim 分頁套件

    如果每用 vim 開一個檔案就要占一個 terminal,那實在太浪費空間啦。所以,有沒有類似瀏覽器分頁效果的套件呢!有的,MinibufExplorer 就是你要的!

    在開啟的 vim 檔案中,使用方式:

      :e <要開啟的檔案路徑>   // 開啟檔案於新分頁
      :b <number>             // 跳到第 <num> 個分頁
      :bd                         // 關閉現在所在的分頁
    
  • Align: 對齊愛好者必裝套件

    有時候利用 tab 來對齊其實還蠻繁瑣的,如果有這個套件輔助,對齊會變的相當簡單俐落。

    使用前:

      int a = 12;
      int blogNum = 3;
      int day = 5;
    

    使用後:

      int a       = 12;
      int blogNum = 3;
      int day     = 5;
    

    安裝方式:

      vim Align.vba.gz    // 用 vim 開啟 Align.vba.gz
      :so %
      :q
    

    使用方式

      :10,20Align =   // 從第10行到第20行,以 = 符號進行對齊
    
  • Ctags, Cscope: C/C++ 開發必裝套件

    這兩套就不用多說了,要實現類似 IDE 強大的 go to definition 的功能,這兩個套件是不可或缺的!

    Ubuntu 下直接安裝方式:

      sudo apt-get install ctags cscope global
    

References

  1. Learn to speak vim – verbs, nouns, and modifiers!: 了解 vim 指令的文法,可以更快速的舉一反三喔!

  2. Writing Vim Plugins

  3. Learn Vimscript the Hard Way

1/01/2012

使用 Markdown 搭配 Vim 寫 Blog

Markdown 是一種非常好用的輕量級標記語言,其易讀易寫並且方便發佈在網路上的特性,使得他越來越被廣泛的使用。所以,記錄一下使用 markdown 和 vim 來寫 blog 所使用到的工具。

  1. 下載 markdown

    Markdown 解譯器是一個 perl 寫成的 script,所以要將寫好的 markdown file 轉成 html,就需要下載這個 script。當然,你要先確定你的系統有 perl 環境才行。

  2. 幫 vim 裝上 markdown 語法高亮度

    參照 Markdown syntax highlighting and conversion in vim 一文,設定好以後,以後開啟 .mkd 檔,vim 就會高亮度標記 markdown syntax 啦!

  3. 將 markdwon 轉換成 html

    只要在 vim 裡面下這行指令,就可以將 markdown 轉換成 html 格式。我把 Markdown.pl 放在 dropbox 當中以便雲端作業。

    :%!~/Dropbox/Markdown.pl --html4tags
    
  4. 學習 markdown 語法 和 一些所見即所得工具

    markdown 的語法其實不多,也相當好記,最重要的應該就是熟練吧!也有一些所見即所得的工具可以讓你即時看到 markdown 轉換成 html 的效果,有助於學習和記憶!

    1. 線上轉換成 html 和 preview 工具

    2. Markdown 語法說名

    3. 所見即所得的 markdown editor

小結

使用 markdown 來撰寫 blog 這種不需要太華麗編排的文章格式已經是綽綽有餘,只是有時後一些眉角還是要注意一下

  1. 像是如果需要在 list 裡面放 code block 那麼就得要 indent 8 spaces 才行

  2. Markdown 的連結有分 行內參考 兩種形式,參考的形式還蠻適合用來寫學術論文或是一些大量引用的文章,可以把一些 reference 集中在一起管理

-- EOF --