製做你的第一個 Atom 文本編輯器插件

摘要: 序言 這篇教程將會教你怎麼製做你的第一個 Atom 文本編輯器的插件。咱們將會製做一個山寨版的 Sourcerer,這是一個從 StackOverflow 查詢並使用代碼片斷的插件。到教程結束時,你將會製做好一個將編程問題(用英語描述的)轉換成獲取自 StackOverflow 的代碼片斷的插件,像這樣: 教程須知 Atom 文本編輯器是用 web 技術創造出來的。javascript

序言

這篇教程將會教你怎麼製做你的第一個 Atom 文本編輯器的插件。咱們將會製做一個山寨版的 Sourcerer,這是一個從 StackOverflow 查詢並使用代碼片斷的插件。到教程結束時,你將會製做好一個將編程問題(用英語描述的)轉換成獲取自 StackOverflow 的代碼片斷的插件,像這樣:html

教程須知

Atom 文本編輯器是用 web 技術創造出來的。咱們將徹底使用 JavaScript 的 EcmaScript 6 規範來製做插件。你須要熟悉如下內容:java

教程的倉庫

你能夠跟着教程一步一步走,或者看看 放在 GitHub 上的倉庫,這裏有插件的源代碼。這個倉庫的歷史提交記錄包含了這裏每個標題。node

開始

安裝 Atom

根據 Atom 官網 的說明來下載 Atom。咱們同時還要安裝上 apm(Atom 包管理器的命令行工具)。你能夠打開 Atom 並在應用菜單中導航到 Atom > Install Shell Commands 來安裝。打開你的命令行終端,運行apm -v 來檢查 apm 是否已經正確安裝好,安裝成功的話打印出來的工具版本和相關環境信息應該是像這樣的:python

 
 
  1. apm -v
  2. > apm 1.9.2
  3. > npm 2.13.3
  4. > node 0.10.40
  5. > python 2.7.10
  6. > git 2.7.4

生成骨架代碼

讓咱們使用 Atom 提供的一個實用工具建立一個新的 package(軟件包)來開始這篇教程。git

  • 啓動編輯器,按下 Cmd+Shift+P(MacOS)或者 Ctrl+Shift+P(Windows/Linux)來打開命令面板Command Palette。
  • 搜索「Package Generator: Generate Package」並點擊列表中正確的條目,你會看到一個輸入提示,輸入軟件包的名稱:「sourcefetch」。
  • 按下回車鍵來生成這個骨架代碼包,它會自動在 Atom 中打開。

若是你在側邊欄沒有看到軟件包的文件,依次按下 Cmd+K Cmd+B(MacOS)或者 Ctrl+KCtrl+B(Windows/Linux)。github

命令面板Command Palette可讓你經過模糊搜索來找到並運行軟件包。這是一個執行命令比較方便的途徑,你不用去找導航菜單,也不用刻意去記快捷鍵。咱們將會在整篇教程中使用這個方法。web

運行骨架代碼包

在開始編程前讓咱們來試用一下這個骨架代碼包。咱們首先須要重啓 Atom,這樣它才能夠識別咱們新增的軟件包。再次打開命令面板,執行 Window: Reload 命令。chrome

從新加載當前窗口以確保 Atom 執行的是咱們最新的源代碼。每當須要測試咱們對軟件包的改動的時候,就須要運行這條命令。npm

經過導航到編輯器菜單的 Packages > sourcefetch > Toggle 或者在命令面板執行 sourcefetch:toggle來運行軟件包的 toggle 命令。你應該會看到屏幕的頂部出現了一個小黑窗。再次運行這條命令就能夠隱藏它。

「toggle」命令

打開 lib/sourcefetch.js,這個文件包含有軟件包的邏輯和 toggle 命令的定義。

 
 
  1. toggle() {
  2. console.log('Sourcefetch was toggled!');
  3.  return (
  4.  this.modalPanel.isVisible() ?
  5.  this.modalPanel.hide() :
  6.  this.modalPanel.show()
  7.  );
  8. }

