├── spec ├── fixtures │ ├── dir │ │ ├── file1 │ │ ├── b │ │ ├── a-dir │ │ │ └── oh-git │ │ └── a │ ├── git │ │ ├── working-dir │ │ │ ├── a.txt │ │ │ ├── .gitignore │ │ │ └── git.git │ │ │ │ ├── HEAD │ │ │ │ ├── refs │ │ │ │ └── heads │ │ │ │ │ └── master │ │ │ │ ├── index │ │ │ │ ├── config │ │ │ │ └── objects │ │ │ │ ├── 16 │ │ │ │ └── 735fb793d7b038818219c4b8c6295346e20eef │ │ │ │ ├── 52 │ │ │ │ └── f56457b6fca045ce41bb9d32e6ca79d23192af │ │ │ │ ├── 65 │ │ │ │ └── a457425a679cbe9adf0d2741785d3ceabb44a7 │ │ │ │ ├── 66 │ │ │ │ └── dc9051da651c15d98d017a88658263cab28f02 │ │ │ │ ├── 06 │ │ │ │ └── 15f9a45968b3515e0a202530ef9f61aba26b6c │ │ │ │ ├── 5b │ │ │ │ └── 24ab4c3baadf534242b1acc220c8fa051b9b20 │ │ │ │ ├── 8a │ │ │ │ └── 9c86f1cb1f14b8f436eb91f4b052c8802ca99e │ │ │ │ ├── e6 │ │ │ │ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391 │ │ │ │ ├── ec │ │ │ │ └── 5e386905ff2d36e291086a1207f2585aaa8920 │ │ │ │ ├── ef │ │ │ │ └── 046e9eecaa5255ea5e9817132d4001724d6ae1 │ │ │ │ ├── fe │ │ │ │ └── bde178cdf35e9df6279d87aa27590c6d92e354 │ │ │ │ └── ff │ │ │ │ └── c8218bd2240a0cb92f6f02548d45784428349b │ │ ├── ignore.git │ │ │ ├── info │ │ │ │ └── exclude │ │ │ ├── HEAD │ │ │ ├── refs │ │ │ │ └── heads │ │ │ │ │ └── master │ │ │ ├── index │ │ │ ├── config │ │ │ └── objects │ │ │ │ ├── 65 │ │ │ │ └── a457425a679cbe9adf0d2741785d3ceabb44a7 │ │ │ │ ├── e6 │ │ │ │ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391 │ │ │ │ └── ef │ │ │ │ └── 046e9eecaa5255ea5e9817132d4001724d6ae1 │ │ └── master.git │ │ │ ├── HEAD │ │ │ ├── refs │ │ │ └── heads │ │ │ │ └── master │ │ │ ├── index │ │ │ ├── config │ │ │ └── objects │ │ │ ├── 65 │ │ │ └── a457425a679cbe9adf0d2741785d3ceabb44a7 │ │ │ ├── e6 │ │ │ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391 │ │ │ └── ef │ │ │ └── 046e9eecaa5255ea5e9817132d4001724d6ae1 │ ├── sample.txt │ ├── packages │ │ ├── package-with-empty-menu │ │ │ ├── menus │ │ │ │ └── menu.cson │ │ │ └── package.json │ │ ├── package-with-empty-keymap │ │ │ ├── keymaps │ │ │ │ └── keymap.cson │ │ │ └── package.json │ │ ├── package-with-incompatible-native-module │ │ │ ├── main.js │ │ │ ├── node_modules │ │ │ │ └── native-module │ │ │ │ │ ├── build │ │ │ │ │ └── Release │ │ │ │ │ │ └── native.node │ │ │ │ │ ├── main.js │ │ │ │ │ └── package.json │ │ │ └── package.json │ │ ├── theme-with-syntax-variables │ │ │ ├── styles │ │ │ │ └── editor.less │ │ │ └── package.json │ │ ├── package-with-invalid-styles │ │ │ ├── styles │ │ │ │ └── index.less │ │ │ └── package.json │ │ ├── package-with-styles │ │ │ └── styles │ │ │ │ ├── 4.css │ │ │ │ ├── 1.css │ │ │ │ ├── 3.test-context.css │ │ │ │ └── 2.less │ │ ├── package-with-broken-keymap │ │ │ └── keymaps │ │ │ │ └── broken.json │ │ ├── package-with-broken-package-json │ │ │ └── package.json │ │ ├── package-with-main │ │ │ ├── package.cson │ │ │ └── main-module.coffee │ │ ├── package-without-module │ │ │ └── package.cson │ │ ├── theme-with-index-css │ │ │ ├── package.json │ │ │ └── index.css │ │ ├── package-with-index │ │ │ └── index.coffee │ │ ├── package-with-serialize-error │ │ │ ├── package.cson │ │ │ └── index.coffee │ │ ├── theme-with-index-less │ │ │ ├── package.json │ │ │ └── index.less │ │ ├── package-with-menus-manifest │ │ │ ├── package.cson │ │ │ └── menus │ │ │ │ ├── menu-3.cson │ │ │ │ ├── menu-1.cson │ │ │ │ └── menu-2.cson │ │ ├── package-with-style-sheets-manifest │ │ │ ├── package.cson │ │ │ └── styles │ │ │ │ ├── 1.css │ │ │ │ ├── 3.css │ │ │ │ └── 2.less │ │ ├── package-with-stylesheets-manifest │ │ │ └── package.cson │ │ ├── package-with-keymaps-manifest │ │ │ ├── package.cson │ │ │ └── keymaps │ │ │ │ ├── keymap-3.cson │ │ │ │ ├── keymap-1.json │ │ │ │ └── keymap-2.cson │ │ ├── package-with-empty-activation-commands │ │ │ ├── index.coffee │ │ │ └── package.json │ │ ├── package-with-keymaps │ │ │ └── keymaps │ │ │ │ ├── keymap-1.cson │ │ │ │ ├── keymap-2.cson │ │ │ │ └── keymap-3.cjson │ │ ├── package-with-deactivate │ │ │ └── index.coffee │ │ ├── package-that-throws-an-exception │ │ │ └── index.coffee │ │ ├── theme-with-ui-variables │ │ │ ├── package.json │ │ │ └── styles │ │ │ │ ├── editor.less │ │ │ │ └── ui-variables.less │ │ ├── package-with-activation-commands │ │ │ ├── package.cson │ │ │ └── index.coffee │ │ ├── package-with-settings │ │ │ └── settings │ │ │ │ └── omg.cson │ │ ├── theme-with-incomplete-ui-variables │ │ │ ├── package.json │ │ │ └── styles │ │ │ │ ├── ui-variables.less │ │ │ │ └── editor.less │ │ ├── theme-without-package-file │ │ │ └── styles │ │ │ │ ├── b.css │ │ │ │ ├── c.less │ │ │ │ ├── a.css │ │ │ │ └── d.csv │ │ ├── theme-with-package-file │ │ │ ├── package.json │ │ │ └── styles │ │ │ │ ├── last.css │ │ │ │ ├── first.css │ │ │ │ └── second.less │ │ ├── package-that-throws-on-activate │ │ │ └── index.coffee │ │ ├── package-that-throws-on-deactivate │ │ │ └── index.coffee │ │ ├── package-with-config-defaults │ │ │ └── index.coffee │ │ ├── package-with-serialization │ │ │ └── index.coffee │ │ ├── package-with-deprecated-pane-item-method │ │ │ └── index.coffee │ │ ├── package-with-injection-selector │ │ │ └── grammars │ │ │ │ └── grammar.cson │ │ ├── package-with-menus │ │ │ └── menus │ │ │ │ ├── menu-2.cson │ │ │ │ ├── menu-1.cson │ │ │ │ └── menu-3.cson │ │ ├── package-with-consumed-services │ │ │ ├── index.coffee │ │ │ └── package.json │ │ ├── package-with-grammars │ │ │ └── grammars │ │ │ │ ├── alot.cson │ │ │ │ └── alittle.cson │ │ ├── package-with-provided-services │ │ │ ├── index.coffee │ │ │ └── package.json │ │ └── package-with-config-schema │ │ │ └── index.coffee │ ├── module-cache │ │ └── file.json │ ├── script.js │ ├── shebang │ ├── 6to5 │ │ ├── invalid.js │ │ ├── double-quotes.js │ │ └── single-quotes.js │ ├── script-with-deprecations.js │ ├── task-spec-handler.coffee │ ├── css.css │ ├── sample.less │ ├── sample-with-tabs.coffee │ ├── sample-with-tabs-and-leading-comment.coffee │ ├── sample-with-tabs-and-initial-comment.js │ ├── sample.js │ ├── coffee.coffee │ └── sample-with-comments.js ├── atom-protocol-handler-spec.coffee ├── clipboard-spec.coffee ├── panel-spec.coffee ├── spec-bootstrap.coffee ├── spec-helper-platform.coffee ├── buffered-node-process-spec.coffee ├── space-pen-extensions-spec.coffee ├── command-installer-spec.coffee ├── task-spec.coffee ├── 6to5-spec.coffee ├── jasmine-helper.coffee ├── tokenized-line-spec.coffee ├── notification-spec.coffee ├── spec-suite.coffee ├── deserializer-manager-spec.coffee ├── menu-manager-spec.coffee ├── time-reporter.coffee ├── notification-manager-spec.coffee ├── panel-element-spec.coffee └── text-utils-spec.coffee ├── .node-version ├── .python-version ├── .npmrc ├── docs ├── contributing.md ├── README.md ├── build-instructions │ ├── freebsd.md │ └── os-x.md ├── advanced │ ├── node-modules.md │ └── configuration.md ├── index.md ├── upgrading │ └── upgrading-your-syntax-theme.md ├── converting-a-text-mate-bundle.md ├── contributing-to-packages.md └── converting-a-text-mate-theme.md ├── dot-atom ├── .gitignore ├── packages │ └── README.md ├── config.cson ├── init.coffee ├── styles.less ├── snippets.cson └── keymap.cson ├── resources ├── atom.png ├── mac │ ├── atom.icns │ ├── file.icns │ ├── helper-Info.plist │ └── speakeasy.pem ├── win │ ├── atom.ico │ ├── loading.gif │ ├── apm.sh │ ├── atom.js │ ├── atom.sh │ └── atom.cmd └── linux │ ├── icons │ ├── 16.png │ ├── 24.png │ ├── 32.png │ ├── 48.png │ ├── 64.png │ ├── 1024.png │ ├── 128.png │ ├── 256.png │ └── 512.png │ ├── atom.desktop.in │ ├── debian │ ├── lintian-overrides │ └── control.in │ └── redhat │ └── atom.spec.in ├── static ├── octicons.woff ├── images │ ├── octocat-spinner-128.gif │ └── transparent-background.gif ├── links.less ├── icons.less ├── markdown.less ├── linux.less ├── popover-list.less ├── index.html ├── bootstrap-overrides.less ├── messages.less ├── workspace-view.less ├── select-list.less ├── atom.less ├── sections.less ├── syntax.less ├── variables │ ├── octicon-mixins.less │ ├── syntax-variables.less │ └── ui-variables.less ├── panes.less ├── bootstrap.less ├── utilities.less └── buttons.less ├── apm ├── README.md └── package.json ├── script ├── rpmbuild ├── build.cmd ├── clean.cmd ├── grunt.cmd ├── utils │ ├── compile-main-to-app │ ├── clean-open-with-menu │ ├── fix-author │ ├── clean-merged-branches │ ├── child-process-wrapper.js │ └── translate-crash-log-addresses.coffee ├── bootstrap.cmd ├── cibuild-atom-rpm ├── copy-folder.cmd ├── cibuild-atom-linux ├── test ├── mkrpm ├── build ├── create-shortcut.cmd ├── set-version ├── grunt ├── mkdeb ├── clean └── cibuild ├── src ├── subscriber-mixin.coffee ├── item-registry.coffee ├── window-bootstrap.coffee ├── replace-handler.coffee ├── custom-event-mixin.coffee ├── cursor-component.coffee ├── scrollbar-corner-component.coffee ├── scoped-properties.coffee ├── theme-package.coffee ├── scan-handler.coffee ├── window.coffee ├── browser │ ├── context-menu.coffee │ ├── atom-protocol-handler.coffee │ └── auto-updater-win32.coffee ├── less-compile-cache.coffee ├── repository-status-handler.coffee ├── panel-element.coffee ├── scroll-view.coffee ├── input-component.coffee ├── task-bootstrap.coffee ├── highlights-component.coffee ├── notification.coffee ├── scope-descriptor.coffee ├── notification-manager.coffee ├── pane-axis-element.coffee ├── clipboard.coffee ├── panel-container-element.coffee ├── overlay-manager.coffee ├── panel-container.coffee ├── menu-helpers.coffee ├── cursors-component.coffee ├── keymap-extensions.coffee ├── deserializer-manager.coffee ├── panel.coffee ├── buffered-node-process.coffee ├── pane-container-view.coffee ├── text-utils.coffee ├── coffee-cache.coffee ├── fold.coffee └── color.coffee ├── .gitignore ├── keymaps ├── emacs.cson └── base.cson ├── coffeelint.json ├── benchmark ├── benchmark-bootstrap.coffee └── browser-process-startup.coffee ├── .pairs ├── Dockerfile ├── .gitattributes ├── LICENSE.md └── README.md /spec/fixtures/dir/file1: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | v0.10.33 2 | -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 2.7.6 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | cache = ~/.atom/.npm 2 | -------------------------------------------------------------------------------- /spec/fixtures/dir/b: -------------------------------------------------------------------------------- 1 | aaa ccc 2 | -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | ../CONTRIBUTING.md -------------------------------------------------------------------------------- /spec/fixtures/dir/a-dir/oh-git: -------------------------------------------------------------------------------- 1 | bbb aaaa -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/a.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/fixtures/sample.txt: -------------------------------------------------------------------------------- 1 | Some text. 2 | -------------------------------------------------------------------------------- /spec/fixtures/git/ignore.git/info/exclude: -------------------------------------------------------------------------------- 1 | a.txt 2 | -------------------------------------------------------------------------------- /spec/fixtures/dir/a: -------------------------------------------------------------------------------- 1 | aaa bbb 2 | cc aa cc 3 | dollar$bill -------------------------------------------------------------------------------- /spec/fixtures/git/ignore.git/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /spec/fixtures/git/master.git/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-empty-menu/menus/menu.cson: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/.gitignore: -------------------------------------------------------------------------------- 1 | poop 2 | ignored.txt 3 | -------------------------------------------------------------------------------- /spec/fixtures/module-cache/file.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar" 3 | } 4 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-empty-keymap/keymaps/keymap.cson: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/fixtures/script.js: -------------------------------------------------------------------------------- 1 | process.stdout.write(process.argv[2]); 2 | -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/git.git/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-incompatible-native-module/main.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-with-syntax-variables/styles/editor.less: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/fixtures/shebang: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | puts "America – fuck yeah!" -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-invalid-styles/styles/index.less: -------------------------------------------------------------------------------- 1 | { 2 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-styles/styles/4.css: -------------------------------------------------------------------------------- 1 | a { color: red } 2 | -------------------------------------------------------------------------------- /dot-atom/.gitignore: -------------------------------------------------------------------------------- 1 | storage 2 | compile-cache 3 | dev 4 | .npm 5 | .node-gyp 6 | -------------------------------------------------------------------------------- /spec/fixtures/6to5/invalid.js: -------------------------------------------------------------------------------- 1 | 'use 6to6'; 2 | 3 | module.exports = v => v + 1 4 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-broken-keymap/keymaps/broken.json: -------------------------------------------------------------------------------- 1 | INVALID 2 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-broken-package-json/package.json: -------------------------------------------------------------------------------- 1 | INVALID 2 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-main/package.cson: -------------------------------------------------------------------------------- 1 | 'main': 'main-module.coffee' -------------------------------------------------------------------------------- /spec/fixtures/packages/package-without-module/package.cson: -------------------------------------------------------------------------------- 1 | "name": "perfect" 2 | -------------------------------------------------------------------------------- /resources/atom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/resources/atom.png -------------------------------------------------------------------------------- /spec/fixtures/6to5/double-quotes.js: -------------------------------------------------------------------------------- 1 | "use 6to5"; 2 | 3 | module.exports = v => v + 1 4 | -------------------------------------------------------------------------------- /spec/fixtures/6to5/single-quotes.js: -------------------------------------------------------------------------------- 1 | 'use 6to5'; 2 | 3 | module.exports = v => v + 1 4 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-with-index-css/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "theme": "ui" 3 | } 4 | -------------------------------------------------------------------------------- /dot-atom/packages/README.md: -------------------------------------------------------------------------------- 1 | All packages in this directory will be automatically loaded 2 | -------------------------------------------------------------------------------- /spec/fixtures/git/ignore.git/refs/heads/master: -------------------------------------------------------------------------------- 1 | ef046e9eecaa5255ea5e9817132d4001724d6ae1 2 | -------------------------------------------------------------------------------- /spec/fixtures/git/master.git/refs/heads/master: -------------------------------------------------------------------------------- 1 | ef046e9eecaa5255ea5e9817132d4001724d6ae1 2 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-index/index.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | activate: -> 3 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-serialize-error/package.cson: -------------------------------------------------------------------------------- 1 | 'main': 'index.coffee' 2 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-with-index-less/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "theme": "ui" 3 | } 4 | -------------------------------------------------------------------------------- /static/octicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/static/octicons.woff -------------------------------------------------------------------------------- /resources/mac/atom.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/resources/mac/atom.icns -------------------------------------------------------------------------------- /resources/mac/file.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/resources/mac/file.icns -------------------------------------------------------------------------------- /resources/win/atom.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/resources/win/atom.ico -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-main/main-module.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | activate: -> 3 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-menus-manifest/package.cson: -------------------------------------------------------------------------------- 1 | menus: ["menu-2", "menu-1"] 2 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-style-sheets-manifest/package.cson: -------------------------------------------------------------------------------- 1 | styleSheets: ['2', '1'] 2 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-stylesheets-manifest/package.cson: -------------------------------------------------------------------------------- 1 | styleSheets: ['2', '1'] 2 | -------------------------------------------------------------------------------- /resources/win/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/resources/win/loading.gif -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/git.git/refs/heads/master: -------------------------------------------------------------------------------- 1 | 8a9c86f1cb1f14b8f436eb91f4b052c8802ca99e 2 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-keymaps-manifest/package.cson: -------------------------------------------------------------------------------- 1 | keymaps: ["keymap-2", "keymap-1"] 2 | -------------------------------------------------------------------------------- /resources/linux/icons/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/resources/linux/icons/16.png -------------------------------------------------------------------------------- /resources/linux/icons/24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/resources/linux/icons/24.png -------------------------------------------------------------------------------- /resources/linux/icons/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/resources/linux/icons/32.png -------------------------------------------------------------------------------- /resources/linux/icons/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/resources/linux/icons/48.png -------------------------------------------------------------------------------- /resources/linux/icons/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/resources/linux/icons/64.png -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-empty-activation-commands/index.coffee: -------------------------------------------------------------------------------- 1 | module.exports = activate: -> 2 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-keymaps/keymaps/keymap-1.cson: -------------------------------------------------------------------------------- 1 | ".test-1": 2 | "ctrl-z": "test-1" 3 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-keymaps/keymaps/keymap-2.cson: -------------------------------------------------------------------------------- 1 | ".test-2": 2 | "ctrl-z": "test-2" 3 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-keymaps/keymaps/keymap-3.cjson: -------------------------------------------------------------------------------- 1 | ".test-3": 2 | "ctrl-z": "test-3" 3 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-styles/styles/1.css: -------------------------------------------------------------------------------- 1 | #jasmine-content { 2 | font-size: 1px; 3 | } 4 | -------------------------------------------------------------------------------- /resources/linux/icons/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/resources/linux/icons/1024.png -------------------------------------------------------------------------------- /resources/linux/icons/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/resources/linux/icons/128.png -------------------------------------------------------------------------------- /resources/linux/icons/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/resources/linux/icons/256.png -------------------------------------------------------------------------------- /resources/linux/icons/512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/resources/linux/icons/512.png -------------------------------------------------------------------------------- /resources/win/apm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | "$0/../../app/apm/bin/node.exe" "$0/../../app/apm/lib/cli.js" "$@" 4 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-with-index-css/index.css: -------------------------------------------------------------------------------- 1 | atom-text-editor { 2 | padding-top: 1234px; 3 | } 4 | -------------------------------------------------------------------------------- /spec/fixtures/script-with-deprecations.js: -------------------------------------------------------------------------------- 1 | require('fs').existsSync('hi'); 2 | process.stdout.write('hi'); 3 | -------------------------------------------------------------------------------- /spec/fixtures/task-spec-handler.coffee: -------------------------------------------------------------------------------- 1 | module.exports = -> 2 | emit("some-event", 1, 2, 3) 3 | 'hello' 4 | -------------------------------------------------------------------------------- /spec/fixtures/css.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: 1234px; 3 | width: 110%; 4 | font-weight: bold !important; 5 | } 6 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-incompatible-native-module/node_modules/native-module/build/Release/native.node: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-keymaps-manifest/keymaps/keymap-3.cson: -------------------------------------------------------------------------------- 1 | ".test-3": 2 | "ctrl-y": "keymap-3" 3 | -------------------------------------------------------------------------------- /spec/fixtures/git/ignore.git/index: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/ignore.git/index -------------------------------------------------------------------------------- /spec/fixtures/git/master.git/index: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/master.git/index -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-deactivate/index.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | activate: -> 3 | deactivate: -> 4 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-style-sheets-manifest/styles/1.css: -------------------------------------------------------------------------------- 1 | #jasmine-content { 2 | font-size: 1px; 3 | } 4 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-style-sheets-manifest/styles/3.css: -------------------------------------------------------------------------------- 1 | #jasmine-content { 2 | font-size: 3px; 3 | } 4 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-styles/styles/3.test-context.css: -------------------------------------------------------------------------------- 1 | #jasmine-content { 2 | font-size: 3px; 3 | } 4 | -------------------------------------------------------------------------------- /spec/fixtures/sample.less: -------------------------------------------------------------------------------- 1 | @color: #4D926F; 2 | 3 | #header { 4 | color: @color; 5 | } 6 | h2 { 7 | color: @color; 8 | } -------------------------------------------------------------------------------- /apm/README.md: -------------------------------------------------------------------------------- 1 | This folder is where [apm](https://github.com/atom/apm) is installed to so that 2 | it is bundled with Atom. 3 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-that-throws-an-exception/index.coffee: -------------------------------------------------------------------------------- 1 | throw new Error("This package throws an exception") 2 | -------------------------------------------------------------------------------- /static/images/octocat-spinner-128.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/static/images/octocat-spinner-128.gif -------------------------------------------------------------------------------- /script/rpmbuild: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | script/build 6 | script/grunt mkrpm publish-build --stack --install-dir /usr 7 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-styles/styles/2.less: -------------------------------------------------------------------------------- 1 | @size: 2px; 2 | 3 | #jasmine-content { 4 | font-size: @size; 5 | } 6 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-with-ui-variables/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "theme": "ui", 3 | "styleSheets": ["editor.less"] 4 | } 5 | -------------------------------------------------------------------------------- /static/images/transparent-background.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/static/images/transparent-background.gif -------------------------------------------------------------------------------- /script/build.cmd: -------------------------------------------------------------------------------- 1 | @IF EXIST "%~dp0\node.exe" ( 2 | "%~dp0\node.exe" "%~dp0\build" %* 3 | ) ELSE ( 4 | node "%~dp0\build" %* 5 | ) 6 | -------------------------------------------------------------------------------- /script/clean.cmd: -------------------------------------------------------------------------------- 1 | @IF EXIST "%~dp0\node.exe" ( 2 | "%~dp0\node.exe" "%~dp0\clean" %* 3 | ) ELSE ( 4 | node "%~dp0\clean" %* 5 | ) 6 | -------------------------------------------------------------------------------- /script/grunt.cmd: -------------------------------------------------------------------------------- 1 | @IF EXIST "%~dp0\node.exe" ( 2 | "%~dp0\node.exe" "%~dp0\grunt" %* 3 | ) ELSE ( 4 | node "%~dp0\grunt" %* 5 | ) 6 | -------------------------------------------------------------------------------- /script/utils/compile-main-to-app: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | coffee -c -o /Applications/Atom.app/Contents/Resources/app/src/ src/main.coffee 4 | -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/git.git/index: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/working-dir/git.git/index -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-activation-commands/package.cson: -------------------------------------------------------------------------------- 1 | 'activationCommands': 2 | '.workspace': 'activation-command' 3 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-empty-menu/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "package-with-empty-menu", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-settings/settings/omg.cson: -------------------------------------------------------------------------------- 1 | '.source.omg': 2 | 'editor': 3 | 'increaseIndentPattern': '^a' 4 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-with-syntax-variables/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "theme": "syntax", 3 | "styleSheets": ["editor.less"] 4 | } 5 | -------------------------------------------------------------------------------- /dot-atom/config.cson: -------------------------------------------------------------------------------- 1 | 'editor': 2 | 'fontSize': 16 3 | 'core': 4 | 'themes': [ 5 | 'atom-dark-ui' 6 | 'atom-dark-syntax' 7 | ] 8 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-empty-keymap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "package-with-empty-keymap", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-keymaps-manifest/keymaps/keymap-1.json: -------------------------------------------------------------------------------- 1 | { 2 | ".test-1": { 3 | "ctrl-z": "keymap-1" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-keymaps-manifest/keymaps/keymap-2.cson: -------------------------------------------------------------------------------- 1 | ".test-1": 2 | "ctrl-z": "keymap-2" 3 | "ctrl-n": "keymap-2" 4 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-with-incomplete-ui-variables/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "theme": "ui", 3 | "styleSheets": ["editor.less"] 4 | } 5 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-with-index-less/index.less: -------------------------------------------------------------------------------- 1 | @padding: 4321px; 2 | 3 | atom-text-editor { 4 | padding-top: @padding; 5 | } 6 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-invalid-styles/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "package-with-invalid-styles", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-style-sheets-manifest/styles/2.less: -------------------------------------------------------------------------------- 1 | @size: 2px; 2 | 3 | #jasmine-content { 4 | font-size: @size; 5 | } 6 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-without-package-file/styles/b.css: -------------------------------------------------------------------------------- 1 | atom-text-editor { 2 | padding-right: 20px; 3 | padding-bottom: 20px; 4 | } 5 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-without-package-file/styles/c.less: -------------------------------------------------------------------------------- 1 | @number: 30px; 2 | 3 | atom-text-editor { 4 | padding-bottom: @number; 5 | } 6 | -------------------------------------------------------------------------------- /spec/fixtures/sample-with-tabs.coffee: -------------------------------------------------------------------------------- 1 | # Econ 101 2 | if this.studyingEconomics 3 | buy() while supply > demand 4 | sell() until supply > demand 5 | -------------------------------------------------------------------------------- /script/bootstrap.cmd: -------------------------------------------------------------------------------- 1 | @IF EXIST "%~dp0\node.exe" ( 2 | "%~dp0\node.exe" "%~dp0\bootstrap" %* 3 | ) ELSE ( 4 | node "%~dp0\bootstrap" %* 5 | ) 6 | 7 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-with-package-file/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "theme": "ui", 3 | "styleSheets": ["first.css", "second.less", "last.css"] 4 | } 5 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-menus-manifest/menus/menu-3.cson: -------------------------------------------------------------------------------- 1 | 'context-menu': 2 | '.test-1': [ 3 | {label: 'Menu item 3', command: 'command-3'} 4 | ] 5 | -------------------------------------------------------------------------------- /spec/fixtures/git/ignore.git/config: -------------------------------------------------------------------------------- 1 | [core] 2 | repositoryformatversion = 0 3 | filemode = true 4 | bare = false 5 | logallrefupdates = true 6 | ignorecase = true 7 | -------------------------------------------------------------------------------- /spec/fixtures/git/master.git/config: -------------------------------------------------------------------------------- 1 | [core] 2 | repositoryformatversion = 0 3 | filemode = true 4 | bare = false 5 | logallrefupdates = true 6 | ignorecase = true 7 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-incompatible-native-module/node_modules/native-module/main.js: -------------------------------------------------------------------------------- 1 | throw new Error("this simulates a native module's failure to load") 2 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-incompatible-native-module/node_modules/native-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "native-module", 3 | "main": "./main.js" 4 | } 5 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-with-package-file/styles/last.css: -------------------------------------------------------------------------------- 1 | atom-text-editor { 2 | /* padding-top: 103px; 3 | padding-right: 103px;*/ 4 | padding-bottom: 103px; 5 | } -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-without-package-file/styles/a.css: -------------------------------------------------------------------------------- 1 | atom-text-editor { 2 | padding-top: 10px; 3 | padding-right: 10px; 4 | padding-bottom: 10px; 5 | } 6 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-that-throws-on-activate/index.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | activate: -> throw new Error('Top that') 3 | deactivate: -> 4 | serialize: -> 5 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-that-throws-on-deactivate/index.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | activate: -> 3 | deactivate: -> throw new Error('Top that') 4 | serialize: -> 5 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-config-defaults/index.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | configDefaults: 3 | numbers: { one: 1, two: 2 } 4 | 5 | activate: -> # no-op 6 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-without-package-file/styles/d.csv: -------------------------------------------------------------------------------- 1 | atom-text-editor { 2 | padding-top: 100px; 3 | padding-right: 100px; 4 | padding-bottom: 100px; 5 | } 6 | -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/git.git/config: -------------------------------------------------------------------------------- 1 | [core] 2 | repositoryformatversion = 0 3 | filemode = true 4 | bare = false 5 | logallrefupdates = true 6 | ignorecase = true 7 | -------------------------------------------------------------------------------- /spec/fixtures/sample-with-tabs-and-leading-comment.coffee: -------------------------------------------------------------------------------- 1 | # This is a comment 2 | if this.studyingEconomics 3 | buy() while supply > demand 4 | sell() until supply > demand 5 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-empty-activation-commands/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "no events", 3 | "version": "0.1.0", 4 | "activationCommands": {"atom-workspace": []} 5 | } 6 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-serialization/index.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | activate: ({@someNumber}) -> 3 | @someNumber ?= 1 4 | 5 | serialize: -> 6 | {@someNumber} 7 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-with-package-file/styles/first.css: -------------------------------------------------------------------------------- 1 | atom-text-editor { 2 | padding-top: 101px; 3 | padding-right: 101px; 4 | padding-bottom: 101px; 5 | 6 | color: red; 7 | } -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-deprecated-pane-item-method/index.coffee: -------------------------------------------------------------------------------- 1 | class TestItem 2 | getUri: -> "test" 3 | 4 | exports.activate = -> 5 | atom.workspace.addOpener -> new TestItem 6 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-incompatible-native-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "package-with-incompatible-native-module", 3 | "version": "1.0", 4 | "main": "./main.js" 5 | } 6 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-serialize-error/index.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | activate: -> 3 | 4 | deactivate: -> 5 | 6 | serialize: -> 7 | throw new Error("I'm no good at this.") 8 | -------------------------------------------------------------------------------- /src/subscriber-mixin.coffee: -------------------------------------------------------------------------------- 1 | {Subscriber} = require 'emissary' 2 | SubscriberMixin = componentDidUnmount: -> @unsubscribe() 3 | Subscriber.extend(SubscriberMixin) 4 | module.exports = SubscriberMixin 5 | -------------------------------------------------------------------------------- /spec/fixtures/git/ignore.git/objects/65/a457425a679cbe9adf0d2741785d3ceabb44a7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/ignore.git/objects/65/a457425a679cbe9adf0d2741785d3ceabb44a7 -------------------------------------------------------------------------------- /spec/fixtures/git/ignore.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/ignore.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 -------------------------------------------------------------------------------- /spec/fixtures/git/ignore.git/objects/ef/046e9eecaa5255ea5e9817132d4001724d6ae1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/ignore.git/objects/ef/046e9eecaa5255ea5e9817132d4001724d6ae1 -------------------------------------------------------------------------------- /spec/fixtures/git/master.git/objects/65/a457425a679cbe9adf0d2741785d3ceabb44a7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/master.git/objects/65/a457425a679cbe9adf0d2741785d3ceabb44a7 -------------------------------------------------------------------------------- /spec/fixtures/git/master.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/master.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 -------------------------------------------------------------------------------- /spec/fixtures/git/master.git/objects/ef/046e9eecaa5255ea5e9817132d4001724d6ae1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/master.git/objects/ef/046e9eecaa5255ea5e9817132d4001724d6ae1 -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-injection-selector/grammars/grammar.cson: -------------------------------------------------------------------------------- 1 | 'name': 'test' 2 | 'scopeName': 'source.test' 3 | 'injectionSelector': 'comment' 4 | 'patterns': [{'include': 'source.sql'}] 5 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-with-package-file/styles/second.less: -------------------------------------------------------------------------------- 1 | @number: 102px; 2 | 3 | atom-text-editor { 4 | /* padding-top: 102px;*/ 5 | padding-right: @number; 6 | padding-bottom: @number; 7 | } -------------------------------------------------------------------------------- /script/utils/clean-open-with-menu: -------------------------------------------------------------------------------- 1 | /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user 2 | killall Finder 3 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-menus/menus/menu-2.cson: -------------------------------------------------------------------------------- 1 | 'menu': [ 2 | { 'label': 'Last' } 3 | ] 4 | 5 | 'context-menu': 6 | '.test-1': [ 7 | {label: 'Menu item 2', command: 'command-2'} 8 | ] 9 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to the Atom Docs 2 | 3 | ![Atom](https://cloud.githubusercontent.com/assets/72919/2874231/3af1db48-d3dd-11e3-98dc-6066f8bc766f.png) 4 | 5 | TODO: Write when docs move to a dedicated repo. 6 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-menus/menus/menu-1.cson: -------------------------------------------------------------------------------- 1 | 'menu': [ 2 | {'label': 'Second to Last'} 3 | ] 4 | 5 | 'context-menu': 6 | '.test-1': [ 7 | {label: 'Menu item 1', command: 'command-1'} 8 | ] 9 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-menus-manifest/menus/menu-1.cson: -------------------------------------------------------------------------------- 1 | 'menu': [ 2 | { 'label': 'Last' } 3 | ] 4 | 5 | 'context-menu': 6 | '.test-1': [ 7 | {label: 'Menu item 1', command: 'command-1'} 8 | ] 9 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-menus/menus/menu-3.cson: -------------------------------------------------------------------------------- 1 | 'menu': [ 2 | { 'label': 'Second to Last' } 3 | ] 4 | 5 | 'context-menu': 6 | '.test-1': [ 7 | {label: 'Menu item 3', command: 'command-3'} 8 | ] 9 | -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/git.git/objects/06/15f9a45968b3515e0a202530ef9f61aba26b6c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/working-dir/git.git/objects/06/15f9a45968b3515e0a202530ef9f61aba26b6c -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/git.git/objects/16/735fb793d7b038818219c4b8c6295346e20eef: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/working-dir/git.git/objects/16/735fb793d7b038818219c4b8c6295346e20eef -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/git.git/objects/52/f56457b6fca045ce41bb9d32e6ca79d23192af: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/working-dir/git.git/objects/52/f56457b6fca045ce41bb9d32e6ca79d23192af -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/git.git/objects/5b/24ab4c3baadf534242b1acc220c8fa051b9b20: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/working-dir/git.git/objects/5b/24ab4c3baadf534242b1acc220c8fa051b9b20 -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/git.git/objects/65/a457425a679cbe9adf0d2741785d3ceabb44a7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/working-dir/git.git/objects/65/a457425a679cbe9adf0d2741785d3ceabb44a7 -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/git.git/objects/66/dc9051da651c15d98d017a88658263cab28f02: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/working-dir/git.git/objects/66/dc9051da651c15d98d017a88658263cab28f02 -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/git.git/objects/8a/9c86f1cb1f14b8f436eb91f4b052c8802ca99e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/working-dir/git.git/objects/8a/9c86f1cb1f14b8f436eb91f4b052c8802ca99e -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/git.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/working-dir/git.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/git.git/objects/ec/5e386905ff2d36e291086a1207f2585aaa8920: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/working-dir/git.git/objects/ec/5e386905ff2d36e291086a1207f2585aaa8920 -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/git.git/objects/ef/046e9eecaa5255ea5e9817132d4001724d6ae1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/working-dir/git.git/objects/ef/046e9eecaa5255ea5e9817132d4001724d6ae1 -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/git.git/objects/fe/bde178cdf35e9df6279d87aa27590c6d92e354: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/working-dir/git.git/objects/fe/bde178cdf35e9df6279d87aa27590c6d92e354 -------------------------------------------------------------------------------- /spec/fixtures/git/working-dir/git.git/objects/ff/c8218bd2240a0cb92f6f02548d45784428349b: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasimir/atom/master/spec/fixtures/git/working-dir/git.git/objects/ff/c8218bd2240a0cb92f6f02548d45784428349b -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-menus-manifest/menus/menu-2.cson: -------------------------------------------------------------------------------- 1 | 'menu': [ 2 | { 'label': 'Second to Last' } 3 | ] 4 | 5 | 'context-menu': 6 | '.test-1': [ 7 | {label: 'Menu item 2', command: 'command-2'} 8 | ] 9 | -------------------------------------------------------------------------------- /static/links.less: -------------------------------------------------------------------------------- 1 | @import "ui-variables"; 2 | 3 | a { 4 | cursor: pointer; 5 | color: @text-color-highlight; 6 | &:hover { 7 | color: @text-color-highlight; 8 | text-decoration: underline; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-with-incomplete-ui-variables/styles/ui-variables.less: -------------------------------------------------------------------------------- 1 | // This does not contain all of the ui-variables available. 2 | @app-background-color: #00f; // Changed 3 | @input-background-color: #f00; // Changed 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *~ 3 | .DS_Store 4 | Thumbs.db 5 | .project 6 | .svn 7 | .nvm-version 8 | node_modules 9 | npm-debug.log 10 | debug.log 11 | /tags 12 | /atom-shell/ 13 | docs/output 14 | docs/includes 15 | spec/fixtures/evil-files/ 16 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-consumed-services/index.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | activate: -> 3 | 4 | deactivate: -> 5 | 6 | consumeFirstServiceV3: -> 7 | 8 | consumeFirstServiceV4: -> 9 | 10 | consumeSecondService: -> 11 | -------------------------------------------------------------------------------- /spec/fixtures/sample-with-tabs-and-initial-comment.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Look, this is a comment. Don't go making assumtions that I want soft tabs 3 | * because this block comment has leading spaces, Geez. 4 | */ 5 | 6 | if (beNice) { 7 | console.log('Thank you for being nice.'); 8 | } 9 | -------------------------------------------------------------------------------- /static/icons.less: -------------------------------------------------------------------------------- 1 | @import "ui-variables"; 2 | 3 | .icon:before { 4 | margin-right: @component-icon-padding; 5 | } 6 | 7 | a.icon, 8 | button.icon { 9 | text-decoration: none; 10 | color: @text-color; 11 | &:hover{ 12 | color: @text-color-highlight; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /apm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "atom-bundled-apm", 3 | "description": "Atom's bundled apm", 4 | "repository": { 5 | "type": "git", 6 | "url": "https://github.com/atom/atom.git" 7 | }, 8 | "dependencies": { 9 | "atom-package-manager": "0.135.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /static/markdown.less: -------------------------------------------------------------------------------- 1 | .source.gfm { 2 | .markup.heading { 3 | font-weight: bold; 4 | } 5 | 6 | .bold { 7 | font-weight: bold; 8 | } 9 | 10 | .italic { 11 | font-style: italic; 12 | } 13 | 14 | .comment.quote { 15 | font-style: italic; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-with-ui-variables/styles/editor.less: -------------------------------------------------------------------------------- 1 | @import "ui-variables"; 2 | 3 | atom-text-editor { 4 | padding-top: @component-padding; 5 | padding-right: @component-padding; 6 | padding-bottom: @component-padding; 7 | 8 | color: @input-background-color; 9 | } 10 | -------------------------------------------------------------------------------- /static/linux.less: -------------------------------------------------------------------------------- 1 | ::-webkit-scrollbar-corner { 2 | background-color: transparent; 3 | } 4 | 5 | ::-webkit-scrollbar { 6 | width: 8px; 7 | height: 8px; 8 | } 9 | 10 | ::-webkit-scrollbar-thumb { 11 | -webkit-border-radius: 2px; 12 | background: rgba(150, 150, 150, .33); 13 | } 14 | -------------------------------------------------------------------------------- /static/popover-list.less: -------------------------------------------------------------------------------- 1 | .select-list.popover-list { 2 | width: 200px; 3 | min-width: 200px; 4 | margin-left: 0; 5 | position: relative; 6 | } 7 | 8 | .select-list.popover-list ol.list-group { 9 | position: relative; 10 | overflow-y: scroll; 11 | max-height: 200px; 12 | } 13 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-grammars/grammars/alot.cson: -------------------------------------------------------------------------------- 1 | 'fileTypes': ['alot', 'foobizbang'] 2 | 'name': 'Alot' 3 | 'scopeName': 'source.alot' 4 | 5 | 'patterns': [ 6 | { 7 | 'captures': 8 | '0': 9 | 'name': 'keyword.alot' 10 | 'match': 'alot' 11 | } 12 | ] 13 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-grammars/grammars/alittle.cson: -------------------------------------------------------------------------------- 1 | 'fileTypes': ['alittle'] 2 | 'name': 'Alittle' 3 | 'scopeName': 'source.alittle' 4 | 5 | 'patterns': [ 6 | { 7 | 'captures': 8 | '0': 9 | 'name': 'keyword.alittle' 10 | 'match': 'alittle' 11 | } 12 | ] 13 | -------------------------------------------------------------------------------- /resources/linux/atom.desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Atom 3 | Comment=<%= description %> 4 | GenericName=Text Editor 5 | Exec=<%= executable %> %U 6 | Icon=<%= iconName %> 7 | Type=Application 8 | StartupNotify=true 9 | Categories=GNOME;GTK;Utility;TextEditor;Development; 10 | MimeType=text/plain; 11 | -------------------------------------------------------------------------------- /keymaps/emacs.cson: -------------------------------------------------------------------------------- 1 | 'atom-text-editor': 2 | 'alt-f': 'editor:move-to-end-of-word' 3 | 'alt-F': 'editor:select-to-end-of-word' 4 | 'alt-b': 'editor:move-to-beginning-of-word' 5 | 'alt-B': 'editor:select-to-beginning-of-word' 6 | 'alt-h': 'editor:delete-to-beginning-of-word' 7 | 'alt-d': 'editor:delete-to-end-of-word' 8 | -------------------------------------------------------------------------------- /script/cibuild-atom-rpm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | docker build -t atom-rpm . 6 | docker run \ 7 | --rm \ 8 | --env JANKY_SHA1="$JANKY_SHA1" \ 9 | --env JANKY_BRANCH="$JANKY_BRANCH" \ 10 | --env ATOM_ACCESS_TOKEN="$BUILD_ATOM_RPM_ACCESS_TOKEN" \ 11 | atom-rpm /atom/script/rpmbuild 12 | docker rmi atom-rpm 13 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-provided-services/index.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | activate: -> 3 | 4 | deactivate: -> 5 | 6 | provideFirstServiceV3: -> 7 | 'first-service-v3' 8 | 9 | provideFirstServiceV4: -> 10 | 'first-service-v4' 11 | 12 | provideSecondService: -> 13 | 'second-service' 14 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-config-schema/index.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | config: 3 | numbers: 4 | type: 'object' 5 | properties: 6 | one: 7 | type: 'integer' 8 | default: 1 9 | two: 10 | type: 'integer' 11 | default: 2 12 | 13 | activate: -> # no-op 14 | -------------------------------------------------------------------------------- /script/copy-folder.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set USAGE=Usage: %0 source destination 4 | 5 | if [%1] == [] ( 6 | echo %USAGE% 7 | exit 1 8 | ) 9 | if [%2] == [] ( 10 | echo %USAGE% 11 | exit 2 12 | ) 13 | 14 | :: rm -rf %2 15 | if exist %2 rmdir %2 /s /q 16 | 17 | :: cp -rf %1 %2 18 | (robocopy %1 %2 /e) ^& IF %ERRORLEVEL% LEQ 1 exit 0 19 | -------------------------------------------------------------------------------- /static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /coffeelint.json: -------------------------------------------------------------------------------- 1 | { 2 | "max_line_length": { 3 | "level": "ignore" 4 | }, 5 | "no_empty_param_list": { 6 | "level": "error" 7 | }, 8 | "arrow_spacing": { 9 | "level": "error" 10 | }, 11 | "no_interpolation_in_single_quotes": { 12 | "level": "error" 13 | }, 14 | "no_debugger": { 15 | "level": "error" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /resources/linux/debian/lintian-overrides: -------------------------------------------------------------------------------- 1 | atom: arch-dependent-file-in-usr-share 2 | atom: changelog-file-missing-in-native-package 3 | atom: copyright-file-contains-full-apache-2-license 4 | atom: copyright-should-refer-to-common-license-file-for-apache-2 5 | atom: embedded-library 6 | atom: package-installs-python-bytecode 7 | atom: unstripped-binary-or-object 8 | -------------------------------------------------------------------------------- /script/utils/fix-author: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | usage() { 4 | echo "usage: $0 sha name email" 5 | exit 1 6 | } 7 | 8 | if [ ! $3 ]; then 9 | usage 10 | fi 11 | 12 | git filter-branch -f --env-filter " 13 | export GIT_AUTHOR_NAME='$2' 14 | export GIT_AUTHOR_EMAIL='$3' 15 | export GIT_COMMITTER_NAME='$2' 16 | export GIT_COMMITTER_EMAIL='$3' 17 | " -- $1..HEAD -------------------------------------------------------------------------------- /script/cibuild-atom-linux: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | export ATOM_ACCESS_TOKEN=$BUILD_ATOM_LINUX_ACCESS_TOKEN 6 | 7 | if [ -d /usr/local/share/nodenv ]; then 8 | export NODENV_ROOT=/usr/local/share/nodenv 9 | export PATH=/usr/local/share/nodenv/bin:/usr/local/share/nodenv/shims:$PATH 10 | export NODENV_VERSION="v0.10.21" 11 | fi 12 | 13 | script/cibuild 14 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-with-incomplete-ui-variables/styles/editor.less: -------------------------------------------------------------------------------- 1 | @import "ui-variables"; 2 | 3 | atom-text-editor { 4 | padding-top: @component-padding; 5 | padding-right: @component-padding; 6 | padding-bottom: @component-padding; 7 | 8 | color: @input-background-color; 9 | background-color: @background-color-info; // From the fallback variables, not overridden 10 | } 11 | -------------------------------------------------------------------------------- /resources/win/atom.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var spawn = require('child_process').spawn; 3 | 4 | var atomCommandPath = path.resolve(__dirname, '..', '..', 'atom.exe'); 5 | var arguments = process.argv.slice(2); 6 | arguments.unshift('--executed-from', process.cwd()); 7 | var options = {detached: true, stdio: 'ignore'}; 8 | spawn(atomCommandPath, arguments, options); 9 | process.exit(0); 10 | -------------------------------------------------------------------------------- /src/item-registry.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | class ItemRegistry 3 | constructor: -> 4 | @items = new WeakSet 5 | 6 | addItem: (item) -> 7 | if @hasItem(item) 8 | throw new Error("The workspace can only contain one instance of item #{item}") 9 | @items.add(item) 10 | 11 | removeItem: (item) -> 12 | @items.delete(item) 13 | 14 | hasItem: (item) -> 15 | @items.has(item) 16 | -------------------------------------------------------------------------------- /script/test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var safeExec = require('./utils/child-process-wrapper.js').safeExec; 3 | var path = require('path'); 4 | 5 | process.chdir(path.dirname(__dirname)); 6 | 7 | safeExec('node script/bootstrap', function() { 8 | var gruntPath = path.join('node_modules', '.bin', 'grunt') + (process.platform === 'win32' ? '.cmd' : ''); 9 | safeExec(gruntPath + ' ci --stack --no-color', process.exit); 10 | }); 11 | -------------------------------------------------------------------------------- /benchmark/benchmark-bootstrap.coffee: -------------------------------------------------------------------------------- 1 | require '../src/window' 2 | Atom = require '../src/atom' 3 | window.atom = Atom.loadOrCreate('spec') 4 | atom.show() unless atom.getLoadSettings().exitWhenDone 5 | window.atom = atom 6 | 7 | {runSpecSuite} = require '../spec/jasmine-helper' 8 | 9 | atom.openDevTools() 10 | 11 | document.title = "Benchmark Suite" 12 | runSpecSuite('../benchmark/benchmark-suite', atom.getLoadSettings().logFile) 13 | -------------------------------------------------------------------------------- /dot-atom/init.coffee: -------------------------------------------------------------------------------- 1 | # Your init script 2 | # 3 | # Atom will evaluate this file each time a new window is opened. It is run 4 | # after packages are loaded/activated and after the previous editor state 5 | # has been restored. 6 | # 7 | # An example hack to log to the console when each text editor is saved. 8 | # 9 | # atom.workspace.observeTextEditors (editor) -> 10 | # editor.onDidSave -> 11 | # console.log "Saved! #{editor.getPath()}" 12 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-consumed-services/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "package-with-consumed-services", 3 | 4 | "consumedServices": { 5 | "service-1": { 6 | "versions": { 7 | ">=0.2 <=0.3.6": "consumeFirstServiceV3", 8 | "^0.4.1": "consumeFirstServiceV4" 9 | } 10 | }, 11 | "service-2": { 12 | "versions": { 13 | "0.2.1 || 0.2.2": "consumeSecondService" 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /static/bootstrap-overrides.less: -------------------------------------------------------------------------------- 1 | @import "ui-variables"; 2 | 3 | .nav { 4 | > li > a { 5 | border-radius: @component-border-radius; 6 | } 7 | > li > a:hover { 8 | background-color: @background-color-highlight; 9 | } 10 | 11 | &.nav-pills > li.active > a { 12 | background-color: @background-color-selected; 13 | } 14 | } 15 | 16 | h1, 17 | h2, 18 | h3, 19 | h4, 20 | h5, 21 | h6 { 22 | font-family: inherit; // inherit from themes 23 | } 24 | -------------------------------------------------------------------------------- /spec/fixtures/sample.js: -------------------------------------------------------------------------------- 1 | var quicksort = function () { 2 | var sort = function(items) { 3 | if (items.length <= 1) return items; 4 | var pivot = items.shift(), current, left = [], right = []; 5 | while(items.length > 0) { 6 | current = items.shift(); 7 | current < pivot ? left.push(current) : right.push(current); 8 | } 9 | return sort(left).concat(pivot).concat(sort(right)); 10 | }; 11 | 12 | return sort(Array.apply(this, arguments)); 13 | }; -------------------------------------------------------------------------------- /.pairs: -------------------------------------------------------------------------------- 1 | pairs: 2 | ns: Nathan Sobo; nathan 3 | cj: Corey Johnson; cj 4 | dg: David Graham; dgraham 5 | ks: Kevin Sawicki; kevin 6 | jc: Jerry Cheung; jerry 7 | bl: Brian Lopez; brian 8 | jp: Justin Palmer; justin 9 | gt: Garen Torikian; garen 10 | mc: Matt Colyer; mcolyer 11 | bo: Ben Ogle; benogle 12 | jr: Jason Rudolph; jasonrudolph 13 | jl: Jessica Lord; jlord 14 | dh: Daniel Hengeveld; danielh 15 | email: 16 | domain: github.com 17 | #global: true 18 | -------------------------------------------------------------------------------- /resources/win/atom.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | while getopts ":fhtvw-:" opt; do 4 | case "$opt" in 5 | -) 6 | case "${OPTARG}" in 7 | foreground|help|test|version|wait) 8 | EXPECT_OUTPUT=1 9 | ;; 10 | esac 11 | ;; 12 | f|h|t|v|w) 13 | EXPECT_OUTPUT=1 14 | ;; 15 | esac 16 | done 17 | 18 | if [ $EXPECT_OUTPUT ]; then 19 | "$0/../../../atom.exe" "$@" 20 | else 21 | "$0/../../app/apm/bin/node.exe" "$0/../atom.js" "$@" 22 | fi 23 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # VERSION: 0.1 2 | # DESCRIPTION: Image to build Atom and create a .rpm file 3 | 4 | # Base docker image 5 | FROM fedora:20 6 | 7 | # Install dependencies 8 | RUN yum install -y \ 9 | make \ 10 | gcc \ 11 | gcc-c++ \ 12 | glibc-devel \ 13 | git-core \ 14 | libgnome-keyring-devel \ 15 | rpmdevtools 16 | 17 | # Install node 18 | RUN curl -sL https://rpm.nodesource.com/setup | bash - 19 | RUN yum install -y nodejs 20 | 21 | ADD . /atom 22 | WORKDIR /atom 23 | -------------------------------------------------------------------------------- /src/window-bootstrap.coffee: -------------------------------------------------------------------------------- 1 | # Like sands through the hourglass, so are the days of our lives. 2 | require './window' 3 | 4 | Atom = require './atom' 5 | window.atom = Atom.loadOrCreate('editor') 6 | atom.initialize() 7 | atom.startEditorWindow() 8 | 9 | # Workaround for focus getting cleared upon window creation 10 | windowFocused = -> 11 | window.removeEventListener('focus', windowFocused) 12 | setTimeout (-> document.querySelector('atom-workspace').focus()), 0 13 | window.addEventListener('focus', windowFocused) 14 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-provided-services/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "package-with-provided-services", 3 | 4 | "providedServices": { 5 | "service-1": { 6 | "description": "The first service", 7 | "versions": { 8 | "0.3.1": "provideFirstServiceV3", 9 | "0.4.1": "provideFirstServiceV4" 10 | } 11 | }, 12 | "service-2": { 13 | "description": "The second service", 14 | "versions": { 15 | "0.2.1": "provideSecondService" 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /spec/fixtures/coffee.coffee: -------------------------------------------------------------------------------- 1 | class quicksort 2 | sort: (items) -> 3 | return items if items.length <= 1 4 | 5 | pivot = items.shift() 6 | left = [] 7 | right = [] 8 | 9 | # Comment in the middle 10 | 11 | while items.length > 0 12 | current = items.shift() 13 | if current < pivot 14 | left.push(current) 15 | else 16 | right.push(current); 17 | 18 | sort(left).concat(pivot).concat(sort(right)) 19 | 20 | noop: -> 21 | # just a noop 22 | 23 | exports.modules = quicksort 24 | -------------------------------------------------------------------------------- /spec/fixtures/packages/package-with-activation-commands/index.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | activateCallCount: 0 3 | activationCommandCallCount: 0 4 | legacyActivationCommandCallCount: 0 5 | 6 | activate: -> 7 | @activateCallCount++ 8 | 9 | atom.commands.add 'atom-workspace', 'activation-command', => 10 | @activationCommandCallCount++ 11 | 12 | editorView = atom.views.getView(atom.workspace.getActiveTextEditor())?.__spacePenView 13 | editorView?.command 'activation-command', => 14 | @legacyActivationCommandCallCount++ 15 | -------------------------------------------------------------------------------- /script/mkrpm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | SPEC_FILE="$1" 6 | DESKTOP_FILE="$2" 7 | BUILD_DIRECTORY="$3" 8 | 9 | RPM_BUILD_ROOT=~/rpmbuild 10 | ARCH=`uname -m` 11 | 12 | rpmdev-setuptree 13 | 14 | cp -r $BUILD_DIRECTORY/Atom $RPM_BUILD_ROOT/BUILD 15 | cp -r $BUILD_DIRECTORY/icons $RPM_BUILD_ROOT/BUILD 16 | cp $SPEC_FILE $RPM_BUILD_ROOT/SPECS 17 | cp ./atom.sh $RPM_BUILD_ROOT/BUILD 18 | cp $DESKTOP_FILE $RPM_BUILD_ROOT/BUILD 19 | 20 | rpmbuild -ba $SPEC_FILE 21 | cp $RPM_BUILD_ROOT/RPMS/$ARCH/atom-*.rpm $BUILD_DIRECTORY/rpm 22 | 23 | rm -rf $RPM_BUILD_ROOT 24 | -------------------------------------------------------------------------------- /src/replace-handler.coffee: -------------------------------------------------------------------------------- 1 | {PathReplacer} = require 'scandal' 2 | 3 | module.exports = (filePaths, regexSource, regexFlags, replacementText) -> 4 | callback = @async() 5 | 6 | replacer = new PathReplacer() 7 | regex = new RegExp(regexSource, regexFlags) 8 | 9 | replacer.on 'file-error', ({code, path, message}) -> 10 | emit('replace:file-error', {code, path, message}) 11 | 12 | replacer.on 'path-replaced', (result) -> 13 | emit('replace:path-replaced', result) 14 | 15 | replacer.replacePaths(regex, replacementText, filePaths, -> callback()) 16 | -------------------------------------------------------------------------------- /resources/linux/debian/control.in: -------------------------------------------------------------------------------- 1 | Package: <%= name %> 2 | Version: <%= version %> 3 | Depends: git, gconf2, gconf-service, libgtk2.0-0, libudev0 | libudev1, libgcrypt11, libnotify4, libxtst6, libnss3, python, gvfs-bin, xdg-utils 4 | Suggests: libgnome-keyring0, gir1.2-gnomekeyring-1.0 5 | Section: <%= section %> 6 | Priority: optional 7 | Architecture: <%= arch %> 8 | Installed-Size: <%= installedSize %> 9 | Maintainer: <%= maintainer %> 10 | Description: <%= description %> 11 | Atom is a free and open source text editor that is modern, approachable, and hackable to the core. 12 | -------------------------------------------------------------------------------- /script/build: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var cp = require('./utils/child-process-wrapper.js'); 3 | var path = require('path'); 4 | 5 | process.chdir(path.dirname(__dirname)); 6 | 7 | cp.safeExec('node script/bootstrap', function() { 8 | // build/node_modules/.bin/grunt "$@" 9 | var gruntPath = path.join('build', 'node_modules', '.bin', 'grunt') + (process.platform === 'win32' ? '.cmd' : ''); 10 | var args = ['--gruntfile', path.resolve('build', 'Gruntfile.coffee')]; 11 | args = args.concat(process.argv.slice(2)); 12 | cp.safeSpawn(gruntPath, args, process.exit); 13 | }); 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Specs depend on character counts, if we don't specify the line endings the 2 | # fixtures will vary depending on platform 3 | spec/fixtures/**/*.js text eol=lf 4 | spec/fixtures/**/*.coffee text eol=lf 5 | spec/fixtures/**/*.less text eol=lf 6 | spec/fixtures/**/*.css text eol=lf 7 | spec/fixtures/**/*.txt text eol=lf 8 | spec/fixtures/dir/**/* text eol=lf 9 | 10 | # Git 1.7 does not support **/* patterns 11 | spec/fixtures/css.css text eol=lf 12 | spec/fixtures/sample.js text eol=lf 13 | spec/fixtures/sample.less text eol=lf 14 | spec/fixtures/sample.txt text eol=lf 15 | -------------------------------------------------------------------------------- /src/custom-event-mixin.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | CustomEventMixin = 3 | componentWillMount: -> 4 | @customEventListeners = {} 5 | 6 | componentWillUnmount: -> 7 | for name, listeners in @customEventListeners 8 | for listener in listeners 9 | @getDOMNode().removeEventListener(name, listener) 10 | 11 | addCustomEventListeners: (customEventListeners) -> 12 | for name, listener of customEventListeners 13 | @customEventListeners[name] ?= [] 14 | @customEventListeners[name].push(listener) 15 | @getDOMNode().addEventListener(name, listener) 16 | -------------------------------------------------------------------------------- /spec/atom-protocol-handler-spec.coffee: -------------------------------------------------------------------------------- 1 | {$} = require '../src/space-pen-extensions' 2 | 3 | describe '"atom" protocol URL', -> 4 | it 'sends the file relative in the package as response', -> 5 | called = false 6 | callback = -> called = true 7 | $.ajax 8 | url: 'atom://async/package.json' 9 | success: callback 10 | # In old versions of jQuery, ajax calls to custom protocol would always 11 | # be treated as error eventhough the browser thinks it's a success 12 | # request. 13 | error: callback 14 | 15 | waitsFor 'request to be done', -> called is true 16 | -------------------------------------------------------------------------------- /dot-atom/styles.less: -------------------------------------------------------------------------------- 1 | /* 2 | * Your Stylesheet 3 | * 4 | * This stylesheet is loaded when Atom starts up and is reloaded automatically 5 | * when it is changed. 6 | * 7 | * If you are unfamiliar with LESS, you can read more about it here: 8 | * http://www.lesscss.org 9 | */ 10 | 11 | .tree-view { 12 | 13 | } 14 | 15 | // style the background and foreground colors on the atom-text-editor-element 16 | // itself 17 | atom-text-editor { 18 | 19 | } 20 | 21 | // To style other content in the text editor's shadow DOM, use the ::shadow 22 | // expression 23 | atom-text-editor::shadow .cursor { 24 | 25 | } 26 | -------------------------------------------------------------------------------- /script/create-shortcut.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set USAGE=Usage: %0 source name-on-desktop 4 | 5 | if [%1] == [] ( 6 | echo %USAGE% 7 | exit 1 8 | ) 9 | if [%2] == [] ( 10 | echo %USAGE% 11 | exit 2 12 | ) 13 | 14 | set SCRIPT="%TEMP%\%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%.vbs" 15 | 16 | echo Set oWS = WScript.CreateObject("WScript.Shell") >> %SCRIPT% 17 | echo sLinkFile = "%USERPROFILE%\Desktop\%2.lnk" >> %SCRIPT% 18 | echo Set oLink = oWS.CreateShortcut(sLinkFile) >> %SCRIPT% 19 | echo oLink.TargetPath = %1 >> %SCRIPT% 20 | echo oLink.Save >> %SCRIPT% 21 | 22 | cscript /nologo %SCRIPT% 23 | del %SCRIPT% 24 | -------------------------------------------------------------------------------- /docs/build-instructions/freebsd.md: -------------------------------------------------------------------------------- 1 | # FreeBSD 2 | 3 | FreeBSD -RELEASE 64-bit is the recommended platform. 4 | 5 | ## Requirements 6 | 7 | * FreeBSD 8 | * `pkg install node` 9 | * `pkg install npm` 10 | * `pkg install libgnome-keyring` 11 | * `npm config set python /usr/local/bin/python2 -g` to ensure that gyp uses Python 2 12 | 13 | ## Instructions 14 | 15 | ```sh 16 | git clone https://github.com/atom/atom 17 | cd atom 18 | script/build # Creates application at $TMPDIR/atom-build/Atom 19 | sudo script/grunt install # Installs command to /usr/local/bin/atom 20 | ``` 21 | 22 | ## Troubleshooting 23 | -------------------------------------------------------------------------------- /script/set-version: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | BUILT_PRODUCTS_DIR=$1 6 | VERSION=$2 7 | PLIST_PATH="$BUILT_PRODUCTS_DIR/Atom.app/Contents/Info.plist" 8 | HELPER_PLIST_PATH="$BUILT_PRODUCTS_DIR/Atom.app/Contents/Frameworks/Atom Helper.app/Contents/Info.plist" 9 | 10 | # Update version 11 | /usr/libexec/PlistBuddy -c "Set CFBundleShortVersionString $VERSION" "$PLIST_PATH" 12 | /usr/libexec/PlistBuddy -c "Set CFBundleVersion $VERSION" "$PLIST_PATH" 13 | /usr/libexec/PlistBuddy -c "Set CFBundleShortVersionString $VERSION" "$HELPER_PLIST_PATH" 14 | /usr/libexec/PlistBuddy -c "Set CFBundleVersion $VERSION" "$HELPER_PLIST_PATH" 15 | -------------------------------------------------------------------------------- /dot-atom/snippets.cson: -------------------------------------------------------------------------------- 1 | # Your snippets 2 | # 3 | # Atom snippets allow you to enter a simple prefix in the editor and hit tab to 4 | # expand the prefix into a larger code block with templated values. 5 | # 6 | # You can create a new snippet in this file by typing "snip" and then hitting 7 | # tab. 8 | # 9 | # An example CoffeeScript snippet to expand log to console.log: 10 | # 11 | # '.source.coffee': 12 | # 'Console log': 13 | # 'prefix': 'log' 14 | # 'body': 'console.log $1' 15 | # 16 | # This file uses CoffeeScript Object Notation (CSON). 17 | # If you are unfamiliar with CSON, you can read more about it here: 18 | # https://github.com/bevry/cson#what-is-cson 19 | -------------------------------------------------------------------------------- /spec/fixtures/sample-with-comments.js: -------------------------------------------------------------------------------- 1 | var quicksort = function () { 2 | /* 3 | this is a multiline comment 4 | it is, I promise 5 | */ 6 | var sort = function(items) { 7 | // This is a collection of 8 | // single line comments. 9 | // Wowza 10 | if (items.length <= 1) return items; 11 | var pivot = items.shift(), current, left = [], right = []; 12 | while(items.length > 0) { 13 | current = items.shift(); 14 | current < pivot ? left.push(current) : right.push(current); 15 | } 16 | return sort(left).concat(pivot).concat(sort(right)); 17 | }; 18 | // this is a single-line comment 19 | return sort(Array.apply(this, arguments)); 20 | }; -------------------------------------------------------------------------------- /src/cursor-component.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react-atom-fork' 2 | {div} = require 'reactionary-atom-fork' 3 | {isEqualForProperties} = require 'underscore-plus' 4 | 5 | module.exports = 6 | CursorComponent = React.createClass 7 | displayName: 'CursorComponent' 8 | 9 | render: -> 10 | {pixelRect, defaultCharWidth} = @props 11 | {top, left, height, width} = pixelRect 12 | width = defaultCharWidth if width is 0 13 | WebkitTransform = "translate(#{left}px, #{top}px)" 14 | 15 | div className: 'cursor', style: {height, width, WebkitTransform} 16 | 17 | shouldComponentUpdate: (newProps) -> 18 | not isEqualForProperties(newProps, @props, 'pixelRect', 'defaultCharWidth') 19 | -------------------------------------------------------------------------------- /docs/build-instructions/os-x.md: -------------------------------------------------------------------------------- 1 | # OS X 2 | 3 | ## Requirements 4 | 5 | * OS X 10.8 or later 6 | * [node.js](http://nodejs.org/download/) v0.10.x 7 | * Command Line Tools for [Xcode](https://developer.apple.com/xcode/downloads/) (run `xcode-select --install` to install) 8 | 9 | ## Instructions 10 | 11 | ```sh 12 | git clone https://github.com/atom/atom.git 13 | cd atom 14 | script/build # Creates application at /Applications/Atom.app 15 | ``` 16 | 17 | ## Troubleshooting 18 | 19 | ### OSX build error reports in atom/atom 20 | * Use [this search](https://github.com/atom/atom/search?q=label%3Abuild-error+label%3Aos-x&type=Issues) to get a list of reports about build errors on OSX. 21 | -------------------------------------------------------------------------------- /spec/clipboard-spec.coffee: -------------------------------------------------------------------------------- 1 | describe "Clipboard", -> 2 | describe "write(text, metadata) and read()", -> 3 | it "writes and reads text to/from the native clipboard", -> 4 | expect(atom.clipboard.read()).toBe 'initial clipboard content' 5 | atom.clipboard.write('next') 6 | expect(atom.clipboard.read()).toBe 'next' 7 | 8 | it "returns metadata if the item on the native clipboard matches the last written item", -> 9 | atom.clipboard.write('next', {meta: 'data'}) 10 | expect(atom.clipboard.read()).toBe 'next' 11 | expect(atom.clipboard.readWithMetadata().text).toBe 'next' 12 | expect(atom.clipboard.readWithMetadata().metadata).toEqual {meta: 'data'} 13 | -------------------------------------------------------------------------------- /script/grunt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var cp = require('./utils/child-process-wrapper.js'); 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | // node build/node_modules/.bin/grunt "$@" 7 | var gruntPath = path.resolve(__dirname, '..', 'build', 'node_modules', '.bin', 'grunt') + (process.platform === 'win32' ? '.cmd' : ''); 8 | 9 | if (!fs.existsSync(gruntPath)) { 10 | console.error('Grunt command does not exist at: ' + gruntPath); 11 | console.error('Run script/bootstrap to install Grunt'); 12 | process.exit(1); 13 | } 14 | 15 | var args = ['--gruntfile', path.resolve('build', 'Gruntfile.coffee')]; 16 | args = args.concat(process.argv.slice(2)); 17 | cp.safeSpawn(gruntPath, args, process.exit); 18 | -------------------------------------------------------------------------------- /static/messages.less: -------------------------------------------------------------------------------- 1 | @import "ui-variables"; 2 | 3 | .info-messages, 4 | .error-messages { 5 | margin: 0; 6 | padding: 0; 7 | list-style: none; 8 | } 9 | 10 | .error-messages { 11 | color: @text-color-error; 12 | } 13 | 14 | ul.background-message { 15 | font-size: @font-size * 3; 16 | 17 | margin: 0; 18 | padding: 0; 19 | 20 | li { 21 | margin: 0; 22 | padding: 0; 23 | list-style: none; 24 | } 25 | 26 | &.centered { 27 | display: -webkit-flex; 28 | position: absolute; 29 | top: 0; 30 | left: 0; 31 | right: 0; 32 | bottom: 0; 33 | 34 | -webkit-align-items: center; 35 | text-align: center; 36 | 37 | li { 38 | width: 100%; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /static/workspace-view.less: -------------------------------------------------------------------------------- 1 | @import "ui-variables"; 2 | @import "octicon-mixins"; 3 | 4 | @font-face { .octicon-font(); } 5 | 6 | html, 7 | body { 8 | width: 100%; 9 | height: 100%; 10 | overflow: hidden; 11 | font-family: @font-family; 12 | font-size: @font-size; 13 | } 14 | 15 | atom-workspace { 16 | display: block; 17 | height: 100%; 18 | overflow: hidden; 19 | position: relative; 20 | background-color: @app-background-color; 21 | font-family: @font-family; 22 | 23 | atom-workspace-axis.horizontal { 24 | display: -webkit-flex; 25 | height: 100%; 26 | } 27 | 28 | atom-workspace-axis.vertical { 29 | display: -webkit-flex; 30 | -webkit-flex: 1; 31 | -webkit-flex-flow: column; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /resources/win/atom.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | SET EXPECT_OUTPUT= 4 | 5 | FOR %%a IN (%*) DO ( 6 | IF /I "%%a"=="-f" SET EXPECT_OUTPUT=YES 7 | IF /I "%%a"=="--foreground" SET EXPECT_OUTPUT=YES 8 | IF /I "%%a"=="-h" SET EXPECT_OUTPUT=YES 9 | IF /I "%%a"=="--help" SET EXPECT_OUTPUT=YES 10 | IF /I "%%a"=="-t" SET EXPECT_OUTPUT=YES 11 | IF /I "%%a"=="--test" SET EXPECT_OUTPUT=YES 12 | IF /I "%%a"=="-v" SET EXPECT_OUTPUT=YES 13 | IF /I "%%a"=="--version" SET EXPECT_OUTPUT=YES 14 | IF /I "%%a"=="-w" SET EXPECT_OUTPUT=YES 15 | IF /I "%%a"=="--wait" SET EXPECT_OUTPUT=YES 16 | ) 17 | 18 | IF "%EXPECT_OUTPUT%"=="YES" ( 19 | "%~dp0\..\..\atom.exe" %* 20 | ) ELSE ( 21 | "%~dp0\..\app\apm\bin\node.exe" "%~dp0\atom.js" %* 22 | ) 23 | -------------------------------------------------------------------------------- /spec/panel-spec.coffee: -------------------------------------------------------------------------------- 1 | Panel = require '../src/panel' 2 | 3 | describe "Panel", -> 4 | [panel] = [] 5 | 6 | class TestPanelItem 7 | constructior: -> 8 | 9 | beforeEach -> 10 | panel = new Panel(item: new TestPanelItem()) 11 | 12 | describe "changing panel visibility", -> 13 | it 'emits an event when visibility changes', -> 14 | panel.onDidChangeVisible spy = jasmine.createSpy() 15 | 16 | panel.hide() 17 | expect(panel.isVisible()).toBe false 18 | expect(spy).toHaveBeenCalledWith(false) 19 | spy.reset() 20 | 21 | panel.show() 22 | expect(panel.isVisible()).toBe true 23 | expect(spy).toHaveBeenCalledWith(true) 24 | 25 | panel.destroy() 26 | expect(panel.isVisible()).toBe false 27 | expect(spy).toHaveBeenCalledWith(false) 28 | -------------------------------------------------------------------------------- /src/scrollbar-corner-component.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react-atom-fork' 2 | {div} = require 'reactionary-atom-fork' 3 | {isEqualForProperties} = require 'underscore-plus' 4 | 5 | module.exports = 6 | ScrollbarCornerComponent = React.createClass 7 | displayName: 'ScrollbarCornerComponent' 8 | 9 | render: -> 10 | {visible, measuringScrollbars, width, height} = @props 11 | 12 | if measuringScrollbars 13 | height = 25 14 | width = 25 15 | 16 | display = 'none' unless visible 17 | 18 | div className: 'scrollbar-corner', style: {display, width, height}, 19 | div style: 20 | height: height + 1 21 | width: width + 1 22 | 23 | shouldComponentUpdate: (newProps) -> 24 | not isEqualForProperties(newProps, @props, 'measuringScrollbars', 'visible', 'width', 'height') 25 | -------------------------------------------------------------------------------- /src/scoped-properties.coffee: -------------------------------------------------------------------------------- 1 | CSON = require 'season' 2 | {CompositeDisposable} = require 'event-kit' 3 | 4 | module.exports = 5 | class ScopedProperties 6 | @load: (scopedPropertiesPath, callback) -> 7 | CSON.readFile scopedPropertiesPath, (error, scopedProperties={}) -> 8 | if error? 9 | callback(error) 10 | else 11 | callback(null, new ScopedProperties(scopedPropertiesPath, scopedProperties)) 12 | 13 | constructor: (@path, @scopedProperties) -> 14 | 15 | activate: -> 16 | for selector, properties of @scopedProperties 17 | atom.config.set(null, properties, scopeSelector: selector, source: @path) 18 | return 19 | 20 | deactivate: -> 21 | for selector of @scopedProperties 22 | atom.config.unset(null, scopeSelector: selector, source: @path) 23 | return 24 | -------------------------------------------------------------------------------- /static/select-list.less: -------------------------------------------------------------------------------- 1 | @import "ui-variables"; 2 | @import "octicon-mixins"; 3 | 4 | .select-list { 5 | .loading { 6 | .loading-message { 7 | .octicon(hourglass); 8 | 9 | &:before { 10 | font-size: 1.1em; 11 | width: 1.1em; 12 | height: 1.1em; 13 | margin-right: 5px; 14 | } 15 | } 16 | 17 | .badge { 18 | margin-left: 10px; 19 | } 20 | } 21 | 22 | ol.list-group { 23 | position: relative; 24 | overflow-y: auto; 25 | max-height: 312px; 26 | margin: @component-padding 0 0 0; 27 | padding: 0; 28 | 29 | li { 30 | display: block; 31 | 32 | .primary-line, 33 | .secondary-line { 34 | text-overflow: ellipsis; 35 | white-space: nowrap; 36 | overflow: hidden; 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /static/atom.less: -------------------------------------------------------------------------------- 1 | // Import from the syntax theme's variables with a fallback to ./variables/syntax-variables.less 2 | @import "./variables/syntax-variables"; 3 | @import "syntax-variables"; 4 | 5 | // Import from the ui theme's variables with a fallback to ./variables/ui-variables.less 6 | @import "./variables/ui-variables"; 7 | @import "ui-variables"; 8 | 9 | @import "octicon-utf-codes"; 10 | @import "octicon-mixins"; 11 | 12 | @import "workspace-view"; 13 | @import "bootstrap-overrides"; 14 | @import "buttons"; 15 | @import "icons"; 16 | @import "links"; 17 | @import "panes"; 18 | @import "panels"; 19 | @import "sections"; 20 | @import "lists"; 21 | @import "popover-list"; 22 | @import "messages"; 23 | @import "markdown"; 24 | @import "text-editor-light"; 25 | @import "select-list"; 26 | @import "syntax"; 27 | @import "utilities"; 28 | @import "octicons"; 29 | -------------------------------------------------------------------------------- /src/theme-package.coffee: -------------------------------------------------------------------------------- 1 | Q = require 'q' 2 | Package = require './package' 3 | 4 | module.exports = 5 | class ThemePackage extends Package 6 | getType: -> 'theme' 7 | 8 | getStyleSheetPriority: -> 1 9 | 10 | enable: -> 11 | atom.config.unshiftAtKeyPath('core.themes', @name) 12 | 13 | disable: -> 14 | atom.config.removeAtKeyPath('core.themes', @name) 15 | 16 | load: -> 17 | @measure 'loadTime', => 18 | try 19 | @metadata ?= Package.loadMetadata(@path) 20 | catch error 21 | console.warn "Failed to load theme named '#{@name}'", error.stack ? error 22 | this 23 | 24 | activate: -> 25 | return @activationDeferred.promise if @activationDeferred? 26 | 27 | @activationDeferred = Q.defer() 28 | @measure 'activateTime', => 29 | @loadStylesheets() 30 | @activateNow() 31 | 32 | @activationDeferred.promise 33 | -------------------------------------------------------------------------------- /static/sections.less: -------------------------------------------------------------------------------- 1 | @import "ui-variables"; 2 | 3 | section, .section { 4 | position: relative; 5 | margin-top: 0; 6 | &:last-child { margin-bottom: 0; } 7 | 8 | &.bordered { 9 | margin: 0; 10 | padding: @component-padding*2 0; 11 | border-top: 1px solid @background-color-highlight; 12 | border-bottom: 1px solid @tool-panel-border-color; 13 | } 14 | 15 | .section-heading:first-child { 16 | margin-top: 0; 17 | font-weight: bold; 18 | color: @text-color-highlight; 19 | } 20 | } 21 | 22 | div > section:first-child, 23 | form > section:first-child, 24 | div > .section:first-child, 25 | form > .section:first-child { 26 | border-top: none; 27 | padding-top: 0; 28 | } 29 | div > section:last-child, 30 | form > section:last-child, 31 | div > .section:last-child, 32 | form > .section:last-child { 33 | border-bottom: none; 34 | padding-bottom: 0; 35 | } 36 | -------------------------------------------------------------------------------- /static/syntax.less: -------------------------------------------------------------------------------- 1 | @import "syntax-variables"; 2 | 3 | atom-text-editor { 4 | .lines { 5 | .markup { 6 | &.git-commit { 7 | &.changed { 8 | color: @syntax-color-modified; 9 | } 10 | 11 | &.deleted { 12 | color: @syntax-color-removed; 13 | } 14 | 15 | &.inserted { 16 | color: @syntax-color-added; 17 | } 18 | } 19 | } 20 | } 21 | } 22 | 23 | .define-selection-flash-color-if-not-defined() { @syntax-selection-flash-color: rgba(100, 255, 100, 0.7); } 24 | .define-selection-flash-color-if-not-defined(); 25 | 26 | @-webkit-keyframes flash { 27 | from { background-color: @syntax-selection-flash-color; } 28 | to { background-color: null; } 29 | } 30 | 31 | atom-text-editor .flash.selection .region { 32 | -webkit-animation-name: flash; 33 | -webkit-animation-duration: .5s; 34 | -webkit-animation-iteration-count: 1; 35 | } 36 | -------------------------------------------------------------------------------- /static/variables/octicon-mixins.less: -------------------------------------------------------------------------------- 1 | .icon-size(@size) { 2 | font-size: @size; 3 | width: @size; 4 | height: @size; 5 | } 6 | 7 | .icon(@size, @display: inline-block) { 8 | font-family: 'Octicons Regular'; 9 | font-weight: normal; 10 | font-style: normal; 11 | display: @display; 12 | line-height: 1; 13 | -webkit-font-smoothing: antialiased; 14 | text-decoration: none; 15 | 16 | .icon-size(@size); 17 | } 18 | 19 | .octicon(@name, @size: 16px) { 20 | @import "octicon-utf-codes.less"; 21 | &:before { 22 | .icon(@size); 23 | content: @@name 24 | } 25 | } 26 | 27 | .mega-octicon(@name, @size: 32px) { 28 | @import "octicon-utf-codes.less"; 29 | &:before { 30 | .icon(@size); 31 | content: @@name 32 | } 33 | } 34 | 35 | .octicon-font() { 36 | font-family: 'Octicons Regular'; 37 | src: url("octicons.woff") format("woff"); 38 | font-weight: normal; 39 | font-style: normal; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/scan-handler.coffee: -------------------------------------------------------------------------------- 1 | {PathSearcher, PathScanner, search} = require 'scandal' 2 | 3 | module.exports = (rootPath, regexSource, options) -> 4 | callback = @async() 5 | 6 | PATHS_COUNTER_SEARCHED_CHUNK = 50 7 | pathsSearched = 0 8 | 9 | searcher = new PathSearcher() 10 | scanner = new PathScanner(rootPath, options) 11 | 12 | searcher.on 'file-error', ({code, path, message}) -> 13 | emit('scan:file-error', {code, path, message}) 14 | 15 | searcher.on 'results-found', (result) -> 16 | emit('scan:result-found', result) 17 | 18 | scanner.on 'path-found', -> 19 | pathsSearched++ 20 | if pathsSearched % PATHS_COUNTER_SEARCHED_CHUNK == 0 21 | emit('scan:paths-searched', pathsSearched) 22 | 23 | flags = "g" 24 | flags += "i" if options.ignoreCase 25 | regex = new RegExp(regexSource, flags) 26 | search regex, scanner, searcher, -> 27 | emit('scan:paths-searched', pathsSearched) 28 | callback() 29 | -------------------------------------------------------------------------------- /src/window.coffee: -------------------------------------------------------------------------------- 1 | # Public: Measure how long a function takes to run. 2 | # 3 | # description - A {String} description that will be logged to the console when 4 | # the function completes. 5 | # fn - A {Function} to measure the duration of. 6 | # 7 | # Returns the value returned by the given function. 8 | window.measure = (description, fn) -> 9 | start = Date.now() 10 | value = fn() 11 | result = Date.now() - start 12 | console.log description, result 13 | value 14 | 15 | # Public: Create a dev tools profile for a function. 16 | # 17 | # description - A {String} description that will be available in the Profiles 18 | # tab of the dev tools. 19 | # fn - A {Function} to profile. 20 | # 21 | # Returns the value returned by the given function. 22 | window.profile = (description, fn) -> 23 | measure description, -> 24 | console.profile(description) 25 | value = fn() 26 | console.profileEnd(description) 27 | value 28 | -------------------------------------------------------------------------------- /src/browser/context-menu.coffee: -------------------------------------------------------------------------------- 1 | Menu = require 'menu' 2 | 3 | module.exports = 4 | class ContextMenu 5 | constructor: (template, @atomWindow) -> 6 | template = @createClickHandlers(template) 7 | menu = Menu.buildFromTemplate(template) 8 | menu.popup(@atomWindow.browserWindow) 9 | 10 | # It's necessary to build the event handlers in this process, otherwise 11 | # closures are dragged across processes and failed to be garbage collected 12 | # appropriately. 13 | createClickHandlers: (template) -> 14 | for item in template 15 | if item.command 16 | item.commandDetail ?= {} 17 | item.commandDetail.contextCommand = true 18 | item.commandDetail.atomWindow = @atomWindow 19 | do (item) => 20 | item.click = => 21 | global.atomApplication.sendCommandToWindow(item.command, @atomWindow, item.commandDetail) 22 | else if item.submenu 23 | @createClickHandlers(item.submenu) 24 | item 25 | -------------------------------------------------------------------------------- /dot-atom/keymap.cson: -------------------------------------------------------------------------------- 1 | # Your keymap 2 | # 3 | # Atom keymaps work similarly to style sheets. Just as style sheets use 4 | # selectors to apply styles to elements, Atom keymaps use selectors to associate 5 | # keystrokes with events in specific contexts. 6 | # 7 | # You can create a new keybinding in this file by typing "key" and then hitting 8 | # tab. 9 | # 10 | # Here's an example taken from Atom's built-in keymap: 11 | # 12 | # 'atom-text-editor': 13 | # 'enter': 'editor:newline' 14 | # 15 | # 'atom-workspace': 16 | # 'ctrl-shift-p': 'core:move-up' 17 | # 'ctrl-p': 'core:move-down' 18 | # 19 | # You can find more information about keymaps in these guides: 20 | # * https://atom.io/docs/latest/customizing-atom#customizing-key-bindings 21 | # * https://atom.io/docs/latest/advanced/keymaps 22 | # 23 | # This file uses CoffeeScript Object Notation (CSON). 24 | # If you are unfamiliar with CSON, you can read more about it here: 25 | # https://github.com/bevry/cson#what-is-cson 26 | -------------------------------------------------------------------------------- /docs/advanced/node-modules.md: -------------------------------------------------------------------------------- 1 | ## Developing Node Modules 2 | 3 | Atom contains a number of packages that are Node modules instead of Atom packages. If you want to 4 | make changes to the Node modules, for instance `atom-keymap`, you have to link them into the 5 | development environment differently than you would a normal Atom package. 6 | 7 | ### Linking a Node Module Into Your Atom Dev Environment 8 | 9 | Here are the steps to run a local version of a node module *not an apm* within Atom. We're using 10 | `atom-keymap` as an example: 11 | 12 | ```bash 13 | $ git clone https://github.com/atom/atom-keymap.git 14 | $ cd atom-keymap 15 | $ npm install 16 | $ npm link 17 | $ apm rebuild # This is the special step, it makes the npm work with Atom's version of Node 18 | $ cd WHERE-YOU-CLONED-ATOM 19 | $ npm link atom-keymap 20 | $ atom # Should work! 21 | ``` 22 | 23 | After this, you'll have to `npm install` and `apm rebuild` when you make a change to the node 24 | module's code. 25 | -------------------------------------------------------------------------------- /static/variables/syntax-variables.less: -------------------------------------------------------------------------------- 1 | // This file has fallback variables. It specifies all syntax variables that 2 | // themes must implement if they include a syntax-variables.less file. 3 | 4 | // General colors 5 | @syntax-text-color: #333; 6 | @syntax-cursor-color: #333; 7 | @syntax-selection-color: #69c; 8 | @syntax-selection-flash-color: #00f; // Color the selection is 'flashed' when you run find next 9 | @syntax-background-color: #fff; 10 | 11 | // Guide colors 12 | @syntax-wrap-guide-color: #ccc; 13 | @syntax-indent-guide-color: #ccc; 14 | @syntax-invisible-character-color: #ccc; 15 | 16 | // For find and replace markers 17 | @syntax-result-marker-color: #444; 18 | @syntax-result-marker-color-selected: #000; 19 | 20 | // Gutter colors 21 | @syntax-gutter-text-color: #333; 22 | @syntax-gutter-text-color-selected: #000; 23 | @syntax-gutter-background-color: #ccc; 24 | @syntax-gutter-background-color-selected: #eee; 25 | 26 | // For git diff info. i.e. in the gutter 27 | @syntax-color-added: green; 28 | @syntax-color-modified: orange; 29 | @syntax-color-removed: red; 30 | @syntax-color-renamed: blue; 31 | -------------------------------------------------------------------------------- /resources/mac/helper-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | Atom Helper 9 | CFBundleExecutable 10 | Atom Helper 11 | CFBundleIdentifier 12 | com.github.atom.helper 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | Atom Helper 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | ${VERSION} 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | ${VERSION} 25 | LSMinimumSystemVersion 26 | 10.7.0 27 | LSUIElement 28 | 1 29 | NSSupportsAutomaticGraphicsSwitching 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /spec/spec-bootstrap.coffee: -------------------------------------------------------------------------------- 1 | # Start the crash reporter before anything else. 2 | require('crash-reporter').start(productName: 'Atom', companyName: 'GitHub') 3 | 4 | path = require 'path' 5 | 6 | try 7 | require '../src/window' 8 | Atom = require '../src/atom' 9 | window.atom = Atom.loadOrCreate('spec') 10 | 11 | # Show window synchronously so a focusout doesn't fire on input elements 12 | # that are focused in the very first spec run. 13 | atom.getCurrentWindow().show() unless atom.getLoadSettings().exitWhenDone 14 | 15 | {runSpecSuite} = require './jasmine-helper' 16 | 17 | # Add 'exports' to module search path. 18 | exportsPath = path.join(atom.getLoadSettings().resourcePath, 'exports') 19 | require('module').globalPaths.push(exportsPath) 20 | # Still set NODE_PATH since tasks may need it. 21 | process.env.NODE_PATH = exportsPath 22 | 23 | document.title = "Spec Suite" 24 | runSpecSuite './spec-suite', atom.getLoadSettings().logFile 25 | catch error 26 | if atom?.getLoadSettings().exitWhenDone 27 | console.error(error.stack ? error) 28 | atom.exit(1) 29 | else 30 | throw error 31 | -------------------------------------------------------------------------------- /spec/spec-helper-platform.coffee: -------------------------------------------------------------------------------- 1 | path = require 'path' 2 | fs = require 'fs-plus' 3 | 4 | ## Platform specific helpers 5 | module.exports = 6 | # Public: Returns true if being run from within Windows 7 | isWindows: -> 8 | !!process.platform.match /^win/ 9 | 10 | # Public: Some files can not exist on Windows filesystems, so we have to 11 | # selectively generate our fixtures. 12 | # 13 | # Returns nothing. 14 | generateEvilFiles: -> 15 | evilFilesPath = path.join(__dirname, 'fixtures', 'evil-files') 16 | fs.removeSync(evilFilesPath) if fs.existsSync(evilFilesPath) 17 | fs.mkdirSync(evilFilesPath) 18 | 19 | if @isWindows() 20 | filenames = [ 21 | "a_file_with_utf8.txt" 22 | "file with spaces.txt" 23 | "utfa\u0306.md" 24 | ] 25 | else 26 | filenames = [ 27 | "a_file_with_utf8.txt" 28 | "file with spaces.txt" 29 | "goddam\nnewlines" 30 | "quote\".txt" 31 | "utfa\u0306.md" 32 | ] 33 | 34 | for filename in filenames 35 | fs.writeFileSync(path.join(evilFilesPath, filename), 'evil file!', flag: 'w') 36 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 GitHub Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /script/utils/clean-merged-branches: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #/ Usage: clean-merged-branches [-f] 3 | #/ Delete merged branches from the origin remote. 4 | #/ 5 | #/ Options: 6 | #/ -f Really delete the branches. Without this branches are shown 7 | #/ but nothing is deleted. 8 | 9 | set -e 10 | 11 | # show usage maybe 12 | [ "$1" = "--help" ] && { 13 | grep '^#/' <"$0"| cut -c4- 14 | exit 0 15 | } 16 | 17 | # fetch and prune remote branches 18 | git fetch origin --prune 19 | 20 | # grab list of merged branches 21 | branches=$( 22 | git branch -a --merged origin/master | 23 | grep remotes/origin/ | 24 | grep -v /master | 25 | sed 's@remotes/origin/@@' 26 | ) 27 | 28 | # bail out with no branches 29 | [ -z "$branches" ] && { 30 | echo "no merged branches detected" 1>&2 31 | exit 0 32 | } 33 | 34 | # delete the branches or just show what would be done without -f 35 | if [ "$1" = -f ]; then 36 | git push origin $(echo "$branches" | sed 's/^ */:/') 37 | else 38 | echo "These branches will be deleted:" 1>&2 39 | echo "$branches" 40 | echo "Run \`$0 -f' if you're sure." 41 | fi 42 | -------------------------------------------------------------------------------- /src/less-compile-cache.coffee: -------------------------------------------------------------------------------- 1 | path = require 'path' 2 | LessCache = require 'less-cache' 3 | 4 | # {LessCache} wrapper used by {ThemeManager} to read stylesheets. 5 | module.exports = 6 | class LessCompileCache 7 | @cacheDir: path.join(process.env.ATOM_HOME, 'compile-cache', 'less') 8 | 9 | constructor: ({resourcePath, importPaths}) -> 10 | @lessSearchPaths = [ 11 | path.join(resourcePath, 'static', 'variables') 12 | path.join(resourcePath, 'static') 13 | ] 14 | 15 | if importPaths? 16 | importPaths = importPaths.concat(@lessSearchPaths) 17 | else 18 | importPaths = @lessSearchPaths 19 | 20 | @cache = new LessCache 21 | cacheDir: @constructor.cacheDir 22 | importPaths: importPaths 23 | resourcePath: resourcePath 24 | fallbackDir: path.join(resourcePath, 'less-compile-cache') 25 | 26 | setImportPaths: (importPaths=[]) -> 27 | @cache.setImportPaths(importPaths.concat(@lessSearchPaths)) 28 | 29 | read: (stylesheetPath) -> 30 | @cache.readFileSync(stylesheetPath) 31 | 32 | cssForFile: (stylesheetPath, lessContent) -> 33 | @cache.cssForFile(stylesheetPath, lessContent) 34 | -------------------------------------------------------------------------------- /src/repository-status-handler.coffee: -------------------------------------------------------------------------------- 1 | Git = require 'git-utils' 2 | path = require 'path' 3 | 4 | module.exports = (repoPath) -> 5 | repo = Git.open(repoPath) 6 | 7 | upstream = {} 8 | statuses = {} 9 | submodules = {} 10 | branch = null 11 | 12 | if repo? 13 | # Statuses in main repo 14 | workingDirectoryPath = repo.getWorkingDirectory() 15 | for filePath, status of repo.getStatus() 16 | statuses[filePath] = status 17 | 18 | # Statuses in submodules 19 | for submodulePath, submoduleRepo of repo.submodules 20 | submodules[submodulePath] = 21 | branch: submoduleRepo.getHead() 22 | upstream: submoduleRepo.getAheadBehindCount() 23 | 24 | workingDirectoryPath = submoduleRepo.getWorkingDirectory() 25 | for filePath, status of submoduleRepo.getStatus() 26 | absolutePath = path.join(workingDirectoryPath, filePath) 27 | # Make path relative to parent repository 28 | relativePath = repo.relativize(absolutePath) 29 | statuses[relativePath] = status 30 | 31 | upstream = repo.getAheadBehindCount() 32 | branch = repo.getHead() 33 | repo.release() 34 | 35 | {statuses, upstream, branch, submodules} 36 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | ## Guides 2 | 3 | * [Getting Started](getting-started.md) 4 | * [Customizing Atom](customizing-atom.md) 5 | * [Creating a Package](creating-a-package.md) 6 | * [Creating a Theme](creating-a-theme.md) 7 | * [Publishing a Package](publishing-a-package.md) 8 | * [Writing Specs](writing-specs.md) 9 | * [Converting a TextMate Bundle](converting-a-text-mate-bundle.md) 10 | * [Converting a TextMate Theme](converting-a-text-mate-theme.md) 11 | * [Contributing](contributing.md) 12 | * [Contributing to Core Packages](contributing-to-packages.md) 13 | * [Debugging](debugging.md) 14 | * [Your First Package](your-first-package.md) 15 | 16 | ### Advanced Topics 17 | 18 | * [Configuration](advanced/configuration.md) 19 | * [Developing Node Modules](advanced/node-modules.md) 20 | * [Keymaps](advanced/keymaps.md) 21 | * [Serialization](advanced/serialization.md) 22 | * [Scopes and Scope Descriptors](advanced/scopes-and-scope-descriptors.md) 23 | * [Theme Variables](theme-variables.md) 24 | * [apm REST API](apm-rest-api.md) 25 | 26 | ### Upgrading to 1.0 APIs 27 | 28 | * [Upgrading Your UI Theme Or Package Selectors](upgrading/upgrading-your-ui-theme.md) 29 | * [Upgrading Your Syntax Theme](upgrading/upgrading-your-syntax-theme.md) 30 | -------------------------------------------------------------------------------- /src/panel-element.coffee: -------------------------------------------------------------------------------- 1 | {CompositeDisposable} = require 'event-kit' 2 | {callAttachHooks} = require './space-pen-extensions' 3 | Panel = require './panel' 4 | 5 | class PanelElement extends HTMLElement 6 | createdCallback: -> 7 | @subscriptions = new CompositeDisposable 8 | 9 | initialize: (@model) -> 10 | @appendChild(@getItemView()) 11 | 12 | @classList.add(@model.getClassName().split(' ')...) if @model.getClassName()? 13 | @subscriptions.add @model.onDidChangeVisible(@visibleChanged.bind(this)) 14 | @subscriptions.add @model.onDidDestroy(@destroyed.bind(this)) 15 | this 16 | 17 | getModel: -> 18 | @model ?= new Panel 19 | 20 | getItemView: -> 21 | atom.views.getView(@getModel().getItem()) 22 | 23 | attachedCallback: -> 24 | callAttachHooks(@getItemView()) # for backward compatibility with SpacePen views 25 | @visibleChanged(@getModel().isVisible()) 26 | 27 | visibleChanged: (visible) -> 28 | if visible 29 | @style.display = null 30 | else 31 | @style.display = 'none' 32 | 33 | destroyed: -> 34 | @subscriptions.dispose() 35 | @parentNode?.removeChild(this) 36 | 37 | module.exports = PanelElement = document.registerElement 'atom-panel', prototype: PanelElement.prototype 38 | -------------------------------------------------------------------------------- /resources/mac/speakeasy.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIDOjCCAi0GByqGSM44BAEwggIgAoIBAQCEh+j0nKWTw7soK6w3uk9PzPGVBksk 3 | wDIaA+d+1CHJY9qhjp7OjAlSOl6nrUlGHzU87DRmBlwYZONAzDZnYpLi7zmPVASg 4 | Xk+AmuqzqahTKtwodJp7R/Aq/lCbB2tXTXOxVo+Jya1BQbfd0wWXJFUlD/xTvrgu 5 | zrtw6VYBvaRu8jCjHAJNZn0CO80igj1ZNxRqmmz1Rkt1tT0KBBfGBTNzXeBmGKHN 6 | bVIKW7zImgfm+UQky+WFei1dqcfWOyfrHIYa3Qn1Nes48SBdrolvfvrChlSpqgEN 7 | wxFW9aoognS1UJTu350AQb2NwOOSQRsR++y3iJp+60nBSDZu7sjNN9etAhUAvqki 8 | JOjBjooRd2odMh7imICHQ3kCggEATwa6W0s2xrolPRpwWZS8ORUNDgEI4eOIvonq 9 | O2qZgwD21zUQOsFjLMbWn0cCtrORr7iM8pFg8Yn8dSccpqs+2cM4uFZAycKXf6w3 10 | jIvV6M3IPQuUSqVFZtqUVuteGTEuAHZKIrXE05P4aJXHLjqSC9JuaXNRm9q7OW7m 11 | rwsoAFyfkKqbtl5Ch+WZ21CE4J+ByTfVwVU4XLiOtce6NABSDWNJsF9fIoFCZCDc 12 | uumLllDJysD8S6aBNhOjNMHPmeIpZBXT23zHH5du/blcEyBbVF3a2ntgudfJmyln 13 | T178CIEUSSjcbz9JyAhhK7OfNlzKhRiO1c4Y3XaZIniLGjF5DwOCAQUAAoIBABGZ 14 | mfuHBW89ub19iICE//VbB91m2f0nUvHk8vE4vvAK8AdD91GODPJr4DU0kJM6ne8r 15 | ohvZgokgDRkGAEceX/nVoG0RLq9T15Xr2qedWVwAffpU10iV9mYwbhHqUKPtG8cj 16 | GW0cDdSI+0oG6UEyn8aQ5p93YEm5N6lq4rWKpxXb/gkrIla4sJJP8VHOOKmo6l1H 17 | AKVIfofiaNAQShu72WVCCurWaoVTUEliEBhy3WlcjuKXEuoL1lpNxyqkt7mf6w71 18 | 6y2+Nh+XUTiFoTIVhk/CH0z+BQTneWEALvfTFzDae+a42rPAisKlt+Gbe7zopnVA 19 | kcQwM0lLzgwx4T1DV3s= 20 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /src/scroll-view.coffee: -------------------------------------------------------------------------------- 1 | {View} = require './space-pen-extensions' 2 | 3 | # Deprecated: Represents a view that scrolls. 4 | # 5 | # Handles several core events to update scroll position: 6 | # 7 | # * `core:move-up` Scrolls the view up 8 | # * `core:move-down` Scrolls the view down 9 | # * `core:page-up` Scrolls the view up by the height of the page 10 | # * `core:page-down` Scrolls the view down by the height of the page 11 | # * `core:move-to-top` Scrolls the editor to the top 12 | # * `core:move-to-bottom` Scroll the editor to the bottom 13 | # 14 | # Subclasses must call `super` if overriding the `initialize` method. 15 | # 16 | # ## Examples 17 | # 18 | # ```coffee 19 | # {ScrollView} = require 'atom' 20 | # 21 | # class MyView extends ScrollView 22 | # @content: -> 23 | # @div() 24 | # 25 | # initialize: -> 26 | # super 27 | # @text('super long content that will scroll') 28 | # ``` 29 | # 30 | module.exports = 31 | class ScrollView extends View 32 | initialize: -> 33 | @on 'core:move-up', => @scrollUp() 34 | @on 'core:move-down', => @scrollDown() 35 | @on 'core:page-up', => @pageUp() 36 | @on 'core:page-down', => @pageDown() 37 | @on 'core:move-to-top', => @scrollToTop() 38 | @on 'core:move-to-bottom', => @scrollToBottom() 39 | -------------------------------------------------------------------------------- /spec/buffered-node-process-spec.coffee: -------------------------------------------------------------------------------- 1 | path = require 'path' 2 | BufferedNodeProcess = require '../src/buffered-node-process' 3 | 4 | describe "BufferedNodeProcess", -> 5 | it "executes the script in a new process", -> 6 | exit = jasmine.createSpy('exitCallback') 7 | output = '' 8 | stdout = (lines) -> output += lines 9 | error = '' 10 | stderr = (lines) -> error += lines 11 | args = ['hi'] 12 | command = path.join(__dirname, 'fixtures', 'script.js') 13 | 14 | new BufferedNodeProcess({command, args, stdout, stderr, exit}) 15 | 16 | waitsFor -> 17 | exit.callCount is 1 18 | 19 | runs -> 20 | expect(output).toBe 'hi' 21 | expect(error).toBe '' 22 | expect(args).toEqual ['hi'] 23 | 24 | it "suppresses deprecations in the new process", -> 25 | exit = jasmine.createSpy('exitCallback') 26 | output = '' 27 | stdout = (lines) -> output += lines 28 | error = '' 29 | stderr = (lines) -> error += lines 30 | command = path.join(__dirname, 'fixtures', 'script-with-deprecations.js') 31 | 32 | new BufferedNodeProcess({command, stdout, stderr, exit}) 33 | 34 | waitsFor -> 35 | exit.callCount is 1 36 | 37 | runs -> 38 | expect(output).toBe 'hi' 39 | expect(error).toBe '' 40 | -------------------------------------------------------------------------------- /static/panes.less: -------------------------------------------------------------------------------- 1 | @import "ui-variables"; 2 | 3 | // Pane-items are things that go inside a pane. Like the UI-Demo, the 4 | // settings-view, the archive-view, the image-view. Etc. Basically a non- 5 | // editor resource with a tab. 6 | atom-pane-container { 7 | display: -webkit-flex; 8 | -webkit-flex: 1; 9 | 10 | atom-pane-axis.vertical { 11 | display: -webkit-flex; 12 | -webkit-flex: 1; 13 | -webkit-flex-direction: column; 14 | } 15 | 16 | atom-pane-axis.horizontal { 17 | display: -webkit-flex; 18 | -webkit-flex: 1; 19 | -webkit-flex-direction: row; 20 | } 21 | 22 | atom-pane { 23 | position: relative; 24 | display: -webkit-flex; 25 | -webkit-flex: 1; 26 | -webkit-flex-direction: column; 27 | overflow: hidden; 28 | 29 | .item-views { 30 | -webkit-flex: 1; 31 | display: -webkit-flex; 32 | min-height: 0; 33 | min-width: 0; 34 | position: relative; 35 | 36 | .pane-item { 37 | color: @text-color; 38 | background-color: @pane-item-background-color; 39 | } 40 | 41 | > *, > atom-text-editor.react > * { 42 | position: absolute; 43 | top: 0; 44 | right: 0; 45 | bottom: 0; 46 | left: 0; 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/input-component.coffee: -------------------------------------------------------------------------------- 1 | {last, isEqual} = require 'underscore-plus' 2 | React = require 'react-atom-fork' 3 | {input} = require 'reactionary-atom-fork' 4 | 5 | module.exports = 6 | InputComponent = React.createClass 7 | displayName: 'InputComponent' 8 | 9 | render: -> 10 | {className, style} = @props 11 | 12 | input {className, style, 'data-react-skip-selection-restoration': true} 13 | 14 | getInitialState: -> 15 | {lastChar: ''} 16 | 17 | componentDidMount: -> 18 | node = @getDOMNode() 19 | node.addEventListener 'paste', @onPaste 20 | node.addEventListener 'compositionupdate', @onCompositionUpdate 21 | 22 | # Don't let text accumulate in the input forever, but avoid excessive reflows 23 | componentDidUpdate: -> 24 | if @lastValueLength > 500 and not @isPressAndHoldCharacter(@state.lastChar) 25 | @getDOMNode().value = '' 26 | @lastValueLength = 0 27 | 28 | # This should actually consult the property lists in /System/Library/Input Methods/PressAndHold.app 29 | isPressAndHoldCharacter: (char) -> 30 | @state.lastChar.match /[aeiouAEIOU]/ 31 | 32 | shouldComponentUpdate: (newProps) -> 33 | not isEqual(newProps.style, @props.style) 34 | 35 | onPaste: (e) -> 36 | e.preventDefault() 37 | 38 | focus: -> 39 | @getDOMNode().focus() 40 | -------------------------------------------------------------------------------- /spec/space-pen-extensions-spec.coffee: -------------------------------------------------------------------------------- 1 | {View, $, $$} = require '../src/space-pen-extensions' 2 | 3 | describe "SpacePen extensions", -> 4 | class TestView extends View 5 | @content: -> @div() 6 | 7 | [view, parent] = [] 8 | 9 | beforeEach -> 10 | view = new TestView 11 | parent = $$ -> @div() 12 | parent.append(view) 13 | 14 | describe "View.subscribe(eventEmitter, eventName, callback)", -> 15 | [emitter, eventHandler] = [] 16 | 17 | beforeEach -> 18 | eventHandler = jasmine.createSpy 'eventHandler' 19 | emitter = $$ -> @div() 20 | view.subscribe emitter, 'foo', eventHandler 21 | 22 | it "subscribes to the given event emitter and unsubscribes when unsubscribe is called", -> 23 | emitter.trigger "foo" 24 | expect(eventHandler).toHaveBeenCalled() 25 | 26 | describe "tooltips", -> 27 | describe "when the window is resized", -> 28 | it "hides the tooltips", -> 29 | class TooltipView extends View 30 | @content: -> 31 | @div() 32 | 33 | view = new TooltipView() 34 | view.attachToDom() 35 | view.setTooltip('this is a tip') 36 | 37 | view.tooltip('show') 38 | expect($(document.body).find('.tooltip')).toBeVisible() 39 | 40 | $(window).trigger('resize') 41 | expect($(document.body).find('.tooltip')).not.toExist() 42 | -------------------------------------------------------------------------------- /spec/command-installer-spec.coffee: -------------------------------------------------------------------------------- 1 | path = require 'path' 2 | fs = require 'fs-plus' 3 | temp = require 'temp' 4 | installer = require '../src/command-installer' 5 | 6 | describe "install(commandPath, callback)", -> 7 | commandFilePath = temp.openSync("atom-command").path 8 | commandName = path.basename(commandFilePath) 9 | installationPath = temp.mkdirSync("atom-bin") 10 | installationFilePath = path.join(installationPath, commandName) 11 | 12 | beforeEach -> 13 | fs.chmodSync(commandFilePath, '755') 14 | spyOn(installer, 'getInstallDirectory').andReturn installationPath 15 | 16 | describe "on #darwin", -> 17 | it "symlinks the command and makes it executable", -> 18 | expect(fs.isFileSync(commandFilePath)).toBeTruthy() 19 | expect(fs.isFileSync(installationFilePath)).toBeFalsy() 20 | 21 | installDone = false 22 | installError = null 23 | installer.createSymlink commandFilePath, false, (error) -> 24 | installDone = true 25 | installError = error 26 | 27 | waitsFor -> 28 | installDone 29 | 30 | runs -> 31 | expect(installError).toBeNull() 32 | expect(fs.isFileSync(installationFilePath)).toBeTruthy() 33 | expect(fs.realpathSync(installationFilePath)).toBe fs.realpathSync(commandFilePath) 34 | expect(fs.isExecutableSync(installationFilePath)).toBeTruthy() 35 | -------------------------------------------------------------------------------- /src/task-bootstrap.coffee: -------------------------------------------------------------------------------- 1 | {userAgent, taskPath} = process.env 2 | handler = null 3 | 4 | setupGlobals = -> 5 | global.attachEvent = -> 6 | console = 7 | warn: -> emit 'task:warn', arguments... 8 | log: -> emit 'task:log', arguments... 9 | error: -> emit 'task:error', arguments... 10 | trace: -> 11 | global.__defineGetter__ 'console', -> console 12 | 13 | global.document = 14 | createElement: -> 15 | setAttribute: -> 16 | getElementsByTagName: -> [] 17 | appendChild: -> 18 | documentElement: 19 | insertBefore: -> 20 | removeChild: -> 21 | getElementById: -> {} 22 | createComment: -> {} 23 | createDocumentFragment: -> {} 24 | 25 | global.emit = (event, args...) -> 26 | process.send({event, args}) 27 | global.navigator = {userAgent} 28 | global.window = global 29 | 30 | handleEvents = -> 31 | process.on 'uncaughtException', (error) -> 32 | console.error(error.message, error.stack) 33 | process.on 'message', ({event, args}={}) -> 34 | return unless event is 'start' 35 | 36 | isAsync = false 37 | async = -> 38 | isAsync = true 39 | (result) -> 40 | emit('task:completed', result) 41 | result = handler.bind({async})(args...) 42 | emit('task:completed', result) unless isAsync 43 | 44 | setupGlobals() 45 | handleEvents() 46 | handler = require(taskPath) 47 | -------------------------------------------------------------------------------- /src/highlights-component.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react-atom-fork' 2 | {div} = require 'reactionary-atom-fork' 3 | {isEqualForProperties} = require 'underscore-plus' 4 | HighlightComponent = require './highlight-component' 5 | 6 | module.exports = 7 | HighlightsComponent = React.createClass 8 | displayName: 'HighlightsComponent' 9 | 10 | render: -> 11 | div className: 'highlights', 12 | @renderHighlights() if @props.performedInitialMeasurement 13 | 14 | renderHighlights: -> 15 | {editor, highlightDecorations, lineHeightInPixels} = @props 16 | 17 | highlightComponents = [] 18 | for markerId, {startPixelPosition, endPixelPosition, decorations} of highlightDecorations 19 | for decoration in decorations 20 | highlightComponents.push(HighlightComponent({editor, key: "#{markerId}-#{decoration.id}", startPixelPosition, endPixelPosition, decoration, lineHeightInPixels})) 21 | 22 | highlightComponents 23 | 24 | componentDidMount: -> 25 | if atom.config.get('editor.useShadowDOM') 26 | insertionPoint = document.createElement('content') 27 | insertionPoint.setAttribute('select', '.underlayer') 28 | @getDOMNode().appendChild(insertionPoint) 29 | 30 | shouldComponentUpdate: (newProps) -> 31 | not isEqualForProperties(newProps, @props, 'highlightDecorations', 'lineHeightInPixels', 'defaultCharWidth', 'scopedCharacterWidthsChangeCount') 32 | -------------------------------------------------------------------------------- /static/bootstrap.less: -------------------------------------------------------------------------------- 1 | // Core variables and mixins 2 | @import "../node_modules/bootstrap/less/variables.less"; 3 | @import "../node_modules/bootstrap/less/mixins.less"; 4 | 5 | // Reset 6 | @import "../node_modules/bootstrap/less/normalize.less"; 7 | 8 | // Core CSS 9 | @import "../node_modules/bootstrap/less/scaffolding.less"; 10 | @import "../node_modules/bootstrap/less/type.less"; 11 | @import "../node_modules/bootstrap/less/code.less"; 12 | @import "../node_modules/bootstrap/less/grid.less"; 13 | @import "../node_modules/bootstrap/less/tables.less"; 14 | @import "../node_modules/bootstrap/less/forms.less"; 15 | @import "../node_modules/bootstrap/less/buttons.less"; 16 | 17 | // Components 18 | @import "../node_modules/bootstrap/less/button-groups.less"; 19 | @import "../node_modules/bootstrap/less/input-groups.less"; 20 | @import "../node_modules/bootstrap/less/navs.less"; 21 | @import "../node_modules/bootstrap/less/labels.less"; 22 | @import "../node_modules/bootstrap/less/badges.less"; 23 | @import "../node_modules/bootstrap/less/alerts.less"; 24 | @import "../node_modules/bootstrap/less/list-group.less"; 25 | @import "../node_modules/bootstrap/less/thumbnails.less"; 26 | @import "../node_modules/bootstrap/less/close.less"; 27 | 28 | // Components w/ JavaScript 29 | @import "../node_modules/bootstrap/less/tooltip.less"; 30 | 31 | // Utility classes 32 | @import "../node_modules/bootstrap/less/utilities.less"; 33 | -------------------------------------------------------------------------------- /resources/linux/redhat/atom.spec.in: -------------------------------------------------------------------------------- 1 | Name: <%= name %> 2 | Version: <%= version %> 3 | Release: 0.1%{?dist} 4 | Summary: <%= description %> 5 | License: MIT 6 | URL: https://atom.io/ 7 | AutoReqProv: no # Avoid libchromiumcontent.so missing dependency 8 | Prefix: <%= installDir %> 9 | 10 | %description 11 | <%= description %> 12 | 13 | %install 14 | mkdir -p %{buildroot}/<%= installDir %>/share/atom/ 15 | cp -r Atom/* %{buildroot}/<%= installDir %>/share/atom/ 16 | mkdir -p %{buildroot}/<%= installDir %>/bin/ 17 | ln -sf ../share/atom/resources/app/apm/node_modules/.bin/apm %{buildroot}/<%= installDir %>/bin/apm 18 | cp atom.sh %{buildroot}/<%= installDir %>/bin/atom 19 | chmod 755 %{buildroot}/<%= installDir %>/bin/atom 20 | mkdir -p %{buildroot}/<%= installDir %>/share/applications/ 21 | cp atom.desktop %{buildroot}/<%= installDir %>/share/applications/ 22 | 23 | # copy over icons in sizes that most desktop environments like 24 | for i in 1024 512 256 128 64 48 32 24 16 25 | do 26 | mkdir -p %{buildroot}/<%= installDir %>/share/icons/hicolor/${i}x${i}/apps 27 | cp icons/${i}.png %{buildroot}/<%= installDir %>/share/icons/hicolor/${i}x${i}/apps/atom.png 28 | done 29 | 30 | %files 31 | <%= installDir %>/bin/atom 32 | <%= installDir %>/bin/apm 33 | <%= installDir %>/share/atom/ 34 | <%= installDir %>/share/applications/atom.desktop 35 | <%= installDir %>/share/icons/hicolor/ 36 | -------------------------------------------------------------------------------- /static/utilities.less: -------------------------------------------------------------------------------- 1 | @import "ui-variables"; 2 | 3 | :focus { 4 | outline: none; 5 | } 6 | 7 | .pull-center { 8 | margin-left: auto; 9 | margin-right: auto; 10 | } 11 | 12 | .padded { 13 | padding: @component-padding; 14 | } 15 | 16 | // Blocks 17 | 18 | // Must be div.block so as not to affect syntax highlighting. 19 | ul.block, 20 | div.block { 21 | margin-bottom: @component-padding; 22 | } 23 | div > ul.block:last-child, 24 | div > div.block:last-child { 25 | margin-bottom: 0; 26 | } 27 | 28 | // Inline Blocks 29 | 30 | .inline-block, 31 | .inline-block-tight { 32 | display: inline-block; 33 | vertical-align: middle; 34 | } 35 | .inline-block { 36 | margin-right: @component-padding; 37 | } 38 | .inline-block-tight { 39 | margin-right: @component-padding/2; 40 | } 41 | div > .inline-block:last-child, 42 | div > .inline-block-tight:last-child { 43 | margin-right: 0; 44 | } 45 | 46 | .inline-block .inline-block { 47 | vertical-align: top; 48 | } 49 | 50 | // Use left margin when it's in a float: right element. 51 | // Sets the margin correctly when inline blocks are hidden and shown. 52 | .pull-right { 53 | .inline-block { 54 | margin-right: 0; 55 | margin-left: @component-padding; 56 | } 57 | .inline-block-tight { 58 | margin-right: 0; 59 | margin-left: @component-padding/2; 60 | } 61 | 62 | > .inline-block:first-child, 63 | > .inline-block-tight:first-child { 64 | margin-left: 0; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /script/mkdeb: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # mkdeb version control-file-path deb-file-path 3 | 4 | set -e 5 | 6 | SCRIPT=`readlink -f "$0"` 7 | ROOT=`readlink -f $(dirname $SCRIPT)/..` 8 | cd $ROOT 9 | 10 | VERSION="$1" 11 | ARCH="$2" 12 | CONTROL_FILE="$3" 13 | DESKTOP_FILE="$4" 14 | ICON_FILE="$5" 15 | DEB_PATH="$6" 16 | FILE_MODE=755 17 | 18 | TARGET_ROOT="`mktemp -d`" 19 | chmod $FILE_MODE "$TARGET_ROOT" 20 | TARGET="$TARGET_ROOT/atom-$VERSION-$ARCH" 21 | 22 | mkdir -m $FILE_MODE -p "$TARGET/usr" 23 | env INSTALL_PREFIX="$TARGET/usr" script/grunt install 24 | 25 | mkdir -m $FILE_MODE -p "$TARGET/DEBIAN" 26 | cp "$CONTROL_FILE" "$TARGET/DEBIAN/control" 27 | 28 | mkdir -m $FILE_MODE -p "$TARGET/usr/share/applications" 29 | cp "$DESKTOP_FILE" "$TARGET/usr/share/applications" 30 | 31 | mkdir -m $FILE_MODE -p "$TARGET/usr/share/pixmaps" 32 | cp "$ICON_FILE" "$TARGET/usr/share/pixmaps" 33 | 34 | # Copy generated LICENSE.md to /usr/share/doc/atom/copyright 35 | mkdir -m $FILE_MODE -p "$TARGET/usr/share/doc/atom" 36 | cp "$TARGET/usr/share/atom/resources/app/LICENSE.md" "$TARGET/usr/share/doc/atom/copyright" 37 | 38 | # Add lintian overrides 39 | mkdir -m $FILE_MODE -p "$TARGET/usr/share/lintian/overrides" 40 | cp "$ROOT/resources/linux/debian/lintian-overrides" "$TARGET/usr/share/lintian/overrides/atom" 41 | 42 | # Remove executable bit from .node files 43 | find "$TARGET" -type f -name "*.node" -exec chmod a-x {} \; 44 | 45 | fakeroot dpkg-deb -b "$TARGET" 46 | mv "$TARGET_ROOT/atom-$VERSION-$ARCH.deb" "$DEB_PATH" 47 | rm -rf "$TARGET_ROOT" 48 | -------------------------------------------------------------------------------- /src/notification.coffee: -------------------------------------------------------------------------------- 1 | {Emitter} = require 'event-kit' 2 | 3 | # Experimental: This will likely change, do not use. 4 | module.exports = 5 | class Notification 6 | constructor: (@type, @message, @options={}) -> 7 | @emitter = new Emitter 8 | @timestamp = new Date() 9 | @dismissed = true 10 | @dismissed = false if @isDismissable() 11 | @displayed = false 12 | 13 | onDidDismiss: (callback) -> 14 | @emitter.on 'did-dismiss', callback 15 | 16 | onDidDisplay: (callback) -> 17 | @emitter.on 'did-display', callback 18 | 19 | getOptions: -> @options 20 | 21 | getType: -> @type 22 | 23 | getMessage: -> @message 24 | 25 | getTimestamp: -> @timestamp 26 | 27 | getDetail: -> @options.detail 28 | 29 | isEqual: (other) -> 30 | @getMessage() == other.getMessage() \ 31 | and @getType() == other.getType() \ 32 | and @getDetail() == other.getDetail() 33 | 34 | dismiss: -> 35 | return unless @isDismissable() and not @isDismissed() 36 | @dismissed = true 37 | @emitter.emit 'did-dismiss', this 38 | 39 | isDismissed: -> @dismissed 40 | 41 | isDismissable: -> !!@options.dismissable 42 | 43 | wasDisplayed: -> @displayed 44 | 45 | setDisplayed: (@displayed) -> 46 | @emitter.emit 'did-display', this 47 | 48 | getIcon: -> 49 | return @options.icon if @options.icon? 50 | switch @type 51 | when 'fatal' then 'bug' 52 | when 'error' then 'flame' 53 | when 'warning' then 'alert' 54 | when 'info' then 'info' 55 | when 'success' then 'check' 56 | -------------------------------------------------------------------------------- /script/utils/child-process-wrapper.js: -------------------------------------------------------------------------------- 1 | var childProcess = require('child_process'); 2 | 3 | // Exit the process if the command failed and only call the callback if the 4 | // command succeed, output of the command would also be piped. 5 | exports.safeExec = function(command, options, callback) { 6 | if (!callback) { 7 | callback = options; 8 | options = {}; 9 | } 10 | if (!options) 11 | options = {}; 12 | 13 | // This needed to be increased for `apm test` runs that generate many failures 14 | // The default is 200KB. 15 | options.maxBuffer = 1024 * 1024; 16 | 17 | var child = childProcess.exec(command, options, function(error, stdout, stderr) { 18 | if (error) 19 | process.exit(error.code || 1); 20 | else 21 | callback(null); 22 | }); 23 | child.stderr.pipe(process.stderr); 24 | if (!options.ignoreStdout) 25 | child.stdout.pipe(process.stdout); 26 | } 27 | 28 | // Same with safeExec but call child_process.spawn instead. 29 | exports.safeSpawn = function(command, args, options, callback) { 30 | if (!callback) { 31 | callback = options; 32 | options = {}; 33 | } 34 | var child = childProcess.spawn(command, args, options); 35 | child.stderr.pipe(process.stderr); 36 | child.stdout.pipe(process.stdout); 37 | child.on('error', function(error) { 38 | console.error('Command \'' + command + '\' failed: ' + error.message); 39 | }); 40 | child.on('exit', function(code) { 41 | if (code != 0) 42 | process.exit(code); 43 | else 44 | callback(null); 45 | }); 46 | } 47 | -------------------------------------------------------------------------------- /script/clean: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var cp = require('./utils/child-process-wrapper.js'); 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | var os = require('os'); 6 | 7 | var removeCommand = process.platform === 'win32' ? 'rmdir /S /Q ' : 'rm -rf '; 8 | var productName = require('../package.json').productName; 9 | 10 | process.chdir(path.dirname(__dirname)); 11 | var home = process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME']; 12 | var tmpdir = os.tmpdir(); 13 | 14 | // Windows: Use START as a way to ignore error if Atom.exe isnt running 15 | var killatom = process.platform === 'win32' ? 'START taskkill /F /IM ' + productName + '.exe' : 'pkill -9 ' + productName + ' || true'; 16 | 17 | var commands = [ 18 | killatom, 19 | [__dirname, '..', 'node_modules'], 20 | [__dirname, '..', 'build', 'node_modules'], 21 | [__dirname, '..', 'apm', 'node_modules'], 22 | [__dirname, '..', 'atom-shell'], 23 | [home, '.atom', '.node-gyp'], 24 | [home, '.atom', 'storage'], 25 | [home, '.atom', '.npm'], 26 | [home, '.atom', 'compile-cache'], 27 | [home, '.atom', 'atom-shell'], 28 | [tmpdir, 'atom-build'], 29 | [tmpdir, 'atom-cached-atom-shells'], 30 | ]; 31 | var run = function() { 32 | var next = commands.shift(); 33 | if (!next) 34 | process.exit(0); 35 | 36 | if (Array.isArray(next)) { 37 | var pathToRemove = path.resolve.apply(path.resolve, next); 38 | if (fs.existsSync(pathToRemove)) 39 | next = removeCommand + pathToRemove; 40 | else 41 | return run(); 42 | } 43 | 44 | cp.safeExec(next, run); 45 | }; 46 | run(); 47 | -------------------------------------------------------------------------------- /spec/task-spec.coffee: -------------------------------------------------------------------------------- 1 | Task = require '../src/task' 2 | 3 | describe "Task", -> 4 | describe "@once(taskPath, args..., callback)", -> 5 | it "terminates the process after it completes", -> 6 | handlerResult = null 7 | task = Task.once require.resolve('./fixtures/task-spec-handler'), (result) -> 8 | handlerResult = result 9 | 10 | processClosed = false 11 | processErrored = false 12 | childProcess = task.childProcess 13 | spyOn(childProcess, 'kill').andCallThrough() 14 | task.childProcess.on 'error', -> processErrored = true 15 | 16 | waitsFor -> 17 | handlerResult? 18 | 19 | runs -> 20 | expect(handlerResult).toBe 'hello' 21 | expect(childProcess.kill).toHaveBeenCalled() 22 | expect(processErrored).toBe false 23 | 24 | it "calls listeners registered with ::on when events are emitted in the task", -> 25 | task = new Task(require.resolve('./fixtures/task-spec-handler')) 26 | 27 | eventSpy = jasmine.createSpy('eventSpy') 28 | task.on("some-event", eventSpy) 29 | 30 | waitsFor (done) -> task.start(done) 31 | 32 | runs -> 33 | expect(eventSpy).toHaveBeenCalledWith(1, 2, 3) 34 | 35 | it "unregisters listeners when the Disposable returned by ::on is disposed", -> 36 | task = new Task(require.resolve('./fixtures/task-spec-handler')) 37 | 38 | eventSpy = jasmine.createSpy('eventSpy') 39 | disposable = task.on("some-event", eventSpy) 40 | disposable.dispose() 41 | 42 | waitsFor (done) -> task.start(done) 43 | 44 | runs -> 45 | expect(eventSpy).not.toHaveBeenCalled() 46 | -------------------------------------------------------------------------------- /src/scope-descriptor.coffee: -------------------------------------------------------------------------------- 1 | # Extended: Wraps an {Array} of `String`s. The Array describes a path from the 2 | # root of the syntax tree to a token including _all_ scope names for the entire 3 | # path. 4 | # 5 | # Methods that take a `ScopeDescriptor` will also accept an {Array} of {Strings} 6 | # scope names e.g. `['.source.js']`. 7 | # 8 | # You can use `ScopeDescriptor`s to get language-specific config settings via 9 | # {Config::get}. 10 | # 11 | # You should not need to create a `ScopeDescriptor` directly. 12 | # 13 | # * {Editor::getRootScopeDescriptor} to get the language's descriptor. 14 | # * {Editor::scopeDescriptorForBufferPosition} to get the descriptor at a 15 | # specific position in the buffer. 16 | # * {Cursor::getScopeDescriptor} to get a cursor's descriptor based on position. 17 | # 18 | # See the [scopes and scope descriptor guide](https://atom.io/docs/v0.138.0/advanced/scopes-and-scope-descriptors) 19 | # for more information. 20 | module.exports = 21 | class ScopeDescriptor 22 | @fromObject: (scopes) -> 23 | if scopes instanceof ScopeDescriptor 24 | scopes 25 | else 26 | new ScopeDescriptor({scopes}) 27 | 28 | ### 29 | Section: Construction and Destruction 30 | ### 31 | 32 | # Public: Create a {ScopeDescriptor} object. 33 | # 34 | # * `object` {Object} 35 | # * `scopes` {Array} of {String}s 36 | constructor: ({@scopes}) -> 37 | 38 | # Public: Returns an {Array} of {String}s 39 | getScopesArray: -> @scopes 40 | 41 | getScopeChain: -> 42 | @scopes 43 | .map (scope) -> 44 | scope = ".#{scope}" unless scope[0] is '.' 45 | scope 46 | .join(' ') 47 | -------------------------------------------------------------------------------- /src/notification-manager.coffee: -------------------------------------------------------------------------------- 1 | {Emitter, Disposable} = require 'event-kit' 2 | Notification = require '../src/notification' 3 | 4 | # Experimental: Allows messaging the user. This will likely change, dont use 5 | # quite yet! 6 | module.exports = 7 | class NotificationManager 8 | constructor: -> 9 | @notifications = [] 10 | @emitter = new Emitter 11 | 12 | ### 13 | Section: Events 14 | ### 15 | 16 | onDidAddNotification: (callback) -> 17 | @emitter.on 'did-add-notification', callback 18 | 19 | ### 20 | Section: Adding Notifications 21 | ### 22 | 23 | addSuccess: (message, options) -> 24 | @addNotification(new Notification('success', message, options)) 25 | 26 | addInfo: (message, options) -> 27 | @addNotification(new Notification('info', message, options)) 28 | 29 | addWarning: (message, options) -> 30 | @addNotification(new Notification('warning', message, options)) 31 | 32 | addError: (message, options) -> 33 | @addNotification(new Notification('error', message, options)) 34 | 35 | addFatalError: (message, options) -> 36 | @addNotification(new Notification('fatal', message, options)) 37 | 38 | add: (type, message, options) -> 39 | @addNotification(new Notification(type, message, options)) 40 | 41 | addNotification: (notification) -> 42 | @notifications.push(notification) 43 | @emitter.emit('did-add-notification', notification) 44 | notification 45 | 46 | ### 47 | Section: Getting Notifications 48 | ### 49 | 50 | getNotifications: -> @notifications 51 | 52 | ### 53 | Section: Managing Notifications 54 | ### 55 | 56 | clear: -> 57 | @notifications = [] 58 | -------------------------------------------------------------------------------- /src/browser/atom-protocol-handler.coffee: -------------------------------------------------------------------------------- 1 | app = require 'app' 2 | fs = require 'fs' 3 | path = require 'path' 4 | protocol = require 'protocol' 5 | 6 | # Handles requests with 'atom' protocol. 7 | # 8 | # It's created by {AtomApplication} upon instantiation and is used to create a 9 | # custom resource loader for 'atom://' URLs. 10 | # 11 | # The following directories are searched in order: 12 | # * ~/.atom/assets 13 | # * ~/.atom/dev/packages (unless in safe mode) 14 | # * ~/.atom/packages 15 | # * RESOURCE_PATH/node_modules 16 | # 17 | module.exports = 18 | class AtomProtocolHandler 19 | constructor: (resourcePath, safeMode) -> 20 | @loadPaths = [] 21 | @dotAtomDirectory = path.join(app.getHomeDir(), '.atom') 22 | 23 | unless safeMode 24 | @loadPaths.push(path.join(@dotAtomDirectory, 'dev', 'packages')) 25 | 26 | @loadPaths.push(path.join(@dotAtomDirectory, 'packages')) 27 | @loadPaths.push(path.join(resourcePath, 'node_modules')) 28 | 29 | @registerAtomProtocol() 30 | 31 | # Creates the 'atom' custom protocol handler. 32 | registerAtomProtocol: -> 33 | protocol.registerProtocol 'atom', (request) => 34 | relativePath = path.normalize(request.url.substr(7)) 35 | 36 | if relativePath.indexOf('assets/') is 0 37 | assetsPath = path.join(@dotAtomDirectory, relativePath) 38 | filePath = assetsPath if fs.statSyncNoException(assetsPath).isFile?() 39 | 40 | unless filePath 41 | for loadPath in @loadPaths 42 | filePath = path.join(loadPath, relativePath) 43 | break if fs.statSyncNoException(filePath).isFile?() 44 | 45 | new protocol.RequestFileJob(filePath) 46 | -------------------------------------------------------------------------------- /src/pane-axis-element.coffee: -------------------------------------------------------------------------------- 1 | {CompositeDisposable} = require 'event-kit' 2 | {callAttachHooks} = require './space-pen-extensions' 3 | 4 | class PaneAxisElement extends HTMLElement 5 | createdCallback: -> 6 | @subscriptions = new CompositeDisposable 7 | 8 | detachedCallback: -> 9 | @subscriptions.dispose() 10 | 11 | initialize: (@model) -> 12 | @subscriptions.add @model.onDidAddChild(@childAdded.bind(this)) 13 | @subscriptions.add @model.onDidRemoveChild(@childRemoved.bind(this)) 14 | @subscriptions.add @model.onDidReplaceChild(@childReplaced.bind(this)) 15 | 16 | @childAdded({child, index}) for child, index in @model.getChildren() 17 | 18 | switch @model.getOrientation() 19 | when 'horizontal' 20 | @classList.add('horizontal', 'pane-row') 21 | when 'vertical' 22 | @classList.add('vertical', 'pane-column') 23 | this 24 | 25 | childAdded: ({child, index}) -> 26 | view = atom.views.getView(child) 27 | @insertBefore(view, @children[index]) 28 | callAttachHooks(view) # for backward compatibility with SpacePen views 29 | 30 | childRemoved: ({child}) -> 31 | view = atom.views.getView(child) 32 | view.remove() 33 | 34 | childReplaced: ({index, oldChild, newChild}) -> 35 | focusedElement = document.activeElement if @hasFocus() 36 | @childRemoved({child: oldChild, index}) 37 | @childAdded({child: newChild, index}) 38 | focusedElement?.focus() if document.activeElement is document.body 39 | 40 | hasFocus: -> 41 | this is document.activeElement or @contains(document.activeElement) 42 | 43 | module.exports = PaneAxisElement = document.registerElement 'atom-pane-axis', prototype: PaneAxisElement.prototype 44 | -------------------------------------------------------------------------------- /spec/6to5-spec.coffee: -------------------------------------------------------------------------------- 1 | to5 = require '../src/6to5' 2 | crypto = require 'crypto' 3 | 4 | describe "6to5 transpiler support", -> 5 | describe "::create6to5VersionAndOptionsDigest", -> 6 | it "returns a digest for the library version and specified options", -> 7 | defaultOptions = 8 | blacklist: [ 9 | 'useStrict' 10 | ] 11 | experimental: true 12 | optional: [ 13 | 'asyncToGenerator' 14 | ] 15 | reactCompat: true 16 | sourceMap: 'inline' 17 | version = '3.0.14' 18 | shasum = crypto.createHash('sha1') 19 | shasum.update('6to5-core', 'utf8') 20 | shasum.update('\0', 'utf8') 21 | shasum.update(version, 'utf8') 22 | shasum.update('\0', 'utf8') 23 | shasum.update('{"blacklist": ["useStrict",],"experimental": true,"optional": ["asyncToGenerator",],"reactCompat": true,"sourceMap": "inline",}') 24 | expectedDigest = shasum.digest('hex') 25 | 26 | observedDigest = to5.create6to5VersionAndOptionsDigest(version, defaultOptions) 27 | expect(observedDigest).toEqual expectedDigest 28 | 29 | describe "when a .js file starts with 'use 6to5';", -> 30 | it "transpiles it using 6to5", -> 31 | transpiled = require('./fixtures/6to5/single-quotes.js') 32 | expect(transpiled(3)).toBe 4 33 | 34 | describe 'when a .js file starts with "use 6to5";', -> 35 | it "transpiles it using 6to5", -> 36 | transpiled = require('./fixtures/6to5/double-quotes.js') 37 | expect(transpiled(3)).toBe 4 38 | 39 | describe "when a .js file does not start with 'use 6to6';", -> 40 | it "does not transpile it using 6to5", -> 41 | expect(-> require('./fixtures/6to5/invalid.js')).toThrow() 42 | -------------------------------------------------------------------------------- /script/utils/translate-crash-log-addresses.coffee: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env coffee 2 | # Usage: 3 | # Copy the crash log into pasteboard and then run 4 | # pbpaste | ./script/translate-crash-log-addresses.coffee 5 | 6 | atos = (addresses, callback) -> 7 | path = require 'path' 8 | exec = require('child_process').exec 9 | 10 | cwd = path.join __dirname, '..' 11 | exec 'atos -o cef/Release/libcef.dylib -arch i386 '.concat(addresses...), cwd: cwd, (error, stdout, stderr) -> 12 | throw error if error? 13 | callback stdout.split('\n') 14 | 15 | parse_stack_trace = (raw) -> 16 | lines = {} 17 | addresses = [] 18 | for line in raw 19 | columns = line.split /\ +/ 20 | if columns[1] == 'libcef.dylib' and /0x[a-f0-9]+/.test columns[3] 21 | lines[columns[0]] = addresses.length 22 | addresses.push '0x' + parseInt(columns[5]).toString(16) + ' ' 23 | 24 | atos addresses, (parsed) -> 25 | for line in raw 26 | columns = line.split /\ +/ 27 | frame = columns[0] 28 | if lines[frame]? 29 | console.log frame, parsed[lines[frame]] 30 | else 31 | console.log line 32 | 33 | parse_log_file = (content) -> 34 | state = 'start' 35 | stack_trace = [] 36 | lines = content.split /\r?\n/ 37 | 38 | for line in lines 39 | if state == 'start' 40 | if /Thread \d+ Crashed::/.test line 41 | console.log line 42 | state = 'parse' 43 | else if state == 'parse' 44 | break if line == '' 45 | stack_trace.push line 46 | 47 | parse_stack_trace stack_trace 48 | 49 | input = '' 50 | process.stdin.resume() 51 | process.stdin.setEncoding 'utf8' 52 | process.stdin.on 'data', (chunk) -> 53 | input += chunk 54 | process.stdin.on 'end', -> 55 | parse_log_file input 56 | 57 | -------------------------------------------------------------------------------- /src/clipboard.coffee: -------------------------------------------------------------------------------- 1 | clipboard = require 'clipboard' 2 | crypto = require 'crypto' 3 | 4 | # Extended: Represents the clipboard used for copying and pasting in Atom. 5 | # 6 | # An instance of this class is always available as the `atom.clipboard` global. 7 | # 8 | # ## Examples 9 | # 10 | # ```coffee 11 | # atom.clipboard.write('hello') 12 | # 13 | # console.log(atom.clipboard.read()) # 'hello' 14 | # ``` 15 | module.exports = 16 | class Clipboard 17 | metadata: null 18 | signatureForMetadata: null 19 | 20 | # Creates an `md5` hash of some text. 21 | # 22 | # * `text` A {String} to hash. 23 | # 24 | # Returns a hashed {String}. 25 | md5: (text) -> 26 | crypto.createHash('md5').update(text, 'utf8').digest('hex') 27 | 28 | # Public: Write the given text to the clipboard. 29 | # 30 | # The metadata associated with the text is available by calling 31 | # {::readWithMetadata}. 32 | # 33 | # * `text` The {String} to store. 34 | # * `metadata` The additional info to associate with the text. 35 | write: (text, metadata) -> 36 | @signatureForMetadata = @md5(text) 37 | @metadata = metadata 38 | clipboard.writeText(text) 39 | 40 | # Public: Read the text from the clipboard. 41 | # 42 | # Returns a {String}. 43 | read: -> 44 | clipboard.readText() 45 | 46 | # Public: Read the text from the clipboard and return both the text and the 47 | # associated metadata. 48 | # 49 | # Returns an {Object} with the following keys: 50 | # * `text` The {String} clipboard text. 51 | # * `metadata` The metadata stored by an earlier call to {::write}. 52 | readWithMetadata: -> 53 | text = @read() 54 | if @signatureForMetadata is @md5(text) 55 | {text, @metadata} 56 | else 57 | {text} 58 | -------------------------------------------------------------------------------- /src/panel-container-element.coffee: -------------------------------------------------------------------------------- 1 | {CompositeDisposable} = require 'event-kit' 2 | 3 | class PanelContainerElement extends HTMLElement 4 | createdCallback: -> 5 | @subscriptions = new CompositeDisposable 6 | 7 | initialize: (@model) -> 8 | @subscriptions.add @model.onDidAddPanel(@panelAdded.bind(this)) 9 | @subscriptions.add @model.onDidRemovePanel(@panelRemoved.bind(this)) 10 | @subscriptions.add @model.onDidDestroy(@destroyed.bind(this)) 11 | @classList.add(@model.getLocation()) 12 | this 13 | 14 | getModel: -> @model 15 | 16 | panelAdded: ({panel, index}) -> 17 | panelElement = atom.views.getView(panel) 18 | panelElement.classList.add(@model.getLocation()) 19 | if @model.isModal() 20 | panelElement.classList.add("overlay", "from-top") 21 | else 22 | panelElement.classList.add("tool-panel", "panel-#{@model.getLocation()}") 23 | 24 | if index >= @childNodes.length 25 | @appendChild(panelElement) 26 | else 27 | referenceItem = @childNodes[index] 28 | @insertBefore(panelElement, referenceItem) 29 | 30 | if @model.isModal() 31 | @hideAllPanelsExcept(panel) 32 | @subscriptions.add panel.onDidChangeVisible (visible) => 33 | @hideAllPanelsExcept(panel) if visible 34 | 35 | panelRemoved: ({panel, index}) -> 36 | @removeChild(atom.views.getView(panel)) 37 | 38 | destroyed: -> 39 | @subscriptions.dispose() 40 | @parentNode?.removeChild(this) 41 | 42 | hideAllPanelsExcept: (excludedPanel) -> 43 | for panel in @model.getPanels() 44 | panel.hide() unless panel is excludedPanel 45 | return 46 | 47 | module.exports = PanelContainerElement = document.registerElement 'atom-panel-container', prototype: PanelContainerElement.prototype 48 | -------------------------------------------------------------------------------- /spec/jasmine-helper.coffee: -------------------------------------------------------------------------------- 1 | fs = require 'fs' 2 | 3 | module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) -> 4 | {$, $$} = require '../src/space-pen-extensions' 5 | 6 | window[key] = value for key, value of require '../vendor/jasmine' 7 | 8 | {TerminalReporter} = require 'jasmine-tagged' 9 | 10 | disableFocusMethods() if process.env.JANKY_SHA1 11 | 12 | TimeReporter = require './time-reporter' 13 | timeReporter = new TimeReporter() 14 | 15 | logStream = fs.openSync(logFile, 'w') if logFile? 16 | log = (str) -> 17 | if logStream? 18 | fs.writeSync(logStream, str) 19 | else 20 | process.stderr.write(str) 21 | 22 | if atom.getLoadSettings().exitWhenDone 23 | reporter = new TerminalReporter 24 | print: (str) -> 25 | log(str) 26 | onComplete: (runner) -> 27 | fs.closeSync(logStream) if logStream? 28 | if process.env.JANKY_SHA1 29 | grim = require 'grim' 30 | grim.logDeprecations() if grim.getDeprecationsLength() > 0 31 | atom.exit(runner.results().failedCount > 0 ? 1 : 0) 32 | else 33 | AtomReporter = require './atom-reporter' 34 | reporter = new AtomReporter() 35 | 36 | require specSuite 37 | 38 | jasmineEnv = jasmine.getEnv() 39 | jasmineEnv.addReporter(reporter) 40 | jasmineEnv.addReporter(timeReporter) 41 | jasmineEnv.setIncludedTags([process.platform]) 42 | 43 | $('body').append $$ -> @div id: 'jasmine-content' 44 | 45 | jasmineEnv.execute() 46 | 47 | disableFocusMethods = -> 48 | ['fdescribe', 'ffdescribe', 'fffdescribe', 'fit', 'ffit', 'fffit'].forEach (methodName) -> 49 | focusMethod = window[methodName] 50 | window[methodName] = (description) -> 51 | error = new Error('Focused spec is running on CI') 52 | focusMethod description, -> throw error 53 | -------------------------------------------------------------------------------- /spec/tokenized-line-spec.coffee: -------------------------------------------------------------------------------- 1 | describe "TokenizedLine", -> 2 | editor = null 3 | 4 | beforeEach -> 5 | waitsForPromise -> atom.packages.activatePackage('language-coffee-script') 6 | 7 | describe "::isOnlyWhitespace()", -> 8 | beforeEach -> 9 | waitsForPromise -> 10 | atom.project.open('coffee.coffee').then (o) -> editor = o 11 | 12 | it "returns true when the line is only whitespace", -> 13 | expect(editor.tokenizedLineForScreenRow(3).isOnlyWhitespace()).toBe true 14 | expect(editor.tokenizedLineForScreenRow(7).isOnlyWhitespace()).toBe true 15 | expect(editor.tokenizedLineForScreenRow(23).isOnlyWhitespace()).toBe true 16 | 17 | it "returns false when the line is not only whitespace", -> 18 | expect(editor.tokenizedLineForScreenRow(0).isOnlyWhitespace()).toBe false 19 | expect(editor.tokenizedLineForScreenRow(2).isOnlyWhitespace()).toBe false 20 | 21 | describe "::getScopeTree()", -> 22 | it "returns a tree whose inner nodes are scopeDescriptor and whose leaf nodes are tokens in those scopeDescriptor", -> 23 | [tokens, tokenIndex] = [] 24 | 25 | ensureValidScopeTree = (scopeTree, scopeDescriptor=[]) -> 26 | if scopeTree.children? 27 | for child in scopeTree.children 28 | ensureValidScopeTree(child, scopeDescriptor.concat([scopeTree.scope])) 29 | else 30 | expect(scopeTree).toBe tokens[tokenIndex++] 31 | expect(scopeDescriptor).toEqual scopeTree.scopes 32 | 33 | waitsForPromise -> 34 | atom.project.open('coffee.coffee').then (o) -> editor = o 35 | 36 | runs -> 37 | tokenIndex = 0 38 | tokens = editor.tokenizedLineForScreenRow(1).tokens 39 | scopeTree = editor.tokenizedLineForScreenRow(1).getScopeTree() 40 | ensureValidScopeTree(scopeTree) 41 | -------------------------------------------------------------------------------- /src/overlay-manager.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | class OverlayManager 3 | constructor: (@container) -> 4 | @overlays = {} 5 | 6 | render: (props) -> 7 | {editor, overlayDecorations, lineHeightInPixels} = props 8 | 9 | existingDecorations = null 10 | for markerId, {headPixelPosition, tailPixelPosition, decorations} of overlayDecorations 11 | for decoration in decorations 12 | pixelPosition = 13 | if decoration.position is 'tail' then tailPixelPosition else headPixelPosition 14 | 15 | @renderOverlay(editor, decoration, pixelPosition, lineHeightInPixels) 16 | 17 | existingDecorations ?= {} 18 | existingDecorations[decoration.id] = true 19 | 20 | for id, overlay of @overlays 21 | unless existingDecorations? and id of existingDecorations 22 | @container.removeChild(overlay) 23 | delete @overlays[id] 24 | 25 | return 26 | 27 | renderOverlay: (editor, decoration, pixelPosition, lineHeightInPixels) -> 28 | item = atom.views.getView(decoration.item) 29 | unless overlay = @overlays[decoration.id] 30 | overlay = @overlays[decoration.id] = document.createElement('atom-overlay') 31 | overlay.appendChild(item) 32 | @container.appendChild(overlay) 33 | 34 | itemWidth = item.offsetWidth 35 | itemHeight = item.offsetHeight 36 | 37 | left = pixelPosition.left 38 | if left + itemWidth - editor.getScrollLeft() > editor.getWidth() and left - itemWidth >= editor.getScrollLeft() 39 | left -= itemWidth 40 | 41 | top = pixelPosition.top + lineHeightInPixels 42 | if top + itemHeight - editor.getScrollTop() > editor.getHeight() and top - itemHeight - lineHeightInPixels >= editor.getScrollTop() 43 | top -= itemHeight + lineHeightInPixels 44 | 45 | overlay.style.top = top + 'px' 46 | overlay.style.left = left + 'px' 47 | -------------------------------------------------------------------------------- /benchmark/browser-process-startup.coffee: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env coffee 2 | 3 | {spawn, exec} = require 'child_process' 4 | fs = require 'fs' 5 | os = require 'os' 6 | path = require 'path' 7 | _ = require 'underscore-plus' 8 | temp = require 'temp' 9 | 10 | directoryToOpen = temp.mkdirSync('browser-process-startup-') 11 | socketPath = path.join(os.tmpdir(), 'atom.sock') 12 | numberOfRuns = 10 13 | 14 | deleteSocketFile = -> 15 | try 16 | fs.unlinkSync(socketPath) if fs.existsSync(socketPath) 17 | catch error 18 | console.error(error) 19 | 20 | launchAtom = (callback) -> 21 | deleteSocketFile() 22 | 23 | cmd = 'atom' 24 | args = ['--safe', '--new-window', '--foreground', directoryToOpen] 25 | atomProcess = spawn(cmd, args) 26 | 27 | output = '' 28 | startupTimes = [] 29 | dataListener = (data) -> 30 | output += data 31 | if match = /App load time: (\d+)/.exec(output) 32 | startupTime = parseInt(match[1]) 33 | atomProcess.stderr.removeListener 'data', dataListener 34 | atomProcess.kill() 35 | exec 'pkill -9 Atom', (error) -> 36 | console.error(error) if error? 37 | callback(startupTime) 38 | 39 | atomProcess.stderr.on 'data', dataListener 40 | 41 | startupTimes = [] 42 | collector = (startupTime) -> 43 | startupTimes.push(startupTime) 44 | if startupTimes.length < numberOfRuns 45 | launchAtom(collector) 46 | else 47 | maxTime = _.max(startupTimes) 48 | minTime = _.min(startupTimes) 49 | totalTime = startupTimes.reduce (previousValue=0, currentValue) -> previousValue + currentValue 50 | console.log "Startup Runs: #{startupTimes.length}" 51 | console.log "First run time: #{startupTimes[0]}ms" 52 | console.log "Max time: #{maxTime}ms" 53 | console.log "Min time: #{minTime}ms" 54 | console.log "Average time: #{Math.round(totalTime/startupTimes.length)}ms" 55 | 56 | launchAtom(collector) 57 | -------------------------------------------------------------------------------- /docs/upgrading/upgrading-your-syntax-theme.md: -------------------------------------------------------------------------------- 1 | # Upgrading Your Syntax Theme 2 | 3 | Text editor content is now rendered in the shadow DOM, which shields it from being styled by global style sheets to protect against accidental style pollution. For more background on the shadow DOM, check out the [Shadow DOM 101][shadow-dom-101] on HTML 5 Rocks. 4 | 5 | Syntax themes are specifically intended to style only text editor content, so they are automatically loaded directly into the text editor's shadow DOM when it is enabled. This happens automatically when the the theme's `package.json` contains a `theme: "syntax"` declaration, so you don't need to change anything to target the appropriate context. 6 | 7 | When theme style sheets are loaded into the text editor's shadow DOM, selectors intended to target the editor from the *outside* no longer make sense. Styles targeting the `.editor` and `.editor-colors` classes instead need to target the `:host` pseudo-element, which matches against the containing `atom-text-editor` node. Check out the [Shadow DOM 201][host-pseudo-element] article for more information about the `:host` pseudo-element. 8 | 9 | Here's an example from Atom's light syntax theme. Note that the `atom-text-editor` selector intended to target the editor from the outside has been retained to allow the theme to keep working during the transition phase when it is possible to disable the shadow DOM. 10 | 11 | ```css 12 | atom-text-editor, :host { /* :host added */ 13 | background-color: @syntax-background-color; 14 | color: @syntax-text-color; 15 | 16 | .invisible-character { 17 | color: @syntax-invisible-character-color; 18 | } 19 | /* more nested selectors... */ 20 | } 21 | ``` 22 | 23 | [shadow-dom-101]: http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom 24 | [host-pseudo-element]: http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201#toc-style-host 25 | -------------------------------------------------------------------------------- /docs/converting-a-text-mate-bundle.md: -------------------------------------------------------------------------------- 1 | ## Converting a TextMate Bundle 2 | 3 | This guide will show you how to convert a [TextMate][TextMate] bundle to an 4 | Atom package. 5 | 6 | Converting a TextMate bundle will allow you to use its editor preferences, 7 | snippets, and colorization inside Atom. 8 | 9 | ### Install apm 10 | 11 | The `apm` command line utility that ships with Atom supports converting 12 | a TextMate bundle to an Atom package. 13 | 14 | Check that you have `apm` installed by running the following command in your 15 | terminal: 16 | 17 | ```sh 18 | apm help init 19 | ``` 20 | 21 | You should see a message print out with details about the `apm init` command. 22 | 23 | If you do not, launch Atom and run the _Atom > Install Shell Commands_ menu 24 | to install the `apm` and `atom` commands. 25 | 26 | ### Convert the Package 27 | 28 | Let's convert the TextMate bundle for the [R][R] programming language. You can find other existing TextMate bundles [here][TextMateOrg]. 29 | 30 | You can convert the R bundle with the following command: 31 | 32 | ```sh 33 | apm init --package ~/.atom/packages/language-r --convert https://github.com/textmate/r.tmbundle 34 | ``` 35 | 36 | You can now browse to `~/.atom/packages/language-r` to see the converted bundle. 37 | 38 | :tada: Your new package is now ready to use, launch Atom and open a `.r` file in 39 | the editor to see it in action! 40 | 41 | ### Further Reading 42 | 43 | * Check out [Publishing a Package](publishing-a-package.html) for more information 44 | on publishing the package you just created to [atom.io][atomio]. 45 | 46 | [atomio]: https://atom.io 47 | [CSS]: https://en.wikipedia.org/wiki/Cascading_Style_Sheets 48 | [Less]: http://lesscss.org 49 | [plist]: https://en.wikipedia.org/wiki/Property_list 50 | [R]: https://en.wikipedia.org/wiki/R_(programming_language) 51 | [TextMate]: http://macromates.com 52 | [TextMateOrg]: https://github.com/textmate 53 | -------------------------------------------------------------------------------- /src/browser/auto-updater-win32.coffee: -------------------------------------------------------------------------------- 1 | {EventEmitter} = require 'events' 2 | _ = require 'underscore-plus' 3 | SquirrelUpdate = require './squirrel-update' 4 | 5 | class AutoUpdater 6 | _.extend @prototype, EventEmitter.prototype 7 | 8 | setFeedUrl: (@updateUrl) -> 9 | 10 | quitAndInstall: -> 11 | if SquirrelUpdate.existsSync() 12 | SquirrelUpdate.restartAtom(require('app')) 13 | else 14 | require('auto-updater').quitAndInstall() 15 | 16 | downloadUpdate: (callback) -> 17 | SquirrelUpdate.spawn ['--download', @updateUrl], (error, stdout) -> 18 | return callback(error) if error? 19 | 20 | try 21 | # Last line of output is the JSON details about the releases 22 | json = stdout.trim().split('\n').pop() 23 | update = JSON.parse(json)?.releasesToApply?.pop?() 24 | catch error 25 | error.stdout = stdout 26 | return callback(error) 27 | 28 | callback(null, update) 29 | 30 | installUpdate: (callback) -> 31 | SquirrelUpdate.spawn(['--update', @updateUrl], callback) 32 | 33 | supportsUpdates: -> 34 | SquirrelUpdate.existsSync() 35 | 36 | checkForUpdates: -> 37 | throw new Error('Update URL is not set') unless @updateUrl 38 | 39 | @emit 'checking-for-update' 40 | 41 | unless SquirrelUpdate.existsSync() 42 | @emit 'update-not-available' 43 | return 44 | 45 | @downloadUpdate (error, update) => 46 | if error? 47 | @emit 'update-not-available' 48 | return 49 | 50 | unless update? 51 | @emit 'update-not-available' 52 | return 53 | 54 | @installUpdate (error) => 55 | if error? 56 | @emit 'update-not-available' 57 | return 58 | 59 | @emit 'update-available' 60 | @emit 'update-downloaded', {}, update.releaseNotes, update.version, new Date(), 'https://atom.io', => @quitAndInstall() 61 | 62 | module.exports = new AutoUpdater() 63 | -------------------------------------------------------------------------------- /src/panel-container.coffee: -------------------------------------------------------------------------------- 1 | {Emitter, CompositeDisposable} = require 'event-kit' 2 | 3 | module.exports = 4 | class PanelContainer 5 | constructor: ({@location}={}) -> 6 | @emitter = new Emitter 7 | @subscriptions = new CompositeDisposable 8 | @panels = [] 9 | 10 | destroy: -> 11 | panel.destroy() for panel in @getPanels() 12 | @subscriptions.dispose() 13 | @emitter.emit 'did-destroy', this 14 | @emitter.dispose() 15 | 16 | ### 17 | Section: Event Subscription 18 | ### 19 | 20 | onDidAddPanel: (callback) -> 21 | @emitter.on 'did-add-panel', callback 22 | 23 | onDidRemovePanel: (callback) -> 24 | @emitter.on 'did-remove-panel', callback 25 | 26 | onDidDestroy: (callback) -> 27 | @emitter.on 'did-destroy', callback 28 | 29 | ### 30 | Section: Panels 31 | ### 32 | 33 | getLocation: -> @location 34 | 35 | isModal: -> @location is 'modal' 36 | 37 | getPanels: -> @panels 38 | 39 | addPanel: (panel) -> 40 | @subscriptions.add panel.onDidDestroy(@panelDestroyed.bind(this)) 41 | 42 | index = @getPanelIndex(panel) 43 | if index is @panels.length 44 | @panels.push(panel) 45 | else 46 | @panels.splice(index, 0, panel) 47 | 48 | @emitter.emit 'did-add-panel', {panel, index} 49 | panel 50 | 51 | panelForItem: (item) -> 52 | for panel in @panels 53 | return panel if panel.getItem() is item 54 | null 55 | 56 | panelDestroyed: (panel) -> 57 | index = @panels.indexOf(panel) 58 | if index > -1 59 | @panels.splice(index, 1) 60 | @emitter.emit 'did-remove-panel', {panel, index} 61 | 62 | getPanelIndex: (panel) -> 63 | priority = panel.getPriority() 64 | if @location in ['bottom', 'right'] 65 | for p, i in @panels by -1 66 | return i + 1 if priority < p.getPriority() 67 | 0 68 | else 69 | for p, i in @panels 70 | return i if priority < p.getPriority() 71 | @panels.length 72 | -------------------------------------------------------------------------------- /spec/notification-spec.coffee: -------------------------------------------------------------------------------- 1 | Notification = require '../src/notification' 2 | 3 | describe "Notification", -> 4 | [notification] = [] 5 | 6 | describe "::getTimestamp()", -> 7 | it "returns a Date object", -> 8 | notification = new Notification('error', 'message!') 9 | expect(notification.getTimestamp() instanceof Date).toBe true 10 | 11 | describe "::getIcon()", -> 12 | it "returns a default when no icon specified", -> 13 | notification = new Notification('error', 'message!') 14 | expect(notification.getIcon()).toBe 'flame' 15 | 16 | it "returns the icon specified", -> 17 | notification = new Notification('error', 'message!', icon: 'my-icon') 18 | expect(notification.getIcon()).toBe 'my-icon' 19 | 20 | describe "dismissing notifications", -> 21 | describe "when the notfication is dismissable", -> 22 | it "calls a callback when the notification is dismissed", -> 23 | dismissedSpy = jasmine.createSpy() 24 | notification = new Notification('error', 'message', dismissable: true) 25 | notification.onDidDismiss dismissedSpy 26 | 27 | expect(notification.isDismissable()).toBe true 28 | expect(notification.isDismissed()).toBe false 29 | 30 | notification.dismiss() 31 | 32 | expect(dismissedSpy).toHaveBeenCalled() 33 | expect(notification.isDismissed()).toBe true 34 | 35 | describe "when the notfication is not dismissable", -> 36 | it "does nothing when ::dismiss() is called", -> 37 | dismissedSpy = jasmine.createSpy() 38 | notification = new Notification('error', 'message') 39 | notification.onDidDismiss dismissedSpy 40 | 41 | expect(notification.isDismissable()).toBe false 42 | expect(notification.isDismissed()).toBe true 43 | 44 | notification.dismiss() 45 | 46 | expect(dismissedSpy).not.toHaveBeenCalled() 47 | expect(notification.isDismissed()).toBe true 48 | -------------------------------------------------------------------------------- /src/menu-helpers.coffee: -------------------------------------------------------------------------------- 1 | _ = require 'underscore-plus' 2 | 3 | ItemSpecificities = new WeakMap 4 | 5 | merge = (menu, item, itemSpecificity=Infinity) -> 6 | item = cloneMenuItem(item) 7 | ItemSpecificities.set(item, itemSpecificity) if itemSpecificity 8 | matchingItemIndex = findMatchingItemIndex(menu, item) 9 | matchingItem = menu[matchingItemIndex] unless matchingItemIndex is - 1 10 | 11 | if matchingItem? 12 | if item.submenu? 13 | merge(matchingItem.submenu, submenuItem, itemSpecificity) for submenuItem in item.submenu 14 | else if itemSpecificity 15 | unless itemSpecificity < ItemSpecificities.get(matchingItem) 16 | menu[matchingItemIndex] = item 17 | else unless item.type is 'separator' and _.last(menu)?.type is 'separator' 18 | menu.push(item) 19 | 20 | unmerge = (menu, item) -> 21 | matchingItemIndex = findMatchingItemIndex(menu, item) 22 | matchingItem = menu[matchingItemIndex] unless matchingItemIndex is - 1 23 | 24 | if matchingItem? 25 | if item.submenu? 26 | unmerge(matchingItem.submenu, submenuItem) for submenuItem in item.submenu 27 | 28 | unless matchingItem.submenu?.length > 0 29 | menu.splice(matchingItemIndex, 1) 30 | 31 | findMatchingItemIndex = (menu, {type, label, submenu}) -> 32 | return -1 if type is 'separator' 33 | for item, index in menu 34 | if normalizeLabel(item.label) is normalizeLabel(label) and item.submenu? is submenu? 35 | return index 36 | -1 37 | 38 | normalizeLabel = (label) -> 39 | return undefined unless label? 40 | 41 | if process.platform is 'darwin' 42 | label 43 | else 44 | label.replace(/\&/g, '') 45 | 46 | cloneMenuItem = (item) -> 47 | item = _.pick(item, 'type', 'label', 'enabled', 'visible', 'command', 'submenu', 'commandDetail') 48 | if item.submenu? 49 | item.submenu = item.submenu.map (submenuItem) -> cloneMenuItem(submenuItem) 50 | item 51 | 52 | module.exports = {merge, unmerge, normalizeLabel, cloneMenuItem} 53 | -------------------------------------------------------------------------------- /spec/spec-suite.coffee: -------------------------------------------------------------------------------- 1 | _ = require 'underscore-plus' 2 | fs = require 'fs-plus' 3 | path = require 'path' 4 | require './spec-helper' 5 | 6 | requireSpecs = (specDirectory, specType) -> 7 | for specFilePath in fs.listTreeSync(specDirectory) when /-spec\.(coffee|js)$/.test specFilePath 8 | require specFilePath 9 | 10 | # Set spec directory on spec for setting up the project in spec-helper 11 | setSpecDirectory(specDirectory) 12 | 13 | setSpecField = (name, value) -> 14 | specs = jasmine.getEnv().currentRunner().specs() 15 | return if specs.length is 0 16 | for index in [specs.length-1..0] 17 | break if specs[index][name]? 18 | specs[index][name] = value 19 | 20 | setSpecType = (specType) -> 21 | setSpecField('specType', specType) 22 | 23 | setSpecDirectory = (specDirectory) -> 24 | setSpecField('specDirectory', specDirectory) 25 | 26 | runAllSpecs = -> 27 | {resourcePath} = atom.getLoadSettings() 28 | 29 | requireSpecs(path.join(resourcePath, 'spec')) 30 | setSpecType('core') 31 | 32 | fixturesPackagesPath = path.join(__dirname, 'fixtures', 'packages') 33 | packagePaths = atom.packages.getAvailablePackageNames().map (packageName) -> 34 | atom.packages.resolvePackagePath(packageName) 35 | packagePaths = _.groupBy packagePaths, (packagePath) -> 36 | if packagePath.indexOf("#{fixturesPackagesPath}#{path.sep}") is 0 37 | 'fixtures' 38 | else if packagePath.indexOf("#{resourcePath}#{path.sep}") is 0 39 | 'bundled' 40 | else 41 | 'user' 42 | 43 | # Run bundled package specs 44 | requireSpecs(path.join(packagePath, 'spec')) for packagePath in packagePaths.bundled ? [] 45 | setSpecType('bundled') 46 | 47 | # Run user package specs 48 | requireSpecs(path.join(packagePath, 'spec')) for packagePath in packagePaths.user ? [] 49 | setSpecType('user') 50 | 51 | if specDirectory = atom.getLoadSettings().specDirectory 52 | requireSpecs(specDirectory) 53 | setSpecType('user') 54 | else 55 | runAllSpecs() 56 | -------------------------------------------------------------------------------- /script/cibuild: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var cp = require('./utils/child-process-wrapper.js'); 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | process.chdir(path.dirname(__dirname)); 7 | 8 | var homeDir = process.platform == 'win32' ? process.env.USERPROFILE : process.env.HOME; 9 | 10 | function loadEnvironmentVariables(filePath) { 11 | try { 12 | var lines = fs.readFileSync(filePath, 'utf8').trim().split('\n'); 13 | for (i in lines) { 14 | var parts = lines[i].split('='); 15 | var key = parts[0].trim(); 16 | var value = parts[1].trim().substr(1, parts[1].length - 2); 17 | process.env[key] = value; 18 | } 19 | } catch(error) { 20 | console.error("Failed to load environment variables: " + filePath, error.code); 21 | } 22 | } 23 | 24 | function readEnvironmentVariables() { 25 | if (process.platform === 'win32') 26 | loadEnvironmentVariables(path.resolve('/jenkins/config/atomcredentials')); 27 | else if (process.platform === 'darwin') { 28 | loadEnvironmentVariables('/var/lib/jenkins/config/atomcredentials'); 29 | loadEnvironmentVariables('/var/lib/jenkins/config/xcodekeychain'); 30 | } 31 | } 32 | 33 | readEnvironmentVariables(); 34 | cp.safeExec.bind(global, 'npm install npm', {cwd: path.resolve(__dirname, '..', 'build')}, function() { 35 | cp.safeExec.bind(global, 'node script/bootstrap', function(error) { 36 | if (error) 37 | process.exit(1); 38 | require('fs-plus').removeSync.bind(global, path.join(homeDir, '.atom')) 39 | var async = require('async'); 40 | var gruntPath = path.join('build', 'node_modules', '.bin', 'grunt') + (process.platform === 'win32' ? '.cmd' : ''); 41 | var tasks = [ 42 | cp.safeExec.bind(global, 'git clean -dff'), 43 | cp.safeExec.bind(global, gruntPath + ' ci --gruntfile build/Gruntfile.coffee --stack --no-color'), 44 | ] 45 | async.series(tasks, function(error) { 46 | process.exit(error ? 1 : 0); 47 | }); 48 | })(); 49 | })(); 50 | -------------------------------------------------------------------------------- /spec/deserializer-manager-spec.coffee: -------------------------------------------------------------------------------- 1 | DeserializerManager = require '../src/deserializer-manager' 2 | 3 | describe "DeserializerManager", -> 4 | manager = null 5 | 6 | class Foo 7 | @deserialize: ({name}) -> new Foo(name) 8 | constructor: (@name) -> 9 | 10 | beforeEach -> 11 | manager = new DeserializerManager 12 | 13 | describe "::add(deserializer)", -> 14 | it "returns a disposable that can be used to remove the manager", -> 15 | disposable = manager.add(Foo) 16 | expect(manager.deserialize({deserializer: 'Foo', name: 'Bar'})).toBeDefined() 17 | disposable.dispose() 18 | spyOn(console, 'warn') 19 | expect(manager.deserialize({deserializer: 'Foo', name: 'Bar'})).toBeUndefined() 20 | 21 | describe "::deserialize(state)", -> 22 | beforeEach -> 23 | manager.add(Foo) 24 | 25 | it "calls deserialize on the manager for the given state object, or returns undefined if one can't be found", -> 26 | spyOn(console, 'warn') 27 | object = manager.deserialize({deserializer: 'Foo', name: 'Bar'}) 28 | expect(object.name).toBe 'Bar' 29 | expect(manager.deserialize({deserializer: 'Bogus'})).toBeUndefined() 30 | 31 | describe "when the manager has a version", -> 32 | beforeEach -> 33 | Foo.version = 2 34 | 35 | describe "when the deserialized state has a matching version", -> 36 | it "attempts to deserialize the state", -> 37 | object = manager.deserialize({deserializer: 'Foo', version: 2, name: 'Bar'}) 38 | expect(object.name).toBe 'Bar' 39 | 40 | describe "when the deserialized state has a non-matching version", -> 41 | it "returns undefined", -> 42 | expect(manager.deserialize({deserializer: 'Foo', version: 3, name: 'Bar'})).toBeUndefined() 43 | expect(manager.deserialize({deserializer: 'Foo', version: 1, name: 'Bar'})).toBeUndefined() 44 | expect(manager.deserialize({deserializer: 'Foo', name: 'Bar'})).toBeUndefined() 45 | -------------------------------------------------------------------------------- /spec/menu-manager-spec.coffee: -------------------------------------------------------------------------------- 1 | MenuManager = require '../src/menu-manager' 2 | 3 | describe "MenuManager", -> 4 | menu = null 5 | 6 | beforeEach -> 7 | menu = new MenuManager(resourcePath: atom.getLoadSettings().resourcePath) 8 | 9 | describe "::add(items)", -> 10 | it "can add new menus that can be removed with the returned disposable", -> 11 | disposable = menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}] 12 | expect(menu.template).toEqual [{label: "A", submenu: [{label: "B", command: "b"}]}] 13 | disposable.dispose() 14 | expect(menu.template).toEqual [] 15 | 16 | it "can add submenu items to existing menus that can be removed with the returned disposable", -> 17 | disposable1 = menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}] 18 | disposable2 = menu.add [{label: "A", submenu: [{label: "C", submenu: [{label: "D", command: 'd'}]}]}] 19 | disposable3 = menu.add [{label: "A", submenu: [{label: "C", submenu: [{label: "E", command: 'e'}]}]}] 20 | 21 | expect(menu.template).toEqual [{ 22 | label: "A", 23 | submenu: [ 24 | {label: "B", command: "b"}, 25 | {label: "C", submenu: [{label: 'D', command: 'd'}, {label: 'E', command: 'e'}]} 26 | ] 27 | }] 28 | 29 | disposable3.dispose() 30 | expect(menu.template).toEqual [{ 31 | label: "A", 32 | submenu: [ 33 | {label: "B", command: "b"}, 34 | {label: "C", submenu: [{label: 'D', command: 'd'}]} 35 | ] 36 | }] 37 | 38 | disposable2.dispose() 39 | expect(menu.template).toEqual [{label: "A", submenu: [{label: "B", command: "b"}]}] 40 | 41 | disposable1.dispose() 42 | expect(menu.template).toEqual [] 43 | 44 | it "does not add duplicate labels to the same menu", -> 45 | originalItemCount = menu.template.length 46 | menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}] 47 | menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}] 48 | expect(menu.template[originalItemCount]).toEqual {label: "A", submenu: [{label: "B", command: "b"}]} 49 | -------------------------------------------------------------------------------- /docs/contributing-to-packages.md: -------------------------------------------------------------------------------- 1 | # Contributing to Official Atom Packages 2 | 3 | If you think you know which package is causing the issue you are reporting, feel 4 | free to open up the issue in that specific repository instead. When in doubt 5 | just open the issue here but be aware that it may get closed here and reopened 6 | in the proper package's repository. 7 | 8 | ## Hacking on Packages 9 | 10 | ### Cloning 11 | 12 | The first step is creating your own clone. 13 | 14 | For example, if you want to make changes to the `tree-view` package, fork the repo on your github account, then clone it: 15 | 16 | ``` 17 | > git clone git@github.com:your-username/tree-view.git 18 | ``` 19 | 20 | Next install all the dependencies: 21 | 22 | ``` 23 | > cd tree-view 24 | > apm install 25 | Installing modules ✓ 26 | ``` 27 | 28 | Now you can link it to development mode so when you run an Atom window with `atom --dev`, you will use your fork instead of the built in package: 29 | 30 | ``` 31 | > apm link -d 32 | ``` 33 | 34 | ### Running in Development Mode 35 | 36 | Editing a package in Atom is a bit of a circular experience: you're using Atom 37 | to modify itself. What happens if you temporarily break something? You don't 38 | want the version of Atom you're using to edit to become useless in the process. 39 | For this reason, you'll only want to load packages in **development mode** while 40 | you are working on them. You'll perform your editing in **stable mode**, only 41 | switching to development mode to test your changes. 42 | 43 | To open a development mode window, use the "Application: Open Dev" command, 44 | which is normally bound to `cmd-shift-o`. You can also run dev mode from the 45 | command line with `atom --dev`. 46 | 47 | To load your package in development mode, create a symlink to it in 48 | `~/.atom/dev/packages`. This occurs automatically when you clone the package 49 | with `apm develop`. You can also run `apm link --dev` and `apm unlink --dev` 50 | from the package directory to create and remove dev-mode symlinks. 51 | 52 | ### Installing Dependencies 53 | 54 | You'll want to keep dependencies up to date by running `apm update` after pulling any upstream changes. 55 | -------------------------------------------------------------------------------- /static/buttons.less: -------------------------------------------------------------------------------- 1 | @import "ui-variables"; 2 | 3 | .btn { 4 | color: @text-color; 5 | border-radius: @component-border-radius; 6 | border: none; 7 | text-shadow: none; 8 | 9 | height: @component-line-height + 2px; 10 | line-height: @component-line-height; 11 | 12 | padding: 0 @component-padding; 13 | font-size: @font-size; 14 | z-index: 0; 15 | 16 | background-color: @button-background-color; 17 | &:hover { 18 | background-color: @button-background-color-hover; 19 | } 20 | &.selected, 21 | &.selected:hover { 22 | // we want the selected button to behave like the :hover button; it's on top of the other buttons. 23 | z-index: 1; 24 | background-color: @button-background-color-selected; 25 | } 26 | } 27 | 28 | .btn.btn-xs, 29 | .btn-group-xs > .btn { 30 | padding: @component-padding/4 @component-padding/2; 31 | font-size: @font-size - 2px; 32 | height: auto; 33 | line-height: 1.3em; 34 | } 35 | .btn.btn-sm, 36 | .btn-group-sm > .btn { 37 | padding: @component-padding/4 @component-padding/2; 38 | height: auto; 39 | line-height: 1.3em; 40 | } 41 | .btn.btn-lg, 42 | .btn-group-lg > .btn { 43 | font-size: @font-size + 2px; 44 | padding: @component-padding - 2px @component-padding + 2px; 45 | height: auto; 46 | line-height: 1.3em; 47 | } 48 | 49 | .btn-group > .btn { 50 | border-left: 1px solid @button-border-color; 51 | border-right: 1px solid @button-border-color; 52 | } 53 | .btn-group > .btn:first-child { 54 | border-left: none; 55 | border-top-left-radius: @component-border-radius; 56 | border-bottom-left-radius: @component-border-radius; 57 | } 58 | .btn-group > .btn:last-child, 59 | .btn-group > .btn.selected:last-child, 60 | .btn-group > .dropdown-toggle { 61 | border-right: none; 62 | border-top-right-radius: @component-border-radius; 63 | border-bottom-right-radius: @component-border-radius; 64 | } 65 | 66 | .btn-toolbar { 67 | > .btn-group + .btn-group, > .btn-group + .btn, > .btn + .btn { 68 | float: none; 69 | display: inline-block; 70 | margin-left: 0; 71 | } 72 | > * { 73 | margin-right: @component-padding / 2; 74 | } 75 | > *:last-child { 76 | margin-right: 0; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /keymaps/base.cson: -------------------------------------------------------------------------------- 1 | 'atom-text-editor': 2 | # Platform Bindings 3 | 'home': 'editor:move-to-first-character-of-line' 4 | 'end': 'editor:move-to-end-of-screen-line' 5 | 'shift-home': 'editor:select-to-first-character-of-line' 6 | 'shift-end': 'editor:select-to-end-of-line' 7 | 8 | 'atom-text-editor:not([mini])': 9 | # Atom Specific 10 | 'ctrl-C': 'editor:copy-path' 11 | 12 | # Sublime Parity 13 | 'tab': 'editor:indent' 14 | 'enter': 'editor:newline' 15 | 'shift-tab': 'editor:outdent-selected-rows' 16 | 'ctrl-K': 'editor:delete-line' 17 | 18 | '.select-list atom-text-editor[mini]': 19 | 'enter': 'core:confirm' 20 | 21 | '.tool-panel.panel-left, .tool-panel.panel-right': 22 | 'escape': 'tool-panel:unfocus' 23 | 24 | 'atom-text-editor !important, atom-text-editor[mini] !important': 25 | 'escape': 'editor:consolidate-selections' 26 | 27 | # allow standard input fields to work correctly 28 | 'body .native-key-bindings': 29 | 'tab': 'core:focus-next' 30 | 'shift-tab': 'core:focus-previous' 31 | 'enter': 'native!' 32 | 'backspace': 'native!' 33 | 'shift-backspace': 'native!' 34 | 'delete': 'native!' 35 | 'up': 'native!' 36 | 'down': 'native!' 37 | 'shift-up': 'native!' 38 | 'shift-down': 'native!' 39 | 'alt-up': 'native!' 40 | 'alt-down': 'native!' 41 | 'alt-shift-up': 'native!' 42 | 'alt-shift-down': 'native!' 43 | 'cmd-up': 'native!' 44 | 'cmd-down': 'native!' 45 | 'cmd-shift-up': 'native!' 46 | 'cmd-shift-down': 'native!' 47 | 'ctrl-up': 'native!' 48 | 'ctrl-down': 'native!' 49 | 'ctrl-shift-up': 'native!' 50 | 'ctrl-shift-down': 'native!' 51 | 'left': 'native!' 52 | 'right': 'native!' 53 | 'shift-left': 'native!' 54 | 'shift-right': 'native!' 55 | 'alt-left': 'native!' 56 | 'alt-right': 'native!' 57 | 'alt-shift-left': 'native!' 58 | 'alt-shift-right': 'native!' 59 | 'cmd-left': 'native!' 60 | 'cmd-right': 'native!' 61 | 'cmd-shift-left': 'native!' 62 | 'cmd-shift-right': 'native!' 63 | 'ctrl-left': 'native!' 64 | 'ctrl-right': 'native!' 65 | 'ctrl-shift-left': 'native!' 66 | 'ctrl-shift-right': 'native!' 67 | 'ctrl-b': 'native!' 68 | 'ctrl-f': 'native!' 69 | 'ctrl-F': 'native!' 70 | 'ctrl-B': 'native!' 71 | 'ctrl-h': 'native!' 72 | 'ctrl-d': 'native!' 73 | -------------------------------------------------------------------------------- /src/cursors-component.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react-atom-fork' 2 | {div} = require 'reactionary-atom-fork' 3 | {debounce, toArray, isEqualForProperties, isEqual} = require 'underscore-plus' 4 | SubscriberMixin = require './subscriber-mixin' 5 | CursorComponent = require './cursor-component' 6 | 7 | module.exports = 8 | CursorsComponent = React.createClass 9 | displayName: 'CursorsComponent' 10 | mixins: [SubscriberMixin] 11 | 12 | cursorBlinkIntervalHandle: null 13 | 14 | render: -> 15 | {performedInitialMeasurement, cursorPixelRects, defaultCharWidth} = @props 16 | {blinkOff} = @state 17 | 18 | className = 'cursors' 19 | className += ' blink-off' if blinkOff 20 | 21 | div {className}, 22 | if performedInitialMeasurement 23 | for key, pixelRect of cursorPixelRects 24 | CursorComponent({key, pixelRect, defaultCharWidth}) 25 | 26 | getInitialState: -> 27 | blinkOff: false 28 | 29 | componentDidMount: -> 30 | @startBlinkingCursors() 31 | 32 | componentWillUnmount: -> 33 | @stopBlinkingCursors() 34 | 35 | shouldComponentUpdate: (newProps, newState) -> 36 | not newState.blinkOff is @state.blinkOff or 37 | not isEqualForProperties(newProps, @props, 'cursorPixelRects', 'scrollTop', 'scrollLeft', 'defaultCharWidth', 'useHardwareAcceleration') 38 | 39 | componentWillUpdate: (newProps) -> 40 | cursorsMoved = @props.cursorPixelRects? and 41 | isEqualForProperties(newProps, @props, 'defaultCharWidth', 'scopedCharacterWidthsChangeCount') and 42 | not isEqual(newProps.cursorPixelRects, @props.cursorPixelRects) 43 | 44 | @pauseCursorBlinking() if cursorsMoved 45 | 46 | startBlinkingCursors: -> 47 | @toggleCursorBlinkHandle = setInterval(@toggleCursorBlink, @props.cursorBlinkPeriod / 2) if @isMounted() 48 | 49 | startBlinkingCursorsAfterDelay: null # Created lazily 50 | 51 | stopBlinkingCursors: -> 52 | clearInterval(@toggleCursorBlinkHandle) 53 | 54 | toggleCursorBlink: -> 55 | @setState(blinkOff: not @state.blinkOff) 56 | 57 | pauseCursorBlinking: -> 58 | @state.blinkOff = false 59 | @stopBlinkingCursors() 60 | @startBlinkingCursorsAfterDelay ?= debounce(@startBlinkingCursors, @props.cursorBlinkResumeDelay) 61 | @startBlinkingCursorsAfterDelay() 62 | -------------------------------------------------------------------------------- /docs/advanced/configuration.md: -------------------------------------------------------------------------------- 1 | ## Configuration API 2 | 3 | ### Reading Config Settings 4 | 5 | If you are writing a package that you want to make configurable, you'll need to 6 | read config settings via the `atom.config` global. You can read the current 7 | value of a namespaced config key with `atom.config.get`: 8 | 9 | ```coffeescript 10 | # read a value with `config.get` 11 | @showInvisibles() if atom.config.get "editor.showInvisibles" 12 | ``` 13 | 14 | Or you can subscribe via `atom.config.observe` to track changes from any view 15 | object. 16 | 17 | ```coffeescript 18 | {View} = require 'space-pen' 19 | 20 | class MyView extends View 21 | attached: -> 22 | @fontSizeObserveSubscription = 23 | atom.config.observe 'editor.fontSize', (newValue, {previous}) => 24 | @adjustFontSize() 25 | 26 | detached: -> 27 | @fontSizeObserveSubscription.dispose() 28 | ``` 29 | 30 | The `atom.config.observe` method will call the given callback immediately with 31 | the current value for the specified key path, and it will also call it in the 32 | future whenever the value of that key path changes. If you only want to invoke 33 | the callback when the next time the value changes, use `atom.config.onDidChange` 34 | instead. 35 | 36 | Subscription methods return *disposable* subscription objects. Note in the 37 | example above how we save the subscription to the `@fontSizeObserveSubscription` 38 | instance variable and dispose of it when the view is detached. To group multiple 39 | subscriptions together, you can add them all to a 40 | [`CompositeDisposable`][composite-disposable] that you dispose when the view is 41 | detached. 42 | 43 | ### Writing Config Settings 44 | 45 | The `atom.config` database is populated on startup from `~/.atom/config.cson`, 46 | but you can programmatically write to it with `atom.config.set`: 47 | 48 | ```coffeescript 49 | # basic key update 50 | atom.config.set("core.showInvisibles", true) 51 | ``` 52 | 53 | If you're exposing package configuration via specific key paths, you'll want to 54 | associate them with a schema in your package's main module. Read more about 55 | schemas in the [config API docs][config-api]. 56 | 57 | [composite-disposable]: https://atom.io/docs/api/latest/CompositeDisposable 58 | [config-api]: https://atom.io/docs/api/latest/Config 59 | -------------------------------------------------------------------------------- /spec/time-reporter.coffee: -------------------------------------------------------------------------------- 1 | _ = require 'underscore-plus' 2 | 3 | module.exports = 4 | class TimeReporter extends jasmine.Reporter 5 | 6 | constructor: -> 7 | window.timedSpecs = [] 8 | window.timedSuites = {} 9 | 10 | window.logLongestSpec = => @logLongestSpecs(1) 11 | window.logLongestSpecs = (number) => @logLongestSpecs(number) 12 | window.logLongestSuite = => @logLongestSuites(1) 13 | window.logLongestSuites = (number) => @logLongestSuites(number) 14 | 15 | logLongestSuites: (number=10, log) -> 16 | return unless window.timedSuites.length > 0 17 | 18 | log ?= (line) -> console.log(line) 19 | log "Longest running suites:" 20 | suites = _.map(window.timedSuites, (key, value) -> [value, key]) 21 | for suite in _.sortBy(suites, (suite) -> -suite[1])[0...number] 22 | time = Math.round(suite[1] / 100) / 10 23 | log " #{suite[0]} (#{time}s)" 24 | undefined 25 | 26 | logLongestSpecs: (number=10, log) -> 27 | return unless window.timedSpecs.length > 0 28 | 29 | log ?= (line) -> console.log(line) 30 | log "Longest running specs:" 31 | for spec in _.sortBy(window.timedSpecs, (spec) -> -spec.time)[0...number] 32 | time = Math.round(spec.time / 100) / 10 33 | log "#{spec.description} (#{time}s)" 34 | undefined 35 | 36 | reportSpecStarting: (spec) -> 37 | stack = [spec.description] 38 | suite = spec.suite 39 | while suite 40 | stack.unshift suite.description 41 | @suite = suite.description 42 | suite = suite.parentSuite 43 | 44 | reducer = (memo, description, index) -> 45 | if index is 0 46 | "#{description}" 47 | else 48 | "#{memo}\n#{_.multiplyString(' ', index)}#{description}" 49 | @description = _.reduce(stack, reducer, '') 50 | @time = Date.now() 51 | 52 | reportSpecResults: (spec) -> 53 | return unless @time? and @description? 54 | 55 | duration = Date.now() - @time 56 | 57 | if duration > 0 58 | window.timedSpecs.push 59 | description: @description 60 | time: duration 61 | fullName: spec.getFullName() 62 | 63 | if timedSuites[@suite] 64 | window.timedSuites[@suite] += duration 65 | else 66 | window.timedSuites[@suite] = duration 67 | 68 | @time = null 69 | @description = null 70 | -------------------------------------------------------------------------------- /src/keymap-extensions.coffee: -------------------------------------------------------------------------------- 1 | fs = require 'fs-plus' 2 | path = require 'path' 3 | KeymapManager = require 'atom-keymap' 4 | CSON = require 'season' 5 | {jQuery} = require 'space-pen' 6 | 7 | KeymapManager::onDidLoadBundledKeymaps = (callback) -> 8 | @emitter.on 'did-load-bundled-keymaps', callback 9 | 10 | KeymapManager::loadBundledKeymaps = -> 11 | @loadKeymap(path.join(@resourcePath, 'keymaps')) 12 | @emit 'bundled-keymaps-loaded' 13 | @emitter.emit 'did-load-bundled-keymaps' 14 | 15 | KeymapManager::getUserKeymapPath = -> 16 | if userKeymapPath = CSON.resolve(path.join(@configDirPath, 'keymap')) 17 | userKeymapPath 18 | else 19 | path.join(@configDirPath, 'keymap.cson') 20 | 21 | KeymapManager::loadUserKeymap = -> 22 | userKeymapPath = @getUserKeymapPath() 23 | return unless fs.isFileSync(userKeymapPath) 24 | 25 | try 26 | @loadKeymap(userKeymapPath, watch: true, suppressErrors: true) 27 | catch error 28 | if error.message.indexOf('Unable to watch path') > -1 29 | message = """ 30 | Unable to watch path: `#{path.basename(userKeymapPath)}`. Make sure you 31 | have permission to read `#{userKeymapPath}`. 32 | 33 | On linux there are currently problems with watch sizes. See 34 | [this document][watches] for more info. 35 | [watches]:https://github.com/atom/atom/blob/master/docs/build-instructions/linux.md#typeerror-unable-to-watch-path 36 | """ 37 | atom.notifications.addError(message, {dismissable: true}) 38 | else 39 | detail = error.path 40 | stack = error.stack 41 | atom.notifications.addFatalError(error.message, {detail, stack, dismissable: true}) 42 | 43 | KeymapManager::subscribeToFileReadFailure = -> 44 | @onDidFailToReadFile (error) => 45 | userKeymapPath = @getUserKeymapPath() 46 | message = "Failed to load `#{userKeymapPath}`" 47 | 48 | detail = if error.location? 49 | error.stack 50 | else 51 | error.message 52 | 53 | atom.notifications.addError(message, {detail: detail, dismissable: true}) 54 | 55 | # This enables command handlers registered via jQuery to call 56 | # `.abortKeyBinding()` on the `jQuery.Event` object passed to the handler. 57 | jQuery.Event::abortKeyBinding = -> 58 | @originalEvent?.abortKeyBinding?() 59 | 60 | module.exports = KeymapManager 61 | -------------------------------------------------------------------------------- /src/deserializer-manager.coffee: -------------------------------------------------------------------------------- 1 | {Disposable} = require 'event-kit' 2 | Grim = require 'grim' 3 | 4 | # Extended: Manages the deserializers used for serialized state 5 | # 6 | # An instance of this class is always available as the `atom.deserializers` 7 | # global. 8 | # 9 | # ## Examples 10 | # 11 | # ```coffee 12 | # class MyPackageView extends View 13 | # atom.deserializers.add(this) 14 | # 15 | # @deserialize: (state) -> 16 | # new MyPackageView(state) 17 | # 18 | # constructor: (@state) -> 19 | # 20 | # serialize: -> 21 | # @state 22 | # ``` 23 | module.exports = 24 | class DeserializerManager 25 | constructor: -> 26 | @deserializers = {} 27 | 28 | # Public: Register the given class(es) as deserializers. 29 | # 30 | # * `deserializers` One or more deserializers to register. A deserializer can 31 | # be any object with a `.name` property and a `.deserialize()` method. A 32 | # common approach is to register a *constructor* as the deserializer for its 33 | # instances by adding a `.deserialize()` class method. 34 | add: (deserializers...) -> 35 | @deserializers[deserializer.name] = deserializer for deserializer in deserializers 36 | new Disposable => 37 | delete @deserializers[deserializer.name] for deserializer in deserializers 38 | 39 | remove: (classes...) -> 40 | Grim.deprecate("Call .dispose() on the Disposable return from ::add instead") 41 | delete @deserializers[name] for {name} in classes 42 | 43 | # Public: Deserialize the state and params. 44 | # 45 | # * `state` The state {Object} to deserialize. 46 | # * `params` The params {Object} to pass as the second arguments to the 47 | # deserialize method of the deserializer. 48 | deserialize: (state, params) -> 49 | return unless state? 50 | 51 | if deserializer = @get(state) 52 | stateVersion = state.get?('version') ? state.version 53 | return if deserializer.version? and deserializer.version isnt stateVersion 54 | deserializer.deserialize(state, params) 55 | else 56 | console.warn "No deserializer found for", state 57 | 58 | # Get the deserializer for the state. 59 | # 60 | # * `state` The state {Object} being deserialized. 61 | get: (state) -> 62 | return unless state? 63 | 64 | name = state.get?('deserializer') ? state.deserializer 65 | @deserializers[name] 66 | -------------------------------------------------------------------------------- /spec/notification-manager-spec.coffee: -------------------------------------------------------------------------------- 1 | NotificationManager = require '../src/notification-manager' 2 | 3 | describe "NotificationManager", -> 4 | [manager] = [] 5 | 6 | beforeEach -> 7 | manager = new NotificationManager 8 | 9 | describe "the atom global", -> 10 | it "has a notifications instance", -> 11 | expect(atom.notifications instanceof NotificationManager).toBe true 12 | 13 | describe "adding events", -> 14 | addSpy = null 15 | 16 | beforeEach -> 17 | addSpy = jasmine.createSpy() 18 | manager.onDidAddNotification(addSpy) 19 | 20 | it "emits an event when a notification has been added", -> 21 | manager.add('error', 'Some error!', icon: 'someIcon') 22 | expect(addSpy).toHaveBeenCalled() 23 | 24 | notification = addSpy.mostRecentCall.args[0] 25 | expect(notification.getType()).toBe 'error' 26 | expect(notification.getMessage()).toBe 'Some error!' 27 | expect(notification.getIcon()).toBe 'someIcon' 28 | 29 | it "emits a fatal error ::addFatalError has been called", -> 30 | manager.addFatalError('Some error!', icon: 'someIcon') 31 | expect(addSpy).toHaveBeenCalled() 32 | notification = addSpy.mostRecentCall.args[0] 33 | expect(notification.getType()).toBe 'fatal' 34 | 35 | it "emits an error ::addError has been called", -> 36 | manager.addError('Some error!', icon: 'someIcon') 37 | expect(addSpy).toHaveBeenCalled() 38 | notification = addSpy.mostRecentCall.args[0] 39 | expect(notification.getType()).toBe 'error' 40 | 41 | it "emits a warning notification ::addWarning has been called", -> 42 | manager.addWarning('Something!', icon: 'someIcon') 43 | expect(addSpy).toHaveBeenCalled() 44 | notification = addSpy.mostRecentCall.args[0] 45 | expect(notification.getType()).toBe 'warning' 46 | 47 | it "emits an info notification ::addInfo has been called", -> 48 | manager.addInfo('Something!', icon: 'someIcon') 49 | expect(addSpy).toHaveBeenCalled() 50 | notification = addSpy.mostRecentCall.args[0] 51 | expect(notification.getType()).toBe 'info' 52 | 53 | it "emits a success notification ::addSuccess has been called", -> 54 | manager.addSuccess('Something!', icon: 'someIcon') 55 | expect(addSpy).toHaveBeenCalled() 56 | notification = addSpy.mostRecentCall.args[0] 57 | expect(notification.getType()).toBe 'success' 58 | -------------------------------------------------------------------------------- /spec/panel-element-spec.coffee: -------------------------------------------------------------------------------- 1 | Panel = require '../src/panel' 2 | PanelElement = require '../src/panel-element' 3 | 4 | describe "PanelElement", -> 5 | [jasmineContent, element, panel] = [] 6 | 7 | class TestPanelItem 8 | constructior: -> 9 | 10 | class TestPanelItemElement extends HTMLElement 11 | createdCallback: -> 12 | @classList.add('test-root') 13 | initialize: (@model) -> 14 | this 15 | 16 | TestPanelItemElement = document.registerElement 'atom-test-item-element', prototype: TestPanelItemElement.prototype 17 | 18 | beforeEach -> 19 | jasmineContent = document.body.querySelector('#jasmine-content') 20 | 21 | atom.views.addViewProvider Panel, (model) -> 22 | new PanelElement().initialize(model) 23 | atom.views.addViewProvider TestPanelItem, (model) -> 24 | new TestPanelItemElement().initialize(model) 25 | 26 | it 'removes the element when the panel is destroyed', -> 27 | panel = new Panel({item: new TestPanelItem}) 28 | element = atom.views.getView(panel) 29 | jasmineContent.appendChild(element) 30 | 31 | expect(element.parentNode).toBe jasmineContent 32 | panel.destroy() 33 | expect(element.parentNode).not.toBe jasmineContent 34 | 35 | describe "changing panel visibility", -> 36 | it 'initially renders panel created with visibile: false', -> 37 | panel = new Panel({visible: false, item: new TestPanelItem}) 38 | element = atom.views.getView(panel) 39 | jasmineContent.appendChild(element) 40 | 41 | expect(element.style.display).toBe 'none' 42 | 43 | it 'hides and shows the panel element when Panel::hide() and Panel::show() are called', -> 44 | panel = new Panel({item: new TestPanelItem}) 45 | element = atom.views.getView(panel) 46 | jasmineContent.appendChild(element) 47 | 48 | expect(element.style.display).not.toBe 'none' 49 | 50 | panel.hide() 51 | expect(element.style.display).toBe 'none' 52 | 53 | panel.show() 54 | expect(element.style.display).not.toBe 'none' 55 | 56 | describe "when a class name is specified", -> 57 | it 'initially renders panel created with visibile: false', -> 58 | panel = new Panel({className: 'some classes', item: new TestPanelItem}) 59 | element = atom.views.getView(panel) 60 | jasmineContent.appendChild(element) 61 | 62 | expect(element).toHaveClass 'some' 63 | expect(element).toHaveClass 'classes' 64 | -------------------------------------------------------------------------------- /src/panel.coffee: -------------------------------------------------------------------------------- 1 | {Emitter} = require 'event-kit' 2 | 3 | # Extended: A container representing a panel on the edges of the editor window. 4 | # You should not create a `Panel` directly, instead use {Workspace::addTopPanel} 5 | # and friends to add panels. 6 | # 7 | # Examples: [tree-view](https://github.com/atom/tree-view), 8 | # [status-bar](https://github.com/atom/status-bar), 9 | # and [find-and-replace](https://github.com/atom/find-and-replace) all use 10 | # panels. 11 | module.exports = 12 | class Panel 13 | ### 14 | Section: Construction and Destruction 15 | ### 16 | 17 | constructor: ({@item, @visible, @priority, @className}={}) -> 18 | @emitter = new Emitter 19 | @visible ?= true 20 | @priority ?= 100 21 | 22 | # Public: Destroy and remove this panel from the UI. 23 | destroy: -> 24 | @hide() 25 | @emitter.emit 'did-destroy', this 26 | @emitter.dispose() 27 | 28 | ### 29 | Section: Event Subscription 30 | ### 31 | 32 | # Public: Invoke the given callback when the pane hidden or shown. 33 | # 34 | # * `callback` {Function} to be called when the pane is destroyed. 35 | # * `visible` {Boolean} true when the panel has been shown 36 | # 37 | # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. 38 | onDidChangeVisible: (callback) -> 39 | @emitter.on 'did-change-visible', callback 40 | 41 | # Public: Invoke the given callback when the pane is destroyed. 42 | # 43 | # * `callback` {Function} to be called when the pane is destroyed. 44 | # * `panel` {Panel} this panel 45 | # 46 | # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. 47 | onDidDestroy: (callback) -> 48 | @emitter.on 'did-destroy', callback 49 | 50 | ### 51 | Section: Panel Details 52 | ### 53 | 54 | # Public: Returns the panel's item. 55 | getItem: -> @item 56 | 57 | # Public: Returns a {Number} indicating this panel's priority. 58 | getPriority: -> @priority 59 | 60 | getClassName: -> @className 61 | 62 | # Public: Returns a {Boolean} true when the panel is visible. 63 | isVisible: -> @visible 64 | 65 | # Public: Hide this panel 66 | hide: -> 67 | wasVisible = @visible 68 | @visible = false 69 | @emitter.emit 'did-change-visible', @visible if wasVisible 70 | 71 | # Public: Show this panel 72 | show: -> 73 | wasVisible = @visible 74 | @visible = true 75 | @emitter.emit 'did-change-visible', @visible unless wasVisible 76 | -------------------------------------------------------------------------------- /docs/converting-a-text-mate-theme.md: -------------------------------------------------------------------------------- 1 | ## Converting a TextMate Theme 2 | 3 | This guide will show you how to convert a [TextMate][TextMate] theme to an Atom 4 | theme. 5 | 6 | ### Differences 7 | 8 | TextMate themes use [plist][plist] files while Atom themes use [CSS][CSS] or 9 | [Less][Less] to style the UI and syntax in the editor. 10 | 11 | The utility that converts the theme first parses the theme's plist file and 12 | then creates comparable CSS rules and properties that will style Atom similarly. 13 | 14 | ### Install apm 15 | 16 | The `apm` command line utility that ships with Atom supports converting 17 | a TextMate theme to an Atom theme. 18 | 19 | Check that you have `apm` installed by running the following command in your 20 | terminal: 21 | 22 | ```sh 23 | apm help init 24 | ``` 25 | 26 | You should see a message print out with details about the `apm init` command. 27 | 28 | If you do not, launch Atom and run the _Atom > Install Shell Commands_ menu 29 | to install the `apm` and `atom` commands. 30 | 31 | You can now run `apm help init` to see all the options for initializing new 32 | packages and themes. 33 | 34 | ### Convert the Theme 35 | 36 | Download the theme you wish to convert, you can browse existing TextMate themes 37 | [here][TextMateThemes]. 38 | 39 | Now, let's say you've downloaded the theme to `~/Downloads/MyTheme.tmTheme`, 40 | you can convert the theme with the following command: 41 | 42 | ```sh 43 | apm init --theme ~/.atom/packages/my-theme --convert ~/Downloads/MyTheme.tmTheme 44 | ``` 45 | 46 | You can browse to `~/.atom/packages/my-theme` to see the converted theme. 47 | 48 | ### Activate the Theme 49 | 50 | Now that your theme is installed to `~/.atom/packages` you can enable it 51 | by launching Atom and selecting the _Atom > Preferences..._ menu. 52 | 53 | Select the _Themes_ link on the left side and choose _My Theme_ from the 54 | __Syntax Theme__ dropdown menu to enable your new theme. 55 | 56 | :tada: Your theme is now enabled, open an editor to see it in action! 57 | 58 | ### Further Reading 59 | 60 | * Check out [Publishing a Package](publishing-a-package.html) for more information 61 | on publishing the theme you just created to [atom.io][atomio]. 62 | 63 | [atomio]: https://atom.io 64 | [CSS]: https://en.wikipedia.org/wiki/Cascading_Style_Sheets 65 | [Less]: http://lesscss.org 66 | [plist]: https://en.wikipedia.org/wiki/Property_list 67 | [TextMate]: http://macromates.com 68 | [TextMateThemes]: http://wiki.macromates.com/Themes/UserSubmittedThemes 69 | -------------------------------------------------------------------------------- /spec/fixtures/packages/theme-with-ui-variables/styles/ui-variables.less: -------------------------------------------------------------------------------- 1 | // Variables different from the original are marked 'Changed' 2 | 3 | @text-color: #333; 4 | @text-color-subtle: #777; 5 | @text-color-highlight: #111; 6 | @text-color-selected: @text-color-highlight; 7 | 8 | @text-color-info: #5293d8; 9 | @text-color-success: #1fe977; 10 | @text-color-warning: #f78a46; 11 | @text-color-error: #c00; 12 | 13 | @background-color-info: #0098ff; 14 | @background-color-success: #17ca65; 15 | @background-color-warning: #ff4800; 16 | @background-color-error: #c00; 17 | @background-color-highlight: rgba(255, 255, 255, 0.10); 18 | @background-color-selected: @background-color-highlight; 19 | 20 | @app-background-color: #00f; // Changed 21 | 22 | @base-background-color: #fff; 23 | @base-border-color: #eee; 24 | 25 | @pane-item-background-color: @base-background-color; 26 | @pane-item-border-color: @base-border-color; 27 | 28 | @input-background-color: #f00; // Changed 29 | @input-border-color: @base-border-color; 30 | 31 | @tool-panel-background-color: #f4f4f4; 32 | @tool-panel-border-color: @base-border-color; 33 | 34 | @inset-panel-background-color: #eee; 35 | @inset-panel-border-color: @base-border-color; 36 | 37 | @panel-heading-background-color: #ddd; 38 | @panel-heading-border-color: transparent; 39 | 40 | @overlay-background-color: #f4f4f4; 41 | @overlay-border-color: @base-border-color; 42 | 43 | @button-background-color: #ccc; 44 | @button-background-color-hover: lighten(@button-background-color, 5%); 45 | @button-background-color-selected: @button-background-color-hover; 46 | @button-border-color: #aaa; 47 | 48 | @tab-bar-background-color: #fff; 49 | @tab-bar-border-color: darken(@tab-background-color-active, 10%); 50 | @tab-background-color: #f4f4f4; 51 | @tab-background-color-active: #fff; 52 | @tab-border-color: @base-border-color; 53 | 54 | @tree-view-background-color: @tool-panel-background-color; 55 | @tree-view-border-color: @tool-panel-border-color; 56 | 57 | @ui-site-color-1: @background-color-success; // green 58 | @ui-site-color-2: @background-color-info; // blue 59 | @ui-site-color-3: @background-color-warning; // orange 60 | @ui-site-color-4: #db2ff4; // purple 61 | @ui-site-color-5: #f5e11d; // yellow 62 | 63 | @font-size: 12px; 64 | 65 | @disclosure-arrow-size: 12px; 66 | 67 | @component-padding: 150px; 68 | @component-icon-padding: 5px; 69 | @component-icon-size: 16px; 70 | @component-line-height: 25px; 71 | @component-border-radius: 2px; 72 | 73 | @tab-height: 30px; 74 | 75 | @font-family: Arial; 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Atom](https://cloud.githubusercontent.com/assets/72919/2874231/3af1db48-d3dd-11e3-98dc-6066f8bc766f.png) 2 | 3 | Atom is a hackable text editor for the 21st century, built on [atom-shell](https://github.com/atom/atom-shell), and based on everything we love about our favorite editors. We designed it to be deeply customizable, but still approachable using the default configuration. 4 | 5 | Visit [atom.io](https://atom.io) to learn more or visit the [Atom forum](https://discuss.atom.io). 6 | 7 | Visit [issue #3684](https://github.com/atom/atom/issues/3684) to learn more 8 | about the Atom 1.0 roadmap. 9 | 10 | ## Installing 11 | 12 | ### OS X 13 | 14 | Download the latest [Atom release](https://github.com/atom/atom/releases/latest). 15 | 16 | Atom will automatically update when a new release is available. 17 | 18 | ### Windows 19 | 20 | Download the latest [AtomSetup.exe installer](https://github.com/atom/atom/releases/latest). 21 | 22 | Atom will automatically update when a new release is available. 23 | 24 | You can also download an `atom-windows.zip` file from the [releases page](https://github.com/atom/atom/releases/latest). 25 | The `.zip` version will not automatically update. 26 | 27 | Using [chocolatey](https://chocolatey.org/)? Run `cinst Atom` to install 28 | the latest version of Atom. 29 | 30 | ### Debian Linux (Ubuntu) 31 | 32 | Currently only a 64-bit version is available. 33 | 34 | 1. Download `atom-amd64.deb` from the [Atom releases page](https://github.com/atom/atom/releases/latest). 35 | 2. Run `sudo dpkg --install atom-amd64.deb` on the downloaded package. 36 | 3. Launch Atom using the installed `atom` command. 37 | 38 | The Linux version does not currently automatically update so you will need to 39 | repeat these steps to upgrade to future releases. 40 | 41 | ### Red Hat Linux (Fedora, CentOS, Red Hat) 42 | 43 | Currently only a 64-bit version is available. 44 | 45 | 1. Download `atom.x86_64.rpm` from the [Atom releases page](https://github.com/atom/atom/releases/latest). 46 | 2. Run `sudo yum localinstall atom.x86_64.rpm` on the downloaded package. 47 | 3. Launch Atom using the installed `atom` command. 48 | 49 | The Linux version does not currently automatically update so you will need to 50 | repeat these steps to upgrade to future releases. 51 | 52 | ## Building 53 | 54 | * [Linux](docs/build-instructions/linux.md) 55 | * [OS X](docs/build-instructions/os-x.md) 56 | * [FreeBSD](docs/build-instructions/freebsd.md) 57 | * [Windows](docs/build-instructions/windows.md) 58 | 59 | ## Developing 60 | 61 | Check out the [guides](https://atom.io/docs/latest) and the [API reference](https://atom.io/docs/api). 62 | -------------------------------------------------------------------------------- /src/buffered-node-process.coffee: -------------------------------------------------------------------------------- 1 | BufferedProcess = require './buffered-process' 2 | path = require 'path' 3 | 4 | # Extended: Like {BufferedProcess}, but accepts a Node script as the command 5 | # to run. 6 | # 7 | # This is necessary on Windows since it doesn't support shebang `#!` lines. 8 | # 9 | # ## Examples 10 | # 11 | # ```coffee 12 | # {BufferedNodeProcess} = require 'atom' 13 | # ``` 14 | module.exports = 15 | class BufferedNodeProcess extends BufferedProcess 16 | 17 | # Public: Runs the given Node script by spawning a new child process. 18 | # 19 | # * `options` An {Object} with the following keys: 20 | # * `command` The {String} path to the JavaScript script to execute. 21 | # * `args` The {Array} of arguments to pass to the script (optional). 22 | # * `options` The options {Object} to pass to Node's `ChildProcess.spawn` 23 | # method (optional). 24 | # * `stdout` The callback {Function} that receives a single argument which 25 | # contains the standard output from the command. The callback is 26 | # called as data is received but it's buffered to ensure only 27 | # complete lines are passed until the source stream closes. After 28 | # the source stream has closed all remaining data is sent in a 29 | # final call (optional). 30 | # * `stderr` The callback {Function} that receives a single argument which 31 | # contains the standard error output from the command. The 32 | # callback is called as data is received but it's buffered to 33 | # ensure only complete lines are passed until the source stream 34 | # closes. After the source stream has closed all remaining data 35 | # is sent in a final call (optional). 36 | # * `exit` The callback {Function} which receives a single argument 37 | # containing the exit status (optional). 38 | constructor: ({command, args, options, stdout, stderr, exit}) -> 39 | node = 40 | if process.platform is 'darwin' 41 | # Use a helper to prevent an icon from appearing on the Dock 42 | path.resolve(process.resourcesPath, '..', 'Frameworks', 43 | 'Atom Helper.app', 'Contents', 'MacOS', 'Atom Helper') 44 | else 45 | process.execPath 46 | 47 | options ?= {} 48 | options.env ?= Object.create(process.env) 49 | options.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE'] = 1 50 | 51 | args = args?.slice() ? [] 52 | args.unshift(command) 53 | args.unshift('--no-deprecation') 54 | 55 | super({command: node, args, options, stdout, stderr, exit}) 56 | -------------------------------------------------------------------------------- /static/variables/ui-variables.less: -------------------------------------------------------------------------------- 1 | // This file has fallback variables. It specifies the variables themes 2 | // must implement. 3 | 4 | // Colors 5 | 6 | @text-color: #333; 7 | @text-color-subtle: #777; 8 | @text-color-highlight: #111; 9 | @text-color-selected: @text-color-highlight; 10 | 11 | @text-color-info: #5293d8; 12 | @text-color-success: #1fe977; 13 | @text-color-warning: #f78a46; 14 | @text-color-error: #c00; 15 | 16 | @background-color-info: #0098ff; 17 | @background-color-success: #17ca65; 18 | @background-color-warning: #ff4800; 19 | @background-color-error: #c00; 20 | @background-color-highlight: rgba(255, 255, 255, 0.10); 21 | @background-color-selected: @background-color-highlight; 22 | 23 | @app-background-color: #fff; 24 | 25 | @base-background-color: #fff; 26 | @base-border-color: #eee; 27 | 28 | @pane-item-background-color: @base-background-color; 29 | @pane-item-border-color: @base-border-color; 30 | 31 | @input-background-color: #fff; 32 | @input-border-color: @base-border-color; 33 | 34 | @tool-panel-background-color: #f4f4f4; 35 | @tool-panel-border-color: @base-border-color; 36 | 37 | @inset-panel-background-color: #eee; 38 | @inset-panel-border-color: @base-border-color; 39 | 40 | @panel-heading-background-color: #ddd; 41 | @panel-heading-border-color: transparent; 42 | 43 | @overlay-background-color: #f4f4f4; 44 | @overlay-border-color: @base-border-color; 45 | 46 | @button-background-color: #ccc; 47 | @button-background-color-hover: lighten(@button-background-color, 5%); 48 | @button-background-color-selected: @button-background-color-hover; 49 | @button-border-color: #aaa; 50 | 51 | @tab-bar-background-color: #fff; 52 | @tab-bar-border-color: darken(@tab-background-color-active, 10%); 53 | @tab-background-color: #f4f4f4; 54 | @tab-background-color-active: #fff; 55 | @tab-border-color: @base-border-color; 56 | 57 | @tree-view-background-color: @tool-panel-background-color; 58 | @tree-view-border-color: @tool-panel-border-color; 59 | 60 | @ui-site-color-1: @background-color-success; // green 61 | @ui-site-color-2: @background-color-info; // blue 62 | @ui-site-color-3: @background-color-warning; // orange 63 | @ui-site-color-4: #db2ff4; // purple 64 | @ui-site-color-5: #f5e11d; // yellow 65 | 66 | 67 | // Sizes 68 | 69 | @font-size: 13px; 70 | @input-font-size: 14px; 71 | 72 | @disclosure-arrow-size: 12px; 73 | 74 | @component-padding: 10px; 75 | @component-icon-padding: 5px; 76 | @component-icon-size: 16px; 77 | @component-line-height: 25px; 78 | @component-border-radius: 2px; 79 | 80 | @tab-height: 30px; 81 | 82 | 83 | // Other 84 | 85 | @font-family: 'Lucida Grande', 'Segoe UI', Ubuntu, Cantarell, sans-serif; 86 | -------------------------------------------------------------------------------- /src/pane-container-view.coffee: -------------------------------------------------------------------------------- 1 | {deprecate} = require 'grim' 2 | Delegator = require 'delegato' 3 | {CompositeDisposable} = require 'event-kit' 4 | {$, View, callAttachHooks} = require './space-pen-extensions' 5 | PaneView = require './pane-view' 6 | PaneContainer = require './pane-container' 7 | 8 | # Manages the list of panes within a {WorkspaceView} 9 | module.exports = 10 | class PaneContainerView extends View 11 | Delegator.includeInto(this) 12 | 13 | @delegatesMethod 'saveAll', toProperty: 'model' 14 | 15 | @content: -> 16 | @div class: 'panes' 17 | 18 | constructor: (@element) -> 19 | super 20 | @subscriptions = new CompositeDisposable 21 | 22 | setModel: (@model) -> 23 | @subscriptions.add @model.onDidChangeActivePaneItem(@onActivePaneItemChanged) 24 | 25 | getRoot: -> 26 | view = atom.views.getView(@model.getRoot()) 27 | view.__spacePenView ? view 28 | 29 | onActivePaneItemChanged: (activeItem) => 30 | @trigger 'pane-container:active-pane-item-changed', [activeItem] 31 | 32 | confirmClose: -> 33 | @model.confirmClose() 34 | 35 | getPaneViews: -> 36 | @find('atom-pane').views() 37 | 38 | indexOfPane: (paneView) -> 39 | @getPaneViews().indexOf(paneView.view()) 40 | 41 | paneAtIndex: (index) -> 42 | @getPaneViews()[index] 43 | 44 | eachPaneView: (callback) -> 45 | callback(paneView) for paneView in @getPaneViews() 46 | paneViewAttached = (e) -> callback($(e.target).view()) 47 | @on 'pane:attached', paneViewAttached 48 | off: => @off 'pane:attached', paneViewAttached 49 | 50 | getFocusedPane: -> 51 | @find('atom-pane:has(:focus)').view() 52 | 53 | getActivePane: -> 54 | deprecate("Use PaneContainerView::getActivePaneView instead.") 55 | @getActivePaneView() 56 | 57 | getActivePaneView: -> 58 | atom.views.getView(@model.getActivePane()).__spacePenView 59 | 60 | getActivePaneItem: -> 61 | @model.getActivePaneItem() 62 | 63 | getActiveView: -> 64 | @getActivePaneView()?.activeView 65 | 66 | paneForUri: (uri) -> 67 | atom.views.getView(@model.paneForURI(uri)).__spacePenView 68 | 69 | focusNextPaneView: -> 70 | @model.activateNextPane() 71 | 72 | focusPreviousPaneView: -> 73 | @model.activatePreviousPane() 74 | 75 | focusPaneViewAbove: -> 76 | @element.focusPaneViewAbove() 77 | 78 | focusPaneViewBelow: -> 79 | @element.focusPaneViewBelow() 80 | 81 | focusPaneViewOnLeft: -> 82 | @element.focusPaneViewOnLeft() 83 | 84 | focusPaneViewOnRight: -> 85 | @element.focusPaneViewOnRight() 86 | 87 | getPanes: -> 88 | deprecate("Use PaneContainerView::getPaneViews() instead") 89 | @getPaneViews() 90 | -------------------------------------------------------------------------------- /src/text-utils.coffee: -------------------------------------------------------------------------------- 1 | isHighSurrogate = (charCode) -> 2 | 0xD800 <= charCode <= 0xDBFF 3 | 4 | isLowSurrogate = (charCode) -> 5 | 0xDC00 <= charCode <= 0xDFFF 6 | 7 | isVariationSelector = (charCode) -> 8 | 0xFE00 <= charCode <= 0xFE0F 9 | 10 | isCombiningCharacter = (charCode) -> 11 | 0x0300 <= charCode <= 0x036F or 12 | 0x1AB0 <= charCode <= 0x1AFF or 13 | 0x1DC0 <= charCode <= 0x1DFF or 14 | 0x20D0 <= charCode <= 0x20FF or 15 | 0xFE20 <= charCode <= 0xFE2F 16 | 17 | # Are the given character codes a high/low surrogate pair? 18 | # 19 | # * `charCodeA` The first character code {Number}. 20 | # * `charCode2` The second character code {Number}. 21 | # 22 | # Return a {Boolean}. 23 | isSurrogatePair = (charCodeA, charCodeB) -> 24 | isHighSurrogate(charCodeA) and isLowSurrogate(charCodeB) 25 | 26 | # Are the given character codes a variation sequence? 27 | # 28 | # * `charCodeA` The first character code {Number}. 29 | # * `charCode2` The second character code {Number}. 30 | # 31 | # Return a {Boolean}. 32 | isVariationSequence = (charCodeA, charCodeB) -> 33 | not isVariationSelector(charCodeA) and isVariationSelector(charCodeB) 34 | 35 | # Are the given character codes a combined character pair? 36 | # 37 | # * `charCodeA` The first character code {Number}. 38 | # * `charCode2` The second character code {Number}. 39 | # 40 | # Return a {Boolean}. 41 | isCombinedCharacter = (charCodeA, charCodeB) -> 42 | not isCombiningCharacter(charCodeA) and isCombiningCharacter(charCodeB) 43 | 44 | # Is the character at the given index the start of high/low surrogate pair 45 | # a variation sequence, or a combined character? 46 | # 47 | # * `string` The {String} to check for a surrogate pair, variation sequence, 48 | # or combined character. 49 | # * `index` The {Number} index to look for a surrogate pair, variation 50 | # sequence, or combined character. 51 | # 52 | # Return a {Boolean}. 53 | isPairedCharacter = (string, index=0) -> 54 | charCodeA = string.charCodeAt(index) 55 | charCodeB = string.charCodeAt(index + 1) 56 | isSurrogatePair(charCodeA, charCodeB) or 57 | isVariationSequence(charCodeA, charCodeB) or 58 | isCombinedCharacter(charCodeA, charCodeB) 59 | 60 | # Does the given string contain at least surrogate pair, variation sequence, 61 | # or combined character? 62 | # 63 | # * `string` The {String} to check for the presence of paired characters. 64 | # 65 | # Returns a {Boolean}. 66 | hasPairedCharacter = (string) -> 67 | index = 0 68 | while index < string.length 69 | return true if isPairedCharacter(string, index) 70 | index++ 71 | false 72 | 73 | module.exports = {isPairedCharacter, hasPairedCharacter} 74 | -------------------------------------------------------------------------------- /src/coffee-cache.coffee: -------------------------------------------------------------------------------- 1 | crypto = require 'crypto' 2 | path = require 'path' 3 | 4 | CoffeeScript = require 'coffee-script' 5 | CSON = require 'season' 6 | fs = require 'fs-plus' 7 | 8 | cacheDir = path.join(process.env.ATOM_HOME, 'compile-cache') 9 | 10 | stats = 11 | hits: 0 12 | misses: 0 13 | 14 | # Use separate compile cache when sudo'ing as root to avoid permission issues 15 | if process.env.USER is 'root' and process.env.SUDO_USER and process.env.SUDO_USER isnt process.env.USER 16 | cacheDir = path.join(cacheDir, 'root') 17 | 18 | coffeeCacheDir = path.join(cacheDir, 'coffee') 19 | CSON.setCacheDir(path.join(cacheDir, 'cson')) 20 | 21 | getCachePath = (coffee) -> 22 | digest = crypto.createHash('sha1').update(coffee, 'utf8').digest('hex') 23 | path.join(coffeeCacheDir, "#{digest}.js") 24 | 25 | getCachedJavaScript = (cachePath) -> 26 | if fs.isFileSync(cachePath) 27 | try 28 | cachedJavaScript = fs.readFileSync(cachePath, 'utf8') 29 | stats.hits++ 30 | return cachedJavaScript 31 | return 32 | 33 | convertFilePath = (filePath) -> 34 | if process.platform is 'win32' 35 | filePath = "/#{path.resolve(filePath).replace(/\\/g, '/')}" 36 | encodeURI(filePath) 37 | 38 | compileCoffeeScript = (coffee, filePath, cachePath) -> 39 | {js, v3SourceMap} = CoffeeScript.compile(coffee, filename: filePath, sourceMap: true) 40 | stats.misses++ 41 | # Include source map in the web page environment. 42 | if btoa? and JSON? and unescape? and encodeURIComponent? 43 | js = "#{js}\n//# sourceMappingURL=data:application/json;base64,#{btoa unescape encodeURIComponent v3SourceMap}\n//# sourceURL=#{convertFilePath(filePath)}" 44 | try 45 | fs.writeFileSync(cachePath, js) 46 | js 47 | 48 | requireCoffeeScript = (module, filePath) -> 49 | coffee = fs.readFileSync(filePath, 'utf8') 50 | cachePath = getCachePath(coffee) 51 | js = getCachedJavaScript(cachePath) ? compileCoffeeScript(coffee, filePath, cachePath) 52 | module._compile(js, filePath) 53 | 54 | module.exports = 55 | cacheDir: cacheDir 56 | 57 | register: -> 58 | Object.defineProperty(require.extensions, '.coffee', { 59 | writable: false 60 | value: requireCoffeeScript 61 | }) 62 | 63 | addPathToCache: (filePath) -> 64 | switch path.extname(filePath) 65 | when '.coffee' 66 | content = fs.readFileSync(filePath, 'utf8') 67 | cachePath = getCachePath(coffee) 68 | compileCoffeeScript(coffee, filePath, cachePath) 69 | when '.cson' 70 | CSON.readFileSync(filePath) 71 | when '.js' 72 | require('./6to5').addPathToCache(filePath) 73 | 74 | getCacheMisses: -> stats.misses 75 | 76 | getCacheHits: -> stats.hits 77 | -------------------------------------------------------------------------------- /src/fold.coffee: -------------------------------------------------------------------------------- 1 | {Point, Range} = require 'text-buffer' 2 | 3 | # Represents a fold that collapses multiple buffer lines into a single 4 | # line on the screen. 5 | # 6 | # Their creation is managed by the {DisplayBuffer}. 7 | module.exports = 8 | class Fold 9 | id: null 10 | displayBuffer: null 11 | marker: null 12 | 13 | constructor: (@displayBuffer, @marker) -> 14 | @id = @marker.id 15 | @displayBuffer.foldsByMarkerId[@marker.id] = this 16 | @updateDisplayBuffer() 17 | @marker.onDidDestroy => @destroyed() 18 | @marker.onDidChange ({isValid}) => @destroy() unless isValid 19 | 20 | # Returns whether this fold is contained within another fold 21 | isInsideLargerFold: -> 22 | largestContainingFoldMarker = @displayBuffer.findFoldMarker(containsRange: @getBufferRange()) 23 | largestContainingFoldMarker and 24 | not largestContainingFoldMarker.getRange().isEqual(@getBufferRange()) 25 | 26 | # Destroys this fold 27 | destroy: -> 28 | @marker.destroy() 29 | 30 | # Returns the fold's {Range} in buffer coordinates 31 | # 32 | # includeNewline - A {Boolean} which, if `true`, includes the trailing newline 33 | # 34 | # Returns a {Range}. 35 | getBufferRange: ({includeNewline}={}) -> 36 | range = @marker.getRange() 37 | 38 | if range.end.row > range.start.row and nextFold = @displayBuffer.largestFoldStartingAtBufferRow(range.end.row) 39 | nextRange = nextFold.getBufferRange() 40 | range = new Range(range.start, nextRange.end) 41 | 42 | if includeNewline 43 | range = range.copy() 44 | range.end.row++ 45 | range.end.column = 0 46 | range 47 | 48 | getBufferRowRange: -> 49 | {start, end} = @getBufferRange() 50 | [start.row, end.row] 51 | 52 | # Returns the fold's start row as a {Number}. 53 | getStartRow: -> 54 | @getBufferRange().start.row 55 | 56 | # Returns the fold's end row as a {Number}. 57 | getEndRow: -> 58 | @getBufferRange().end.row 59 | 60 | # Returns a {String} representation of the fold. 61 | inspect: -> 62 | "Fold(#{@getStartRow()}, #{@getEndRow()})" 63 | 64 | # Retrieves the number of buffer rows spanned by the fold. 65 | # 66 | # Returns a {Number}. 67 | getBufferRowCount: -> 68 | @getEndRow() - @getStartRow() + 1 69 | 70 | # Identifies if a fold is nested within a fold. 71 | # 72 | # fold - A {Fold} to check 73 | # 74 | # Returns a {Boolean}. 75 | isContainedByFold: (fold) -> 76 | @isContainedByRange(fold.getBufferRange()) 77 | 78 | updateDisplayBuffer: -> 79 | unless @isInsideLargerFold() 80 | @displayBuffer.updateScreenLines(@getStartRow(), @getEndRow() + 1, 0, updateMarkers: true) 81 | 82 | destroyed: -> 83 | delete @displayBuffer.foldsByMarkerId[@marker.id] 84 | @updateDisplayBuffer() 85 | -------------------------------------------------------------------------------- /spec/text-utils-spec.coffee: -------------------------------------------------------------------------------- 1 | textUtils = require '../src/text-utils' 2 | 3 | describe 'text utilities', -> 4 | describe '.hasPairedCharacter(string)', -> 5 | it 'returns true when the string contains a surrogate pair, variation sequence, or combined character', -> 6 | expect(textUtils.hasPairedCharacter('abc')).toBe false 7 | expect(textUtils.hasPairedCharacter('a\uD835\uDF97b\uD835\uDF97c')).toBe true 8 | expect(textUtils.hasPairedCharacter('\uD835\uDF97')).toBe true 9 | expect(textUtils.hasPairedCharacter('\u2714\uFE0E')).toBe true 10 | expect(textUtils.hasPairedCharacter('e\u0301')).toBe true 11 | 12 | expect(textUtils.hasPairedCharacter('\uD835')).toBe false 13 | expect(textUtils.hasPairedCharacter('\uDF97')).toBe false 14 | expect(textUtils.hasPairedCharacter('\uFE0E')).toBe false 15 | expect(textUtils.hasPairedCharacter('\u0301')).toBe false 16 | 17 | expect(textUtils.hasPairedCharacter('\uFE0E\uFE0E')).toBe false 18 | expect(textUtils.hasPairedCharacter('\u0301\u0301')).toBe false 19 | 20 | describe '.isPairedCharacter(string, index)', -> 21 | it 'returns true when the index is the start of a high/low surrogate pair, variation sequence, or combined character', -> 22 | expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 0)).toBe false 23 | expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 1)).toBe true 24 | expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 2)).toBe false 25 | expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 3)).toBe false 26 | expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 4)).toBe true 27 | expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 5)).toBe false 28 | expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 6)).toBe false 29 | 30 | expect(textUtils.isPairedCharacter('a\u2714\uFE0E', 0)).toBe false 31 | expect(textUtils.isPairedCharacter('a\u2714\uFE0E', 1)).toBe true 32 | expect(textUtils.isPairedCharacter('a\u2714\uFE0E', 2)).toBe false 33 | expect(textUtils.isPairedCharacter('a\u2714\uFE0E', 3)).toBe false 34 | 35 | expect(textUtils.isPairedCharacter('\uD835')).toBe false 36 | expect(textUtils.isPairedCharacter('\uDF97')).toBe false 37 | expect(textUtils.isPairedCharacter('\uFE0E')).toBe false 38 | expect(textUtils.isPairedCharacter('\uFE0E')).toBe false 39 | 40 | expect(textUtils.isPairedCharacter('\uFE0E\uFE0E')).toBe false 41 | 42 | expect(textUtils.isPairedCharacter('ae\u0301c', 0)).toBe false 43 | expect(textUtils.isPairedCharacter('ae\u0301c', 1)).toBe true 44 | expect(textUtils.isPairedCharacter('ae\u0301c', 2)).toBe false 45 | expect(textUtils.isPairedCharacter('ae\u0301c', 3)).toBe false 46 | expect(textUtils.isPairedCharacter('ae\u0301c', 4)).toBe false 47 | -------------------------------------------------------------------------------- /src/color.coffee: -------------------------------------------------------------------------------- 1 | _ = require 'underscore-plus' 2 | ParsedColor = null 3 | 4 | # Essential: A simple color class returned from {Config::get} when the value 5 | # at the key path is of type 'color'. 6 | module.exports = 7 | class Color 8 | # Essential: Parse a {String} or {Object} into a {Color}. 9 | # 10 | # * `value` A {String} such as `'white'`, `#ff00ff`, or 11 | # `'rgba(255, 15, 60, .75)'` or an {Object} with `red`, `green`, `blue`, 12 | # and `alpha` properties. 13 | # 14 | # Returns a {Color} or `null` if it cannot be parsed. 15 | @parse: (value) -> 16 | return null if _.isArray(value) or _.isFunction(value) 17 | return null unless _.isObject(value) or _.isString(value) 18 | 19 | ParsedColor ?= require 'color' 20 | 21 | try 22 | parsedColor = new ParsedColor(value) 23 | catch error 24 | return null 25 | 26 | new Color(parsedColor.red(), parsedColor.green(), parsedColor.blue(), parsedColor.alpha()) 27 | 28 | constructor: (red, green, blue, alpha) -> 29 | Object.defineProperties this, 30 | red: 31 | set: (newRed) -> red = parseColor(newRed) 32 | get: -> red 33 | enumerable: true 34 | configurable: false 35 | green: 36 | set: (newGreen) -> green = parseColor(newGreen) 37 | get: -> green 38 | enumerable: true 39 | configurable: false 40 | blue: 41 | set: (newBlue) -> blue = parseColor(newBlue) 42 | get: -> blue 43 | enumerable: true 44 | configurable: false 45 | alpha: 46 | set: (newAlpha) -> alpha = parseAlpha(newAlpha) 47 | get: -> alpha 48 | enumerable: true 49 | configurable: false 50 | 51 | @red = red 52 | @green = green 53 | @blue = blue 54 | @alpha = alpha 55 | 56 | # Essential: Returns a {String} in the form `'#abcdef'`. 57 | toHexString: -> 58 | "##{numberToHexString(@red)}#{numberToHexString(@green)}#{numberToHexString(@blue)}" 59 | 60 | # Essential: Returns a {String} in the form `'rgba(25, 50, 75, .9)'`. 61 | toRGBAString: -> 62 | "rgba(#{@red}, #{@green}, #{@blue}, #{@alpha})" 63 | 64 | isEqual: (color) -> 65 | return true if this is color 66 | color = Color.parse(color) unless color instanceof Color 67 | return false unless color? 68 | color.red is @red and color.blue is @blue and color.green is @green and color.alpha is @alpha 69 | 70 | clone: -> new Color(@red, @green, @blue, @alpha) 71 | 72 | parseColor = (color) -> 73 | color = parseInt(color) 74 | color = 0 if isNaN(color) 75 | color = Math.max(color, 0) 76 | color = Math.min(color, 255) 77 | color 78 | 79 | parseAlpha = (alpha) -> 80 | alpha = parseFloat(alpha) 81 | alpha = 1 if isNaN(alpha) 82 | alpha = Math.max(alpha, 0) 83 | alpha = Math.min(alpha, 1) 84 | alpha 85 | 86 | numberToHexString = (number) -> 87 | hex = number.toString(16) 88 | hex = "0#{hex}" if number < 10 89 | hex 90 | --------------------------------------------------------------------------------