創用 CC 授權條款
除非另有註明,本網站的著作Fygul Hether製作,以創用CC 姓名標示-非商業性-禁止改作 4.0 國際 授權條款釋出。

2020年5月30日 星期六

Windows上的文件編碼與gVim界面選單出現亂碼的問題

問題描述

在Windows使用gVim時發現開啟的中文文字檔出現亂碼,很容易知道因為是是utf-8編碼的文字檔,在預設使用cp950編碼的Windows上開啟,因編碼不同,自然是亂碼。直覺上這問題應該好解決,設置Vim使用utf-8即可:

:set encoding=utf-8
試了沒問題,因為我習慣用utf-8,所以在 _vimrc 加入 set encoding=utf-8

重啟Vim後我卻發現,這回輪到命令選單變成亂碼,即使再加入langmenu的設置後重開Vim也是:

set langmenu=zh_TW.UTF-8
此時 :set all 的顯示結果中也出現 langmenu=zh_TW.UTF-8 ,但選單是亂碼。

langmenu必須在menu載入之前做好設置,故要加在 _vimrc 中。但如果真要在執行Vim時切換選單語言,做法像是先移除選單,重新設置langmenu,重讀選單語言翻譯[1]:

:source $VIMRUNTIME/delmenu.vim
:set langmenu=zh_TW.UTF-8
:source $VIMRUNTIME/menu.vim
上述delmenu.vim用來移除選單;menu.vim用來翻譯選單語言,而語言檔在 $VIMRUNTIME/lang 中,其中有個README.TXT中有些說明。

我試著這樣做之後選單上的中文字則是可正常顯示,不清楚為何設在 _vimrc中會造成亂碼,懷疑是否bug?

另一個觀察到的現象則是編輯的檔案名稱若有中文,暫存的swap檔與最終存檔時,檔名也可能出現亂碼。

我開始懷疑encoding選項影響的層面似乎比我想像的多,而我須要的是希望在讀、寫文件時做正確編碼,之後查了一下,發現果然如此。編碼方面的問題倒不難解決,反而是命令選單的亂碼現象困擾了好一陣子。

在無法解決命令選單亂碼的期間,只好先暫時做個補救的措施,後來花不少時間排查,才發現命令選單亂碼的成因,終於得以解決。

綜合以上,簡單說是二個問題:一、未正確設置Vim的文件編碼,導致中文文件內容,或中文檔名出現亂碼;二、gVim命令選單,即GUI界面的中文呈現亂碼。

本文談論以下幾點,並在最後附上參考連結:
  1. 針對上述第二問題,我採用的暫時措施。
  2. 上述第二問題的成因。
  3. 設置編碼。解決上述第一個問題。
  4. Vim與編碼有關的幾個設置。
  5. 與編碼相關的幾個問題。
  6. Vim與語言顯示有關的幾個設置。
  7. 其他
4,5,6也可以算是對1,2,3的一些補充說明。

1. 解決gVim界面選單亂碼的暫時措施

上面已提到如何在執行Vim時切換選單語言,但每回都要這麼做也有點麻煩。因我很少用gVim上的選單,所以我採用的方式就是不顯示選單,亂碼自然就看不到了。在_vimrc中加入:

set guioption=M

2. gVim選單亂碼的成因

發現這成因算是有點偶然,原本是懷疑別種因素造成問題,想在Virtual Box上的另一個Windows環境做測試與驗證,在兩個環境上做些比較之後,我發現出問題的機器上還有其他設定項目是VBox機器所沒有的,於是改變懷疑的對象,從中逐一測試,終於發現兇手。

雖然不清楚真正的原因是什麼,但設置項目的順序不同,結果會有差異。_vimrc設置檔中原本有不少項目,其中有這兩項:

syntax on
filetype plugin indent on
把 set encoding 放在它們的後面,gVim選單會出現亂碼。把這二項移到 set encoding 的後面去,選單亂碼的現象就不見了。也就是只要這二項中的任一項出現在 set encoding 的前頭,選單就會出現亂碼。