toggle 是這個模塊導出的一個函數。根據模態面板的可見性,它經過一個三目運算符 來調用 show 和hide 方法。modalPanel 是 Panel(一個由 Atom API 提供的 UI 元素) 的一個實例。咱們須要在export default 內部聲明 modalPanel 纔可讓咱們經過一個實例變量 this 來訪問它。

 
 
  1. this.subscriptions.add(atom.commands.add('atom-workspace', {
  2.  'sourcefetch:toggle': () => this.toggle()
  3. }));

上面的語句讓 Atom 在用戶運行 sourcefetch:toggle 的時候執行 toggle 方法。咱們指定了一個 匿名函數 () => this.toggle(),每次執行這條命令的時候都會執行這個函數。這是事件驅動編程(一種經常使用的 JavaScript 模式)的一個範例。

Atom 命令

命令只是用戶觸發事件時使用的一些字符串標識符,它定義在軟件包的命名空間內。咱們已經用過的命令有:

  • package-generator:generate-package
  • Window:reload
  • sourcefetch:toggle

軟件包對應到命令,以執行代碼來響應事件。

進行你的第一次代碼更改

讓咱們來進行第一次代碼更改——咱們將經過改變 toggle 函數來實現逆轉用戶選中文本的功能。

改變 「toggle」 函數

以下更改 toggle 函數。

 
 
  1. toggle() {
  2. let editor
  3.  if (editor = atom.workspace.getActiveTextEditor()) {
  4. let selection = editor.getSelectedText()
  5. let reversed = selection.split('').reverse().join('')
  6. editor.insertText(reversed)
  7.  }
  8. }

測試你的改動

  • 經過在命令面板運行 Window: Reload 來從新加載 Atom。
  • 經過導航到 File > New 來建立一個新文件,隨便寫點什麼並經過光標選中它。
  • 經過命令面板、Atom 菜單或者右擊文本而後選中 Toggle sourcefetch 來運行sourcefetch:toggle 命令。

更新後的命令將會改變選中文本的順序:

在 sourcefetch 教程倉庫 查看這一步的所有代碼更改。

Atom 編輯器 API

咱們添加的代碼經過用 TextEditor API 來訪問編輯器內的文本並進行操做。讓咱們來仔細看看。

 
  
  1. let editor
  2. if (editor = atom.workspace.getActiveTextEditor()) { /* ... */ }

頭兩行代碼獲取了 TextEditor 實例的一個引用。變量的賦值和後面的代碼被包在一個條件結構裏,這是爲了處理沒有可用的編輯器實例的狀況,例如,當用戶在設置菜單中運行該命令時。

 
  
  1. let selection = editor.getSelectedText()

調用 getSelectedText 方法可讓咱們訪問到用戶選中的文本。若是當前沒有文本被選中,函數將返回一個空字符串。

 
  
  1. let reversed = selection.split('').reverse().join('')
  2. editor.insertText(reversed)

咱們選中的文本經過一個 JavaScript 字符串方法 來逆轉。最後,咱們調用 insertText 方法來將選中的文本替換爲逆轉後的文本副本。經過閱讀 Atom API 文檔,你能夠學到更多關於 TextEditor 的不一樣的方法。

瀏覽骨架代碼

如今咱們已經完成第一次代碼更改了,讓咱們瀏覽骨架代碼包的代碼來深刻了解一下 Atom 的軟件包是怎樣構成的。

主文件

主文件是 Atom 軟件包的入口文件。Atom 經過 package.json 裏的條目設置來找到主文件的位置:

 
  
  1. "main": "./lib/sourcefetch",

這個文件導出一個帶有生命週期函數(Atom 在特定的事件發生時調用的處理函數)的對象。

  • activate 會在 Atom 初次加載軟件包的時候調用。這個函數用來初始化一些諸如軟件包所需的用戶界面元素的對象,以及訂閱軟件包命令的處理函數。
  • deactivate 會在軟件包停用的時候調用,例如,當用戶關閉或者刷新編輯器的時候。
  • serialize Atom 調用它在使用軟件包的過程當中保存軟件包的當前狀態。它的返回值會在 Atom 下一次加載軟件包的時候做爲一個參數傳遞給 activate

