制做你的第一个 Atom 文本编辑器插件

原文连接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中国”

原文连接

相关文章
相关标签/搜索