diff --git a/README.md b/README.md index 7ad08b369..9b88e7b8f 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,14 @@ -![Atom](https://cloud.githubusercontent.com/assets/72919/2874231/3af1db48-d3dd-11e3-98dc-6066f8bc766f.png) +# Atom [![Build status](https://dev.azure.com/github/Atom/_apis/build/status/Atom%20Production%20Branches?branchName=master)](https://dev.azure.com/github/Atom/_build/latest?definitionId=32&branchName=master) [![Linux Build Status](https://travis-ci.org/atom/atom.svg?branch=master)](https://travis-ci.org/atom/atom) [![Windows Build Status](https://ci.appveyor.com/api/projects/status/1tkktwh654w07eim?svg=true)](https://ci.appveyor.com/project/Atom/atom) [![Dependency Status](https://david-dm.org/atom/atom.svg)](https://david-dm.org/atom/atom) [![Join the Atom Community on Slack](https://atom-slack.herokuapp.com/badge.svg)](https://atom-slack.herokuapp.com) -Atom is a hackable text editor for the 21st century, built on [Electron](https://github.com/atom/electron), and based on everything we love about our favorite editors. We designed it to be deeply customizable, but still approachable using the default configuration. +Atom is a hackable text editor for the 21st century, built on [Electron](https://github.com/electron/electron), and based on everything we love about our favorite editors. We designed it to be deeply customizable, but still approachable using the default configuration. + +![Atom](https://user-images.githubusercontent.com/378023/49132477-f4b77680-f31f-11e8-8357-ac6491761c6c.png) + +![Atom Screenshot](https://user-images.githubusercontent.com/378023/49132478-f4b77680-f31f-11e8-9e10-e8454d8d9b7e.png) Visit [atom.io](https://atom.io) to learn more or visit the [Atom forum](https://discuss.atom.io). diff --git a/apm/package-lock.json b/apm/package-lock.json index fcbb89967..e9b15786d 100644 --- a/apm/package-lock.json +++ b/apm/package-lock.json @@ -21,7 +21,6 @@ "node-gyp": "3.4.0", "npm": "6.2.0", "open": "0.0.5", - "plist": "git+https://github.com/nathansobo/node-plist.git#bd3a93387f1d4b2cff819b200870d35465796e77", "q": "~0.9.7", "read": "~1.0.5", "request": "^2.87.0", @@ -3974,7 +3973,7 @@ }, "plist": { "version": "git+https://github.com/nathansobo/node-plist.git#bd3a93387f1d4b2cff819b200870d35465796e77", - "from": "git+https://github.com/nathansobo/node-plist.git", + "from": "git+https://github.com/nathansobo/node-plist.git#bd3a93387f1d4b2cff819b200870d35465796e77", "requires": { "xmlbuilder": "0.4.x", "xmldom": "0.1.x" @@ -4500,7 +4499,7 @@ }, "xmlbuilder": { "version": "0.4.3", - "resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-0.4.3.tgz", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-0.4.3.tgz", "integrity": "sha1-xGFLp04K0ZbmCcknLNnh3bKKilg=" }, "xmldom": { diff --git a/docs/rfcs/004-decoration-ordering.md b/docs/rfcs/004-decoration-ordering.md new file mode 100644 index 000000000..2dc4be638 --- /dev/null +++ b/docs/rfcs/004-decoration-ordering.md @@ -0,0 +1,44 @@ +# Decoration ordering + +## Status + +Accepted + +## Summary + +Order block decoration items in the DOM in a deterministic and controllable way. + +## Motivation + +When multiple block decorations are created at the same screen line, they are inserted into the DOM in an order determined by the sequence of their creation; from oldest to newest when `position` is set to `"before"`, from newest to oldest when `position` is set to `"after"`. While this is deterministic, it is limited: it isn't possible to insert decorations within a sequence of existing ones, and it's difficult to control the order of decorations when creating and destroying and moving markers around an editor. + +We hit the need for this in [atom/github#1913](https://github.com/atom/github/pull/1913) when we have a block decoration for multiple consecutive collapsed file patches. + +## Explanation + +[TextEditor::decorateMarker()](https://atom.io/docs/api/v1.34.0/TextEditor#instance-decorateMarker) accepts an additional `order` parameter in its `decorationParams` argument when `type` is "block". When multiple block or overlay decorations occur at the same screen line, they are ordered within the DOM in increasing "order" value. + +Block decorations with the same `order` property are rendered in the order they were created, oldest to newest. Block decorations with no `order` property are rendered after those with one, in the order in which they were created, oldest to newest. + +## Drawbacks + +This is a breaking change for co-located block decorations created with an "after" position - they'll now appear in the reverse order. + +When multiple packages create block decorations at the same screen line, they'll need to coordinate their `order` values to have expected behavior. There may not even be a clear, universal answer about how block decorations from distinct packages _should_ be ordered. + +This adds another situational parameter to `TextEditor::decorationMarker()`, which already has complicated arguments. + +## Rationale and alternatives + +Originally I wanted to address the package coordination problem with a similar approach to [the way context menu items are ordered](https://github.com/atom/atom/pull/16661), by allowing individual decorations to specify constraints: "before this block," "after this block," "next to this block" and so forth. I ultimately chose to write up the simpler proposal because: + +* Block decoration collisions among packages seem much less likely than context menu collisions. +* Constraint satisfaction problems are complex. There would be a relatively high chance of introducing bugs and performance regressions. +* The order number approach is similar to the APIs already offered to order status bar tiles and custom gutters. + +The alternative to having an explicit API for this is at all is to create and destroy decorations to achieve the desired order. That's possible, but requires a great deal of bookkeeping on the package's side to accomplish, especially as decorations are added and removed and text is edited. + +## Unresolved questions + +- Should overlay decorations respect an `order` parameter in a similar fashion? +- Should screen column effect decoration ordering at all? diff --git a/package-lock.json b/package-lock.json index d83e1fcea..fc087fb3a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "atom", - "version": "1.34.0-dev", + "version": "1.36.0-dev", "lockfileVersion": 1, "requires": true, "dependencies": { "@atom/nsfw": { - "version": "1.0.18", - "resolved": "https://registry.npmjs.org/@atom/nsfw/-/nsfw-1.0.18.tgz", - "integrity": "sha512-YceKV9a3X62mh4Q78Nyi8aTRaoVGdpeJBHogL8gxU17iBhEpYvxGgMfTe02j1hH2taFT4barkZ5RdZkGKIsJ/w==", + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/@atom/nsfw/-/nsfw-1.0.20.tgz", + "integrity": "sha512-g/7g0xeqoqhnpb28GZr0I6h8q6sKzS83ic+e+40cD5GoEx8Gpo2MzlvrHvrkONGxckxnSmtcIGlon7YoT/UV3Q==", "requires": { - "fs-extra": "^0.26.5", + "fs-extra": "^7.0.0", "lodash.isinteger": "^4.0.4", "lodash.isundefined": "^3.0.1", - "nan": "^2.0.0", - "promisify-node": "^0.3.0" + "nan": "^2.10.0", + "promisify-node": "^0.5.0" } }, "@atom/source-map-support": { @@ -283,7 +283,7 @@ }, "json5": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, "lodash": { @@ -314,9 +314,9 @@ } }, "atom-keymap": { - "version": "8.2.11", - "resolved": "https://registry.npmjs.org/atom-keymap/-/atom-keymap-8.2.11.tgz", - "integrity": "sha512-dpTpDNENJMjT9tc+F5xUOzMKkf9rje+VZcy/Iz1+U2xvtfyhTDiHJgglXFfIqJ/0s1sCYBUfQESjJFmwBXRe1Q==", + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/atom-keymap/-/atom-keymap-8.2.12.tgz", + "integrity": "sha512-qAXylPa/uysvYhZC1zJR7yG7QFs2RqU+2646JYGeiqgm0nMxLpdJpJ9ABIXbDNxzjhlRXNmZkr5V6N22RWjh4Q==", "requires": { "clear-cut": "^2", "emissary": "^1.1.0", @@ -364,11 +364,6 @@ "resolved": "https://registry.npmjs.org/atom-slick/-/atom-slick-2.0.0.tgz", "integrity": "sha1-/w2+Fb4sTtomi50w124lF+C308o=" }, - "atom-ui": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/atom-ui/-/atom-ui-0.4.1.tgz", - "integrity": "sha1-cNl3ZsukcW15jpSWKq0HkghB6lw=" - }, "autocomplete-atom-api": { "version": "https://www.atom.io/api/packages/autocomplete-atom-api/versions/0.10.7/tarball", "integrity": "sha512-027xza+IwcoAut6ryUQYJGXkIOJkFVAA2mRzmOX5DdADSrifXDn3BZtPjfRpMMvqstC8H+xuxNs0dOdUYhssqw==" @@ -555,7 +550,7 @@ }, "jsesc": { "version": "1.3.0", - "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" }, "lodash": { @@ -710,22 +705,22 @@ }, "babel-plugin-syntax-class-properties": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=" }, "babel-plugin-syntax-flow": { "version": "6.18.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=" }, "babel-plugin-syntax-jsx": { "version": "6.18.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" }, "babel-plugin-syntax-object-rest-spread": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=" }, "babel-plugin-transform-class-properties": { @@ -893,9 +888,9 @@ "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" }, "core-js": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.1.tgz", + "integrity": "sha512-L72mmmEayPJBejKIWe2pYtGis5r0tQ5NaJekdhyXgeMQTpJoBsH0NL4ElY2LfSoV15xeQWKQ+XTTOZdyero5Xg==" }, "home-or-tmp": { "version": "2.0.0", @@ -908,7 +903,7 @@ }, "json5": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, "lodash": { @@ -941,9 +936,9 @@ }, "dependencies": { "core-js": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.1.tgz", + "integrity": "sha512-L72mmmEayPJBejKIWe2pYtGis5r0tQ5NaJekdhyXgeMQTpJoBsH0NL4ElY2LfSoV15xeQWKQ+XTTOZdyero5Xg==" } } }, @@ -1087,8 +1082,8 @@ "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" }, "bookmarks": { - "version": "https://www.atom.io/api/packages/bookmarks/versions/0.45.1/tarball", - "integrity": "sha512-BcKY7ujoJoQ6x0C0CPeV4e9cw0cqwjlKvCVh3T6XeDwZQ1Na8KMrjPHWp8dO7B1cnGFN1LCWWQGWqGH624Ymkw==", + "version": "https://www.atom.io/api/packages/bookmarks/versions/0.46.0/tarball", + "integrity": "sha512-ZgYwD3Diq6nkagxuorWuKXyUBMJUZjjK1ePEYUUEzh155QcD/H1k66RZ/SfO5HrWZ4fPN+j6ux/qoXcnD77Ntg==", "requires": { "atom-select-list": "^0.7.0" } @@ -1111,8 +1106,8 @@ } }, "bracket-matcher": { - "version": "https://www.atom.io/api/packages/bracket-matcher/versions/0.90.2/tarball", - "integrity": "sha512-ANAi0fOKm5Air6jgv682ye3UFYQpYy3s3Dk89Ap7bcNnZgsdmojA7Lq1EmeD+yobjYUqemSp/qelkktttAOgzg==", + "version": "https://www.atom.io/api/packages/bracket-matcher/versions/0.90.4/tarball", + "integrity": "sha512-vOeFxfxQGwBoNkuK7srzVUN65q7jL8UKN/IuReilfqp7eg46z39NSchQvw87dpgEOAQEkV3N99h/vBcMmIDTuw==", "requires": { "first-mate": "^7.0.1", "underscore-plus": "1.x" @@ -1162,14 +1157,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, - "cached-run-in-this-context": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cached-run-in-this-context/-/cached-run-in-this-context-0.5.0.tgz", - "integrity": "sha512-FdtDP0u8WjetQ95nLz9vI06efJTFrmtmk5ZT6FECpyTKi9aakNLMHyMH21WRbGYyWlbmB/QlRoB/g1lcEpyjMw==", - "requires": { - "nan": "^2.10.0" - } - }, "camelcase": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", @@ -1288,11 +1275,6 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=" }, - "circular-json": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.7.tgz", - "integrity": "sha512-/pXoV1JA847qRKPrHbBK6YIBGFF8GOP4wzSgUOA7q0ew0vAv0iJswP+2/nZQ9uzA3Azi7eTrg9L2yzXc/7ZMIA==" - }, "classnames": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", @@ -1593,9 +1575,9 @@ } }, "date-format": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-1.2.0.tgz", - "integrity": "sha1-YV6CjiM90aubua4JUODOzPpuytg=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.0.0.tgz", + "integrity": "sha512-M6UqVvZVgFYqZL1SfHsRGIQSz3ZL+qgbsV5Lp1Vj61LZVYuEwcMXYay7DRDtYs2HQQBK5hQtQ0fD9aEJ89V0LA==" }, "debug": { "version": "2.6.9", @@ -1840,16 +1822,45 @@ } }, "dugite": { - "version": "1.79.0", - "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.79.0.tgz", - "integrity": "sha512-1iohG+Yj+7wwVNUv+HCWaK5ZeAbqNyxHZf96B65KojBVcvMT29i8Tnh/Ta/KHI7LcI0dQqSqsKJdZozpWjXWKw==", + "version": "1.81.0", + "resolved": "https://registry.npmjs.org/dugite/-/dugite-1.81.0.tgz", + "integrity": "sha512-aH1cVzbEXOHqpiub9PWJUN+R2p7H+tvN+VqyAYHR9Tj/axLDccWJk5aKDN1/US82DkaIYWUZz8x0lAbjfqrq4Q==", "requires": { "checksum": "^0.1.1", "mkdirp": "^0.5.1", - "progress": "^2.0.0", + "progress": "^2.0.3", "request": "^2.88.0", "rimraf": "^2.5.4", - "tar": "^4.4.6" + "tar": "^4.4.7" + }, + "dependencies": { + "chownr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==" + }, + "minizlib": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", + "requires": { + "minipass": "^2.2.1" + } + }, + "tar": { + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + } } }, "duplexer": { @@ -1867,11 +1878,11 @@ } }, "element-resize-detector": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/element-resize-detector/-/element-resize-detector-1.1.14.tgz", - "integrity": "sha1-rwZKCmGKggrVcKlcXuxbd74BKME=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/element-resize-detector/-/element-resize-detector-1.2.0.tgz", + "integrity": "sha512-UmhNB8sIJVZeg56gEjgmMd6p37sCg8j8trVW0LZM7Wzv+kxQ5CnRHcgRKBTB/kFUSn3e7UP59kl2V2U8Du1hmg==", "requires": { - "batch-processor": "^1.0.0" + "batch-processor": "1.0.0" } }, "emissary": { @@ -2145,8 +2156,8 @@ } }, "find-and-replace": { - "version": "https://www.atom.io/api/packages/find-and-replace/versions/0.215.14/tarball", - "integrity": "sha512-6TGLE6HQPWeD7jCrtIh5lxoXSoFcSQplbcaFX/HPUmjcUko3/QfuLEuTFmosidwQSWSAcPwUpcQ0Ih3e2KiryA==", + "version": "https://www.atom.io/api/packages/find-and-replace/versions/0.218.0/tarball", + "integrity": "sha512-c77OpEcgce8cfPgjPQStEvK016AVmNMUfKIuCYgzYbjTik2lCSU+QAEG3q6MitIzqoFiSW6WW3FL502HFyZwKg==", "requires": { "binary-search": "^1.3.3", "element-resize-detector": "^1.1.10", @@ -2192,6 +2203,11 @@ } } }, + "flatted": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", + "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==" + }, "flatten": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", @@ -2306,25 +2322,13 @@ "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=" }, "fs-extra": { - "version": "0.26.7", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", - "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.0.tgz", + "integrity": "sha512-EglNDLRpmaTWiD/qraZn6HREAEAHJcJOmxNEYwq6xeMKnVMAy3GUcFB+wXt2C6k4CNvB/mP1y/U3dzvKKj5OtQ==", "requires": { "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0", - "path-is-absolute": "^1.0.0", - "rimraf": "^2.2.8" - }, - "dependencies": { - "jsonfile": { - "version": "2.4.0", - "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "requires": { - "graceful-fs": "^4.1.6" - } - } + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } }, "fs-minipass": { @@ -2336,9 +2340,9 @@ } }, "fs-plus": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fs-plus/-/fs-plus-3.0.2.tgz", - "integrity": "sha1-a19Sp3EolMTd6f2PgfqMYN8EHz0=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fs-plus/-/fs-plus-3.1.1.tgz", + "integrity": "sha512-Se2PJdOWXqos1qVTkvqqjb0CSnfBnwwD+pq+z4ksT+e97mEShod/hrNg0TRCCsXPbJzcIq+NuzQhigunMWMJUA==", "requires": { "async": "^1.5.2", "mkdirp": "^0.5.1", @@ -2348,7 +2352,7 @@ "dependencies": { "async": { "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" } } @@ -2397,8 +2401,8 @@ "integrity": "sha1-gy9kifvodnaUWVmckUpnDsIpR+4=" }, "fuzzy-finder": { - "version": "https://www.atom.io/api/packages/fuzzy-finder/versions/1.8.2/tarball", - "integrity": "sha512-wg3uX5fPtVItOByflO+vsQKHAqn3aSgutYM+xO3lEKQov9DuMdtMzMgbf/Tlam0YwjV+Qz/JV10LluJuliP03A==", + "version": "https://www.atom.io/api/packages/fuzzy-finder/versions/1.9.0/tarball", + "integrity": "sha512-YJTPPMZLQmDiUa6eoONhHF7sOvAPQqrXNFLfPGAUItDUoJxvJBwkPcxh+ryCHLlO8MuoJdDvAKHsU0mGzb/JeQ==", "requires": { "async": "0.2.6", "atom-select-list": "^0.7.0", @@ -2483,8 +2487,8 @@ } }, "github": { - "version": "https://www.atom.io/api/packages/github/versions/0.23.0/tarball", - "integrity": "sha512-VWpKCWY5jsQpEF3XmWCwdlFU5n2S0PQ2PLOD/9WnvuC9U7vtKyrEdd5bqWxS76KNOwpjw6CRoyPmK7WYsKtz6g==", + "version": "https://www.atom.io/api/packages/github/versions/0.24.0/tarball", + "integrity": "sha512-STupVetbztFBB+eGnzUyuX1jbeRL9z9vkkf3t1zbi0+8zr82NDWhSRlyojYyJ0vsT0BbqYxDeKWYl4kQySOfdg==", "requires": { "atom-babel6-transpiler": "1.2.0", "babel-generator": "6.26.1", @@ -2498,7 +2502,7 @@ "classnames": "2.2.6", "compare-sets": "1.0.1", "dugite": "^1.79.0", - "event-kit": "2.5.2", + "event-kit": "2.5.3", "fs-extra": "4.0.3", "graphql": "0.13.2", "keytar": "4.2.1", @@ -2512,20 +2516,15 @@ "react-select": "1.2.1", "react-tabs": "^2.3.0", "relay-runtime": "1.6.0", - "temp": "0.8.3", + "temp": "0.9.0", "tinycolor2": "1.4.1", - "tree-kill": "1.2.0", + "tree-kill": "1.2.1", "underscore-plus": "1.6.8", - "what-the-diff": "0.4.0", + "what-the-diff": "0.5.0", "what-the-status": "1.0.3", "yubikiri": "1.0.0" }, "dependencies": { - "event-kit": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.5.2.tgz", - "integrity": "sha512-1w3eEk45CstP8gzQtJdxhNl6kmvT+3dsGMK31VX7Wmt1/hlwS+s2yJY7SeVRhyhhx2W8neomdBfSZ9ACJ9eNeg==" - }, "fs-extra": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", @@ -2535,6 +2534,14 @@ "jsonfile": "^4.0.0", "universalify": "^0.1.0" } + }, + "temp": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.0.tgz", + "integrity": "sha512-YfUhPQCJoNQE5N+FJQcdPz63O3x3sdT4Xju69Gj4iZe0lBKOtnAMi0SLj9xKhGkcGhsxThvTJ/usxtFPo438zQ==", + "requires": { + "rimraf": "~2.6.2" + } } } }, @@ -2756,20 +2763,14 @@ "optional": true }, "image-view": { - "version": "https://www.atom.io/api/packages/image-view/versions/0.63.1/tarball", - "integrity": "sha512-KMtreZG1QLdCiCmkoHPKnP54oe2mEXDyoliM0wYTsVvaTOIfXW6Gi1rbQgGClqi+iHHWOBFKuJdmVGj/phbK9Q==", + "version": "https://www.atom.io/api/packages/image-view/versions/0.64.0/tarball", + "integrity": "sha512-MQLv/IFAvBvycg7ZrcyIHpcQ/dxKNNRmlMyB0rlY1Owc01bNJDDjkhmSDKSNwl0T9slWwE4emlzGQvqoNWUDbw==", "requires": { - "bytes": "^2.4.0", + "bytes": "^3.0.0", "etch": "0.9.0", - "fs-plus": "^3.0.0", - "underscore-plus": "^1.0.0" + "fs-plus": "^3.0.0" }, "dependencies": { - "bytes": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.5.0.tgz", - "integrity": "sha1-TJQj6i0lLCcMQbK97+/5u2tiwGo=" - }, "etch": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/etch/-/etch-0.9.0.tgz", @@ -3109,7 +3110,7 @@ }, "keytar": { "version": "4.2.1", - "resolved": "http://registry.npmjs.org/keytar/-/keytar-4.2.1.tgz", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-4.2.1.tgz", "integrity": "sha1-igamV3/fY3PgqmsRInfmPex3/RI=", "requires": { "nan": "2.8.0", @@ -3131,14 +3132,6 @@ "is-buffer": "^1.1.5" } }, - "klaw": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", - "requires": { - "graceful-fs": "^4.1.9" - } - }, "language-c": { "version": "https://www.atom.io/api/packages/language-c/versions/0.60.14/tarball", "integrity": "sha512-jGFMc9vNutvBflFdoUXWJqxBFdMFG7n13PxS8z+SB8H0taZStq55JixDaQ0i/qu7ay4K5BCJ7y/PHdL13vjouQ==", @@ -3152,8 +3145,8 @@ "integrity": "sha512-HJfBRKbzOYGlEVQNnnRtx0BgiZ9pHlUioHUtG9pFV65EgO4jm4Q5cPHLDvBj+zEy0cm28eYgEYFjfacyBaZElg==" }, "language-coffee-script": { - "version": "https://www.atom.io/api/packages/language-coffee-script/versions/0.49.3/tarball", - "integrity": "sha512-2xXcSiiRySd0qE4lhsOTqMwcKlBVKc/0ru9HHGJSeTdp/On9iNrkcM1+asDYa/QmvppgAILC2/0xUS6+B/cnqQ==" + "version": "https://www.atom.io/api/packages/language-coffee-script/versions/0.50.0/tarball", + "integrity": "sha512-Sp3b1i8wsd+AELphP2f52mli4C3YjicGC8ps21g48V3SrTZoM7tLE7lkcEdKddYlTqo0fBixTKN2R/iL6GcEVw==" }, "language-csharp": { "version": "https://www.atom.io/api/packages/language-csharp/versions/1.1.0/tarball", @@ -3182,8 +3175,8 @@ } }, "language-html": { - "version": "https://www.atom.io/api/packages/language-html/versions/0.51.5/tarball", - "integrity": "sha512-ZzYdXsmbcKpRHvkq2SyWVByVmzsVAx6UquYOFlN5R51Wn21WeAIHhvf0sz54WntkTXOCGoaII/4sLxrkeqNEKw==", + "version": "https://www.atom.io/api/packages/language-html/versions/0.52.0/tarball", + "integrity": "sha512-fmj0XFE6x8LsiJwcTtXDqDlajcPYDf+ZFHE13K4N1fQrWa7/lICN5k0qOWTvWZJPeEL+p32okzN+SdWmiYKdpw==", "requires": { "atom-grammar-test": "^0.6.3", "tree-sitter-embedded-template": "^0.13.0", @@ -3199,10 +3192,10 @@ "integrity": "sha512-kdTsc2efREnuj72WsAfcx28h0RqrVUIGF7BQcS5zy+ZibqbvnaB5DiVunRFYLhefGoaKVkAyTdRkZWMKH/yIWg==" }, "language-javascript": { - "version": "https://www.atom.io/api/packages/language-javascript/versions/0.129.18/tarball", - "integrity": "sha512-ZCcMHpz7tiBzKCeaDzNGfDcthz504qcleo9hsPFcPkGL0uwOBe4AWpX1xNUz+Uhljf9jHzu7aS3d2G0lvGAMKQ==", + "version": "https://www.atom.io/api/packages/language-javascript/versions/0.129.19/tarball", + "integrity": "sha512-ClPU0dc41WqagaPd+qy5DQ5ahDCVcfFxC1nwppyQSsSXzrzsiE2+FuYzG33OMaSGDA6/zZ6gBkHXnXXPFzWcNA==", "requires": { - "tree-sitter-javascript": "^0.13.8", + "tree-sitter-javascript": "^0.13.10", "tree-sitter-jsdoc": "^0.13.4", "tree-sitter-regex": "^0.13.1" } @@ -3248,10 +3241,10 @@ } }, "language-ruby": { - "version": "https://www.atom.io/api/packages/language-ruby/versions/0.72.14/tarball", - "integrity": "sha512-acTLw8OPSpsCLiwTwMR8kekEJ50FUL4ZFWrriUTjJXg9ePdYCglKsZr5Zaw36a/3AIceCwbwTSWG+hW/O3kYRQ==", + "version": "https://www.atom.io/api/packages/language-ruby/versions/0.72.15/tarball", + "integrity": "sha512-S+VSHL5wUjXvCGswOYTtB/O6D1irmwyU+pkqktyv8o7BKUfvhOygFGAtFTfjglzGdezw4gHnWgb92fMHcymkwQ==", "requires": { - "tree-sitter-ruby": "^0.13.10" + "tree-sitter-ruby": "^0.13.12" } }, "language-ruby-on-rails": { @@ -3583,21 +3576,21 @@ "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" }, "log4js": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-3.0.5.tgz", - "integrity": "sha512-IX5c3G/7fuTtdr0JjOT2OIR12aTESVhsH6cEsijloYwKgcPRlO6DgOU72v0UFhWcoV1HN6+M3dwT89qVPLXm0w==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.0.0.tgz", + "integrity": "sha512-XlxZfcFAvQjnjCJBIV/EpsPmrVC12n+TxNUKgrmQh6eeA+9X+6UqvaRNV8t6dpMtXszl1LAQimB4pqyp2Gsgfw==", "requires": { - "circular-json": "^0.5.5", - "date-format": "^1.2.0", + "date-format": "^2.0.0", "debug": "^3.1.0", + "flatted": "^2.0.0", "rfdc": "^1.1.2", - "streamroller": "0.7.0" + "streamroller": "^1.0.1" }, "dependencies": { "debug": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", - "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "requires": { "ms": "^2.1.1" } @@ -4086,8 +4079,8 @@ } }, "notifications": { - "version": "https://www.atom.io/api/packages/notifications/versions/0.70.5/tarball", - "integrity": "sha512-Eye5knLSgDXOr4qQNv/mnSp+rfmckK+J3Gok6j+tQuaiIYwCPPmJ2rRjy5t6gaJo81yZRuheBf0ur3TpKTXuUw==", + "version": "https://www.atom.io/api/packages/notifications/versions/0.70.6/tarball", + "integrity": "sha512-Gen7TAvNIBwSE9LDl1ejr8Sp2ipGP0je4F2mVqQkED0ScjEr+uHFMqamCYSCh0k6YqQ12Hu0b4clagTPrtMOKQ==", "requires": { "dompurify": "^1.0.3", "fs-plus": "^3.0.0", @@ -4249,9 +4242,9 @@ "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" }, "pathwatcher": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/pathwatcher/-/pathwatcher-8.0.1.tgz", - "integrity": "sha1-UaLOKgHbbDLYZ/ZYXvKEvmvQo64=", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/pathwatcher/-/pathwatcher-8.0.2.tgz", + "integrity": "sha512-zuP+fLmB2IB6z89ikcehA+vG/ITx3Cmhaj3DJrBgnbdss6dwPolSq7cDBjgZ78Vl+SXmG7CHGIOM5mqdT9h7BQ==", "requires": { "async": "~0.2.10", "emissary": "^1.3.2", @@ -4259,19 +4252,19 @@ "fs-plus": "^3.0.0", "grim": "^2.0.1", "iconv-lite": "~0.4.4", - "nan": "2.x", + "nan": "^2.10.0", "underscore-plus": "~1.x" }, "dependencies": { "async": { "version": "0.2.10", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "resolved": "http://registry.npmjs.org/async/-/async-0.2.10.tgz", "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" }, "grim": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/grim/-/grim-2.0.2.tgz", - "integrity": "sha1-52CinKe4NDsMH/r2ziDyGkbuiu0=", + "integrity": "sha512-Qj7hTJRfd87E/gUgfvM0YIH/g2UA2SV6niv6BYXk1o6w4mhgv+QyYM1EjOJQljvzgEj4SqSsRWldXIeKHz3e3Q==", "requires": { "event-kit": "^2.0.0" } @@ -4361,7 +4354,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" } } @@ -4377,9 +4370,9 @@ "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=" }, "progress": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz", - "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" }, "promise": { "version": "7.3.1", @@ -4390,11 +4383,12 @@ } }, "promisify-node": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/promisify-node/-/promisify-node-0.3.0.tgz", - "integrity": "sha1-tLVaz5D6p9K4uQyjlomQhsAwYM8=", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/promisify-node/-/promisify-node-0.5.0.tgz", + "integrity": "sha512-GR2E4qgCoKFTprhULqP2OP3bl8kHo16XtnqtkHH6be7tPW1yL6rXd15nl3oV2sLTFv1+j6tqoF69VVpFtJ/j+A==", "requires": { - "nodegit-promise": "~4.0.0" + "nodegit-promise": "^4.0.0", + "object-assign": "^4.1.1" } }, "prop-types": { @@ -4934,8 +4928,8 @@ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" }, "settings-view": { - "version": "https://www.atom.io/api/packages/settings-view/versions/0.257.2/tarball", - "integrity": "sha512-wAqucDcKKHKiCGw9a29/s6dWLfAB9tBdawQ3dKBxqLwh/eERdQjO4qAxlbsMDlWDf9iOsgSSYpfk8r1/OqbMbQ==", + "version": "https://www.atom.io/api/packages/settings-view/versions/0.258.0/tarball", + "integrity": "sha512-X2avkVC51tM8yGxyQDXF9DZUbxTOhuJPZbgZJaXkebo+Yj/aq4AUkc+AQFOHzWs+PWctyIzCem4PyRq8XIoQ+A==", "requires": { "async": "~0.2.9", "dompurify": "^1.0.2", @@ -5069,12 +5063,10 @@ } }, "solarized-dark-syntax": { - "version": "https://www.atom.io/api/packages/solarized-dark-syntax/versions/1.3.0/tarball", - "integrity": "sha512-2X4Df16sQqna8dmpWnpk2FoL346cXW34Vk2JKJY23fYYCH3t16mGl9G9URB7+S2x+/WmeCjdwIQSMsGvBf/95g==" + "version": "file:packages/solarized-dark-syntax" }, "solarized-light-syntax": { - "version": "https://www.atom.io/api/packages/solarized-light-syntax/versions/1.3.0/tarball", - "integrity": "sha512-DVl8aJnecUKy5s1WY5mDyN1/3McqyZWfE3cjBVY8U7X4w9Xkp8SPVndVGufSpSWIxh9vY/iSU4kfBxWqUdiW5w==" + "version": "file:packages/solarized-light-syntax" }, "source-map": { "version": "0.1.32", @@ -5121,22 +5113,22 @@ "integrity": "sha1-enzShHDMbToc/m1miG9rxDDTrIc=" }, "spell-check": { - "version": "https://www.atom.io/api/packages/spell-check/versions/0.74.2/tarball", - "integrity": "sha512-WhwhDF4nznhQuwnRemZbXODI6aqax2HlHudfLEjbhzkRGjEbfssRK82lRRvCK9LmQh3fAqCqbmELU40NEODJ8Q==", + "version": "https://www.atom.io/api/packages/spell-check/versions/0.74.3/tarball", + "integrity": "sha512-QYy0xpSKp8OSZjlvq7fOjrf/NdG4BncHvn9AmO/vcuJvWAoiwEWhqqB+BSA6uSrxOxJeJhbDJSxOrvm4YXs1xQ==", "requires": { "atom-pathspec": "^0.0.0", "atom-select-list": "^0.7.0", "multi-integer-range": "^2.0.0", "natural": "^0.4.0", - "spellchecker": "^3.4.4", + "spellchecker": "^3.5.1", "spelling-manager": "^1.1.0", "underscore-plus": "^1" } }, "spellchecker": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/spellchecker/-/spellchecker-3.5.0.tgz", - "integrity": "sha512-Xa7XnRulYhh5N/XENeL2O8/875XhLBjos7Bemv0rfcgV6ojNYMSrXscUZUGJwniX2t67eY+lNUJeptD1bMauHQ==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/spellchecker/-/spellchecker-3.5.1.tgz", + "integrity": "sha512-R1qUBsDZzio+7MFZN6/AtPUe5NGvnc0wywckuXAlp9akASaYSFqKuI5O8p3rSiA+yKP31qC7Iijjoygmzkh6xw==", "requires": { "any-promise": "^1.3.0", "nan": "^2.10.0" @@ -5208,8 +5200,8 @@ "integrity": "sha1-ATl5IuX2Ls8whFUiyVxP4dJefU4=" }, "status-bar": { - "version": "https://www.atom.io/api/packages/status-bar/versions/1.8.15/tarball", - "integrity": "sha512-zQa+fdr6pAnix4Lw3tKiU6Uq8Hx1dLsb+w2SaxIDbJaZatO25rN9FTZqNrw0ZchJpCEiSkuLolqUutPB4iNydQ==", + "version": "https://www.atom.io/api/packages/status-bar/versions/1.8.17/tarball", + "integrity": "sha512-QqUIcKw3QuFtstyl841kJ67oBGewWJGe12q+aEkyv6c6jvWBThfLHrGbnvJxgWqtYWbYQtXuqQdj3Wd//EZk6g==", "requires": { "fs-plus": "^3.0.1", "grim": "^2.0.1", @@ -5219,7 +5211,7 @@ "grim": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/grim/-/grim-2.0.2.tgz", - "integrity": "sha1-52CinKe4NDsMH/r2ziDyGkbuiu0=", + "integrity": "sha512-Qj7hTJRfd87E/gUgfvM0YIH/g2UA2SV6niv6BYXk1o6w4mhgv+QyYM1EjOJQljvzgEj4SqSsRWldXIeKHz3e3Q==", "requires": { "event-kit": "^2.0.0" } @@ -5235,24 +5227,38 @@ } }, "streamroller": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", - "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.1.tgz", + "integrity": "sha512-FKL2mEB0A+XTIWSOlBHm2DvdsER5cGraqrUufO0lFMfsVY+Gpb3TC29Z+6/l0Urbb7vtm6m9zJOQBVl6fEkZBA==", "requires": { - "date-format": "^1.2.0", + "async": "^2.6.1", + "date-format": "^2.0.0", "debug": "^3.1.0", - "mkdirp": "^0.5.1", - "readable-stream": "^2.3.0" + "fs-extra": "^7.0.0", + "lodash": "^4.17.10" }, "dependencies": { + "async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "requires": { + "lodash": "^4.17.10" + } + }, "debug": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", - "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "requires": { "ms": "^2.1.1" } }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -5324,9 +5330,9 @@ } }, "superstring": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/superstring/-/superstring-2.3.4.tgz", - "integrity": "sha512-DcNkTCdB9F3FMZRdURSALsHi+7DWqFCI0cH+Eg8mwBg+kxQs6GeB3LrGUvCI5bEB6Dtlu2ox8UYN0onPN4JeZQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/superstring/-/superstring-2.3.6.tgz", + "integrity": "sha512-kDTXCXArhHL1lRk2zBW7ByRJByqVwoLK3E3jlf8+LcwQLZgSMs9dwrDHDpBdoOm89kstSBSrGcW8OJqNkxjWrQ==", "requires": { "nan": "^2.10.0" } @@ -5361,8 +5367,8 @@ "integrity": "sha1-Dk7jdvNjHkLXl3oHTb0rOCeEMIE=" }, "tabs": { - "version": "https://www.atom.io/api/packages/tabs/versions/0.109.2/tarball", - "integrity": "sha512-IdKT8s9Wm4++Sm5wLzrI+nLCB57DMUtTMYnLGlA9Y/C/IRlfMp3PQC2aM/dHGuIzf9JsXsI2wfPsJcU4YXKFoQ==", + "version": "https://www.atom.io/api/packages/tabs/versions/0.110.0/tarball", + "integrity": "sha512-O8Tj9zfpcNavbFuHcNVUnv09Bbya4gFSJgd79IRFHy+d/blViK2Ai8X0Y32vJjxgywzrCIpthOHxw0l9qaqylA==", "requires": { "fs-plus": "^3.0.0", "temp": "~0.8.1", @@ -5460,21 +5466,21 @@ } }, "text-buffer": { - "version": "13.15.0", - "resolved": "https://registry.npmjs.org/text-buffer/-/text-buffer-13.15.0.tgz", - "integrity": "sha512-8X2rSI/W+w+nzSLQ8vm1xLFKZbgcLndDEOsMzN3lNKCy3Zuzru40fl2KHEko6MqHXAGKgA78+kvEDW/gryCP1g==", + "version": "13.15.3", + "resolved": "https://registry.npmjs.org/text-buffer/-/text-buffer-13.15.3.tgz", + "integrity": "sha512-H2fz/N15g0fBP7R33FUFLnIyND+Lji/xmuvHg9rKgmfCh7NAVxiFIvnZTabuBhL9InqPrtV5t4hkUy+r3dNXMg==", "requires": { "delegato": "^1.0.0", "diff": "^2.2.1", "emissary": "^1.0.0", "event-kit": "^2.4.0", - "fs-admin": "^0.1.4", + "fs-admin": "^0.1.7", "fs-plus": "^3.0.0", "grim": "^2.0.2", "mkdirp": "^0.5.1", - "pathwatcher": "8.0.1", + "pathwatcher": "8.0.2", "serializable": "^1.0.3", - "superstring": "2.3.4", + "superstring": "2.3.6", "underscore-plus": "^1.0.0" }, "dependencies": { @@ -5537,9 +5543,9 @@ } }, "tree-kill": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.0.tgz", - "integrity": "sha512-DlX6dR0lOIRDFxI0mjL9IYg6OTncLm/Zt+JiBhE5OlFcAR8yc9S7FFXU9so0oda47frdM/JFsk7UjNt9vscKcg==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", + "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==" }, "tree-sitter": { "version": "0.13.23", @@ -5667,17 +5673,17 @@ } }, "tree-sitter-html": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/tree-sitter-html/-/tree-sitter-html-0.13.4.tgz", - "integrity": "sha512-l52UJ27BmGdwUgEC3d7UJKTtAJDIQ9GL+du8qQoDt2oJg/iSRxckZeevwJ+YyCfYjBlqFH7nXDLtVJxEzhdM/g==", + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/tree-sitter-html/-/tree-sitter-html-0.13.5.tgz", + "integrity": "sha512-lawojfDlj/9ujEYvLoW4+WTTh2ocrYCYP2Dw5LmwxuvvE2lHr/D4RWA8W1N4jpR58tVef0SSqnnQwJkl1pNIeA==", "requires": { "nan": "^2.10.0" } }, "tree-sitter-javascript": { - "version": "0.13.8", - "resolved": "https://registry.npmjs.org/tree-sitter-javascript/-/tree-sitter-javascript-0.13.8.tgz", - "integrity": "sha512-p7u6ZXEX1sIjgGNAiuSNnK6PSl5FiUsQzEV2QOAYVH5GN13cUnUsoa/BiaDMWQ3uddoNXwTdxhB8UwNAolizQQ==", + "version": "0.13.10", + "resolved": "https://registry.npmjs.org/tree-sitter-javascript/-/tree-sitter-javascript-0.13.10.tgz", + "integrity": "sha512-ku/841Nu7k/VXwI2ifm7xxv2cUiiYztLlIeYTYZXpjaIHMfFer5XZRgmZldJHVthTQ9uRMEr7UQ0qeqnWKzOlg==", "requires": { "nan": "^2.4.0" } @@ -5691,9 +5697,9 @@ }, "dependencies": { "nan": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz", - "integrity": "sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA==" + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" } } }, @@ -5714,26 +5720,31 @@ } }, "tree-sitter-ruby": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/tree-sitter-ruby/-/tree-sitter-ruby-0.13.11.tgz", - "integrity": "sha512-EBmBBZ20yaoRqDRgQof9Yir29/3lv5cY/y8UDUC1GzRf5pYd4CsYU0WAjIJ7dyAv+3n7p3y/LOuXkyJLiIN1wA==", + "version": "0.13.12", + "resolved": "https://registry.npmjs.org/tree-sitter-ruby/-/tree-sitter-ruby-0.13.12.tgz", + "integrity": "sha512-QAf7qtOuOSgYtLnJKOapUw389mwSFQdg9LdSXOO1aO5OZ0yFewFChOSxjG4sH7skaXQenkQdT9ASD79WbjRuZw==", "requires": { "nan": "^2.10.0", "prebuild-install": "^5.0.0" }, "dependencies": { + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "prebuild-install": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.2.1.tgz", - "integrity": "sha512-9DAccsInWHB48TBQi2eJkLPE049JuAI6FjIH0oIrij4bpDVEbX6JvlWRAcAAlUqBHhjgq0jNqA3m3bBXWm9v6w==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.2.2.tgz", + "integrity": "sha512-4e8VJnP3zJdZv/uP0eNWmr2r9urp4NECw7Mt1OSAi3rcLrbBRxGiAkfUFtre2MhQ5wfREAjRV+K1gubvs/GPsA==", "requires": { "detect-libc": "^1.0.3", - "expand-template": "^1.0.2", + "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.0", "mkdirp": "^0.5.1", @@ -5769,8 +5780,8 @@ } }, "tree-view": { - "version": "https://www.atom.io/api/packages/tree-view/versions/0.224.4/tarball", - "integrity": "sha512-C1TZTezOu8y5qv4xsYM3G7JePyF4o7TqFj2jYo09YiXtW3m/RX+uTT7WfL8ozGsq082uVzuPlu8/kQAotv95qQ==", + "version": "https://www.atom.io/api/packages/tree-view/versions/0.224.5/tarball", + "integrity": "sha512-cIHL5pewQlD8v5Y30cquYTc74TeJ6+6wXKA6+Hsjh0Z28+lEB3Gqac8AKYPFUaGsSEm5MH6us3FJ/4y1Yqkr2Q==", "requires": { "@atom/temp": "~0.8.4", "fs-plus": "^3.0.0", @@ -5926,9 +5937,9 @@ } }, "what-the-diff": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/what-the-diff/-/what-the-diff-0.4.0.tgz", - "integrity": "sha512-Aw5OoYs5pY4RcZhD9UrS/brg/YRFm/SRRwJEI3f12PTWYadXzkvmf2eGDggSwcZuH2OH8J5HmtUK6LH+jRc2aA==" + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/what-the-diff/-/what-the-diff-0.5.0.tgz", + "integrity": "sha512-+ZX92uzic8Ufbyvl128Rsi8Hf67lYMKA4MJBOUtDnA3PD+rQY0493G25KAKzb9qQ8NN5TcD6VyV/BqBFq1Ktuw==" }, "what-the-status": { "version": "1.0.3", @@ -5985,21 +5996,8 @@ } }, "wrap-guide": { - "version": "https://www.atom.io/api/packages/wrap-guide/versions/0.40.3/tarball", - "integrity": "sha512-TQdO+E8t8sS3c4UUym2Orrf4s6/AYGrfu32lUHLMgnSYcBov/t8J3jYJfPImNkCq7kgYgfycQZM5UryW54J4KA==", - "requires": { - "grim": "^2.0.1" - }, - "dependencies": { - "grim": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/grim/-/grim-2.0.2.tgz", - "integrity": "sha1-52CinKe4NDsMH/r2ziDyGkbuiu0=", - "requires": { - "event-kit": "^2.0.0" - } - } - } + "version": "https://www.atom.io/api/packages/wrap-guide/versions/0.41.0/tarball", + "integrity": "sha512-1XF9yc6pjp3f9smEBrnrNuk0pA6fKd+xet5OMD05ehZs4wA9/lnXrxTd9hCPJpP4krqHdcNFB5/h4VRJWlrlmQ==" }, "wrappy": { "version": "1.0.2", diff --git a/package.json b/package.json index db340eed0..b3dec5c74 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.35.0-dev", + "version": "1.36.0-dev", "description": "A hackable text editor for the 21st Century.", "main": "./src/main-process/main.js", "repository": { @@ -12,9 +12,9 @@ "url": "https://github.com/atom/atom/issues" }, "license": "MIT", - "electronVersion": "2.0.14", + "electronVersion": "3.0.14", "dependencies": { - "@atom/nsfw": "1.0.18", + "@atom/nsfw": "^1.0.20", "@atom/source-map-support": "^0.3.4", "@atom/watcher": "1.0.8", "about": "file:packages/about", @@ -22,11 +22,10 @@ "async": "0.2.6", "atom-dark-syntax": "file:packages/atom-dark-syntax", "atom-dark-ui": "file:packages/atom-dark-ui", - "atom-keymap": "8.2.11", + "atom-keymap": "8.2.12", "atom-light-syntax": "file:packages/atom-light-syntax", "atom-light-ui": "file:packages/atom-light-ui", "atom-select-list": "^0.7.2", - "atom-ui": "0.4.1", "autocomplete-atom-api": "https://www.atom.io/api/packages/autocomplete-atom-api/versions/0.10.7/tarball", "autocomplete-css": "https://www.atom.io/api/packages/autocomplete-css/versions/0.17.5/tarball", "autocomplete-html": "https://www.atom.io/api/packages/autocomplete-html/versions/0.8.8/tarball", @@ -38,9 +37,8 @@ "background-tips": "https://www.atom.io/api/packages/background-tips/versions/0.28.0/tarball", "base16-tomorrow-dark-theme": "file:packages/base16-tomorrow-dark-theme", "base16-tomorrow-light-theme": "file:packages/base16-tomorrow-light-theme", - "bookmarks": "https://www.atom.io/api/packages/bookmarks/versions/0.45.1/tarball", - "bracket-matcher": "https://www.atom.io/api/packages/bracket-matcher/versions/0.90.2/tarball", - "cached-run-in-this-context": "0.5.0", + "bookmarks": "https://www.atom.io/api/packages/bookmarks/versions/0.46.0/tarball", + "bracket-matcher": "https://www.atom.io/api/packages/bracket-matcher/versions/0.90.4/tarball", "chai": "3.5.0", "chart.js": "^2.3.0", "clear-cut": "^2.0.2", @@ -56,23 +54,23 @@ "etch": "^0.12.6", "event-kit": "^2.5.3", "exception-reporting": "file:packages/exception-reporting", - "find-and-replace": "https://www.atom.io/api/packages/find-and-replace/versions/0.215.14/tarball", + "find-and-replace": "https://www.atom.io/api/packages/find-and-replace/versions/0.218.0/tarball", "find-parent-dir": "^0.3.0", "first-mate": "7.1.3", "focus-trap": "2.4.5", "fs-admin": "^0.1.7", - "fs-plus": "^3.0.1", + "fs-plus": "^3.1.1", "fstream": "0.1.24", "fuzzaldrin": "^2.1", - "fuzzy-finder": "https://www.atom.io/api/packages/fuzzy-finder/versions/1.8.2/tarball", + "fuzzy-finder": "https://www.atom.io/api/packages/fuzzy-finder/versions/1.9.0/tarball", "git-diff": "file:packages/git-diff", "git-utils": "5.2.1", - "github": "https://www.atom.io/api/packages/github/versions/0.23.0/tarball", + "github": "https://www.atom.io/api/packages/github/versions/0.24.0/tarball", "glob": "^7.1.1", "go-to-line": "file:packages/go-to-line", "grammar-selector": "file:packages/grammar-selector", "grim": "1.5.0", - "image-view": "https://www.atom.io/api/packages/image-view/versions/0.63.1/tarball", + "image-view": "https://www.atom.io/api/packages/image-view/versions/0.64.0/tarball", "incompatible-packages": "file:packages/incompatible-packages", "jasmine-json": "~0.0", "jasmine-reporters": "1.1.0", @@ -81,16 +79,16 @@ "keybinding-resolver": "https://www.atom.io/api/packages/keybinding-resolver/versions/0.38.4/tarball", "language-c": "https://www.atom.io/api/packages/language-c/versions/0.60.14/tarball", "language-clojure": "https://www.atom.io/api/packages/language-clojure/versions/0.22.7/tarball", - "language-coffee-script": "https://www.atom.io/api/packages/language-coffee-script/versions/0.49.3/tarball", + "language-coffee-script": "https://www.atom.io/api/packages/language-coffee-script/versions/0.50.0/tarball", "language-csharp": "https://www.atom.io/api/packages/language-csharp/versions/1.1.0/tarball", "language-css": "https://www.atom.io/api/packages/language-css/versions/0.43.0/tarball", "language-gfm": "https://www.atom.io/api/packages/language-gfm/versions/0.90.6/tarball", "language-git": "https://www.atom.io/api/packages/language-git/versions/0.19.1/tarball", "language-go": "https://www.atom.io/api/packages/language-go/versions/0.46.6/tarball", - "language-html": "https://www.atom.io/api/packages/language-html/versions/0.51.5/tarball", + "language-html": "https://www.atom.io/api/packages/language-html/versions/0.52.0/tarball", "language-hyperlink": "https://www.atom.io/api/packages/language-hyperlink/versions/0.17.0/tarball", "language-java": "https://www.atom.io/api/packages/language-java/versions/0.31.1/tarball", - "language-javascript": "https://www.atom.io/api/packages/language-javascript/versions/0.129.18/tarball", + "language-javascript": "https://www.atom.io/api/packages/language-javascript/versions/0.129.19/tarball", "language-json": "https://www.atom.io/api/packages/language-json/versions/0.19.2/tarball", "language-less": "https://www.atom.io/api/packages/language-less/versions/0.34.3/tarball", "language-make": "https://www.atom.io/api/packages/language-make/versions/0.23.0/tarball", @@ -100,7 +98,7 @@ "language-php": "https://www.atom.io/api/packages/language-php/versions/0.44.1/tarball", "language-property-list": "https://www.atom.io/api/packages/language-property-list/versions/0.9.1/tarball", "language-python": "https://www.atom.io/api/packages/language-python/versions/0.51.8/tarball", - "language-ruby": "https://www.atom.io/api/packages/language-ruby/versions/0.72.14/tarball", + "language-ruby": "https://www.atom.io/api/packages/language-ruby/versions/0.72.15/tarball", "language-ruby-on-rails": "https://www.atom.io/api/packages/language-ruby-on-rails/versions/0.25.3/tarball", "language-rust-bundled": "file:packages/language-rust-bundled", "language-sass": "https://www.atom.io/api/packages/language-sass/versions/0.62.0/tarball", @@ -126,7 +124,7 @@ "mocha-multi-reporters": "^1.1.4", "mock-spawn": "^0.2.6", "normalize-package-data": "^2.0.0", - "notifications": "https://www.atom.io/api/packages/notifications/versions/0.70.5/tarball", + "notifications": "https://www.atom.io/api/packages/notifications/versions/0.70.6/tarball", "nslog": "^3", "one-dark-syntax": "file:packages/one-dark-syntax", "one-dark-ui": "file:packages/one-dark-ui", @@ -134,7 +132,7 @@ "one-light-ui": "file:packages/one-light-ui", "open-on-github": "https://www.atom.io/api/packages/open-on-github/versions/1.3.1/tarball", "package-generator": "https://www.atom.io/api/packages/package-generator/versions/1.3.0/tarball", - "pathwatcher": "8.0.1", + "pathwatcher": "8.0.2", "postcss": "5.2.4", "postcss-selector-parser": "2.2.1", "property-accessors": "^1.1.3", @@ -146,29 +144,29 @@ "season": "^6.0.2", "semver": "^4.3.3", "service-hub": "^0.7.4", - "settings-view": "https://www.atom.io/api/packages/settings-view/versions/0.257.2/tarball", + "settings-view": "https://www.atom.io/api/packages/settings-view/versions/0.258.0/tarball", "sinon": "1.17.4", "snippets": "https://www.atom.io/api/packages/snippets/versions/1.4.0/tarball", - "solarized-dark-syntax": "https://www.atom.io/api/packages/solarized-dark-syntax/versions/1.3.0/tarball", - "solarized-light-syntax": "https://www.atom.io/api/packages/solarized-light-syntax/versions/1.3.0/tarball", - "spell-check": "https://www.atom.io/api/packages/spell-check/versions/0.74.2/tarball", - "status-bar": "https://www.atom.io/api/packages/status-bar/versions/1.8.15/tarball", + "solarized-dark-syntax": "file:packages/solarized-dark-syntax", + "solarized-light-syntax": "file:packages/solarized-light-syntax", + "spell-check": "https://www.atom.io/api/packages/spell-check/versions/0.74.3/tarball", + "status-bar": "https://www.atom.io/api/packages/status-bar/versions/1.8.17/tarball", "styleguide": "https://www.atom.io/api/packages/styleguide/versions/0.49.12/tarball", "symbols-view": "https://www.atom.io/api/packages/symbols-view/versions/0.118.2/tarball", - "tabs": "https://www.atom.io/api/packages/tabs/versions/0.109.2/tarball", + "tabs": "https://www.atom.io/api/packages/tabs/versions/0.110.0/tarball", "temp": "^0.8.3", - "text-buffer": "13.15.0", + "text-buffer": "13.15.3", "timecop": "https://www.atom.io/api/packages/timecop/versions/0.36.2/tarball", "tree-sitter": "0.13.23", "tree-sitter-css": "^0.13.7", - "tree-view": "https://www.atom.io/api/packages/tree-view/versions/0.224.4/tarball", + "tree-view": "https://www.atom.io/api/packages/tree-view/versions/0.224.5/tarball", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.8", "update-package-dependencies": "https://www.atom.io/api/packages/update-package-dependencies/versions/0.13.1/tarball", "welcome": "https://www.atom.io/api/packages/welcome/versions/0.36.7/tarball", "whitespace": "https://www.atom.io/api/packages/whitespace/versions/0.37.7/tarball", "winreg": "^1.2.1", - "wrap-guide": "https://www.atom.io/api/packages/wrap-guide/versions/0.40.3/tarball", + "wrap-guide": "https://www.atom.io/api/packages/wrap-guide/versions/0.41.0/tarball", "yargs": "^3.23.0" }, "packageDependencies": { @@ -182,8 +180,8 @@ "one-light-ui": "file:./packages/one-light-ui", "one-dark-syntax": "file:./packages/one-dark-syntax", "one-light-syntax": "file:./packages/one-light-syntax", - "solarized-dark-syntax": "1.3.0", - "solarized-light-syntax": "1.3.0", + "solarized-dark-syntax": "file:./packages/solarized-dark-syntax", + "solarized-light-syntax": "file:./packages/solarized-light-syntax", "about": "file:./packages/about", "archive-view": "0.65.1", "autocomplete-atom-api": "0.10.7", @@ -194,55 +192,55 @@ "autoflow": "file:./packages/autoflow", "autosave": "0.24.6", "background-tips": "0.28.0", - "bookmarks": "0.45.1", - "bracket-matcher": "0.90.2", + "bookmarks": "0.46.0", + "bracket-matcher": "0.90.4", "command-palette": "0.43.5", "dalek": "file:./packages/dalek", "deprecation-cop": "file:./packages/deprecation-cop", "dev-live-reload": "file:./packages/dev-live-reload", "encoding-selector": "0.23.9", "exception-reporting": "file:./packages/exception-reporting", - "find-and-replace": "0.215.14", - "fuzzy-finder": "1.8.2", - "github": "0.23.0", + "find-and-replace": "0.218.0", + "fuzzy-finder": "1.9.0", + "github": "0.24.0", "git-diff": "file:./packages/git-diff", "go-to-line": "file:./packages/go-to-line", "grammar-selector": "file:./packages/grammar-selector", - "image-view": "0.63.1", + "image-view": "0.64.0", "incompatible-packages": "file:./packages/incompatible-packages", "keybinding-resolver": "0.38.4", "line-ending-selector": "file:./packages/line-ending-selector", "link": "file:./packages/link", "markdown-preview": "0.159.25", "metrics": "1.6.2", - "notifications": "0.70.5", + "notifications": "0.70.6", "open-on-github": "1.3.1", "package-generator": "1.3.0", - "settings-view": "0.257.2", + "settings-view": "0.258.0", "snippets": "1.4.0", - "spell-check": "0.74.2", - "status-bar": "1.8.15", + "spell-check": "0.74.3", + "status-bar": "1.8.17", "styleguide": "0.49.12", "symbols-view": "0.118.2", - "tabs": "0.109.2", + "tabs": "0.110.0", "timecop": "0.36.2", - "tree-view": "0.224.4", + "tree-view": "0.224.5", "update-package-dependencies": "0.13.1", "welcome": "0.36.7", "whitespace": "0.37.7", - "wrap-guide": "0.40.3", + "wrap-guide": "0.41.0", "language-c": "0.60.14", "language-clojure": "0.22.7", - "language-coffee-script": "0.49.3", + "language-coffee-script": "0.50.0", "language-csharp": "1.1.0", "language-css": "0.43.0", "language-gfm": "0.90.6", "language-git": "0.19.1", "language-go": "0.46.6", - "language-html": "0.51.5", + "language-html": "0.52.0", "language-hyperlink": "0.17.0", "language-java": "0.31.1", - "language-javascript": "0.129.18", + "language-javascript": "0.129.19", "language-json": "0.19.2", "language-less": "0.34.3", "language-make": "0.23.0", @@ -252,7 +250,7 @@ "language-php": "0.44.1", "language-property-list": "0.9.1", "language-python": "0.51.8", - "language-ruby": "0.72.14", + "language-ruby": "0.72.15", "language-ruby-on-rails": "0.25.3", "language-rust-bundled": "file:./packages/language-rust-bundled", "language-sass": "0.62.0", @@ -271,6 +269,7 @@ "preinstall": "node -e 'process.exit(0)'", "test": "node script/test" }, + "standard-engine": "./script/node_modules/standard", "standard": { "env": { "atomtest": true, diff --git a/packages/README.md b/packages/README.md index 800ba55c6..0ff6021de 100644 --- a/packages/README.md +++ b/packages/README.md @@ -87,8 +87,8 @@ See [RFC 003](https://github.com/atom/atom/blob/master/docs/rfcs/003-consolidate | **package-generator** | [`atom/package-generator`][package-generator] | [#18279](https://github.com/atom/atom/issues/18279) | | **settings-view** | [`atom/settings-view`][settings-view] | | | **snippets** | [`atom/snippets`][snippets] | | -| **solarized-dark-syntax** | [`atom/solarized-dark-syntax`][solarized-dark-syntax] | [#18280](https://github.com/atom/atom/issues/18280) | -| **solarized-light-syntax** | [`atom/solarized-light-syntax`][solarized-light-syntax] | [#18281](https://github.com/atom/atom/issues/18281) | +| **solarized-dark-syntax** | [`./solarized-dark-syntax`](./solarized-dark-syntax) | [#18280](https://github.com/atom/atom/issues/18280) | +| **solarized-light-syntax** | [`./solarized-light-syntax`](./solarized-light-syntax) | [#18281](https://github.com/atom/atom/issues/18281) | | **spell-check** | [`atom/spell-check`][spell-check] | | | **status-bar** | [`atom/status-bar`][status-bar] | [#18282](https://github.com/atom/atom/issues/18282) | | **styleguide** | [`atom/styleguide`][styleguide] | [#18283](https://github.com/atom/atom/issues/18283) | @@ -158,8 +158,6 @@ See [RFC 003](https://github.com/atom/atom/blob/master/docs/rfcs/003-consolidate [package-generator]: https://github.com/atom/package-generator [settings-view]: https://github.com/atom/settings-view [snippets]: https://github.com/atom/snippets -[solarized-dark-syntax]: https://github.com/atom/solarized-dark-syntax -[solarized-light-syntax]: https://github.com/atom/solarized-light-syntax [spell-check]: https://github.com/atom/spell-check [status-bar]: https://github.com/atom/status-bar [styleguide]: https://github.com/atom/styleguide diff --git a/packages/autoflow/lib/autoflow.coffee b/packages/autoflow/lib/autoflow.coffee index 3bb31745b..656d800e4 100644 --- a/packages/autoflow/lib/autoflow.coffee +++ b/packages/autoflow/lib/autoflow.coffee @@ -51,14 +51,30 @@ module.exports = tabLengthInSpaces = '' for block in paragraphBlocks + blockLines = block.split('\n') + + # For LaTeX tags surrounding the text, we simply ignore them, and + # reproduce them verbatim in the wrapped text. + beginningLinesToIgnore = [] + endingLinesToIgnore = [] + latexTagRegex = /^\s*\\\w+(\[.*\])?\{\w+\}(\[.*\])?\s*$/g # e.g. \begin{verbatim} + latexTagStartRegex = /^\s*\\\w+\s*\{\s*$/g # e.g. \item{ + latexTagEndRegex = /^\s*\}\s*$/g # e.g. } + while blockLines[0].match(latexTagRegex) or + blockLines[0].match(latexTagStartRegex) + beginningLinesToIgnore.push(blockLines[0]) + blockLines.shift() + while blockLines[blockLines.length - 1].match(latexTagRegex) or + blockLines[blockLines.length - 1].match(latexTagEndRegex) + endingLinesToIgnore.unshift(blockLines[blockLines.length - 1]) + blockLines.pop() # TODO: this could be more language specific. Use the actual comment char. # Remember that `-` has to be the last character in the character class. - linePrefix = block.match(/^\s*(\/\/|\/\*|;;|#'|\|\|\||--|[#%*>-])?\s*/g)[0] + linePrefix = blockLines[0].match(/^\s*(\/\/|\/\*|;;|#'|\|\|\||--|[#%*>-])?\s*/g)[0] linePrefixTabExpanded = linePrefix if tabLengthInSpaces linePrefixTabExpanded = linePrefix.replace(/\t/g, tabLengthInSpaces) - blockLines = block.split('\n') if linePrefix escapedLinePrefix = _.escapeRegExp(linePrefix) @@ -93,7 +109,8 @@ module.exports = currentLineLength += segment.length lines.push(linePrefix + currentLine.join('')) - paragraphs.push(lines.join('\n').replace(/\s+\n/g, '\n')) + wrappedLines = beginningLinesToIgnore.concat(lines.concat(endingLinesToIgnore)) + paragraphs.push(wrappedLines.join('\n').replace(/\s+\n/g, '\n')) leadingVerticalSpace + paragraphs.join('\n\n') + trailingVerticalSpace diff --git a/packages/autoflow/spec/autoflow-spec.coffee b/packages/autoflow/spec/autoflow-spec.coffee index e8b7ed81f..3e132305d 100644 --- a/packages/autoflow/spec/autoflow-spec.coffee +++ b/packages/autoflow/spec/autoflow-spec.coffee @@ -560,3 +560,71 @@ describe "Autoflow package", -> ''' expect(autoflow.reflow(test, wrapColumn: 80)).toEqual res + + it 'properly reflows text around LaTeX tags', -> + text = + ''' + \\begin{verbatim} + Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. Eget condimentum integer, porta sagittis nam, fusce vitae a vitae augue. Nec semper quis sed ut, est porttitor praesent. Nisl velit quam dolore velit quam, elementum neque pellentesque pulvinar et vestibulum. + \\end{verbatim} + ''' + + res = + ''' + \\begin{verbatim} + Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at + blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. Eget + condimentum integer, porta sagittis nam, fusce vitae a vitae augue. Nec + semper quis sed ut, est porttitor praesent. Nisl velit quam dolore velit + quam, elementum neque pellentesque pulvinar et vestibulum. + \\end{verbatim} + ''' + + expect(autoflow.reflow(text, wrapColumn: 80)).toEqual res + + it 'properly reflows text inside LaTeX tags', -> + text = + ''' + \\item{ + Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. Eget condimentum integer, porta sagittis nam, fusce vitae a vitae augue. Nec semper quis sed ut, est porttitor praesent. Nisl velit quam dolore velit quam, elementum neque pellentesque pulvinar et vestibulum. + } + ''' + + res = + ''' + \\item{ + Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at + blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. Eget + condimentum integer, porta sagittis nam, fusce vitae a vitae augue. Nec + semper quis sed ut, est porttitor praesent. Nisl velit quam dolore velit + quam, elementum neque pellentesque pulvinar et vestibulum. + } + ''' + + expect(autoflow.reflow(text, wrapColumn: 80)).toEqual res + + it 'properly reflows text inside nested LaTeX tags', -> + text = + ''' + \\begin{enumerate}[label=(\\alph*)] + \\item{ + Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. Eget condimentum integer, porta sagittis nam, fusce vitae a vitae augue. Nec semper quis sed ut, est porttitor praesent. Nisl velit quam dolore velit quam, elementum neque pellentesque pulvinar et vestibulum. + } + \\end{enumerate} + ''' + + res = + ''' + \\begin{enumerate}[label=(\\alph*)] + \\item{ + Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at + blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. + Eget condimentum integer, porta sagittis nam, fusce vitae a vitae augue. + Nec semper quis sed ut, est porttitor praesent. Nisl velit quam dolore + velit quam, elementum neque pellentesque pulvinar et vestibulum. + } + \\end{enumerate} + ''' + + expect(autoflow.reflow(text, wrapColumn: 80)).toEqual res + diff --git a/packages/language-rust-bundled/grammars/tree-sitter-rust.cson b/packages/language-rust-bundled/grammars/tree-sitter-rust.cson index f9361ddb0..6f77d1b90 100644 --- a/packages/language-rust-bundled/grammars/tree-sitter-rust.cson +++ b/packages/language-rust-bundled/grammars/tree-sitter-rust.cson @@ -79,6 +79,7 @@ scopes: ''' use_wildcard > identifier:nth-child(0), + use_wildcard > scoped_identifier > identifier:nth-child(2), scoped_type_identifier > identifier:nth-child(0), scoped_type_identifier > scoped_identifier:nth-child(0) > identifier, scoped_identifier > identifier:nth-child(0), diff --git a/packages/solarized-dark-syntax/LICENSE.md b/packages/solarized-dark-syntax/LICENSE.md new file mode 100644 index 000000000..4d231b456 --- /dev/null +++ b/packages/solarized-dark-syntax/LICENSE.md @@ -0,0 +1,20 @@ +Copyright (c) 2014 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/solarized-dark-syntax/README.md b/packages/solarized-dark-syntax/README.md new file mode 100644 index 000000000..e9092d48e --- /dev/null +++ b/packages/solarized-dark-syntax/README.md @@ -0,0 +1,9 @@ +# Solarized Dark Syntax theme + +Atom theme using the ever popular dark [solarized](http://ethanschoonover.com/solarized) colors. + +screenshot + +This theme is installed by default with Atom and can be activated by going to +the _Themes_ section in the Settings view (`cmd-,`) and selecting it from the +_Syntax Themes_ dropdown menu. diff --git a/packages/solarized-dark-syntax/index.less b/packages/solarized-dark-syntax/index.less new file mode 100644 index 000000000..3c3a0755a --- /dev/null +++ b/packages/solarized-dark-syntax/index.less @@ -0,0 +1,22 @@ +// Solarized Syntax Theme + +@import "styles/syntax-variables.less"; + +// Editor +@import "styles/editor.less"; + +// Languages +@import "styles/syntax/_base.less"; +@import "styles/syntax/c.less"; +@import "styles/syntax/coffee.less"; +@import "styles/syntax/css.less"; +@import "styles/syntax/go.less"; +@import "styles/syntax/java.less"; +@import "styles/syntax/javascript.less"; +@import "styles/syntax/markdown.less"; +@import "styles/syntax/markup.less"; +@import "styles/syntax/php.less"; +@import "styles/syntax/python.less"; +@import "styles/syntax/ruby.less"; +@import "styles/syntax/scala.less"; +@import "styles/syntax/typescript.less"; diff --git a/packages/solarized-dark-syntax/package.json b/packages/solarized-dark-syntax/package.json new file mode 100644 index 000000000..ae41754ae --- /dev/null +++ b/packages/solarized-dark-syntax/package.json @@ -0,0 +1,11 @@ +{ + "name": "solarized-dark-syntax", + "theme": "syntax", + "version": "1.3.0", + "description": "A dark syntax theme using the solarized colors", + "repository": "https://github.com/atom/atom", + "license": "MIT", + "engines": { + "atom": ">0.50.0" + } +} diff --git a/packages/solarized-dark-syntax/styles/colors.less b/packages/solarized-dark-syntax/styles/colors.less new file mode 100644 index 000000000..93050c438 --- /dev/null +++ b/packages/solarized-dark-syntax/styles/colors.less @@ -0,0 +1,27 @@ + +// Solarized color scheme +// http://ethanschoonover.com/solarized#the-values + +// Background/Foreground Tones +@base03: #002b36; +@base02: #073642; + +// Content Tones +@base01: #586e75; +@base00: #657b83; +@base0: #839496; +@base1: #93a1a1; + +// Background/Foreground Tones +@base2: #eee8d5; +@base3: #fdf6e3; + +// Accent Colors +@yellow: #b58900; +@orange: #cb4b16; +@red: #dc322f; +@magenta: #d33682; +@violet: #6c71c4; +@blue: #268bd2; +@cyan: #2aa198; +@green: #859900; diff --git a/packages/solarized-dark-syntax/styles/editor.less b/packages/solarized-dark-syntax/styles/editor.less new file mode 100644 index 000000000..d46a53781 --- /dev/null +++ b/packages/solarized-dark-syntax/styles/editor.less @@ -0,0 +1,44 @@ +atom-text-editor { + color: @syntax-text-color; + background-color: @syntax-background-color; + + .gutter { + color: @syntax-gutter-text-color; + background-color: @syntax-gutter-background-color; + + .line-number { + &.cursor-line { + background-color: @syntax-gutter-background-color-selected; + } + } + } + + .invisible-character { + color: @syntax-invisible-character-color; + } + + .indent-guide { + color: @syntax-indent-guide-color; + } + + .cursor { + border-color: @syntax-cursor-color; + } + + .cursor-line { + background-color: @syntax-cursor-line; + } + + .selection .region { + background-color: @syntax-selection-color; + } + + .fold-marker:after, + .gutter .line-number.folded { + color: @magenta; + } + + .bracket-matcher .region { + border-color: @magenta; + } +} diff --git a/packages/solarized-dark-syntax/styles/syntax-variables.less b/packages/solarized-dark-syntax/styles/syntax-variables.less new file mode 100644 index 000000000..2f3a5d019 --- /dev/null +++ b/packages/solarized-dark-syntax/styles/syntax-variables.less @@ -0,0 +1,55 @@ +@import "colors.less"; + +// This defines all syntax variables that syntax themes must implement when they +// include a syntax-variables.less file. + +// General colors +@syntax-text-color: @base0; +@syntax-cursor-color: @base3; +@syntax-selection-color: lighten(@base02, 1%); +@syntax-selection-flash-color: @base1; +@syntax-background-color: @base03; + +// Guide colors +@syntax-wrap-guide-color: lighten(@base02, 6%); +@syntax-indent-guide-color: lighten(@base02, 6%); +@syntax-invisible-character-color: lighten(@base02, 6%); + +// For find and replace markers +@syntax-result-marker-color: @cyan; +@syntax-result-marker-color-selected: @base3; + +// Gutter colors +@syntax-gutter-text-color: @base0; +@syntax-gutter-text-color-selected: @base2; +@syntax-gutter-background-color: @base02; +@syntax-gutter-background-color-selected: lighten(@base02, 6%); + +// For git diff info. i.e. in the gutter +@syntax-color-added: @green; +@syntax-color-renamed: @blue; +@syntax-color-modified: @yellow; +@syntax-color-removed: @red; + +// For language entity colors +@syntax-color-variable: @blue; +@syntax-color-constant: @yellow; +@syntax-color-property: @yellow; +@syntax-color-value: @cyan; +@syntax-color-function: @blue; +@syntax-color-method: @blue; +@syntax-color-class: @blue; +@syntax-color-keyword: @green; +@syntax-color-tag: @blue; +@syntax-color-attribute: @syntax-comment-color; +@syntax-color-import: @red; +@syntax-color-snippet: @syntax-color-keyword; + + +// Custom variables +// Warning: Don't use in packages + +@syntax-comment-color: @base01; +@syntax-subtle-color: @base00; +@syntax-emphasized-color: @base1; +@syntax-cursor-line: fade(lighten(@syntax-background-color, 30%), 8%); // needs to be semi-transparent diff --git a/packages/solarized-dark-syntax/styles/syntax/_base.less b/packages/solarized-dark-syntax/styles/syntax/_base.less new file mode 100644 index 000000000..e176941fc --- /dev/null +++ b/packages/solarized-dark-syntax/styles/syntax/_base.less @@ -0,0 +1,100 @@ +.syntax--comment { + color: @syntax-comment-color; + font-style: italic; + + .syntax--markup.syntax--link { + color: @syntax-comment-color; + } +} + +.syntax--string { + color: @cyan; + &.syntax--regexp { + color: @red; + } +} + +.syntax--constant { + &.syntax--numeric { + color: @magenta; + } + &.syntax--language { + color: @yellow; + } + &.syntax--character, + &.syntax--other, + &.syntax--support { + color: @orange; + } +} + +.syntax--variable { + color: @blue; +} + +.syntax--keyword { + color: @green; +} + +.syntax--storage { + color: @green; +} + +.syntax--meta.syntax--class { + color: @blue; +} + +.syntax--entity { + &.syntax--name { + &.syntax--class, + &.syntax--function, + &.syntax--section, + &.syntax--type { + color: @blue; + } + } + &.syntax--other.syntax--attribute-name { + color: @syntax-subtle-color; + } +} + +.syntax--support { + &.syntax--function { + color: @blue; + &.syntax--builtin { + color: @green; + } + } + &.syntax--type, + &.syntax--class { + color: @green; + } +} + +.syntax--tag { + &.syntax--entity.syntax--name { + color: @blue; + } + &.syntax--punctuation.syntax--definition { + &.syntax--html, + &.syntax--begin, + &.syntax--end { + color: @syntax-comment-color; + } + } +} + +.syntax--invalid { + &.syntax--deprecated { + color: @yellow; + text-decoration: underline; + } + &.syntax--illegal { + color: @red; + text-decoration: underline; + } +} + +.syntax--none { + color: @syntax-text-color; +} diff --git a/packages/solarized-dark-syntax/styles/syntax/c.less b/packages/solarized-dark-syntax/styles/syntax/c.less new file mode 100644 index 000000000..9a094bcad --- /dev/null +++ b/packages/solarized-dark-syntax/styles/syntax/c.less @@ -0,0 +1,44 @@ +.syntax--source.syntax--c, +.syntax--source.syntax--cpp { + .syntax--meta.syntax--preprocessor { + color: @red; + } + .syntax--keyword.syntax--control.syntax--directive { + color: @orange; + } + .syntax--punctuation.syntax--string { + color: @cyan; + } + .syntax--constant { + color: @orange; + + &.syntax--numeric, &.syntax--language.syntax--c { + color: @cyan; + } + } + .syntax--storage { + color: @yellow; + } + .syntax--entity { + color: @syntax-text-color; + + &.syntax--name.syntax--function.syntax--preprocessor { + color: @red; + } + } + .syntax--support.syntax--type { + color: @yellow; + + &.syntax--posix-reserved { + color: @syntax-text-color; + } + } + .syntax--variable { + &.syntax--other.syntax--dot-access { + color: @syntax-text-color; + } + &.syntax--parameter.syntax--preprocessor { + color: @red; + } + } +} diff --git a/packages/solarized-dark-syntax/styles/syntax/coffee.less b/packages/solarized-dark-syntax/styles/syntax/coffee.less new file mode 100644 index 000000000..c353f72a3 --- /dev/null +++ b/packages/solarized-dark-syntax/styles/syntax/coffee.less @@ -0,0 +1,58 @@ +.syntax--source.syntax--coffee { + .syntax--support.syntax--class { + color: @green; + } + + .syntax--variable, + .syntax--entity.syntax--name.syntax--function, + .syntax--entity.syntax--name.syntax--class { + color: @blue; + } + .syntax--variable.syntax--parameter.syntax--function { + color: @syntax-text-color; + } + .syntax--variable.syntax--other.syntax--readwrite { + color: @green; + } + + .syntax--storage.syntax--type.syntax--function { + color: @green; + } + + .syntax--entity.syntax--name { + color: @syntax-text-color; + } + + .syntax--meta.syntax--brace { + &.syntax--round, + &.syntax--square { + color: @syntax-text-color; + } + } + .syntax--meta.syntax--delimiter { + color: @syntax-text-color; + } + + .syntax--storage.syntax--type.syntax--class { + color: @green; + } + + .syntax--punctuation.syntax--terminator { + color: @syntax-text-color; + } + + .syntax--punctuation.syntax--section.syntax--embedded { + color: @red; + } + .syntax--embedded.syntax--source { + color: @syntax-text-color; + } + + .syntax--constant.syntax--numeric { + color: @magenta; + } + + .syntax--constant.syntax--language.syntax--boolean { + color: @yellow; + } +} diff --git a/packages/solarized-dark-syntax/styles/syntax/css.less b/packages/solarized-dark-syntax/styles/syntax/css.less new file mode 100644 index 000000000..8bfaf8c34 --- /dev/null +++ b/packages/solarized-dark-syntax/styles/syntax/css.less @@ -0,0 +1,63 @@ +.syntax--source.syntax--css { + + .syntax--punctuation { + &.syntax--separator, + &.syntax--terminator { + color: @syntax-text-color; + } + &.syntax--property-list.syntax--begin, + &.syntax--property-list.syntax--end { + color: @red; + } + &.syntax--section.syntax--function { + color: @cyan; + } + } + + .syntax--entity.syntax--name { + color: @green; + } + .syntax--attribute-name.syntax--class, + .syntax--id { + color: @blue; + } + .syntax--pseudo-element, + .syntax--pseudo-class { + color: @orange; + } + + .syntax--property-value { + color: @cyan; + } + .syntax--constant.syntax--numeric { + color: @cyan; + .syntax--unit { + color: @cyan; + } + } + .syntax--rgb-value { + color: @cyan; + } + .syntax--support.syntax--constant { + color: @cyan; + &.syntax--media { + color: @red; + } + } + + .syntax--keyword.syntax--important { + color: @red; + } + +} + + +// Less/Sass should have their own files, +// but for just a single override, here should be fine too + +.syntax--source.syntax--less, +.syntax--source.syntax--scss { + .syntax--keyword.syntax--unit { + color: @cyan; + } +} diff --git a/packages/solarized-dark-syntax/styles/syntax/go.less b/packages/solarized-dark-syntax/styles/syntax/go.less new file mode 100644 index 000000000..b12558e83 --- /dev/null +++ b/packages/solarized-dark-syntax/styles/syntax/go.less @@ -0,0 +1,10 @@ +.syntax--source.syntax--go { + + .syntax--operator { + color: @syntax-text-color; + &.syntax--assignment { + color: @green; + } + } + +} diff --git a/packages/solarized-dark-syntax/styles/syntax/java.less b/packages/solarized-dark-syntax/styles/syntax/java.less new file mode 100644 index 000000000..6fa5c64a7 --- /dev/null +++ b/packages/solarized-dark-syntax/styles/syntax/java.less @@ -0,0 +1,47 @@ +.syntax--source.syntax--java { + .syntax--keyword.syntax--operator{ + color:@green; + } + .syntax--keyword.syntax--import{ + color: @orange; + } + .syntax--storage.syntax--modifier.syntax--import{ + color: @syntax-comment-color; + } + .syntax--meta.syntax--class{ + .syntax--storage.syntax--modifier{ + color: @yellow; + } + .syntax--meta.syntax--class.syntax--identifier{ + .syntax--entity.syntax--name.syntax--type.syntax--class{ + color: @blue; + } + } + } + .syntax--storage.syntax--type.syntax--primitive.syntax--array{ + color:@green; + } + .syntax--constant.syntax--numeric{ + color:@magenta; + } + .syntax--constant.syntax--other{ + color:@orange; + } + .syntax--storage.syntax--type{ + color:@green; + } + .syntax--meta.syntax--method-call{ + //@ibocon: method parameter's color + color:@red; + //@ibocon: method and variable use different hightlight + .syntax--meta.syntax--method{ + color:@violet; + } + .syntax--punctuation.syntax--definition.syntax--seperator.syntax--parameter{ + color:@green; + } + } + .syntax--punctuation.syntax--definition.syntax--method-parameters{ + color: @syntax-emphasized-color; + } +} diff --git a/packages/solarized-dark-syntax/styles/syntax/javascript.less b/packages/solarized-dark-syntax/styles/syntax/javascript.less new file mode 100644 index 000000000..ebd1e7db8 --- /dev/null +++ b/packages/solarized-dark-syntax/styles/syntax/javascript.less @@ -0,0 +1,128 @@ +.syntax--source.syntax--js { + .syntax--comma { + color: @syntax-text-color; + } + + .syntax--support.syntax--class { + color: @green; + } + + .syntax--entity { + &.syntax--name.syntax--type { + color: @yellow; + } + &.syntax--name { + color: @syntax-text-color; + + &.syntax--function { + color: @blue; + } + } + + &.syntax--name.syntax--tag { + color: @blue; + } + + &.syntax--other.syntax--attribute-name { + color: @yellow; + } + } + + + .syntax--meta.syntax--brace { + color: @syntax-text-color; + } + + .syntax--keyword { + color: @syntax-text-color; + } + .syntax--keyword.syntax--operator.syntax--new { + color: @green; + } + .syntax--keyword.syntax--control { + color: @orange; + } + .syntax--keyword.syntax--control.syntax--regexp { + color: @cyan; + } + + .syntax--variable { + color: @syntax-text-color; + } + .syntax--variable.syntax--dom { + color: @green; + } + .syntax--delimiter + .syntax--dom { + color: @syntax-text-color; + } + .syntax--name { + color: @syntax-text-color; + } + .syntax--variable.syntax--language { + color: @blue; + } + .syntax--variable.syntax--parameter { + color: @syntax-text-color; + } + + .syntax--regexp { + color: @cyan; + } + + .syntax--support.syntax--function { + color: @syntax-text-color; + } + .syntax--support.syntax--constant { + color: @syntax-text-color; + } + + .syntax--storage.syntax--modifier { + color: @yellow; + } + + .syntax--punctuation.syntax--terminator.syntax--statement { + color: @syntax-text-color; + } + + .syntax--meta.syntax--delimiter.syntax--method.syntax--period { + color: @syntax-text-color; + } + .syntax--meta.syntax--brace.syntax--square { + color: @blue; + } + .syntax--meta.syntax--brace.syntax--curly { + color: @blue; + } + + .syntax--string.syntax--quoted.syntax--template { + .syntax--embedded.syntax--source { + color: @syntax-text-color; + & > .syntax--embedded.syntax--punctuation { + color: @red; + } + } + } + + &.syntax--embedded .syntax--entity.syntax--name.syntax--tag { + color: @blue; + } + + .syntax--import { + .syntax--control { + color: @orange; + } + } +} + + +// JavaScript (Rails) language-ruby-on-rails + +.syntax--source.syntax--js.syntax--rails { + .syntax--instance { + color: @blue; + } + + .syntax--class { + color: @yellow; + } +} diff --git a/packages/solarized-dark-syntax/styles/syntax/markdown.less b/packages/solarized-dark-syntax/styles/syntax/markdown.less new file mode 100644 index 000000000..2ca0038d9 --- /dev/null +++ b/packages/solarized-dark-syntax/styles/syntax/markdown.less @@ -0,0 +1,26 @@ +.syntax--md, +.syntax--gfm { + .syntax--link .syntax--entity { + color: @violet; + } + + .syntax--list { + &.syntax--ordered { + color: @green; + } + &.syntax--unordered { + color: @yellow; + } + } + + .syntax--raw { + font-style: italic; + } + + &.syntax--support { + color:@syntax-comment-color; + &.syntax--quote { + color: @violet; + } + } +} diff --git a/packages/solarized-dark-syntax/styles/syntax/markup.less b/packages/solarized-dark-syntax/styles/syntax/markup.less new file mode 100644 index 000000000..f94b56f5b --- /dev/null +++ b/packages/solarized-dark-syntax/styles/syntax/markup.less @@ -0,0 +1,30 @@ +.syntax--markup { + + &.syntax--bold { + font-weight: bold; + } + &.syntax--italic { + font-style: italic; + } + + &.syntax--heading { + color: @blue; + } + + &.syntax--link { + color: @cyan; + } + + &.syntax--deleted { + color: @red; + } + + &.syntax--changed { + color: @yellow; + } + + &.syntax--inserted { + color: @cyan; + } + +} diff --git a/packages/solarized-dark-syntax/styles/syntax/php.less b/packages/solarized-dark-syntax/styles/syntax/php.less new file mode 100644 index 000000000..8eb510d41 --- /dev/null +++ b/packages/solarized-dark-syntax/styles/syntax/php.less @@ -0,0 +1,67 @@ +.syntax--source.syntax--php { + .syntax--storage { + &.syntax--type { + &.syntax--class { + color: @yellow; + } + &.syntax--function { + color: @orange; + } + } + &.syntax--modifier { + color: @yellow; + } + } + .syntax--entity { + &.syntax--name { + &.syntax--type.syntax--class { + color: @syntax-text-color; + } + &.syntax--function { + color: @syntax-text-color; + } + } + &.syntax--other { + color: @syntax-text-color; + } + } + .syntax--variable { + color: @blue; + } + .syntax--punctuation.syntax--definition { + color: @syntax-text-color; + &.syntax--comment { + color: @syntax-comment-color; + } + &.syntax--array { + color: @red; + } + &.syntax--string { + color: @syntax-text-color; + } + &.syntax--variable { + color: @green; + } + } + .syntax--support.syntax--function { + &.syntax--construct { + color: @yellow; + } + &.syntax--array { + color: @green; + } + } + .syntax--keyword { + &.syntax--operator { + &.syntax--class { + color: @yellow; + } + &.syntax--assignment { + color: @green; + } + } + &.syntax--other { + color: @red; + } + } +} diff --git a/packages/solarized-dark-syntax/styles/syntax/python.less b/packages/solarized-dark-syntax/styles/syntax/python.less new file mode 100644 index 000000000..ffe29ba2b --- /dev/null +++ b/packages/solarized-dark-syntax/styles/syntax/python.less @@ -0,0 +1,100 @@ +.syntax--source.syntax--python { + .syntax--entity { + color: @syntax-text-color; + + &.syntax--name { + color: @blue; + } + &.syntax--other { + color: @blue; + } + } + + .syntax--function { + color: @blue; + + &.syntax--magic { + color: @blue; + } + } + + .syntax--punctuation.syntax--string { + color: @cyan; + } + .syntax--keyword { + &.syntax--operator { + color: @syntax-text-color; + &.syntax--quantifier { + color: @cyan; + } + &.syntax--logical { + color: @green; + } + } + &.syntax--control.syntax--import { + color: @orange; + } + &.syntax--other { + color: @green; + } + } + .syntax--constant { + &.syntax--language { + color: @blue; + } + &.syntax--character { + color: @cyan; + } + &.syntax--other { + color: @red; + } + } + + .syntax--entity.syntax--name.syntax--type.syntax--class { + color: @blue; + } + .syntax--variable { + color: @syntax-text-color; + } + .syntax--support { + &.syntax--function.syntax--builtin { + color: @blue; + } + &.syntax--type { + &.syntax--exception.syntax--python { + color: @yellow; + } + &.syntax--python { + color: @blue; + } + } + } + .syntax--storage.syntax--type.syntax--string { + color: @cyan; + } + + .syntax--storage.syntax--type.syntax--class { + color: @green; + &.syntax--todo { + color: @magenta; + } + } + + .syntax--storage.syntax--type.syntax--function { + color: @green; + } + + .syntax--punctuation.syntax--definition.syntax--parameters { + color: @syntax-text-color; + } + + .syntax--punctuation.syntax--section.syntax--function.syntax--begin { + color: @syntax-text-color; + } + + .syntax--punctuation.syntax--separator.syntax--parameters { + color: @syntax-text-color; + } + + +} diff --git a/packages/solarized-dark-syntax/styles/syntax/ruby.less b/packages/solarized-dark-syntax/styles/syntax/ruby.less new file mode 100644 index 000000000..3e3d8b58c --- /dev/null +++ b/packages/solarized-dark-syntax/styles/syntax/ruby.less @@ -0,0 +1,129 @@ +.syntax--source.syntax--ruby { + + .syntax--meta.syntax--embedded { + .syntax--punctuation.syntax--section { + color: @red; + } + } + .syntax--punctuation.syntax--definition { + color: @syntax-text-color; + &.syntax--string { + color: @red; + } + } + .syntax--punctuation.syntax--definition.syntax--comment { + color: @syntax-comment-color; + } + .syntax--entity.syntax--inherited-class { + color: @yellow; + } + .syntax--variable { + &.syntax--parameter { + color: @syntax-text-color; + } + } + .syntax--variable.syntax--constant { + color: @yellow; + } + .syntax--constant.syntax--boolean { + color: @cyan; + } + .syntax--instance { + .syntax--punctuation.syntax--definition { + color: @blue; + } + } + .syntax--class { + color: @yellow; + &.syntax--control { + color: @syntax-text-color; + } + } + .syntax--module { + color: @yellow; + } + .syntax--require { + .syntax--keyword.syntax--other.syntax--special-method { + color: @orange; + } + } + .syntax--keyword.syntax--other.syntax--special-method { + color: @orange; + } + .syntax--keyword.syntax--other { + color: @green; + } + .syntax--keyword.syntax--control { + color: @green; + } + .syntax--keyword.syntax--operator { + color: @syntax-text-color; + } + .syntax--special-method { + color: @blue; + } + .syntax--symbol { + color: @cyan; + .syntax--punctuation.syntax--definition { + color: @cyan; + } + } + .syntax--hashkey { + color: @red; + .syntax--punctuation.syntax--definition { + color: @red; + } + } + .syntax--string.syntax--regexp { + color: @red; + } + .syntax--todo { + color: @magenta; + } + .syntax--variable.syntax--ruby.syntax--global { + color: @blue; + .syntax--punctuation { + color: @blue; + } + } + .syntax--variable.syntax--block { + color: @blue; + } + .syntax--variable.syntax--self { + color: @cyan; + } + .syntax--punctuation.syntax--separator { + color: @syntax-text-color; + } + .syntax--numeric { + color: @cyan; + } + .syntax--punctuation.syntax--section.syntax--regexp { + color: @red; + } + .syntax--string.syntax--interpolated { + color: @cyan; + } + .syntax--string.syntax--interpolated { + .syntax--embedded.syntax--line.syntax--ruby { + .syntax--punctuation { + .syntax--source.syntax--ruby { + color: @red; + } + } + .syntax--source.syntax--ruby { + .syntax--punctuation.syntax--array, + .syntax--punctuation.syntax--function { + color: @syntax-text-color; + } + color: @syntax-text-color; + } + } + } + .syntax--support.syntax--function { + color: @syntax-text-color; + } + .syntax--support.syntax--function.syntax--kernel { + color: @green; + } +} diff --git a/packages/solarized-dark-syntax/styles/syntax/scala.less b/packages/solarized-dark-syntax/styles/syntax/scala.less new file mode 100644 index 000000000..376514087 --- /dev/null +++ b/packages/solarized-dark-syntax/styles/syntax/scala.less @@ -0,0 +1,79 @@ +.syntax--source.syntax--scala { + .syntax--variable { + color: @syntax-emphasized-color; + } + + .syntax--declaration { + color: @syntax-emphasized-color; + font-weight: bold; + } + .syntax--comparison { + color: @syntax-emphasized-color; + } + .syntax--class, .syntax--type { + color: @yellow; + } + .syntax--val { + font-weight: normal; + } + .syntax--variable { + font-weight: bold; + } + .syntax--variable.syntax--parameter { + color: @violet; + font-weight: normal; + } + .syntax--control.syntax--flow { + color: @syntax-emphasized-color; + font-weight: bold; + } + .syntax--constant.syntax--language { + color: @syntax-emphasized-color; + font-weight: bold; + } + .syntax--function.syntax--declaration { + color: @violet; + } + .syntax--modifier.syntax--other { + font-weight: bold; + } + .syntax--package { + color: @syntax-emphasized-color; + } + .syntax--variable.syntax--import { + font-weight: normal; + } + + .syntax--type { + .syntax--bounds, .syntax--class { + color: @violet; + } + } + + .syntax--documentation { + :not(.syntax--embedded) { + // out of scope ? + // https://github.syntax--com/atom/link + &.syntax--link.syntax--entity { + color: @blue; + text-decoration: underline; + } + .syntax--class, .syntax--parameter { + color: @syntax-emphasized-color; + } + .syntax--description { + color: @syntax-comment-color; + } + } + } + + .syntax--embedded { + color: darken(@syntax-emphasized-color, 15%); + + // so we dont confused it with normal expressions + font-style: italic; + .syntax--margin, .syntax--delimiters { + font-style: normal; + } + } +} diff --git a/packages/solarized-dark-syntax/styles/syntax/typescript.less b/packages/solarized-dark-syntax/styles/syntax/typescript.less new file mode 100644 index 000000000..1a3288073 --- /dev/null +++ b/packages/solarized-dark-syntax/styles/syntax/typescript.less @@ -0,0 +1,22 @@ +.syntax--source.syntax--ts, +.syntax--source.syntax--tsx { + .syntax--import { + .syntax--control { + color: @orange; + } + } + + .syntax--entity { + &.syntax--name.syntax--type { + color: @yellow; + } + + &.syntax--inherited-class { + color: @yellow; + } + } + + .syntax--support.syntax--type { + color: @yellow; + } +} diff --git a/packages/solarized-light-syntax/LICENSE.md b/packages/solarized-light-syntax/LICENSE.md new file mode 100644 index 000000000..4d231b456 --- /dev/null +++ b/packages/solarized-light-syntax/LICENSE.md @@ -0,0 +1,20 @@ +Copyright (c) 2014 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/solarized-light-syntax/README.md b/packages/solarized-light-syntax/README.md new file mode 100644 index 000000000..8a0adbd83 --- /dev/null +++ b/packages/solarized-light-syntax/README.md @@ -0,0 +1,9 @@ +# Solarized Light Syntax theme + +Atom theme using the ever popular light [solarized](http://ethanschoonover.com/solarized) colors. + +screenshot + +This theme is installed by default with Atom and can be activated by going to +the _Themes_ section in the Settings view (`cmd-,`) and selecting it from the +_Syntax Themes_ dropdown menu. diff --git a/packages/solarized-light-syntax/index.less b/packages/solarized-light-syntax/index.less new file mode 100644 index 000000000..3c3a0755a --- /dev/null +++ b/packages/solarized-light-syntax/index.less @@ -0,0 +1,22 @@ +// Solarized Syntax Theme + +@import "styles/syntax-variables.less"; + +// Editor +@import "styles/editor.less"; + +// Languages +@import "styles/syntax/_base.less"; +@import "styles/syntax/c.less"; +@import "styles/syntax/coffee.less"; +@import "styles/syntax/css.less"; +@import "styles/syntax/go.less"; +@import "styles/syntax/java.less"; +@import "styles/syntax/javascript.less"; +@import "styles/syntax/markdown.less"; +@import "styles/syntax/markup.less"; +@import "styles/syntax/php.less"; +@import "styles/syntax/python.less"; +@import "styles/syntax/ruby.less"; +@import "styles/syntax/scala.less"; +@import "styles/syntax/typescript.less"; diff --git a/packages/solarized-light-syntax/package.json b/packages/solarized-light-syntax/package.json new file mode 100644 index 000000000..fd13b2203 --- /dev/null +++ b/packages/solarized-light-syntax/package.json @@ -0,0 +1,11 @@ +{ + "name": "solarized-light-syntax", + "theme": "syntax", + "version": "1.3.0", + "description": "A light syntax theme using the solarized colors", + "repository": "https://github.com/atom/atom", + "license": "MIT", + "engines": { + "atom": ">0.50.0" + } +} diff --git a/packages/solarized-light-syntax/styles/colors.less b/packages/solarized-light-syntax/styles/colors.less new file mode 100644 index 000000000..93050c438 --- /dev/null +++ b/packages/solarized-light-syntax/styles/colors.less @@ -0,0 +1,27 @@ + +// Solarized color scheme +// http://ethanschoonover.com/solarized#the-values + +// Background/Foreground Tones +@base03: #002b36; +@base02: #073642; + +// Content Tones +@base01: #586e75; +@base00: #657b83; +@base0: #839496; +@base1: #93a1a1; + +// Background/Foreground Tones +@base2: #eee8d5; +@base3: #fdf6e3; + +// Accent Colors +@yellow: #b58900; +@orange: #cb4b16; +@red: #dc322f; +@magenta: #d33682; +@violet: #6c71c4; +@blue: #268bd2; +@cyan: #2aa198; +@green: #859900; diff --git a/packages/solarized-light-syntax/styles/editor.less b/packages/solarized-light-syntax/styles/editor.less new file mode 100644 index 000000000..d46a53781 --- /dev/null +++ b/packages/solarized-light-syntax/styles/editor.less @@ -0,0 +1,44 @@ +atom-text-editor { + color: @syntax-text-color; + background-color: @syntax-background-color; + + .gutter { + color: @syntax-gutter-text-color; + background-color: @syntax-gutter-background-color; + + .line-number { + &.cursor-line { + background-color: @syntax-gutter-background-color-selected; + } + } + } + + .invisible-character { + color: @syntax-invisible-character-color; + } + + .indent-guide { + color: @syntax-indent-guide-color; + } + + .cursor { + border-color: @syntax-cursor-color; + } + + .cursor-line { + background-color: @syntax-cursor-line; + } + + .selection .region { + background-color: @syntax-selection-color; + } + + .fold-marker:after, + .gutter .line-number.folded { + color: @magenta; + } + + .bracket-matcher .region { + border-color: @magenta; + } +} diff --git a/packages/solarized-light-syntax/styles/syntax-variables.less b/packages/solarized-light-syntax/styles/syntax-variables.less new file mode 100644 index 000000000..79d7b36e9 --- /dev/null +++ b/packages/solarized-light-syntax/styles/syntax-variables.less @@ -0,0 +1,55 @@ +@import "colors.less"; + +// This defines all syntax variables that syntax themes must implement when they +// include a syntax-variables.less file. + +// General colors +@syntax-text-color: @base00; +@syntax-cursor-color: @base03; +@syntax-selection-color: @base2; +@syntax-selection-flash-color: @base0; +@syntax-background-color: @base3; + +// Guide colors +@syntax-wrap-guide-color: darken(@base2, 12%); +@syntax-indent-guide-color: darken(@base2, 12%); +@syntax-invisible-character-color: darken(@base2, 12%); + +// For find and replace markers +@syntax-result-marker-color: @base1; +@syntax-result-marker-color-selected: @base03; + +// Gutter colors +@syntax-gutter-text-color: @base00; +@syntax-gutter-text-color-selected: @base03; +@syntax-gutter-background-color: @base2; +@syntax-gutter-background-color-selected: darken(@syntax-gutter-background-color, 10%); + +// For git diff info. i.e. in the gutter +@syntax-color-added: @green; +@syntax-color-renamed: @blue; +@syntax-color-modified: @yellow; +@syntax-color-removed: @red; + +// For language entity colors +@syntax-color-variable: @blue; +@syntax-color-constant: @yellow; +@syntax-color-property: @yellow; +@syntax-color-value: @cyan; +@syntax-color-function: @blue; +@syntax-color-method: @blue; +@syntax-color-class: @blue; +@syntax-color-keyword: @green; +@syntax-color-tag: @blue; +@syntax-color-attribute: @syntax-comment-color; +@syntax-color-import: @red; +@syntax-color-snippet: @syntax-color-keyword; + + +// Custom variables +// Warning: Don't use in packages + +@syntax-comment-color: @base1; +@syntax-subtle-color: @base00; +@syntax-emphasized-color: @base01; +@syntax-cursor-line: fade(darken(@syntax-background-color, 30%), 15%); // needs to be semi-transparent diff --git a/packages/solarized-light-syntax/styles/syntax/_base.less b/packages/solarized-light-syntax/styles/syntax/_base.less new file mode 100644 index 000000000..e176941fc --- /dev/null +++ b/packages/solarized-light-syntax/styles/syntax/_base.less @@ -0,0 +1,100 @@ +.syntax--comment { + color: @syntax-comment-color; + font-style: italic; + + .syntax--markup.syntax--link { + color: @syntax-comment-color; + } +} + +.syntax--string { + color: @cyan; + &.syntax--regexp { + color: @red; + } +} + +.syntax--constant { + &.syntax--numeric { + color: @magenta; + } + &.syntax--language { + color: @yellow; + } + &.syntax--character, + &.syntax--other, + &.syntax--support { + color: @orange; + } +} + +.syntax--variable { + color: @blue; +} + +.syntax--keyword { + color: @green; +} + +.syntax--storage { + color: @green; +} + +.syntax--meta.syntax--class { + color: @blue; +} + +.syntax--entity { + &.syntax--name { + &.syntax--class, + &.syntax--function, + &.syntax--section, + &.syntax--type { + color: @blue; + } + } + &.syntax--other.syntax--attribute-name { + color: @syntax-subtle-color; + } +} + +.syntax--support { + &.syntax--function { + color: @blue; + &.syntax--builtin { + color: @green; + } + } + &.syntax--type, + &.syntax--class { + color: @green; + } +} + +.syntax--tag { + &.syntax--entity.syntax--name { + color: @blue; + } + &.syntax--punctuation.syntax--definition { + &.syntax--html, + &.syntax--begin, + &.syntax--end { + color: @syntax-comment-color; + } + } +} + +.syntax--invalid { + &.syntax--deprecated { + color: @yellow; + text-decoration: underline; + } + &.syntax--illegal { + color: @red; + text-decoration: underline; + } +} + +.syntax--none { + color: @syntax-text-color; +} diff --git a/packages/solarized-light-syntax/styles/syntax/c.less b/packages/solarized-light-syntax/styles/syntax/c.less new file mode 100644 index 000000000..9a094bcad --- /dev/null +++ b/packages/solarized-light-syntax/styles/syntax/c.less @@ -0,0 +1,44 @@ +.syntax--source.syntax--c, +.syntax--source.syntax--cpp { + .syntax--meta.syntax--preprocessor { + color: @red; + } + .syntax--keyword.syntax--control.syntax--directive { + color: @orange; + } + .syntax--punctuation.syntax--string { + color: @cyan; + } + .syntax--constant { + color: @orange; + + &.syntax--numeric, &.syntax--language.syntax--c { + color: @cyan; + } + } + .syntax--storage { + color: @yellow; + } + .syntax--entity { + color: @syntax-text-color; + + &.syntax--name.syntax--function.syntax--preprocessor { + color: @red; + } + } + .syntax--support.syntax--type { + color: @yellow; + + &.syntax--posix-reserved { + color: @syntax-text-color; + } + } + .syntax--variable { + &.syntax--other.syntax--dot-access { + color: @syntax-text-color; + } + &.syntax--parameter.syntax--preprocessor { + color: @red; + } + } +} diff --git a/packages/solarized-light-syntax/styles/syntax/coffee.less b/packages/solarized-light-syntax/styles/syntax/coffee.less new file mode 100644 index 000000000..c353f72a3 --- /dev/null +++ b/packages/solarized-light-syntax/styles/syntax/coffee.less @@ -0,0 +1,58 @@ +.syntax--source.syntax--coffee { + .syntax--support.syntax--class { + color: @green; + } + + .syntax--variable, + .syntax--entity.syntax--name.syntax--function, + .syntax--entity.syntax--name.syntax--class { + color: @blue; + } + .syntax--variable.syntax--parameter.syntax--function { + color: @syntax-text-color; + } + .syntax--variable.syntax--other.syntax--readwrite { + color: @green; + } + + .syntax--storage.syntax--type.syntax--function { + color: @green; + } + + .syntax--entity.syntax--name { + color: @syntax-text-color; + } + + .syntax--meta.syntax--brace { + &.syntax--round, + &.syntax--square { + color: @syntax-text-color; + } + } + .syntax--meta.syntax--delimiter { + color: @syntax-text-color; + } + + .syntax--storage.syntax--type.syntax--class { + color: @green; + } + + .syntax--punctuation.syntax--terminator { + color: @syntax-text-color; + } + + .syntax--punctuation.syntax--section.syntax--embedded { + color: @red; + } + .syntax--embedded.syntax--source { + color: @syntax-text-color; + } + + .syntax--constant.syntax--numeric { + color: @magenta; + } + + .syntax--constant.syntax--language.syntax--boolean { + color: @yellow; + } +} diff --git a/packages/solarized-light-syntax/styles/syntax/css.less b/packages/solarized-light-syntax/styles/syntax/css.less new file mode 100644 index 000000000..8bfaf8c34 --- /dev/null +++ b/packages/solarized-light-syntax/styles/syntax/css.less @@ -0,0 +1,63 @@ +.syntax--source.syntax--css { + + .syntax--punctuation { + &.syntax--separator, + &.syntax--terminator { + color: @syntax-text-color; + } + &.syntax--property-list.syntax--begin, + &.syntax--property-list.syntax--end { + color: @red; + } + &.syntax--section.syntax--function { + color: @cyan; + } + } + + .syntax--entity.syntax--name { + color: @green; + } + .syntax--attribute-name.syntax--class, + .syntax--id { + color: @blue; + } + .syntax--pseudo-element, + .syntax--pseudo-class { + color: @orange; + } + + .syntax--property-value { + color: @cyan; + } + .syntax--constant.syntax--numeric { + color: @cyan; + .syntax--unit { + color: @cyan; + } + } + .syntax--rgb-value { + color: @cyan; + } + .syntax--support.syntax--constant { + color: @cyan; + &.syntax--media { + color: @red; + } + } + + .syntax--keyword.syntax--important { + color: @red; + } + +} + + +// Less/Sass should have their own files, +// but for just a single override, here should be fine too + +.syntax--source.syntax--less, +.syntax--source.syntax--scss { + .syntax--keyword.syntax--unit { + color: @cyan; + } +} diff --git a/packages/solarized-light-syntax/styles/syntax/go.less b/packages/solarized-light-syntax/styles/syntax/go.less new file mode 100644 index 000000000..b12558e83 --- /dev/null +++ b/packages/solarized-light-syntax/styles/syntax/go.less @@ -0,0 +1,10 @@ +.syntax--source.syntax--go { + + .syntax--operator { + color: @syntax-text-color; + &.syntax--assignment { + color: @green; + } + } + +} diff --git a/packages/solarized-light-syntax/styles/syntax/java.less b/packages/solarized-light-syntax/styles/syntax/java.less new file mode 100644 index 000000000..6fa5c64a7 --- /dev/null +++ b/packages/solarized-light-syntax/styles/syntax/java.less @@ -0,0 +1,47 @@ +.syntax--source.syntax--java { + .syntax--keyword.syntax--operator{ + color:@green; + } + .syntax--keyword.syntax--import{ + color: @orange; + } + .syntax--storage.syntax--modifier.syntax--import{ + color: @syntax-comment-color; + } + .syntax--meta.syntax--class{ + .syntax--storage.syntax--modifier{ + color: @yellow; + } + .syntax--meta.syntax--class.syntax--identifier{ + .syntax--entity.syntax--name.syntax--type.syntax--class{ + color: @blue; + } + } + } + .syntax--storage.syntax--type.syntax--primitive.syntax--array{ + color:@green; + } + .syntax--constant.syntax--numeric{ + color:@magenta; + } + .syntax--constant.syntax--other{ + color:@orange; + } + .syntax--storage.syntax--type{ + color:@green; + } + .syntax--meta.syntax--method-call{ + //@ibocon: method parameter's color + color:@red; + //@ibocon: method and variable use different hightlight + .syntax--meta.syntax--method{ + color:@violet; + } + .syntax--punctuation.syntax--definition.syntax--seperator.syntax--parameter{ + color:@green; + } + } + .syntax--punctuation.syntax--definition.syntax--method-parameters{ + color: @syntax-emphasized-color; + } +} diff --git a/packages/solarized-light-syntax/styles/syntax/javascript.less b/packages/solarized-light-syntax/styles/syntax/javascript.less new file mode 100644 index 000000000..ec1ebf068 --- /dev/null +++ b/packages/solarized-light-syntax/styles/syntax/javascript.less @@ -0,0 +1,128 @@ +.syntax--source.syntax--js { + .syntax--comma { + color: @syntax-text-color; + } + + .syntax--support.syntax--class { + color: @green; + } + + .syntax--entity { + &.syntax--name.syntax--type { + color: @yellow; + } + &.syntax--name { + color: @syntax-text-color; + + &.syntax--function { + color: @blue; + } + } + + &.syntax--name.syntax--tag { + color: @blue; + } + + &.syntax--other.syntax--attribute-name { + color: @yellow; + } + } + + + .syntax--meta.syntax--brace { + color: @syntax-text-color; + } + + .syntax--keyword { + color: @syntax-text-color; + } + .syntax--keyword.syntax--operator.syntax--new { + color: @green; + } + .syntax--keyword.syntax--control { + color: @orange; + } + .syntax--keyword.syntax--control.syntax--regexp { + color: @cyan; + } + + .syntax--variable { + color: @syntax-text-color; + } + .syntax--variable.syntax--dom { + color: @green; + } + .syntax--delimiter + .syntax--dom { + color: @syntax-text-color; + } + .syntax--name { + color: @syntax-text-color; + } + .syntax--variable.syntax--language { + color: @blue; + } + .syntax--variable.syntax--parameter { + color: @syntax-text-color; + } + + .syntax--regexp { + color: @cyan; + } + + .syntax--support.syntax--function { + color: @syntax-text-color; + } + .syntax--support.syntax--constant { + color: @syntax-text-color; + } + + .syntax--storage.syntax--modifier { + color: @yellow; + } + + .syntax--punctuation.syntax--terminator.syntax--statement { + color: @syntax-text-color; + } + + .syntax--meta.syntax--delimiter.syntax--method.syntax--period { + color: @syntax-text-color; + } + .syntax--meta.syntax--brace.syntax--square { + color: @blue; + } + .syntax--meta.syntax--brace.syntax--curly { + color: @blue; + } + + .syntax--string.syntax--quoted.syntax--template { + .syntax--embedded.syntax--source { + color: @syntax-text-color; + & > .syntax--embedded.syntax--punctuation { + color: @red; + } + } + } + + &.syntax--embedded .syntax--entity.syntax--name.syntax--tag { + color: @blue; + } + + .syntax--import { + .syntax--control { + color: @orange; + } + } +} + + +// JavaScript (Rails) language-ruby-on-rails + +.syntax--source.syntax--js.syntax--rails { + .syntax--instance { + color: @blue; + } + + .syntax--class { + color: @yellow; + } +} diff --git a/packages/solarized-light-syntax/styles/syntax/markdown.less b/packages/solarized-light-syntax/styles/syntax/markdown.less new file mode 100644 index 000000000..2ca0038d9 --- /dev/null +++ b/packages/solarized-light-syntax/styles/syntax/markdown.less @@ -0,0 +1,26 @@ +.syntax--md, +.syntax--gfm { + .syntax--link .syntax--entity { + color: @violet; + } + + .syntax--list { + &.syntax--ordered { + color: @green; + } + &.syntax--unordered { + color: @yellow; + } + } + + .syntax--raw { + font-style: italic; + } + + &.syntax--support { + color:@syntax-comment-color; + &.syntax--quote { + color: @violet; + } + } +} diff --git a/packages/solarized-light-syntax/styles/syntax/markup.less b/packages/solarized-light-syntax/styles/syntax/markup.less new file mode 100644 index 000000000..f94b56f5b --- /dev/null +++ b/packages/solarized-light-syntax/styles/syntax/markup.less @@ -0,0 +1,30 @@ +.syntax--markup { + + &.syntax--bold { + font-weight: bold; + } + &.syntax--italic { + font-style: italic; + } + + &.syntax--heading { + color: @blue; + } + + &.syntax--link { + color: @cyan; + } + + &.syntax--deleted { + color: @red; + } + + &.syntax--changed { + color: @yellow; + } + + &.syntax--inserted { + color: @cyan; + } + +} diff --git a/packages/solarized-light-syntax/styles/syntax/php.less b/packages/solarized-light-syntax/styles/syntax/php.less new file mode 100644 index 000000000..8eb510d41 --- /dev/null +++ b/packages/solarized-light-syntax/styles/syntax/php.less @@ -0,0 +1,67 @@ +.syntax--source.syntax--php { + .syntax--storage { + &.syntax--type { + &.syntax--class { + color: @yellow; + } + &.syntax--function { + color: @orange; + } + } + &.syntax--modifier { + color: @yellow; + } + } + .syntax--entity { + &.syntax--name { + &.syntax--type.syntax--class { + color: @syntax-text-color; + } + &.syntax--function { + color: @syntax-text-color; + } + } + &.syntax--other { + color: @syntax-text-color; + } + } + .syntax--variable { + color: @blue; + } + .syntax--punctuation.syntax--definition { + color: @syntax-text-color; + &.syntax--comment { + color: @syntax-comment-color; + } + &.syntax--array { + color: @red; + } + &.syntax--string { + color: @syntax-text-color; + } + &.syntax--variable { + color: @green; + } + } + .syntax--support.syntax--function { + &.syntax--construct { + color: @yellow; + } + &.syntax--array { + color: @green; + } + } + .syntax--keyword { + &.syntax--operator { + &.syntax--class { + color: @yellow; + } + &.syntax--assignment { + color: @green; + } + } + &.syntax--other { + color: @red; + } + } +} diff --git a/packages/solarized-light-syntax/styles/syntax/python.less b/packages/solarized-light-syntax/styles/syntax/python.less new file mode 100644 index 000000000..ffe29ba2b --- /dev/null +++ b/packages/solarized-light-syntax/styles/syntax/python.less @@ -0,0 +1,100 @@ +.syntax--source.syntax--python { + .syntax--entity { + color: @syntax-text-color; + + &.syntax--name { + color: @blue; + } + &.syntax--other { + color: @blue; + } + } + + .syntax--function { + color: @blue; + + &.syntax--magic { + color: @blue; + } + } + + .syntax--punctuation.syntax--string { + color: @cyan; + } + .syntax--keyword { + &.syntax--operator { + color: @syntax-text-color; + &.syntax--quantifier { + color: @cyan; + } + &.syntax--logical { + color: @green; + } + } + &.syntax--control.syntax--import { + color: @orange; + } + &.syntax--other { + color: @green; + } + } + .syntax--constant { + &.syntax--language { + color: @blue; + } + &.syntax--character { + color: @cyan; + } + &.syntax--other { + color: @red; + } + } + + .syntax--entity.syntax--name.syntax--type.syntax--class { + color: @blue; + } + .syntax--variable { + color: @syntax-text-color; + } + .syntax--support { + &.syntax--function.syntax--builtin { + color: @blue; + } + &.syntax--type { + &.syntax--exception.syntax--python { + color: @yellow; + } + &.syntax--python { + color: @blue; + } + } + } + .syntax--storage.syntax--type.syntax--string { + color: @cyan; + } + + .syntax--storage.syntax--type.syntax--class { + color: @green; + &.syntax--todo { + color: @magenta; + } + } + + .syntax--storage.syntax--type.syntax--function { + color: @green; + } + + .syntax--punctuation.syntax--definition.syntax--parameters { + color: @syntax-text-color; + } + + .syntax--punctuation.syntax--section.syntax--function.syntax--begin { + color: @syntax-text-color; + } + + .syntax--punctuation.syntax--separator.syntax--parameters { + color: @syntax-text-color; + } + + +} diff --git a/packages/solarized-light-syntax/styles/syntax/ruby.less b/packages/solarized-light-syntax/styles/syntax/ruby.less new file mode 100644 index 000000000..3e3d8b58c --- /dev/null +++ b/packages/solarized-light-syntax/styles/syntax/ruby.less @@ -0,0 +1,129 @@ +.syntax--source.syntax--ruby { + + .syntax--meta.syntax--embedded { + .syntax--punctuation.syntax--section { + color: @red; + } + } + .syntax--punctuation.syntax--definition { + color: @syntax-text-color; + &.syntax--string { + color: @red; + } + } + .syntax--punctuation.syntax--definition.syntax--comment { + color: @syntax-comment-color; + } + .syntax--entity.syntax--inherited-class { + color: @yellow; + } + .syntax--variable { + &.syntax--parameter { + color: @syntax-text-color; + } + } + .syntax--variable.syntax--constant { + color: @yellow; + } + .syntax--constant.syntax--boolean { + color: @cyan; + } + .syntax--instance { + .syntax--punctuation.syntax--definition { + color: @blue; + } + } + .syntax--class { + color: @yellow; + &.syntax--control { + color: @syntax-text-color; + } + } + .syntax--module { + color: @yellow; + } + .syntax--require { + .syntax--keyword.syntax--other.syntax--special-method { + color: @orange; + } + } + .syntax--keyword.syntax--other.syntax--special-method { + color: @orange; + } + .syntax--keyword.syntax--other { + color: @green; + } + .syntax--keyword.syntax--control { + color: @green; + } + .syntax--keyword.syntax--operator { + color: @syntax-text-color; + } + .syntax--special-method { + color: @blue; + } + .syntax--symbol { + color: @cyan; + .syntax--punctuation.syntax--definition { + color: @cyan; + } + } + .syntax--hashkey { + color: @red; + .syntax--punctuation.syntax--definition { + color: @red; + } + } + .syntax--string.syntax--regexp { + color: @red; + } + .syntax--todo { + color: @magenta; + } + .syntax--variable.syntax--ruby.syntax--global { + color: @blue; + .syntax--punctuation { + color: @blue; + } + } + .syntax--variable.syntax--block { + color: @blue; + } + .syntax--variable.syntax--self { + color: @cyan; + } + .syntax--punctuation.syntax--separator { + color: @syntax-text-color; + } + .syntax--numeric { + color: @cyan; + } + .syntax--punctuation.syntax--section.syntax--regexp { + color: @red; + } + .syntax--string.syntax--interpolated { + color: @cyan; + } + .syntax--string.syntax--interpolated { + .syntax--embedded.syntax--line.syntax--ruby { + .syntax--punctuation { + .syntax--source.syntax--ruby { + color: @red; + } + } + .syntax--source.syntax--ruby { + .syntax--punctuation.syntax--array, + .syntax--punctuation.syntax--function { + color: @syntax-text-color; + } + color: @syntax-text-color; + } + } + } + .syntax--support.syntax--function { + color: @syntax-text-color; + } + .syntax--support.syntax--function.syntax--kernel { + color: @green; + } +} diff --git a/packages/solarized-light-syntax/styles/syntax/scala.less b/packages/solarized-light-syntax/styles/syntax/scala.less new file mode 100644 index 000000000..376514087 --- /dev/null +++ b/packages/solarized-light-syntax/styles/syntax/scala.less @@ -0,0 +1,79 @@ +.syntax--source.syntax--scala { + .syntax--variable { + color: @syntax-emphasized-color; + } + + .syntax--declaration { + color: @syntax-emphasized-color; + font-weight: bold; + } + .syntax--comparison { + color: @syntax-emphasized-color; + } + .syntax--class, .syntax--type { + color: @yellow; + } + .syntax--val { + font-weight: normal; + } + .syntax--variable { + font-weight: bold; + } + .syntax--variable.syntax--parameter { + color: @violet; + font-weight: normal; + } + .syntax--control.syntax--flow { + color: @syntax-emphasized-color; + font-weight: bold; + } + .syntax--constant.syntax--language { + color: @syntax-emphasized-color; + font-weight: bold; + } + .syntax--function.syntax--declaration { + color: @violet; + } + .syntax--modifier.syntax--other { + font-weight: bold; + } + .syntax--package { + color: @syntax-emphasized-color; + } + .syntax--variable.syntax--import { + font-weight: normal; + } + + .syntax--type { + .syntax--bounds, .syntax--class { + color: @violet; + } + } + + .syntax--documentation { + :not(.syntax--embedded) { + // out of scope ? + // https://github.syntax--com/atom/link + &.syntax--link.syntax--entity { + color: @blue; + text-decoration: underline; + } + .syntax--class, .syntax--parameter { + color: @syntax-emphasized-color; + } + .syntax--description { + color: @syntax-comment-color; + } + } + } + + .syntax--embedded { + color: darken(@syntax-emphasized-color, 15%); + + // so we dont confused it with normal expressions + font-style: italic; + .syntax--margin, .syntax--delimiters { + font-style: normal; + } + } +} diff --git a/packages/solarized-light-syntax/styles/syntax/typescript.less b/packages/solarized-light-syntax/styles/syntax/typescript.less new file mode 100644 index 000000000..1a3288073 --- /dev/null +++ b/packages/solarized-light-syntax/styles/syntax/typescript.less @@ -0,0 +1,22 @@ +.syntax--source.syntax--ts, +.syntax--source.syntax--tsx { + .syntax--import { + .syntax--control { + color: @orange; + } + } + + .syntax--entity { + &.syntax--name.syntax--type { + color: @yellow; + } + + &.syntax--inherited-class { + color: @yellow; + } + } + + .syntax--support.syntax--type { + color: @yellow; + } +} diff --git a/resources/mac/atom-Info.plist b/resources/mac/atom-Info.plist index c22653622..3401bdef5 100644 --- a/resources/mac/atom-Info.plist +++ b/resources/mac/atom-Info.plist @@ -34,6 +34,8 @@ AtomApplication NSSupportsAutomaticGraphicsSwitching + NSRequiresAquaSystemAppearance + NO SUScheduledCheckInterval 3600 CFBundleURLTypes diff --git a/script/lib/clean-dependencies.js b/script/lib/clean-dependencies.js index 72007cf04..5b64e5e89 100644 --- a/script/lib/clean-dependencies.js +++ b/script/lib/clean-dependencies.js @@ -3,10 +3,12 @@ const path = require('path') const CONFIG = require('../config') module.exports = function () { - // We can't require fs-extra if `script/bootstrap` has never been run, because - // it's a third party module. This is okay because cleaning dependencies only - // makes sense if dependencies have been installed at least once. + // We can't require fs-extra or glob if `script/bootstrap` has never been run, + // because they are third party modules. This is okay because cleaning + // dependencies only makes sense if dependencies have been installed at least + // once. const fs = require('fs-extra') + const glob = require('glob') const apmDependenciesPath = path.join(CONFIG.apmRootPath, 'node_modules') console.log(`Cleaning ${apmDependenciesPath}`) @@ -19,4 +21,9 @@ module.exports = function () { const scriptDependenciesPath = path.join(CONFIG.scriptRootPath, 'node_modules') console.log(`Cleaning ${scriptDependenciesPath}`) fs.removeSync(scriptDependenciesPath) + + const bundledPackageDependenciesPaths = path.join(CONFIG.repositoryRootPath, 'packages', '**', 'node_modules') + for (const bundledPackageDependencyPath of glob.sync(bundledPackageDependenciesPaths)) { + fs.removeSync(bundledPackageDependencyPath) + } } diff --git a/script/lib/copy-assets.js b/script/lib/copy-assets.js index 27b5f086c..b04916cd9 100644 --- a/script/lib/copy-assets.js +++ b/script/lib/copy-assets.js @@ -15,7 +15,6 @@ module.exports = function () { path.join(CONFIG.repositoryRootPath, 'benchmarks', 'benchmark-runner.js'), path.join(CONFIG.repositoryRootPath, 'dot-atom'), path.join(CONFIG.repositoryRootPath, 'exports'), - path.join(CONFIG.repositoryRootPath, 'node_modules'), path.join(CONFIG.repositoryRootPath, 'package.json'), path.join(CONFIG.repositoryRootPath, 'static'), path.join(CONFIG.repositoryRootPath, 'src'), @@ -23,9 +22,22 @@ module.exports = function () { ] srcPaths = srcPaths.concat(glob.sync(path.join(CONFIG.repositoryRootPath, 'spec', '*.*'), {ignore: path.join('**', '*-spec.*')})) for (let srcPath of srcPaths) { - fs.copySync(srcPath, computeDestinationPath(srcPath), {filter: includePathInPackagedApp, dereference: true}) + fs.copySync(srcPath, computeDestinationPath(srcPath), {filter: includePathInPackagedApp}) } + // Run a copy pass to dereference symlinked directories under node_modules. + // We do this to ensure that symlinked repo-local bundled packages get + // copied to the output folder correctly. We dereference only the top-level + // symlinks and not nested symlinks to avoid issues where symlinked binaries + // are duplicated in Atom's installation packages (see atom/atom#18490). + const nodeModulesPath = path.join(CONFIG.repositoryRootPath, 'node_modules') + glob.sync(path.join(nodeModulesPath, '*')) + .map(p => fs.lstatSync(p).isSymbolicLink() ? path.resolve(nodeModulesPath, fs.readlinkSync(p)) : p) + .forEach(modulePath => { + const destPath = path.join(CONFIG.intermediateAppPath, 'node_modules', path.basename(modulePath)) + fs.copySync(modulePath, destPath, { filter: includePathInPackagedApp }) + }) + fs.copySync( path.join(CONFIG.repositoryRootPath, 'resources', 'app-icons', CONFIG.channel, 'png', '1024.png'), path.join(CONFIG.intermediateAppPath, 'resources', 'atom.png') diff --git a/script/lib/generate-startup-snapshot.js b/script/lib/generate-startup-snapshot.js index 4e4945e19..f6921d77a 100644 --- a/script/lib/generate-startup-snapshot.js +++ b/script/lib/generate-startup-snapshot.js @@ -37,11 +37,11 @@ module.exports = function (packagedAppPath) { requiredModuleRelativePath.endsWith(path.join('node_modules', 'minimatch', 'minimatch.js')) || requiredModuleRelativePath.endsWith(path.join('node_modules', 'request', 'index.js')) || requiredModuleRelativePath.endsWith(path.join('node_modules', 'request', 'request.js')) || + requiredModuleRelativePath.endsWith(path.join('node_modules', 'temp', 'lib', 'temp.js')) || requiredModuleRelativePath === path.join('..', 'exports', 'atom.js') || requiredModuleRelativePath === path.join('..', 'src', 'electron-shims.js') || requiredModuleRelativePath === path.join('..', 'node_modules', 'atom-keymap', 'lib', 'command-event.js') || requiredModuleRelativePath === path.join('..', 'node_modules', 'babel-core', 'index.js') || - requiredModuleRelativePath === path.join('..', 'node_modules', 'cached-run-in-this-context', 'lib', 'main.js') || requiredModuleRelativePath === path.join('..', 'node_modules', 'debug', 'node.js') || requiredModuleRelativePath === path.join('..', 'node_modules', 'git-utils', 'src', 'git.js') || requiredModuleRelativePath === path.join('..', 'node_modules', 'glob', 'glob.js') || @@ -60,7 +60,6 @@ module.exports = function (packagedAppPath) { requiredModuleRelativePath === path.join('..', 'node_modules', 'spelling-manager', 'node_modules', 'natural', 'lib', 'natural', 'index.js') || requiredModuleRelativePath === path.join('..', 'node_modules', 'tar', 'tar.js') || requiredModuleRelativePath === path.join('..', 'node_modules', 'ls-archive', 'node_modules', 'tar', 'tar.js') || - requiredModuleRelativePath === path.join('..', 'node_modules', 'temp', 'lib', 'temp.js') || requiredModuleRelativePath === path.join('..', 'node_modules', 'tmp', 'lib', 'tmp.js') || requiredModuleRelativePath === path.join('..', 'node_modules', 'tree-sitter', 'index.js') || requiredModuleRelativePath === path.join('..', 'node_modules', 'yauzl', 'index.js') || @@ -97,22 +96,36 @@ module.exports = function (packagedAppPath) { {env: Object.assign({}, process.env, {ELECTRON_RUN_AS_NODE: 1})} ) - const generatedStartupBlobPath = path.join(CONFIG.buildOutputPath, 'snapshot_blob.bin') - console.log(`Generating startup blob at "${generatedStartupBlobPath}"`) - childProcess.execFileSync( - path.join(CONFIG.repositoryRootPath, 'script', 'node_modules', 'electron-mksnapshot', 'bin', 'mksnapshot'), - ['--no-use_ic', snapshotScriptPath, '--startup_blob', generatedStartupBlobPath] + console.log('Generating startup blob with mksnapshot') + childProcess.spawnSync( + process.execPath, [ + path.join(CONFIG.repositoryRootPath, 'script', 'node_modules', 'electron-mksnapshot', 'mksnapshot.js'), + snapshotScriptPath, + '--output_dir', + CONFIG.buildOutputPath + ] ) let startupBlobDestinationPath if (process.platform === 'darwin') { - startupBlobDestinationPath = `${packagedAppPath}/Contents/Frameworks/Electron Framework.framework/Resources/snapshot_blob.bin` + startupBlobDestinationPath = `${packagedAppPath}/Contents/Frameworks/Electron Framework.framework/Resources` } else { - startupBlobDestinationPath = path.join(packagedAppPath, 'snapshot_blob.bin') + startupBlobDestinationPath = packagedAppPath } - console.log(`Moving generated startup blob into "${startupBlobDestinationPath}"`) - fs.unlinkSync(startupBlobDestinationPath) - fs.renameSync(generatedStartupBlobPath, startupBlobDestinationPath) + const snapshotBinaries = ['v8_context_snapshot.bin', 'snapshot_blob.bin'] + for (let snapshotBinary of snapshotBinaries) { + const destinationPath = path.join(startupBlobDestinationPath, snapshotBinary) + console.log(`Moving generated startup blob into "${destinationPath}"`) + try { + fs.unlinkSync(destinationPath) + } catch (err) { + // Doesn't matter if the file doesn't exist already + if (!err.code || err.code !== 'ENOENT') { + throw err + } + } + fs.renameSync(path.join(CONFIG.buildOutputPath, snapshotBinary), destinationPath) + } }) } diff --git a/script/lib/package-application.js b/script/lib/package-application.js index 1b3c19b28..7125deea5 100644 --- a/script/lib/package-application.js +++ b/script/lib/package-application.js @@ -29,6 +29,7 @@ module.exports = function () { 'name': appName, 'out': CONFIG.buildOutputPath, 'overwrite': true, + 'deref-symlinks': false, 'platform': process.platform, 'version': CONFIG.appMetadata.electronVersion, 'version-string': { diff --git a/script/package-lock.json b/script/package-lock.json index 4a9b6a5db..d5ca5840a 100644 --- a/script/package-lock.json +++ b/script/package-lock.json @@ -649,9 +649,9 @@ } }, "bindings": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.0.tgz", - "integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw==" + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.1.tgz", + "integrity": "sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew==" }, "bl": { "version": "1.2.2", @@ -921,9 +921,9 @@ "integrity": "sha512-7I/xceXfKyUJmSAn/jw8ve/9DyOP7XxufNYLI9Px7CmsKgEUaZLUTax6nZxGQtaoiZCjpu6cHPj20xC/vqRReQ==" }, "chownr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", - "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==" }, "chromium-pickle-js": { "version": "0.1.0", @@ -1691,54 +1691,76 @@ "integrity": "sha1-YMf4e9YrzGqJT6jM1q+3gjok90I=" }, "electron-chromedriver": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/electron-chromedriver/-/electron-chromedriver-2.0.0.tgz", - "integrity": "sha512-kERk/Wzhc9RzW9jUKXA5kJc4m8BlL6c9p5QH+CrIlst0saeqZL1Up7vzD4ZOnuBDpAVBBYJ4jhkAKIssf8ZlXg==", + "version": "3.0.0-beta.1", + "resolved": "https://registry.npmjs.org/electron-chromedriver/-/electron-chromedriver-3.0.0-beta.1.tgz", + "integrity": "sha512-S8KuOWqTISSfeVccrh1XjqR5tARdkAbF93azz8TvuNJTKoIw7V54mLKoyhi2Hj5UvKuPLcrHmfa4B9Uh45A5lA==", "requires": { "electron-download": "^4.1.0", "extract-zip": "^1.6.5" } }, "electron-download": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/electron-download/-/electron-download-4.1.0.tgz", - "integrity": "sha1-v5MsdG8vh//MCdHdRy8v9rkYeEU=", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/electron-download/-/electron-download-4.1.1.tgz", + "integrity": "sha512-FjEWG9Jb/ppK/2zToP+U5dds114fM1ZOJqMAR4aXXL5CvyPE9fiqBK/9YcwC9poIFQTEJk/EM/zyRwziziRZrg==", "requires": { - "debug": "^2.2.0", + "debug": "^3.0.0", "env-paths": "^1.0.0", - "fs-extra": "^2.0.0", + "fs-extra": "^4.0.1", "minimist": "^1.2.0", - "nugget": "^2.0.0", + "nugget": "^2.0.1", "path-exists": "^3.0.0", - "rc": "^1.1.2", - "semver": "^5.3.0", - "sumchecker": "^2.0.1" + "rc": "^1.2.1", + "semver": "^5.4.1", + "sumchecker": "^2.0.2" }, "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, "fs-extra": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz", - "integrity": "sha1-BGxwFjzvmq1GsOSn+kZ/si1x3jU=", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", "requires": { "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0" + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" } }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "semver": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==" } } }, "electron-link": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/electron-link/-/electron-link-0.2.2.tgz", - "integrity": "sha1-uWvx/MrowwyAuiaTBq+UVOYtP2U=", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/electron-link/-/electron-link-0.3.2.tgz", + "integrity": "sha512-V7QmtujzWgvrW5BI2CKmIRF+q+pkrFO5Lecd8TpibbBz+FfW5WQ4kCN0sZjNaUOMtGGroCib721OqIDEynjwgA==", "requires": { "ast-util": "^0.6.0", "encoding-down": "~5.0.0", - "indent-string": "^2.1.0", + "indent-string": "^3.2.0", "leveldown": "~4.0.0", "levelup": "~3.0.0", "recast": "^0.12.6", @@ -1752,15 +1774,20 @@ "integrity": "sha512-UY7+9DPzlJ9VM8eY0b2TUZcZvF+1pO0hzMtAyjBYKhOmnvRlqYNYnWdtsMj0V16CGaMlpL0G1jnLbLo4AyotuQ==" }, "core-js": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.1.tgz", + "integrity": "sha512-L72mmmEayPJBejKIWe2pYtGis5r0tQ5NaJekdhyXgeMQTpJoBsH0NL4ElY2LfSoV15xeQWKQ+XTTOZdyero5Xg==" }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=" + }, "recast": { "version": "0.12.9", "resolved": "https://registry.npmjs.org/recast/-/recast-0.12.9.tgz", @@ -1783,12 +1810,13 @@ } }, "electron-mksnapshot": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/electron-mksnapshot/-/electron-mksnapshot-2.0.0.tgz", - "integrity": "sha512-OoZwZJNKgHP+DwhCGVTJEuDSeb478hOzAbHeg7dKGCHDbKKmUWmjGc+pEjxGutpqQ3Mn8hCdLzdx2c/lAJcTLA==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/electron-mksnapshot/-/electron-mksnapshot-3.0.10.tgz", + "integrity": "sha512-Toy6sAC3t9tgvq1kUYsx+4TRNPDj7Bzoo+1gx5FD8Q0YCS+tq+ter62Ot6dBXCKG9SwoaGBz84b++MgO0VobYw==", "requires": { "electron-download": "^4.1.0", - "extract-zip": "^1.6.5" + "extract-zip": "^1.6.5", + "temp": "^0.8.3" } }, "electron-osx-sign": { @@ -4718,17 +4746,17 @@ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" }, "node-abi": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.4.3.tgz", - "integrity": "sha512-b656V5C0628gOOA2kwcpNA/bxdlqYF9FvxJ+qqVX0ctdXNVZpS8J6xEUYir3WAKc7U0BH/NRlSpNbGsy+azjeg==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.5.1.tgz", + "integrity": "sha512-oDbFc7vCFx0RWWCweTer3hFm1u+e60N5FtGnmRV6QqvgATGFH/XRR6vqWIeBVosCYCqt6YdIr2L0exLZuEdVcQ==", "requires": { "semver": "^5.4.1" }, "dependencies": { "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" } } }, @@ -9874,16 +9902,16 @@ } }, "tar-stream": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.1.tgz", - "integrity": "sha512-IFLM5wp3QrJODQFPm6/to3LJZrONdBY/otxcvDIQzu217zKye6yVR3hhi9lAjrC2Z+m/j5oDxMPb1qcd8cIvpA==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", "requires": { "bl": "^1.0.0", - "buffer-alloc": "^1.1.0", + "buffer-alloc": "^1.2.0", "end-of-stream": "^1.0.0", "fs-constants": "^1.0.0", "readable-stream": "^2.3.0", - "to-buffer": "^1.1.0", + "to-buffer": "^1.1.1", "xtend": "^4.0.0" }, "dependencies": { @@ -10304,6 +10332,11 @@ "unist-util-is": "^2.1.1" } }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", diff --git a/script/package.json b/script/package.json index d3f913f24..6f287196c 100644 --- a/script/package.json +++ b/script/package.json @@ -9,9 +9,9 @@ "coffeelint": "1.15.7", "colors": "1.1.2", "donna": "1.0.16", - "electron-chromedriver": "~2.0", - "electron-link": "0.2.2", - "electron-mksnapshot": "~2.0", + "electron-chromedriver": "~3.0.0-beta.1", + "electron-link": "0.3.2", + "electron-mksnapshot": "~3.0.10", "electron-packager": "7.3.0", "electron-winstaller": "2.6.4", "fs-admin": "^0.1.5", diff --git a/script/test b/script/test index 64688daa1..5270a3912 100755 --- a/script/test +++ b/script/test @@ -3,7 +3,36 @@ 'use strict' require('colors') -const argv = require('yargs').argv +const argv = require('yargs') + .option('core-main', { + describe: 'Run core main process tests', + boolean: true, + default: false + }) + .option('skip-main', { + describe: 'Skip main process tests if they would otherwise run on your platform', + boolean: true, + default: false, + conflicts: 'core-main' + }) + .option('core-renderer', { + describe: 'Run core renderer process tests', + boolean: true, + default: false + }) + .option('core-benchmark', { + describe: 'Run core benchmarks', + boolean: true, + default: false + }) + .option('package', { + describe: 'Run bundled package specs', + boolean: true, + default: false + }) + .help() + .argv + const assert = require('assert') const async = require('async') const childProcess = require('child_process') @@ -148,10 +177,27 @@ function runBenchmarkTests (callback) { cp.on('close', exitCode => { callback(null, exitCode) }) } -let testSuitesToRun = testSuitesForPlatform(process.platform) +let testSuitesToRun = requestedTestSuites() || testSuitesForPlatform(process.platform) + +function requestedTestSuites () { + const suites = [] + if (argv.coreMain) { + suites.push(runCoreMainProcessTests) + } + if (argv.coreRenderer) { + suites.push(runCoreRenderProcessTests) + } + if (argv.coreBenchmark) { + suites.push(runBenchmarkTests) + } + if (argv.package) { + suites.push(...packageTestSuites) + } + return suites.length > 0 ? suites : null +} function testSuitesForPlatform (platform) { - let suites = []; + let suites = [] switch (platform) { case 'darwin': suites = [runCoreMainProcessTests, runCoreRenderProcessTests, runBenchmarkTests].concat(packageTestSuites) @@ -167,10 +213,10 @@ function testSuitesForPlatform (platform) { } if (argv.skipMainProcessTests) { - suites = suites.filter(suite => suite !== runCoreMainProcessTests); + suites = suites.filter(suite => suite !== runCoreMainProcessTests) } - return suites; + return suites } async.series(testSuitesToRun, function (err, exitCodes) { diff --git a/spec/atom-environment-spec.js b/spec/atom-environment-spec.js index aea5313e8..5e9617374 100644 --- a/spec/atom-environment-spec.js +++ b/spec/atom-environment-spec.js @@ -639,7 +639,6 @@ describe('AtomEnvironment', () => { describe('::openLocations(locations) (called via IPC from browser process)', () => { beforeEach(() => { - spyOn(atom.workspace, 'open') atom.project.setPaths([]) }) @@ -649,48 +648,72 @@ describe('AtomEnvironment', () => { }) describe('when the opened path exists', () => { - it("adds it to the project's paths", async () => { + it('opens a file', async () => { const pathToOpen = __filename await atom.openLocations([{pathToOpen}]) - expect(atom.project.getPaths()[0]).toBe(__dirname) + expect(atom.project.getPaths()).toEqual([]) }) - describe('then a second path is opened with forceAddToWindow', () => { - it("adds the second path to the project's paths", async () => { - const firstPathToOpen = __dirname - const secondPathToOpen = path.resolve(__dirname, './fixtures') - await atom.openLocations([{pathToOpen: firstPathToOpen}]) - await atom.openLocations([{pathToOpen: secondPathToOpen, forceAddToWindow: true}]) - expect(atom.project.getPaths()).toEqual([firstPathToOpen, secondPathToOpen]) - }) - }) - }) - - describe('when the opened path does not exist but its parent directory does', () => { - it('adds the parent directory to the project paths', async () => { - const pathToOpen = path.join(__dirname, 'this-path-does-not-exist.txt') - await atom.openLocations([{pathToOpen}]) - expect(atom.project.getPaths()[0]).toBe(__dirname) - }) - }) - - describe('when the opened path is a file', () => { - it('opens it in the workspace', async () => { - const pathToOpen = __filename - await atom.openLocations([{pathToOpen}]) - expect(atom.workspace.open.mostRecentCall.args[0]).toBe(__filename) - }) - }) - - describe('when the opened path is a directory', () => { - it('does not open it in the workspace', async () => { + it('opens a directory as a project folder', async () => { const pathToOpen = __dirname await atom.openLocations([{pathToOpen}]) - expect(atom.workspace.open.callCount).toBe(0) + expect(atom.workspace.getTextEditors().map(e => e.getPath())).toEqual([]) + expect(atom.project.getPaths()).toEqual([pathToOpen]) }) }) - describe('when the opened path is a uri', () => { + describe('when the opened path does not exist', () => { + it('opens it as a new file', async () => { + const pathToOpen = path.join(__dirname, 'this-path-does-not-exist.txt') + await atom.openLocations([{pathToOpen}]) + expect(atom.workspace.getTextEditors().map(e => e.getPath())).toEqual([pathToOpen]) + expect(atom.project.getPaths()).toEqual([]) + }) + + it('may be required to be an existing directory', async () => { + spyOn(atom.notifications, 'addWarning') + + const nonExistent = path.join(__dirname, 'no') + const existingFile = __filename + const existingDir = path.join(__dirname, 'fixtures') + + await atom.openLocations([ + {pathToOpen: nonExistent, mustBeDirectory: true}, + {pathToOpen: existingFile, mustBeDirectory: true}, + {pathToOpen: existingDir, mustBeDirectory: true} + ]) + + expect(atom.workspace.getTextEditors()).toEqual([]) + expect(atom.project.getPaths()).toEqual([existingDir]) + + expect(atom.notifications.addWarning).toHaveBeenCalledWith( + 'Unable to open project folders', + {description: `The directories \`${nonExistent}\` and \`${existingFile}\` do not exist.`} + ) + }) + }) + + describe('when the opened path is handled by a registered directory provider', () => { + let serviceDisposable + + beforeEach(() => { + serviceDisposable = atom.packages.serviceHub.provide('atom.directory-provider', '0.1.0', { + directoryForURISync (uri) { + if (uri.startsWith('remote://')) { + return { getPath() { return uri } } + } else { + return null + } + } + }) + + waitsFor(() => atom.project.directoryProviders.length > 0) + }) + + afterEach(() => { + serviceDisposable.dispose() + }) + it("adds it to the project's paths as is", async () => { const pathToOpen = 'remote://server:7644/some/dir/path' spyOn(atom.project, 'addPath') @@ -719,6 +742,27 @@ describe('AtomEnvironment', () => { expect(atom.project.getPaths()).toEqual([]) }) + it('includes missing mandatory project folders in computation of initial state key', async () => { + const existingDir = path.join(__dirname, 'fixtures') + const missingDir = path.join(__dirname, 'no') + + atom.loadState.andCallFake(function (key) { + if (key === `${existingDir}:${missingDir}`) { + return Promise.resolve(state) + } else { + return Promise.resolve(null) + } + }) + + await atom.openLocations([ + {pathToOpen: existingDir}, + {pathToOpen: missingDir, mustBeDirectory: true} + ]) + + expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(state, [existingDir], []) + expect(atom.project.getPaths(), [existingDir]) + }) + it('opens the specified files', async () => { await atom.openLocations([{pathToOpen: __dirname}, {pathToOpen: __filename}]) expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(state, [__dirname], [__filename]) @@ -741,7 +785,7 @@ describe('AtomEnvironment', () => { const fileToOpen = path.join(pathToOpen, 'michelle-is-awesome.txt') await atom.openLocations([{pathToOpen}, {pathToOpen: fileToOpen}]) expect(atom.attemptRestoreProjectStateForPaths).not.toHaveBeenCalledWith(state, [pathToOpen], [fileToOpen]) - expect(atom.project.getPaths()).toEqual([__dirname]) + expect(atom.project.getPaths()).toEqual([__dirname, pathToOpen]) }) }) }) diff --git a/spec/decoration-manager-spec.coffee b/spec/decoration-manager-spec.coffee index 76bc37b75..02073a3a2 100644 --- a/spec/decoration-manager-spec.coffee +++ b/spec/decoration-manager-spec.coffee @@ -1,6 +1,7 @@ DecorationManager = require '../src/decoration-manager' TextEditor = require '../src/text-editor' +# Tests crash the renderer process on Electron 3.0, disabling for now. describe "DecorationManager", -> [decorationManager, buffer, editor, markerLayer1, markerLayer2] = [] @@ -64,7 +65,9 @@ describe "DecorationManager", -> {oldProperties, newProperties} = updatedSpy.mostRecentCall.args[0] expect(oldProperties).toEqual decorationProperties - expect(newProperties).toEqual {type: 'line-number', gutterName: 'line-number', class: 'two'} + expect(newProperties.type).toBe 'line-number' + expect(newProperties.gutterName).toBe 'line-number' + expect(newProperties.class).toBe 'two' describe "::getDecorations(properties)", -> it "returns decorations matching the given optional properties", -> diff --git a/spec/fixtures/babel/invalid.js b/spec/fixtures/babel/invalid.js index 585a4365b..513264538 100644 --- a/spec/fixtures/babel/invalid.js +++ b/spec/fixtures/babel/invalid.js @@ -1,3 +1,3 @@ 'use 6to6'; -module.exports = async function* hello() {} +export default 42; diff --git a/spec/integration/smoke-spec.coffee b/spec/integration/smoke-spec.coffee index e147cf5c0..dd6c9776f 100644 --- a/spec/integration/smoke-spec.coffee +++ b/spec/integration/smoke-spec.coffee @@ -23,10 +23,14 @@ describe "Smoke Test", -> it "can open a file in Atom and perform basic operations on it", -> tempDirPath = temp.mkdirSync("empty-dir") - runAtom [path.join(tempDirPath, "new-file")], {ATOM_HOME: atomHome}, (client) -> + filePath = path.join(tempDirPath, "new-file") + + fs.writeFileSync filePath, "", {encoding: "utf8"} + + runAtom [filePath], {ATOM_HOME: atomHome}, (client) -> client .treeViewRootDirectories() - .then ({value}) -> expect(value).toEqual([tempDirPath]) + .then ({value}) -> expect(value).toEqual([]) .waitForExist("atom-text-editor", 5000) .then (exists) -> expect(exists).toBe true .waitForPaneItemCount(1, 1000) diff --git a/spec/main-process/atom-application.test.js b/spec/main-process/atom-application.test.js index c49e36b5d..c271608c4 100644 --- a/spec/main-process/atom-application.test.js +++ b/spec/main-process/atom-application.test.js @@ -1,3 +1,5 @@ +/* globals assert */ + const temp = require('temp').track() const season = require('season') const dedent = require('dedent') @@ -44,55 +46,226 @@ describe('AtomApplication', function () { }) describe('launch', () => { - it('can open to a specific line number of a file', async () => { - const filePath = path.join(makeTempDir(), 'new-file') - fs.writeFileSync(filePath, '1\n2\n3\n4\n') - const atomApplication = buildAtomApplication() + describe('with no paths', () => { + it('reopens any previously opened windows', async () => { + if (process.platform === 'win32') return // Test is too flakey on Windows - const [window] = await atomApplication.launch(parseCommandLine([filePath + ':3'])) - await focusWindow(window) + const tempDirPath1 = makeTempDir() + const tempDirPath2 = makeTempDir() - const cursorRow = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => { - atom.workspace.observeTextEditors(textEditor => { - sendBackToMainProcess(textEditor.getCursorBufferPosition().row) - }) + const atomApplication1 = buildAtomApplication() + const [app1Window1] = await atomApplication1.launch(parseCommandLine([tempDirPath1])) + await emitterEventPromise(app1Window1, 'window:locations-opened') + + const [app1Window2] = await atomApplication1.launch(parseCommandLine([tempDirPath2])) + await emitterEventPromise(app1Window2, 'window:locations-opened') + + await Promise.all([ + app1Window1.prepareToUnload(), + app1Window2.prepareToUnload() + ]) + + const atomApplication2 = buildAtomApplication() + const [app2Window1, app2Window2] = await atomApplication2.launch(parseCommandLine([])) + await Promise.all([ + emitterEventPromise(app2Window1, 'window:locations-opened'), + emitterEventPromise(app2Window2, 'window:locations-opened') + ]) + + assert.deepEqual(await getTreeViewRootDirectories(app2Window1), [tempDirPath1]) + assert.deepEqual(await getTreeViewRootDirectories(app2Window2), [tempDirPath2]) }) - assert.equal(cursorRow, 2) + it('when windows already exist, opens a new window with a single untitled buffer', async () => { + const atomApplication = buildAtomApplication() + const [window1] = await atomApplication.launch(parseCommandLine([])) + await focusWindow(window1) + const window1EditorTitle = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { + sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle()) + }) + assert.equal(window1EditorTitle, 'untitled') + + const window2 = atomApplication.openWithOptions(parseCommandLine([])) + await window2.loadedPromise + const window2EditorTitle = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { + sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle()) + }) + assert.equal(window2EditorTitle, 'untitled') + + assert.deepEqual(atomApplication.getAllWindows(), [window2, window1]) + }) + + it('when no windows are open but --new-window is passed, opens a new window with a single untitled buffer', async () => { + // Populate some saved state + const tempDirPath1 = makeTempDir() + const tempDirPath2 = makeTempDir() + + const atomApplication1 = buildAtomApplication() + const [app1Window1] = await atomApplication1.launch(parseCommandLine([tempDirPath1])) + await emitterEventPromise(app1Window1, 'window:locations-opened') + + const [app1Window2] = await atomApplication1.launch(parseCommandLine([tempDirPath2])) + await emitterEventPromise(app1Window2, 'window:locations-opened') + + await Promise.all([ + app1Window1.prepareToUnload(), + app1Window2.prepareToUnload() + ]) + + // Launch with --new-window + const atomApplication2 = buildAtomApplication() + const appWindows2 = await atomApplication2.launch(parseCommandLine(['--new-window'])) + assert.lengthOf(appWindows2, 1) + const [appWindow2] = appWindows2 + await appWindow2.loadedPromise + const window2EditorTitle = await evalInWebContents(appWindow2.browserWindow.webContents, sendBackToMainProcess => { + sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle()) + }) + assert.equal(window2EditorTitle, 'untitled') + }) + + it('does not open an empty editor if core.openEmptyEditorOnStart is false', async () => { + const configPath = path.join(process.env.ATOM_HOME, 'config.cson') + const config = season.readFileSync(configPath) + if (!config['*'].core) config['*'].core = {} + config['*'].core.openEmptyEditorOnStart = false + season.writeFileSync(configPath, config) + + const atomApplication = buildAtomApplication() + const [window1] = await atomApplication.launch(parseCommandLine([])) + await focusWindow(window1) + + // wait a bit just to make sure we don't pass due to querying the render process before it loads + await timeoutPromise(1000) + + const itemCount = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { + sendBackToMainProcess(atom.workspace.getActivePane().getItems().length) + }) + assert.equal(itemCount, 0) + }) }) - it('can open to a specific line and column of a file', async () => { - const filePath = path.join(makeTempDir(), 'new-file') - fs.writeFileSync(filePath, '1\n2\n3\n4\n') - const atomApplication = buildAtomApplication() + describe('with file or folder paths', () => { + it('shows all directories in the tree view when multiple directory paths are passed to Atom', async () => { + const dirAPath = makeTempDir('a') + const dirBPath = makeTempDir('b') + const dirBSubdirPath = path.join(dirBPath, 'c') + fs.mkdirSync(dirBSubdirPath) - const [window] = await atomApplication.launch(parseCommandLine([filePath + ':2:2'])) - await focusWindow(window) + const atomApplication = buildAtomApplication() + const [window1] = await atomApplication.launch(parseCommandLine([dirAPath, dirBPath])) + await focusWindow(window1) - const cursorPosition = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => { - atom.workspace.observeTextEditors(textEditor => { - sendBackToMainProcess(textEditor.getCursorBufferPosition()) - }) + await conditionPromise(async () => (await getTreeViewRootDirectories(window1)).length === 2) + assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath, dirBPath]) }) - assert.deepEqual(cursorPosition, {row: 1, column: 1}) + it('can open to a specific line number of a file', async () => { + const filePath = path.join(makeTempDir(), 'new-file') + fs.writeFileSync(filePath, '1\n2\n3\n4\n') + const atomApplication = buildAtomApplication() + + const [window] = await atomApplication.launch(parseCommandLine([filePath + ':3'])) + await focusWindow(window) + + const cursorRow = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => { + atom.workspace.observeTextEditors(textEditor => { + sendBackToMainProcess(textEditor.getCursorBufferPosition().row) + }) + }) + + assert.equal(cursorRow, 2) + }) + + it('can open to a specific line and column of a file', async () => { + const filePath = path.join(makeTempDir(), 'new-file') + fs.writeFileSync(filePath, '1\n2\n3\n4\n') + const atomApplication = buildAtomApplication() + + const [window] = await atomApplication.launch(parseCommandLine([filePath + ':2:2'])) + await focusWindow(window) + + const cursorPosition = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => { + atom.workspace.observeTextEditors(textEditor => { + sendBackToMainProcess(textEditor.getCursorBufferPosition()) + }) + }) + + assert.deepEqual(cursorPosition, {row: 1, column: 1}) + }) + + it('removes all trailing whitespace and colons from the specified path', async () => { + let filePath = path.join(makeTempDir(), 'new-file') + fs.writeFileSync(filePath, '1\n2\n3\n4\n') + const atomApplication = buildAtomApplication() + + const [window] = await atomApplication.launch(parseCommandLine([filePath + ':: '])) + await focusWindow(window) + + const openedPath = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => { + atom.workspace.observeTextEditors(textEditor => { + sendBackToMainProcess(textEditor.getPath()) + }) + }) + + assert.equal(openedPath, filePath) + }) + + it('opens an empty text editor when launched with a new file path', async () => { + // Choosing "Don't save" + mockElectronShowMessageBox({response: 2}) + + const atomApplication = buildAtomApplication() + const newFilePath = path.join(makeTempDir(), 'new-file') + const [window] = await atomApplication.launch(parseCommandLine([newFilePath])) + await focusWindow(window) + const {editorTitle, editorText} = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => { + atom.workspace.observeTextEditors(editor => { + sendBackToMainProcess({editorTitle: editor.getTitle(), editorText: editor.getText()}) + }) + }) + assert.equal(editorTitle, path.basename(newFilePath)) + assert.equal(editorText, '') + assert.deepEqual(await getTreeViewRootDirectories(window), []) + }) }) - it('removes all trailing whitespace and colons from the specified path', async () => { - let filePath = path.join(makeTempDir(), 'new-file') - fs.writeFileSync(filePath, '1\n2\n3\n4\n') - const atomApplication = buildAtomApplication() + describe('when the --add option is specified', () => { + it('adds folders to existing windows when the --add option is used', async () => { + const dirAPath = makeTempDir('a') + const dirBPath = makeTempDir('b') + const dirCPath = makeTempDir('c') + const existingDirCFilePath = path.join(dirCPath, 'existing-file') + fs.writeFileSync(existingDirCFilePath, 'this is an existing file') - const [window] = await atomApplication.launch(parseCommandLine([filePath + ':: '])) - await focusWindow(window) + const atomApplication = buildAtomApplication() + const [window1] = await atomApplication.launch(parseCommandLine([dirAPath])) + await focusWindow(window1) - const openedPath = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => { - atom.workspace.observeTextEditors(textEditor => { - sendBackToMainProcess(textEditor.getPath()) + await conditionPromise(async () => (await getTreeViewRootDirectories(window1)).length === 1) + assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath]) + + // When opening *files* with --add, reuses an existing window + let [reusedWindow] = await atomApplication.launch(parseCommandLine([existingDirCFilePath, '--add'])) + assert.equal(reusedWindow, window1) + assert.deepEqual(atomApplication.getAllWindows(), [window1]) + let activeEditorPath = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { + const subscription = atom.workspace.onDidChangeActivePaneItem(textEditor => { + sendBackToMainProcess(textEditor.getPath()) + subscription.dispose() + }) }) - }) + assert.equal(activeEditorPath, existingDirCFilePath) + assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath]) - assert.equal(openedPath, filePath) + // When opening *directories* with --add, reuses an existing window and adds the directory to the project + reusedWindow = (await atomApplication.launch(parseCommandLine([dirBPath, '-a'])))[0] + assert.equal(reusedWindow, window1) + assert.deepEqual(atomApplication.getAllWindows(), [window1]) + + await conditionPromise(async () => (await getTreeViewRootDirectories(reusedWindow)).length === 2) + assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath, dirBPath]) + }) }) if (process.platform === 'darwin' || process.platform === 'win32') { @@ -114,95 +287,15 @@ describe('AtomApplication', function () { }) } - it('reuses existing windows when opening paths, but not directories', async () => { - const dirAPath = makeTempDir("a") - const dirBPath = makeTempDir("b") - const dirCPath = makeTempDir("c") - const existingDirCFilePath = path.join(dirCPath, 'existing-file') - fs.writeFileSync(existingDirCFilePath, 'this is an existing file') - - const atomApplication = buildAtomApplication() - const [window1] = await atomApplication.launch(parseCommandLine([path.join(dirAPath, 'new-file')])) - await emitterEventPromise(window1, 'window:locations-opened') - await focusWindow(window1) - - let activeEditorPath = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { - atom.workspace.observeTextEditors(textEditor => { - sendBackToMainProcess(textEditor.getPath()) - }) - }) - assert.equal(activeEditorPath, path.join(dirAPath, 'new-file')) - - // Reuses the window when opening *files*, even if they're in a different directory - // Does not change the project paths when doing so. - const [reusedWindow] = await atomApplication.launch(parseCommandLine([existingDirCFilePath])) - assert.equal(reusedWindow, window1) - assert.deepEqual(atomApplication.getAllWindows(), [window1]) - activeEditorPath = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { - const subscription = atom.workspace.onDidChangeActivePaneItem(textEditor => { - sendBackToMainProcess(textEditor.getPath()) - subscription.dispose() - }) - }) - assert.equal(activeEditorPath, existingDirCFilePath) - assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath]) - - // Opens new windows when opening directories - const [window2] = await atomApplication.launch(parseCommandLine([dirCPath])) - await emitterEventPromise(window2, 'window:locations-opened') - assert.notEqual(window2, window1) - await focusWindow(window2) - assert.deepEqual(await getTreeViewRootDirectories(window2), [dirCPath]) - }) - - it('adds folders to existing windows when the --add option is used', async () => { - const dirAPath = makeTempDir("a") - const dirBPath = makeTempDir("b") - const dirCPath = makeTempDir("c") - const existingDirCFilePath = path.join(dirCPath, 'existing-file') - fs.writeFileSync(existingDirCFilePath, 'this is an existing file') - - const atomApplication = buildAtomApplication() - const [window1] = await atomApplication.launch(parseCommandLine([path.join(dirAPath, 'new-file')])) - await focusWindow(window1) - - let activeEditorPath = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { - atom.workspace.observeTextEditors(textEditor => { - sendBackToMainProcess(textEditor.getPath()) - }) - }) - assert.equal(activeEditorPath, path.join(dirAPath, 'new-file')) - - // When opening *files* with --add, reuses an existing window and adds - // parent directory to the project - let [reusedWindow] = await atomApplication.launch(parseCommandLine([existingDirCFilePath, '--add'])) - assert.equal(reusedWindow, window1) - assert.deepEqual(atomApplication.getAllWindows(), [window1]) - activeEditorPath = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { - const subscription = atom.workspace.onDidChangeActivePaneItem(textEditor => { - sendBackToMainProcess(textEditor.getPath()) - subscription.dispose() - }) - }) - assert.equal(activeEditorPath, existingDirCFilePath) - assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath, dirCPath]) - - // When opening *directories* with add reuses an existing window and adds - // the directory to the project - reusedWindow = (await atomApplication.launch(parseCommandLine([dirBPath, '-a'])))[0] - assert.equal(reusedWindow, window1) - assert.deepEqual(atomApplication.getAllWindows(), [window1]) - - await conditionPromise(async () => (await getTreeViewRootDirectories(reusedWindow)).length === 3) - assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath, dirCPath, dirBPath]) - }) - it('persists window state based on the project directories', async () => { + // Choosing "Don't save" + mockElectronShowMessageBox({response: 2}) + const tempDirPath = makeTempDir() const atomApplication = buildAtomApplication() const nonExistentFilePath = path.join(tempDirPath, 'new-file') - const [window1] = await atomApplication.launch(parseCommandLine([nonExistentFilePath])) + const [window1] = await atomApplication.launch(parseCommandLine([tempDirPath, nonExistentFilePath])) await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { atom.workspace.observeTextEditors(textEditor => { textEditor.insertText('Hello World!') @@ -213,7 +306,7 @@ describe('AtomApplication', function () { window1.close() await window1.closedPromise - // Restore unsaved state when opening the directory itself + // Restore unsaved state when opening the same project directory const [window2] = await atomApplication.launch(parseCommandLine([tempDirPath])) await window2.loadedPromise const window2Text = await evalInWebContents(window2.browserWindow.webContents, sendBackToMainProcess => { @@ -223,95 +316,6 @@ describe('AtomApplication', function () { sendBackToMainProcess(textEditor.getText()) }) assert.equal(window2Text, 'Hello World! How are you?') - await window2.prepareToUnload() - window2.close() - await window2.closedPromise - - // Restore unsaved state when opening a path to a non-existent file in the directory - const [window3] = await atomApplication.launch(parseCommandLine([path.join(tempDirPath, 'another-non-existent-file')])) - await window3.loadedPromise - const window3Texts = await evalInWebContents(window3.browserWindow.webContents, (sendBackToMainProcess, nonExistentFilePath) => { - sendBackToMainProcess(atom.workspace.getTextEditors().map(editor => editor.getText())) - }) - assert.include(window3Texts, 'Hello World! How are you?') - }) - - it('shows all directories in the tree view when multiple directory paths are passed to Atom', async () => { - const dirAPath = makeTempDir("a") - const dirBPath = makeTempDir("b") - const dirBSubdirPath = path.join(dirBPath, 'c') - fs.mkdirSync(dirBSubdirPath) - - const atomApplication = buildAtomApplication() - const [window1] = await atomApplication.launch(parseCommandLine([dirAPath, dirBPath])) - await focusWindow(window1) - - assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath, dirBPath]) - }) - - it('reuses windows with no project paths to open directories', async () => { - const tempDirPath = makeTempDir() - const atomApplication = buildAtomApplication() - const [window1] = await atomApplication.launch(parseCommandLine([])) - await focusWindow(window1) - - const [reusedWindow] = await atomApplication.launch(parseCommandLine([tempDirPath])) - assert.equal(reusedWindow, window1) - await conditionPromise(async () => (await getTreeViewRootDirectories(reusedWindow)).length > 0) - }) - - it('opens a new window with a single untitled buffer when launched with no path, even if windows already exist', async () => { - const atomApplication = buildAtomApplication() - const [window1] = await atomApplication.launch(parseCommandLine([])) - await focusWindow(window1) - const window1EditorTitle = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { - sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle()) - }) - assert.equal(window1EditorTitle, 'untitled') - - const window2 = atomApplication.openWithOptions(parseCommandLine([])) - await focusWindow(window2) - const window2EditorTitle = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { - sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle()) - }) - assert.equal(window2EditorTitle, 'untitled') - - assert.deepEqual(atomApplication.getAllWindows(), [window2, window1]) - }) - - it('does not open an empty editor when opened with no path if the core.openEmptyEditorOnStart config setting is false', async () => { - const configPath = path.join(process.env.ATOM_HOME, 'config.cson') - const config = season.readFileSync(configPath) - if (!config['*'].core) config['*'].core = {} - config['*'].core.openEmptyEditorOnStart = false - season.writeFileSync(configPath, config) - - const atomApplication = buildAtomApplication() - const [window1] = await atomApplication.launch(parseCommandLine([])) - await focusWindow(window1) - - // wait a bit just to make sure we don't pass due to querying the render process before it loads - await timeoutPromise(1000) - - const itemCount = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { - sendBackToMainProcess(atom.workspace.getActivePane().getItems().length) - }) - assert.equal(itemCount, 0) - }) - - it('opens an empty text editor and loads its parent directory in the tree-view when launched with a new file path', async () => { - const atomApplication = buildAtomApplication() - const newFilePath = path.join(makeTempDir(), 'new-file') - const [window] = await atomApplication.launch(parseCommandLine([newFilePath])) - await focusWindow(window) - const {editorTitle, editorText} = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => { - atom.workspace.observeTextEditors(editor => { - sendBackToMainProcess({editorTitle: editor.getTitle(), editorText: editor.getText()}) - }) - }) - assert.equal(editorTitle, path.basename(newFilePath)) - assert.equal(editorText, '') - assert.deepEqual(await getTreeViewRootDirectories(window), [path.dirname(newFilePath)]) }) it('adds a remote directory to the project when launched with a remote directory', async () => { @@ -343,38 +347,11 @@ describe('AtomApplication', function () { } }) - it('reopens any previously opened windows when launched with no path', async () => { - if (process.platform === 'win32') return; // Test is too flakey on Windows - - const tempDirPath1 = makeTempDir() - const tempDirPath2 = makeTempDir() - - const atomApplication1 = buildAtomApplication() - const [app1Window1] = await atomApplication1.launch(parseCommandLine([tempDirPath1])) - await emitterEventPromise(app1Window1, 'window:locations-opened') - const [app1Window2] = await atomApplication1.launch(parseCommandLine([tempDirPath2])) - await emitterEventPromise(app1Window2, 'window:locations-opened') - - await Promise.all([ - app1Window1.prepareToUnload(), - app1Window2.prepareToUnload() - ]) - - const atomApplication2 = buildAtomApplication() - const [app2Window1, app2Window2] = await atomApplication2.launch(parseCommandLine([])) - await Promise.all([ - emitterEventPromise(app2Window1, 'window:locations-opened'), - emitterEventPromise(app2Window2, 'window:locations-opened') - ]) - - assert.deepEqual(await getTreeViewRootDirectories(app2Window1), [tempDirPath1]) - assert.deepEqual(await getTreeViewRootDirectories(app2Window2), [tempDirPath2]) - }) - it('does not reopen any previously opened windows when launched with no path and `core.restorePreviousWindowsOnStart` is no', async () => { const atomApplication1 = buildAtomApplication() const [app1Window1] = await atomApplication1.launch(parseCommandLine([makeTempDir()])) await focusWindow(app1Window1) + const [app1Window2] = await atomApplication1.launch(parseCommandLine([makeTempDir()])) await focusWindow(app1Window2) @@ -424,15 +401,16 @@ describe('AtomApplication', function () { }) it('kills the specified pid after a newly-opened file in an existing window is closed', async () => { - const [window] = await atomApplication.launch(parseCommandLine(['--wait', '--pid', '101'])) - await focusWindow(window) - - const filePath1 = temp.openSync('test').path - const filePath2 = temp.openSync('test').path + const projectDir = makeTempDir('existing') + const filePath1 = path.join(projectDir, 'file-1') + const filePath2 = path.join(projectDir, 'file-2') fs.writeFileSync(filePath1, 'File 1') fs.writeFileSync(filePath2, 'File 2') - const [reusedWindow] = await atomApplication.launch(parseCommandLine(['--wait', '--pid', '102', filePath1, filePath2])) + const [window] = await atomApplication.launch(parseCommandLine(['--wait', '--pid', '101', projectDir])) + await focusWindow(window) + + const [reusedWindow] = await atomApplication.launch(parseCommandLine(['--add', '--wait', '--pid', '102', filePath1, filePath2])) assert.equal(reusedWindow, window) const activeEditorPath = await evalInWebContents(window.browserWindow.webContents, send => { @@ -471,8 +449,9 @@ describe('AtomApplication', function () { await focusWindow(window) const dirPath1 = makeTempDir() - const [reusedWindow] = await atomApplication.launch(parseCommandLine(['--wait', '--pid', '101', dirPath1])) + const [reusedWindow] = await atomApplication.launch(parseCommandLine(['--add', '--wait', '--pid', '101', dirPath1])) assert.equal(reusedWindow, window) + await conditionPromise(async () => (await getTreeViewRootDirectories(window)).length === 1) assert.deepEqual(await getTreeViewRootDirectories(window), [dirPath1]) assert.deepEqual(killedPids, []) @@ -498,7 +477,7 @@ describe('AtomApplication', function () { if (process.platform === 'linux' || process.platform === 'win32') { it('quits the application', async () => { const atomApplication = buildAtomApplication() - const [window] = await atomApplication.launch(parseCommandLine([path.join(makeTempDir("a"), 'file-a')])) + const [window] = await atomApplication.launch(parseCommandLine([path.join(makeTempDir('a'), 'file-a')])) await focusWindow(window) window.close() await window.closedPromise @@ -508,7 +487,7 @@ describe('AtomApplication', function () { } else if (process.platform === 'darwin') { it('leaves the application open', async () => { const atomApplication = buildAtomApplication() - const [window] = await atomApplication.launch(parseCommandLine([path.join(makeTempDir("a"), 'file-a')])) + const [window] = await atomApplication.launch(parseCommandLine([path.join(makeTempDir('a'), 'file-a')])) await focusWindow(window) window.close() await window.closedPromise @@ -524,24 +503,24 @@ describe('AtomApplication', function () { const dirB = makeTempDir() const atomApplication = buildAtomApplication() - const [window] = await atomApplication.launch(parseCommandLine([dirA, dirB])) - await emitterEventPromise(window, 'window:locations-opened') - await focusWindow(window) - assert.deepEqual(await getTreeViewRootDirectories(window), [dirA, dirB]) + const [window0] = await atomApplication.launch(parseCommandLine([dirA, dirB])) + await focusWindow(window0) + await conditionPromise(async () => (await getTreeViewRootDirectories(window0)).length === 2) + assert.deepEqual(await getTreeViewRootDirectories(window0), [dirA, dirB]) const saveStatePromise = emitterEventPromise(atomApplication, 'application:did-save-state') - await evalInWebContents(window.browserWindow.webContents, (sendBackToMainProcess) => { + await evalInWebContents(window0.browserWindow.webContents, (sendBackToMainProcess) => { atom.project.removePath(atom.project.getPaths()[0]) sendBackToMainProcess(null) }) - assert.deepEqual(await getTreeViewRootDirectories(window), [dirB]) + assert.deepEqual(await getTreeViewRootDirectories(window0), [dirB]) await saveStatePromise // Window state should be saved when the project folder is removed const atomApplication2 = buildAtomApplication() const [window2] = await atomApplication2.launch(parseCommandLine([])) - await emitterEventPromise(window2, 'window:locations-opened') await focusWindow(window2) + await conditionPromise(async () => (await getTreeViewRootDirectories(window2)).length === 1) assert.deepEqual(await getTreeViewRootDirectories(window2), [dirB]) }) }) @@ -562,11 +541,11 @@ describe('AtomApplication', function () { let reached = await evalInWebContents(windows[0].browserWindow.webContents, sendBackToMainProcess => { sendBackToMainProcess(global.reachedUrlMain) }) - assert.equal(reached, true); - windows[0].close(); + assert.isTrue(reached) + windows[0].close() }) - it('triggers /core/open/file in the correct window', async function() { + it('triggers /core/open/file in the correct window', async function () { const dirAPath = makeTempDir('a') const dirBPath = makeTempDir('b') @@ -594,12 +573,12 @@ describe('AtomApplication', function () { }) it('waits until all the windows have saved their state before quitting', async () => { - const dirAPath = makeTempDir("a") - const dirBPath = makeTempDir("b") + const dirAPath = makeTempDir('a') + const dirBPath = makeTempDir('b') const atomApplication = buildAtomApplication() - const [window1] = await atomApplication.launch(parseCommandLine([path.join(dirAPath, 'file-a')])) + const [window1] = await atomApplication.launch(parseCommandLine([dirAPath])) await focusWindow(window1) - const [window2] = await atomApplication.launch(parseCommandLine([path.join(dirBPath, 'file-b')])) + const [window2] = await atomApplication.launch(parseCommandLine([dirBPath])) await focusWindow(window2) electron.app.quit() await new Promise(process.nextTick) @@ -662,7 +641,7 @@ describe('AtomApplication', function () { function buildAtomApplication (params = {}) { const atomApplication = new AtomApplication(Object.assign({ resourcePath: ATOM_RESOURCE_PATH, - atomHomeDirPath: process.env.ATOM_HOME, + atomHomeDirPath: process.env.ATOM_HOME }, params)) atomApplicationsToDestroy.push(atomApplication) return atomApplication @@ -680,7 +659,7 @@ describe('AtomApplication', function () { electron.app.quit = function () { this.quit.callCount++ let defaultPrevented = false - this.emit('before-quit', {preventDefault() { defaultPrevented = true }}) + this.emit('before-quit', {preventDefault () { defaultPrevented = true }}) if (!defaultPrevented) didQuit = true } @@ -710,12 +689,15 @@ describe('AtomApplication', function () { resolve(result) } - webContents.executeJavaScript(dedent` + const js = dedent` function sendBackToMainProcess (result) { require('electron').ipcRenderer.send('${channelId}', result) } (${source})(sendBackToMainProcess, ${args.map(JSON.stringify).join(', ')}) - `) + ` + // console.log(`about to execute:\n${js}`) + + webContents.executeJavaScript(js) }) } @@ -728,6 +710,8 @@ describe('AtomApplication', function () { .from(treeView.element.querySelectorAll('.project-root > .header .name')) .map(element => element.dataset.path) ) + } else { + sendBackToMainProcess([]) } }) }) diff --git a/spec/selection-spec.js b/spec/selection-spec.js index e9cf1c617..216c3936c 100644 --- a/spec/selection-spec.js +++ b/spec/selection-spec.js @@ -1,5 +1,6 @@ const TextEditor = require('../src/text-editor') +// Tests crash the renderer process on Electron 3.0, disabling for now. describe('Selection', () => { let buffer, editor, selection diff --git a/spec/style-manager-spec.js b/spec/style-manager-spec.js index 641c93709..fba73c808 100644 --- a/spec/style-manager-spec.js +++ b/spec/style-manager-spec.js @@ -47,7 +47,6 @@ describe('StyleManager', () => { atom-text-editor::shadow .class-1, atom-text-editor::shadow .class-2 { color: red } atom-text-editor::shadow > .class-3 { color: yellow } atom-text-editor .class-4 { color: blue } - another-element::shadow .class-5 { color: white } atom-text-editor[data-grammar*=\"js\"]::shadow .class-6 { color: green; } atom-text-editor[mini].is-focused::shadow .class-7 { color: green; } `) @@ -55,7 +54,6 @@ describe('StyleManager', () => { 'atom-text-editor.editor .class-1, atom-text-editor.editor .class-2', 'atom-text-editor.editor > .class-3', 'atom-text-editor .class-4', - 'another-element::shadow .class-5', 'atom-text-editor[data-grammar*=\"js\"].editor .class-6', 'atom-text-editor[mini].is-focused.editor .class-7' ]) @@ -102,13 +100,6 @@ describe('StyleManager', () => { ]) }) - it('does not transform CSS rules with invalid syntax', () => { - styleManager.addStyleSheet("atom-text-editor::shadow .class-1 { font-family: inval'id }") - expect(Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map((r) => r.selectorText)).toEqual([ - 'atom-text-editor::shadow .class-1' - ]) - }) - it('does not throw exceptions on rules with no selectors', () => { styleManager.addStyleSheet('@media screen {font-size: 10px}', {context: 'atom-text-editor'}) }) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index 2db53db53..dbad4a3e7 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -2638,7 +2638,71 @@ describe('TextEditorComponent', () => { expect(editor.getCursorScreenPosition()).toEqual([0, 0]) }) - function createBlockDecorationAtScreenRow(editor, screenRow, {height, margin, marginTop, marginBottom, position, invalidate}) { + it('uses the order property to control the order of block decorations at the same screen row', async () => { + const editor = buildEditor({autoHeight: false}) + const {component, element} = buildComponent({editor}) + element.style.height = 10 * component.getLineHeight() + horizontalScrollbarHeight + 'px' + await component.getNextUpdatePromise() + + // Order parameters that differ from creation order; that collide; and that are not provided. + const [beforeItems, beforeDecorations] = [30, 20, undefined, 20, 10, undefined].map(order => { + return createBlockDecorationAtScreenRow(editor, 2, {height: 10, position: 'before', order}) + }).reduce((lists, result) => { + lists[0].push(result.item) + lists[1].push(result.decoration) + return lists + }, [[], []]) + + const [afterItems, afterDecorations] = [undefined, 1, 6, undefined, 6, 2].map(order => { + return createBlockDecorationAtScreenRow(editor, 2, {height: 10, position: 'after', order}) + }).reduce((lists, result) => { + lists[0].push(result.item) + lists[1].push(result.decoration) + return lists + }, [[], []]) + + await component.getNextUpdatePromise() + + expect(beforeItems[4].previousSibling).toBe(lineNodeForScreenRow(component, 1)) + expect(beforeItems[4].nextSibling).toBe(beforeItems[1]) + expect(beforeItems[1].nextSibling).toBe(beforeItems[3]) + expect(beforeItems[3].nextSibling).toBe(beforeItems[0]) + expect(beforeItems[0].nextSibling).toBe(beforeItems[2]) + expect(beforeItems[2].nextSibling).toBe(beforeItems[5]) + expect(beforeItems[5].nextSibling).toBe(lineNodeForScreenRow(component, 2)) + expect(afterItems[1].previousSibling).toBe(lineNodeForScreenRow(component, 2)) + expect(afterItems[1].nextSibling).toBe(afterItems[5]) + expect(afterItems[5].nextSibling).toBe(afterItems[2]) + expect(afterItems[2].nextSibling).toBe(afterItems[4]) + expect(afterItems[4].nextSibling).toBe(afterItems[0]) + expect(afterItems[0].nextSibling).toBe(afterItems[3]) + + // Create a decoration somewhere else and move it to the same screen row as the existing decorations + const {item: later, decoration} = createBlockDecorationAtScreenRow(editor, 4, {height: 20, position: 'after', order: 3}) + await component.getNextUpdatePromise() + expect(later.previousSibling).toBe(lineNodeForScreenRow(component, 4)) + expect(later.nextSibling).toBe(lineNodeForScreenRow(component, 5)) + + decoration.getMarker().setHeadScreenPosition([2, 0]) + await component.getNextUpdatePromise() + expect(later.previousSibling).toBe(afterItems[5]) + expect(later.nextSibling).toBe(afterItems[2]) + + // Move a decoration away from its screen row and ensure the rest maintain their order + beforeDecorations[3].getMarker().setHeadScreenPosition([5, 0]) + await component.getNextUpdatePromise() + expect(beforeItems[3].previousSibling).toBe(lineNodeForScreenRow(component, 4)) + expect(beforeItems[3].nextSibling).toBe(lineNodeForScreenRow(component, 5)) + + expect(beforeItems[4].previousSibling).toBe(lineNodeForScreenRow(component, 1)) + expect(beforeItems[4].nextSibling).toBe(beforeItems[1]) + expect(beforeItems[1].nextSibling).toBe(beforeItems[0]) + expect(beforeItems[0].nextSibling).toBe(beforeItems[2]) + expect(beforeItems[2].nextSibling).toBe(beforeItems[5]) + expect(beforeItems[5].nextSibling).toBe(lineNodeForScreenRow(component, 2)) + }); + + function createBlockDecorationAtScreenRow(editor, screenRow, {height, margin, marginTop, marginBottom, position, order, invalidate}) { const marker = editor.markScreenPosition([screenRow, 0], {invalidate: invalidate || 'never'}) const item = document.createElement('div') item.style.height = height + 'px' @@ -2646,7 +2710,7 @@ describe('TextEditorComponent', () => { if (marginTop != null) item.style.marginTop = marginTop + 'px' if (marginBottom != null) item.style.marginBottom = marginBottom + 'px' item.style.width = 30 + 'px' - const decoration = editor.decorateMarker(marker, {type: 'block', item, position}) + const decoration = editor.decorateMarker(marker, {type: 'block', item, position, order}) return {item, decoration, marker} } diff --git a/spec/text-editor-spec.js b/spec/text-editor-spec.js index 587e1b523..908ea8082 100644 --- a/spec/text-editor-spec.js +++ b/spec/text-editor-spec.js @@ -6861,7 +6861,7 @@ describe('TextEditor', () => { const marker = editor.markBufferRange([[2, 4], [6, 8]]) const decoration = editor.decorateMarker(marker, {type: 'highlight', class: 'foo'}) expect(editor.decorationsStateForScreenRowRange(0, 5)[decoration.id]).toEqual({ - properties: {type: 'highlight', class: 'foo'}, + properties: {id: decoration.id, order: Infinity, type: 'highlight', class: 'foo'}, screenRange: marker.getScreenRange(), bufferRange: marker.getBufferRange(), rangeIsReversed: false diff --git a/spec/text-mate-language-mode-spec.js b/spec/text-mate-language-mode-spec.js index 47b79af2d..226a828e7 100644 --- a/spec/text-mate-language-mode-spec.js +++ b/spec/text-mate-language-mode-spec.js @@ -6,6 +6,7 @@ const _ = require('underscore-plus') const dedent = require('dedent') const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') +// Tests crash the renderer process on Electron 3.0, disabling for now. describe('TextMateLanguageMode', () => { let languageMode, buffer, config diff --git a/spec/theme-manager-spec.js b/spec/theme-manager-spec.js index 9d1d3a3cc..48bc17ebe 100644 --- a/spec/theme-manager-spec.js +++ b/spec/theme-manager-spec.js @@ -251,9 +251,9 @@ h2 { it('returns a disposable allowing styles applied by the given path to be removed', function () { const cssPath = require.resolve('./fixtures/css.css') - expect(getComputedStyle(document.body).fontWeight).not.toBe('bold') + expect(getComputedStyle(document.body).fontWeight).not.toBe('700') const disposable = atom.themes.requireStylesheet(cssPath) - expect(getComputedStyle(document.body).fontWeight).toBe('bold') + expect(getComputedStyle(document.body).fontWeight).toBe('700') let styleElementRemovedHandler atom.styles.onDidRemoveStyleElement(styleElementRemovedHandler = jasmine.createSpy('styleElementRemovedHandler')) diff --git a/spec/tree-sitter-language-mode-spec.js b/spec/tree-sitter-language-mode-spec.js index b6e5db70e..7b8344d9c 100644 --- a/spec/tree-sitter-language-mode-spec.js +++ b/spec/tree-sitter-language-mode-spec.js @@ -407,7 +407,7 @@ describe('TreeSitterLanguageMode', () => { scopes: { 'identifier': 'variable', 'call_expression > identifier': 'function', - 'new_expression > call_expression > identifier': 'constructor' + 'new_expression > identifier': 'constructor' } }) @@ -1307,6 +1307,42 @@ describe('TreeSitterLanguageMode', () => { `) }) + it('updates fold locations when the buffer changes', () => { + const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { + parser: 'tree-sitter-javascript', + folds: [ + { + start: {type: '{', index: 0}, + end: {type: '}', index: -1} + } + ] + }) + + buffer.setText(dedent ` + class A { + // a + constructor (b) { + this.b = b + } + } + `) + + const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + buffer.setLanguageMode(languageMode) + expect(languageMode.isFoldableAtRow(0)).toBe(true) + expect(languageMode.isFoldableAtRow(1)).toBe(false) + expect(languageMode.isFoldableAtRow(2)).toBe(true) + expect(languageMode.isFoldableAtRow(3)).toBe(false) + expect(languageMode.isFoldableAtRow(4)).toBe(false) + + buffer.insert([0, 0], '\n') + expect(languageMode.isFoldableAtRow(0)).toBe(false) + expect(languageMode.isFoldableAtRow(1)).toBe(true) + expect(languageMode.isFoldableAtRow(2)).toBe(false) + expect(languageMode.isFoldableAtRow(3)).toBe(true) + expect(languageMode.isFoldableAtRow(4)).toBe(false) + }) + describe('when folding a node that ends with a line break', () => { it('ends the fold at the end of the previous line', async () => { const grammar = new TreeSitterGrammar(atom.grammars, pythonGrammarPath, { diff --git a/spec/workspace-spec.js b/spec/workspace-spec.js index 091588a70..7bfbe5408 100644 --- a/spec/workspace-spec.js +++ b/spec/workspace-spec.js @@ -2086,7 +2086,7 @@ describe('Workspace', () => { }) runs(() => { - fs.rename(path.join(projectPath, 'git.git'), path.join(projectPath, '.git')) + fs.renameSync(path.join(projectPath, 'git.git'), path.join(projectPath, '.git')) ignoredPath = path.join(projectPath, 'ignored.txt') fs.writeFileSync(ignoredPath, 'this match should not be included') }) diff --git a/src/atom-environment.js b/src/atom-environment.js index 915ff78f1..98a89fe45 100644 --- a/src/atom-environment.js +++ b/src/atom-environment.js @@ -1,5 +1,6 @@ const crypto = require('crypto') const path = require('path') +const util = require('util') const {ipcRenderer} = require('electron') const _ = require('underscore-plus') @@ -44,6 +45,8 @@ const TextBuffer = require('text-buffer') const TextEditorRegistry = require('./text-editor-registry') const AutoUpdateManager = require('./auto-update-manager') +const stat = util.promisify(fs.stat) + let nextId = 0 // Essential: Atom global for dealing with packages, themes, menus, and the window. @@ -1010,6 +1013,7 @@ class AtomEnvironment { // window.alert('bummer') // } // }) + // ``` // // ```js // // Legacy sync version @@ -1358,42 +1362,71 @@ or use Pane::saveItemAs for programmatic saving.`) async openLocations (locations) { const needsProjectPaths = this.project && this.project.getPaths().length === 0 - const foldersToAddToProject = [] + const foldersToAddToProject = new Set() const fileLocationsToOpen = [] + const missingFolders = [] - function pushFolderToOpen (folder) { - if (!foldersToAddToProject.includes(folder)) { - foldersToAddToProject.push(folder) - } - } + // Asynchronously fetch stat information about each requested path to open. + const locationStats = await Promise.all( + locations.map(async location => { + const stats = location.pathToOpen ? await stat(location.pathToOpen).catch(() => null) : null + return {location, stats} + }), + ) - for (const location of locations) { + for (const {location, stats} of locationStats) { const {pathToOpen} = location - if (pathToOpen && (needsProjectPaths || location.forceAddToWindow)) { - if (fs.existsSync(pathToOpen)) { - pushFolderToOpen(this.project.getDirectoryForProjectPath(pathToOpen).getPath()) - } else if (fs.existsSync(path.dirname(pathToOpen))) { - pushFolderToOpen(this.project.getDirectoryForProjectPath(path.dirname(pathToOpen)).getPath()) - } else { - pushFolderToOpen(this.project.getDirectoryForProjectPath(pathToOpen).getPath()) - } + if (!pathToOpen) { + // Untitled buffer + fileLocationsToOpen.push(location) + continue } - if (!fs.isDirectorySync(pathToOpen)) { - fileLocationsToOpen.push(location) + if (stats !== null) { + // Path exists + if (stats.isDirectory()) { + // Directory: add as a project folder + foldersToAddToProject.add(this.project.getDirectoryForProjectPath(pathToOpen).getPath()) + } else if (stats.isFile()) { + if (location.mustBeDirectory) { + // File: no longer a directory + missingFolders.push(location) + } else { + // File: add as a file location + fileLocationsToOpen.push(location) + } + } + } else { + // Path does not exist + // Attempt to interpret as a URI from a non-default directory provider + const directory = this.project.getProvidedDirectoryForProjectPath(pathToOpen) + if (directory) { + // Found: add as a project folder + foldersToAddToProject.add(directory.getPath()) + } else if (location.mustBeDirectory) { + // Not found and must be a directory: add to missing list and use to derive state key + missingFolders.push(location) + } else { + // Not found: open as a new file + fileLocationsToOpen.push(location) + } } if (location.hasWaitSession) this.pathsWithWaitSessions.add(pathToOpen) } let restoredState = false - if (foldersToAddToProject.length > 0) { - const state = await this.loadState(this.getStateKey(foldersToAddToProject)) + if (foldersToAddToProject.size > 0 || missingFolders.length > 0) { + // Include missing folders in the state key so that sessions restored with no-longer-present project root folders + // don't lose data. + const foldersForStateKey = Array.from(foldersToAddToProject) + .concat(missingFolders.map(location => location.pathToOpen)) + const state = await this.loadState(this.getStateKey(Array.from(foldersForStateKey))) // only restore state if this is the first path added to the project if (state && needsProjectPaths) { const files = fileLocationsToOpen.map((location) => location.pathToOpen) - await this.attemptRestoreProjectStateForPaths(state, foldersToAddToProject, files) + await this.attemptRestoreProjectStateForPaths(state, Array.from(foldersToAddToProject), files) restoredState = true } else { for (let folder of foldersToAddToProject) { @@ -1410,6 +1443,33 @@ or use Pane::saveItemAs for programmatic saving.`) await Promise.all(fileOpenPromises) } + if (missingFolders.length > 0) { + let message = 'Unable to open project folder' + if (missingFolders.length > 1) { + message += 's' + } + + let description = 'The ' + if (missingFolders.length === 1) { + description += 'directory `' + description += missingFolders[0].pathToOpen + description += '` does not exist.' + } else if (missingFolders.length === 2) { + description += `directories \`${missingFolders[0].pathToOpen}\` ` + description += `and \`${missingFolders[1].pathToOpen}\` do not exist.` + } else { + description += 'directories ' + description += (missingFolders + .slice(0, -1) + .map(location => location.pathToOpen) + .map(pathToOpen => '`' + pathToOpen + '`, ') + .join('')) + description += 'and `' + missingFolders[missingFolders.length - 1].pathToOpen + '` do not exist.' + } + + this.notifications.addWarning(message, {description}) + } + ipcRenderer.send('window-command', 'window:locations-opened') } diff --git a/src/compile-cache.js b/src/compile-cache.js index ea387a631..f1f596e86 100644 --- a/src/compile-cache.js +++ b/src/compile-cache.js @@ -177,7 +177,7 @@ exports.install = function (resourcesPath, nodeRequire) { var rawData = sourceMappingURL.slice(sourceMappingURL.indexOf(',') + 1) try { - var sourceMap = JSON.parse(new Buffer(rawData, 'base64')) + var sourceMap = JSON.parse(Buffer.from(rawData, 'base64')) } catch (error) { console.warn('Error parsing source map', error.stack) return null diff --git a/src/decoration.js b/src/decoration.js index 69bbcaa19..989e48588 100644 --- a/src/decoration.js +++ b/src/decoration.js @@ -3,12 +3,17 @@ const {Emitter} = require('event-kit') let idCounter = 0 const nextId = () => idCounter++ -// Applies changes to a decorationsParam {Object} to make it possible to -// differentiate decorations on custom gutters versus the line-number gutter. -const translateDecorationParamsOldToNew = function (decorationParams) { - if (decorationParams.type === 'line-number') { +const normalizeDecorationProperties = function (decoration, decorationParams) { + decorationParams.id = decoration.id + + if (decorationParams.type === 'line-number' && decorationParams.gutterName == null) { decorationParams.gutterName = 'line-number' } + + if (decorationParams.order == null) { + decorationParams.order = Infinity + } + return decorationParams } @@ -164,7 +169,7 @@ class Decoration { setProperties (newProperties) { if (this.destroyed) { return } const oldProperties = this.properties - this.properties = translateDecorationParamsOldToNew(newProperties) + this.properties = normalizeDecorationProperties(this, newProperties) if (newProperties.type != null) { this.decorationManager.decorationDidChangeType(this) } diff --git a/src/file-system-blob-store.js b/src/file-system-blob-store.js index 67a959735..81e4a6f39 100644 --- a/src/file-system-blob-store.js +++ b/src/file-system-blob-store.js @@ -20,7 +20,7 @@ class FileSystemBlobStore { reset () { this.inMemoryBlobs = new Map() - this.storedBlob = new Buffer(0) + this.storedBlob = Buffer.alloc(0) this.storedBlobMap = {} this.usedKeys = new Set() } diff --git a/src/main-process/atom-application.js b/src/main-process/atom-application.js index c10895650..f6ada6137 100644 --- a/src/main-process/atom-application.js +++ b/src/main-process/atom-application.js @@ -187,6 +187,8 @@ class AtomApplication extends EventEmitter { (options.urlsToOpen && options.urlsToOpen.length > 0)) { optionsForWindowsToOpen.push(options) shouldReopenPreviousWindows = this.config.get('core.restorePreviousWindowsOnStart') === 'always' + } else if (options.newWindow) { + shouldReopenPreviousWindows = false } else { shouldReopenPreviousWindows = this.config.get('core.restorePreviousWindowsOnStart') !== 'no' } @@ -206,9 +208,9 @@ class AtomApplication extends EventEmitter { openWithOptions (options) { const { - initialPaths, pathsToOpen, executedFrom, + foldersToOpen, urlsToOpen, benchmark, benchmarkTest, @@ -216,7 +218,6 @@ class AtomApplication extends EventEmitter { pidToKillWhenClosed, devMode, safeMode, - newWindow, logFile, profileStartup, timeout, @@ -248,13 +249,12 @@ class AtomApplication extends EventEmitter { timeout, env }) - } else if (pathsToOpen.length > 0) { + } else if ((pathsToOpen && pathsToOpen.length > 0) || (foldersToOpen && foldersToOpen.length > 0)) { return this.openPaths({ - initialPaths, pathsToOpen, + foldersToOpen, executedFrom, pidToKillWhenClosed, - newWindow, devMode, safeMode, profileStartup, @@ -267,9 +267,7 @@ class AtomApplication extends EventEmitter { } else { // Always open a editor window if this is the first instance of Atom. return this.openPath({ - initialPaths, pidToKillWhenClosed, - newWindow, devMode, safeMode, profileStartup, @@ -576,7 +574,7 @@ class AtomApplication extends EventEmitter { this.disposable.add(ipcHelpers.respondTo('set-user-settings', (window, settings, filePath) => { if (!this.quitting) { - ConfigFile.at(filePath || this.configFilePath).update(JSON.parse(settings)) + return ConfigFile.at(filePath || this.configFilePath).update(JSON.parse(settings)) } })) @@ -777,17 +775,14 @@ class AtomApplication extends EventEmitter { // options - // :pathToOpen - The file path to open // :pidToKillWhenClosed - The integer of the pid to kill - // :newWindow - Boolean of whether this should be opened in a new window. // :devMode - Boolean to control the opened window's dev mode. // :safeMode - Boolean to control the opened window's safe mode. // :profileStartup - Boolean to control creating a profile of the startup time. // :window - {AtomWindow} to open file paths in. // :addToLastWindow - Boolean of whether this should be opened in last focused window. openPath ({ - initialPaths, pathToOpen, pidToKillWhenClosed, - newWindow, devMode, safeMode, profileStartup, @@ -797,10 +792,8 @@ class AtomApplication extends EventEmitter { env } = {}) { return this.openPaths({ - initialPaths, pathsToOpen: [pathToOpen], pidToKillWhenClosed, - newWindow, devMode, safeMode, profileStartup, @@ -815,19 +808,18 @@ class AtomApplication extends EventEmitter { // // options - // :pathsToOpen - The array of file paths to open + // :foldersToOpen - An array of additional paths to open that must be existing directories // :pidToKillWhenClosed - The integer of the pid to kill - // :newWindow - Boolean of whether this should be opened in a new window. // :devMode - Boolean to control the opened window's dev mode. // :safeMode - Boolean to control the opened window's safe mode. // :windowDimensions - Object with height and width keys. // :window - {AtomWindow} to open file paths in. // :addToLastWindow - Boolean of whether this should be opened in last focused window. openPaths ({ - initialPaths, pathsToOpen, + foldersToOpen, executedFrom, pidToKillWhenClosed, - newWindow, devMode, safeMode, windowDimensions, @@ -837,32 +829,45 @@ class AtomApplication extends EventEmitter { addToLastWindow, env } = {}) { - if (!pathsToOpen || pathsToOpen.length === 0) return if (!env) env = process.env + if (!pathsToOpen) pathsToOpen = [] + if (!foldersToOpen) foldersToOpen = [] + devMode = Boolean(devMode) safeMode = Boolean(safeMode) clearWindowState = Boolean(clearWindowState) - const locationsToOpen = [] - for (let i = 0; i < pathsToOpen.length; i++) { - const location = this.parsePathToOpen(pathsToOpen[i], executedFrom, addToLastWindow) - location.forceAddToWindow = addToLastWindow - location.hasWaitSession = pidToKillWhenClosed != null - locationsToOpen.push(location) - pathsToOpen[i] = location.pathToOpen + const locationsToOpen = pathsToOpen.map(pathToOpen => { + return this.parsePathToOpen(pathToOpen, executedFrom, { + forceAddToWindow: addToLastWindow, + hasWaitSession: pidToKillWhenClosed != null + }) + }) + + for (const folderToOpen of foldersToOpen) { + locationsToOpen.push({ + pathToOpen: folderToOpen, + initialLine: null, + initialColumn: null, + mustBeDirectory: true, + forceAddToWindow: addToLastWindow, + hasWaitSession: pidToKillWhenClosed != null + }) } + if (locationsToOpen.length === 0) { + return + } + + const normalizedPathsToOpen = locationsToOpen.map(location => location.pathToOpen).filter(Boolean) + let existingWindow - if (!newWindow) { - existingWindow = this.windowForPaths(pathsToOpen, devMode) + if (addToLastWindow && normalizedPathsToOpen.length > 0) { + existingWindow = this.windowForPaths(normalizedPathsToOpen, devMode) if (!existingWindow) { let lastWindow = window || this.getLastFocusedWindow() if (lastWindow && lastWindow.devMode === devMode) { - if (addToLastWindow || ( - locationsToOpen.every(({stat}) => stat && stat.isFile()) || - (locationsToOpen.some(({stat}) => stat && stat.isDirectory()) && !lastWindow.hasProjectPath()))) { - existingWindow = lastWindow - } + existingWindow = lastWindow } } } @@ -895,7 +900,6 @@ class AtomApplication extends EventEmitter { if (!windowDimensions) windowDimensions = this.getDimensionsForNewWindow() openedWindow = new AtomWindow(this, this.fileRecoveryService, { - initialPaths, locationsToOpen, windowInitializationScript, resourcePath, @@ -916,7 +920,7 @@ class AtomApplication extends EventEmitter { } this.waitSessionsByWindow.get(openedWindow).push({ pid: pidToKillWhenClosed, - remainingPaths: new Set(pathsToOpen) + remainingPaths: new Set(normalizedPathsToOpen) }) } @@ -984,8 +988,7 @@ class AtomApplication extends EventEmitter { const states = await this.storageFolder.load('application.json') if (states) { return states.map(state => ({ - initialPaths: state.initialPaths, - pathsToOpen: state.initialPaths.filter(p => fs.isDirectorySync(p)), + foldersToOpen: state.initialPaths, urlsToOpen: [], devMode: this.devMode, safeMode: this.safeMode @@ -1264,7 +1267,7 @@ class AtomApplication extends EventEmitter { } } - parsePathToOpen (pathToOpen, executedFrom = '') { + parsePathToOpen (pathToOpen, executedFrom, extra) { let initialColumn, initialLine if (!pathToOpen) { return {pathToOpen} @@ -1286,10 +1289,9 @@ class AtomApplication extends EventEmitter { } const normalizedPath = path.normalize(path.resolve(executedFrom, fs.normalize(pathToOpen))) - const stat = fs.statSyncNoException(normalizedPath) - if (stat || !url.parse(pathToOpen).protocol) pathToOpen = normalizedPath + if (!url.parse(pathToOpen).protocol) pathToOpen = normalizedPath - return {pathToOpen, stat, initialLine, initialColumn} + return Object.assign({pathToOpen, initialLine, initialColumn}, extra) } // Opens a native dialog to prompt the user for a path. diff --git a/src/main-process/atom-window.js b/src/main-process/atom-window.js index a56679143..d7f480f16 100644 --- a/src/main-process/atom-window.js +++ b/src/main-process/atom-window.js @@ -23,9 +23,7 @@ class AtomWindow extends EventEmitter { this.devMode = settings.devMode this.resourcePath = settings.resourcePath - let {pathToOpen, locationsToOpen} = settings - if (!locationsToOpen && pathToOpen) locationsToOpen = [{pathToOpen}] - if (!locationsToOpen) locationsToOpen = [] + const locationsToOpen = settings.locationsToOpen || [] this.loadedPromise = new Promise(resolve => { this.resolveLoadedPromise = resolve }) this.closedPromise = new Promise(resolve => { this.resolveClosedPromise = resolve }) @@ -73,23 +71,7 @@ class AtomWindow extends EventEmitter { if (this.loadSettings.safeMode == null) this.loadSettings.safeMode = false if (this.loadSettings.clearWindowState == null) this.loadSettings.clearWindowState = false - if (!this.loadSettings.initialPaths) { - this.loadSettings.initialPaths = [] - for (const {pathToOpen, stat} of locationsToOpen) { - if (!pathToOpen) continue - if (stat && stat.isDirectory()) { - this.loadSettings.initialPaths.push(pathToOpen) - } else { - const parentDirectory = path.dirname(pathToOpen) - if (stat && stat.isFile() || fs.existsSync(parentDirectory)) { - this.loadSettings.initialPaths.push(parentDirectory) - } else { - this.loadSettings.initialPaths.push(pathToOpen) - } - } - } - } - + this.loadSettings.initialPaths = locationsToOpen.map(location => location.pathToOpen).filter(Boolean) this.loadSettings.initialPaths.sort() // Only send to the first non-spec window created diff --git a/src/main-process/auto-updater-win32.js b/src/main-process/auto-updater-win32.js index 062d290b9..053ef040d 100644 --- a/src/main-process/auto-updater-win32.js +++ b/src/main-process/auto-updater-win32.js @@ -39,7 +39,7 @@ class AutoUpdater extends EventEmitter { } supportsUpdates () { - SquirrelUpdate.existsSync() + return SquirrelUpdate.existsSync() } checkForUpdates () { diff --git a/src/main-process/parse-command-line.js b/src/main-process/parse-command-line.js index 5d7849eac..3aa019565 100644 --- a/src/main-process/parse-command-line.js +++ b/src/main-process/parse-command-line.js @@ -11,16 +11,20 @@ module.exports = function parseCommandLine (processArgs) { dedent`Atom Editor v${version} Usage: + atom atom [options] [path ...] atom file[:line[:column]] - One or more paths to files or folders may be specified. If there is an - existing Atom window that contains all of the given folders, the paths - will be opened in that window. Otherwise, they will be opened in a new - window. + If no arguments are given and no Atom windows are already open, restore all windows + from the previous editing session. Use "atom --new-window" to open a single empty + Atom window instead. - A file may be opened at the desired line (and optionally column) by - appending the numbers right after the file name, e.g. \`atom file:5:8\`. + If no arguments are given and at least one Atom window is open, open a new, empty + Atom window. + + One or more paths to files or folders may be specified. All paths will be opened + in a new Atom window. Each file may be opened at the desired line (and optionally + column) by appending the numbers after the file name, e.g. \`atom file:5:8\`. Paths that start with \`atom://\` will be interpreted as URLs. @@ -39,7 +43,7 @@ module.exports = function parseCommandLine (processArgs) { options.alias('f', 'foreground').boolean('f').describe('f', 'Keep the main process in the foreground.') options.alias('h', 'help').boolean('h').describe('h', 'Print this usage message.') options.alias('l', 'log-file').string('l').describe('l', 'Log all output to file.') - options.alias('n', 'new-window').boolean('n').describe('n', 'Open a new window.') + options.alias('n', 'new-window').boolean('n').describe('n', 'Launch an empty Atom window instead of restoring previous session.') options.boolean('profile-startup').describe('profile-startup', 'Create a profile of the startup execution time.') options.alias('r', 'resource-path').string('r').describe('r', 'Set the path to the Atom source directory and enable dev-mode.') options.boolean('safe').describe( diff --git a/src/native-compile-cache.js b/src/native-compile-cache.js index cc947e84b..d8211b9f4 100644 --- a/src/native-compile-cache.js +++ b/src/native-compile-cache.js @@ -1,7 +1,7 @@ const Module = require('module') const path = require('path') -const cachedVm = require('cached-run-in-this-context') const crypto = require('crypto') +const vm = require('vm') function computeHash (contents) { return crypto.createHash('sha1').update(contents, 'utf8').digest('hex') @@ -34,6 +34,24 @@ class NativeCompileCache { this.previousModuleCompile = Module.prototype._compile } + runInThisContext (code, filename) { + // produceCachedData is deprecated after Node 10.6, will need to update + // this for Electron 4.0 to use script.createCachedData() + const script = new vm.Script(code, {filename, produceCachedData: true}) + return { + result: script.runInThisContext(), + cacheBuffer: script.cachedData + } + } + + runInThisContextCached (code, filename, cachedData) { + const script = new vm.Script(code, {filename, cachedData}) + return { + result: script.runInThisContext(), + wasRejected: script.cachedDataRejected + } + } + overrideModuleCompile () { let self = this // Here we override Node's module.js @@ -64,7 +82,7 @@ class NativeCompileCache { let compiledWrapper = null if (self.cacheStore.has(cacheKey)) { let buffer = self.cacheStore.get(cacheKey) - let compilationResult = cachedVm.runInThisContextCached(wrapper, filename, buffer) + let compilationResult = self.runInThisContextCached(wrapper, filename, buffer) compiledWrapper = compilationResult.result if (compilationResult.wasRejected) { self.cacheStore.delete(cacheKey) @@ -72,12 +90,12 @@ class NativeCompileCache { } else { let compilationResult try { - compilationResult = cachedVm.runInThisContext(wrapper, filename) + compilationResult = self.runInThisContext(wrapper, filename) } catch (err) { console.error(`Error running script ${filename}`) throw err } - if (compilationResult.cacheBuffer) { + if (compilationResult.cacheBuffer !== null) { self.cacheStore.set(cacheKey, compilationResult.cacheBuffer) } compiledWrapper = compilationResult.result diff --git a/src/pane-container.js b/src/pane-container.js index b14d6ea57..1185d7a9c 100644 --- a/src/pane-container.js +++ b/src/pane-container.js @@ -282,7 +282,7 @@ class PaneContainer { this.cancelStoppedChangingActivePaneItemTimeout() // `setTimeout()` isn't available during the snapshotting phase, but that's okay. - if (typeof setTimeout === 'function') { + if (!global.isGeneratingSnapshot) { this.stoppedChangingActivePaneItemTimeout = setTimeout(() => { this.stoppedChangingActivePaneItemTimeout = null this.emitter.emit('did-stop-changing-active-pane-item', activeItem) diff --git a/src/project.js b/src/project.js index 8ccf60c0b..3ceaa5cff 100644 --- a/src/project.js +++ b/src/project.js @@ -204,11 +204,11 @@ class Project extends Model { // // absolute path to the filesystem entry that was touched // console.log(`Event path: ${event.path}`) // - // if (event.type === 'renamed') { + // if (event.action === 'renamed') { // console.log(`.. renamed from: ${event.oldPath}`) // } // } - // } + // }) // // disposable.dispose() // ``` @@ -441,14 +441,20 @@ class Project extends Model { } } - getDirectoryForProjectPath (projectPath) { - let directory = null + getProvidedDirectoryForProjectPath (projectPath) { for (let provider of this.directoryProviders) { if (typeof provider.directoryForURISync === 'function') { - directory = provider.directoryForURISync(projectPath) - if (directory) break + const directory = provider.directoryForURISync(projectPath) + if (directory) { + return directory + } } } + return null + } + + getDirectoryForProjectPath (projectPath) { + let directory = this.getProvidedDirectoryForProjectPath(projectPath) if (directory == null) { directory = this.defaultDirectoryProvider.directoryForURISync(projectPath) } diff --git a/src/task.coffee b/src/task.coffee index fa09c69f1..05d61f5a7 100644 --- a/src/task.coffee +++ b/src/task.coffee @@ -84,17 +84,17 @@ class Task # Routes messages from the child to the appropriate event. handleEvents: -> - @childProcess.removeAllListeners() + @childProcess.removeAllListeners('message') @childProcess.on 'message', ({event, args}) => @emitter.emit(event, args) if @childProcess? # Catch the errors that happened before task-bootstrap. if @childProcess.stdout? - @childProcess.stdout.removeAllListeners() + @childProcess.stdout.removeAllListeners('data') @childProcess.stdout.on 'data', (data) -> console.log data.toString() if @childProcess.stderr? - @childProcess.stderr.removeAllListeners() + @childProcess.stderr.removeAllListeners('data') @childProcess.stderr.on 'data', (data) -> console.error data.toString() # Public: Starts the task. @@ -147,9 +147,9 @@ class Task terminate: -> return false unless @childProcess? - @childProcess.removeAllListeners() - @childProcess.stdout?.removeAllListeners() - @childProcess.stderr?.removeAllListeners() + @childProcess.removeAllListeners('message') + @childProcess.stdout?.removeAllListeners('data') + @childProcess.stderr?.removeAllListeners('data') @childProcess.kill() @childProcess = null diff --git a/src/text-editor-component.js b/src/text-editor-component.js index 1e5f1f260..9da3db137 100644 --- a/src/text-editor-component.js +++ b/src/text-editor-component.js @@ -1191,6 +1191,10 @@ class TextEditorComponent { decorationsByScreenLine.set(screenLine.id, decorations) } decorations.push(decoration) + + // Order block decorations by increasing values of their "order" property. Break ties with "id", which mirrors + // their creation sequence. + decorations.sort((a, b) => a.order !== b.order ? a.order - b.order : a.id - b.id) } addTextDecorationToRender (decoration, screenRange, marker) { @@ -3862,15 +3866,24 @@ class LinesTileComponent { if (blockDecorations) { blockDecorations.forEach((newDecorations, screenLineId) => { - var oldDecorations = oldProps.blockDecorations ? oldProps.blockDecorations.get(screenLineId) : null - for (var i = 0; i < newDecorations.length; i++) { - var newDecoration = newDecorations[i] - if (oldDecorations && oldDecorations.includes(newDecoration)) continue + const oldDecorations = oldProps.blockDecorations ? oldProps.blockDecorations.get(screenLineId) : null + const lineNode = lineComponentsByScreenLineId.get(screenLineId).element + let lastAfter = lineNode + + for (let i = 0; i < newDecorations.length; i++) { + const newDecoration = newDecorations[i] + const element = TextEditor.viewForItem(newDecoration.item) + + if (oldDecorations && oldDecorations.includes(newDecoration)) { + if (newDecoration.position === 'after') { + lastAfter = element + } + continue + } - var element = TextEditor.viewForItem(newDecoration.item) - var lineNode = lineComponentsByScreenLineId.get(screenLineId).element if (newDecoration.position === 'after') { - this.element.insertBefore(element, lineNode.nextSibling) + this.element.insertBefore(element, lastAfter.nextSibling) + lastAfter = element } else { this.element.insertBefore(element, lineNode) } @@ -4433,7 +4446,7 @@ class NodePool { if (element) { element.className = className || '' - element.styleMap.forEach((value, key) => { + element.attributeStyleMap.forEach((value, key) => { if (!style || style[key] == null) element.style[key] = '' }) if (style) Object.assign(element.style, style) diff --git a/src/text-editor.js b/src/text-editor.js index abdbb9c51..fe14e562c 100644 --- a/src/text-editor.js +++ b/src/text-editor.js @@ -959,9 +959,6 @@ class TextEditor { return this.decorationManager.onDidUpdateDecorations(callback) } - // Essential: Retrieves the current {TextBuffer}. - getBuffer () { return this.buffer } - // Retrieves the current buffer's URI. getURI () { return this.buffer.getUri() } @@ -1076,6 +1073,15 @@ class TextEditor { } } + /* + Section: Buffer + */ + + // Essential: Retrieves the current {TextBuffer}. + getBuffer () { + return this.buffer + } + /* Section: File Details */ @@ -2215,14 +2221,17 @@ class TextEditor { // // The following are the supported decorations types: // - // * __line__: Adds your CSS `class` to the line nodes within the range - // marked by the marker - // * __line-number__: Adds your CSS `class` to the line number nodes within the - // range marked by the marker - // * __highlight__: Adds a new highlight div to the editor surrounding the - // range marked by the marker. When the user selects text, the selection is - // visualized with a highlight decoration internally. The structure of this - // highlight will be + // * __line__: Adds the given CSS `class` to the lines overlapping the rows + // spanned by the marker. + // * __line-number__: Adds the given CSS `class` to the line numbers overlapping + // the rows spanned by the marker + // * __text__: Injects spans into all text overlapping the marked range, then adds + // the given `class` or `style` to these spans. Use this to manipulate the foreground + // color or styling of text in a range. + // * __highlight__: Creates an absolutely-positioned `.highlight` div to the editor + // containing nested divs that cover the marked region. For example, when the user + // selects text, the selection is implemented with a highlight decoration. The structure + // of this highlight will be: // ```html //
// @@ -2230,45 +2239,25 @@ class TextEditor { //
// ``` // * __overlay__: Positions the view associated with the given item at the head - // or tail of the given `DisplayMarker`. - // * __gutter__: A decoration that tracks a {DisplayMarker} in a {Gutter}. Gutter - // decorations are created by calling {Gutter::decorateMarker} on the - // desired `Gutter` instance. + // or tail of the given `DisplayMarker`, depending on the `position` property. + // * __gutter__: Tracks a {DisplayMarker} in a {Gutter}. Gutter decorations are created + // by calling {Gutter::decorateMarker} on the desired `Gutter` instance. // * __block__: Positions the view associated with the given item before or - // after the row of the given `TextEditorMarker`. + // after the row of the given {DisplayMarker}, depending on the `position` property. + // Block decorations at the same screen row are ordered by their `order` property. + // * __cursor__: Render a cursor at the head of the {DisplayMarker}. If multiple cursor decorations + // are created for the same marker, their class strings and style objects are combined + // into a single cursor. This decoration type may be used to style existing cursors + // by passing in their markers or to render artificial cursors that don't actaully + // exist in the model by passing a marker that isn't associated with a real cursor. // // ## Arguments // // * `marker` A {DisplayMarker} you want this decoration to follow. // * `decorationParams` An {Object} representing the decoration e.g. // `{type: 'line-number', class: 'linter-error'}` - // * `type` There are several supported decoration types. The behavior of the - // types are as follows: - // * `line` Adds the given `class` to the lines overlapping the rows - // spanned by the `DisplayMarker`. - // * `line-number` Adds the given `class` to the line numbers overlapping - // the rows spanned by the `DisplayMarker`. - // * `text` Injects spans into all text overlapping the marked range, - // then adds the given `class` or `style` properties to these spans. - // Use this to manipulate the foreground color or styling of text in - // a given range. - // * `highlight` Creates an absolutely-positioned `.highlight` div - // containing nested divs to cover the marked region. For example, this - // is used to implement selections. - // * `overlay` Positions the view associated with the given item at the - // head or tail of the given `DisplayMarker`, depending on the `position` - // property. - // * `gutter` Tracks a {DisplayMarker} in a {Gutter}. Created by calling - // {Gutter::decorateMarker} on the desired `Gutter` instance. - // * `block` Positions the view associated with the given item before or - // after the row of the given `TextEditorMarker`, depending on the `position` - // property. - // * `cursor` Renders a cursor at the head of the given marker. If multiple - // decorations are created for the same marker, their class strings and - // style objects are combined into a single cursor. You can use this - // decoration type to style existing cursors by passing in their markers - // or render artificial cursors that don't actually exist in the model - // by passing a marker that isn't actually associated with a cursor. + // * `type` Determines the behavior and appearance of this {Decoration}. Supported decoration types + // and their uses are listed above. // * `class` This CSS class will be applied to the decorated line number, // line, text spans, highlight regions, cursors, or overlay. // * `style` An {Object} containing CSS style properties to apply to the @@ -2294,12 +2283,15 @@ class TextEditor { // Controls where the view is positioned relative to the `TextEditorMarker`. // Values can be `'head'` (the default) or `'tail'` for overlay decorations, and // `'before'` (the default) or `'after'` for block decorations. + // * `order` (optional) Only applicable to decorations of type `block`. Controls + // where the view is positioned relative to other block decorations at the + // same screen row. If unspecified, block decorations render oldest to newest. // * `avoidOverflow` (optional) Only applicable to decorations of type // `overlay`. Determines whether the decoration adjusts its horizontal or // vertical position to remain fully visible when it would otherwise // overflow the editor. Defaults to `true`. // - // Returns a {Decoration} object + // Returns the created {Decoration} object. decorateMarker (marker, decorationParams) { return this.decorationManager.decorateMarker(marker, decorationParams) } diff --git a/src/tooltip-manager.js b/src/tooltip-manager.js index d2d42763d..d5fb8b0c0 100644 --- a/src/tooltip-manager.js +++ b/src/tooltip-manager.js @@ -10,7 +10,7 @@ let Tooltip = null // // The essence of displaying a tooltip // -// ```javascript +// ```js // // display it // const disposable = atom.tooltips.add(div, {title: 'This is a tooltip'}) // @@ -21,7 +21,7 @@ let Tooltip = null // In practice there are usually multiple tooltips. So we add them to a // CompositeDisposable // -// ```javascript +// ```js // const {CompositeDisposable} = require('atom') // const subscriptions = new CompositeDisposable() // @@ -37,7 +37,7 @@ let Tooltip = null // You can display a key binding in the tooltip as well with the // `keyBindingCommand` option. // -// ```javascript +// ```js // disposable = atom.tooltips.add(this.caseOptionButton, { // title: 'Match Case', // keyBindingCommand: 'find-and-replace:toggle-case-option', diff --git a/src/tree-sitter-language-mode.js b/src/tree-sitter-language-mode.js index c6b5a85ee..3b40f489f 100644 --- a/src/tree-sitter-language-mode.js +++ b/src/tree-sitter-language-mode.js @@ -94,7 +94,7 @@ class TreeSitterLanguageMode { } } - bufferDidFinishTransaction (changes) { + bufferDidFinishTransaction ({changes}) { for (let i = 0, {length} = changes; i < length; i++) { const {oldRange, newRange} = changes[i] spliceArray( diff --git a/static/atom-ui/README.md b/static/atom-ui/README.md new file mode 100644 index 000000000..b3c02c7df --- /dev/null +++ b/static/atom-ui/README.md @@ -0,0 +1,13 @@ +# :sparkles: Atom UI :sparkles: + +This is Atom's UI library. Originally forked from Bootstrap `3.3.6`, then merged with some core styles and now tweaked to Atom's needy needs. + +## Components + +Here a list of [all components](atom-ui.less). Open the [Styleguide](https://github.com/atom/styleguide) package (`cmd-ctrl-shift-g`) to see them in action and how to use them. + +![Styleguide](https://cloud.githubusercontent.com/assets/378023/15767543/ccecf9bc-2983-11e6-9c5e-d228d39f52b0.png) + +## Feature requests + +If you need something, feel free to open an issue and it might can be added. :v: diff --git a/static/atom-ui/_index.less b/static/atom-ui/_index.less new file mode 100644 index 000000000..4a1db024b --- /dev/null +++ b/static/atom-ui/_index.less @@ -0,0 +1,35 @@ +// Atom UI + +// Private! Don't use these in packages. +// If you need something, feel free to open an issue and it might can be made public +@import "styles/private/scaffolding.less"; + +@import "styles/private/alerts.less"; +@import "styles/private/close.less"; +@import "styles/private/code.less"; +@import "styles/private/forms.less"; +@import "styles/private/links.less"; +@import "styles/private/navs.less"; +@import "styles/private/sections.less"; +@import "styles/private/tables.less"; +@import "styles/private/utilities.less"; + + +// Public components +// Open the Styleguide to see them in action +@import "styles/badges.less"; +@import "styles/button-groups.less"; +@import "styles/buttons.less"; +@import "styles/git-status.less"; +@import "styles/icons.less"; +@import "styles/inputs.less"; +@import "styles/layout.less"; +@import "styles/lists.less"; +@import "styles/loading.less"; +@import "styles/messages.less"; +@import "styles/modals.less"; +@import "styles/panels.less"; +@import "styles/select-list.less"; +@import "styles/site-colors.less"; +@import "styles/text.less"; +@import "styles/tooltip.less"; diff --git a/static/atom-ui/styles/badges.less b/static/atom-ui/styles/badges.less new file mode 100644 index 000000000..048113d89 --- /dev/null +++ b/static/atom-ui/styles/badges.less @@ -0,0 +1,64 @@ +@import "ui-variables"; + +.badge { + display: inline-block; + line-height: 1; + vertical-align: middle; + font-weight: normal; + text-align: center; + white-space: nowrap; + border-radius: 1em; + + &:empty { + display: none; // Hide when un-used + } + + + // Color ---------------------- + + .badge-color( @fg: @text-color-selected; @bg: @background-color-selected; ) { + color: @fg; + background-color: @bg; + } + .badge-color(); + &.badge-info { .badge-color(white, @background-color-info); } + &.badge-success { .badge-color(white, @background-color-success); } + &.badge-warning { .badge-color(white, @background-color-warning); } + &.badge-error { .badge-color(white, @background-color-error); } + + + // Size ---------------------- + + .badge-size( @size: @font-size; ) { + @padding: round(@size/4); + font-size: @size; + min-width: @size + @padding*2; + padding: @padding round(@padding*1.5); + } + .badge-size(); // default + + // Fixed size + &.badge-large { .badge-size(18px); } + &.badge-medium { .badge-size(14px); } + &.badge-small { .badge-size(10px); } + + // Flexible size + // The size changes depending on the parent element + // Best used for larger sizes, since em's can cause rounding errors + &.badge-flexible { + @size: .8em; + @padding: @size/2; + font-size: @size; + min-width: @size + @padding*2; + padding: @padding @padding*1.5; + } + + + // Icon ---------------------- + + &.icon { + font-size: round(@component-icon-size*0.8); + padding: @component-icon-padding @component-icon-padding*2; + } + +} diff --git a/static/atom-ui/styles/button-groups.less b/static/atom-ui/styles/button-groups.less new file mode 100644 index 000000000..430522071 --- /dev/null +++ b/static/atom-ui/styles/button-groups.less @@ -0,0 +1,187 @@ +@import "variables/variables"; +@import "ui-variables"; +@import "mixins/mixins"; + +// +// Button groups +// -------------------------------------------------- + +// Make the div behave like a button +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-block; + vertical-align: middle; // match .btn alignment given font-size hack above + > .btn { + position: relative; + float: left; + // Bring the "active" button to the front + &:hover, + &:focus, + &:active, + &.active { + z-index: 2; + } + } +} + + +// Borders +// --------------------------------------------------------- + +.btn-group > .btn { + border-left: 1px solid @button-border-color; + border-right: 1px solid @button-border-color; +} +.btn-group > .btn:first-child { + border-left: none; + border-top-left-radius: @component-border-radius; + border-bottom-left-radius: @component-border-radius; +} +.btn-group > .btn:last-child, +.btn-group > .btn.selected:last-child, +.btn-group > .dropdown-toggle { + border-right: none; + border-top-right-radius: @component-border-radius; + border-bottom-right-radius: @component-border-radius; +} + +// Prevent double borders when buttons are next to each other +.btn-group { + .btn + .btn, + .btn + .btn-group, + .btn-group + .btn, + .btn-group + .btn-group { + margin-left: -1px; + } +} + +// Optional: Group multiple button groups together for a toolbar +.btn-toolbar { + margin-left: -5px; // Offset the first child's margin + &:extend(.clearfix all); + + .btn, + .btn-group, + .input-group { + float: left; + } + > .btn, + > .btn-group, + > .input-group { + margin-left: 5px; + } +} + +.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { + border-radius: 0; +} + +// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match +.btn-group > .btn:first-child { + margin-left: 0; + &:not(:last-child):not(.dropdown-toggle) { + .border-right-radius(0); + } +} +// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + .border-left-radius(0); +} + +// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group) +.btn-group > .btn-group { + float: left; +} +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child:not(:last-child) { + > .btn:last-child, + > .dropdown-toggle { + .border-right-radius(0); + } +} +.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child { + .border-left-radius(0); +} + +// On active and open, don't show outline +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + + +// Sizing +// +// Remix the default button sizing classes into new ones for easier manipulation. + +.btn-group-xs > .btn { &:extend(.btn-xs); } +.btn-group-sm > .btn { &:extend(.btn-sm); } +.btn-group-lg > .btn { &:extend(.btn-lg); } + + +// Split button dropdowns +// ---------------------- + +// Give the line between buttons some depth +.btn-group > .btn + .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; +} +.btn-group > .btn-lg + .dropdown-toggle { + padding-left: 12px; + padding-right: 12px; +} + +// The clickable button for toggling the menu +// Remove the gradient and set the same inset shadow as the :active state +.btn-group.open .dropdown-toggle { + box-shadow: inset 0 3px 5px rgba(0,0,0,.125); + + // Show no shadow for `.btn-link` since it has no other button styles. + &.btn-link { + box-shadow: none; + } +} + + +// Reposition the caret +.btn .caret { + margin-left: 0; +} +// Carets in other button sizes +.btn-lg .caret { + border-width: @caret-width-large @caret-width-large 0; + border-bottom-width: 0; +} +// Upside down carets for .dropup +.dropup .btn-lg .caret { + border-width: 0 @caret-width-large @caret-width-large; +} + + +// Justified button groups +// ---------------------- + +.btn-group-justified { + display: table; + width: 100%; + table-layout: fixed; + border-collapse: separate; + > .btn, + > .btn-group { + float: none; + display: table-cell; + width: 1%; + } + > .btn-group .btn { + width: 100%; + } + + > .btn-group .dropdown-menu { + left: auto; + } +} diff --git a/static/atom-ui/styles/buttons.less b/static/atom-ui/styles/buttons.less new file mode 100644 index 000000000..5f5c35d9b --- /dev/null +++ b/static/atom-ui/styles/buttons.less @@ -0,0 +1,274 @@ +@import "variables/variables"; +@import "ui-variables"; +@import "mixins/mixins"; + +// +// Buttons +// -------------------------------------------------- + + +// Base styles +// -------------------------------------------------- + +.btn { + display: inline-block; + margin-bottom: 0; // For input.btn + height: @component-line-height + 2px; + padding: 0 @component-padding; + font-size: @font-size; + font-weight: normal; + line-height: @component-line-height; + text-align: center; + vertical-align: middle; + border: none; + border-radius: @component-border-radius; + background-color: @btn-default-bg; + white-space: nowrap; + cursor: pointer; + z-index: 0; + -webkit-user-select: none; + + &, + &:active, + &.active { + &:focus, + &.focus { + .tab-focus(); + } + } + + &:hover, + &:focus, + &.focus { + color: @btn-default-color; + text-decoration: none; + background-color: @button-background-color-hover; + } + + &:active, + &.active { + outline: 0; + background-image: none; + box-shadow: inset 0 3px 5px rgba(0,0,0,.125); + } + + &.selected, + &.selected:hover { + // we want the selected button to behave like the :hover button; it's on top of the other buttons. + z-index: 1; + color: @text-color-selected; + background-color: @button-background-color-selected; + } + + &.disabled, + &[disabled], + fieldset[disabled] & { + cursor: @cursor-disabled; + opacity: .65; + box-shadow: none; + } + + a& { + &.disabled, + fieldset[disabled] & { + pointer-events: none; // Future-proof disabling of clicks on `` elements + } + } +} + + +// Button variants +// -------------------------------------------------- + +.button-variant(@color; @background;) { + color: @color; + background-color: @background; + + &:focus, + &.focus { + color: @color; + background-color: darken(@background, 10%); + } + &:hover { + color: @color; + background-color: darken(@background, 10%); + } + &:active, + &.active { + color: @color; + background-color: darken(@background, 10%); + + &:hover, + &:focus, + &.focus { + color: @color; + background-color: darken(@background, 17%); + } + } + &.selected, + &.selected:hover { + // we want the selected button to behave like the :hover button; it's on top of the other buttons. + z-index: 1; + background-color: darken(@background, 10%); + } + + &.disabled, + &[disabled], + fieldset[disabled] & { + &:hover, + &:focus, + &.focus { + background-color: @background; + } + } + + .badge { + color: @background; + background-color: @color; + } +} + +.btn-primary { + .button-variant(@btn-primary-color; @btn-primary-bg;); +} +// Success appears as green +.btn-success { + .button-variant(@btn-success-color; @btn-success-bg;); +} +// Info appears as blue-green +.btn-info { + .button-variant(@btn-info-color; @btn-info-bg;); +} +// Warning appears as orange +.btn-warning { + .button-variant(@btn-warning-color; @btn-warning-bg;); +} +// Danger and error appear as red +.btn-error { + .button-variant(@btn-error-color; @btn-error-bg;); +} + + +// Button Sizes +// -------------------------------------------------- + +.btn-xs, +.btn-group-xs > .btn { + padding: @component-padding/4 @component-padding/2; + font-size: @font-size - 2px; + height: auto; + line-height: 1.3em; + &.icon:before { + font-size: @font-size - 2px; + } +} +.btn-sm, +.btn-group-sm > .btn { + padding: @component-padding/4 @component-padding/2; + height: auto; + line-height: 1.3em; + &.icon:before { + font-size: @font-size + 1px; + } +} +.btn-lg, +.btn-group-lg > .btn { + font-size: @font-size + 2px; + padding: @component-padding - 2px @component-padding + 2px; + height: auto; + line-height: 1.3em; + &.icon:before { + font-size: @font-size + 6px; + } +} + + +// Link button +// ------------------------- + +// Make a button look and behave like a link +.btn-link { + color: @link-color; + font-weight: normal; + border-radius: 0; + &, + &:active, + &.active, + &[disabled], + fieldset[disabled] & { + background-color: transparent; + box-shadow: none; + } + &:hover, + &:focus { + color: @link-hover-color; + text-decoration: @link-hover-decoration; + background-color: transparent; + } + &[disabled], + fieldset[disabled] & { + &:hover, + &:focus { + color: @btn-link-disabled-color; + text-decoration: none; + } + } +} + + +// Block button +// -------------------------------------------------- + +.btn-block { + display: block; + width: 100%; +} + +// Vertically space out multiple block buttons +.btn-block + .btn-block { + margin-top: 5px; +} + +// Specificity overrides +input[type="submit"], +input[type="reset"], +input[type="button"] { + &.btn-block { + width: 100%; + } +} + + +// Icon buttons +// -------------------------------------------------- + +.btn.icon { + &:before { + width: initial; + height: initial; + margin-right: .3125em; + } + &:empty:before { + margin-right: 0; + } +} + + +// Button Toolbar +// -------------------------------------------------- + +.btn-toolbar { + > .btn-group + .btn-group, + > .btn-group + .btn, + > .btn + .btn { + float: none; + display: inline-block; + margin-left: 0; + } + > * { + margin-right: @component-padding / 2; + } + > *:last-child { + margin-right: 0; + } +} diff --git a/static/atom-ui/styles/git-status.less b/static/atom-ui/styles/git-status.less new file mode 100644 index 000000000..ead7ed73d --- /dev/null +++ b/static/atom-ui/styles/git-status.less @@ -0,0 +1,13 @@ +@import "ui-variables"; + +// +// Git Status +// -------------------------------------------------- + +.status { + &-ignored { color: @text-color-subtle; } + &-added { color: @text-color-success; } + &-modified { color: @text-color-warning; } + &-removed { color: @text-color-error; } + &-renamed { color: @text-color-info; } +} diff --git a/static/atom-ui/styles/icons.less b/static/atom-ui/styles/icons.less new file mode 100644 index 000000000..993ba28f8 --- /dev/null +++ b/static/atom-ui/styles/icons.less @@ -0,0 +1,13 @@ +@import "ui-variables"; + +.icon::before { + margin-right: @component-icon-padding; +} + +a.icon { + text-decoration: none; + color: @text-color; + &:hover{ + color: @text-color-highlight; + } +} diff --git a/static/atom-ui/styles/inputs.less b/static/atom-ui/styles/inputs.less new file mode 100644 index 000000000..591de55db --- /dev/null +++ b/static/atom-ui/styles/inputs.less @@ -0,0 +1,383 @@ +@import "./variables/ui-variables"; // Fallback for @use-custom-controls +@import "ui-variables"; + +@component-size: @component-icon-size; // use for text-less controls like radio, checkboxes etc. +@component-margin-side: .3em; +@text-component-height: 2em; +@component-background-color: mix(@text-color, @base-background-color, 20%); + + +// +// Overrides +// ------------------------- + +input.input-radio, +input.input-checkbox, +input.input-toggle { + margin-top: 0; // Override Bootstrap's 4px +} +.input-label { + margin-bottom: 0; +} + +// +// Mixins +// ------------------------- + +.input-field-mixin() { + padding: .25em .4em; + line-height: 1.5; // line-height + padding = @text-component-height + border-radius: @component-border-radius; + border: 1px solid @input-border-color; + background-color: @input-background-color; + &::-webkit-input-placeholder { + color: @text-color-subtle; + } + &:invalid { + color: @text-color-error; + border-color: @background-color-error; + } +} + +.input-block-mixin() { + display: block; + width: 100%; +} + + +// +// Checkbox +// ------------------------- + +.input-checkbox { + vertical-align: middle; + + & when (@use-custom-controls) { + -webkit-appearance: none; + display: inline-block; + position: relative; + width: @component-size; + height: @component-size; + font-size: inherit; + border-radius: @component-border-radius; + background-color: @component-background-color; + transition: background-color .16s cubic-bezier(0.5, 0.15, 0.2, 1); + + &&:focus { + outline: 0; // TODO: Add it back + } + &:active { + background-color: @background-color-info; + } + + &:before, + &:after { + content: ""; + position: absolute; + top: @component-size * .75; + left: @component-size * .4; + height: 2px; + border-radius: 1px; + background-color: @base-background-color; + transform-origin: 0 0; + opacity: 0; + transition: transform .1s cubic-bezier(0.5, 0.15, 0.2, 1), opacity .1s cubic-bezier(0.5, 0.15, 0.2, 1); + } + &:before { + width: @component-size * .33; + transform: translate3d(0,0,0) rotate(225deg) scale(0); + } + &:after { + width: @component-size * .66; + margin: -1px; + transform: translate3d(0,0,0) rotate(-45deg) scale(0); + transition-delay: .05s; + } + + &:checked { + background-color: @background-color-info; + &:active { + background-color: @component-background-color; + } + &:before { + opacity: 1; + transform: translate3d(0,0,0) rotate(225deg) scale(1); + transition-delay: .05s; + } + &:after { + opacity: 1; + transform: translate3d(0, 0, 0) rotate(-45deg) scale(1); + transition-delay: 0; + } + } + + &:indeterminate { + background-color: @background-color-info; + &:active { + background-color: @component-background-color; + } + &:after { + opacity: 1; + transform: translate3d(@component-size * -.14, @component-size * -.25, 0) rotate(0deg) scale(1); + transition-delay: 0; + } + } + } +} + + +// +// Color +// ------------------------- + + +.input-color { + vertical-align: middle; + + & when (@use-custom-controls) { + -webkit-appearance: none; + padding: 0; + width: @component-size * 2.5; + height: @component-size * 2.5; + border-radius: 50%; + border: 2px solid @input-border-color; + background-color: @input-background-color; + &::-webkit-color-swatch-wrapper { padding: 0; } + &::-webkit-color-swatch { + border: 1px solid hsla(0,0%,0%,.1); + border-radius: 50%; + transition: transform .16s cubic-bezier(0.5, 0.15, 0.2, 1); + &:active { + transition-duration: 0s; + transform: scale(.9); + } + } + } +} + + + +// +// Label +// ------------------------- + +.input-label { + .input-radio, + .input-checkbox, + .input-toggle { + margin-top: -.25em; // Vertical center (visually) - since most labels are upper case. + margin-right: @component-margin-side; + } +} + + +// +// Number +// ------------------------- + +.input-number { + vertical-align: middle; + + & when (@use-custom-controls) { + .input-field-mixin(); + position: relative; + width: auto; + .platform-darwin & { + padding-right: 1.2em; // space for the spin button + &::-webkit-inner-spin-button { + -webkit-appearance: menulist-button; + position: absolute; + top: 1px; + bottom: 1px; + right: 1px; + width: calc(.6em ~'+' 9px); // magic numbers, OMG! + outline: 1px solid @input-background-color; + outline-offset: -1px; // reduces border radius (that can't be changed) + border-right: .2em solid @background-color-highlight; // a bit more padding + background-color: @background-color-highlight; + transition: transform .16s cubic-bezier(0.5, 0.15, 0.2, 1); + &:active { + transform: scale(.9); + transition-duration: 0s; + } + } + } + } +} + + +// +// Radio +// ------------------------- + +.input-radio { + vertical-align: middle; + + & when (@use-custom-controls) { + -webkit-appearance: none; + display: inline-block; + position: relative; + width: @component-size; + height: @component-size; + font-size: inherit; + border-radius: 50%; + background-color: @component-background-color; + transition: background-color .16s cubic-bezier(0.5, 0.15, 0.2, 1); + + &:before { + content: ""; + position: absolute; + width: inherit; + height: inherit; + border-radius: inherit; + border: @component-size/3 solid transparent; + background-clip: content-box; + background-color: @base-background-color; + transform: scale(0); + transition: transform .1s cubic-bezier(0.5, 0.15, 0.2, 1); + } + &&:focus { + outline: none; + } + &:active { + background-color: @background-color-info; + } + &:checked { + background-color: @background-color-info; + &:before { + transform: scale(1); + } + } + } +} + + +// +// Range (Slider) +// ------------------------- + +.input-range { + & when (@use-custom-controls) { + -webkit-appearance: none; + margin: @component-padding 0; + height: 4px; + border-radius: @component-border-radius; + background-color: @component-background-color; + &::-webkit-slider-thumb { + -webkit-appearance: none; + width: @component-size; + height: @component-size; + border-radius: 50%; + background-color: @background-color-info; + transition: transform .16s; + &:active { + transition-duration: 0s; + transform: scale(.9); + } + } + } +} + + +// +// Search +// ------------------------- + +.input-search { + .input-block-mixin(); + &&::-webkit-search-cancel-button { + -webkit-appearance: searchfield-cancel-button; + } + + & when (@use-custom-controls) { + .input-field-mixin(); + } +} + + +// +// Select +// ------------------------- + +.input-select { + vertical-align: middle; + + & when (@use-custom-controls) { + height: calc(@text-component-height ~'+' 2px); // + 2px? Magic! + border-radius: @component-border-radius; + border: 1px solid @button-border-color; + background-color: @button-background-color; + } +} + + +// +// Text +// ------------------------- + +.input-text { + .input-block-mixin(); + + & when (@use-custom-controls) { + .input-field-mixin(); + } +} + + +// +// Text Area +// ------------------------- + +.input-textarea { + .input-block-mixin(); + + & when (@use-custom-controls) { + .input-field-mixin(); + } +} + + +// +// Toggle +// ------------------------- + +.input-toggle { + & when (@use-custom-controls) { + -webkit-appearance: none; + display: inline-block; + position: relative; + font-size: inherit; + width: @component-size * 2; + height: @component-size; + vertical-align: middle; + border-radius: 2em; + background-color: @component-background-color; + transition: background-color .2s cubic-bezier(0.5, 0.15, 0.2, 1); + + &&:focus { + outline: 0; + } + &:checked { + background-color: @background-color-info; + } + + // Thumb + &:before { + content: ""; + position: absolute; + width: @component-size; + height: @component-size; + border-radius: inherit; + border: @component-size/4 solid transparent; + background-clip: content-box; + background-color: @base-background-color; + transition: transform .2s cubic-bezier(0.5, 0.15, 0.2, 1); + } + &:active:before { + opacity: .5; + } + &:checked:before { + transform: translate3d(100%, 0, 0); + } + } +} diff --git a/static/atom-ui/styles/layout.less b/static/atom-ui/styles/layout.less new file mode 100644 index 000000000..83560fab9 --- /dev/null +++ b/static/atom-ui/styles/layout.less @@ -0,0 +1,85 @@ +@import "ui-variables"; +@import "mixins/mixins"; + +.padded { + padding: @component-padding; +} + +// Blocks + +.center-block { + display: block; + margin-left: auto; + margin-right: auto; +} + +// Must be div.block so as not to affect syntax highlighting. +ul.block, +div.block { + margin-bottom: @component-padding; +} +div > ul.block:last-child, +div > div.block:last-child { + margin-bottom: 0; +} + +// Inline Blocks + +.inline-block, +.inline-block-tight { + display: inline-block; + vertical-align: middle; +} +.inline-block { + margin-right: @component-padding; +} +.inline-block-tight { + margin-right: @component-padding/2; +} +div > .inline-block:last-child, +div > .inline-block-tight:last-child { + margin-right: 0; +} + +.inline-block .inline-block { + vertical-align: top; +} + +// Centering +// ------------------------- + +.pull-center { + margin-left: auto; + margin-right: auto; +} + +// Floats +// ------------------------- + +// Use left margin when it's in a float: right element. +// Sets the margin correctly when inline blocks are hidden and shown. +.pull-right { + float: right !important; + + .inline-block { + margin-right: 0; + margin-left: @component-padding; + } + .inline-block-tight { + margin-right: 0; + margin-left: @component-padding/2; + } + + > .inline-block:first-child, + > .inline-block-tight:first-child { + margin-left: 0; + } +} + +.pull-left { + float: left !important; +} + +.clearfix { + .clearfix(); +} diff --git a/static/atom-ui/styles/lists.less b/static/atom-ui/styles/lists.less new file mode 100644 index 000000000..d8a32d919 --- /dev/null +++ b/static/atom-ui/styles/lists.less @@ -0,0 +1,291 @@ +@import "variables/variables"; +@import "ui-variables"; +@import "mixins/mixins"; + +@import "octicon-mixins"; + +// +// List options +// -------------------------------------------------- + +// Unstyled keeps list items block level, just removes default browser padding and list-style +.list-unstyled { + padding-left: 0; + list-style: none; +} + +// Inline turns list items into inline-block +.list-inline { + .list-unstyled(); + margin-left: -5px; + + > li { + display: inline-block; + padding-left: 5px; + padding-right: 5px; + } +} + + +// +// List groups +// -------------------------------------------------- + +// Mixins + +.list-group-item-variant(@state; @background; @color) { + .list-group-item-@{state} { + color: @color; + background-color: @background; + + a&, + button& { + color: @color; + + .list-group-item-heading { + color: inherit; + } + + &:hover, + &:focus { + color: @color; + background-color: darken(@background, 5%); + } + &.active, + &.active:hover, + &.active:focus { + color: #fff; + background-color: @color; + border-color: @color; + } + } + } +} + + + +// Individual list items +// +// Use on `li`s or `div`s within the `.list-group` parent. + +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + // Place the border on the list items and negative margin up for better styling + margin-bottom: -1px; + background-color: @list-group-bg; + border: 1px solid @list-group-border; + + // Round the first and last items + &:first-child { + .border-top-radius(@list-group-border-radius); + } + &:last-child { + margin-bottom: 0; + .border-bottom-radius(@list-group-border-radius); + } +} + + +// Interactive list items +// +// Use anchor or button elements instead of `li`s or `div`s to create interactive items. +// Includes an extra `.active` modifier class for showing selected items. + +a.list-group-item, +button.list-group-item { + color: @list-group-link-color; + + .list-group-item-heading { + color: @list-group-link-heading-color; + } + + // Hover state + &:hover, + &:focus { + text-decoration: none; + color: @list-group-link-hover-color; + background-color: @list-group-hover-bg; + } +} + +button.list-group-item { + width: 100%; + text-align: left; +} + +.list-group-item { + // Disabled state + &.disabled, + &.disabled:hover, + &.disabled:focus { + background-color: @list-group-disabled-bg; + color: @list-group-disabled-color; + cursor: @cursor-disabled; + + // Force color to inherit for custom content + .list-group-item-heading { + color: inherit; + } + .list-group-item-text { + color: @list-group-disabled-text-color; + } + } + + // Active class on item itself, not parent + &.active, + &.active:hover, + &.active:focus { + z-index: 2; // Place active items above their siblings for proper border styling + color: @list-group-active-color; + background-color: @list-group-active-bg; + border-color: @list-group-active-border; + + // Force color to inherit for custom content + .list-group-item-heading, + .list-group-item-heading > small, + .list-group-item-heading > .small { + color: inherit; + } + .list-group-item-text { + color: @list-group-active-text-color; + } + } +} + + +// Contextual variants +// +// Add modifier classes to change text and background color on individual items. +// Organizationally, this must come after the `:hover` states. + +.list-group-item-variant(success; @state-success-bg; @state-success-text); +.list-group-item-variant(info; @state-info-bg; @state-info-text); +.list-group-item-variant(warning; @state-warning-bg; @state-warning-text); +.list-group-item-variant(danger; @state-danger-bg; @state-danger-text); + + +// Custom content options +// +// Extra classes for creating well-formatted content within `.list-group-item`s. + +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} + + + +// This is a bootstrap override +// --------------------------------------------- + +.list-group, +.list-group .list-group-item { + background-color: transparent; + border: none; + padding: 0; + margin: 0; + position: static; +} + +.list-group, +.list-tree { + margin: 0; + padding: 0; + list-style: none; + cursor: default; + + li:not(.list-nested-item), + li.list-nested-item > .list-item { + line-height: @component-line-height; + text-wrap: none; + white-space: nowrap; + } + + // The background highlight uses ::before rather than the item background so + // it can span the entire width of the parent container rather than the size + // of the list item. + .selected::before { + content: ''; + background-color: @background-color-selected; + position: absolute; + left: 0; + right: 0; + height: @component-line-height; + } + + // Make sure the background highlight is below the content. + .selected > * { + position: relative; + } + + .icon::before { + margin-right: @component-icon-padding; + position: relative; + top: 1px; + } + .no-icon { + padding-left: @component-icon-padding + @component-icon-size; + } +} + + + +// +// List Tree +// -------------------------------------------------- + +// Handle indentation of the tree. Assume disclosure arrows. + +.list-tree { + .list-nested-item > .list-tree > li, + .list-nested-item > .list-group > li { + padding-left: @component-icon-size + @component-icon-padding; + } + + &.has-collapsable-children { + @disclosure-arrow-padding: @disclosure-arrow-size + @component-icon-padding; + li.list-item { + margin-left: @disclosure-arrow-padding; + } + + .list-nested-item.collapsed > .list-group, + .list-nested-item.collapsed > .list-tree { + display: none; + } + + // Nested items always get disclosure arrows + .list-nested-item > .list-item { + .octicon(chevron-down, @disclosure-arrow-size); + &::before{ + position: relative; + top: -1px; + margin-right: @component-icon-padding; + } + } + .list-nested-item.collapsed > .list-item { + .octicon(chevron-right, @disclosure-arrow-size); + &::before{ + left: 1px; + } + } + + .list-nested-item > .list-tree > li, + .list-nested-item > .list-group > li { + padding-left: @disclosure-arrow-padding; + } + + // You want a subtree to be flat -- no collapsable children + .has-flat-children, + &.has-flat-children { + li.list-item { + margin-left: 0; + } + } + } +} diff --git a/static/atom-ui/styles/loading.less b/static/atom-ui/styles/loading.less new file mode 100644 index 000000000..dff5b1782 --- /dev/null +++ b/static/atom-ui/styles/loading.less @@ -0,0 +1,21 @@ +// +// Loading +// -------------------------------------------------- + +.loading-spinner(@size) { + display: block; + width: @size; + height: @size; + background-image: url(images/octocat-spinner-128.gif); + background-repeat: no-repeat; + background-size: cover; + + &.inline-block { + display: inline-block; + } +} + +.loading-spinner-tiny { .loading-spinner(16px); } +.loading-spinner-small { .loading-spinner(32px); } +.loading-spinner-medium { .loading-spinner(48px); } +.loading-spinner-large { .loading-spinner(64px); } diff --git a/static/atom-ui/styles/messages.less b/static/atom-ui/styles/messages.less new file mode 100644 index 000000000..a679c92cb --- /dev/null +++ b/static/atom-ui/styles/messages.less @@ -0,0 +1,41 @@ +@import "ui-variables"; + +.info-messages, +.error-messages { + margin: 0; + padding: 0; + list-style: none; +} + +.error-messages { + color: @text-color-error; +} + +ul.background-message { + font-size: @font-size * 3; + + margin: 0; + padding: 0; + + li { + margin: 0; + padding: 0; + list-style: none; + } + + &.centered { + display: flex; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + + align-items: center; + text-align: center; + + li { + width: 100%; + } + } +} diff --git a/static/atom-ui/styles/mixins/mixins.less b/static/atom-ui/styles/mixins/mixins.less new file mode 100644 index 000000000..afd8d5136 --- /dev/null +++ b/static/atom-ui/styles/mixins/mixins.less @@ -0,0 +1,88 @@ +@import "ui-variables"; + +// Core mixins +// ---------------------------------------- + +// Focus +// +.tab-focus() { + outline: 2px auto @text-color-info; + outline-offset: -2px; +} + + +// Border-radius +// +.border-top-radius(@radius) { + border-top-right-radius: @radius; + border-top-left-radius: @radius; +} +.border-right-radius(@radius) { + border-bottom-right-radius: @radius; + border-top-right-radius: @radius; +} +.border-bottom-radius(@radius) { + border-bottom-right-radius: @radius; + border-bottom-left-radius: @radius; +} +.border-left-radius(@radius) { + border-bottom-left-radius: @radius; + border-top-left-radius: @radius; +} + + +// Clearfix +// +// For modern browsers +// 1. The space content is one way to avoid an Opera bug when the +// contenteditable attribute is included anywhere else in the document. +// Otherwise it causes space to appear at the top and bottom of elements +// that are clearfixed. +// 2. The use of `table` rather than `block` is only necessary if using +// `:before` to contain the top-margins of child elements. +// +// Source: http://nicolasgallagher.com/micro-clearfix-hack/ + +.clearfix() { + &:before, + &:after { + content: " "; // 1 + display: table; // 2 + } + &:after { + clear: both; + } +} + + +// CSS image replacement +// +// Heads up! v3 launched with only `.hide-text()`, but per our pattern for +// mixins being reused as classes with the same name, this doesn't hold up. As +// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. +// +// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757 + +// Deprecated as of v3.0.1 (has been removed in v4) +.hide-text() { + font: ~"0/0" a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +// New mixin to use as of v3.0.1 +.text-hide() { + .hide-text(); +} + + +// Text overflow +// Requires inline-block or block for proper styling + +.text-overflow() { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/static/atom-ui/styles/modals.less b/static/atom-ui/styles/modals.less new file mode 100644 index 000000000..8857f3a68 --- /dev/null +++ b/static/atom-ui/styles/modals.less @@ -0,0 +1,83 @@ +@import "ui-variables"; + +// +// Modals +// -------------------------------------------------- + +.overlay, // deprecated .overlay +atom-panel.modal { + position: absolute; + display: block; + top: 0; + left: 50%; + width: 500px; + margin-left: -250px; + z-index: 9999; + box-sizing: border-box; + border-top: none; + border-top-left-radius: 0; + border-top-right-radius: 0; + + color: @text-color; + background-color: @overlay-background-color; + + padding: 10px; + + // shrink modals when window gets narrow + @media (max-width: 500px) { + & { + width: 100%; + left: 0; + margin-left: 0; + } + } + + h1 { + margin-top: 0; + color: @text-color-highlight; + font-size: 1.6em; + font-weight: bold; + } + + h2 { + font-size: 1.3em; + } + + atom-text-editor[mini] { + margin-bottom: 10px; + } + + .message { + padding-top: 5px; + font-size: 11px; + } + + &.mini { + width: 200px; + margin-left: -100px; + font-size: 12px; + } +} + + +// Deprecated: overlay, from-top, from-bottom, floating +// -------------------------------------------------- +// TODO: Remove these! + +.overlay.from-top { + top: 0; + border-top: none; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.overlay.from-bottom { + bottom: 0; + border-bottom: none; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +.overlay.floating { + left: auto; +} diff --git a/static/atom-ui/styles/panels.less b/static/atom-ui/styles/panels.less new file mode 100644 index 000000000..72bfc4bb8 --- /dev/null +++ b/static/atom-ui/styles/panels.less @@ -0,0 +1,38 @@ +@import "ui-variables"; + +// +// Panels +// -------------------------------------------------- + +.tool-panel, // deprecated: .tool-panel +.panel, // deprecated: .panel +atom-panel { + background-color: @tool-panel-background-color; +} + +.inset-panel { + border-radius: @component-border-radius; + background-color: @inset-panel-background-color; +} + +.panel-heading { + margin: 0; + padding: @component-padding; + border-radius: 0; + font-size: @font-size; + line-height: 1; + background-color: @panel-heading-background-color; + + .inset-panel & { + border-radius: @component-border-radius @component-border-radius 0 0; + } + + .btn { + @btn-height: @component-line-height - 5px; + height: @btn-height; + line-height: @btn-height; + font-size: @font-size - 2px; + position: relative; + top: -5px; + } +} diff --git a/static/atom-ui/styles/private/README.md b/static/atom-ui/styles/private/README.md new file mode 100644 index 000000000..a383db448 --- /dev/null +++ b/static/atom-ui/styles/private/README.md @@ -0,0 +1,5 @@ +# Private components + +> Private! Don't use these in packages. + +If you need something, feel free to open an issue and it might can be made public. diff --git a/static/atom-ui/styles/private/alerts.less b/static/atom-ui/styles/private/alerts.less new file mode 100644 index 000000000..cc32a8c8c --- /dev/null +++ b/static/atom-ui/styles/private/alerts.less @@ -0,0 +1,114 @@ +@import "../variables/variables"; +@import "ui-variables"; + +// +// Alerts +// -------------------------------------------------- + +//## Define alert colors, border radius, and padding. + +@alert-padding: 15px; +@alert-border-radius: @border-radius-base; +@alert-link-font-weight: bold; + +@alert-success-bg: @state-success-bg; +@alert-success-text: @state-success-text; +@alert-success-border: @state-success-border; + +@alert-info-bg: @state-info-bg; +@alert-info-text: @state-info-text; +@alert-info-border: @state-info-border; + +@alert-warning-bg: @state-warning-bg; +@alert-warning-text: @state-warning-text; +@alert-warning-border: @state-warning-border; + +@alert-danger-bg: @state-danger-bg; +@alert-danger-text: @state-danger-text; +@alert-danger-border: @state-danger-border; + + +//## variant mixin + +.alert-variant(@background; @border; @text-color) { + background-color: @background; + border-color: @border; + color: @text-color; + + hr { + border-top-color: darken(@border, 5%); + } + .alert-link { + color: darken(@text-color, 10%); + } +} + + +// Base styles +// ------------------------- + +.alert { + padding: @alert-padding; + margin-bottom: @line-height-computed; + border: 1px solid transparent; + border-radius: @alert-border-radius; + + // Headings for larger alerts + h4 { + margin-top: 0; + // Specified for the h4 to prevent conflicts of changing @headings-color + color: inherit; + } + + // Provide class for links that match alerts + .alert-link { + font-weight: @alert-link-font-weight; + } + + // Improve alignment and spacing of inner content + > p, + > ul { + margin-bottom: 0; + } + + > p + p { + margin-top: 5px; + } +} + +// Dismissible alerts +// +// Expand the right padding and account for the close button's positioning. + +.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0. +.alert-dismissible { + padding-right: (@alert-padding + 20); + + // Adjust close link position + .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; + } +} + +// Alternate styles +// +// Generate contextual modifier classes for colorizing the alert. + +.alert-success { + .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text); +} + +.alert-info { + .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text); +} + +.alert-warning { + .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text); +} + +.alert-danger { + .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text); +} diff --git a/static/atom-ui/styles/private/close.less b/static/atom-ui/styles/private/close.less new file mode 100644 index 000000000..9befb2e9d --- /dev/null +++ b/static/atom-ui/styles/private/close.less @@ -0,0 +1,38 @@ +// +// Close icon (deprecated) +// -------------------------------------------------- + +.close { + @font-size-base: 14px; + @close-font-weight: bold; + @close-color: #000; + @close-text-shadow: 0 1px 0 #fff; + + float: right; + font-size: (@font-size-base * 1.5); + font-weight: @close-font-weight; + line-height: 1; + color: @close-color; + text-shadow: @close-text-shadow; + opacity: .2; + + &:hover, + &:focus { + color: @close-color; + text-decoration: none; + cursor: pointer; + opacity: .5; + } + + // Additional properties for button version + // iOS requires the button element instead of an anchor tag. + // If you want the anchor version, it requires `href="#"`. + // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile + button& { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; + } +} diff --git a/static/atom-ui/styles/private/code.less b/static/atom-ui/styles/private/code.less new file mode 100644 index 000000000..a657ca70e --- /dev/null +++ b/static/atom-ui/styles/private/code.less @@ -0,0 +1,77 @@ +@import "../variables/variables"; +@import "ui-variables"; + +// +// Code (inline and block) +// -------------------------------------------------- + +@code-color: @text-color-highlight; +@code-bg: @background-color-highlight; + +@pre-color: @code-color; +@pre-bg: @code-bg; +@pre-border-color: @base-border-color; +@pre-scrollable-max-height: 340px; + +// Inline and block code styles +code, +kbd, +pre, +samp { + font-family: @font-family-monospace; +} + +// Inline code +code { + padding: 2px 4px; + font-size: 90%; + color: @code-color; + background-color: @code-bg; + border-radius: @border-radius-base; +} + +// User input typically entered via keyboard +kbd { + padding: 2px 4px; + font-size: 90%; + color: @code-color; + background-color: @code-bg; + border-radius: @border-radius-small; + + kbd { + padding: 0; + font-size: 100%; + font-weight: bold; + } +} + +// Blocks of code +pre { + display: block; + padding: ((@line-height-computed - 1) / 2); + margin: 0 0 (@line-height-computed / 2); + font-size: (@font-size-base - 1); // 14px to 13px + line-height: @line-height-base; + word-break: break-all; + word-wrap: break-word; + color: @pre-color; + background-color: @pre-bg; + border: 1px solid @pre-border-color; + border-radius: @border-radius-base; + + // Account for some code outputs that place code tags in pre tags + code { + padding: 0; + font-size: inherit; + color: inherit; + white-space: pre-wrap; + background-color: transparent; + border-radius: 0; + } +} + +// Enable scrollable blocks of code +.pre-scrollable { + max-height: @pre-scrollable-max-height; + overflow-y: scroll; +} diff --git a/static/atom-ui/styles/private/forms.less b/static/atom-ui/styles/private/forms.less new file mode 100644 index 000000000..c0172bb0d --- /dev/null +++ b/static/atom-ui/styles/private/forms.less @@ -0,0 +1,705 @@ +@import "../variables/variables"; +@import "ui-variables"; +@import "../mixins/mixins"; + +// +// Forms +// -------------------------------------------------- + + +@input-bg: #fff; //** `` background color +@input-bg-disabled: @gray-lighter; //** `` background color +@input-color: @gray; //** Text color for ``s +@input-border: #ccc; //** `` border color + +// TODO: Rename `@input-border-radius` to `@input-border-radius-base` in v4 +//** Default `.form-control` border radius +// This has no effect on ``s in CSS. +@input-border-radius: @border-radius-base; //** Large `.form-control` border radius +@input-border-radius-large: @border-radius-large; //** Small `.form-control` border radius +@input-border-radius-small: @border-radius-small; +@input-border-focus: #66afe9; //** Border color for inputs on focus +@input-color-placeholder: #999; //** Placeholder text color +@input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2); //** Default `.form-control` height +@input-height-large: (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2); //** Large `.form-control` height +@input-height-small: (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2); //** Small `.form-control` height + +@form-group-margin-bottom: 15px; //** `.form-group` margin + +@legend-color: @gray-dark; +@legend-border-color: #e5e5e5; + +@input-group-addon-bg: @gray-lighter; //** Background color for textual input addons +@input-group-addon-border-color: @input-border; //** Border color for textual input addons + +@cursor-disabled: not-allowed; //** Disabled cursor for form controls and buttons. + +@grid-gutter-width: 30px; //** Padding between columns. Gets divided in half for the left and right. + + +// Form validation states +// +// Used in forms.less to generate the form validation CSS for warnings, errors, +// and successes. + +.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) { + // Color the label and help text + .help-block, + .control-label, + .radio, + .checkbox, + .radio-inline, + .checkbox-inline, + &.radio label, + &.checkbox label, + &.radio-inline label, + &.checkbox-inline label { + color: @text-color; + } + // Set the border and box shadow on specific inputs to match + .form-control { + border-color: @border-color; + box-shadow: inset 0 1px 1px rgba(0,0,0,.075); // Redeclare so transitions work + &:focus { + border-color: darken(@border-color, 10%); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%); + } + } + // Set validation states also for addons + .input-group-addon { + color: @text-color; + border-color: @border-color; + background-color: @background-color; + } + // Optional feedback icon + .form-control-feedback { + color: @text-color; + } +} + + +// Form control focus state +// +// Generate a customized focus state and for any input with the specified color, +// which defaults to the `@input-border-focus` variable. +// +// We highly encourage you to not customize the default value, but instead use +// this to tweak colors on an as-needed basis. This aesthetic change is based on +// WebKit's default styles, but applicable to a wider range of browsers. Its +// usability and accessibility should be taken into account with any change. +// +// Example usage: change the default blue border and shadow to white for better +// contrast against a dark gray background. +.form-control-focus(@color: @input-border-focus) { + @color-rgba: rgba(red(@color), green(@color), blue(@color), .6); + &:focus { + border-color: @color; + outline: 0; + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @color-rgba; + } +} + +// Form control sizing +// +// Relative text size, padding, and border-radii changes for form controls. For +// horizontal sizing, wrap controls in the predefined grid classes. `s in some browsers, due to the limited stylability of `s in IE10+. + &::-ms-expand { + border: 0; + background-color: transparent; + } + + // Disabled and read-only inputs + // + // HTML5 says that controls under a fieldset > legend:first-child won't be + // disabled if the fieldset is disabled. Due to implementation difficulty, we + // don't honor that edge case; we style them as disabled anyway. + &[disabled], + &[readonly], + fieldset[disabled] & { + background-color: @input-bg-disabled; + opacity: 1; // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655 + } + + &[disabled], + fieldset[disabled] & { + cursor: @cursor-disabled; + } + + // Reset height for `textarea`s + textarea& { + height: auto; + } +} + + +// Form groups +// +// Designed to help with the organization and spacing of vertical forms. For +// horizontal forms, use the predefined grid classes. + +.form-group { + margin-bottom: @form-group-margin-bottom; +} + + +// Checkboxes and radios +// +// Indent the labels to position radios/checkboxes as hanging controls. + +.radio, +.checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; + + label { + min-height: @line-height-computed; // Ensure the input doesn't jump when there is no text + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; + } +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + position: absolute; + margin-left: -20px; + margin-top: 4px \9; +} + +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing +} + +// Radios and checkboxes on same line +.radio-inline, +.checkbox-inline { + position: relative; + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + vertical-align: middle; + font-weight: normal; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; // space out consecutive inline controls +} + +// Apply same disabled cursor tweak as for inputs +// Some special care is needed because