咱們將會重命名咱們的軟件包命令爲 fetch,並移除一些咱們再也不須要的用戶界面元素。按照以下更改主文件:

 
  
  1. 'use babel';
  2. import { CompositeDisposable } from 'atom'
  3. export default {
  4. subscriptions: null,
  5. activate() {
  6.  this.subscriptions = new CompositeDisposable()
  7.  this.subscriptions.add(atom.commands.add('atom-workspace', {
  8.  'sourcefetch:fetch': () => this.fetch()
  9.  }))
  10.  },
  11. deactivate() {
  12.  this.subscriptions.dispose()
  13.  },
  14. fetch() {
  15. let editor
  16.  if (editor = atom.workspace.getActiveTextEditor()) {
  17. let selection = editor.getSelectedText()
  18. selection = selection.split('').reverse().join('')
  19. editor.insertText(selection)
  20.  }
  21.  }
  22. };

「啓用」命令

爲了提高性能,Atom 軟件包能夠用時加載。咱們可讓 Atom 在用戶執行特定的命令的時候才加載咱們的軟件包。這些命令被稱爲 啓用命令,它們在 package.json 中定義:

 
  
  1. "activationCommands": {
  2.  "atom-workspace": "sourcefetch:toggle"
  3. },

更新一下這個條目設置,讓 fetch 成爲一個啓用命令。

 
  
  1. "activationCommands": {
  2.  "atom-workspace": "sourcefetch:fetch"
  3. },

有一些軟件包須要在 Atom 啓動的時候被加載,例如那些改變 Atom 外觀的軟件包。在那樣的狀況下,activationCommands 會被徹底忽略。

「觸發」命令

菜單項

menus 目錄下的 JSON 文件指定了哪些菜單項是爲咱們的軟件包而建的。讓咱們看看menus/sourcefetch.json

 
  
  1. "context-menu": {
  2.  "atom-text-editor": [
  3.  {
  4.  "label": "Toggle sourcefetch",
  5.  "command": "sourcefetch:toggle"
  6.  }
  7.  ]
  8. },

這個 context-menu 對象可讓咱們定義右擊菜單的一些新條目。每個條目都是經過一個顯示在菜單的label 屬性和一個點擊後執行的命令的 command 屬性來定義的。

 
  
  1. "context-menu": {
  2.  "atom-text-editor": [
  3.  {
  4.  "label": "Fetch code",
  5.  "command": "sourcefetch:fetch"
  6.  }
  7.  ]
  8. },

同一個文件中的這個 menu 對象用來定義插件的自定義應用菜單。咱們以下重命名它的條目:

 
  
  1. "menu": [
  2.  {
  3.  "label": "Packages",
  4.  "submenu": [
  5.  {
  6.  "label": "sourcefetch",
  7.  "submenu": [
  8.  {
  9.  "label": "Fetch code",
  10.  "command": "sourcefetch:fetch"
  11.  }
  12.  ]
  13.  }
  14.  ]
  15.  }
  16. ]

鍵盤快捷鍵

命令還能夠經過鍵盤快捷鍵來觸發。快捷鍵經過 keymaps 目錄的 JSON 文件來定義:

 
  
  1. {
  2.  "atom-workspace": {
  3.  "ctrl-alt-o": "sourcefetch:toggle"
  4.  }
  5. }

以上代碼可讓用戶經過 Ctrl+Alt+O(Windows/Linux) 或 Cmd+Alt+O(MacOS) 來觸發 toggle 命令。

重命名引用的命令爲 fetch

 
  
  1. "ctrl-alt-o": "sourcefetch:fetch"

經過執行 Window: Reload 命令來重啓 Atom。你應該會看到 Atom 的右擊菜單更新了,而且逆轉文本的功能應該還能夠像以前同樣使用。

在 sourcefetch 教程倉庫 查看這一步全部的代碼更改。

