ATOM

Package 作成時の便利フレーズ、知識など

More than 3 years have passed since last update.

Atom の Package 開発でよく使うフレーズ、知識等を気まぐれに追記していきます。

自分の理解整理の為の dump が目的です。

API の使い方は、本体のコード や、ユーザー atom の Package を読むのが一番よい。

ちなみに、ここにまとめる為に整理、変更して書いてるので、自分の Package 内で使っているものとは若干違います。

整理変更後、全部の動作確認はしていないので、何かあればコメントで指摘して下さい。


便利キーマップ

基本的に、cmd-t や、cmd-r で表示されるミニエディタの絞込時に、; セミコロンを入力する事は無いので、これを決定(core:confirm)として使っている。

また、ctrl-u で行頭まで文字列を一気に消せるようにもしている。


keymap.cson

'.select-list':

';': 'core:confirm'
'ctrl-u': 'editor:delete-to-beginning-of-line'


Atom 自体の Hack


ATOM_DEV_RESOURCE_PATH 環境変数

atom コマンドのヘルプを見れば書いてあるが、ATOM_DEV_RESOURCE_PATH という環境変数がある。

ここに指定したPATHは、dev モードで起動した時、source をロードする PATH として使われる。

つまり、直接 coffee の source を変更して、dev モードで起動するだけで、動作を直ぐに確認出来る。

デフォルトでは、~/github/atom が使われるので、~/github 直下に atom を clone しておけば、

$ atom -d で起動するだけで良い。

$ atom --help

Atom Editor v1.0.3-9774b20

Usage: atom [options] [path ...]

One or more paths to files or folders may be specified. If there is an
existing Atom window that contains all of the given folders, the paths
will be opened in that window. Otherwise, they will be opened in a new
window.

Environment Variables:

ATOM_DEV_RESOURCE_PATH The path from which Atom loads source code in dev mode.
Defaults to `~/github/atom`.

ATOM_HOME The root path for all configuration files and folders.
Defaults to `~/.atom`.
<以下省略>


TextEditor 内で使われている単語リストを取得する

lazy-motion 内で似たようなことをやっている。

二回目の get 以降は、キャッシュを返すので、取得しなおしたければ、destroy() 後、get すればいける(はず)。

# 指定したパターンにマッチするテキストのリストを返す

getTokenProvider: (editor, pattern) ->
matches = null

get: ->
return matches if matches
matches = []
editor.scan pattern, ({matchText}) =>
matches.push matchText
matches

destroy: ->
matches = null

Usage

editor = atom.workspace.getActiveTextEditor()

@tokenProvider ?= @getTokenProvider(editor, /\w+/g)
console.log @tokenProvider.get()
@tokenProvider.destroy()
@tokenProvider = null


Markdown 内のソースコード部分の Grammar スコープ名を得る。

例えば、Markdown 内の、CoffeeScript のコード部分にカーソルがある時、source.coffee のようなスコープ名を取得したい。

単に以下の様にしたのでは取得できない。

scopeName = atom.workspace.getActiveTextEditor().getGrammar().scopeName

scopeName # => 'source.gfm'

方法

# カーソル位置の ScopeDescriptor を得る

getCursorScope: ->
editor = atom.workspace.getActiveTextEditor()
[rowStart, rowEnd] = editor.getLastSelection().getBufferRowRange()
editor.scopeDescriptorForBufferPosition([rowStart, 0])

# 渡された ScopeDescriptor から最もカーソル位置に近い、Grammar Scope を得る。
# scopesArray は、`comment.line.number-signe.coffee` のような scope も含まれるので
# grammarScopename に絞って探す。
getGrammarScopeNameForScope: (scope)->
scopeNames = scope.getScopesArray().slice().reverse()
for scopeName in scopeNames when scopeName in @getGrammarScopeNames()
return scopeName
null

# 利用できる Grammarの ScopeName のリストを得る。
getGrammarScopeNames: ->
atom.grammars.getGrammars().map (grammar) ->
grammar.scopeName

Usage

scopeName = @getGrammarScopeNameForScope @getCursorScope()


画面をフラッシュする

注意を促したいときに。Screen Beep 的なもん。

ScreenRow の範囲でフラッシュしてるので、Fold があっても大丈夫。


  • coffee

flashScreen: (editor, duration=150) ->

[startRow, endRow] = editor.getVisibleRowRange().map (row) ->
editor.bufferRowForScreenRow row

range = [[startRow, 0], [endRow, Infinity]]
marker = editor.markBufferRange range,
invalidate: 'never'
persistent: false

flashingDecoration = editor.decorateMarker marker,
type: 'highlight'
class: 'sample-flash'

setTimeout =>
flashingDecoration.getMarker().destroy()
, duration


  • less

@import "syntax-variables";

atom-text-editor::shadow {
.sample-flash .region {
background-color: @syntax-selection-flash-color;
}
}


  • Usage

@flashScreen atom.workspace.getActiveTextEditor(), 200


ヒストリ管理

ヒストリ管理をしたいことは良くある。

簡単版.

_ = require 'underscore-plus'

getHistoryManager: (maxSize) ->
entries = []
index = -1

get: (direction) ->
if direction is 'prev'
index = (index + 1) % entries.length
else if direction is 'next'
index -= 1
index = (entries.length - 1) if index < 0
entries[index]

save: (entry) ->
return if _.isEmpty(entry)
entries.unshift entry
entries = _.uniq entries # Eliminate duplicates
if entries.length > maxSize
entries.splice maxSize

reset: ->
index = -1

destroy: ->
entries = null
index = null

Usage

historySize = 10

@historyManager = @getHistoryManager historySize

# 保存
@historyManager.save 'foo'

# 取り出し
if entry = @historyManager.get 'prev'
console.log entry

# 不要になったら開放
@historyManager.destroy()


画面に見えている、TextEditor を得る。

path はオプションで、 同じPATHの TextEditor のみを取得したい場合に指定する。

getVisibleEditors: ({path}={}) ->

editors = atom.workspace.getPanes()
.map (pane) -> pane.getActiveEditor()
.filter (editor) -> editor?

if path
editors = editors.filter (editor) ->
editor.getPath() is path
editors

Usage

# case-1

editors = @getVisibleEditors()

# case-2
editor = atom.workspace.getActiveTextEditor()
editors = @getVisibleEditors path: editor.getPath()


TextEditor の状態を保存して復旧する

エディタの状態を復旧する関数を返す関数。

Emacs には save-excursion という関数(スペシャル・フォーム)があって、いろいろやった後にエディタの見た目の状態を一発で元に戻すことができて便利だった。

それには全く及ばないが、screenTop と、fold を元の状態に戻せる。

スクロールしたり、fold を開いたりしても、元に戻せるという事。

# Return function to restore editor state.

saveEditorState: (editor) ->
scrollTop = editor.getScrollTop()
foldStartRows = editor.displayBuffer.findFoldMarkers().map (m) =>
editor.displayBuffer.foldForMarker(m).getStartRow()
->
for row in foldStartRows.reverse() when not editor.isFoldedAtBufferRow(row)
editor.foldBufferRow row
editor.setScrollTop scrollTop

Usage

editor = atom.workspace.getActiveTextEditor()

@restoreEditorState = @saveEditorState editor

# <このあと, scroll や unfold が必要な処理>

@restoreEditorState()