天天看點

atom html自動補全插件,[工具資源] Atom 文法高亮插件編寫指南_html/css_WEB-ITnose

Atom想必無需多作介紹了,是一款除了啟動運作慢之外,其它部分都挺優秀的編輯器。由于我在寫一個解析渲染 ASS 字幕的 JavaScript 庫—— ASS.js,經常要檢視 .ass檔案。然而面對一大片白花花的代碼很不舒服,Atom 上又沒有現成的 ASS 文法高亮插件,于是決定自己寫一個。

目錄結構

那麼文法高亮插件該怎麼寫呢? 官方文檔有講到如何建立一個普通的插件,而對于文法高亮插件,最快的熟悉方法是檢視已有的插件,例如 Atom 官方維護的 language-json。文法高亮插件一般有如下目錄結構(其中 ssa為語言名稱):

language-ssa├── grammars│ └── ssa.cson├── spec│ └── ssa-spec.coffee├── LICENSE.md├── README.md└── package.json

由于 language-ass 名稱已經被占用了,于是我取名為 language-ssa,ASS 字幕是由 SSA 字幕添加進階特性後發展來的,兩者文法基本一緻 。其中 ssa.cson就是寫文法正則的主檔案,字尾 CSON 是個和 JSON 一樣的資料交換語言,但它是 CoffeeScript 的子集,看下 該項目的 README 基本就會了; ssa-spec.coffee是測試檔案,雖然不是必須的,但靠譜的項目都應該有測試; LICENSE.md和 README.md在 Atom 的插件頁面會有連結和展示; package.json和普通的 Node.js 項目一樣,它的 engines字段多了指定 Atom 的版本,看下 樣例就清楚了。

在本地開發測試時,直接把 language-ssa 檔案夾放到 ~/.atom/packages/目錄下并重載( Ctrl+Alt+R) Atom 後就會生效了。

文法規則

Atom 文法檔案的各個字段與 TextMate 編輯器的文法檔案相同,TextMate 給出了較為詳細的 文檔,下面是補充介紹,可以對照着 language-ssa的文法檔案來閱讀: scopeName字段,它應當是每種語言文法的唯一名字,一般取名為 source.ssa或 text.ssa,前一半一般是固定的,後一半是該語言的名稱。而當該語言是另一個語言的擴充時,例如 markdown 是 HTML 的擴充,可以取名為 text.html.markdown,這樣在目前 scope 的規則比對完後,會比對 text.htmlscope 的規則,相當于調用了 HTML 的文法規則。

name字段,在 Atom 右下角顯示的語言名稱。

fileTypes字段,是個數組,指定要生效于哪些字尾的檔案。

firstLineMatch字段,是一條正則,如果該正則可以比對某字尾不明的檔案的第一行,那麼就當作該語言來解析。

foldingStartMarker和 foldingStopMarker字段,都是正則,比對到的位置會有一個折疊标記,可以将代碼塊折疊。但是我在測試時發現 Atom 會自動根據縮進來産生折疊标記,這兩個字段是如何影響的還不太清楚。

patterns字段,是一個數組,這裡是寫文法正則的地方,裡面是若幹個 pattern 對象,姑且稱之為「規則」,其中可以包含以下字段: comment字段,注釋,無實際效果,描述該「規則」。

name字段,是由若幹個 .分隔的字元串,這些名稱将作為被比對部分的 class 名。假如其值為 comment.line.character.semicolon.ssa,被比對到的文本是 ; 分号注釋,那麼可以按下 Ctrl+Alt+I打開 DevTools,檢視到對應生成的 HTML 為 ; 分号注釋。

代碼高亮的顔色效果是由 Theme 決定的,Theme 事實上就是根據這些 class 來添加顔色。後面會提到一些約定俗成的 class 名。

match字段,是一條正則,被它比對到的文本将被加上 name字段的 class。它隻能比對單行文本,并且隻比對一次。

captures字段,是一個對象,其 key 為一個數字,表示配置設定 match字段中的捕獲,如果為 0則表示整體,這與 JS 中 String 的 match 方法表現一緻;其 value 可以是一個 name字段,直接為配置設定到的部分命名,也可以是一個 patterns字段,然後對配置設定到的部分繼續寫「規則」。