使用 NodeJS 模塊

如今咱們已經完成了第一次代碼更改而且瞭解了 Atom 軟件包的結構,讓咱們介紹一下 Node 包管理器(npm) 中的第一個依賴項模塊。咱們將使用 request 模塊發起 HTTP 請求來下載網站的 HTML 文件。稍後將會用到這個功能來扒 StackOverflow 的頁面。

安裝依賴

打開你的命令行工具,切換到你的軟件包的根目錄並運行:

 
  
  1. npm install --save request@2.73.0
  2. apm install

這兩條命令將 request 模塊添加到咱們軟件包的依賴列表並將模塊安裝到 node_modules 目錄。你應該會在 package.json 看到一個新條目。@ 符號的做用是讓 npm 安裝咱們這篇教程須要用到的特定版本的模塊。運行 apm install 是爲了讓 Atom 知道使用咱們新安裝的模塊。

 
  
  1. "dependencies": {
  2.  "request": "^2.73.0"
  3. }

下載 HTML 並將記錄打印在開發者控制檯

經過在 lib/sourcefetch.js 的頂部添加一條引用語句引入 request 模塊到咱們的主文件:

 
  
  1. import { CompositeDisposable } from 'atom'
  2. import request from 'request'

如今,在 fetch 函數下面添加一個新函數 download 做爲模塊的導出項:

 
  
  1. export default {
  2.  /* subscriptions, activate(), deactivate() */
  3. fetch() {
  4.  ...
  5.  },
  6. download(url) {
  7. request(url, (error, response, body) => {
  8.  if (!error && response.statusCode == 200) {
  9. console.log(body)
  10.  }
  11.  })
  12.  }
  13. }

這個函數用 request 模塊來下載一個頁面的內容並將記錄輸出到控制檯。當 HTTP 請求完成以後,咱們的回調函數會將響應體做爲參數來被調用。

最後一步是更新 fetch 函數以調用 download 函數:

 
  
  1. fetch() {
  2. let editor
  3.  if (editor = atom.workspace.getActiveTextEditor()) {
  4. let selection = editor.getSelectedText()
  5.  this.download(selection)
  6.  }
  7. },

fetch 函數如今的功能是將 selection 看成一個 URL 傳遞給 download 函數,而再也不是逆轉選中的文本了。讓咱們來看看此次的更改:

  • 經過執行 Window: Reload 命令來從新加載 Atom。
  • 打開開發者工具。爲此,導航到菜單中的 View > Developer > Toggle Developer Tools
  • 新建一個文件,導航到 File > New
  • 輸入一個 URL 並選中它,例如:http://www.atom.io
  • 用上述的任意一種方法執行咱們軟件包的命令:

開發者工具讓 Atom 軟件包的調試更輕鬆。每一個 console.log 語句均可以將信息打印到交互控制檯,你還可使用 Elements 選項卡來瀏覽整個應用的可視化結構——即 HTML 的文本對象模型(DOM)

在 sourcefetch 教程倉庫 查看這一步全部的代碼更改。

 

用 Promises 來將下載好的 HTML 插入到編輯器中

理想狀況下,咱們但願 download 函數能夠將 HTML 做爲一個字符串來返回,而不只僅是將頁面的內容打印到控制檯。然而,返回文本內容是沒法實現的,由於咱們要在回調函數裏面訪問內容而不是在 download 函數那裏。

咱們會經過返回一個 Promise 來解決這個問題,而再也不是返回一個值。讓咱們改動 download 函數來返回一個 Promise:

 
   
  1. download(url) {
  2.  return new Promise((resolve, reject) => {
  3. request(url, (error, response, body) => {
  4.  if (!error && response.statusCode == 200) {
  5. resolve(body)
  6.  } else {
  7. reject({
  8. reason: 'Unable to download page'
  9.  })
  10.  }
  11.  })
  12.  })
  13. }

