/static/codemoomoo2.png

5. Editors in Linux (Vim)

Text Editor เป็นเครื่องมือพื้นฐานที่สำคัญที่สุดของผู้ดูแลระบบและนักพัฒนาบนลินุกซ์ โดยเฉพาะบน Server ที่ไม่มี GUI การเชี่ยวชาญ Vim ซึ่งเป็น Editor แบบ Modal ที่มีอยู่ในเกือบทุก Unix-like System จะช่วยเพิ่มประสิทธิภาพการแก้ไขข้อความอย่างก้าวกระโดด บทความนี้ครอบคลุมตั้งแต่แนวคิดพื้นฐาน โหมดการทำงาน การเคลื่อนที่ การแก้ไข การค้นหา-แทนที่ การตั้งค่า ไปจนถึง Neovim สมัยใหม่และระบบ Plugin


5.1 ภาพรวมของ Text Editor (Text Editor Overview)

Text Editor คือโปรแกรมที่ใช้สำหรับสร้างและแก้ไขไฟล์ข้อความธรรมดา (Plain Text) แตกต่างจาก Word Processor ตรงที่เน้นการแก้ไขข้อความบริสุทธิ์โดยไม่มี Formatting แบบ Rich Text ซึ่งเหมาะสำหรับงานเขียนโค้ด (Source Code), ไฟล์ตั้งค่า (Configuration File) และเอกสารแบบ Markup เช่น Markdown หรือ LaTeX

5.1.1 CLI Editor (Command-Line Interface Editor)

CLI Editor คือ Editor ที่ทำงานบน Terminal ล้วน ๆ ไม่ต้องอาศัยระบบกราฟิก เหมาะสำหรับการแก้ไขไฟล์บน Server ที่เข้าถึงผ่าน SSH

5.1.2 GUI Editor (Graphical User Interface Editor)

GUI Editor มีหน้าต่างและเมนูแบบภาพ เหมาะกับงานบนเครื่อง Desktop หรือ Laptop

5.1.3 TUI IDE (Text-based User Interface IDE)

TUI IDE อยู่กึ่งกลางระหว่าง CLI Editor และ GUI IDE — ทำงานใน Terminal แต่มี UI ที่ซับซ้อนเหมือน IDE

5.1.4 ความสำคัญของการใช้ Editor บน Server โดยไม่มี GUI

การทำงานกับ Server ในสภาพแวดล้อมจริง (Production) แทบทั้งหมดเป็นการเข้าถึงผ่าน SSH สู่ Terminal ที่ไม่มี GUI ทำให้ทักษะการใช้ CLI Editor กลายเป็นทักษะพื้นฐานที่ขาดไม่ได้

เหตุผลสำคัญ:

  1. Bandwidth น้อย — CLI Editor ส่งข้อมูลเป็นตัวอักษร ต่างจาก GUI ที่ต้อง forward X11 หรือใช้ VNC
  2. รองรับในทุก Distributionvi มีในทุก POSIX OS เป็น minimum guarantee
  3. ทำงานใน Recovery Mode / Single User Mode ได้ เมื่อระบบมีปัญหา
  4. ทำงานใน Container ที่ไม่มี GUI Stack ได้โดยตรง
  5. Latency ต่ำ เมื่อทำงานข้ามทวีปผ่าน SSH
flowchart TB
    User[ผู้ใช้
User] --> Dev{สภาพแวดล้อม
Environment} Dev -->|Desktop/Laptop| GUI[GUI Editor
VS Code, Zed, Sublime] Dev -->|Server via SSH| CLI[CLI Editor
vim, nano, emacs] Dev -->|Power User| TUI[TUI IDE
LazyVim, Helix] GUI --> Output[ไฟล์ข้อความ
Text File] CLI --> Output TUI --> Output Output --> VCS[Version Control
Git]

5.2 Vim Mode (โหมดการทำงานของ Vim)

สิ่งที่ทำให้ Vim แตกต่างจาก Editor ทั่วไปคือ Modal Editing — ในแต่ละโหมด ปุ่มคีย์บอร์ดจะมีความหมายต่างกัน ทำให้สามารถสั่งงานซับซ้อนได้โดยไม่ต้องย้ายมือไปที่ Mouse หรือ Arrow key

5.2.1 Normal Mode (โหมดเริ่มต้น – Command Mode)

Normal Mode คือโหมดเริ่มต้นเมื่อเปิด Vim ในโหมดนี้:

5.2.2 Insert Mode

Insert Mode เป็นโหมดสำหรับพิมพ์ข้อความเข้าไปในไฟล์ มีหลายวิธีเข้าโหมดนี้ ซึ่งแต่ละวิธีให้ตำแหน่ง Cursor ต่างกัน

คำสั่ง ความหมาย ตำแหน่งที่เริ่มพิมพ์
i insert ก่อนตัวอักษรที่ Cursor ชี้อยู่
a append หลังตัวอักษรที่ Cursor ชี้อยู่
I Insert at line start ต้นบรรทัด (หลัง indent)
A Append at line end ท้ายบรรทัด
o open line below เปิดบรรทัดใหม่ใต้บรรทัดปัจจุบัน
O Open line above เปิดบรรทัดใหม่เหนือบรรทัดปัจจุบัน
s substitute char ลบตัวอักษรปัจจุบันแล้วเข้า Insert
S Substitute line ลบทั้งบรรทัดแล้วเข้า Insert