要特別提醒一下,這奇怪的現象只在Windows上出現,在Ubuntu並不會。

3. 正確的編碼設置

就自己的使用情況而言,像這樣就可以了:

set encoding=utf-8
set fileencodings=utf-8,cp950,cp936,gb18030,latin1
這樣既可編輯utf-8編碼的文件,也可編輯cp950編碼的文件。

若須要其他編碼,可查一下 :help encoding-values ,自行加到fileencodings列表中,像:
  • big5:也就是cp950的別名,正體中文。
  • cp936:簡體中文。
  • gb18030:大陸製訂且通用的一種Unicode變體。
  • cp932:日文。
  • cp949:韓文。
設置編碼列表時,要注意一下順序,若發現有問題時,試著調整一下編碼的順序。譬如latin1與cp950別放在utf-8之前。原則上把要求嚴格的編碼放在前,寬鬆的放後面[3],再者是較常用的排在前,像:

ucs-bom,utf-8,cp950,cp936,gb18030,euc-jp,euc-kr,latin1

4. 編碼相關設置

以下解釋幾個與編碼相關的設置:
  • encoding
  • fileencoding
  • fileencodings
  • termencoding
這些選項設定值中的字元都會被自動轉成小寫,所以打大寫字母也無妨,底線轉成 '-'。Vim成功辨識編碼的名稱後,改成標準的名稱,如"Latin-1"變成"latin1","utf8"變成"utf-8"。

encoding 或 enc

預設為 "latin1" 或來自$LANG的值。

設定Vim內部所用的字元編碼。適用在buffer, register中的文字、表達式中的字串、存在viminfo中的文字等等……。設定Vim工作可用的字元種類。

變更此選項並不會改變Vim中既有文字的編碼。它能導致non-ASCII文字變無效。正常應該保持預設值,或在Vim啟動時設定

檔案的字元編碼可不同於 'encoding',此由 'fileencoding' 指定。轉換是以iconv()或以 'charconvert' 指定時完成。

正常時 'encoding' 會與目前 locale 相同。如果Vim認得環境設定,預設是如此。如果 'encoding' 不是設成目前 locale,必須設置'termencoding'以轉換(終端機畫面中)打字或顯示的文字。

使用"unicode", "ucs-2" 或 "ucs-4"時,Vim內部用utf-8。

fileencoding 或 fenc

預設為空字串。設置本buffer檔案的字元編碼。

當'fileencoding'與'encoding'不同時,在寫入檔案時做轉換。讀取的轉換見後述。

當'fileencoding'為空,使用與'encoding'相同的值(即讀或寫檔案時並不做轉換)。

轉換也發生在'encoding'與'fileencoding'都是Unicode編碼,且'fileencoding'不是utf-8。那是因為內部的Unicode都是存成utf-8。

注意像在utf-8轉換成cp950時,其中的Unicode字元會丟失變成?符號。

當讀取檔案時,'fileencoding'的設定會來自'fileencodings'。要讀取某編碼,但設定'fileencoding'卻無作用時,使用 ++enc 參數(見後述)。一例外:當'fileencodings'是空的,則使用'fileencoding'的值。

新檔案,使用'fileencoding'的globle value。可以這麼設它:

:setglobal fenc=utf-8
在開始編輯檔案之後才設此選項時,設定'modified'選項(即此檔被視為已修改)。當'modifialbe'關閉時,無法變更此選項。

註:在6.0版前,此選項指定了整個Vim的編碼,現在則是改用'encoding'。舊式簡稱 'fe' 也不再使用。在網路上查這類資料時,要注意也許找到的是這類已過時的舊資料。

fileencodings 或 fencs

預設為"ucs-bom";當'encoding'設成Unicode值時,則是"ucs-bom,utf-8,default,latin1"。