Promises 容許咱們經過將異步邏輯封裝在一個提供兩個回調方法的函數裏來返回得到的值(resolve 用來處理請求成功的返回值,reject 用來向使用者報錯)。若是請求返回了錯誤咱們就調用 reject,不然就用resolve 來處理 HTML。

讓咱們更改 fetch 函數來使用 download 返回的 Promise:

 
   
  1. fetch() {
  2. let editor
  3.  if (editor = atom.workspace.getActiveTextEditor()) {
  4. let selection = editor.getSelectedText()
  5.  this.download(selection).then((html) => {
  6. editor.insertText(html)
  7.  }).catch((error) => {
  8. atom.notifications.addWarning(error.reason)
  9.  })
  10.  }
  11. },

在咱們新版的 fetch 函數裏,咱們經過在 download 返回的 Promise 調用 then 方法來對 HTML 進行操做。這會將 HTML 插入到編輯器中。咱們一樣會經過調用 catch 方法來接收並處理全部的錯誤。咱們經過用Atom Notification API 來顯示警告的形式來處理錯誤。

看看發生了什麼變化。從新加載 Atom 並在一個選中的 URL 上執行軟件包命令:

若是這個 URL 是無效的,一個警告通知將會彈出來:

在 sourcefetch 教程倉庫 查看這一步全部的代碼更改。

編寫一個爬蟲來提取 StackOverflow 頁面的代碼片斷

下一步涉及用咱們前面扒到的 StackOverflow 的頁面的 HTML 來提取代碼片斷。咱們尤爲關注那些來自採納答案(提問者選擇的一個正確答案)的代碼。咱們能夠在假設這類答案都是相關且正確的前提下大大簡化咱們這個軟件包的實現。

使用 jQuery 和 Chrome 開發者工具來構建查詢

這一部分假設你使用的是 Chrome 瀏覽器。你接下來可使用其它瀏覽器,可是提示可能會不同。

讓咱們先看看一張典型的包含採納答案和代碼片斷的 StackOverflow 頁面。咱們將會使用 Chrome 開發者工具來瀏覽 HTML:

  • 打開 Chrome 並跳到任意一個帶有采納答案和代碼的 StackOverflow 頁面,好比像這個用 Python 寫的 hello world 的例子或者這個關於 用 C 來讀取文本內容的問題
  • 滾動窗口到採納答案的位置並選中一部分代碼。
  • 右擊選中文本並選擇 檢查
  • 使用元素偵察器來檢查代碼片斷在 HTML 中的位置。

注意文本結構應該是這樣的:

 
   
  1. <div class="accepted-answer">
  2. ...
  3. ...
  4.  <pre>
  5.  <code>
  6. ...snippet elements...
  7.  </code>
  8.  </pre>
  9. ...
  10. ...
  11. </div>
  • 採納的答案經過一個 class 爲 accepted-answer 的 div 來表示
  • 代碼塊位於 pre 元素的內部
  • 呈現代碼片斷的元素就是裏面那一對 code 標籤

如今讓咱們寫一些 jQuery 代碼來提取代碼片斷:

  • 在開發者工具那裏點擊 Console 選項卡來訪問 Javascript 控制檯。
  • 在控制檯中輸入 $('div.accepted-answer pre code').text() 並按下回車鍵。

你應該會看到控制檯中打印出採納答案的代碼片斷。咱們剛剛運行的代碼使用了一個 jQuery 提供的特別的 $函數。$ 接收要選擇的查詢字符串並返回網站中的某些 HTML 元素。讓咱們經過思考幾個查詢案例看看這段代碼的工做原理:

 
   
  1. $('div.accepted-answer')
  2. > [<div id="answer-1077349" class="answer accepted-answer" ... ></div>]

上面的查詢會匹配全部 class 爲 accepted-answer 的 <div> 元素,在咱們的案例中只有一個 div。

 
   
  1. $('div.accepted-answer pre code')
  2. > [<code>...</code>]

在前面的基礎上改造了一下,這個查詢會匹配全部在以前匹配的 <div> 內部的 <pre> 元素內部的 <code>元素。

 
   
  1. $('div.accepted-answer pre code').text()
  2. > "print("Hello World!")"

