diff --git a/translated/20160820 Building your first Atom plugin.md b/translated/20160820 Building your first Atom plugin.md index fdb6a35916..97af205040 100644 --- a/translated/20160820 Building your first Atom plugin.md +++ b/translated/20160820 Building your first Atom plugin.md @@ -1,32 +1,28 @@ -OneNewLife translated +制作你的第一个 Atom 文本编辑器插件 +=========== -制作你的第一个 Atom 插件 -===== - ->作者: [GitHub 校园专家][1] @NickTikhonov。 - -这篇教程将会教你怎么制作你的第一个 Atom 插件。我们将会制作一个山寨的 [Sourcerer][2]——一个查询并使用 StackOverflow 的代码片段的插件。到教程结束时,你将会制作好一个将编程问题(用英语描述的)转换成获取自 StackOverflow 的代码片段的插件,像这样: +这篇教程将会教你怎么制作你的第一个 Atom 文本编辑器的插件。我们将会制作一个山寨版的 [Sourcerer][2],这是一个从 StackOverflow 查询并使用代码片段的插件。到教程结束时,你将会制作好一个将编程问题(用英语描述的)转换成获取自 StackOverflow 的代码片段的插件,像这样: ![](https://cloud.githubusercontent.com/assets/6755555/17759382/836dd780-64ab-11e6-8f6a-329f66f01fd7.gif) -### 教程须知 +#### 教程须知 -Atom 是用 web 技术创造出来的。我们将完全使用 JavaScript 的 EcmaScript 6 规范来制作插件。你需要熟悉以下内容: +Atom 文本编辑器是用 web 技术创造出来的。我们将完全使用 JavaScript 的 EcmaScript 6 规范来制作插件。你需要熟悉以下内容: - 使用命令行 - JavaScript 编程 - [Promises][14] - [HTTP][16] -### 教程仓库 +#### 教程的仓库 -你可以跟着教程一步一步走,或者看看 [GitHub 上的补充仓库][3],这里有插件的源代码。这个仓库的历史提交记录标注有每一步的大纲。 +你可以跟着教程一步一步走,或者看看 [放在 GitHub 上的仓库][3],这里有插件的源代码。这个仓库的历史提交记录包含了这里每一个标题。 ### 开始 #### 安装 Atom -根据 [Atom 官网][16] 的说明来下载 Atom。我们同时还要装上 `apm`(Atom 包管理器的命令行工具)。你可以打开 Atom并在应用菜单中导航到 `Atom > Install Shell Commands`。通过打开你的命令行终端,运行 `apm -v` 来检查 `apm` 是否已经正确安装好,安装成功的话打印出来的工具版本和相关环境信息应该是像这样的: +根据 [Atom 官网][16] 的说明来下载 Atom。我们同时还要安装上 `apm`(Atom 包管理器的命令行工具)。你可以打开 Atom 并在应用菜单中导航到 `Atom > Install Shell Commands` 来安装。打开你的命令行终端,运行 `apm -v` 来检查 `apm` 是否已经正确安装好,安装成功的话打印出来的工具版本和相关环境信息应该是像这样的: ``` apm -v @@ -37,29 +33,27 @@ apm -v > git 2.7.4 ``` -#### 生成启动包 +#### 生成代码起步 -让我们通过使用 Atom 提供的一个实用工具创建一个新的 **package**(软件包)来开始这篇教程。 +让我们使用 Atom 提供的一个实用工具创建一个新的 **package**(软件包)来开始这篇教程。 -- 启动编辑器,按下 `Cmd+Shift+P`(MacOS)或者 `Ctrl+Shift+P`(Windows/Linux)来打开 **Command Palette**(命令面板)。 - -- 搜索“Package Generator: Generate Package”并点击列表中选中的条目,你会看到一个弹窗,输入软件包的名称——“sourcefetch”。 - -- 按下回车键来生成这个启动包,它会自动在 Atom 中打开。 +- 起步编辑器,按下 `Cmd+Shift+P`(MacOS)或者 `Ctrl+Shift+P`(Windows/Linux)来打开命令面板(Command Palette)。 +- 搜索“Package Generator: Generate Package”并点击列表中正确的条目,你会看到一个输入提示,输入软件包的名称:“sourcefetch”。 +- 按下回车键来生成这个起步包,它会自动在 Atom 中打开。 如果你在侧边栏没有看到软件包的文件,依次按下 `Cmd+K` `Cmd+B`(MacOS)或者 `Ctrl+K` `Ctrl+B`(Windows/Linux)。 ![](https://cloud.githubusercontent.com/assets/6755555/17759387/8387a354-64ab-11e6-97db-ea469f008bef.gif) -命令面板可以让你通过模糊搜索来找到并运行软件包。这是一个执行命令比较方便的途径,你不用去找导航菜单,也不用刻意去记快捷键。我们将会在整篇教程中使用这个方法。 +> 命令面板(Command Palette)可以让你通过模糊搜索来找到并运行软件包。这是一个执行命令比较方便的途径,你不用去找导航菜单,也不用刻意去记快捷键。我们将会在整篇教程中使用这个方法。 -#### 运行启动包 +#### 运行起步包 -在开始编程前让我们来试用一下这个启动包。我们首先需要重启 Atom,这样它才可以识别我们新增的软件包。再次打开命令面板,执行 `Window: Reload` 命令。 +在开始编程前让我们来试用一下这个起步包。我们首先需要重启 Atom,这样它才可以识别我们新增的软件包。再次打开命令面板,执行 `Window: Reload` 命令。 -重新加载当前窗口以确保 Atom 执行的是我们最新的源代码。每当需要测试对软件包的改动的时候,我们就需要运行这条命令。 +重新加载当前窗口以确保 Atom 执行的是我们最新的源代码。每当需要测试我们对软件包的改动的时候,就需要运行这条命令。 -通过导航到编辑器菜单的 `Packages > sourcefetch > Toggle` 或者在命令面板执行 `sourcefetch: Toggle` 来运行软件包的 `toggle` 命令。你应该会看到屏幕的顶部出现了一个小黑窗。再次运行这条命令就可以隐藏它。 +通过导航到编辑器菜单的 `Packages > sourcefetch > Toggle` 或者在命令面板执行 `sourcefetch:toggle` 来运行软件包的 `toggle` 命令。你应该会看到屏幕的顶部出现了一个小黑窗。再次运行这条命令就可以隐藏它。 ![](https://cloud.githubusercontent.com/assets/6755555/17759386/83799fc0-64ab-11e6-9f0c-0df9b1dbff8b.gif) @@ -78,7 +72,7 @@ toggle() { } ``` -`toggle` 是这个模块导出的一个函数。根据模态面板的可见性,它通过一个 [三目运算符][17] 来调用 `show` 和 `hide` 方法。`modalPanel` 是 [Panel][18](一个由 Atom API 提供的 UI 元素) 的一个实例。我们需要在 `export default` 内部声明 `modalPanel` 才可以让我们通过一个实例变量 `this` 来访问它。 +`toggle` 是这个模块导出的一个函数。根据模态面板的可见性,它通过一个[三目运算符][17] 来调用 `show` 和 `hide` 方法。`modalPanel` 是 [Panel][18](一个由 Atom API 提供的 UI 元素) 的一个实例。我们需要在 `export default` 内部声明 `modalPanel` 才可以让我们通过一个实例变量 `this` 来访问它。 ``` this.subscriptions.add(atom.commands.add('atom-workspace', { @@ -86,25 +80,25 @@ this.subscriptions.add(atom.commands.add('atom-workspace', { })); ``` -上面的语句让 Atom 在用户运行 `sourcefetch:toggle` 的时候执行 `toggle` 方法。我们订阅了一个 [匿名函数][19] `() => this.toggle()`,每次执行这条命令的时候都会执行这个函数。这是 [事件驱动编程][20](一种常用的 JavaScript 模式)的一个范例。 +上面的语句让 Atom 在用户运行 `sourcefetch:toggle` 的时候执行 `toggle` 方法。我们指定了一个 [匿名函数][19] `() => this.toggle()`,每次执行这条命令的时候都会执行这个函数。这是[事件驱动编程][20](一种常用的 JavaScript 模式)的一个范例。 #### Atom 命令 -命令只是用户触发事件时使用的一些字符串标识符,它在软件包的一个命名空间内定义。我们已经用过的命令有: +命令只是用户触发事件时使用的一些字符串标识符,它定义在软件包的命名空间内。我们已经用过的命令有: -- `Package-Generator: Generate-Package` -- `Window: Reload` +- `package-generator:generate-package` +- `Window:reload` - `sourcefetch:toggle` -软件包通过订阅命令来执行代码以达到响应事件的目的。 +软件包对应到命令,以执行代码来响应事件。 ### 进行你的第一次代码更改 让我们来进行第一次代码更改——我们将通过改变 `toggle` 函数来实现逆转用户选中文本的功能。 -#### 改变“toggle”函数 +#### 改变 “toggle” 函数 -- 更改 `toggle` 函数以匹配下面的代码段。 +如下更改 `toggle` 函数。 ``` toggle() { @@ -119,17 +113,15 @@ toggle() { #### 测试你的改动 -- 通过在命令面板运行 `Window: Reload` 来重新加载 Atom - +- 通过在命令面板运行 `Window: Reload` 来重新加载 Atom。 - 通过导航到 `File > New` 来创建一个新文件,随便写点什么并通过光标选中它。 - -- 通过命令面板、Atom 菜单或者右击文本然后选中 `Toggle sourcefetch` 来运行 `sourcefetch:toggle` 命令 +- 通过命令面板、Atom 菜单或者右击文本然后选中 `Toggle sourcefetch` 来运行 `sourcefetch:toggle` 命令。 更新后的命令将会改变选中文本的顺序: ![](https://cloud.githubusercontent.com/assets/6755555/17759381/836acd60-64ab-11e6-84dc-4ef4471a361f.gif) -在 [sourcefetch 教程仓库][4] 查看这一步所有的代码更改。 +在 [sourcefetch 教程仓库][4] 查看这一步的全部代码更改。 ### Atom 编辑器 API @@ -140,7 +132,7 @@ let editor if (editor = atom.workspace.getActiveTextEditor()) { /* ... */ } ``` -头两行代码获取了 [TextEditor][5] 实例的一个引用。变量的赋值和后面的代码被包在一个条件结构里,这是为了处理没有可用的编辑器实例的情况,例如,当用户在设置菜单中运行命令时。 +头两行代码获取了 [TextEditor][5] 实例的一个引用。变量的赋值和后面的代码被包在一个条件结构里,这是为了处理没有可用的编辑器实例的情况,例如,当用户在设置菜单中运行该命令时。 ``` let selection = editor.getSelectedText() @@ -155,9 +147,9 @@ editor.insertText(reversed) 我们选中的文本通过一个 [JavaScript 字符串方法][6] 来逆转。最后,我们调用 `insertText` 方法来将选中的文本替换为逆转后的文本副本。通过阅读 [Atom API 文档][5],你可以学到更多关于 TextEditor 的不同的方法。 -### 浏览启动包 +### 浏览这个起步包 -现在我们已经完成第一次代码更改了,让我们浏览启动包的代码来深入了解一下 Atom 的软件包是怎样构成的。 +现在我们已经完成第一次代码更改了,让我们浏览起步包的代码来深入了解一下 Atom 的软件包是怎样构成的。 #### 主文件 @@ -170,12 +162,10 @@ editor.insertText(reversed) 这个文件导出一个带有生命周期函数(Atom 在特定的事件发生时调用的处理函数)的对象。 - **activate** 会在 Atom 初次加载软件包的时候调用。这个函数用来初始化一些诸如软件包所需的用户界面元素的对象,以及订阅软件包命令的处理函数。 - - **deactivate** 会在软件包停用的时候调用,例如,当用户关闭或者刷新编辑器的时候。 +- **serialize** Atom 调用它在使用软件包的过程中保存软件包的当前状态。它的返回值会在 Atom 下一次加载软件包的时候作为一个参数传递给 `activate`。 -- **serialize** 会在使用软件包的过程中被 Atom 调用以保存软件包的当前状态。它的返回值会在 Atom 下一次加载软件包的时候作为一个参数传递给 `activate`。 - -我们将会重命名我们的软件包命令为 `fetch`,并移除一些我们不再需要的用户界面元素。更改主文件以匹配下面这个版本: +我们将会重命名我们的软件包命令为 `fetch`,并移除一些我们不再需要的用户界面元素。按照如下更改主文件: ``` 'use babel'; @@ -209,9 +199,9 @@ export default { }; ``` -### 启用命令 +### “启用”命令 -为了提升性能,Atom 软件包可以懒加载。我们可以让 Atom 在用户执行特定的命令的时候加载我们的软件包。这些命令被称为 **启用命令**,它们在 `package.json` 中定义: +为了提升性能,Atom 软件包可以用时加载。我们可以让 Atom 在用户执行特定的命令的时候才加载我们的软件包。这些命令被称为 **启用命令**,它们在 `package.json` 中定义: ``` "activationCommands": { @@ -219,7 +209,7 @@ export default { }, ``` -更新一下条目设置,让 `fetch` 成为一个启用命令。 +更新一下这个条目设置,让 `fetch` 成为一个启用命令。 ``` "activationCommands": { @@ -229,7 +219,7 @@ export default { 有一些软件包需要在 Atom 启动的时候被加载,例如那些改变 Atom 外观的软件包。在那样的情况下,`activationCommands` 会被完全忽略。 -### 触发命令 +### “触发”命令 #### 菜单项 @@ -246,7 +236,7 @@ export default { }, ``` -这个 `context-menu` 对象可以让我们定义右击菜单的一些新条目。每一个条目都是通过一个决定显示内容的 `label` 属性和一个决定点击后执行的命令的 `command` 属性来定义的。 +这个 `context-menu` 对象可以让我们定义右击菜单的一些新条目。每一个条目都是通过一个显示在菜单的 `label` 属性和一个点击后执行的命令的 `command` 属性来定义的。 ``` "context-menu": { @@ -259,7 +249,7 @@ export default { }, ``` -同一个文件中的这个 `menu` 对象用来定义插件的自定义应用菜单。我们同样要重命名它的条目: +同一个文件中的这个 `menu` 对象用来定义插件的自定义应用菜单。我们如下重命名它的条目: ``` "menu": [ @@ -306,7 +296,7 @@ export default { ### 使用 NodeJS 模块 -现在我们已经完成了第一次代码更改并且了解了 Atom 软件包的结构,让我们介绍一下 [Node 包管理器(npm)][22] 中的第一个依赖项模块。我们将使用 **request** 模块发 HTTP 请求来下载网站的 HTML 文件。稍后将会用到这个功能来扒 StackOverflow 的页面。 +现在我们已经完成了第一次代码更改并且了解了 Atom 软件包的结构,让我们介绍一下 [Node 包管理器(npm)][22] 中的第一个依赖项模块。我们将使用 **request** 模块发起 HTTP 请求来下载网站的 HTML 文件。稍后将会用到这个功能来扒 StackOverflow 的页面。 #### 安装依赖 @@ -355,7 +345,7 @@ export default { } ``` -这个函数用 `request` 模块来下载一张页面的内容并将记录输出到控制台。当 HTTP 请求完成之后,我们的 [回调函数][23] 会将响应体作为参数来被调用。 +这个函数用 `request` 模块来下载一个页面的内容并将记录输出到控制台。当 HTTP 请求完成之后,我们的[回调函数][23]会将响应体作为参数来被调用。 最后一步是更新 `fetch` 函数以调用 `download` 函数: @@ -372,24 +362,20 @@ fetch() { `fetch` 函数现在的功能是将 selection 当作一个 URL 传递给 `download` 函数,而不再是逆转选中的文本了。让我们来看看这次的更改: - 通过执行 `Window: Reload` 命令来重新加载 Atom。 - - 打开开发者工具。为此,导航到菜单中的 `View > Developer > Toggle Developer Tools`。 - - 新建一个文件,导航到 `File > New`。 - - 输入一个 URL 并选中它,例如:`http://www.atom.io`。 - - 用上述的任意一种方法执行我们软件包的命令: ![](https://cloud.githubusercontent.com/assets/6755555/17759384/836ea91c-64ab-11e6-8fbe-7d15fb482c6d.gif) -**开发者工具** 让 Atom 软件包的调试更轻松。任意 `console.log` 语句都可以将信息打印到交互控制台,你还可以使用 `Elements` 选项卡来浏览整个应用的可视化结构——即 HTML 的 [文本对象模型(DOM)][8]。 +> **开发者工具**让 Atom 软件包的调试更轻松。每个 `console.log` 语句都可以将信息打印到交互控制台,你还可以使用 `Elements` 选项卡来浏览整个应用的可视化结构——即 HTML 的[文本对象模型(DOM)][8]。 在 [sourcefetch 教程仓库][9] 查看这一步所有的代码更改。 ### 用 Promises 来将下载好的 HTML 插入到编辑器中 -理想情况下,我们希望 download 函数可以将 HTML 作为一个字符串来返回,而不仅仅是将页面的内容打印到控制台。然而,`返回体` 是无法实现的,因为我们要在回调函数里面访问 `返回体` 而不是在 `download` 函数那里。 +理想情况下,我们希望 `download` 函数可以将 HTML 作为一个字符串来返回,而不仅仅是将页面的内容打印到控制台。然而,返回文本内容是无法实现的,因为我们要在回调函数里面访问内容而不是在 `download` 函数那里。 我们会通过返回一个 [Promise][24] 来解决这个问题,而不再是返回一个值。让我们改动 `download` 函数来返回一个 Promise: @@ -409,7 +395,7 @@ download(url) { } ``` -Promises 允许我们通过将异步逻辑封装在一个提供两个回调方法(`resolve` 用来处理请求成功的返回值,`reject` 用来向使用者报错)的函数里来返回获得的值。如果请求返回了错误我们就调用 `reject`,否则就用 `resolve` 来处理 HTML。 +Promises 允许我们通过将异步逻辑封装在一个提供两个回调方法的函数里来返回获得的值(`resolve` 用来处理请求成功的返回值,`reject` 用来向使用者报错)。如果请求返回了错误我们就调用 `reject`,否则就用 `resolve` 来处理 HTML。 让我们更改 `fetch` 函数来使用 `download` 返回的 Promise: @@ -449,12 +435,9 @@ fetch() { 让我们先看看一张典型的包含采纳答案和代码片段的 StackOverflow 页面。我们将会使用 Chrome 开发者工具来浏览 HTML: -- 打开 Chrome 并跳到任意一张带有采纳答案和代码的 StackOverflow 页面,比如像这个用 Python 写的 [hello world][27] 的例子或者这个关于 [用 `C` 来读取文本内容的问题][28]。 - +- 打开 Chrome 并跳到任意一个带有采纳答案和代码的 StackOverflow 页面,比如像这个用 Python 写的 [hello world][27] 的例子或者这个关于 [用 `C` 来读取文本内容的问题][28]。 - 滚动窗口到采纳答案的位置并选中一部分代码。 - - 右击选中文本并选择 `检查`。 - - 使用元素侦察器来检查代码片段在 HTML 中的位置。 注意文本结构应该是这样的: @@ -473,10 +456,8 @@ fetch() { ``` -- 采纳答案通过一个 class 为 `accepted-answer` 的 `div` 来表示 - +- 采纳的答案通过一个 class 为 `accepted-answer` 的 `div` 来表示 - 代码块位于 `pre` 元素的内部 - - 呈现代码片段的元素就是里面那一对 `code` 标签 ![](https://cloud.githubusercontent.com/assets/6755555/17759380/83689a90-64ab-11e6-89b2-7172c03baae7.gif) @@ -484,10 +465,9 @@ fetch() { 现在让我们写一些 `jQuery` 代码来提取代码片段: - 在开发者工具那里点击 **Console** 选项卡来访问 Javascript 控制台。 - - 在控制台中输入 `$('div.accepted-answer pre code').text()` 并按下回车键。 -你应该会看到控制台中打印出采纳答案的代码片段。我们刚刚运行的代码使用了一个 jQuery 提供的特别的 `$` 函数。`$` 接收要选择的 **查询字符串** 并返回网站中的某些 HTML 元素。让我们通过思考几个查询案例看看这段代码的工作原理: +你应该会看到控制台中打印出采纳答案的代码片段。我们刚刚运行的代码使用了一个 jQuery 提供的特别的 `$` 函数。`$` 接收要选择的**查询字符串**并返回网站中的某些 HTML 元素。让我们通过思考几个查询案例看看这段代码的工作原理: ``` $('div.accepted-answer') @@ -525,7 +505,7 @@ apm install #### 实现扒页面的功能 -- 在 `lib/sourcefetch.js` 为 `cheerio` 添加一条引用语句: +在 `lib/sourcefetch.js` 为 `cheerio` 添加一条引用语句: ``` import { CompositeDisposable } from 'atom' @@ -533,7 +513,7 @@ import request from 'request' import cheerio from 'cheerio' ``` -- 现在创建一个新函数 `scrape`,它用来提取 StackOverflow HTML 里面的代码片段: +现在创建一个新函数 `scrape`,它用来提取 StackOverflow HTML 里面的代码片段: ``` fetch() { @@ -550,7 +530,7 @@ download(url) { } ``` -- 最后,让我们更改 `fetch` 函数以传递下载好的 HTML 给 `scrape` 而不是将其插入到编辑器: +最后,让我们更改 `fetch` 函数以传递下载好的 HTML 给 `scrape` 而不是将其插入到编辑器: ``` fetch() { @@ -578,7 +558,7 @@ fetch() { ### 测试更新后的软件包 -- 重新加载 Atom 并在一个选中的 StackOverflow URL 上运行 `soucefetch:fetch` 以查看到目前为止的进度。 +重新加载 Atom 并在一个选中的 StackOverflow URL 上运行 `soucefetch:fetch` 以查看到目前为止的进度。 如果我们在一个有采纳答案的页面上运行这条命令,代码片段将会被插入到编辑器中: @@ -594,11 +574,11 @@ fetch() { ### 实现用来查找相关的 StackOverflow URL 的谷歌搜索功能 -现在我们已经将 StackOverflow 的 URL 转化为代码片段了,让我们来实现最后一个函数——`search`,它应该要返回一个相关的 URL 并附加一些像“hello world”或者“快排”这样的描述。我们会通过一个非官方的 `google` npm 模块来使用谷歌搜索功能,这样可以让我们以编程的方式来搜索。 +现在我们已经将 StackOverflow 的 URL 转化为代码片段了,让我们来实现最后一个函数——`search`,它应该要返回一个相关的 URL 并附加一些像“hello world”或者“快速排序”这样的描述。我们会通过一个非官方的 `google` npm 模块来使用谷歌搜索功能,这样可以让我们以编程的方式来搜索。 -#### 安装 Google npm 模块 +#### 安装这个 Google npm 模块 -- 通过在软件包的根目录打开命令行工具并执行命令来安装 `google` 模块: +通过在软件包的根目录打开命令行工具并执行命令来安装 `google` 模块: ``` npm install --save google@2.0.0 @@ -653,7 +633,7 @@ scrape() { } ``` -以上代码通过谷歌来搜索一张和指定的关键词以及编程语言相关的 StackOverflow 页面,并返回一个最热门的 URL。让我们看看这是怎样来实现的: +以上代码通过谷歌来搜索一个和指定的关键词以及编程语言相关的 StackOverflow 页面,并返回一个最热门的 URL。让我们看看这是怎样来实现的: ``` let searchString = `${query} in ${language} site:stackoverflow.com` @@ -713,32 +693,30 @@ fetch() { 让我们看看发生了什么变化: - 我们选中的文本现在变成了用户输入的 `query` - - 我们使用 [TextEditor API][21] 来获取当前编辑器选项卡使用的 `language` - - 我们调用 `search` 方法来获取一个 URL,然后通过在得到的 Promise 上调用 `then` 方法来访问这个 URL -我们不在 `download` 返回的 Promise 上调用 `then` 方法,而是在前面 `search` 方法本身链式调用的另一个 `then` 方法返回的 Promise 上面接着调用 `then` 方法。这样可以帮助我们避免 [回调地狱][31] +我们不在 `download` 返回的 Promise 上调用 `then` 方法,而是在前面 `search` 方法本身链式调用的另一个 `then` 方法返回的 Promise 上面接着调用 `then` 方法。这样可以帮助我们避免[回调地狱][31] 在 [sourcefetch 教程仓库][12] 查看这一步所有的代码更改。 ### 测试最终的插件 -大功告成了!重新加载 Atom,对一个问题描述运行软件包的命令来看看我们最终的插件,不要忘了在编辑器右下角选择一种语言。 +大功告成了!重新加载 Atom,对一个“问题描述”运行软件包的命令来看看我们最终的插件是否工作,不要忘了在编辑器右下角选择一种语言。 ![](https://cloud.githubusercontent.com/assets/6755555/17759382/836dd780-64ab-11e6-8f6a-329f66f01fd7.gif) ### 下一步 -现在你知道怎么去“hack” Atom 的基本原理了,通过 [fork sourcefetch 这个仓库并添加你的特性][13] 来随心所欲地实践你所学到的知识。 +现在你知道怎么去 “hack” Atom 的基本原理了,通过 [分叉 sourcefetch 这个仓库并添加你的特性][13] 来随心所欲地实践你所学到的知识。 -------------------------------------------------------------------------------- -编译自: https://github.com/blog/2231-building-your-first-atom-plugin +via: https://github.com/blog/2231-building-your-first-atom-plugin 作者:[NickTikhonov][a] 译者:[OneNewLife](https://github.com/OneNewLife) -校对:[校对者ID](https://github.com/校对者ID) +校对:[wxy](https://github.com/wxy) 本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出