這是在開始編輯既有檔案時,所考慮採用的字元編碼列表。在讀取檔案時,Vim試著用第一個編碼。若出錯,再試列表中的下一個。找到可用的編碼時,'fileencoding'就設為這編碼;若失敗則設成空字串,意即使用'encoding'的值。

當使用 ++enc 參數時,就不採用'fileencodings'的值。

'fileencodings'不用在新檔案,新檔用'fileencoding'的global value,見上述。

"default"使用來自環境的編碼。此即'encoding'的預設值。

設定此選項要直到下次讀取檔案時才會生效。

termencoding 與 tenc

預設為空字串;GTK+ GUI則是"utf-8"。

終端機用的編碼,指定鍵盤所產生與顯示上的字元編碼。在GUI,它只用在鍵盤,'encoding'用在顯示。但這不適用於GTK+ GUI,它強迫使用"utf-8"。在Win32 GUI與console版本,不使用此選項,因Win32系統總是傳送Unicode字元。

空白時,使用與'encoding'相同的編碼。

5. 與編碼相關的幾個問題

存檔時指定使用不同編碼

例如目前正編輯著以cp950編碼的文件,要另存新檔並採用utf-8編碼:

:w ++enc=utf-8 new_filename.txt
要注意若原本utf-8編輯的檔案,要轉換存成cp950時,其中若有Unicode中的字會失效。

編碼辨識錯誤

開啟既有文件時難免會搞錯編碼,在此情況下,如果自己清楚文件的編碼,可自行指定:

:edit ++enc=cp950 traditional_chinese.txt

6. 語言相關設置

界面及語言相關的設置項目:
  • language
  • langmenu
  • guioption

language

顯示/設置語言,包含訊息、時間格式:

:language {name}
可支援的語言名稱,在Unix上,可見locale -a

顯示/設置訊息語言,可用來額外設置與language不同的訊息語言,如果想讓二者不同的話:

:language message

langmenu

選單語言,預設是英文。若環境設置正確,且有可用的語言檔,會自動轉譯成本地語言。
你也可以自行設定想要的語言。例如把界面選單的語言改為英文,即預設的語言:

:set langmenu=none

guioption

不顯示界面選單:

:set guioption=M
也可簡寫為:

:set go=M
想顯示界面選單則把上述的M改為m。

7. 其他

在處理以上問題的過程,還發現幾個設置值得記錄一下,暫且記在此處,來日若有必要再做調整。

set guifont

如果在gVim編輯文字無法正常顯示Unicode字元,可設置GUI畫面所用的字型,換個支援Unicode的字型。最簡單的方式利用"Edit/Select Font..."所顯示的字型對話盒試好想要的字型,然後看字型名稱:

:set guifont
接著可以在gvimrc加入使用此字型的設置。例,在Windows上,使用Courier New字型:

:set guifont=courier_new:h12

以滑鼠顏色指示中文輸入法開關狀態

在Vim中使用中文輸入法時經常有的困擾,就是不慎在中文輸入啟用的狀態下打Vim命令。這有不同的解決方式,其中之一是利用游標來指示輸入法狀態以減輕這困擾。這裡提到的方法只適用於Windows上的gVim,並使用安裝成內置式的中文輸入法,並不適於可攜式的。

在gvimrc中加入以下設置:

if has('multi_byte_ime')
    highlight Cursor guifg=NONE guibg=Green
    highlight CursorIM guifg=NONE guibg=Purple
endif
這段的作用是在判斷出有多位元的IME,像中文輸入法時,在啟用輸入法時,游標顯示為紫色,關閉時則變成綠色。

參考連結

  1. https://vimhelp.org/usr_45.txt.html#usr_45.txt
  2. https://vimhelp.org/options.txt.html#options.txt
  3. http://edyfox.codecarver.org/html/vim_fileencodings_detection.html
  4. https://vimhelp.org/mlang.txt.html#%3Alanguage
  5. https://vimhelp.org/mbyte.txt.html

沒有留言:

張貼留言