text 函數提取並鏈接本來將由上一個查詢返回的元素列表中的全部文本。這也從代碼中去除了用來使語法高亮的元素。

介紹 Cheerio

咱們的下一步涉及使用咱們建立好的查詢結合 Cheerio(一個服務器端實現的 jQuery)來實現扒頁面的功能。

安裝 Cheerio

打開你的命令行工具,切換到你的軟件包的根目錄並執行:

 
    
  1. npm install --save cheerio@0.20.0
  2. apm install

實現扒頁面的功能

在 lib/sourcefetch.js 爲 cheerio 添加一條引用語句:

 
    
  1. import { CompositeDisposable } from 'atom'
  2. import request from 'request'
  3. import cheerio from 'cheerio'

如今建立一個新函數 scrape,它用來提取 StackOverflow HTML 裏面的代碼片斷:

 
    
  1. fetch() {
  2.  ...
  3. },
  4. scrape(html) {
  5. = cheerio.load(html)
  6.  return $('div.accepted-answer pre code').text()
  7. },
  8. download(url) {
  9.  ...
  10. }

最後,讓咱們更改 fetch 函數以傳遞下載好的 HTML 給 scrape 而不是將其插入到編輯器:

 
    
  1. fetch() {
  2. let editor
  3. let self = this
  4.  if (editor = atom.workspace.getActiveTextEditor()) {
  5. let selection = editor.getSelectedText()
  6.  this.download(selection).then((html) => {
  7. let answer = self.scrape(html)
  8.  if (answer === '') {
  9. atom.notifications.addWarning('No answer found :(')
  10.  } else {
  11. editor.insertText(answer)
  12.  }
  13.  }).catch((error) => {
  14. console.log(error)
  15. atom.notifications.addWarning(error.reason)
  16.  })
  17.  }
  18. },

咱們扒取頁面的功能僅僅用兩行代碼就實現了,由於 cheerio 已經替咱們作好了全部的工做!咱們經過調用load 方法加載 HTML 字符串來建立一個 $ 函數,而後用這個函數來執行 jQuery 語句並返回結果。你能夠在官方 開發者文檔 查看完整的 Cheerio API

測試更新後的軟件包

從新加載 Atom 並在一個選中的 StackOverflow URL 上運行 soucefetch:fetch 以查看到目前爲止的進度。

若是咱們在一個有采納答案的頁面上運行這條命令,代碼片斷將會被插入到編輯器中:

若是咱們在一個沒有采納答案的頁面上運行這條命令,將會彈出一個警告通知:

咱們最新的 fetch 函數給咱們提供了一個 StackOverflow 頁面的代碼片斷而再也不是整個 HTML 內容。要注意咱們更新的 fetch 函數會檢查有沒有答案並顯示通知以提醒用戶。

在 sourcefetch 教程倉庫 查看這一步全部的代碼更改。

實現用來查找相關的 StackOverflow URL 的谷歌搜索功能

如今咱們已經將 StackOverflow 的 URL 轉化爲代碼片斷了,讓咱們來實現最後一個函數——search,它應該要返回一個相關的 URL 並附加一些像「hello world」或者「快速排序」這樣的描述。咱們會經過一個非官方的 google npm 模塊來使用谷歌搜索功能,這樣可讓咱們以編程的方式來搜索。

安裝這個 Google npm 模塊

經過在軟件包的根目錄打開命令行工具並執行命令來安裝 google 模塊:

 
     
  1. npm install --save google@2.0.0
  2. apm install

引入並配置模塊

在 lib/sourcefetch.js 的頂部爲 google 模塊添加一條引用語句:

 
     
  1. import google from "google"

咱們將配置一下 google 以限制搜索期間返回的結果數。將下面這行代碼添加到引用語句下面以限制搜索返回最熱門的那個結果。

 
     
  1. google.resultsPerPage = 1

實現 search 函數