include字段,它的值有三種情況: 調用另一個語言,例如值為 'text.html'時,表示在目前「規則」中應用 HTML 的文法。

調用該「規則」自身,值為 '$self',可以遞歸地去比對文本。

調用一個「倉庫」,值為井号開頭的 '#repoName',後面會講到在 repository字段中可以為一個「規則」命名。

begin和 end字段,都是正則,比對 begin開始到 end結束的一段文本,它可以比對多行文本,并且不能和 match字段一起使用。

patterns字段,當有 begin和 end時可以嵌套 patterns來比對它們之間的文本。

contentName字段,它和 name字段類似,但是隻給 begin與 end之間的文本加上 class。

beginCaptures和 endCaptures字段,與 captures字段類似,分别是 begin和 end的捕獲。

這些「規則」 按順序執行下來,每條「規則」 每次隻比對一次,一次循環後,回到第一條「規則」,選擇目前行中 還未被比對的文本進行第二輪比對,以此循環,直到全部都比對完或者 超出循環次數。Atom 中一個 patterns 預設的循環次數貌似是 99 次,超出後就不處理該比對範圍内的文本了。一般我們打開壓縮過的 JS 檔案時,滾動條拖到行尾發現是沒有高亮的,就是這個原因。

repository字段,是一個對象,用來命名一些需要重複調用的「規則」,可以被 include字段調用。

正則用法

