
Text Editor เป็นเครื่องมือพื้นฐานที่สำคัญที่สุดของผู้ดูแลระบบและนักพัฒนาบนลินุกซ์ โดยเฉพาะบน Server ที่ไม่มี GUI การเชี่ยวชาญ Vim ซึ่งเป็น Editor แบบ Modal ที่มีอยู่ในเกือบทุก Unix-like System จะช่วยเพิ่มประสิทธิภาพการแก้ไขข้อความอย่างก้าวกระโดด บทความนี้ครอบคลุมตั้งแต่แนวคิดพื้นฐาน โหมดการทำงาน การเคลื่อนที่ การแก้ไข การค้นหา-แทนที่ การตั้งค่า ไปจนถึง Neovim สมัยใหม่และระบบ Plugin
Text Editor คือโปรแกรมที่ใช้สำหรับสร้างและแก้ไขไฟล์ข้อความธรรมดา (Plain Text) แตกต่างจาก Word Processor ตรงที่เน้นการแก้ไขข้อความบริสุทธิ์โดยไม่มี Formatting แบบ Rich Text ซึ่งเหมาะสำหรับงานเขียนโค้ด (Source Code), ไฟล์ตั้งค่า (Configuration File) และเอกสารแบบ Markup เช่น Markdown หรือ LaTeX
CLI Editor คือ Editor ที่ทำงานบน Terminal ล้วน ๆ ไม่ต้องอาศัยระบบกราฟิก เหมาะสำหรับการแก้ไขไฟล์บน Server ที่เข้าถึงผ่าน SSH
^O = Write Out, ^X = Exit)GUI Editor มีหน้าต่างและเมนูแบบภาพ เหมาะกับงานบนเครื่อง Desktop หรือ Laptop
TUI IDE อยู่กึ่งกลางระหว่าง CLI Editor และ GUI IDE — ทำงานใน Terminal แต่มี UI ที่ซับซ้อนเหมือน IDE
การทำงานกับ Server ในสภาพแวดล้อมจริง (Production) แทบทั้งหมดเป็นการเข้าถึงผ่าน SSH สู่ Terminal ที่ไม่มี GUI ทำให้ทักษะการใช้ CLI Editor กลายเป็นทักษะพื้นฐานที่ขาดไม่ได้
เหตุผลสำคัญ:
vi มีในทุก POSIX OS เป็น minimum guarantee
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]
สิ่งที่ทำให้ Vim แตกต่างจาก Editor ทั่วไปคือ Modal Editing — ในแต่ละโหมด ปุ่มคีย์บอร์ดจะมีความหมายต่างกัน ทำให้สามารถสั่งงานซับซ้อนได้โดยไม่ต้องย้ายมือไปที่ Mouse หรือ Arrow key
Normal Mode คือโหมดเริ่มต้นเมื่อเปิด Vim ในโหมดนี้:
h j k l คือการเคลื่อนที่, dd คือลบบรรทัด, yy คือคัดลอกบรรทัดEsc หรือ Ctrl+[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 |
Visual Mode ใช้สำหรับเลือกข้อความ (Selection) ก่อนสั่งปฏิบัติการ (เช่น copy, delete, change)
v — Character-wise Visual เลือกทีละตัวอักษรV — Line-wise Visual เลือกทีละบรรทัดCtrl+v — Block-wise Visual เลือกเป็นสี่เหลี่ยม (Column selection) สำหรับแก้ไขหลายบรรทัดพร้อมกันgv — เลือกพื้นที่เดิมที่เคยเลือกไว้ล่าสุดCommand-line Mode เปิดใช้งานด้วยปุ่มเริ่มต้น 3 ชนิด
: — เริ่ม Ex command เช่น :w, :q, :s/old/new/g, :set number/ — ค้นหาไปข้างหน้า (Forward Search)? — ค้นหาย้อนกลับ (Backward Search)
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 = จำนวนการกดปุ่มเฉลี่ยต่อการแก้ไขหนึ่งครั้ง, ei = การแก้ไขครั้งที่ i, n = จำนวนการแก้ไขทั้งหมด การใช้ Text Object และ Motion ช่วยลดค่า K ลงได้มาก เช่น ci" (change inside quote) ทำหน้าที่แทนการเลือกด้วย Mouse + ลบ + พิมพ์ = ลด Keystroke จาก ~10 กดเหลือ 3 กด
Motion คือคำสั่งเคลื่อนที่ Cursor ซึ่งสามารถนำไป "คูณ" กับ Operator เช่น d (delete), y (yank), c (change) เพื่อสร้างคำสั่งที่ทรงพลัง เช่น d5w = ลบ 5 คำถัดไป
h — ไปทางซ้าย 1 ตัวอักษรj — ลงล่าง 1 บรรทัดk — ขึ้นบน 1 บรรทัดl — ไปทางขวา 1 ตัวอักษร💡 ที่มาของ hjkl — คีย์บอร์ดของ ADM-3A ในยุคแรก (ที่ Bill Joy ใช้เขียน vi) มีลูกศรพิมพ์บนปุ่ม h j k l พอดี
w — ไปที่ต้นคำถัดไป (word next, ถือเครื่องหมายเป็นคำ)W — เหมือน w แต่นับเฉพาะ whitespace เป็นตัวคั่น (WORD)b — ไปที่ต้นคำก่อนหน้า (back)B — เหมือน b แต่เป็น WORDe — ไปที่ท้ายคำถัดไป (end)E — เหมือน e แต่เป็น WORDge — ไปที่ท้ายคำก่อนหน้า0 — ไปที่ต้นบรรทัด (คอลัมน์ 0)^ — ไปที่ตัวอักษรแรกที่ไม่ใช่ whitespace ของบรรทัด$ — ไปที่ท้ายบรรทัดg_ — ไปที่ตัวอักษรสุดท้ายที่ไม่ใช่ whitespacegg — ไปที่บรรทัดแรกของไฟล์G — ไปที่บรรทัดสุดท้าย:42 หรือ 42G — ไปที่บรรทัด 42Ctrl+f — Forward 1 หน้า (Page Down)Ctrl+b — Backward 1 หน้า (Page Up)Ctrl+d — Down ครึ่งหน้าCtrl+u — Up ครึ่งหน้าCtrl+e — เลื่อน extra line ลง (cursor อยู่กับที่)Ctrl+y — เลื่อน yank line ขึ้นH — High: ไปบนสุดของหน้าจอที่มองเห็นM — Middle: ไปกลางหน้าจอL — Low: ไปล่างสุดของหน้าจอ% — กระโดดไปวงเล็บคู่ (Match Bracket (), {}, []){ — ไปย่อหน้าก่อน (Paragraph back)} — ไปย่อหน้าถัดไปzz — เลื่อนหน้าจอให้ Cursor อยู่กลางจอzt — Cursor อยู่บนสุด (top)zb — Cursor อยู่ล่างสุด (bottom)/pattern + Enter — ค้นหาไปข้างหน้า?pattern + Enter — ค้นหาย้อนกลับn — ไปผลการค้นหาถัดไป (ทิศเดิม)N — ไปผลการค้นหาก่อนหน้า (ทิศตรงข้าม)* — ค้นหาคำที่ Cursor ชี้อยู่ไปข้างหน้า# — ค้นหาคำที่ Cursor ชี้อยู่ย้อนกลับf{char} — find ตัวอักษรถัดไปในบรรทัดF{char} — find ย้อนกลับt{char} — till (ไปที่ตัวอักษรก่อนอักขระ); / , — ทำซ้ำ f/F/t/T ไปข้างหน้า / ย้อนกลับMark คือการตั้งจุดอ้างอิงในไฟล์ เพื่อกระโดดกลับมาได้ภายหลัง
ma — ตั้ง Mark ชื่อ a ที่ Cursor ปัจจุบัน`a — กระโดดไปที่ตัวอักษรที่ Mark a ถูกตั้งไว้'a — กระโดดไปที่ต้นบรรทัดที่ Mark a อยู่a-z) — ใช้ภายในไฟล์A-Z) — ใช้ข้ามไฟล์ได้ (Global Mark):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
การแก้ไขใน Vim ยึดหลัก Operator + Motion / Text Object — เมื่อเข้าใจรูปแบบนี้ จะสามารถผสมคำสั่งนับพันได้จากส่วนประกอบไม่กี่ตัว
x — ลบตัวอักษรที่ Cursor (เทียบเท่า dl)X — ลบตัวอักษรก่อน Cursor (เทียบเท่า dh)dd — ลบทั้งบรรทัดdw — ลบจาก Cursor ถึงต้นคำถัดไปd$ หรือ D — ลบจาก Cursor ถึงท้ายบรรทัดd0 — ลบจาก Cursor ถึงต้นบรรทัดdG — ลบจาก Cursor ถึงท้ายไฟล์dgg — ลบจาก Cursor ถึงต้นไฟล์3dd — ลบ 3 บรรทัดใน Vim เรียกการคัดลอกว่า yank (y) ไม่ใช่ copy
yy หรือ Y — yank ทั้งบรรทัดyw — yank จนถึงต้นคำถัดไปy$ — yank ถึงท้ายบรรทัดyG — yank ถึงท้ายไฟล์5yy — yank 5 บรรทัดp — วางหลัง Cursor (ถ้า yank แบบบรรทัด จะวางใต้บรรทัดปัจจุบัน)P — วางก่อน Cursor (ถ้า yank แบบบรรทัด จะวางเหนือบรรทัดปัจจุบัน)"0p — วางจาก Register 0 (yank ล่าสุด ไม่รวม delete)"+p — วางจาก System ClipboardChange = Delete + เข้า Insert Mode อัตโนมัติ มีประสิทธิภาพสูงมาก
cc หรือ S — Change ทั้งบรรทัดcw — Change จากตำแหน่งปัจจุบันถึงต้นคำถัดไปc$ หรือ C — Change ถึงท้ายบรรทัดciw — Change inside word (เปลี่ยนคำทั้งคำ ไม่ว่า Cursor จะอยู่ที่ไหนในคำ)ci" — Change ข้อความใน ""ci( — Change ข้อความใน ()r{char} — แทนตัวอักษร 1 ตัว (ไม่เข้า Insert)R — เข้า Replace Mode พิมพ์ทับตัวอักษรไปเรื่อย ๆ~ — สลับพิมพ์เล็ก/ใหญ่ของตัวอักษรที่ Cursoru — UndoCtrl+r — RedoU — Undo ทั้งบรรทัด (ยกเลิกการเปลี่ยนแปลงทั้งหมดในบรรทัดปัจจุบัน):earlier 10m — ย้อนไป 10 นาทีก่อน (Persistent Undo Tree):later 5m — ไปข้างหน้า 5 นาที. (dot) คือหนึ่งในคำสั่งที่ทรงพลังที่สุดใน Vim — ทำการแก้ไขครั้งล่าสุดซ้ำ
ตัวอย่าง: พิมพ์ cw แก้เป็นคำว่า Hello แล้ว Esc จากนั้นไปที่คำอื่น กด . — จะเปลี่ยนคำนั้นเป็น Hello ทันที
Vim รองรับ Count นำหน้าคำสั่งเพื่อทำซ้ำ:
5dd — ลบ 5 บรรทัด3w — ไปข้างหน้า 3 คำd3w — ลบ 3 คำถัดไป2yy — yank 2 บรรทัด10j — ลงล่าง 10 บรรทัดรูปแบบทั่วไป: [count][operator][count][motion]
Text Object คือ "วัตถุทางข้อความ" ที่ Vim เข้าใจ เช่น คำ ประโยค ย่อหน้า ก้อนวงเล็บ — ใช้ร่วมกับ Operator โดยมีรูปแบบ 2 แบบ:
i = inner (ไม่รวมขอบ เช่น ไม่รวมเครื่องหมายคำพูด)a = around (รวมขอบ)| 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 ให้พิมพ์ใหม่ได้เลย
Visual Mode ให้เราเห็นว่ากำลังเลือกอะไรอยู่ก่อนสั่ง Operator ซึ่งตรงกับแนวคิดของ Editor อื่น ๆ ที่คุ้นเคย (Select → Act)
v — Character-wise: เลือกทีละตัวอักษร สามารถขยายเลือกด้วย motion ทุกแบบ (w, $, 3j, เป็นต้น)V — Line-wise: เลือกทีละบรรทัดเต็มCtrl+v — Block-wise: เลือกเป็นสี่เหลี่ยมคอลัมน์ (Visual Block)เมื่อเลือกด้วย Visual Mode แล้ว สามารถกด Operator ได้ทันที
y — yank พื้นที่ที่เลือกd — ลบพื้นที่ที่เลือกc — ลบและเข้า Insert Mode> / < — เพิ่ม / ลด indent= — Auto-indent ตามภาษาgU / gu — แปลงเป็นพิมพ์ใหญ่ / เล็ก~ — สลับพิมพ์เล็ก-ใหญ่เมื่อต้องการ indent โค้ดหลายบรรทัดพร้อมกัน:
V ที่บรรทัดแรก5j เพื่อเลือก 5 บรรทัดลงไป (หรือกด V ตามด้วยเลือกบรรทัดปลายทาง)> เพื่อเพิ่ม indent หรือ < เพื่อลด indent. เพื่อทำซ้ำการ indent เดิมเทคนิคสุดยอดของ 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
การค้นหา-แทนที่ของ Vim ใช้ Regular Expression ที่ทรงพลัง สามารถทำ Refactoring เชิงข้อความได้อย่างรวดเร็ว
/foo + Enter — หาคำว่า foo ไปข้างหน้า?foo + Enter — หาคำว่า foo ย้อนกลับn — ไปผลถัดไป (ทิศเดียวกับคำสั่งเดิม)N — ไปผลก่อนหน้า* — หาคำใต้ Cursor ไปข้างหน้า (whole word)# — หาคำใต้ Cursor ย้อนกลับg* / g# — เหมือน */# แต่ไม่ใช่ whole wordรูปแบบทั่วไป: :[range]s/pattern/replacement/[flags]
:s/old/new/ — แทนที่ครั้งแรกในบรรทัดปัจจุบัน:s/old/new/g — แทนที่ทุกครั้งในบรรทัดปัจจุบัน (g = global within line):%s/old/new/g — แทนที่ทุกครั้งในทั้งไฟล์:%s/old/new/gc — แทนที่ทุกครั้งในไฟล์ แต่ถามยืนยันทุกครั้ง (c = confirm):5,10s/old/new/g — แทนที่เฉพาะบรรทัดที่ 5 ถึง 10| Range | ความหมาย |
|---|---|
. |
บรรทัดปัจจุบัน |
$ |
บรรทัดสุดท้าย |
% |
ทั้งไฟล์ (เทียบเท่า 1,$) |
1,10 |
บรรทัดที่ 1 ถึง 10 |
.,+5 |
บรรทัดปัจจุบันลงไปอีก 5 บรรทัด |
'<,'> |
ช่วงที่เพิ่งเลือกใน Visual Mode |
/pat1/,/pat2/ |
จากบรรทัดที่ match pat1 ถึง pat2 |
g — global: ทุกจุดที่พบในบรรทัด (ถ้าไม่ใส่ จะแทนเฉพาะครั้งแรก)c — confirm: ถามยืนยันทุกครั้ง (y/n/a/q/l)i — ignore caseI — case sensitive (บังคับ)n — number: แค่นับจำนวน match โดยไม่แทน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
| คำสั่ง | ความหมาย |
|---|---|
:w |
บันทึก (write) |
:w filename |
บันทึกเป็นชื่อใหม่ |
:w !sudo tee % |
บันทึกด้วย sudo เมื่อเปิดไฟล์มาโดยไม่มี permission |
:q |
ออก (quit) |
:q! |
ออกโดยไม่บันทึก |
:wq / :x / ZZ |
บันทึกและออก |
ZQ |
ออกโดยไม่บันทึก (เทียบเท่า :q!) |
:wa |
บันทึกทุก buffer |
:qa |
ออกจากทุก buffer |
:wqa |
บันทึกและออกจากทุก buffer |
Buffer คือไฟล์ที่เปิดใน memory ของ Vim หนึ่ง session สามารถเปิดหลายไฟล์พร้อมกันได้
:e filename — edit เปิดไฟล์ (สร้าง buffer ใหม่):ls หรือ :buffers — แสดงรายการ buffer ทั้งหมด:b <number> หรือ :b <name> — สลับไป buffer ที่ระบุ:bn — buffer next:bp — buffer previous:bd — buffer delete (ปิด buffer):bufdo <cmd> — รันคำสั่งกับทุก buffer เช่น :bufdo %s/foo/bar/g | w:sp / :split — แยกจอแนวนอน (บน-ล่าง):vsp / :vsplit — แยกจอแนวตั้ง (ซ้าย-ขวา)Ctrl+w + h/j/k/l — สลับไปหน้าต่างตามทิศทางCtrl+w + w — สลับหน้าต่างตามลำดับCtrl+w + q — ปิดหน้าต่างปัจจุบันCtrl+w + = — ปรับหน้าต่างให้เท่ากันCtrl+w + _ — ขยายแนวตั้งสูงสุดCtrl+w + | — ขยายแนวนอนสูงสุดCtrl+w + + / - — ปรับขนาดแนวตั้งCtrl+w + > / < — ปรับขนาดแนวนอนTab ของ Vim ต่างจาก Tab ของ Editor อื่น — เป็น กลุ่มของ window layout (ไม่ใช่ tab สำหรับเปิดไฟล์)
:tabnew — สร้างแท็บใหม่:tabnew filename — เปิดไฟล์ในแท็บใหม่gt — แท็บถัดไปgT — แท็บก่อนหน้า:tabclose — ปิดแท็บ:tabs — แสดงรายการแท็บ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
~/.vimrc (Linux/macOS), ~/_vimrc (Windows)~/.config/nvim/init.vim หรือ ~/.config/nvim/init.lua (สมัยใหม่)เมื่อเปิด Vim จะโหลดไฟล์เหล่านี้อัตโนมัติ สามารถ reload ขณะใช้งานด้วย :source ~/.vimrc หรือ :so $MYVIMRC
" ============================================
" ~/.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
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
| คำสั่ง | ความหมาย | โหมดที่ทำงาน |
|---|---|---|
: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>
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
Plugin เป็นการขยายความสามารถของ Vim ตั้งแต่ File Explorer, Git Integration, LSP, Fuzzy Finder เป็นต้น
| 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:
:PlugInstall — ติดตั้ง plugin ที่ประกาศไว้:PlugUpdate — อัปเดต:PlugClean — ลบ plugin ที่เอาออกจากลิสต์:PlugStatus — ดูสถานะ:PlugUpgrade — อัปเดตตัว vim-plug เอง" ตัวอย่าง 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> " ประวัติไฟล์ที่เปิด
" vim-fugitive — ตัวอย่างคำสั่ง
:Git " git status ใน window
:Git blame " git blame
:Git commit " commit
:Git push " push
:Gdiffsplit " diff split
Neovim (nvim) เป็น fork ของ Vim ที่เริ่มในปี 2014 โดย Thiago de Arruda เพื่อปรับปรุงโครงสร้างภายใน Vim ให้ทันสมัย รองรับการพัฒนาแบบชุมชน และเพิ่มความสามารถที่ Vim ดั้งเดิมทำได้ยาก
| คุณสมบัติ | 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 เฉพาะ |
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,
})
LSP เป็น Protocol ที่แยกการวิเคราะห์ภาษา (Language Server) ออกจาก Editor — ทำให้ Language Server ตัวเดียวใช้ได้กับหลาย Editor
vim.lsp) — อยู่ใน core ตั้งแต่ v0.5-- ตัวอย่าง 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,
},
}
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,
}
สำหรับผู้ที่ไม่อยาก 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) = ระดับความชำนาญที่เวลา t, Pmax = ระดับความชำนาญสูงสุดที่เป็นไปได้, λ = ค่าคงที่อัตราการเรียนรู้ (ขึ้นกับความถี่การใช้), t = เวลาที่ฝึก Vim อย่างสม่ำเสมอ ในทางปฏิบัติ ผู้ใช้ส่วนใหญ่ "ผ่านโค้งชัน" ได้ใน 2-4 สัปดาห์ของการใช้งานจริงทุกวัน
Vim คือเครื่องมือที่ลงทุนเรียนรู้ครั้งเดียว ใช้ได้ตลอดชีวิต — เพราะ:
ข้อเสนอแนะสำหรับผู้เริ่มต้น:
vimtutor (พิมพ์ vimtutor ใน terminal ได้ทันทีหากติดตั้ง vim).vimrc พื้นฐาน (ไม่ต้องเยอะ) เน้น set number, set relativenumber, Color Scheme และ Leader Key