接下來讓咱們來實現咱們的 search 函數:

 
     
  1. fetch() {
  2.  ...
  3. },
  4. search(query, language) {
  5.  return new Promise((resolve, reject) => {
  6. let searchString = `${query} in ${language} site:stackoverflow.com`
  7. google(searchString, (err, res) => {
  8.  if (err) {
  9. reject({
  10. reason: 'A search error has occured :('
  11.  })
  12.  } else if (res.links.length === 0) {
  13. reject({
  14. reason: 'No results found :('
  15.  })
  16.  } else {
  17. resolve(res.links[0].href)
  18.  }
  19.  })
  20.  })
  21. },
  22. scrape() {
  23.  ...
  24. }

以上代碼經過谷歌來搜索一個和指定的關鍵詞以及編程語言相關的 StackOverflow 頁面,並返回一個最熱門的 URL。讓咱們看看這是怎樣來實現的:

 
     
  1. let searchString = `${query} in ${language} site:stackoverflow.com`

咱們使用用戶輸入的查詢和當前所選的語言來構造搜索字符串。比方說,當用戶在寫 Python 的時候輸入「hello world」,查詢語句就會變成 hello world in python site:stackoverflow.com。字符串的最後一部分是谷歌搜索提供的一個過濾器,它讓咱們能夠將搜索結果的來源限制爲 StackOverflow。

 
     
  1. google(searchString, (err, res) => {
  2.  if (err) {
  3. reject({
  4. reason: 'A search error has occured :('
  5.  })
  6.  } else if (res.links.length === 0) {
  7. reject({
  8. reason: 'No results found :('
  9.  })
  10.  } else {
  11. resolve(res.links[0].href)
  12.  }
  13. })

咱們將 google 方法放在一個 Promise 裏面,這樣咱們能夠異步地返回咱們的 URL。咱們會傳遞由google 返回的全部錯誤而且會在沒有可用的搜索結果的時候返回一個錯誤。不然咱們將經過 resolve 來解析最熱門結果的 URL。

更新 fetch 來使用 search

咱們的最後一步是更新 fetch 函數來使用 search 函數:

 
     
  1. fetch() {
  2. let editor
  3. let self = this
  4.  if (editor = atom.workspace.getActiveTextEditor()) {
  5. let query = editor.getSelectedText()
  6. let language = editor.getGrammar().name
  7.  self.search(query, language).then((url) => {
  8. atom.notifications.addSuccess('Found google results!')
  9.  return self.download(url)
  10.  }).then((html) => {
  11. let answer = self.scrape(html)
  12.  if (answer === '') {
  13. atom.notifications.addWarning('No answer found :(')
  14.  } else {
  15. atom.notifications.addSuccess('Found snippet!')
  16. editor.insertText(answer)
  17.  }
  18.  }).catch((error) => {
  19. atom.notifications.addWarning(error.reason)
  20.  })
  21.  }
  22. }

讓咱們看看發生了什麼變化:

  • 咱們選中的文本如今變成了用戶輸入的 query
  • 咱們使用 TextEditor API 來獲取當前編輯器選項卡使用的 language
  • 咱們調用 search 方法來獲取一個 URL,而後經過在獲得的 Promise 上調用 then 方法來訪問這個 URL

咱們不在 download 返回的 Promise 上調用 then 方法,而是在前面 search 方法自己鏈式調用的另外一個then 方法返回的 Promise 上面接着調用 then 方法。這樣能夠幫助咱們避免回調地獄

在 sourcefetch 教程倉庫 查看這一步全部的代碼更改。

測試最終的插件

大功告成了!從新加載 Atom,對一個「問題描述」運行軟件包的命令來看看咱們最終的插件是否工做,不要忘了在編輯器右下角選擇一種語言。

下一步

如今你知道怎麼去 「hack」 Atom 的基本原理了,經過 分叉 sourcefetch 這個倉庫並添加你的特性 來爲所欲爲地實踐你所學到的知識。

原文發佈時間爲:2016-10-15

本文來自雲棲社區合做夥伴「Linux中國」

原文連接

相關文章
相關標籤/搜索