上面提到的文法正則與 JavaScript 中的 RegExp 對象用法基本一緻,不過還是有一些差異的。就正則本身來說,ES5 和 ES6 還不支援 look-behind,不能使用 (?<=exp)和 (?

而寫成字元串後就無法像原生正則那樣加修飾符了,在 TextMate 找到 正則的文檔,發現可以通過 (?imx-imx)和 (?imx-imx:subexp)的方式開啟或關閉對應的修飾符。例如 (?i)abc(?-i)def, (?i)表示它之後的比對忽略大小寫, (?-i)表示取消忽略大小寫,也就是該正則裡 abc可以大小寫, def必須小寫。這種寫法是對修飾符的後面起作用,還可以寫成 (?i:abc)def這樣的形式,隻對 abc這個局部起作用。 (?m)表示支援比對多行,雖然 TextMate 的文檔是這麼說,但是我測試發現在 Atom 中是無效的,對于單條正則來說是沒辦法比對多行的,要想比對多行隻能使用 begin和 end的方式。 (?x)則可以忽略正則中的空白字元直接量(空格、Tab、換行),而有反斜杠轉義的空白字元則不會被忽略,這樣當正則過長時就可以換行書寫了,也可以給正則的某一部分加上注釋,詳細的介紹可以看下 這篇文章。如果有多個修飾符可以寫到一起,例如 (?ix)abc。RegExp 對象中的 g 修飾符是不支援的,文法正則每次隻比對一次。

命名約定

文法高亮主要是将代碼解析為多個部分,然後給不同語義的部分加上不同的顔色。雖然各個部分可以随意命名生成 class,但是一個 Theme 不可能為每一個語言都專門寫一套配色,是以會有一些約定俗成的名稱,一般的 Theme 都會支援這些命名約定: comment:注釋 line:單行注釋 double-slash: //注釋

double-dash: --注釋

number-sign: #注釋

percentage: %注釋

character:其他類型的注釋

block:塊級注釋 documentation:注釋文檔

constant:各種形式的常量 numeric:數字常量,例如 42, 6.626e-34, 0xFF

character:字元常量,例如 < escape:轉義字元常量,例如 \n

language:語言本身提供的特殊常量,例如 true, false, null

other:其他常量,例如 CSS 中的顔色

invalid:無效的文法 illegal:非法的文法

deprecated:棄用的文法

keyword:關鍵字 control:流程控制關鍵字,例如 continue, while, return

operator:操作符關鍵字,例如 and, &&

other:其他關鍵字

markup:适用于标記語言,例如 HTML、markdown underline:下劃線 link:連結

bold:粗體

heading:章節的頭部,可以在後面跟一個等級,例如

...可以是 markup.heading.2.html

italic:斜體

list:清單 numbered:有序清單

unnumbered:無序清單

quote:引用

raw:原始文本,例如一段代碼。

other:其他标記結構體

meta:元通常用來标記文檔中的較大的一部分。标記為元的部分一般是沒有樣式的,通常某一塊文本如果語義或結構上是同一部分,就可以标記為元。例如聲明函數的一行可以是 meta.function,然後它的子集是 storage.type, entity.name.function, variable.parameter之類的。

punctuation:标點,這個在 TextMate 文檔中沒有提到,但是實際中有使用。不過似乎并沒有樣式。 definition:定義符,例如 :

separator:分隔符,例如 ,

terminator:結束符,例如 ;

storage:有關「存放」的東西 type:類型,例如 class, function, int, var

modifier:修飾符,例如 static, final, abstract

string:字元串 quoted:有引号字元串 single:單引号字元串,例如 'foo'

double:雙引号字元串,例如 "foo"

triple:三引号字元串,例如 """Python"""

other:其他引号字元串,例如 $'shell'

unquoted:無引号字元串

interpolated:插值字元串,例如 `foo: ${foo}`

regexp:正規表達式

other:其他字元串

support:由架構或庫提供的東西 function:由架構或庫提供的函數,例如 Objective-C 中的 NSLog

class:由架構或庫提供的類

type:由架構或庫提供的類型,可能隻會在 C 派生的語言中用到,有 typedef和 struct的那些語言。大多數語言使用類而非類型。

constant:由架構或庫提供的常量(魔術數字)

variable:由架構或庫提供的變量,例如 AppKit 中的 NSApp

other:除了上面提到的

variable:變量 parameter:參數

language:語言本身提供的變量,例如 this, super, self

other:其他變量

通常,命名時應以上述的約定開頭,并且能滿足子項的都應寫上去;之後一般會根據目前的部分寫一個自定義的名稱,雖然可能對樣式不起作用,但額外的資訊可以将它辨別為特定的語義;最後一般都是跟一個語言名稱。例如 ASS 檔案中區塊頭部 [Script Info],其中的 [可以命名為 punctuation.definition.section.begin.ssa,約定部分是 punctuation.definition,自定義部分是 section.begin,最後是語言名稱。

測試內建

Atom 插件是使用 Jasmine測試架構的,對文法高亮插件的測試主要用到了 Atom Grammar API,Atom 官方維護的 文法高亮插件都有寫測試,具體寫法可以參考。

Atom 插件的持續內建依然可以參考 Atom 官方項目,一般 .travis.yml檔案 長這樣就行了,它會跑一遍 spec目錄下的測試,有配置 lint 的話就再跑一遍 lint。如果不用 Travis CI,可以根據 這個項目部署其他服務。

釋出插件

釋出插件時首先要檢查名稱是否可用,一般文法高亮插件都是命名為 language-語言名的。然後需要一個公開的 Git 倉庫來放置代碼,一般都是開源在 GitHub 上,并在 package.json中寫明倉庫位址。當第一次 push 到 Git 時, package.json中的 version一般是 0.0.0。然後登入 https://atom.io/account獲得 API token,在終端輸入 apm login --token YOUR_TOKEN就可以準備釋出了:

$ apm publish minorPreparing and tagging a new version donePushing v0.1.0 tag donePublishing [email protected] done

運作上述指令後,apm 會自動給 version的次版本加一,然後生成一個 message 為 Prepare 0.1.0 release的 commit,并加上一個 v0.1.0的 Tag,一起 push 到 GitHub 上。之後就可以在 https://atom.io/packages/language-語言名上看到已成功釋出了。

總結

本文大緻介紹了 Atom 文法高亮插件的編寫流程和方式,并根據我在開發中遇到的情況對 TextMate 的文檔進行了補充。但本文應當作為參考,在上手開發之前還需多看看已有的項目,才能了解并解決問題。

聲明:本文原創釋出php中文網,轉載請注明出處,感謝您的尊重!如有疑問,請聯系[email protected]處理