5.2.3 Visual Mode

Visual Mode ใช้สำหรับเลือกข้อความ (Selection) ก่อนสั่งปฏิบัติการ (เช่น copy, delete, change)

5.2.4 Command-line Mode (Ex Mode)

Command-line Mode เปิดใช้งานด้วยปุ่มเริ่มต้น 3 ชนิด

stateDiagram-v2
    [*] --> Normal
    Normal --> Insert: i, a, o, I, A, O, s, S
    Insert --> Normal: Esc / Ctrl+[
    Normal --> Visual: v, V, Ctrl+v
    Visual --> Normal: Esc / v
    Normal --> CommandLine: ": / ?"
    CommandLine --> Normal: Enter / Esc
    Visual --> CommandLine: ":"
    Normal --> Replace: R
    Replace --> Normal: Esc
    note right of Normal
        โหมดเริ่มต้น
        Command Mode
        ใช้เวลามากที่สุด
    end note

ประสิทธิภาพของ Modal Editing สามารถประเมินได้ด้วยสูตรจำนวนการกดปุ่มเฉลี่ย (Average Keystroke) ต่อการแก้ไขหนึ่งครั้ง ยิ่งค่า K น้อย ยิ่งมีประสิทธิภาพสูง:

K = i=1n keystrokes(ei) n

โดยที่ K = จำนวนการกดปุ่มเฉลี่ยต่อการแก้ไขหนึ่งครั้ง, ei = การแก้ไขครั้งที่ i, n = จำนวนการแก้ไขทั้งหมด การใช้ Text Object และ Motion ช่วยลดค่า K ลงได้มาก เช่น ci" (change inside quote) ทำหน้าที่แทนการเลือกด้วย Mouse + ลบ + พิมพ์ = ลด Keystroke จาก ~10 กดเหลือ 3 กด


5.3 การเคลื่อนที่ใน Vim (Motions)

Motion คือคำสั่งเคลื่อนที่ Cursor ซึ่งสามารถนำไป "คูณ" กับ Operator เช่น d (delete), y (yank), c (change) เพื่อสร้างคำสั่งที่ทรงพลัง เช่น d5w = ลบ 5 คำถัดไป

5.3.1 ตัวอักษร (Character Motion)

💡 ที่มาของ hjkl — คีย์บอร์ดของ ADM-3A ในยุคแรก (ที่ Bill Joy ใช้เขียน vi) มีลูกศรพิมพ์บนปุ่ม h j k l พอดี

5.3.2 คำ (Word Motion)

5.3.3 บรรทัด (Line Motion)

5.3.4 หน้าจอ (Screen Motion)

5.3.5 ตำแหน่งพิเศษ

5.3.6 การค้นหา (Search Motion)

5.3.7 Marks

Mark คือการตั้งจุดอ้างอิงในไฟล์ เพื่อกระโดดกลับมาได้ภายหลัง

ตัวอย่างการใช้งานรวม (Combined Motion):

# ภายใน Vim — ทดลองกับไฟล์ตัวอย่าง
# สร้างไฟล์ทดสอบ
$ cat > sample.txt << 'EOF'
บรรทัดแรก: Introduction to Vim motions
บรรทัดสอง: h j k l เป็นการเคลื่อนที่พื้นฐาน
บรรทัดสาม: w b e สำหรับเคลื่อนที่ระดับคำ
บรรทัดสี่: gg ไปต้นไฟล์, G ไปท้ายไฟล์
บรรทัดห้า: สุดท้าย 100 และจบ
EOF

# เปิดไฟล์ด้วย vim
$ vim sample.txt

# ลองคำสั่งต่อไปนี้ (อยู่ใน Normal Mode):
# gg          -> ไปบรรทัดแรก
# G           -> ไปบรรทัดสุดท้าย
# 3G          -> ไปบรรทัดที่ 3
# 5w          -> ไปข้างหน้า 5 คำ
# $           -> ไปท้ายบรรทัด
# f:          -> หาเครื่องหมาย : ตัวถัดไป
# ma          -> ตั้ง mark ชื่อ a
# G           -> ไปบรรทัดสุดท้าย
# `a          -> กระโดดกลับไปที่ mark a

5.4 การแก้ไขข้อความ (Text Editing)

การแก้ไขใน Vim ยึดหลัก Operator + Motion / Text Object — เมื่อเข้าใจรูปแบบนี้ จะสามารถผสมคำสั่งนับพันได้จากส่วนประกอบไม่กี่ตัว

5.4.1 ลบ (Delete)

5.4.2 Yank (Copy)

ใน Vim เรียกการคัดลอกว่า yank (y) ไม่ใช่ copy

5.4.3 Paste

5.4.4 Change

Change = Delete + เข้า Insert Mode อัตโนมัติ มีประสิทธิภาพสูงมาก

5.4.5 Replace

5.4.6 Undo / Redo

5.4.7 Repeat (Dot Command)

. (dot) คือหนึ่งในคำสั่งที่ทรงพลังที่สุดใน Vim — ทำการแก้ไขครั้งล่าสุดซ้ำ

ตัวอย่าง: พิมพ์ cw แก้เป็นคำว่า Hello แล้ว Esc จากนั้นไปที่คำอื่น กด . — จะเปลี่ยนคำนั้นเป็น Hello ทันที

5.4.8 Count + Motion

Vim รองรับ Count นำหน้าคำสั่งเพื่อทำซ้ำ:

รูปแบบทั่วไป: [count][operator][count][motion]

5.4.9 Text Object

Text Object คือ "วัตถุทางข้อความ" ที่ Vim เข้าใจ เช่น คำ ประโยค ย่อหน้า ก้อนวงเล็บ — ใช้ร่วมกับ Operator โดยมีรูปแบบ 2 แบบ:

Text Object ความหมาย ตัวอย่าง
iw / aw word ciw เปลี่ยนคำ
is / as sentence das ลบประโยค
ip / ap paragraph yap yank ย่อหน้า
i" / a" string "" ci" เปลี่ยนข้อความใน ""
i' / a' string '' di' ลบข้อความใน ''
i( / a( หรือ ib () ci( แก้พารามิเตอร์
i{ / a{ หรือ iB {} ci{ แก้เนื้อใน block
i[ / a[ [] ci[
i< / a< <> ci<
it / at XML/HTML tag cit แก้เนื้อใน tag

ตัวอย่างใช้งานจริง:

# สมมติมีโค้ด Python นี้
def greet(name, greeting="Hello"):
    print(f"{greeting}, {name}!")

# ต้องการแก้ parameters ทั้งหมด
# -> เลื่อน Cursor ไปที่ใดก็ได้ภายใน () แล้วกด ci(
# -> Vim จะลบ "name, greeting="Hello"" และเข้า Insert Mode ทันที

# ต้องการเปลี่ยน "Hello" เป็นค่าอื่น
# -> เลื่อน Cursor ไปที่ใดก็ได้ภายใน "" แล้วกด ci"
# -> Vim จะลบ "Hello" และเข้า Insert Mode ให้พิมพ์ใหม่ได้เลย

5.5 Visual Mode และการเลือกข้อความ

Visual Mode ให้เราเห็นว่ากำลังเลือกอะไรอยู่ก่อนสั่ง Operator ซึ่งตรงกับแนวคิดของ Editor อื่น ๆ ที่คุ้นเคย (Select → Act)

5.5.1 Character-wise, Line-wise, Block-wise

5.5.2 การ yank / delete / change กับ Selection

เมื่อเลือกด้วย Visual Mode แล้ว สามารถกด Operator ได้ทันที

5.5.3 Block Indent

เมื่อต้องการ indent โค้ดหลายบรรทัดพร้อมกัน:

  1. กด V ที่บรรทัดแรก
  2. กด 5j เพื่อเลือก 5 บรรทัดลงไป (หรือกด V ตามด้วยเลือกบรรทัดปลายทาง)
  3. กด > เพื่อเพิ่ม indent หรือ < เพื่อลด indent
  4. กด . เพื่อทำซ้ำการ indent เดิม

5.5.4 Multi-line Insert ด้วย Ctrl+V + I + Esc

เทคนิคสุดยอดของ Visual Block Mode — เพิ่มข้อความหลายบรรทัดพร้อมกัน เช่น การเพิ่ม # หน้าทุกบรรทัดเพื่อ Comment:

# สมมติมีโค้ดนี้
line1 = "hello"
line2 = "world"
line3 = "vim"

# ขั้นตอน:
# 1. เลื่อน Cursor ไปที่ต้นบรรทัดแรก
# 2. กด Ctrl+v (Visual Block)
# 3. กด 2j เพื่อขยายการเลือกลง 2 บรรทัด (รวม 3 บรรทัด)
# 4. กด I (Insert ตัวพิมพ์ใหญ่)
# 5. พิมพ์ "# "
# 6. กด Esc
# 7. Vim จะใส่ "# " หน้าทุกบรรทัดที่เลือกพร้อมกัน

# ผลลัพธ์:
# line1 = "hello"
# line2 = "world"
# line3 = "vim"

การลบ column พร้อมกัน:

# ต้องการลบ "# " ออกจากทุกบรรทัด
# 1. เลื่อน Cursor ไปที่ # บรรทัดแรก
# 2. กด Ctrl+v
# 3. กด 2j (เลือกลง 3 บรรทัด)
# 4. กด l สองครั้ง (เลือก "# " ทั้ง 2 ตัวอักษร)
# 5. กด d เพื่อลบ
flowchart TB
    subgraph Select [ขั้นตอน Select]
        S1[v: Character] --> S2[V: Line]
        S2 --> S3[Ctrl+v: Block]
    end
    subgraph Extend [ขยาย Selection]
        E1[Motion: w, $, j, G]
        E2[Text Object: iw, ip, i-bracket]
    end
    subgraph Operate [ดำเนินการ]
        O1[y: Yank]
        O2[d: Delete]
        O3[c: Change]
        O4[greater: Indent+]
        O5[less: Indent-]
        O6[gU/gu: Case]
    end
    Select --> Extend --> Operate

5.6 Search และ Replace (ค้นหาและแทนที่)

การค้นหา-แทนที่ของ Vim ใช้ Regular Expression ที่ทรงพลัง สามารถทำ Refactoring เชิงข้อความได้อย่างรวดเร็ว

5.6.1 Pattern

5.6.2 Substitute Command

รูปแบบทั่วไป: :[range]s/pattern/replacement/[flags]

5.6.3 Range

Range ความหมาย
. บรรทัดปัจจุบัน
$ บรรทัดสุดท้าย
% ทั้งไฟล์ (เทียบเท่า 1,$)
1,10 บรรทัดที่ 1 ถึง 10
.,+5 บรรทัดปัจจุบันลงไปอีก 5 บรรทัด
'<,'> ช่วงที่เพิ่งเลือกใน Visual Mode
/pat1/,/pat2/ จากบรรทัดที่ match pat1 ถึง pat2

5.6.4 Flag

5.6.5 Regular Expression ใน Vim

Vim มีโหมด regex ของตัวเอง เรียกว่า Magic Mode โดยค่าเริ่มต้นใช้ magic

Metacharacter สำคัญ:

รูปแบบ ความหมาย ตัวอย่าง
. ตัวอักษรใดก็ได้ 1 ตัว a.c → abc, axc, a1c
* 0+ ตัวของตัวก่อนหน้า ab* → a, ab, abb
\+ 1+ ตัว ab\+ → ab, abb
\? 0 หรือ 1 ตัว colou\?r → color, colour
\d ตัวเลข 0-9 \d\+ → เลขต่อเนื่อง
\w word character (a-zA-Z0-9_) \w\+
\s whitespace \s\+ → ช่องว่างต่อเนื่อง
^ ต้นบรรทัด ^# → บรรทัดที่ขึ้นต้นด้วย #
$ ท้ายบรรทัด ;\s*$ → ; ตามด้วยช่องว่างท้าย
\(...\) group \(ab\)\+ → ab, abab
\1, \2 back-reference

Very Magic Mode — เพิ่ม \v ที่ต้น pattern เพื่อใช้ regex แบบ PCRE-like (ไม่ต้อง escape เยอะ)

" ธรรมดา (magic):
:%s/\(foo\)\(bar\)/\2\1/g

" Very magic (\v) — อ่านง่ายกว่า:
:%s/\v(foo)(bar)/\2\1/g

ตัวอย่างการ Refactor ด้วย Substitute:

# สร้างไฟล์ทดสอบ
$ cat > refactor_demo.py << 'EOF'
def get_user_name():
    user_name = "Alice"
    print(user_name)
    return user_name

def update_user_name(user_name):
    old_name = user_name
    return old_name
EOF

$ vim refactor_demo.py

" ภายใน Vim:
" 1) เปลี่ยน user_name เป็น username ทั้งไฟล์ (ถามก่อน)
:%s/user_name/username/gc

" 2) ลบบรรทัดว่างที่ซ้ำหลายบรรทัด ให้เหลือบรรทัดว่างเดียว
:%s/\n\n\+/\r\r/g

" 3) เพิ่ม type hint: def foo(x): -> def foo(x: str):
:%s/\vdef (\w+)\(user_name\):/def \1(user_name: str):/g

" 4) แทนคำเฉพาะ case-insensitive
:%s/alice/Bob/gi

5.7 การทำงานกับไฟล์และ Buffer

5.7.1 คำสั่งพื้นฐานการบันทึกและออก

คำสั่ง ความหมาย
:w บันทึก (write)
:w filename บันทึกเป็นชื่อใหม่
:w !sudo tee % บันทึกด้วย sudo เมื่อเปิดไฟล์มาโดยไม่มี permission
:q ออก (quit)
:q! ออกโดยไม่บันทึก
:wq / :x / ZZ บันทึกและออก
ZQ ออกโดยไม่บันทึก (เทียบเท่า :q!)
:wa บันทึกทุก buffer
:qa ออกจากทุก buffer
:wqa บันทึกและออกจากทุก buffer

5.7.2 Buffer

Buffer คือไฟล์ที่เปิดใน memory ของ Vim หนึ่ง session สามารถเปิดหลายไฟล์พร้อมกันได้

5.7.3 Window Split

5.7.4 Tab

Tab ของ Vim ต่างจาก Tab ของ Editor อื่น — เป็น กลุ่มของ window layout (ไม่ใช่ tab สำหรับเปิดไฟล์)

5.7.5 Register

Register คือพื้นที่เก็บข้อความที่ yank/delete ไว้ (คล้าย Clipboard หลายช่อง) ใช้ " นำหน้าเพื่อระบุ

Register ความหมาย
" Unnamed register (default สำหรับ y, d, c, s, x)
0 Yank register (เฉพาะ yank ล่าสุด ไม่รวม delete)
1-9 Delete history (delete ล่าสุดอยู่ใน "1)
a-z Named register (ผู้ใช้กำหนด)
A-Z Append to named register
+ System clipboard (X11 / Wayland)
* Primary selection (X11 middle-click)
/ Last search pattern
: Last ex command
. Last inserted text
% Current filename

ตัวอย่าง:

" yank บรรทัดไปเก็บใน register a
"ayy

" ไปอีกที่หนึ่งแล้ววาง
"ap

" append yank ถัดไปเข้า register a
"Ayy

" ดู register ทั้งหมด
:registers

" ดูเฉพาะ register a, 0, +
:registers a0+

" yank เข้า system clipboard
"+yy
" paste จาก system clipboard
"+p

5.8 การตั้งค่า Vim (Vim Configuration)

5.8.1 ไฟล์คอนฟิก

เมื่อเปิด Vim จะโหลดไฟล์เหล่านี้อัตโนมัติ สามารถ reload ขณะใช้งานด้วย :source ~/.vimrc หรือ :so $MYVIMRC

5.8.2 Options สำคัญ

" ============================================
" ~/.vimrc — ตัวอย่างไฟล์คอนฟิกพื้นฐาน
" ============================================

" --- General ---
set nocompatible           " ไม่ใช้โหมดเข้ากันกับ vi (เปิด feature vim)
set number                 " แสดงเลขบรรทัด
set relativenumber         " แสดงเลขบรรทัดแบบสัมพัทธ์ (ดีต่อการนับ motion)
set cursorline             " เน้นบรรทัดที่ cursor อยู่
set showcmd                " แสดง command ที่กำลังพิมพ์
set showmode               " แสดง mode ปัจจุบัน
set scrolloff=8            " เก็บ 8 บรรทัดขึ้นล่างขณะเลื่อน
set sidescrolloff=5        " เก็บ 5 คอลัมน์ซ้ายขวา
set wrap                   " ตัดคำเมื่อบรรทัดยาว
set linebreak              " ตัดที่คำ ไม่ใช่กลางตัวอักษร

" --- Indentation ---
set tabstop=4              " แสดง Tab เป็น 4 ช่อง
set softtabstop=4          " กด Tab/Backspace ครั้งละ 4 ช่อง
set shiftwidth=4           " >> / << ครั้งละ 4 ช่อง
set expandtab              " แปลง Tab เป็น Space
set autoindent             " สืบทอด indent จากบรรทัดก่อน
set smartindent            " เพิ่ม indent เมื่อขึ้นบรรทัดหลัง {

" --- Search ---
set hlsearch               " ไฮไลต์ผลการค้นหา
set incsearch              " ค้นหาแบบ incremental (แสดงขณะพิมพ์)
set ignorecase             " ไม่สนตัวพิมพ์เล็ก-ใหญ่
set smartcase              " ยกเว้นถ้า pattern มีตัวพิมพ์ใหญ่ จะเป็น case-sensitive

" --- File ---
set encoding=utf-8         " ใช้ UTF-8 (สำคัญสำหรับภาษาไทย)
set fileencoding=utf-8
set nobackup               " ไม่สร้าง backup file
set noswapfile             " ไม่สร้าง swap file
set undofile               " เก็บ undo history ข้าม session
set undodir=~/.vim/undodir " ที่เก็บไฟล์ undo
set autoread               " reload เมื่อไฟล์เปลี่ยนจากภายนอก

" --- UI ---
syntax on                  " เปิด syntax highlighting
set termguicolors          " รองรับสีแบบ 24-bit (GUI colors)
set background=dark        " พื้นหลังมืด
colorscheme gruvbox        " ใช้ theme Gruvbox Dark
set mouse=a                " เปิดใช้งาน mouse ทุกโหมด
set clipboard=unnamedplus  " ใช้ system clipboard เป็น default

" --- Leader Key ---
let mapleader = " "        " ตั้ง Space เป็น Leader Key

" --- Key Mappings ---
" บันทึกด้วย <Leader>w
nnoremap <leader>w :w<CR>
" ออกด้วย <Leader>q
nnoremap <leader>q :q<CR>
" ปิดไฮไลต์ค้นหา
nnoremap <leader>h :nohlsearch<CR>
" ย้าย window
nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l

" Visual mode: ย้ายบรรทัดที่เลือก
vnoremap J :m '>+1<CR>gv=gv
vnoremap K :m '<-2<CR>gv=gv

5.8.3 Color Scheme

Vim มี Color Scheme พื้นฐานหลายตัว และสามารถติดตั้งเพิ่มได้ ตัวอย่างยอดนิยม:

Scheme สไตล์ คำสั่ง
Gruvbox Dark Retro warm (น้ำตาล-เหลือง) colorscheme gruvbox
Solarized คอนทราสต์ต่ำ สบายตา colorscheme solarized
Nord โทนฟ้า-เทาเย็น colorscheme nord
Catppuccin Pastel ทันสมัย colorscheme catppuccin_mocha
Tokyo Night มืดโทนม่วง-น้ำเงิน colorscheme tokyonight
Dracula ม่วงเข้ม-ชมพู colorscheme dracula
One Dark คล้าย Atom One Dark colorscheme onedark

การติดตั้ง Gruvbox ด้วย vim-plug:

" ใน ~/.vimrc
call plug#begin('~/.vim/plugged')
Plug 'morhetz/gruvbox'
call plug#end()

" หลังจาก :PlugInstall
set background=dark
colorscheme gruvbox

5.8.4 Key Mapping

คำสั่ง ความหมาย โหมดที่ทำงาน
:map ทั่วไป (ทุกโหมด) + recursive all
:nmap Normal Mode + recursive n
:imap Insert Mode + recursive i
:vmap Visual Mode + recursive v
:noremap ทั่วไป ไม่ recursive all
:nnoremap Normal ไม่ recursive n
:inoremap Insert ไม่ recursive i
:vnoremap Visual ไม่ recursive v

⚠️ แนะนำให้ใช้ noremap เป็นค่าเริ่มต้น เพื่อป้องกันปัญหา recursive mapping ที่ทำให้ mapping ซ้อนกัน

" ตัวอย่าง: map jj เป็น Esc ใน Insert Mode
inoremap jj <Esc>

" ตัวอย่าง: เปิดเทอร์มินัลใน split ด้วย <Leader>t
nnoremap <leader>t :belowright split \| terminal<CR>

" Visual: จัดตัวอักษรใน selection ให้อยู่กึ่งกลาง (ต้องมี plugin)
vnoremap <leader>c :center<CR>

5.8.5 Leader Key

Leader Key คือปุ่ม "อินโทร" สำหรับ mapping ของผู้ใช้ ค่าเริ่มต้นคือ \ แต่นิยมเปลี่ยนเป็น Space เพราะกดง่ายและไม่ชนกับปุ่มอื่น

let mapleader = " "         " Space
let maplocalleader = ","    " Comma สำหรับ filetype-specific

" ตัวอย่างการใช้ Leader
nnoremap <leader>w :w<CR>   " Space + w บันทึก
nnoremap <leader>q :q<CR>   " Space + q ออก
nnoremap <leader>ff :Files<CR>  " Space + ff เปิด fuzzy finder

5.9 Plugin Manager และ Plugin ยอดนิยม

Plugin เป็นการขยายความสามารถของ Vim ตั้งแต่ File Explorer, Git Integration, LSP, Fuzzy Finder เป็นต้น

5.9.1 Plugin Manager

Manager ภาษา จุดเด่น
vim-plug VimL เบา เรียบง่าย นิยมที่สุดสำหรับ Vim
Vundle VimL รุ่นเก่า กำลังเสื่อมความนิยม
Pathogen VimL แค่จัดการ runtime path
dein.vim VimL เร็ว รองรับ async
packer.nvim Lua สำหรับ Neovim
lazy.nvim Lua ทันสมัยที่สุด lazy-loading ในตัว

ติดตั้ง vim-plug:

# สำหรับ Vim
$ curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim

# สำหรับ Neovim
$ sh -c 'curl -fLo "${XDG_DATA_HOME:-$HOME/.local/share}"/nvim/site/autoload/plug.vim --create-dirs \
       https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'

การใช้งานใน .vimrc:

" เริ่มบล็อก plugin
call plug#begin('~/.vim/plugged')

" Color scheme
Plug 'morhetz/gruvbox'

" File explorer
Plug 'preservim/nerdtree'

" Fuzzy finder
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'

" Git
Plug 'tpope/vim-fugitive'
Plug 'airblade/vim-gitgutter'

" Status line
Plug 'vim-airline/vim-airline'
Plug 'vim-airline/vim-airline-themes'

" Completion
Plug 'neoclide/coc.nvim', {'branch': 'release'}

" Editing helper
Plug 'tpope/vim-surround'
Plug 'tpope/vim-commentary'

call plug#end()

คำสั่ง vim-plug:

5.9.2 File Explorer

5.9.3 Fuzzy Finder

" ตัวอย่าง fzf.vim key mappings
nnoremap <leader>ff :Files<CR>     " ค้นหาไฟล์
nnoremap <leader>fg :GFiles<CR>    " ค้นหาไฟล์ใน git
nnoremap <leader>fb :Buffers<CR>   " ค้นหา buffer
nnoremap <leader>fr :Rg<CR>        " ripgrep ค้นหาข้อความทั่วโปรเจกต์
nnoremap <leader>fh :History<CR>   " ประวัติไฟล์ที่เปิด

5.9.4 Completion

5.9.5 Linter / Formatter

5.9.6 Git Integration

" vim-fugitive — ตัวอย่างคำสั่ง
:Git                " git status ใน window
:Git blame          " git blame
:Git commit         " commit
:Git push           " push
:Gdiffsplit         " diff split

5.9.7 Statusline


5.10 Neovim และ Modern Vim

Neovim (nvim) เป็น fork ของ Vim ที่เริ่มในปี 2014 โดย Thiago de Arruda เพื่อปรับปรุงโครงสร้างภายใน Vim ให้ทันสมัย รองรับการพัฒนาแบบชุมชน และเพิ่มความสามารถที่ Vim ดั้งเดิมทำได้ยาก

5.10.1 ความแตกต่างระหว่าง Vim กับ Neovim

คุณสมบัติ Vim Neovim
ภาษาสำหรับ config VimL (.vimrc) VimL + Lua (init.lua)
Async API รองรับบางส่วน (Vim 8+) รองรับเต็มรูปแบบ
Embedded Terminal :terminal (Vim 8+) :terminal native
LSP Client ต้องผ่าน plugin เช่น coc.nvim Built-in LSP
Treesitter ไม่มี native Built-in nvim-treesitter
RPC / GUI API จำกัด เต็มรูปแบบ (มี GUI อิสระ เช่น Neovide)
Default Binding Backward compatible ปรับปรุงบ้าง (เช่น Y = y$)
Codebase เน้น backward compat refactor ให้อ่านง่ายขึ้น
Plugin ใหม่ ใช้ร่วมกับ Vim ได้ มี ecosystem Lua เฉพาะ

5.10.2 Lua Configuration

Neovim รองรับการเขียน config ด้วย Lua ซึ่งเร็วและ expressive กว่า VimL

-- ~/.config/nvim/init.lua

-- Leader key (ต้องตั้งก่อนโหลด plugin)
vim.g.mapleader = " "
vim.g.maplocalleader = ","

-- Options
local opt = vim.opt
opt.number = true
opt.relativenumber = true
opt.cursorline = true
opt.expandtab = true
opt.tabstop = 4
opt.shiftwidth = 4
opt.termguicolors = true
opt.clipboard = "unnamedplus"
opt.ignorecase = true
opt.smartcase = true
opt.undofile = true
opt.scrolloff = 8

-- Key mapping helper
local map = vim.keymap.set

-- Basic mappings
map("n", "<leader>w", ":w<CR>", { desc = "Save" })
map("n", "<leader>q", ":q<CR>", { desc = "Quit" })
map("n", "<leader>h", ":nohlsearch<CR>", { desc = "Clear search highlight" })

-- Window navigation
map("n", "<C-h>", "<C-w>h")
map("n", "<C-j>", "<C-w>j")
map("n", "<C-k>", "<C-w>k")
map("n", "<C-l>", "<C-w>l")

-- Visual mode: move lines
map("v", "J", ":m '>+1<CR>gv=gv")
map("v", "K", ":m '<-2<CR>gv=gv")

-- Auto command: เปิด line highlight เฉพาะ buffer ปัจจุบัน
vim.api.nvim_create_autocmd({ "BufEnter" }, {
  callback = function() vim.wo.cursorline = true end,
})
vim.api.nvim_create_autocmd({ "BufLeave" }, {
  callback = function() vim.wo.cursorline = false end,
})

5.10.3 LSP (Language Server Protocol) และ mason.nvim

LSP เป็น Protocol ที่แยกการวิเคราะห์ภาษา (Language Server) ออกจาก Editor — ทำให้ Language Server ตัวเดียวใช้ได้กับหลาย Editor

-- ตัวอย่าง lazy.nvim setup สำหรับ LSP
return {
  {
    "williamboman/mason.nvim",
    config = function()
      require("mason").setup()
    end,
  },
  {
    "williamboman/mason-lspconfig.nvim",
    dependencies = { "williamboman/mason.nvim" },
    config = function()
      require("mason-lspconfig").setup({
        ensure_installed = {
          "lua_ls",       -- Lua
          "pyright",      -- Python
          "tsserver",     -- TypeScript/JavaScript
          "gopls",        -- Go
          "rust_analyzer",-- Rust
          "clangd",       -- C/C++
          "bashls",       -- Bash
        },
      })
    end,
  },
  {
    "neovim/nvim-lspconfig",
    dependencies = { "williamboman/mason-lspconfig.nvim" },
    config = function()
      local lspconfig = require("lspconfig")
      
      -- ตั้งค่า server แต่ละตัว
      lspconfig.pyright.setup({})
      lspconfig.gopls.setup({})
      lspconfig.rust_analyzer.setup({})
      
      -- Key mappings เมื่อ LSP attach
      vim.api.nvim_create_autocmd("LspAttach", {
        callback = function(event)
          local opts = { buffer = event.buf }
          vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts)
          vim.keymap.set("n", "gr", vim.lsp.buf.references, opts)
          vim.keymap.set("n", "K", vim.lsp.buf.hover, opts)
          vim.keymap.set("n", "<leader>rn", vim.lsp.buf.rename, opts)
          vim.keymap.set("n", "<leader>ca", vim.lsp.buf.code_action, opts)
          vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, opts)
          vim.keymap.set("n", "]d", vim.diagnostic.goto_next, opts)
        end,
      })
    end,
  },
}

5.10.4 Treesitter สำหรับ Syntax Highlighting

Treesitter สร้าง Concrete Syntax Tree ของโค้ด ทำให้ Syntax Highlighting แม่นยำกว่า regex-based แบบเดิม และเปิดประตูสู่ feature เช่น:

-- lazy.nvim setup
return {
  "nvim-treesitter/nvim-treesitter",
  build = ":TSUpdate",
  config = function()
    require("nvim-treesitter.configs").setup({
      ensure_installed = {
        "lua", "vim", "vimdoc",
        "python", "javascript", "typescript",
        "go", "rust", "c", "cpp",
        "bash", "markdown", "json", "yaml",
        "html", "css",
      },
      highlight = { enable = true },
      indent = { enable = true },
      incremental_selection = {
        enable = true,
        keymaps = {
          init_selection = "<CR>",
          node_incremental = "<CR>",
          node_decremental = "<BS>",
          scope_incremental = "<TAB>",
        },
      },
    })
  end,
}

5.10.5 Pre-configured Neovim

สำหรับผู้ที่ไม่อยาก config เองทั้งหมด มี Distribution ที่เตรียม config ครบเซ็ต:

Distribution จุดเด่น เหมาะกับ
LazyVim Modular, lazy-loaded ทันสมัยที่สุด ผู้ที่อยากเริ่มเร็วแต่ปรับแต่งได้
NvChad UI สวย เน้นความเร็ว ผู้ชอบความเรียบ-เร็ว
AstroNvim รองรับภาษาเยอะ พร้อมใช้ ทุก use case
LunarVim มี feature เยอะ คล้าย IDE ผู้มาจาก VS Code
kickstart.nvim config เดี่ยว ~500 บรรทัด อ่านเข้าใจง่าย ผู้ที่อยากเรียนรู้ build เอง
SpaceVim คล้าย Spacemacs มี layer system ผู้มาจาก Emacs

ติดตั้ง LazyVim (ตัวอย่าง):

# สำรอง config เดิม
$ mv ~/.config/nvim ~/.config/nvim.bak
$ mv ~/.local/share/nvim ~/.local/share/nvim.bak
$ mv ~/.local/state/nvim ~/.local/state/nvim.bak
$ mv ~/.cache/nvim ~/.cache/nvim.bak

# Clone LazyVim starter
$ git clone https://github.com/LazyVim/starter ~/.config/nvim
$ rm -rf ~/.config/nvim/.git

# เปิด Neovim — จะติดตั้ง plugin อัตโนมัติ
$ nvim
flowchart TB
    subgraph Era1 [ยุคดั้งเดิม 1976-1990]
        ed[ed 1971
Ken Thompson] ex[ex 1976
Bill Joy] vi[vi 1976
Bill Joy] ed --> ex --> vi end subgraph Era2 [ยุค Vim 1991-2013] stevie[Stevie 1987
Atari ST] vim[Vim 1991
Bram Moolenaar] vim7[Vim 7 2006
tabs, undo branch] vim8[Vim 8 2016
async, packages] stevie --> vim vi --> vim vim --> vim7 --> vim8 end subgraph Era3 [ยุค Neovim 2014-ปัจจุบัน] nvim[Neovim 2014
fork โดย Thiago] nvim05[Neovim 0.5 2021
Lua, Built-in LSP] nvim09[Neovim 0.9+ 2023
Treesitter, Inlay hints] nvim --> nvim05 --> nvim09 vim --> nvim end subgraph Era4 [Modern Distributions] lazy[LazyVim] nvchad[NvChad] astro[AstroNvim] kick[kickstart.nvim] nvim09 --> lazy & nvchad & astro & kick end vim8 -.-> nvim05

สูตรประเมินประสิทธิภาพการเรียนรู้ Vim — ใช้เส้นโค้งการเรียนรู้แบบ Exponential Learning Curve ซึ่งอธิบายว่าความชำนาญ (Proficiency) เพิ่มขึ้นตามเวลาที่ใช้ฝึก (t) โดยมี asymptote ที่ Pmax:

P(t) = Pmax (1- e-λt )

โดยที่ P(t) = ระดับความชำนาญที่เวลา t, Pmax = ระดับความชำนาญสูงสุดที่เป็นไปได้, λ = ค่าคงที่อัตราการเรียนรู้ (ขึ้นกับความถี่การใช้), t = เวลาที่ฝึก Vim อย่างสม่ำเสมอ ในทางปฏิบัติ ผู้ใช้ส่วนใหญ่ "ผ่านโค้งชัน" ได้ใน 2-4 สัปดาห์ของการใช้งานจริงทุกวัน


บทสรุป (Summary)

Vim คือเครื่องมือที่ลงทุนเรียนรู้ครั้งเดียว ใช้ได้ตลอดชีวิต — เพราะ:

  1. มีอยู่ทุกที่ (ubiquity) — SSH เข้า Server ใดก็ใช้ได้ทันที
  2. Modal Editing ลด Keystroke อย่างมีนัยสำคัญ เมื่อเทียบกับ Editor แบบทั่วไป
  3. Composable — ผสม Operator + Motion + Text Object ได้ไม่จำกัด
  4. Extensible — Plugin ecosystem ใหญ่ และมี Neovim ที่ modernize ต่อยอด
  5. ปรัชญา "Editor as Code" — config เป็น text file version control ได้ ปรับแต่งได้ทุกจุด

ข้อเสนอแนะสำหรับผู้เริ่มต้น: