From 0f0446f9225ef9b0c51e38b016830bbe0c92548d Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Mon, 29 Jan 2018 15:29:10 -0800 Subject: [PATCH 001/103] Bump version -> 0.2.22 (#1390) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 429246b31b..0394986a38 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "author": "", "email": "bryphe@outlook.com", "homepage": "https://www.onivim.io", - "version": "0.2.21", + "version": "0.2.22", "description": "NeoVim front-end with IDE-style extensibility", "keywords": ["vim", "neovim", "text", "editor", "ide", "vim"], "main": "./lib/main/src/main.js", From f090b7f3bd9cd81fc63d1a9f2bd76f2ba461e1d6 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Mon, 29 Jan 2018 17:40:54 -0800 Subject: [PATCH 002/103] Add overflow handling to buffer layers (#1391) --- .../Editor/NeovimEditor/NeovimActiveWindow.tsx | 2 ++ .../NeovimEditor/NeovimBufferLayersView.tsx | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/browser/src/Editor/NeovimEditor/NeovimActiveWindow.tsx b/browser/src/Editor/NeovimEditor/NeovimActiveWindow.tsx index aaecd7a643..b9c5888524 100644 --- a/browser/src/Editor/NeovimEditor/NeovimActiveWindow.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimActiveWindow.tsx @@ -24,6 +24,8 @@ export class NeovimActiveWindow extends React.PureComponent{this.props.children} diff --git a/browser/src/Editor/NeovimEditor/NeovimBufferLayersView.tsx b/browser/src/Editor/NeovimEditor/NeovimBufferLayersView.tsx index 25164e0346..303b199478 100644 --- a/browser/src/Editor/NeovimEditor/NeovimBufferLayersView.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimBufferLayersView.tsx @@ -21,6 +21,16 @@ export interface NeovimBufferLayersViewProps { layers: State.Layers } +const InnerLayerStyle: React.CSSProperties = { + position: "absolute", + top: "0px", + left: "0px", + right: "0px", + bottom: "0px", + overflowY: "auto", + overflowX: "auto", +} + export class NeovimBufferLayersView extends React.PureComponent { public render(): JSX.Element { const containers = this.props.windows.map(windowState => { @@ -37,7 +47,11 @@ export class NeovimBufferLayersView extends React.PureComponent { - return
{l.render(layerContext)}
+ return ( +
+ {l.render(layerContext)} +
+ ) }) const dimensions = getWindowPixelDimensions(windowState) From bc86337e50845cfd73a029511db364b2000c824c Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Mon, 29 Jan 2018 19:56:24 -0800 Subject: [PATCH 003/103] Run prettier over markdown / json files (#1395) --- .vscode/launch.json | 11 +- ACCOUNTING.md | 15 +- BACKERS.md | 40 +- CONTRIBUTING.md | 19 +- README.md | 89 +- browser/tsconfig.json | 14 +- browser/tsconfig.test.json | 14 +- extensions/css/syntaxes/css.tmLanguage.json | 3652 +++---- extensions/go/syntaxes/go.json | 1366 +-- .../syntaxes/JavaScript.tmLanguage.json | 8610 ++++++++-------- .../syntaxes/JavaScriptReact.tmLanguage.json | 8613 +++++++++-------- extensions/less/syntaxes/less.tmLanguage.json | 1095 ++- extensions/oni-layer-browser/package.json | 32 +- extensions/oni-layer-browser/tsconfig.json | 14 +- .../oni-plugin-markdown-preview/package.json | 66 +- .../oni-plugin-markdown-preview/tsconfig.json | 14 +- extensions/reason/syntaxes/reason.json | 4733 ++++----- extensions/scss/syntaxes/scss.json | 3422 +++---- .../icons/seti-icon-theme.json | 2849 +++--- extensions/theme-icons-seti/package.json | 32 +- extensions/theme-nord/package.json | 36 +- extensions/theme-onedark/package.json | 36 +- .../colors/solarized8_dark.json | 64 +- .../colors/solarized8_light.json | 64 +- extensions/theme-solarized/package.json | 46 +- .../syntaxes/TypeScript.tmLanguage.json | 8079 ++++++++-------- .../syntaxes/TypeScriptReact.tmLanguage.json | 8608 ++++++++-------- main/tsconfig.json | 13 +- test/ci/AutoCompletionTest.json | 38 - test/tsconfig.json | 15 +- vim/core/oni-core-statusbar/package.json | 9 +- vim/core/oni-plugin-buffers/package.json | 9 +- vim/core/oni-plugin-git/package.json | 9 +- vim/core/oni-plugin-typescript/package.json | 5 +- vim/core/oni-plugin-typescript/tsconfig.json | 10 +- .../oni-plugin-typescript/tsconfig.test.json | 11 +- 36 files changed, 26132 insertions(+), 25620 deletions(-) delete mode 100644 test/ci/AutoCompletionTest.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 0896e465b4..eb4a4465be 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,9 +12,7 @@ "windows": { "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd" }, - "runtimeArgs": [ - "--enable-logging" - ], + "runtimeArgs": ["--enable-logging"], "console": "internalConsole" }, { @@ -27,10 +25,7 @@ "windows": { "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd" }, - "runtimeArgs": [ - "--enable-logging", - "${workspaceRoot}/lib/main/src/main.js" - ], + "runtimeArgs": ["--enable-logging", "${workspaceRoot}/lib/main/src/main.js"], "webRoot": "${workspaceRoot}", "sourceMaps": true, "sourceMapPathOverrides": { @@ -38,4 +33,4 @@ } } ] -} \ No newline at end of file +} diff --git a/ACCOUNTING.md b/ACCOUNTING.md index c1fe69bc6d..256592ac73 100644 --- a/ACCOUNTING.md +++ b/ACCOUNTING.md @@ -1,15 +1,18 @@ # ONI + ## Accounting This file will contain a monthly report including: -- Incoming contributions -- How the contributions are distributed, in accordance with the project's goals + +* Incoming contributions +* How the contributions are distributed, in accordance with the project's goals The initial plan for allocation is as follows: -- 10% - Vim - Contribute to Bram's charity of choice -- 20% - Neovim Development -- 35% - Paid to contributors via bounties -- 35% - Paid to maintainer + +* 10% - Vim - Contribute to Bram's charity of choice +* 20% - Neovim Development +* 35% - Paid to contributors via bounties +* 35% - Paid to maintainer Your contributions help keep this project alive! diff --git a/BACKERS.md b/BACKERS.md index 6a03977ada..d10fbcdcbb 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -4,10 +4,10 @@ Oni is an MIT-licensed open-source project. It's an independent project without If you use Oni, please consider joining them via the following options: -- Become a backer on [OpenCollective](https://opencollective.com/oni#backer) -- Become a backer on [Bountysource](https://salt.bountysource.com/teams/oni) -- Make a donation via [PayPal](https://www.paypal.me/bryphe/25) -- Make a donation via Bitcoin / Ethereum (coming soon) +* Become a backer on [OpenCollective](https://opencollective.com/oni#backer) +* Become a backer on [Bountysource](https://salt.bountysource.com/teams/oni) +* Make a donation via [PayPal](https://www.paypal.me/bryphe/25) +* Make a donation via Bitcoin / Ethereum (coming soon) Thanks you to all our backers for making Oni possible! @@ -54,31 +54,31 @@ Thanks you to all our backers for making Oni possible! ## VIP Backers via BountySource -- @jordwalke -- @mhartington +* @jordwalke +* @mhartington ## Backers via BountySource -- @adambard -- @akin_so -- @ayohan -- @badosu -- @josemarluedke -- @napcode -- @robtrac -- @rrichardson -- @sbuljac +* @adambard +* @akin_so +* @ayohan +* @badosu +* @josemarluedke +* @napcode +* @robtrac +* @rrichardson +* @sbuljac ## Backers via PayPal -- @mchalkley +* @mchalkley ## Backers via OpenCollective -- Tal Amuyal -- Akinola Sowemimo -- Martijn Arts -- Amadeus Folego +* Tal Amuyal +* Akinola Sowemimo +* Martijn Arts +* Amadeus Folego diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 587bb8f97e..b01bcf2241 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,16 +4,17 @@ First, thank you for considering contributing to oni! It's people like you that make the open source community such a great community! 😊 -We welcome any type of contribution, not only code. You can help with -- **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open) -- **Marketing**: writing blog posts, howto's, printing stickers, ... -- **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ... -- **Code**: take a look at the [open issues](issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them. -- **Money**: we welcome financial contributions in full transparency on our [open collective](https://opencollective.com/oni). +We welcome any type of contribution, not only code. You can help with + +* **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open) +* **Marketing**: writing blog posts, howto's, printing stickers, ... +* **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ... +* **Code**: take a look at the [open issues](issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them. +* **Money**: we welcome financial contributions in full transparency on our [open collective](https://opencollective.com/oni). ## Your First Contribution -Working on your first Pull Request? You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github). +Working on your first Pull Request? You can learn how from this _free_ series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github). ## Submitting code @@ -41,14 +42,12 @@ You can also reach us at hello@oni.opencollective.com. Thank you to all the people who have already contributed to oni! - ### Backers Thank you to all our backers! [[Become a backer](https://opencollective.com/oni#backer)] - ### Sponsors Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/oni#sponsor)) @@ -64,4 +63,4 @@ Thank you to all our sponsors! (please ask your company to also support this ope - \ No newline at end of file + diff --git a/README.md b/README.md index fcd8940797..102e5160e8 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,9 @@

Supporting Oni

Oni is an independent, MIT-licensed open source project. Please consider supporting Oni by: -- [Become a backer or sponsor on Open Collective](https://opencollective.com/oni) -- [Become a backer on BountySource](https://www.bountysource.com/teams/oni) +* [Become a backer or sponsor on Open Collective](https://opencollective.com/oni) +* [Become a backer on BountySource](https://www.bountysource.com/teams/oni)

Sponsors via OpenCollective

@@ -55,7 +55,7 @@ The vision of Oni is to build an editor that allows you to go from _thought to c

-This repository is under __active development__, and until 1.0 please consider everything unstable. +This repository is under **active development**, and until 1.0 please consider everything unstable. Check out [Releases](https://github.com/onivim/oni/releases) for the latest binaries, or [Build Oni](https://github.com/onivim/oni/wiki/Development) from source. Consider making a donation via [OpenCollective](https://opencollective.com/oni) [BountySource](https://salt.bountysource.com/teams/oni) if you find this project useful! @@ -63,11 +63,11 @@ Check out [Releases](https://github.com/onivim/oni/releases) for the latest bina Oni brings several IDE-like integrations to neovim: -- [Quick Info](https://github.com/onivim/oni/wiki/Features#quick-info) -- [Code Completion](https://github.com/onivim/oni/wiki/Features#code-completion) -- [Syntax / Compilation Errors](https://github.com/onivim/oni/wiki/Features#syntax--compilation-errors) -- [Fuzzy Finding](https://github.com/onivim/oni/wiki/Features#fuzzy-finder) -- [Status Bar](https://github.com/onivim/oni/wiki/Features#status-bar) +* [Quick Info](https://github.com/onivim/oni/wiki/Features#quick-info) +* [Code Completion](https://github.com/onivim/oni/wiki/Features#code-completion) +* [Syntax / Compilation Errors](https://github.com/onivim/oni/wiki/Features#syntax--compilation-errors) +* [Fuzzy Finding](https://github.com/onivim/oni/wiki/Features#fuzzy-finder) +* [Status Bar](https://github.com/onivim/oni/wiki/Features#status-bar) And more coming - check out our [Roadmap](https://github.com/onivim/oni/wiki/Roadmap) @@ -76,9 +76,10 @@ Oni is cross-platform and supports Windows, Mac, and Linux. ## Installation We have installation guides for each platform: -- [Windows](https://github.com/onivim/oni/wiki/Installation-Guide#windows) -- [Mac](https://github.com/onivim/oni/wiki/Installation-Guide#mac) -- [Linux](https://github.com/onivim/oni/wiki/Installation-Guide#linux) + +* [Windows](https://github.com/onivim/oni/wiki/Installation-Guide#windows) +* [Mac](https://github.com/onivim/oni/wiki/Installation-Guide#mac) +* [Linux](https://github.com/onivim/oni/wiki/Installation-Guide#linux) The latest binaries are available on our [Releases](https://github.com/onivim/oni/releases) page, and if you'd prefer to build from source, check out our [Development](https://github.com/onivim/oni/wiki/Development) guide. @@ -86,51 +87,51 @@ The latest binaries are available on our [Releases](https://github.com/onivim/on The goal of this project is to provide both the full-fledged Vim experience, with no compromises, while pushing forward to enable new productivity scenarios. -- __Modern UX__ - The Vim experience should not be compromised by terminal limitations. -- __Rich plugin development__ - using JavaScript, instead of VimL. -- __Cross-platform support__ - across Windows, OS X, and Linux. -- __Batteries included__ - rich features are available out of the box - minimal setup needed to be productive. -- __Performance__ - no compromises, Vim is fast, and Oni should be fast too. -- __Ease Learning Curve__ - without sacrificing the Vim experience. +* **Modern UX** - The Vim experience should not be compromised by terminal limitations. +* **Rich plugin development** - using JavaScript, instead of VimL. +* **Cross-platform support** - across Windows, OS X, and Linux. +* **Batteries included** - rich features are available out of the box - minimal setup needed to be productive. +* **Performance** - no compromises, Vim is fast, and Oni should be fast too. +* **Ease Learning Curve** - without sacrificing the Vim experience. -Vim is an incredible tool for manipulating *text* at the speed of thought. With a composable, modal command language, it is no wonder that Vim usage is still prevalent today. +Vim is an incredible tool for manipulating _text_ at the speed of thought. With a composable, modal command language, it is no wonder that Vim usage is still prevalent today. -However, going from thought to *code* has some different challenges than going from thought to *text*. Code editors today provide several benefits that help to reduce __cognitive load__ when writing code, and that benefit is tremendously important - not only in terms of pure coding efficiency and productivity, but also in making the process of writing code enjoyable and fun. +However, going from thought to _code_ has some different challenges than going from thought to _text_. Code editors today provide several benefits that help to reduce **cognitive load** when writing code, and that benefit is tremendously important - not only in terms of pure coding efficiency and productivity, but also in making the process of writing code enjoyable and fun. The goal of this project is to give an editor that gives the best of both worlds - the power, speed, and flexibility of using Vim for manipulating text, as well as the rich tooling that comes with an IDE. We want to make coding as efficient, fast, and fun as we can! ## Documentation -- Check out the [Wiki](https://github.com/onivim/oni/wiki) for documentation on how to use and modify Oni. -- [FAQ](https://github.com/onivim/oni/wiki/FAQ) -- [Roadmap](https://github.com/onivim/oni/wiki/Roadmap) +* Check out the [Wiki](https://github.com/onivim/oni/wiki) for documentation on how to use and modify Oni. +* [FAQ](https://github.com/onivim/oni/wiki/FAQ) +* [Roadmap](https://github.com/onivim/oni/wiki/Roadmap) ## Contributing There many ways to get involved & contribute to Oni: -- Support Oni financially by making a donation via [OpenCollective](https://opencollective.com/oni) or [Bountysource](https://salt.bountysource.com/teams/oni) -- Thumbs up existing [issues](https://github.com/onivim/oni/issues) if they impact you. -- [Create an issue](https://github.com/onivim/oni/issues) for bugs or new features. -- Review and upate our [documentation](https://github.com/onivim/oni/wiki). -- Try out the latest [released build](https://github.com/onivim/oni/releases). -- Help us [develop](https://github.com/onivim/oni/wiki/Development): - - Review [PRs](https://github.com/onivim/oni/pulls) - - Submit a bug fix or feature - - Add test cases +* Support Oni financially by making a donation via [OpenCollective](https://opencollective.com/oni) or [Bountysource](https://salt.bountysource.com/teams/oni) +* Thumbs up existing [issues](https://github.com/onivim/oni/issues) if they impact you. +* [Create an issue](https://github.com/onivim/oni/issues) for bugs or new features. +* Review and upate our [documentation](https://github.com/onivim/oni/wiki). +* Try out the latest [released build](https://github.com/onivim/oni/releases). +* Help us [develop](https://github.com/onivim/oni/wiki/Development): + * Review [PRs](https://github.com/onivim/oni/pulls) + * Submit a bug fix or feature + * Add test cases ## Acknowledgements Oni is an independent project and is made possible by the support of some exceptional people. Big thanks to the following people for helping to realize this project: -- the [neovim team](https://neovim.io/), especially [justinmk](https://github.com/justinmk) and [tarruda](https://github.com/tarruda) - Oni would not be possible without their vision -- [jordwalke](https://github.com/jordwalke) for his generous support, inspiration, and ideas. And React ;) -- [keforbes](https://github.com/keforbes) for helping to get this project off the ground -- [tillarnold](https://github.com/tillarnold) for giving us the `oni` npm package name -- [mhartington](https://github.com/mhartington) for his generous support -- [badosu](https://github.com/badosu) for his support, contributions, and managing the AUR releases -- All our current monthly [sponsors](https://salt.bountysource.com/teams/oni/supporters) and [backers](BACKERS.md) -- All of our [contributors](https://github.com/onivim/oni/graphs/contributors) - thanks for helping to improve this project! +* the [neovim team](https://neovim.io/), especially [justinmk](https://github.com/justinmk) and [tarruda](https://github.com/tarruda) - Oni would not be possible without their vision +* [jordwalke](https://github.com/jordwalke) for his generous support, inspiration, and ideas. And React ;) +* [keforbes](https://github.com/keforbes) for helping to get this project off the ground +* [tillarnold](https://github.com/tillarnold) for giving us the `oni` npm package name +* [mhartington](https://github.com/mhartington) for his generous support +* [badosu](https://github.com/badosu) for his support, contributions, and managing the AUR releases +* All our current monthly [sponsors](https://salt.bountysource.com/teams/oni/supporters) and [backers](BACKERS.md) +* All of our [contributors](https://github.com/onivim/oni/graphs/contributors) - thanks for helping to improve this project! Several other great neovim front-end UIs [here](https://github.com/neovim/neovim/wiki/Related-projects) served as a reference, especially [NyaoVim](https://github.com/rhysd/NyaoVim) and [VimR](https://github.com/qvacua/vimr). I encourage you to check those out! @@ -150,9 +151,9 @@ Windows and OSX have a bundled version of Neovim, which is covered under [Neovim ### Bundled Plugins Bundled plugins have their own license terms. These include: -- [typescript-vim](https://github.com/leafgarland/typescript-vim) (`oni/vim/core/typescript.vim`) -- [targets.vim](https://github.com/wellle/targets.vim) (`oni/vim/default/bundle/targets.vim`) -- [vim-commentary](https://github.com/tpope/vim-commentary) (`oni/vim/default/bundle/vim-commentary`) -- [vim-unimpaired](https://github.com/tpope/vim-unimpaired) (`oni/vim/default/bundle/vim-unimpaired`) -- [vim-reasonml](https://github.com/reasonml-editor/vim-reason) (`.vim` files in `oni/vim/core/oni-plugin-reasonml`) +* [typescript-vim](https://github.com/leafgarland/typescript-vim) (`oni/vim/core/typescript.vim`) +* [targets.vim](https://github.com/wellle/targets.vim) (`oni/vim/default/bundle/targets.vim`) +* [vim-commentary](https://github.com/tpope/vim-commentary) (`oni/vim/default/bundle/vim-commentary`) +* [vim-unimpaired](https://github.com/tpope/vim-unimpaired) (`oni/vim/default/bundle/vim-unimpaired`) +* [vim-reasonml](https://github.com/reasonml-editor/vim-reason) (`.vim` files in `oni/vim/core/oni-plugin-reasonml`) diff --git a/browser/tsconfig.json b/browser/tsconfig.json index 248bf6137e..a4e25c3646 100644 --- a/browser/tsconfig.json +++ b/browser/tsconfig.json @@ -5,10 +5,7 @@ "experimentalDecorators": true, "forceConsistentCasingInFileNames": true, "jsx": "react", - "lib": [ - "dom", - "es2017" - ], + "lib": ["dom", "es2017"], "module": "esnext", "moduleResolution": "node", "newLine": "LF", @@ -28,11 +25,6 @@ "target": "es2015", "sourceMap": true }, - "include": [ - "src/**/*.ts", - "test/**/*.ts" - ], - "exclude": [ - "node_modules" - ] + "include": ["src/**/*.ts", "test/**/*.ts"], + "exclude": ["node_modules"] } diff --git a/browser/tsconfig.test.json b/browser/tsconfig.test.json index d6f906421e..55dedc0057 100644 --- a/browser/tsconfig.test.json +++ b/browser/tsconfig.test.json @@ -5,10 +5,7 @@ "experimentalDecorators": true, "forceConsistentCasingInFileNames": true, "jsx": "react", - "lib": [ - "dom", - "es2017" - ], + "lib": ["dom", "es2017"], "module": "commonjs", "moduleResolution": "node", "newLine": "LF", @@ -28,11 +25,6 @@ "target": "es2015", "sourceMap": true }, - "include": [ - "src/**/*.ts", - "test/**/*.ts" - ], - "exclude": [ - "node_modules" - ] + "include": ["src/**/*.ts", "test/**/*.ts"], + "exclude": ["node_modules"] } diff --git a/extensions/css/syntaxes/css.tmLanguage.json b/extensions/css/syntaxes/css.tmLanguage.json index 95caf37121..e2c0b457c9 100644 --- a/extensions/css/syntaxes/css.tmLanguage.json +++ b/extensions/css/syntaxes/css.tmLanguage.json @@ -1,1807 +1,1847 @@ { - "information_for_contributors": [ - "This file has been converted from https://github.com/atom/language-css/blob/master/grammars/css.cson", - "If you want to provide a fix or improvement, please create a pull request against the original repository.", - "Once accepted there, we are happy to receive an update request." - ], - "version": "https://github.com/atom/language-css/commit/ec289867164a34fce48a69776b7f8dc380e3dc37", - "scopeName": "source.css", - "name": "CSS", - "fileTypes": [ - "css", - "css.erb" - ], - "firstLineMatch": "(?xi)\n# Emacs modeline\n-\\*-(?:\\s*(?=[^:;\\s]+\\s*-\\*-)|(?:.*?[;\\s]|(?<=-\\*-))mode\\s*:\\s*)\n css\n(?=[\\s;]|(?]?\\d+|m)?|\\sex)(?=:(?=\\s*set?\\s[^\\n:]+:)|:(?!\\s*set?\\s))(?:(?:\\s|\\s*:\\s*)\\w*(?:\\s*=(?:[^\\n\\\\\\s]|\\\\.)*)?)*[\\s:](?:filetype|ft|syntax)\\s*=\n css\n(?=\\s|:|$)", - "patterns": [ - { - "include": "#comment-block" - }, - { - "include": "#escapes" - }, - { - "include": "#combinators" - }, - { - "include": "#selector" - }, - { - "include": "#at-rules" - }, - { - "include": "#rule-list" - } - ], - "repository": { - "at-rules": { - "patterns": [ - { - "begin": "\\A(?:\\xEF\\xBB\\xBF)?(?i:(?=\\s*@charset\\b))", - "end": ";|(?=$)", - "endCaptures": { - "0": { - "name": "punctuation.terminator.rule.css" - } - }, - "name": "meta.at-rule.charset.css", - "patterns": [ - { - "captures": { - "1": { - "name": "invalid.illegal.not-lowercase.charset.css" - }, - "2": { - "name": "invalid.illegal.leading-whitespace.charset.css" - }, - "3": { - "name": "invalid.illegal.no-whitespace.charset.css" - }, - "4": { - "name": "invalid.illegal.whitespace.charset.css" - }, - "5": { - "name": "invalid.illegal.not-double-quoted.charset.css" - }, - "6": { - "name": "invalid.illegal.unclosed-string.charset.css" - }, - "7": { - "name": "invalid.illegal.unexpected-characters.charset.css" - } - }, - "match": "(?x) # Possible errors:\n\\G\n((?!@charset)@\\w+) # Not lowercase (@charset is case-sensitive)\n|\n\\G(\\s+) # Preceding whitespace\n|\n(@charset\\S[^;]*) # No whitespace after @charset\n|\n(?<=@charset) # Before quoted charset name\n(\\x20{2,}|\\t+) # More than one space used, or a tab\n|\n(?<=@charset\\x20) # Beginning of charset name\n([^\";]+) # Not double-quoted\n|\n(\"[^\"]+$) # Unclosed quote\n|\n(?<=\") # After charset name\n([^;]+) # Unexpected junk instead of semicolon" - }, - { - "captures": { - "1": { - "name": "keyword.control.at-rule.charset.css" - }, - "2": { - "name": "punctuation.definition.keyword.css" - } - }, - "match": "((@)charset)(?=\\s)" - }, - { - "begin": "\"", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.css" - } - }, - "end": "\"|$", - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.css" - } - }, - "name": "string.quoted.double.css", - "patterns": [ - { - "begin": "(?:\\G|^)(?=(?:[^\"])+$)", - "end": "$", - "name": "invalid.illegal.unclosed.string.css" - } - ] - } - ] - }, - { - "begin": "(?i)((@)import)(?:\\s+|$|(?=['\"]|/\\*))", - "beginCaptures": { - "1": { - "name": "keyword.control.at-rule.import.css" - }, - "2": { - "name": "punctuation.definition.keyword.css" - } - }, - "end": ";", - "endCaptures": { - "0": { - "name": "punctuation.terminator.rule.css" - } - }, - "name": "meta.at-rule.import.css", - "patterns": [ - { - "begin": "\\G\\s*(?=/\\*)", - "end": "(?<=\\*/)\\s*", - "patterns": [ - { - "include": "#comment-block" - } - ] - }, - { - "include": "#string" - }, - { - "include": "#url" - }, - { - "include": "#media-query-list" - } - ] - }, - { - "begin": "(?i)((@)font-face)(?=\\s*|{|/\\*|$)", - "beginCaptures": { - "1": { - "name": "keyword.control.at-rule.font-face.css" - }, - "2": { - "name": "punctuation.definition.keyword.css" - } - }, - "end": "(?!\\G)", - "name": "meta.at-rule.font-face.css", - "patterns": [ - { - "include": "#comment-block" - }, - { - "include": "#escapes" - }, - { - "include": "#rule-list" - } - ] - }, - { - "begin": "(?i)(@)page(?=[\\s:{]|/\\*|$)", - "captures": { - "0": { - "name": "keyword.control.at-rule.page.css" - }, - "1": { - "name": "punctuation.definition.keyword.css" - } - }, - "end": "(?=\\s*($|[:{;]))", - "name": "meta.at-rule.page.css", - "patterns": [ - { - "include": "#rule-list" - } - ] - }, - { - "begin": "(?i)(?=@media(\\s|\\(|/\\*|$))", - "end": "(?<=})(?!\\G)", - "patterns": [ - { - "begin": "(?i)\\G(@)media", - "beginCaptures": { - "0": { - "name": "keyword.control.at-rule.media.css" - }, - "1": { - "name": "punctuation.definition.keyword.css" - } - }, - "end": "(?=\\s*[{;])", - "name": "meta.at-rule.media.header.css", - "patterns": [ - { - "include": "#media-query-list" - } - ] - }, - { - "begin": "{", - "beginCaptures": { - "0": { - "name": "punctuation.section.media.begin.bracket.curly.css" - } - }, - "end": "}", - "endCaptures": { - "0": { - "name": "punctuation.section.media.end.bracket.curly.css" - } - }, - "name": "meta.at-rule.media.body.css", - "patterns": [ - { - "include": "$self" - } - ] - } - ] - }, - { - "begin": "(?i)(?=@counter-style([\\s'\"{;]|/\\*|$))", - "end": "(?<=})(?!\\G)", - "patterns": [ - { - "begin": "(?i)\\G(@)counter-style", - "beginCaptures": { - "0": { - "name": "keyword.control.at-rule.counter-style.css" - }, - "1": { - "name": "punctuation.definition.keyword.css" - } - }, - "end": "(?=\\s*{)", - "name": "meta.at-rule.counter-style.header.css", - "patterns": [ - { - "include": "#comment-block" - }, - { - "include": "#escapes" - }, - { - "captures": { - "0": { - "patterns": [ - { - "include": "#escapes" - } - ] - } - }, - "match": "(?x)\n(?:[-a-zA-Z_] | [^\\x00-\\x7F]) # First letter\n(?:[-a-zA-Z0-9_] | [^\\x00-\\x7F] # Remainder of identifier\n |\\\\(?:[0-9a-fA-F]{1,6}|.)\n)*", - "name": "variable.parameter.style-name.css" - } - ] - }, - { - "begin": "{", - "beginCaptures": { - "0": { - "name": "punctuation.section.property-list.begin.bracket.curly.css" - } - }, - "end": "}", - "endCaptures": { - "0": { - "name": "punctuation.section.property-list.end.bracket.curly.css" - } - }, - "name": "meta.at-rule.counter-style.body.css", - "patterns": [ - { - "include": "#comment-block" - }, - { - "include": "#escapes" - }, - { - "include": "#rule-list-innards" - } - ] - } - ] - }, - { - "begin": "(?i)(?=@document([\\s'\"{;]|/\\*|$))", - "end": "(?<=})(?!\\G)", - "patterns": [ - { - "begin": "(?i)\\G(@)document", - "beginCaptures": { - "0": { - "name": "keyword.control.at-rule.document.css" - }, - "1": { - "name": "punctuation.definition.keyword.css" - } - }, - "end": "(?=\\s*[{;])", - "name": "meta.at-rule.document.header.css", - "patterns": [ - { - "begin": "(?i)(?>>", - "name": "invalid.deprecated.combinator.css" - }, - { - "match": ">>|>|\\+|~", - "name": "keyword.operator.combinator.css" - } - ] - }, - "commas": { - "match": ",", - "name": "punctuation.separator.list.comma.css" - }, - "comment-block": { - "begin": "/\\*", - "beginCaptures": { - "0": { - "name": "punctuation.definition.comment.begin.css" - } - }, - "end": "\\*/", - "endCaptures": { - "0": { - "name": "punctuation.definition.comment.end.css" - } - }, - "name": "comment.block.css" - }, - "escapes": { - "patterns": [ - { - "match": "\\\\[0-9a-fA-F]{1,6}", - "name": "constant.character.escape.codepoint.css" - }, - { - "begin": "\\\\$\\s*", - "end": "^(?<:=]|\\)|/\\*) # Terminates cleanly" - }, - "media-feature-keywords": { - "match": "(?xi)\n(?<=^|\\s|:|\\*/)\n(?: portrait # Orientation\n | landscape\n | progressive # Scan types\n | interlace\n | fullscreen # Display modes\n | standalone\n | minimal-ui\n | browser\n)\n(?=\\s|\\)|$)", - "name": "support.constant.property-value.css" - }, - "media-query": { - "begin": "\\G", - "end": "(?=\\s*[{;])", - "patterns": [ - { - "include": "#comment-block" - }, - { - "include": "#escapes" - }, - { - "include": "#media-types" - }, - { - "match": "(?i)(?<=\\s|^|,|\\*/)(only|not)(?=\\s|{|/\\*|$)", - "name": "keyword.operator.logical.$1.media.css" - }, - { - "match": "(?i)(?<=\\s|^|\\*/|\\))and(?=\\s|/\\*|$)", - "name": "keyword.operator.logical.and.media.css" - }, - { - "match": ",(?:(?:\\s*,)+|(?=\\s*[;){]))", - "name": "invalid.illegal.comma.css" - }, - { - "include": "#commas" - }, - { - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.definition.parameters.begin.bracket.round.css" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.definition.parameters.end.bracket.round.css" - } - }, - "patterns": [ - { - "include": "#media-features" - }, - { - "include": "#media-feature-keywords" - }, - { - "match": ":", - "name": "punctuation.separator.key-value.css" - }, - { - "match": ">=|<=|=|<|>", - "name": "keyword.operator.comparison.css" - }, - { - "captures": { - "1": { - "name": "constant.numeric.css" - }, - "2": { - "name": "keyword.operator.arithmetic.css" - }, - "3": { - "name": "constant.numeric.css" - } - }, - "match": "(\\d+)\\s*(/)\\s*(\\d+)", - "name": "meta.ratio.css" - }, - { - "include": "#numeric-values" - }, - { - "include": "#comment-block" - } - ] - } - ] - }, - "media-query-list": { - "begin": "(?=\\s*[^{;])", - "end": "(?=\\s*[{;])", - "patterns": [ - { - "include": "#media-query" - } - ] - }, - "media-types": { - "captures": { - "1": { - "name": "support.constant.media.css" - }, - "2": { - "name": "invalid.deprecated.constant.media.css" - } - }, - "match": "(?xi)\n(?<=^|\\s|,|\\*/)\n(?:\n # Valid media types\n (all|print|screen|speech)\n |\n # Deprecated in Media Queries 4: http://dev.w3.org/csswg/mediaqueries/#media-types\n (aural|braille|embossed|handheld|projection|tty|tv)\n)\n(?=$|[{,\\s;]|/\\*)" - }, - "numeric-values": { - "patterns": [ - { - "captures": { - "1": { - "name": "punctuation.definition.constant.css" - } - }, - "match": "(#)(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\\b", - "name": "constant.other.color.rgb-value.hex.css" - }, - { - "captures": { - "1": { - "name": "keyword.other.unit.percentage.css" - }, - "2": { - "name": "keyword.other.unit.${2:/downcase}.css" - } - }, - "match": "(?xi) (?+~|] # - Followed by another selector\n | /\\* # - Followed by a block comment\n )\n |\n # Name contains unescaped ASCII symbol\n (?: # Check for acceptable preceding characters\n [-a-zA-Z_0-9]|[^\\x00-\\x7F] # - Valid selector character\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # - Escape sequence\n )*\n (?: # Invalid punctuation\n [!\"'%&(*;+~|] # - Another selector\n | /\\* # - A block comment\n)", - "name": "entity.other.attribute-name.class.css" - }, - { - "captures": { - "1": { - "name": "punctuation.definition.entity.css" - }, - "2": { - "patterns": [ - { - "include": "#escapes" - } - ] - } - }, - "match": "(?x)\n(\\#)\n(\n -?\n (?![0-9])\n (?:[-a-zA-Z0-9_]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+\n)\n(?=$|[\\s,.\\#)\\[:{>+~|]|/\\*)", - "name": "entity.other.attribute-name.id.css" - }, - { - "begin": "\\[", - "beginCaptures": { - "0": { - "name": "punctuation.definition.entity.begin.bracket.square.css" - } - }, - "end": "\\]", - "endCaptures": { - "0": { - "name": "punctuation.definition.entity.end.bracket.square.css" - } - }, - "name": "meta.attribute-selector.css", - "patterns": [ - { - "include": "#comment-block" - }, - { - "include": "#string" - }, - { - "captures": { - "1": { - "name": "storage.modifier.ignore-case.css" - } - }, - "match": "(?<=[\"'\\s]|^|\\*/)\\s*([iI])\\s*(?=[\\s\\]]|/\\*|$)" - }, - { - "captures": { - "1": { - "name": "string.unquoted.attribute-value.css", - "patterns": [ - { - "include": "#escapes" - } - ] - } - }, - "match": "(?x)(?<==)\\s*((?!/\\*)(?:[^\\\\\"'\\s\\]]|\\\\.)+)" - }, - { - "include": "#escapes" - }, - { - "match": "[~|^$*]?=", - "name": "keyword.operator.pattern.css" - }, - { - "match": "\\|", - "name": "punctuation.separator.css" - }, - { - "captures": { - "1": { - "name": "entity.other.namespace-prefix.css", - "patterns": [ - { - "include": "#escapes" - } - ] - } - }, - "match": "(?x)\n# Qualified namespace prefix\n( -?(?!\\d)(?:[\\w-]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+\n| \\*\n)\n# Lookahead to ensure there's a valid identifier ahead\n(?=\n \\| (?!\\s|=|$|\\])\n (?: -?(?!\\d)\n | [\\\\\\w-]\n | [^\\x00-\\x7F]\n )\n)" - }, - { - "captures": { - "1": { - "name": "entity.other.attribute-name.css", - "patterns": [ - { - "include": "#escapes" - } - ] - } - }, - "match": "(?x)\n(-?(?!\\d)(?>[\\w-]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+)\n\\s*\n(?=[~|^\\]$*=]|/\\*)" - } - ] - }, - { - "include": "#pseudo-classes" - }, - { - "include": "#pseudo-elements" - }, - { - "include": "#functional-pseudo-classes" - }, - { - "match": "(?x) (?\\s,.\\#|){:\\[]|/\\*|$)", - "name": "entity.name.tag.css" - }, - "unicode-range": { - "captures": { - "0": { - "name": "constant.other.unicode-range.css" - }, - "1": { - "name": "punctuation.separator.dash.unicode-range.css" - } - }, - "match": "(?]?\\d+|m)?|\\sex)(?=:(?=\\s*set?\\s[^\\n:]+:)|:(?!\\s*set?\\s))(?:(?:\\s|\\s*:\\s*)\\w*(?:\\s*=(?:[^\\n\\\\\\s]|\\\\.)*)?)*[\\s:](?:filetype|ft|syntax)\\s*=\n css\n(?=\\s|:|$)", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#escapes" + }, + { + "include": "#combinators" + }, + { + "include": "#selector" + }, + { + "include": "#at-rules" + }, + { + "include": "#rule-list" + } + ], + "repository": { + "at-rules": { + "patterns": [ + { + "begin": "\\A(?:\\xEF\\xBB\\xBF)?(?i:(?=\\s*@charset\\b))", + "end": ";|(?=$)", + "endCaptures": { + "0": { + "name": "punctuation.terminator.rule.css" + } + }, + "name": "meta.at-rule.charset.css", + "patterns": [ + { + "captures": { + "1": { + "name": "invalid.illegal.not-lowercase.charset.css" + }, + "2": { + "name": "invalid.illegal.leading-whitespace.charset.css" + }, + "3": { + "name": "invalid.illegal.no-whitespace.charset.css" + }, + "4": { + "name": "invalid.illegal.whitespace.charset.css" + }, + "5": { + "name": "invalid.illegal.not-double-quoted.charset.css" + }, + "6": { + "name": "invalid.illegal.unclosed-string.charset.css" + }, + "7": { + "name": "invalid.illegal.unexpected-characters.charset.css" + } + }, + "match": + "(?x) # Possible errors:\n\\G\n((?!@charset)@\\w+) # Not lowercase (@charset is case-sensitive)\n|\n\\G(\\s+) # Preceding whitespace\n|\n(@charset\\S[^;]*) # No whitespace after @charset\n|\n(?<=@charset) # Before quoted charset name\n(\\x20{2,}|\\t+) # More than one space used, or a tab\n|\n(?<=@charset\\x20) # Beginning of charset name\n([^\";]+) # Not double-quoted\n|\n(\"[^\"]+$) # Unclosed quote\n|\n(?<=\") # After charset name\n([^;]+) # Unexpected junk instead of semicolon" + }, + { + "captures": { + "1": { + "name": "keyword.control.at-rule.charset.css" + }, + "2": { + "name": "punctuation.definition.keyword.css" + } + }, + "match": "((@)charset)(?=\\s)" + }, + { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.css" + } + }, + "end": "\"|$", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.css" + } + }, + "name": "string.quoted.double.css", + "patterns": [ + { + "begin": "(?:\\G|^)(?=(?:[^\"])+$)", + "end": "$", + "name": "invalid.illegal.unclosed.string.css" + } + ] + } + ] + }, + { + "begin": "(?i)((@)import)(?:\\s+|$|(?=['\"]|/\\*))", + "beginCaptures": { + "1": { + "name": "keyword.control.at-rule.import.css" + }, + "2": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": ";", + "endCaptures": { + "0": { + "name": "punctuation.terminator.rule.css" + } + }, + "name": "meta.at-rule.import.css", + "patterns": [ + { + "begin": "\\G\\s*(?=/\\*)", + "end": "(?<=\\*/)\\s*", + "patterns": [ + { + "include": "#comment-block" + } + ] + }, + { + "include": "#string" + }, + { + "include": "#url" + }, + { + "include": "#media-query-list" + } + ] + }, + { + "begin": "(?i)((@)font-face)(?=\\s*|{|/\\*|$)", + "beginCaptures": { + "1": { + "name": "keyword.control.at-rule.font-face.css" + }, + "2": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": "(?!\\G)", + "name": "meta.at-rule.font-face.css", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#escapes" + }, + { + "include": "#rule-list" + } + ] + }, + { + "begin": "(?i)(@)page(?=[\\s:{]|/\\*|$)", + "captures": { + "0": { + "name": "keyword.control.at-rule.page.css" + }, + "1": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": "(?=\\s*($|[:{;]))", + "name": "meta.at-rule.page.css", + "patterns": [ + { + "include": "#rule-list" + } + ] + }, + { + "begin": "(?i)(?=@media(\\s|\\(|/\\*|$))", + "end": "(?<=})(?!\\G)", + "patterns": [ + { + "begin": "(?i)\\G(@)media", + "beginCaptures": { + "0": { + "name": "keyword.control.at-rule.media.css" + }, + "1": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": "(?=\\s*[{;])", + "name": "meta.at-rule.media.header.css", + "patterns": [ + { + "include": "#media-query-list" + } + ] + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.media.begin.bracket.curly.css" + } + }, + "end": "}", + "endCaptures": { + "0": { + "name": "punctuation.section.media.end.bracket.curly.css" + } + }, + "name": "meta.at-rule.media.body.css", + "patterns": [ + { + "include": "$self" + } + ] + } + ] + }, + { + "begin": "(?i)(?=@counter-style([\\s'\"{;]|/\\*|$))", + "end": "(?<=})(?!\\G)", + "patterns": [ + { + "begin": "(?i)\\G(@)counter-style", + "beginCaptures": { + "0": { + "name": "keyword.control.at-rule.counter-style.css" + }, + "1": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": "(?=\\s*{)", + "name": "meta.at-rule.counter-style.header.css", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#escapes" + }, + { + "captures": { + "0": { + "patterns": [ + { + "include": "#escapes" + } + ] + } + }, + "match": + "(?x)\n(?:[-a-zA-Z_] | [^\\x00-\\x7F]) # First letter\n(?:[-a-zA-Z0-9_] | [^\\x00-\\x7F] # Remainder of identifier\n |\\\\(?:[0-9a-fA-F]{1,6}|.)\n)*", + "name": "variable.parameter.style-name.css" + } + ] + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": + "punctuation.section.property-list.begin.bracket.curly.css" + } + }, + "end": "}", + "endCaptures": { + "0": { + "name": + "punctuation.section.property-list.end.bracket.curly.css" + } + }, + "name": "meta.at-rule.counter-style.body.css", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#escapes" + }, + { + "include": "#rule-list-innards" + } + ] + } + ] + }, + { + "begin": "(?i)(?=@document([\\s'\"{;]|/\\*|$))", + "end": "(?<=})(?!\\G)", + "patterns": [ + { + "begin": "(?i)\\G(@)document", + "beginCaptures": { + "0": { + "name": "keyword.control.at-rule.document.css" + }, + "1": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": "(?=\\s*[{;])", + "name": "meta.at-rule.document.header.css", + "patterns": [ + { + "begin": "(?i)(?>>", + "name": "invalid.deprecated.combinator.css" + }, + { + "match": ">>|>|\\+|~", + "name": "keyword.operator.combinator.css" + } + ] + }, + "commas": { + "match": ",", + "name": "punctuation.separator.list.comma.css" + }, + "comment-block": { + "begin": "/\\*", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.begin.css" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.end.css" + } + }, + "name": "comment.block.css" + }, + "escapes": { + "patterns": [ + { + "match": "\\\\[0-9a-fA-F]{1,6}", + "name": "constant.character.escape.codepoint.css" + }, + { + "begin": "\\\\$\\s*", + "end": "^(?<:=]|\\)|/\\*) # Terminates cleanly" + }, + "media-feature-keywords": { + "match": + "(?xi)\n(?<=^|\\s|:|\\*/)\n(?: portrait # Orientation\n | landscape\n | progressive # Scan types\n | interlace\n | fullscreen # Display modes\n | standalone\n | minimal-ui\n | browser\n)\n(?=\\s|\\)|$)", + "name": "support.constant.property-value.css" + }, + "media-query": { + "begin": "\\G", + "end": "(?=\\s*[{;])", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#escapes" + }, + { + "include": "#media-types" + }, + { + "match": "(?i)(?<=\\s|^|,|\\*/)(only|not)(?=\\s|{|/\\*|$)", + "name": "keyword.operator.logical.$1.media.css" + }, + { + "match": "(?i)(?<=\\s|^|\\*/|\\))and(?=\\s|/\\*|$)", + "name": "keyword.operator.logical.and.media.css" + }, + { + "match": ",(?:(?:\\s*,)+|(?=\\s*[;){]))", + "name": "invalid.illegal.comma.css" + }, + { + "include": "#commas" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.parameters.begin.bracket.round.css" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.end.bracket.round.css" + } + }, + "patterns": [ + { + "include": "#media-features" + }, + { + "include": "#media-feature-keywords" + }, + { + "match": ":", + "name": "punctuation.separator.key-value.css" + }, + { + "match": ">=|<=|=|<|>", + "name": "keyword.operator.comparison.css" + }, + { + "captures": { + "1": { + "name": "constant.numeric.css" + }, + "2": { + "name": "keyword.operator.arithmetic.css" + }, + "3": { + "name": "constant.numeric.css" + } + }, + "match": "(\\d+)\\s*(/)\\s*(\\d+)", + "name": "meta.ratio.css" + }, + { + "include": "#numeric-values" + }, + { + "include": "#comment-block" + } + ] + } + ] + }, + "media-query-list": { + "begin": "(?=\\s*[^{;])", + "end": "(?=\\s*[{;])", + "patterns": [ + { + "include": "#media-query" + } + ] + }, + "media-types": { + "captures": { + "1": { + "name": "support.constant.media.css" + }, + "2": { + "name": "invalid.deprecated.constant.media.css" + } + }, + "match": + "(?xi)\n(?<=^|\\s|,|\\*/)\n(?:\n # Valid media types\n (all|print|screen|speech)\n |\n # Deprecated in Media Queries 4: http://dev.w3.org/csswg/mediaqueries/#media-types\n (aural|braille|embossed|handheld|projection|tty|tv)\n)\n(?=$|[{,\\s;]|/\\*)" + }, + "numeric-values": { + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.definition.constant.css" + } + }, + "match": "(#)(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\\b", + "name": "constant.other.color.rgb-value.hex.css" + }, + { + "captures": { + "1": { + "name": "keyword.other.unit.percentage.css" + }, + "2": { + "name": "keyword.other.unit.${2:/downcase}.css" + } + }, + "match": + "(?xi) (?+~|] # - Followed by another selector\n | /\\* # - Followed by a block comment\n )\n |\n # Name contains unescaped ASCII symbol\n (?: # Check for acceptable preceding characters\n [-a-zA-Z_0-9]|[^\\x00-\\x7F] # - Valid selector character\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # - Escape sequence\n )*\n (?: # Invalid punctuation\n [!\"'%&(*;+~|] # - Another selector\n | /\\* # - A block comment\n)", + "name": "entity.other.attribute-name.class.css" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.entity.css" + }, + "2": { + "patterns": [ + { + "include": "#escapes" + } + ] + } + }, + "match": + "(?x)\n(\\#)\n(\n -?\n (?![0-9])\n (?:[-a-zA-Z0-9_]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+\n)\n(?=$|[\\s,.\\#)\\[:{>+~|]|/\\*)", + "name": "entity.other.attribute-name.id.css" + }, + { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "punctuation.definition.entity.begin.bracket.square.css" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.definition.entity.end.bracket.square.css" + } + }, + "name": "meta.attribute-selector.css", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#string" + }, + { + "captures": { + "1": { + "name": "storage.modifier.ignore-case.css" + } + }, + "match": "(?<=[\"'\\s]|^|\\*/)\\s*([iI])\\s*(?=[\\s\\]]|/\\*|$)" + }, + { + "captures": { + "1": { + "name": "string.unquoted.attribute-value.css", + "patterns": [ + { + "include": "#escapes" + } + ] + } + }, + "match": "(?x)(?<==)\\s*((?!/\\*)(?:[^\\\\\"'\\s\\]]|\\\\.)+)" + }, + { + "include": "#escapes" + }, + { + "match": "[~|^$*]?=", + "name": "keyword.operator.pattern.css" + }, + { + "match": "\\|", + "name": "punctuation.separator.css" + }, + { + "captures": { + "1": { + "name": "entity.other.namespace-prefix.css", + "patterns": [ + { + "include": "#escapes" + } + ] + } + }, + "match": + "(?x)\n# Qualified namespace prefix\n( -?(?!\\d)(?:[\\w-]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+\n| \\*\n)\n# Lookahead to ensure there's a valid identifier ahead\n(?=\n \\| (?!\\s|=|$|\\])\n (?: -?(?!\\d)\n | [\\\\\\w-]\n | [^\\x00-\\x7F]\n )\n)" + }, + { + "captures": { + "1": { + "name": "entity.other.attribute-name.css", + "patterns": [ + { + "include": "#escapes" + } + ] + } + }, + "match": + "(?x)\n(-?(?!\\d)(?>[\\w-]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+)\n\\s*\n(?=[~|^\\]$*=]|/\\*)" + } + ] + }, + { + "include": "#pseudo-classes" + }, + { + "include": "#pseudo-elements" + }, + { + "include": "#functional-pseudo-classes" + }, + { + "match": + "(?x) (?\\s,.\\#|){:\\[]|/\\*|$)", + "name": "entity.name.tag.css" + }, + "unicode-range": { + "captures": { + "0": { + "name": "constant.other.unicode-range.css" + }, + "1": { + "name": "punctuation.separator.dash.unicode-range.css" + } + }, + "match": "(?,\\s*\\w+(?:\\.\\w+)*)*)(?=\\s*=(?!=))", - "captures": { - "1": { - "patterns": [ - { - "match": "\\d\\w*", - "name": "invalid.illegal.identifier.go" - }, - { - "match": "\\w+(?:\\.\\w+)*", - "name": "variable.other.assignment.go", - "captures": { - "0": { - "patterns": [ - { - "include": "#delimiters" - } - ] - } - } - }, - { - "include": "#delimiters" - } - ] - } - } - }, - { - "match": "\\w+(?:,\\s*\\w+)*(?=\\s*:=)", - "captures": { - "0": { - "patterns": [ - { - "match": "\\d\\w*", - "name": "invalid.illegal.identifier.go" - }, - { - "match": "\\w+", - "name": "variable.other.assignment.go" - }, - { - "include": "#delimiters" - } - ] - } - } - }, - { - "comment": "Terminators", - "match": ";", - "name": "punctuation.terminator.go" - }, - { - "include": "#brackets" - }, - { - "include": "#delimiters" - }, - { - "include": "#keywords" - }, - { - "include": "#operators" - }, - { - "include": "#runes" - }, - { - "include": "#storage_types" - } - ], - "repository": { - "brackets": { - "patterns": [ - { - "begin": "{", - "beginCaptures": { - "0": { - "name": "punctuation.definition.begin.bracket.curly.go" - } - }, - "end": "}", - "endCaptures": { - "0": { - "name": "punctuation.definition.end.bracket.curly.go" - } - }, - "patterns": [ - { - "include": "$self" - } - ] - }, - { - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.definition.begin.bracket.round.go" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.definition.end.bracket.round.go" - } - }, - "patterns": [ - { - "include": "$self" - } - ] - }, - { - "match": "\\[|\\]", - "name": "punctuation.definition.bracket.square.go" - } - ] - }, - "comments": { - "patterns": [ - { - "begin": "/\\*", - "end": "\\*/", - "captures": { - "0": { - "name": "punctuation.definition.comment.go" - } - }, - "name": "comment.block.go" - }, - { - "begin": "//", - "beginCaptures": { - "0": { - "name": "punctuation.definition.comment.go" - } - }, - "end": "$", - "name": "comment.line.double-slash.go" - } - ] - }, - "delimiters": { - "patterns": [ - { - "match": ",", - "name": "punctuation.other.comma.go" - }, - { - "match": "\\.(?!\\.\\.)", - "name": "punctuation.other.period.go" - }, - { - "match": ":(?!=)", - "name": "punctuation.other.colon.go" - } - ] - }, - "imports": { - "patterns": [ - { - "match": "((?!\\s+\")[^\\s]*)?\\s*((\")([^\"]*)(\"))", - "captures": { - "1": { - "name": "entity.alias.import.go" - }, - "2": { - "name": "string.quoted.double.go" - }, - "3": { - "name": "punctuation.definition.string.begin.go" - }, - "4": { - "name": "entity.name.import.go" - }, - "5": { - "name": "punctuation.definition.string.end.go" - } - } - }, - { - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.definition.imports.begin.bracket.round.go" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.definition.imports.end.bracket.round.go" - } - }, - "patterns": [ - { - "include": "#comments" - }, - { - "include": "#imports" - } - ] - } - ] - }, - "keywords": { - "patterns": [ - { - "comment": "Flow control keywords", - "match": "\\b(break|case|continue|default|defer|else|fallthrough|for|go|goto|if|range|return|select|switch)\\b", - "name": "keyword.control.go" - }, - { - "match": "\\bchan\\b", - "name": "keyword.channel.go" - }, - { - "match": "\\bconst\\b", - "name": "keyword.const.go" - }, - { - "match": "\\bfunc\\b", - "name": "keyword.function.go" - }, - { - "match": "\\binterface\\b", - "name": "keyword.interface.go" - }, - { - "match": "\\bmap\\b", - "name": "keyword.map.go" - }, - { - "match": "\\bstruct\\b", - "name": "keyword.struct.go" - } - ] - }, - "operators": { - "comment": "Note that the order here is very important!", - "patterns": [ - { - "match": "(\\*|&)(?=\\w)", - "name": "keyword.operator.address.go" - }, - { - "match": "<\\-", - "name": "keyword.operator.channel.go" - }, - { - "match": "\\-\\-", - "name": "keyword.operator.decrement.go" - }, - { - "match": "\\+\\+", - "name": "keyword.operator.increment.go" - }, - { - "match": "(==|!=|<=|>=|<[^<]|>[^>])", - "name": "keyword.operator.comparison.go" - }, - { - "match": "(&&|\\|\\||!)", - "name": "keyword.operator.logical.go" - }, - { - "match": "(=|\\+=|\\-=|\\|=|\\^=|\\*=|/=|:=|%=|<<=|>>=|&\\^=|&=)", - "name": "keyword.operator.assignment.go" - }, - { - "match": "(\\+|\\-|\\*|/|%)", - "name": "keyword.operator.arithmetic.go" - }, - { - "match": "(&(?!\\^)|\\||\\^|&\\^|<<|>>)", - "name": "keyword.operator.arithmetic.bitwise.go" - }, - { - "match": "\\.\\.\\.", - "name": "keyword.operator.ellipsis.go" - } - ] - }, - "runes": { - "patterns": [ - { - "begin": "'", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.go" - } - }, - "end": "'", - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.go" - } - }, - "name": "string.quoted.rune.go", - "patterns": [ - { - "match": "\\G(\\\\([0-7]{3}|[abfnrtv\\\\'\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})|.)(?=')", - "name": "constant.other.rune.go" - }, - { - "match": "[^']+", - "name": "invalid.illegal.unknown-rune.go" - } - ] - } - ] - }, - "storage_types": { - "patterns": [ - { - "match": "\\bbool\\b", - "name": "storage.type.boolean.go" - }, - { - "match": "\\bbyte\\b", - "name": "storage.type.byte.go" - }, - { - "match": "\\berror\\b", - "name": "storage.type.error.go" - }, - { - "match": "\\b(complex(64|128)|float(32|64)|u?int(8|16|32|64)?)\\b", - "name": "storage.type.numeric.go" - }, - { - "match": "\\brune\\b", - "name": "storage.type.rune.go" - }, - { - "match": "\\bstring\\b", - "name": "storage.type.string.go" - }, - { - "match": "\\buintptr\\b", - "name": "storage.type.uintptr.go" - } - ] - }, - "string_escaped_char": { - "patterns": [ - { - "match": "\\\\([0-7]{3}|[abfnrtv\\\\'\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})", - "name": "constant.character.escape.go" - }, - { - "match": "\\\\[^0-7xuUabfnrtv\\'\"]", - "name": "invalid.illegal.unknown-escape.go" - } - ] - }, - "string_placeholder": { - "patterns": [ - { - "match": "%(\\[\\d+\\])?([\\+#\\-0\\x20]{,2}((\\d+|\\*)?(\\.?(\\d+|\\*|(\\[\\d+\\])\\*?)?(\\[\\d+\\])?)?))?[vT%tbcdoqxXUbeEfFgGsp]", - "name": "constant.other.placeholder.go" - } - ] - }, - "variables": { - "patterns": [ - { - "match": "(\\w+(?:,\\s*\\w+)*)(\\s+\\*?\\w+(?:\\.\\w+)?\\s*)?(?=\\s*=)", - "captures": { - "1": { - "patterns": [ - { - "match": "\\d\\w*", - "name": "invalid.illegal.identifier.go" - }, - { - "match": "\\w+", - "name": "variable.other.assignment.go" - }, - { - "include": "#delimiters" - } - ] - }, - "2": { - "patterns": [ - { - "include": "$self" - } - ] - } - } - }, - { - "match": "(\\w+(?:,\\s*\\w+)*)(\\s+(\\[(\\d*|\\.\\.\\.)\\])*\\*?(<-)?\\w+(?:\\.\\w+)?\\s*[^=].*)", - "captures": { - "1": { - "patterns": [ - { - "match": "\\d\\w*", - "name": "invalid.illegal.identifier.go" - }, - { - "match": "\\w+", - "name": "variable.other.declaration.go" - }, - { - "include": "#delimiters" - } - ] - }, - "2": { - "patterns": [ - { - "include": "$self" - } - ] - } - } - }, - { - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.definition.variables.begin.bracket.round.go" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.definition.variables.end.bracket.round.go" - } - }, - "patterns": [ - { - "include": "$self" - }, - { - "include": "#variables" - } - ] - } - ] - } - } -} \ No newline at end of file + "information_for_contributors": [ + "This file has been converted from https://github.com/atom/language-go/blob/master/grammars/go.cson", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": + "https://github.com/atom/language-go/commit/f7c6ca60bfd9d11252560b21e9378e5f82438ce3", + "scopeName": "source.go", + "name": "Go", + "comment": "Go language", + "fileTypes": ["go"], + "foldingStartMarker": "({|\\()\\s*$", + "foldingStopMarker": "(}|\\))\\s*$", + "patterns": [ + { + "include": "#comments" + }, + { + "comment": "Interpreted string literals", + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.go" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.go" + } + }, + "name": "string.quoted.double.go", + "patterns": [ + { + "include": "#string_escaped_char" + }, + { + "include": "#string_placeholder" + } + ] + }, + { + "comment": "Raw string literals", + "begin": "`", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.go" + } + }, + "end": "`", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.go" + } + }, + "name": "string.quoted.raw.go", + "patterns": [ + { + "include": "#string_placeholder" + } + ] + }, + { + "comment": "Syntax error receiving channels", + "match": "<\\-([\\t ]+)chan\\b", + "captures": { + "1": { + "name": "invalid.illegal.receive-channel.go" + } + } + }, + { + "comment": "Syntax error sending channels", + "match": "\\bchan([\\t ]+)<-", + "captures": { + "1": { + "name": "invalid.illegal.send-channel.go" + } + } + }, + { + "comment": "Syntax error using slices", + "match": "\\[\\](\\s+)", + "captures": { + "1": { + "name": "invalid.illegal.slice.go" + } + } + }, + { + "comment": "Syntax error numeric literals", + "match": "\\b0[0-7]*[89]\\d*\\b", + "name": "invalid.illegal.numeric.go" + }, + { + "comment": "Built-in functions", + "match": + "\\b(append|cap|close|complex|copy|delete|imag|len|make|new|panic|print|println|real|recover)\\b(?=\\()", + "name": "support.function.builtin.go" + }, + { + "comment": "Function declarations", + "match": "^(\\bfunc\\b)(?:\\s+(\\([^\\)]+\\)\\s+)?(\\w+)(?=\\())?", + "captures": { + "1": { + "name": "keyword.function.go" + }, + "2": { + "patterns": [ + { + "include": "#brackets" + }, + { + "include": "#operators" + } + ] + }, + "3": { + "patterns": [ + { + "match": "\\d\\w*", + "name": "invalid.illegal.identifier.go" + }, + { + "match": "\\w+", + "name": "entity.name.function.go" + } + ] + } + } + }, + { + "comment": "Functions", + "match": "(\\bfunc\\b)|(\\w+)(?=\\()", + "captures": { + "1": { + "name": "keyword.function.go" + }, + "2": { + "patterns": [ + { + "match": "\\d\\w*", + "name": "invalid.illegal.identifier.go" + }, + { + "match": "\\w+", + "name": "support.function.go" + } + ] + } + } + }, + { + "comment": "Floating-point literals", + "match": "(\\.\\d+([Ee][-+]\\d+)?i?)\\b|\\b\\d+\\.\\d*(([Ee][-+]\\d+)?i?\\b)?", + "name": "constant.numeric.floating-point.go" + }, + { + "comment": "Integers", + "match": + "\\b((0x[0-9a-fA-F]+)|(0[0-7]+i?)|(\\d+([Ee]\\d+)?i?)|(\\d+[Ee][-+]\\d+i?))\\b", + "name": "constant.numeric.integer.go" + }, + { + "comment": "Language constants", + "match": "\\b(true|false|nil|iota)\\b", + "name": "constant.language.go" + }, + { + "begin": "\\b(package)\\s+", + "beginCaptures": { + "1": { + "name": "keyword.package.go" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "match": "\\d\\w*", + "name": "invalid.illegal.identifier.go" + }, + { + "match": "\\w+", + "name": "entity.name.package.go" + } + ] + }, + { + "begin": "\\b(type)\\s+", + "beginCaptures": { + "1": { + "name": "keyword.type.go" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "match": "\\d\\w*", + "name": "invalid.illegal.identifier.go" + }, + { + "match": "\\w+", + "name": "entity.name.type.go" + } + ] + }, + { + "begin": "\\b(import)\\s+", + "beginCaptures": { + "1": { + "name": "keyword.import.go" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "include": "#imports" + } + ] + }, + { + "begin": "\\b(var)\\s+", + "beginCaptures": { + "1": { + "name": "keyword.var.go" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "include": "#variables" + } + ] + }, + { + "match": "(?,\\s*\\w+(?:\\.\\w+)*)*)(?=\\s*=(?!=))", + "captures": { + "1": { + "patterns": [ + { + "match": "\\d\\w*", + "name": "invalid.illegal.identifier.go" + }, + { + "match": "\\w+(?:\\.\\w+)*", + "name": "variable.other.assignment.go", + "captures": { + "0": { + "patterns": [ + { + "include": "#delimiters" + } + ] + } + } + }, + { + "include": "#delimiters" + } + ] + } + } + }, + { + "match": "\\w+(?:,\\s*\\w+)*(?=\\s*:=)", + "captures": { + "0": { + "patterns": [ + { + "match": "\\d\\w*", + "name": "invalid.illegal.identifier.go" + }, + { + "match": "\\w+", + "name": "variable.other.assignment.go" + }, + { + "include": "#delimiters" + } + ] + } + } + }, + { + "comment": "Terminators", + "match": ";", + "name": "punctuation.terminator.go" + }, + { + "include": "#brackets" + }, + { + "include": "#delimiters" + }, + { + "include": "#keywords" + }, + { + "include": "#operators" + }, + { + "include": "#runes" + }, + { + "include": "#storage_types" + } + ], + "repository": { + "brackets": { + "patterns": [ + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.begin.bracket.curly.go" + } + }, + "end": "}", + "endCaptures": { + "0": { + "name": "punctuation.definition.end.bracket.curly.go" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.begin.bracket.round.go" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.end.bracket.round.go" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "match": "\\[|\\]", + "name": "punctuation.definition.bracket.square.go" + } + ] + }, + "comments": { + "patterns": [ + { + "begin": "/\\*", + "end": "\\*/", + "captures": { + "0": { + "name": "punctuation.definition.comment.go" + } + }, + "name": "comment.block.go" + }, + { + "begin": "//", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.go" + } + }, + "end": "$", + "name": "comment.line.double-slash.go" + } + ] + }, + "delimiters": { + "patterns": [ + { + "match": ",", + "name": "punctuation.other.comma.go" + }, + { + "match": "\\.(?!\\.\\.)", + "name": "punctuation.other.period.go" + }, + { + "match": ":(?!=)", + "name": "punctuation.other.colon.go" + } + ] + }, + "imports": { + "patterns": [ + { + "match": "((?!\\s+\")[^\\s]*)?\\s*((\")([^\"]*)(\"))", + "captures": { + "1": { + "name": "entity.alias.import.go" + }, + "2": { + "name": "string.quoted.double.go" + }, + "3": { + "name": "punctuation.definition.string.begin.go" + }, + "4": { + "name": "entity.name.import.go" + }, + "5": { + "name": "punctuation.definition.string.end.go" + } + } + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.imports.begin.bracket.round.go" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.imports.end.bracket.round.go" + } + }, + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#imports" + } + ] + } + ] + }, + "keywords": { + "patterns": [ + { + "comment": "Flow control keywords", + "match": + "\\b(break|case|continue|default|defer|else|fallthrough|for|go|goto|if|range|return|select|switch)\\b", + "name": "keyword.control.go" + }, + { + "match": "\\bchan\\b", + "name": "keyword.channel.go" + }, + { + "match": "\\bconst\\b", + "name": "keyword.const.go" + }, + { + "match": "\\bfunc\\b", + "name": "keyword.function.go" + }, + { + "match": "\\binterface\\b", + "name": "keyword.interface.go" + }, + { + "match": "\\bmap\\b", + "name": "keyword.map.go" + }, + { + "match": "\\bstruct\\b", + "name": "keyword.struct.go" + } + ] + }, + "operators": { + "comment": "Note that the order here is very important!", + "patterns": [ + { + "match": "(\\*|&)(?=\\w)", + "name": "keyword.operator.address.go" + }, + { + "match": "<\\-", + "name": "keyword.operator.channel.go" + }, + { + "match": "\\-\\-", + "name": "keyword.operator.decrement.go" + }, + { + "match": "\\+\\+", + "name": "keyword.operator.increment.go" + }, + { + "match": "(==|!=|<=|>=|<[^<]|>[^>])", + "name": "keyword.operator.comparison.go" + }, + { + "match": "(&&|\\|\\||!)", + "name": "keyword.operator.logical.go" + }, + { + "match": "(=|\\+=|\\-=|\\|=|\\^=|\\*=|/=|:=|%=|<<=|>>=|&\\^=|&=)", + "name": "keyword.operator.assignment.go" + }, + { + "match": "(\\+|\\-|\\*|/|%)", + "name": "keyword.operator.arithmetic.go" + }, + { + "match": "(&(?!\\^)|\\||\\^|&\\^|<<|>>)", + "name": "keyword.operator.arithmetic.bitwise.go" + }, + { + "match": "\\.\\.\\.", + "name": "keyword.operator.ellipsis.go" + } + ] + }, + "runes": { + "patterns": [ + { + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.go" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.go" + } + }, + "name": "string.quoted.rune.go", + "patterns": [ + { + "match": + "\\G(\\\\([0-7]{3}|[abfnrtv\\\\'\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})|.)(?=')", + "name": "constant.other.rune.go" + }, + { + "match": "[^']+", + "name": "invalid.illegal.unknown-rune.go" + } + ] + } + ] + }, + "storage_types": { + "patterns": [ + { + "match": "\\bbool\\b", + "name": "storage.type.boolean.go" + }, + { + "match": "\\bbyte\\b", + "name": "storage.type.byte.go" + }, + { + "match": "\\berror\\b", + "name": "storage.type.error.go" + }, + { + "match": "\\b(complex(64|128)|float(32|64)|u?int(8|16|32|64)?)\\b", + "name": "storage.type.numeric.go" + }, + { + "match": "\\brune\\b", + "name": "storage.type.rune.go" + }, + { + "match": "\\bstring\\b", + "name": "storage.type.string.go" + }, + { + "match": "\\buintptr\\b", + "name": "storage.type.uintptr.go" + } + ] + }, + "string_escaped_char": { + "patterns": [ + { + "match": + "\\\\([0-7]{3}|[abfnrtv\\\\'\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})", + "name": "constant.character.escape.go" + }, + { + "match": "\\\\[^0-7xuUabfnrtv\\'\"]", + "name": "invalid.illegal.unknown-escape.go" + } + ] + }, + "string_placeholder": { + "patterns": [ + { + "match": + "%(\\[\\d+\\])?([\\+#\\-0\\x20]{,2}((\\d+|\\*)?(\\.?(\\d+|\\*|(\\[\\d+\\])\\*?)?(\\[\\d+\\])?)?))?[vT%tbcdoqxXUbeEfFgGsp]", + "name": "constant.other.placeholder.go" + } + ] + }, + "variables": { + "patterns": [ + { + "match": "(\\w+(?:,\\s*\\w+)*)(\\s+\\*?\\w+(?:\\.\\w+)?\\s*)?(?=\\s*=)", + "captures": { + "1": { + "patterns": [ + { + "match": "\\d\\w*", + "name": "invalid.illegal.identifier.go" + }, + { + "match": "\\w+", + "name": "variable.other.assignment.go" + }, + { + "include": "#delimiters" + } + ] + }, + "2": { + "patterns": [ + { + "include": "$self" + } + ] + } + } + }, + { + "match": + "(\\w+(?:,\\s*\\w+)*)(\\s+(\\[(\\d*|\\.\\.\\.)\\])*\\*?(<-)?\\w+(?:\\.\\w+)?\\s*[^=].*)", + "captures": { + "1": { + "patterns": [ + { + "match": "\\d\\w*", + "name": "invalid.illegal.identifier.go" + }, + { + "match": "\\w+", + "name": "variable.other.declaration.go" + }, + { + "include": "#delimiters" + } + ] + }, + "2": { + "patterns": [ + { + "include": "$self" + } + ] + } + } + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.variables.begin.bracket.round.go" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.variables.end.bracket.round.go" + } + }, + "patterns": [ + { + "include": "$self" + }, + { + "include": "#variables" + } + ] + } + ] + } + } +} diff --git a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json index d9981eea89..655f454d20 100644 --- a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json @@ -1,4262 +1,4350 @@ { - "information_for_contributors": [ - "This file has been converted from https://github.com/Microsoft/TypeScript-TmLanguage/blob/master/TypeScriptReact.tmLanguage", - "If you want to provide a fix or improvement, please create a pull request against the original repository.", - "Once accepted there, we are happy to receive an update request." - ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/8361b1a232501c67911c81a4664a9460d7922c6b", - "name": "JavaScript (with React support)", - "scopeName": "source.js", - "fileTypes": [ - ".js", - ".jsx", - ".es6", - ".mjs" - ], - "uuid": "805375ec-d614-41f5-8993-5843fe63ea82", - "patterns": [ - { - "include": "#directives" - }, - { - "include": "#statements" - }, - { - "name": "comment.line.shebang.ts", - "match": "\\A(#!).*(?=$)", - "captures": { - "1": { - "name": "punctuation.definition.comment.ts" - } - } - } - ], - "repository": { - "statements": { - "patterns": [ - { - "include": "#string" - }, - { - "include": "#template" - }, - { - "include": "#comment" - }, - { - "include": "#declaration" - }, - { - "include": "#control-statement" - }, - { - "include": "#after-operator-block-as-object-literal" - }, - { - "include": "#decl-block" - }, - { - "include": "#expression" - }, - { - "include": "#punctuation-semicolon" - } - ] - }, - "declaration": { - "patterns": [ - { - "include": "#decorator" - }, - { - "include": "#var-expr" - }, - { - "include": "#function-declaration" - }, - { - "include": "#class-declaration" - }, - { - "include": "#interface-declaration" - }, - { - "include": "#enum-declaration" - }, - { - "include": "#namespace-declaration" - }, - { - "include": "#type-alias-declaration" - }, - { - "include": "#import-equals-declaration" - }, - { - "include": "#import-declaration" - }, - { - "include": "#export-declaration" - } - ] - }, - "control-statement": { - "patterns": [ - { - "include": "#switch-statement" - }, - { - "include": "#for-loop" - }, - { - "name": "keyword.control.trycatch.js", - "match": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", - "beginCaptures": { - "1": { - "name": "meta.definition.variable.js entity.name.function.js" - } - }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", - "patterns": [ - { - "include": "#var-single-variable-type-annotation" - } - ] - }, - { - "name": "meta.var-single-variable.expr.js", - "begin": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", - "beginCaptures": { - "1": { - "name": "meta.definition.variable.js variable.other.constant.js" - } - }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", - "patterns": [ - { - "include": "#var-single-variable-type-annotation" - } - ] - }, - { - "name": "meta.var-single-variable.expr.js", - "begin": "([_$[:alpha:]][_$[:alnum:]]*)", - "beginCaptures": { - "1": { - "name": "meta.definition.variable.js variable.other.readwrite.js" - } - }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", - "patterns": [ - { - "include": "#var-single-variable-type-annotation" - } - ] - } - ] - }, - "var-single-variable-type-annotation": { - "patterns": [ - { - "include": "#type-annotation" - }, - { - "include": "#string" - }, - { - "include": "#comment" - } - ] - }, - "destructuring-variable": { - "patterns": [ - { - "name": "meta.object-binding-pattern-variable.js", - "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", - "captures": { - "1": { - "name": "storage.modifier.js" - }, - "2": { - "name": "keyword.operator.rest.js" - }, - "3": { - "name": "entity.name.function.js variable.language.this.js" - }, - "4": { - "name": "entity.name.function.js" - }, - "5": { - "name": "keyword.operator.optional.js" - } - } - }, - { - "match": "(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" - }, - { - "name": "meta.definition.property.js variable.object.property.js", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - }, - { - "name": "keyword.operator.optional.js", - "match": "\\?" - } - ] - } - ] - }, - "variable-initializer": { - "patterns": [ - { - "begin": "(?)", - "captures": { - "1": { - "name": "storage.modifier.async.js" - }, - "2": { - "name": "variable.parameter.js" - } - } - }, - { - "name": "meta.arrow.js", - "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", - "beginCaptures": { - "1": { - "name": "storage.modifier.async.js" - } - }, - "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#type-parameters" - }, - { - "include": "#function-parameters" - }, - { - "include": "#arrow-return-type" - } - ] - }, - { - "name": "meta.arrow.js", - "begin": "=>", - "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.js" - } - }, - "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", - "patterns": [ - { - "include": "#decl-block" - }, - { - "include": "#expression" - } - ] - } - ] - }, - "indexer-declaration": { - "name": "meta.indexer.declaration.js", - "begin": "(?:(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", - "captures": { - "0": { - "name": "meta.object-literal.key.js" - }, - "1": { - "name": "entity.name.function.js" - } - } - }, - { - "name": "meta.object.member.js", - "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", - "captures": { - "0": { - "name": "meta.object-literal.key.js" - } - } - }, - { - "name": "meta.object.member.js", - "begin": "\\.\\.\\.", - "beginCaptures": { - "0": { - "name": "keyword.operator.spread.js" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "name": "meta.object.member.js", - "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", - "captures": { - "1": { - "name": "variable.other.readwrite.js" - } - } - }, - { - "name": "meta.object.member.js", - "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", - "end": "(?=,|\\}|$)", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "name": "meta.object.member.js", - "begin": ":", - "beginCaptures": { - "0": { - "name": "meta.object-literal.key.js punctuation.separator.key-value.js" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "include": "#punctuation-comma" - } - ] - }, - "ternary-expression": { - "begin": "(\\?)", - "beginCaptures": { - "0": { - "name": "keyword.operator.ternary.js" - } - }, - "end": "(:)", - "endCaptures": { - "0": { - "name": "keyword.operator.ternary.js" - } - }, - "patterns": [ - { - "include": "#expression" - } - ] - }, - "function-call": { - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", - "patterns": [ - { - "name": "meta.function-call.js", - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", - "patterns": [ - { - "include": "#literal" - }, - { - "include": "#support-objects" - }, - { - "include": "#object-identifiers" - }, - { - "include": "#punctuation-accessor" - }, - { - "name": "keyword.operator.expression.import.js", - "match": "(?![\\.\\$])\\bimport(?=\\s*[\\(]\\s*[\\\"\\'\\`])" - }, - { - "name": "entity.name.function.js", - "match": "([_$[:alpha:]][_$[:alnum:]]*)" - } - ] - }, - { - "include": "#comment" - }, - { - "name": "meta.type.parameters.js", - "begin": "\\<", - "beginCaptures": { - "0": { - "name": "punctuation.definition.typeparameters.begin.js" - } - }, - "end": "\\>", - "endCaptures": { - "0": { - "name": "punctuation.definition.typeparameters.end.js" - } - }, - "patterns": [ - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - { - "include": "#paren-expression" - } - ] - }, - "new-expr": { - "name": "new.expr.js", - "begin": "(?>=|>>>=|\\|=" - }, - { - "name": "keyword.operator.bitwise.shift.js", - "match": "<<|>>>|>>" - }, - { - "name": "keyword.operator.comparison.js", - "match": "===|!==|==|!=" - }, - { - "name": "keyword.operator.relational.js", - "match": "<=|>=|<>|<|>" - }, - { - "name": "keyword.operator.logical.js", - "match": "\\!|&&|\\|\\|" - }, - { - "name": "keyword.operator.bitwise.js", - "match": "\\&|~|\\^|\\|" - }, - { - "name": "keyword.operator.assignment.js", - "match": "\\=" - }, - { - "name": "keyword.operator.decrement.js", - "match": "--" - }, - { - "name": "keyword.operator.increment.js", - "match": "\\+\\+" - }, - { - "name": "keyword.operator.arithmetic.js", - "match": "%|\\*|/|-|\\+" - }, - { - "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", - "captures": { - "1": { - "name": "keyword.operator.arithmetic.js" - } - } - } - ] - }, - "typeof-operator": { - "name": "keyword.operator.expression.typeof.js", - "match": "(?=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "captures": { - "1": { - "name": "punctuation.accessor.js" - }, - "2": { - "name": "support.constant.dom.js" - }, - "3": { - "name": "support.variable.property.dom.js" - } - } - }, - { - "name": "support.class.node.js", - "match": "(?x)(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", - "captures": { - "1": { - "name": "punctuation.accessor.js" - }, - "2": { - "name": "entity.name.function.js" - } - } - }, - { - "match": "(\\.)\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", - "captures": { - "1": { - "name": "punctuation.accessor.js" - }, - "2": { - "name": "variable.other.constant.property.js" - } - } - }, - { - "match": "(\\.)\\s*([_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "punctuation.accessor.js" - }, - "2": { - "name": "variable.other.property.js" - } - } - }, - { - "name": "variable.other.constant.js", - "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" - }, - { - "name": "variable.other.readwrite.js", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - } - ] - }, - "object-identifiers": { - "patterns": [ - { - "name": "support.class.js", - "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\.\\s*prototype\\b(?!\\$))" - }, - { - "match": "(?x)(\\.)\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "punctuation.accessor.js" - }, - "2": { - "name": "variable.other.constant.object.property.js" - }, - "3": { - "name": "variable.other.object.property.js" - } - } - }, - { - "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "variable.other.constant.object.js" - }, - "2": { - "name": "variable.other.object.js" - } - } - } - ] - }, - "type-annotation": { - "patterns": [ - { - "name": "meta.type.annotation.js", - "begin": "(:)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.js" - } - }, - "end": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - }, - { - "name": "meta.type.annotation.js", - "begin": "(:)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.js" - } - }, - "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - } - ] - }, - "return-type": { - "patterns": [ - { - "name": "meta.return.type.js", - "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.js" - } - }, - "end": "(?|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", - "patterns": [ - { - "begin": "(?<=[:])(?=\\s*\\{)", - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "include": "#type-predicate-operator" - }, - { - "include": "#type" - } - ] - }, - "type-parameters": { - "name": "meta.type.parameters.js", - "begin": "(<)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.begin.js" - } - }, - "end": "(>)", - "endCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.end.js" - } - }, - "patterns": [ - { - "include": "#comment" - }, - { - "name": "storage.modifier.js", - "match": "(?)" - }, - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - "type": { - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#string" - }, - { - "include": "#numeric-literal" - }, - { - "include": "#type-primitive" - }, - { - "include": "#type-builtin-literals" - }, - { - "include": "#type-parameters" - }, - { - "include": "#type-tuple" - }, - { - "include": "#type-object" - }, - { - "include": "#type-operators" - }, - { - "include": "#type-fn-type-parameters" - }, - { - "include": "#type-paren-or-function-parameters" - }, - { - "include": "#type-function-return-type" - }, - { - "include": "#type-name" - } - ] - }, - "type-primitive": { - "name": "support.type.primitive.js", - "match": "(?)\n ))\n )\n )\n)", - "end": "(?<=\\))", - "patterns": [ - { - "include": "#function-parameters" - } - ] - } - ] - }, - "type-function-return-type": { - "patterns": [ - { - "name": "meta.type.function.return.js", - "begin": "(=>)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "storage.type.function.arrow.js" - } - }, - "end": "(?)(?]|//|$)", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - }, - { - "name": "meta.type.function.return.js", - "begin": "=>", - "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.js" - } - }, - "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - } - ] - }, - "type-function-return-type-core": { - "patterns": [ - { - "include": "#comment" - }, - { - "begin": "(?<==>)(?=\\s*\\{)", - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "include": "#type-predicate-operator" - }, - { - "include": "#type" - } - ] - }, - "type-operators": { - "patterns": [ - { - "include": "#typeof-operator" - }, - { - "begin": "([&|])(?=\\s*\\{)", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.js" - } - }, - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "begin": "[&|]", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.js" - } - }, - "end": "(?=\\S)" - }, - { - "name": "keyword.operator.expression.keyof.js", - "match": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", - "beginCaptures": { - "1": { - "name": "punctuation.definition.string.begin.js" - } - }, - "end": "(/)([gimuy]*)", - "endCaptures": { - "1": { - "name": "punctuation.definition.string.end.js" - }, - "2": { - "name": "keyword.other.js" - } - }, - "patterns": [ - { - "include": "#regexp" - } - ] - }, - { - "name": "string.regexp.js", - "begin": "(?\\s*$)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.comment.js" - } - }, - "end": "(?=^)", - "patterns": [ - { - "name": "meta.tag.js", - "begin": "(<)(reference|amd-dependency|amd-module)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.tag.directive.js" - }, - "2": { - "name": "entity.name.tag.directive.js" - } - }, - "end": "/>", - "endCaptures": { - "0": { - "name": "punctuation.definition.tag.directive.js" - } - }, - "patterns": [ - { - "name": "entity.other.attribute-name.directive.js", - "match": "path|types|no-default-lib|name" - }, - { - "name": "keyword.operator.assignment.js", - "match": "=" - }, - { - "include": "#string" - } - ] - } - ] - }, - "docblock": { - "patterns": [ - { - "match": "(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "constant.language.access-type.jsdoc" - } - } - }, - { - "match": "(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "entity.name.type.instance.jsdoc" - }, - "4": { - "name": "punctuation.definition.bracket.angle.begin.jsdoc" - }, - "5": { - "name": "constant.other.email.link.underline.jsdoc" - }, - "6": { - "name": "punctuation.definition.bracket.angle.end.jsdoc" - } - } - }, - { - "match": "(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "entity.name.type.instance.jsdoc" - }, - "4": { - "name": "keyword.operator.control.jsdoc" - }, - "5": { - "name": "entity.name.type.instance.jsdoc" - } - } - }, - { - "name": "meta.example.jsdoc", - "begin": "((@)example)\\s+", - "end": "(?=@|\\*/)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "patterns": [ - { - "match": "^\\s\\*\\s+" - }, - { - "contentName": "constant.other.description.jsdoc", - "begin": "\\G(<)caption(>)", - "beginCaptures": { - "0": { - "name": "entity.name.tag.inline.jsdoc" - }, - "1": { - "name": "punctuation.definition.bracket.angle.begin.jsdoc" - }, - "2": { - "name": "punctuation.definition.bracket.angle.end.jsdoc" - } - }, - "end": "()|(?=\\*/)", - "endCaptures": { - "0": { - "name": "entity.name.tag.inline.jsdoc" - }, - "1": { - "name": "punctuation.definition.bracket.angle.begin.jsdoc" - }, - "2": { - "name": "punctuation.definition.bracket.angle.end.jsdoc" - } - } - }, - { - "match": "[^\\s@*](?:[^*]|\\*[^/])*", - "captures": { - "0": { - "name": "source.embedded.js" - } - } - } - ] - }, - { - "match": "(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "constant.language.symbol-type.jsdoc" - } - } - }, - { - "match": "(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.link.underline.jsdoc" - }, - "4": { - "name": "entity.name.type.instance.jsdoc" - } - } - }, - { - "match": "(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.jsdoc" - } - } - }, - { - "match": "(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.jsdoc" - } - } - }, - { - "begin": "((@)typedef)\\s+(?={)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", - "patterns": [ - { - "include": "#jsdoctype" - }, - { - "name": "entity.name.type.instance.jsdoc", - "match": "(?:[^@\\s*/]|\\*[^/])+" - } - ] - }, - { - "begin": "((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", - "patterns": [ - { - "include": "#jsdoctype" - }, - { - "name": "variable.other.jsdoc", - "match": "([A-Za-z_$][\\w$.\\[\\]]*)" - }, - { - "name": "variable.other.jsdoc", - "match": "(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", - "captures": { - "1": { - "name": "punctuation.definition.optional-value.begin.bracket.square.jsdoc" - }, - "2": { - "name": "keyword.operator.assignment.jsdoc" - }, - "3": { - "name": "source.embedded.js" - }, - "4": { - "name": "punctuation.definition.optional-value.end.bracket.square.jsdoc" - }, - "5": { - "name": "invalid.illegal.syntax.jsdoc" - } - } - } - ] - }, - { - "begin": "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", - "patterns": [ - { - "include": "#jsdoctype" - } - ] - }, - { - "match": "(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "entity.name.type.instance.jsdoc" - } - } - }, - { - "contentName": "variable.other.jsdoc", - "begin": "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.jsdoc" - }, - "4": { - "name": "punctuation.definition.string.begin.jsdoc" - } - }, - "end": "(\\3)|(?=$|\\*/)", - "endCaptures": { - "0": { - "name": "variable.other.jsdoc" - }, - "1": { - "name": "punctuation.definition.string.end.jsdoc" - } - } - }, - { - "match": "((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.jsdoc" - } - } - }, - { - "name": "storage.type.class.jsdoc", - "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", - "captures": { - "1": { - "name": "punctuation.definition.block.tag.jsdoc" - } - } - }, - { - "include": "#inline-tags" - } - ] - }, - "brackets": { - "patterns": [ - { - "begin": "{", - "end": "}|(?=\\*/)", - "patterns": [ - { - "include": "#brackets" - } - ] - }, - { - "begin": "\\[", - "end": "\\]|(?=\\*/)", - "patterns": [ - { - "include": "#brackets" - } - ] - } - ] - }, - "inline-tags": { - "patterns": [ - { - "name": "constant.other.description.jsdoc", - "match": "(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))", - "captures": { - "1": { - "name": "punctuation.definition.bracket.square.begin.jsdoc" - }, - "2": { - "name": "punctuation.definition.bracket.square.end.jsdoc" - } - } - }, - { - "name": "entity.name.type.instance.jsdoc", - "begin": "({)((@)(?:link(?:code|plain)?|tutorial))\\s*", - "beginCaptures": { - "1": { - "name": "punctuation.definition.bracket.curly.begin.jsdoc" - }, - "2": { - "name": "storage.type.class.jsdoc" - }, - "3": { - "name": "punctuation.definition.inline.tag.jsdoc" - } - }, - "end": "}|(?=\\*/)", - "endCaptures": { - "0": { - "name": "punctuation.definition.bracket.curly.end.jsdoc" - } - }, - "patterns": [ - { - "match": "\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?", - "captures": { - "1": { - "name": "variable.other.link.underline.jsdoc" - }, - "2": { - "name": "punctuation.separator.pipe.jsdoc" - } - } - }, - { - "match": "\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?", - "captures": { - "1": { - "name": "variable.other.description.jsdoc" - }, - "2": { - "name": "punctuation.separator.pipe.jsdoc" - } - } - } - ] - } - ] - }, - "jsdoctype": { - "patterns": [ - { - "name": "invalid.illegal.type.jsdoc", - "match": "\\G{(?:[^}*]|\\*[^/}])+$" - }, - { - "contentName": "entity.name.type.instance.jsdoc", - "begin": "\\G({)", - "beginCaptures": { - "0": { - "name": "entity.name.type.instance.jsdoc" - }, - "1": { - "name": "punctuation.definition.bracket.curly.begin.jsdoc" - } - }, - "end": "((}))\\s*|(?=\\*/)", - "endCaptures": { - "1": { - "name": "entity.name.type.instance.jsdoc" - }, - "2": { - "name": "punctuation.definition.bracket.curly.end.jsdoc" - } - }, - "patterns": [ - { - "include": "#brackets" - } - ] - } - ] - }, - "jsx": { - "patterns": [ - { - "include": "#jsx-tag-without-attributes-in-expression" - }, - { - "include": "#jsx-tag-in-expression" - } - ] - }, - "jsx-tag-without-attributes-in-expression": { - "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", - "end": "(?!\\s*(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", - "patterns": [ - { - "include": "#jsx-tag-without-attributes" - } - ] - }, - "jsx-tag-without-attributes": { - "name": "meta.tag.without-attributes.js", - "begin": "(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?)", - "end": "()", - "beginCaptures": { - "1": { - "name": "punctuation.definition.tag.begin.js" - }, - "2": { - "name": "entity.name.tag.js" - }, - "3": { - "name": "support.class.component.js" - }, - "4": { - "name": "punctuation.definition.tag.end.js" - } - }, - "endCaptures": { - "1": { - "name": "punctuation.definition.tag.begin.js" - }, - "2": { - "name": "entity.name.tag.js" - }, - "3": { - "name": "support.class.component.js" - }, - "4": { - "name": "punctuation.definition.tag.end.js" - } - }, - "contentName": "meta.jsx.children.js", - "patterns": [ - { - "include": "#jsx-children" - } - ] - }, - "jsx-tag-in-expression": { - "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", - "end": "(/>)|(?:())", - "endCaptures": { - "0": { - "name": "meta.tag.js" - }, - "1": { - "name": "punctuation.definition.tag.end.js" - }, - "2": { - "name": "punctuation.definition.tag.begin.js" - }, - "3": { - "name": "entity.name.tag.js" - }, - "4": { - "name": "support.class.component.js" - }, - "5": { - "name": "punctuation.definition.tag.end.js" - } - }, - "patterns": [ - { - "include": "#jsx-tag" - } - ] - }, - "jsx-child-tag": { - "begin": "(?x)\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", - "end": "(/>)|(?:())", - "endCaptures": { - "0": { - "name": "meta.tag.js" - }, - "1": { - "name": "punctuation.definition.tag.end.js" - }, - "2": { - "name": "punctuation.definition.tag.begin.js" - }, - "3": { - "name": "entity.name.tag.js" - }, - "4": { - "name": "support.class.component.js" - }, - "5": { - "name": "punctuation.definition.tag.end.js" - } - }, - "patterns": [ - { - "include": "#jsx-tag" - } - ] - }, - "jsx-tag": { - "name": "meta.tag.js", - "begin": "(?x)\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", - "end": "(?=(/>)|(?:()))", - "patterns": [ - { - "begin": "(?x)\n (<)\\s*\n ((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.tag.begin.js" - }, - "2": { - "name": "entity.name.tag.js" - }, - "3": { - "name": "support.class.component.js" - } - }, - "end": "(?=[/]?>)", - "contentName": "meta.tag.attributes.js", - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#jsx-tag-attributes" - }, - { - "include": "#jsx-tag-attributes-illegal" - } - ] - }, - { - "begin": "(>)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.tag.end.js" - } - }, - "end": "(?=|/\\*|//)", - "captures": { - "1": { - "name": "entity.other.attribute-name.js" - } - } - }, - "jsx-tag-attribute-assignment": { - "name": "keyword.operator.assignment.js", - "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" - }, - "jsx-string-double-quoted": { - "name": "string.quoted.double.js", - "begin": "\"", - "end": "\"", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.js" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.js" - } - }, - "patterns": [ - { - "include": "#jsx-entities" - } - ] - }, - "jsx-string-single-quoted": { - "name": "string.quoted.single.js", - "begin": "'", - "end": "'", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.js" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.js" - } - }, - "patterns": [ - { - "include": "#jsx-entities" - } - ] - }, - "jsx-tag-attributes-illegal": { - "name": "invalid.illegal.attribute.js", - "match": "\\S+" - } - } -} \ No newline at end of file + "information_for_contributors": [ + "This file has been converted from https://github.com/Microsoft/TypeScript-TmLanguage/blob/master/TypeScriptReact.tmLanguage", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": + "https://github.com/Microsoft/TypeScript-TmLanguage/commit/8361b1a232501c67911c81a4664a9460d7922c6b", + "name": "JavaScript (with React support)", + "scopeName": "source.js", + "fileTypes": [".js", ".jsx", ".es6", ".mjs"], + "uuid": "805375ec-d614-41f5-8993-5843fe63ea82", + "patterns": [ + { + "include": "#directives" + }, + { + "include": "#statements" + }, + { + "name": "comment.line.shebang.ts", + "match": "\\A(#!).*(?=$)", + "captures": { + "1": { + "name": "punctuation.definition.comment.ts" + } + } + } + ], + "repository": { + "statements": { + "patterns": [ + { + "include": "#string" + }, + { + "include": "#template" + }, + { + "include": "#comment" + }, + { + "include": "#declaration" + }, + { + "include": "#control-statement" + }, + { + "include": "#after-operator-block-as-object-literal" + }, + { + "include": "#decl-block" + }, + { + "include": "#expression" + }, + { + "include": "#punctuation-semicolon" + } + ] + }, + "declaration": { + "patterns": [ + { + "include": "#decorator" + }, + { + "include": "#var-expr" + }, + { + "include": "#function-declaration" + }, + { + "include": "#class-declaration" + }, + { + "include": "#interface-declaration" + }, + { + "include": "#enum-declaration" + }, + { + "include": "#namespace-declaration" + }, + { + "include": "#type-alias-declaration" + }, + { + "include": "#import-equals-declaration" + }, + { + "include": "#import-declaration" + }, + { + "include": "#export-declaration" + } + ] + }, + "control-statement": { + "patterns": [ + { + "include": "#switch-statement" + }, + { + "include": "#for-loop" + }, + { + "name": "keyword.control.trycatch.js", + "match": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.js entity.name.function.js" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + }, + { + "name": "meta.var-single-variable.expr.js", + "begin": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.js variable.other.constant.js" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + }, + { + "name": "meta.var-single-variable.expr.js", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.js variable.other.readwrite.js" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + } + ] + }, + "var-single-variable-type-annotation": { + "patterns": [ + { + "include": "#type-annotation" + }, + { + "include": "#string" + }, + { + "include": "#comment" + } + ] + }, + "destructuring-variable": { + "patterns": [ + { + "name": "meta.object-binding-pattern-variable.js", + "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.js" + }, + "2": { + "name": "keyword.operator.rest.js" + }, + "3": { + "name": "entity.name.function.js variable.language.this.js" + }, + "4": { + "name": "entity.name.function.js" + }, + "5": { + "name": "keyword.operator.optional.js" + } + } + }, + { + "match": + "(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + }, + { + "name": "meta.definition.property.js variable.object.property.js", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.js", + "match": "\\?" + } + ] + } + ] + }, + "variable-initializer": { + "patterns": [ + { + "begin": "(?)", + "captures": { + "1": { + "name": "storage.modifier.async.js" + }, + "2": { + "name": "variable.parameter.js" + } + } + }, + { + "name": "meta.arrow.js", + "begin": + "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js" + } + }, + "end": + "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.js", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.js" + } + }, + "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "patterns": [ + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.js", + "begin": + "(?:(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "0": { + "name": "meta.object-literal.key.js" + }, + "1": { + "name": "entity.name.function.js" + } + } + }, + { + "name": "meta.object.member.js", + "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", + "captures": { + "0": { + "name": "meta.object-literal.key.js" + } + } + }, + { + "name": "meta.object.member.js", + "begin": "\\.\\.\\.", + "beginCaptures": { + "0": { + "name": "keyword.operator.spread.js" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.js", + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", + "captures": { + "1": { + "name": "variable.other.readwrite.js" + } + } + }, + { + "name": "meta.object.member.js", + "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", + "end": "(?=,|\\}|$)", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.js", + "begin": ":", + "beginCaptures": { + "0": { + "name": "meta.object-literal.key.js punctuation.separator.key-value.js" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "include": "#punctuation-comma" + } + ] + }, + "ternary-expression": { + "begin": "(\\?)", + "beginCaptures": { + "0": { + "name": "keyword.operator.ternary.js" + } + }, + "end": "(:)", + "endCaptures": { + "0": { + "name": "keyword.operator.ternary.js" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "function-call": { + "begin": + "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", + "end": + "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", + "patterns": [ + { + "name": "meta.function-call.js", + "begin": + "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", + "end": + "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", + "patterns": [ + { + "include": "#literal" + }, + { + "include": "#support-objects" + }, + { + "include": "#object-identifiers" + }, + { + "include": "#punctuation-accessor" + }, + { + "name": "keyword.operator.expression.import.js", + "match": "(?![\\.\\$])\\bimport(?=\\s*[\\(]\\s*[\\\"\\'\\`])" + }, + { + "name": "entity.name.function.js", + "match": "([_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + { + "include": "#comment" + }, + { + "name": "meta.type.parameters.js", + "begin": "\\<", + "beginCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.begin.js" + } + }, + "end": "\\>", + "endCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.end.js" + } + }, + "patterns": [ + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + { + "include": "#paren-expression" + } + ] + }, + "new-expr": { + "name": "new.expr.js", + "begin": "(?>=|>>>=|\\|=" + }, + { + "name": "keyword.operator.bitwise.shift.js", + "match": "<<|>>>|>>" + }, + { + "name": "keyword.operator.comparison.js", + "match": "===|!==|==|!=" + }, + { + "name": "keyword.operator.relational.js", + "match": "<=|>=|<>|<|>" + }, + { + "name": "keyword.operator.logical.js", + "match": "\\!|&&|\\|\\|" + }, + { + "name": "keyword.operator.bitwise.js", + "match": "\\&|~|\\^|\\|" + }, + { + "name": "keyword.operator.assignment.js", + "match": "\\=" + }, + { + "name": "keyword.operator.decrement.js", + "match": "--" + }, + { + "name": "keyword.operator.increment.js", + "match": "\\+\\+" + }, + { + "name": "keyword.operator.arithmetic.js", + "match": "%|\\*|/|-|\\+" + }, + { + "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", + "captures": { + "1": { + "name": "keyword.operator.arithmetic.js" + } + } + } + ] + }, + "typeof-operator": { + "name": "keyword.operator.expression.typeof.js", + "match": "(?=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "captures": { + "1": { + "name": "punctuation.accessor.js" + }, + "2": { + "name": "support.constant.dom.js" + }, + "3": { + "name": "support.variable.property.dom.js" + } + } + }, + { + "name": "support.class.node.js", + "match": + "(?x)(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "captures": { + "1": { + "name": "punctuation.accessor.js" + }, + "2": { + "name": "entity.name.function.js" + } + } + }, + { + "match": "(\\.)\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "captures": { + "1": { + "name": "punctuation.accessor.js" + }, + "2": { + "name": "variable.other.constant.property.js" + } + } + }, + { + "match": "(\\.)\\s*([_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.js" + }, + "2": { + "name": "variable.other.property.js" + } + } + }, + { + "name": "variable.other.constant.js", + "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" + }, + { + "name": "variable.other.readwrite.js", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "object-identifiers": { + "patterns": [ + { + "name": "support.class.js", + "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\.\\s*prototype\\b(?!\\$))" + }, + { + "match": + "(?x)(\\.)\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.js" + }, + "2": { + "name": "variable.other.constant.object.property.js" + }, + "3": { + "name": "variable.other.object.property.js" + } + } + }, + { + "match": + "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "variable.other.constant.object.js" + }, + "2": { + "name": "variable.other.object.js" + } + } + } + ] + }, + "type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.js", + "begin": "(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js" + } + }, + "end": + "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + }, + { + "name": "meta.type.annotation.js", + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js" + } + }, + "end": + "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "return-type": { + "patterns": [ + { + "name": "meta.return.type.js", + "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js" + } + }, + "end": "(?|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "begin": "(?<=[:])(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-parameters": { + "name": "meta.type.parameters.js", + "begin": "(<)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.begin.js" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.js" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.js", + "match": "(?)" + }, + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "type": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#numeric-literal" + }, + { + "include": "#type-primitive" + }, + { + "include": "#type-builtin-literals" + }, + { + "include": "#type-parameters" + }, + { + "include": "#type-tuple" + }, + { + "include": "#type-object" + }, + { + "include": "#type-operators" + }, + { + "include": "#type-fn-type-parameters" + }, + { + "include": "#type-paren-or-function-parameters" + }, + { + "include": "#type-function-return-type" + }, + { + "include": "#type-name" + } + ] + }, + "type-primitive": { + "name": "support.type.primitive.js", + "match": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.js", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.js" + } + }, + "end": "(?)(?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.js", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.js" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.js" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.js" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.js", + "match": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.js" + } + }, + "end": "(/)([gimuy]*)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.js" + }, + "2": { + "name": "keyword.other.js" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "string.regexp.js", + "begin": + "(?\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.js" + } + }, + "end": "(?=^)", + "patterns": [ + { + "name": "meta.tag.js", + "begin": "(<)(reference|amd-dependency|amd-module)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.directive.js" + }, + "2": { + "name": "entity.name.tag.directive.js" + } + }, + "end": "/>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.directive.js" + } + }, + "patterns": [ + { + "name": "entity.other.attribute-name.directive.js", + "match": "path|types|no-default-lib|name" + }, + { + "name": "keyword.operator.assignment.js", + "match": "=" + }, + { + "include": "#string" + } + ] + } + ] + }, + "docblock": { + "patterns": [ + { + "match": "(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.access-type.jsdoc" + } + } + }, + { + "match": + "(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "5": { + "name": "constant.other.email.link.underline.jsdoc" + }, + "6": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": + "(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "keyword.operator.control.jsdoc" + }, + "5": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "name": "meta.example.jsdoc", + "begin": "((@)example)\\s+", + "end": "(?=@|\\*/)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "patterns": [ + { + "match": "^\\s\\*\\s+" + }, + { + "contentName": "constant.other.description.jsdoc", + "begin": "\\G(<)caption(>)", + "beginCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + }, + "end": "()|(?=\\*/)", + "endCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "[^\\s@*](?:[^*]|\\*[^/])*", + "captures": { + "0": { + "name": "source.embedded.js" + } + } + } + ] + }, + { + "match": + "(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.symbol-type.jsdoc" + } + } + }, + { + "match": + "(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.link.underline.jsdoc" + }, + "4": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "match": + "(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "match": + "(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "begin": "((@)typedef)\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "entity.name.type.instance.jsdoc", + "match": "(?:[^@\\s*/]|\\*[^/])+" + } + ] + }, + { + "begin": + "((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "variable.other.jsdoc", + "match": "([A-Za-z_$][\\w$.\\[\\]]*)" + }, + { + "name": "variable.other.jsdoc", + "match": + "(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", + "captures": { + "1": { + "name": + "punctuation.definition.optional-value.begin.bracket.square.jsdoc" + }, + "2": { + "name": "keyword.operator.assignment.jsdoc" + }, + "3": { + "name": "source.embedded.js" + }, + "4": { + "name": + "punctuation.definition.optional-value.end.bracket.square.jsdoc" + }, + "5": { + "name": "invalid.illegal.syntax.jsdoc" + } + } + } + ] + }, + { + "begin": + "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + } + ] + }, + { + "match": + "(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "contentName": "variable.other.jsdoc", + "begin": "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + }, + "4": { + "name": "punctuation.definition.string.begin.jsdoc" + } + }, + "end": "(\\3)|(?=$|\\*/)", + "endCaptures": { + "0": { + "name": "variable.other.jsdoc" + }, + "1": { + "name": "punctuation.definition.string.end.jsdoc" + } + } + }, + { + "match": + "((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "name": "storage.type.class.jsdoc", + "match": + "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", + "captures": { + "1": { + "name": "punctuation.definition.block.tag.jsdoc" + } + } + }, + { + "include": "#inline-tags" + } + ] + }, + "brackets": { + "patterns": [ + { + "begin": "{", + "end": "}|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + }, + { + "begin": "\\[", + "end": "\\]|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "inline-tags": { + "patterns": [ + { + "name": "constant.other.description.jsdoc", + "match": "(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))", + "captures": { + "1": { + "name": "punctuation.definition.bracket.square.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.square.end.jsdoc" + } + } + }, + { + "name": "entity.name.type.instance.jsdoc", + "begin": "({)((@)(?:link(?:code|plain)?|tutorial))\\s*", + "beginCaptures": { + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + }, + "2": { + "name": "storage.type.class.jsdoc" + }, + "3": { + "name": "punctuation.definition.inline.tag.jsdoc" + } + }, + "end": "}|(?=\\*/)", + "endCaptures": { + "0": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "match": "\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.link.underline.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + }, + { + "match": "\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.description.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + } + ] + } + ] + }, + "jsdoctype": { + "patterns": [ + { + "name": "invalid.illegal.type.jsdoc", + "match": "\\G{(?:[^}*]|\\*[^/}])+$" + }, + { + "contentName": "entity.name.type.instance.jsdoc", + "begin": "\\G({)", + "beginCaptures": { + "0": { + "name": "entity.name.type.instance.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + } + }, + "end": "((}))\\s*|(?=\\*/)", + "endCaptures": { + "1": { + "name": "entity.name.type.instance.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "jsx": { + "patterns": [ + { + "include": "#jsx-tag-without-attributes-in-expression" + }, + { + "include": "#jsx-tag-in-expression" + } + ] + }, + "jsx-tag-without-attributes-in-expression": { + "begin": + "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", + "end": "(?!\\s*(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", + "patterns": [ + { + "include": "#jsx-tag-without-attributes" + } + ] + }, + "jsx-tag-without-attributes": { + "name": "meta.tag.without-attributes.js", + "begin": "(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?)", + "end": "()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js" + }, + "2": { + "name": "entity.name.tag.js" + }, + "3": { + "name": "support.class.component.js" + }, + "4": { + "name": "punctuation.definition.tag.end.js" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js" + }, + "2": { + "name": "entity.name.tag.js" + }, + "3": { + "name": "support.class.component.js" + }, + "4": { + "name": "punctuation.definition.tag.end.js" + } + }, + "contentName": "meta.jsx.children.js", + "patterns": [ + { + "include": "#jsx-children" + } + ] + }, + "jsx-tag-in-expression": { + "begin": + "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "end": "(/>)|(?:())", + "endCaptures": { + "0": { + "name": "meta.tag.js" + }, + "1": { + "name": "punctuation.definition.tag.end.js" + }, + "2": { + "name": "punctuation.definition.tag.begin.js" + }, + "3": { + "name": "entity.name.tag.js" + }, + "4": { + "name": "support.class.component.js" + }, + "5": { + "name": "punctuation.definition.tag.end.js" + } + }, + "patterns": [ + { + "include": "#jsx-tag" + } + ] + }, + "jsx-child-tag": { + "begin": + "(?x)\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "end": "(/>)|(?:())", + "endCaptures": { + "0": { + "name": "meta.tag.js" + }, + "1": { + "name": "punctuation.definition.tag.end.js" + }, + "2": { + "name": "punctuation.definition.tag.begin.js" + }, + "3": { + "name": "entity.name.tag.js" + }, + "4": { + "name": "support.class.component.js" + }, + "5": { + "name": "punctuation.definition.tag.end.js" + } + }, + "patterns": [ + { + "include": "#jsx-tag" + } + ] + }, + "jsx-tag": { + "name": "meta.tag.js", + "begin": + "(?x)\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "end": "(?=(/>)|(?:()))", + "patterns": [ + { + "begin": + "(?x)\n (<)\\s*\n ((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js" + }, + "2": { + "name": "entity.name.tag.js" + }, + "3": { + "name": "support.class.component.js" + } + }, + "end": "(?=[/]?>)", + "contentName": "meta.tag.attributes.js", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#jsx-tag-attributes" + }, + { + "include": "#jsx-tag-attributes-illegal" + } + ] + }, + { + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.js" + } + }, + "end": "(?=|/\\*|//)", + "captures": { + "1": { + "name": "entity.other.attribute-name.js" + } + } + }, + "jsx-tag-attribute-assignment": { + "name": "keyword.operator.assignment.js", + "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" + }, + "jsx-string-double-quoted": { + "name": "string.quoted.double.js", + "begin": "\"", + "end": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-string-single-quoted": { + "name": "string.quoted.single.js", + "begin": "'", + "end": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-tag-attributes-illegal": { + "name": "invalid.illegal.attribute.js", + "match": "\\S+" + } + } +} diff --git a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json index c72bdbc95f..7af33dc045 100644 --- a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json @@ -1,4262 +1,4353 @@ { - "information_for_contributors": [ - "This file has been converted from https://github.com/Microsoft/TypeScript-TmLanguage/blob/master/TypeScriptReact.tmLanguage", - "If you want to provide a fix or improvement, please create a pull request against the original repository.", - "Once accepted there, we are happy to receive an update request." - ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/8361b1a232501c67911c81a4664a9460d7922c6b", - "name": "JavaScript (with React support)", - "scopeName": "source.js.jsx", - "fileTypes": [ - ".js", - ".jsx", - ".es6", - ".mjs" - ], - "uuid": "805375ec-d614-41f5-8993-5843fe63ea82", - "patterns": [ - { - "include": "#directives" - }, - { - "include": "#statements" - }, - { - "name": "comment.line.shebang.ts", - "match": "\\A(#!).*(?=$)", - "captures": { - "1": { - "name": "punctuation.definition.comment.ts" - } - } - } - ], - "repository": { - "statements": { - "patterns": [ - { - "include": "#string" - }, - { - "include": "#template" - }, - { - "include": "#comment" - }, - { - "include": "#declaration" - }, - { - "include": "#control-statement" - }, - { - "include": "#after-operator-block-as-object-literal" - }, - { - "include": "#decl-block" - }, - { - "include": "#expression" - }, - { - "include": "#punctuation-semicolon" - } - ] - }, - "declaration": { - "patterns": [ - { - "include": "#decorator" - }, - { - "include": "#var-expr" - }, - { - "include": "#function-declaration" - }, - { - "include": "#class-declaration" - }, - { - "include": "#interface-declaration" - }, - { - "include": "#enum-declaration" - }, - { - "include": "#namespace-declaration" - }, - { - "include": "#type-alias-declaration" - }, - { - "include": "#import-equals-declaration" - }, - { - "include": "#import-declaration" - }, - { - "include": "#export-declaration" - } - ] - }, - "control-statement": { - "patterns": [ - { - "include": "#switch-statement" - }, - { - "include": "#for-loop" - }, - { - "name": "keyword.control.trycatch.js.jsx", - "match": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", - "beginCaptures": { - "1": { - "name": "meta.definition.variable.js.jsx entity.name.function.js.jsx" - } - }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", - "patterns": [ - { - "include": "#var-single-variable-type-annotation" - } - ] - }, - { - "name": "meta.var-single-variable.expr.js.jsx", - "begin": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", - "beginCaptures": { - "1": { - "name": "meta.definition.variable.js.jsx variable.other.constant.js.jsx" - } - }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", - "patterns": [ - { - "include": "#var-single-variable-type-annotation" - } - ] - }, - { - "name": "meta.var-single-variable.expr.js.jsx", - "begin": "([_$[:alpha:]][_$[:alnum:]]*)", - "beginCaptures": { - "1": { - "name": "meta.definition.variable.js.jsx variable.other.readwrite.js.jsx" - } - }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", - "patterns": [ - { - "include": "#var-single-variable-type-annotation" - } - ] - } - ] - }, - "var-single-variable-type-annotation": { - "patterns": [ - { - "include": "#type-annotation" - }, - { - "include": "#string" - }, - { - "include": "#comment" - } - ] - }, - "destructuring-variable": { - "patterns": [ - { - "name": "meta.object-binding-pattern-variable.js.jsx", - "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", - "captures": { - "1": { - "name": "storage.modifier.js.jsx" - }, - "2": { - "name": "keyword.operator.rest.js.jsx" - }, - "3": { - "name": "entity.name.function.js.jsx variable.language.this.js.jsx" - }, - "4": { - "name": "entity.name.function.js.jsx" - }, - "5": { - "name": "keyword.operator.optional.js.jsx" - } - } - }, - { - "match": "(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" - }, - { - "name": "meta.definition.property.js.jsx variable.object.property.js.jsx", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - }, - { - "name": "keyword.operator.optional.js.jsx", - "match": "\\?" - } - ] - } - ] - }, - "variable-initializer": { - "patterns": [ - { - "begin": "(?)", - "captures": { - "1": { - "name": "storage.modifier.async.js.jsx" - }, - "2": { - "name": "variable.parameter.js.jsx" - } - } - }, - { - "name": "meta.arrow.js.jsx", - "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", - "beginCaptures": { - "1": { - "name": "storage.modifier.async.js.jsx" - } - }, - "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#type-parameters" - }, - { - "include": "#function-parameters" - }, - { - "include": "#arrow-return-type" - } - ] - }, - { - "name": "meta.arrow.js.jsx", - "begin": "=>", - "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.js.jsx" - } - }, - "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", - "patterns": [ - { - "include": "#decl-block" - }, - { - "include": "#expression" - } - ] - } - ] - }, - "indexer-declaration": { - "name": "meta.indexer.declaration.js.jsx", - "begin": "(?:(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", - "captures": { - "0": { - "name": "meta.object-literal.key.js.jsx" - }, - "1": { - "name": "entity.name.function.js.jsx" - } - } - }, - { - "name": "meta.object.member.js.jsx", - "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", - "captures": { - "0": { - "name": "meta.object-literal.key.js.jsx" - } - } - }, - { - "name": "meta.object.member.js.jsx", - "begin": "\\.\\.\\.", - "beginCaptures": { - "0": { - "name": "keyword.operator.spread.js.jsx" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "name": "meta.object.member.js.jsx", - "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", - "captures": { - "1": { - "name": "variable.other.readwrite.js.jsx" - } - } - }, - { - "name": "meta.object.member.js.jsx", - "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", - "end": "(?=,|\\}|$)", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "name": "meta.object.member.js.jsx", - "begin": ":", - "beginCaptures": { - "0": { - "name": "meta.object-literal.key.js.jsx punctuation.separator.key-value.js.jsx" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "include": "#punctuation-comma" - } - ] - }, - "ternary-expression": { - "begin": "(\\?)", - "beginCaptures": { - "0": { - "name": "keyword.operator.ternary.js.jsx" - } - }, - "end": "(:)", - "endCaptures": { - "0": { - "name": "keyword.operator.ternary.js.jsx" - } - }, - "patterns": [ - { - "include": "#expression" - } - ] - }, - "function-call": { - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", - "patterns": [ - { - "name": "meta.function-call.js.jsx", - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", - "patterns": [ - { - "include": "#literal" - }, - { - "include": "#support-objects" - }, - { - "include": "#object-identifiers" - }, - { - "include": "#punctuation-accessor" - }, - { - "name": "keyword.operator.expression.import.js.jsx", - "match": "(?![\\.\\$])\\bimport(?=\\s*[\\(]\\s*[\\\"\\'\\`])" - }, - { - "name": "entity.name.function.js.jsx", - "match": "([_$[:alpha:]][_$[:alnum:]]*)" - } - ] - }, - { - "include": "#comment" - }, - { - "name": "meta.type.parameters.js.jsx", - "begin": "\\<", - "beginCaptures": { - "0": { - "name": "punctuation.definition.typeparameters.begin.js.jsx" - } - }, - "end": "\\>", - "endCaptures": { - "0": { - "name": "punctuation.definition.typeparameters.end.js.jsx" - } - }, - "patterns": [ - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - { - "include": "#paren-expression" - } - ] - }, - "new-expr": { - "name": "new.expr.js.jsx", - "begin": "(?>=|>>>=|\\|=" - }, - { - "name": "keyword.operator.bitwise.shift.js.jsx", - "match": "<<|>>>|>>" - }, - { - "name": "keyword.operator.comparison.js.jsx", - "match": "===|!==|==|!=" - }, - { - "name": "keyword.operator.relational.js.jsx", - "match": "<=|>=|<>|<|>" - }, - { - "name": "keyword.operator.logical.js.jsx", - "match": "\\!|&&|\\|\\|" - }, - { - "name": "keyword.operator.bitwise.js.jsx", - "match": "\\&|~|\\^|\\|" - }, - { - "name": "keyword.operator.assignment.js.jsx", - "match": "\\=" - }, - { - "name": "keyword.operator.decrement.js.jsx", - "match": "--" - }, - { - "name": "keyword.operator.increment.js.jsx", - "match": "\\+\\+" - }, - { - "name": "keyword.operator.arithmetic.js.jsx", - "match": "%|\\*|/|-|\\+" - }, - { - "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", - "captures": { - "1": { - "name": "keyword.operator.arithmetic.js.jsx" - } - } - } - ] - }, - "typeof-operator": { - "name": "keyword.operator.expression.typeof.js.jsx", - "match": "(?=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "captures": { - "1": { - "name": "punctuation.accessor.js.jsx" - }, - "2": { - "name": "support.constant.dom.js.jsx" - }, - "3": { - "name": "support.variable.property.dom.js.jsx" - } - } - }, - { - "name": "support.class.node.js.jsx", - "match": "(?x)(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", - "captures": { - "1": { - "name": "punctuation.accessor.js.jsx" - }, - "2": { - "name": "entity.name.function.js.jsx" - } - } - }, - { - "match": "(\\.)\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", - "captures": { - "1": { - "name": "punctuation.accessor.js.jsx" - }, - "2": { - "name": "variable.other.constant.property.js.jsx" - } - } - }, - { - "match": "(\\.)\\s*([_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "punctuation.accessor.js.jsx" - }, - "2": { - "name": "variable.other.property.js.jsx" - } - } - }, - { - "name": "variable.other.constant.js.jsx", - "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" - }, - { - "name": "variable.other.readwrite.js.jsx", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - } - ] - }, - "object-identifiers": { - "patterns": [ - { - "name": "support.class.js.jsx", - "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\.\\s*prototype\\b(?!\\$))" - }, - { - "match": "(?x)(\\.)\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "punctuation.accessor.js.jsx" - }, - "2": { - "name": "variable.other.constant.object.property.js.jsx" - }, - "3": { - "name": "variable.other.object.property.js.jsx" - } - } - }, - { - "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "variable.other.constant.object.js.jsx" - }, - "2": { - "name": "variable.other.object.js.jsx" - } - } - } - ] - }, - "type-annotation": { - "patterns": [ - { - "name": "meta.type.annotation.js.jsx", - "begin": "(:)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.js.jsx" - } - }, - "end": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - }, - { - "name": "meta.type.annotation.js.jsx", - "begin": "(:)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.js.jsx" - } - }, - "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - } - ] - }, - "return-type": { - "patterns": [ - { - "name": "meta.return.type.js.jsx", - "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.js.jsx" - } - }, - "end": "(?|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", - "patterns": [ - { - "begin": "(?<=[:])(?=\\s*\\{)", - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "include": "#type-predicate-operator" - }, - { - "include": "#type" - } - ] - }, - "type-parameters": { - "name": "meta.type.parameters.js.jsx", - "begin": "(<)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.begin.js.jsx" - } - }, - "end": "(>)", - "endCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.end.js.jsx" - } - }, - "patterns": [ - { - "include": "#comment" - }, - { - "name": "storage.modifier.js.jsx", - "match": "(?)" - }, - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - "type": { - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#string" - }, - { - "include": "#numeric-literal" - }, - { - "include": "#type-primitive" - }, - { - "include": "#type-builtin-literals" - }, - { - "include": "#type-parameters" - }, - { - "include": "#type-tuple" - }, - { - "include": "#type-object" - }, - { - "include": "#type-operators" - }, - { - "include": "#type-fn-type-parameters" - }, - { - "include": "#type-paren-or-function-parameters" - }, - { - "include": "#type-function-return-type" - }, - { - "include": "#type-name" - } - ] - }, - "type-primitive": { - "name": "support.type.primitive.js.jsx", - "match": "(?)\n ))\n )\n )\n)", - "end": "(?<=\\))", - "patterns": [ - { - "include": "#function-parameters" - } - ] - } - ] - }, - "type-function-return-type": { - "patterns": [ - { - "name": "meta.type.function.return.js.jsx", - "begin": "(=>)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "storage.type.function.arrow.js.jsx" - } - }, - "end": "(?)(?]|//|$)", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - }, - { - "name": "meta.type.function.return.js.jsx", - "begin": "=>", - "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.js.jsx" - } - }, - "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - } - ] - }, - "type-function-return-type-core": { - "patterns": [ - { - "include": "#comment" - }, - { - "begin": "(?<==>)(?=\\s*\\{)", - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "include": "#type-predicate-operator" - }, - { - "include": "#type" - } - ] - }, - "type-operators": { - "patterns": [ - { - "include": "#typeof-operator" - }, - { - "begin": "([&|])(?=\\s*\\{)", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.js.jsx" - } - }, - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "begin": "[&|]", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.js.jsx" - } - }, - "end": "(?=\\S)" - }, - { - "name": "keyword.operator.expression.keyof.js.jsx", - "match": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", - "beginCaptures": { - "1": { - "name": "punctuation.definition.string.begin.js.jsx" - } - }, - "end": "(/)([gimuy]*)", - "endCaptures": { - "1": { - "name": "punctuation.definition.string.end.js.jsx" - }, - "2": { - "name": "keyword.other.js.jsx" - } - }, - "patterns": [ - { - "include": "#regexp" - } - ] - }, - { - "name": "string.regexp.js.jsx", - "begin": "(?\\s*$)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.comment.js.jsx" - } - }, - "end": "(?=^)", - "patterns": [ - { - "name": "meta.tag.js.jsx", - "begin": "(<)(reference|amd-dependency|amd-module)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.tag.directive.js.jsx" - }, - "2": { - "name": "entity.name.tag.directive.js.jsx" - } - }, - "end": "/>", - "endCaptures": { - "0": { - "name": "punctuation.definition.tag.directive.js.jsx" - } - }, - "patterns": [ - { - "name": "entity.other.attribute-name.directive.js.jsx", - "match": "path|types|no-default-lib|name" - }, - { - "name": "keyword.operator.assignment.js.jsx", - "match": "=" - }, - { - "include": "#string" - } - ] - } - ] - }, - "docblock": { - "patterns": [ - { - "match": "(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "constant.language.access-type.jsdoc" - } - } - }, - { - "match": "(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "entity.name.type.instance.jsdoc" - }, - "4": { - "name": "punctuation.definition.bracket.angle.begin.jsdoc" - }, - "5": { - "name": "constant.other.email.link.underline.jsdoc" - }, - "6": { - "name": "punctuation.definition.bracket.angle.end.jsdoc" - } - } - }, - { - "match": "(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "entity.name.type.instance.jsdoc" - }, - "4": { - "name": "keyword.operator.control.jsdoc" - }, - "5": { - "name": "entity.name.type.instance.jsdoc" - } - } - }, - { - "name": "meta.example.jsdoc", - "begin": "((@)example)\\s+", - "end": "(?=@|\\*/)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "patterns": [ - { - "match": "^\\s\\*\\s+" - }, - { - "contentName": "constant.other.description.jsdoc", - "begin": "\\G(<)caption(>)", - "beginCaptures": { - "0": { - "name": "entity.name.tag.inline.jsdoc" - }, - "1": { - "name": "punctuation.definition.bracket.angle.begin.jsdoc" - }, - "2": { - "name": "punctuation.definition.bracket.angle.end.jsdoc" - } - }, - "end": "()|(?=\\*/)", - "endCaptures": { - "0": { - "name": "entity.name.tag.inline.jsdoc" - }, - "1": { - "name": "punctuation.definition.bracket.angle.begin.jsdoc" - }, - "2": { - "name": "punctuation.definition.bracket.angle.end.jsdoc" - } - } - }, - { - "match": "[^\\s@*](?:[^*]|\\*[^/])*", - "captures": { - "0": { - "name": "source.embedded.js.jsx" - } - } - } - ] - }, - { - "match": "(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "constant.language.symbol-type.jsdoc" - } - } - }, - { - "match": "(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.link.underline.jsdoc" - }, - "4": { - "name": "entity.name.type.instance.jsdoc" - } - } - }, - { - "match": "(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.jsdoc" - } - } - }, - { - "match": "(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.jsdoc" - } - } - }, - { - "begin": "((@)typedef)\\s+(?={)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", - "patterns": [ - { - "include": "#jsdoctype" - }, - { - "name": "entity.name.type.instance.jsdoc", - "match": "(?:[^@\\s*/]|\\*[^/])+" - } - ] - }, - { - "begin": "((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", - "patterns": [ - { - "include": "#jsdoctype" - }, - { - "name": "variable.other.jsdoc", - "match": "([A-Za-z_$][\\w$.\\[\\]]*)" - }, - { - "name": "variable.other.jsdoc", - "match": "(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", - "captures": { - "1": { - "name": "punctuation.definition.optional-value.begin.bracket.square.jsdoc" - }, - "2": { - "name": "keyword.operator.assignment.jsdoc" - }, - "3": { - "name": "source.embedded.js.jsx" - }, - "4": { - "name": "punctuation.definition.optional-value.end.bracket.square.jsdoc" - }, - "5": { - "name": "invalid.illegal.syntax.jsdoc" - } - } - } - ] - }, - { - "begin": "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", - "patterns": [ - { - "include": "#jsdoctype" - } - ] - }, - { - "match": "(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "entity.name.type.instance.jsdoc" - } - } - }, - { - "contentName": "variable.other.jsdoc", - "begin": "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.jsdoc" - }, - "4": { - "name": "punctuation.definition.string.begin.jsdoc" - } - }, - "end": "(\\3)|(?=$|\\*/)", - "endCaptures": { - "0": { - "name": "variable.other.jsdoc" - }, - "1": { - "name": "punctuation.definition.string.end.jsdoc" - } - } - }, - { - "match": "((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.jsdoc" - } - } - }, - { - "name": "storage.type.class.jsdoc", - "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", - "captures": { - "1": { - "name": "punctuation.definition.block.tag.jsdoc" - } - } - }, - { - "include": "#inline-tags" - } - ] - }, - "brackets": { - "patterns": [ - { - "begin": "{", - "end": "}|(?=\\*/)", - "patterns": [ - { - "include": "#brackets" - } - ] - }, - { - "begin": "\\[", - "end": "\\]|(?=\\*/)", - "patterns": [ - { - "include": "#brackets" - } - ] - } - ] - }, - "inline-tags": { - "patterns": [ - { - "name": "constant.other.description.jsdoc", - "match": "(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))", - "captures": { - "1": { - "name": "punctuation.definition.bracket.square.begin.jsdoc" - }, - "2": { - "name": "punctuation.definition.bracket.square.end.jsdoc" - } - } - }, - { - "name": "entity.name.type.instance.jsdoc", - "begin": "({)((@)(?:link(?:code|plain)?|tutorial))\\s*", - "beginCaptures": { - "1": { - "name": "punctuation.definition.bracket.curly.begin.jsdoc" - }, - "2": { - "name": "storage.type.class.jsdoc" - }, - "3": { - "name": "punctuation.definition.inline.tag.jsdoc" - } - }, - "end": "}|(?=\\*/)", - "endCaptures": { - "0": { - "name": "punctuation.definition.bracket.curly.end.jsdoc" - } - }, - "patterns": [ - { - "match": "\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?", - "captures": { - "1": { - "name": "variable.other.link.underline.jsdoc" - }, - "2": { - "name": "punctuation.separator.pipe.jsdoc" - } - } - }, - { - "match": "\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?", - "captures": { - "1": { - "name": "variable.other.description.jsdoc" - }, - "2": { - "name": "punctuation.separator.pipe.jsdoc" - } - } - } - ] - } - ] - }, - "jsdoctype": { - "patterns": [ - { - "name": "invalid.illegal.type.jsdoc", - "match": "\\G{(?:[^}*]|\\*[^/}])+$" - }, - { - "contentName": "entity.name.type.instance.jsdoc", - "begin": "\\G({)", - "beginCaptures": { - "0": { - "name": "entity.name.type.instance.jsdoc" - }, - "1": { - "name": "punctuation.definition.bracket.curly.begin.jsdoc" - } - }, - "end": "((}))\\s*|(?=\\*/)", - "endCaptures": { - "1": { - "name": "entity.name.type.instance.jsdoc" - }, - "2": { - "name": "punctuation.definition.bracket.curly.end.jsdoc" - } - }, - "patterns": [ - { - "include": "#brackets" - } - ] - } - ] - }, - "jsx": { - "patterns": [ - { - "include": "#jsx-tag-without-attributes-in-expression" - }, - { - "include": "#jsx-tag-in-expression" - } - ] - }, - "jsx-tag-without-attributes-in-expression": { - "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", - "end": "(?!\\s*(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", - "patterns": [ - { - "include": "#jsx-tag-without-attributes" - } - ] - }, - "jsx-tag-without-attributes": { - "name": "meta.tag.without-attributes.js.jsx", - "begin": "(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?)", - "end": "()", - "beginCaptures": { - "1": { - "name": "punctuation.definition.tag.begin.js.jsx" - }, - "2": { - "name": "entity.name.tag.js.jsx" - }, - "3": { - "name": "support.class.component.js.jsx" - }, - "4": { - "name": "punctuation.definition.tag.end.js.jsx" - } - }, - "endCaptures": { - "1": { - "name": "punctuation.definition.tag.begin.js.jsx" - }, - "2": { - "name": "entity.name.tag.js.jsx" - }, - "3": { - "name": "support.class.component.js.jsx" - }, - "4": { - "name": "punctuation.definition.tag.end.js.jsx" - } - }, - "contentName": "meta.jsx.children.js.jsx", - "patterns": [ - { - "include": "#jsx-children" - } - ] - }, - "jsx-tag-in-expression": { - "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", - "end": "(/>)|(?:())", - "endCaptures": { - "0": { - "name": "meta.tag.js.jsx" - }, - "1": { - "name": "punctuation.definition.tag.end.js.jsx" - }, - "2": { - "name": "punctuation.definition.tag.begin.js.jsx" - }, - "3": { - "name": "entity.name.tag.js.jsx" - }, - "4": { - "name": "support.class.component.js.jsx" - }, - "5": { - "name": "punctuation.definition.tag.end.js.jsx" - } - }, - "patterns": [ - { - "include": "#jsx-tag" - } - ] - }, - "jsx-child-tag": { - "begin": "(?x)\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", - "end": "(/>)|(?:())", - "endCaptures": { - "0": { - "name": "meta.tag.js.jsx" - }, - "1": { - "name": "punctuation.definition.tag.end.js.jsx" - }, - "2": { - "name": "punctuation.definition.tag.begin.js.jsx" - }, - "3": { - "name": "entity.name.tag.js.jsx" - }, - "4": { - "name": "support.class.component.js.jsx" - }, - "5": { - "name": "punctuation.definition.tag.end.js.jsx" - } - }, - "patterns": [ - { - "include": "#jsx-tag" - } - ] - }, - "jsx-tag": { - "name": "meta.tag.js.jsx", - "begin": "(?x)\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", - "end": "(?=(/>)|(?:()))", - "patterns": [ - { - "begin": "(?x)\n (<)\\s*\n ((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.tag.begin.js.jsx" - }, - "2": { - "name": "entity.name.tag.js.jsx" - }, - "3": { - "name": "support.class.component.js.jsx" - } - }, - "end": "(?=[/]?>)", - "contentName": "meta.tag.attributes.js.jsx", - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#jsx-tag-attributes" - }, - { - "include": "#jsx-tag-attributes-illegal" - } - ] - }, - { - "begin": "(>)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.tag.end.js.jsx" - } - }, - "end": "(?=|/\\*|//)", - "captures": { - "1": { - "name": "entity.other.attribute-name.js.jsx" - } - } - }, - "jsx-tag-attribute-assignment": { - "name": "keyword.operator.assignment.js.jsx", - "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" - }, - "jsx-string-double-quoted": { - "name": "string.quoted.double.js.jsx", - "begin": "\"", - "end": "\"", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.js.jsx" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.js.jsx" - } - }, - "patterns": [ - { - "include": "#jsx-entities" - } - ] - }, - "jsx-string-single-quoted": { - "name": "string.quoted.single.js.jsx", - "begin": "'", - "end": "'", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.js.jsx" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.js.jsx" - } - }, - "patterns": [ - { - "include": "#jsx-entities" - } - ] - }, - "jsx-tag-attributes-illegal": { - "name": "invalid.illegal.attribute.js.jsx", - "match": "\\S+" - } - } -} \ No newline at end of file + "information_for_contributors": [ + "This file has been converted from https://github.com/Microsoft/TypeScript-TmLanguage/blob/master/TypeScriptReact.tmLanguage", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": + "https://github.com/Microsoft/TypeScript-TmLanguage/commit/8361b1a232501c67911c81a4664a9460d7922c6b", + "name": "JavaScript (with React support)", + "scopeName": "source.js.jsx", + "fileTypes": [".js", ".jsx", ".es6", ".mjs"], + "uuid": "805375ec-d614-41f5-8993-5843fe63ea82", + "patterns": [ + { + "include": "#directives" + }, + { + "include": "#statements" + }, + { + "name": "comment.line.shebang.ts", + "match": "\\A(#!).*(?=$)", + "captures": { + "1": { + "name": "punctuation.definition.comment.ts" + } + } + } + ], + "repository": { + "statements": { + "patterns": [ + { + "include": "#string" + }, + { + "include": "#template" + }, + { + "include": "#comment" + }, + { + "include": "#declaration" + }, + { + "include": "#control-statement" + }, + { + "include": "#after-operator-block-as-object-literal" + }, + { + "include": "#decl-block" + }, + { + "include": "#expression" + }, + { + "include": "#punctuation-semicolon" + } + ] + }, + "declaration": { + "patterns": [ + { + "include": "#decorator" + }, + { + "include": "#var-expr" + }, + { + "include": "#function-declaration" + }, + { + "include": "#class-declaration" + }, + { + "include": "#interface-declaration" + }, + { + "include": "#enum-declaration" + }, + { + "include": "#namespace-declaration" + }, + { + "include": "#type-alias-declaration" + }, + { + "include": "#import-equals-declaration" + }, + { + "include": "#import-declaration" + }, + { + "include": "#export-declaration" + } + ] + }, + "control-statement": { + "patterns": [ + { + "include": "#switch-statement" + }, + { + "include": "#for-loop" + }, + { + "name": "keyword.control.trycatch.js.jsx", + "match": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.js.jsx entity.name.function.js.jsx" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + }, + { + "name": "meta.var-single-variable.expr.js.jsx", + "begin": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.js.jsx variable.other.constant.js.jsx" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + }, + { + "name": "meta.var-single-variable.expr.js.jsx", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)", + "beginCaptures": { + "1": { + "name": + "meta.definition.variable.js.jsx variable.other.readwrite.js.jsx" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + } + ] + }, + "var-single-variable-type-annotation": { + "patterns": [ + { + "include": "#type-annotation" + }, + { + "include": "#string" + }, + { + "include": "#comment" + } + ] + }, + "destructuring-variable": { + "patterns": [ + { + "name": "meta.object-binding-pattern-variable.js.jsx", + "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.js.jsx" + }, + "2": { + "name": "keyword.operator.rest.js.jsx" + }, + "3": { + "name": "entity.name.function.js.jsx variable.language.this.js.jsx" + }, + "4": { + "name": "entity.name.function.js.jsx" + }, + "5": { + "name": "keyword.operator.optional.js.jsx" + } + } + }, + { + "match": + "(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + }, + { + "name": + "meta.definition.property.js.jsx variable.object.property.js.jsx", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.js.jsx", + "match": "\\?" + } + ] + } + ] + }, + "variable-initializer": { + "patterns": [ + { + "begin": "(?)", + "captures": { + "1": { + "name": "storage.modifier.async.js.jsx" + }, + "2": { + "name": "variable.parameter.js.jsx" + } + } + }, + { + "name": "meta.arrow.js.jsx", + "begin": + "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js.jsx" + } + }, + "end": + "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.js.jsx", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.js.jsx" + } + }, + "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "patterns": [ + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.js.jsx", + "begin": + "(?:(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "0": { + "name": "meta.object-literal.key.js.jsx" + }, + "1": { + "name": "entity.name.function.js.jsx" + } + } + }, + { + "name": "meta.object.member.js.jsx", + "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", + "captures": { + "0": { + "name": "meta.object-literal.key.js.jsx" + } + } + }, + { + "name": "meta.object.member.js.jsx", + "begin": "\\.\\.\\.", + "beginCaptures": { + "0": { + "name": "keyword.operator.spread.js.jsx" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.js.jsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", + "captures": { + "1": { + "name": "variable.other.readwrite.js.jsx" + } + } + }, + { + "name": "meta.object.member.js.jsx", + "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", + "end": "(?=,|\\}|$)", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.js.jsx", + "begin": ":", + "beginCaptures": { + "0": { + "name": + "meta.object-literal.key.js.jsx punctuation.separator.key-value.js.jsx" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "include": "#punctuation-comma" + } + ] + }, + "ternary-expression": { + "begin": "(\\?)", + "beginCaptures": { + "0": { + "name": "keyword.operator.ternary.js.jsx" + } + }, + "end": "(:)", + "endCaptures": { + "0": { + "name": "keyword.operator.ternary.js.jsx" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "function-call": { + "begin": + "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", + "end": + "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", + "patterns": [ + { + "name": "meta.function-call.js.jsx", + "begin": + "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", + "end": + "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", + "patterns": [ + { + "include": "#literal" + }, + { + "include": "#support-objects" + }, + { + "include": "#object-identifiers" + }, + { + "include": "#punctuation-accessor" + }, + { + "name": "keyword.operator.expression.import.js.jsx", + "match": "(?![\\.\\$])\\bimport(?=\\s*[\\(]\\s*[\\\"\\'\\`])" + }, + { + "name": "entity.name.function.js.jsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + { + "include": "#comment" + }, + { + "name": "meta.type.parameters.js.jsx", + "begin": "\\<", + "beginCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.begin.js.jsx" + } + }, + "end": "\\>", + "endCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + { + "include": "#paren-expression" + } + ] + }, + "new-expr": { + "name": "new.expr.js.jsx", + "begin": "(?>=|>>>=|\\|=" + }, + { + "name": "keyword.operator.bitwise.shift.js.jsx", + "match": "<<|>>>|>>" + }, + { + "name": "keyword.operator.comparison.js.jsx", + "match": "===|!==|==|!=" + }, + { + "name": "keyword.operator.relational.js.jsx", + "match": "<=|>=|<>|<|>" + }, + { + "name": "keyword.operator.logical.js.jsx", + "match": "\\!|&&|\\|\\|" + }, + { + "name": "keyword.operator.bitwise.js.jsx", + "match": "\\&|~|\\^|\\|" + }, + { + "name": "keyword.operator.assignment.js.jsx", + "match": "\\=" + }, + { + "name": "keyword.operator.decrement.js.jsx", + "match": "--" + }, + { + "name": "keyword.operator.increment.js.jsx", + "match": "\\+\\+" + }, + { + "name": "keyword.operator.arithmetic.js.jsx", + "match": "%|\\*|/|-|\\+" + }, + { + "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", + "captures": { + "1": { + "name": "keyword.operator.arithmetic.js.jsx" + } + } + } + ] + }, + "typeof-operator": { + "name": "keyword.operator.expression.typeof.js.jsx", + "match": "(?=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "support.constant.dom.js.jsx" + }, + "3": { + "name": "support.variable.property.dom.js.jsx" + } + } + }, + { + "name": "support.class.node.js.jsx", + "match": + "(?x)(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "entity.name.function.js.jsx" + } + } + }, + { + "match": "(\\.)\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "variable.other.constant.property.js.jsx" + } + } + }, + { + "match": "(\\.)\\s*([_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "variable.other.property.js.jsx" + } + } + }, + { + "name": "variable.other.constant.js.jsx", + "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" + }, + { + "name": "variable.other.readwrite.js.jsx", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "object-identifiers": { + "patterns": [ + { + "name": "support.class.js.jsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\.\\s*prototype\\b(?!\\$))" + }, + { + "match": + "(?x)(\\.)\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "variable.other.constant.object.property.js.jsx" + }, + "3": { + "name": "variable.other.object.property.js.jsx" + } + } + }, + { + "match": + "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "variable.other.constant.object.js.jsx" + }, + "2": { + "name": "variable.other.object.js.jsx" + } + } + } + ] + }, + "type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.js.jsx", + "begin": "(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js.jsx" + } + }, + "end": + "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + }, + { + "name": "meta.type.annotation.js.jsx", + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js.jsx" + } + }, + "end": + "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "return-type": { + "patterns": [ + { + "name": "meta.return.type.js.jsx", + "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js.jsx" + } + }, + "end": "(?|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "begin": "(?<=[:])(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-parameters": { + "name": "meta.type.parameters.js.jsx", + "begin": "(<)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.begin.js.jsx" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.js.jsx", + "match": "(?)" + }, + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "type": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#numeric-literal" + }, + { + "include": "#type-primitive" + }, + { + "include": "#type-builtin-literals" + }, + { + "include": "#type-parameters" + }, + { + "include": "#type-tuple" + }, + { + "include": "#type-object" + }, + { + "include": "#type-operators" + }, + { + "include": "#type-fn-type-parameters" + }, + { + "include": "#type-paren-or-function-parameters" + }, + { + "include": "#type-function-return-type" + }, + { + "include": "#type-name" + } + ] + }, + "type-primitive": { + "name": "support.type.primitive.js.jsx", + "match": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.js.jsx", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.js.jsx" + } + }, + "end": "(?)(?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.js.jsx", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.js.jsx" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.js.jsx" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.js.jsx" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.js.jsx", + "match": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.js.jsx" + } + }, + "end": "(/)([gimuy]*)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.js.jsx" + }, + "2": { + "name": "keyword.other.js.jsx" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "string.regexp.js.jsx", + "begin": + "(?\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.js.jsx" + } + }, + "end": "(?=^)", + "patterns": [ + { + "name": "meta.tag.js.jsx", + "begin": "(<)(reference|amd-dependency|amd-module)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.directive.js.jsx" + }, + "2": { + "name": "entity.name.tag.directive.js.jsx" + } + }, + "end": "/>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.directive.js.jsx" + } + }, + "patterns": [ + { + "name": "entity.other.attribute-name.directive.js.jsx", + "match": "path|types|no-default-lib|name" + }, + { + "name": "keyword.operator.assignment.js.jsx", + "match": "=" + }, + { + "include": "#string" + } + ] + } + ] + }, + "docblock": { + "patterns": [ + { + "match": "(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.access-type.jsdoc" + } + } + }, + { + "match": + "(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "5": { + "name": "constant.other.email.link.underline.jsdoc" + }, + "6": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": + "(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "keyword.operator.control.jsdoc" + }, + "5": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "name": "meta.example.jsdoc", + "begin": "((@)example)\\s+", + "end": "(?=@|\\*/)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "patterns": [ + { + "match": "^\\s\\*\\s+" + }, + { + "contentName": "constant.other.description.jsdoc", + "begin": "\\G(<)caption(>)", + "beginCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + }, + "end": "()|(?=\\*/)", + "endCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "[^\\s@*](?:[^*]|\\*[^/])*", + "captures": { + "0": { + "name": "source.embedded.js.jsx" + } + } + } + ] + }, + { + "match": + "(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.symbol-type.jsdoc" + } + } + }, + { + "match": + "(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.link.underline.jsdoc" + }, + "4": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "match": + "(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "match": + "(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "begin": "((@)typedef)\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "entity.name.type.instance.jsdoc", + "match": "(?:[^@\\s*/]|\\*[^/])+" + } + ] + }, + { + "begin": + "((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "variable.other.jsdoc", + "match": "([A-Za-z_$][\\w$.\\[\\]]*)" + }, + { + "name": "variable.other.jsdoc", + "match": + "(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", + "captures": { + "1": { + "name": + "punctuation.definition.optional-value.begin.bracket.square.jsdoc" + }, + "2": { + "name": "keyword.operator.assignment.jsdoc" + }, + "3": { + "name": "source.embedded.js.jsx" + }, + "4": { + "name": + "punctuation.definition.optional-value.end.bracket.square.jsdoc" + }, + "5": { + "name": "invalid.illegal.syntax.jsdoc" + } + } + } + ] + }, + { + "begin": + "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + } + ] + }, + { + "match": + "(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "contentName": "variable.other.jsdoc", + "begin": "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + }, + "4": { + "name": "punctuation.definition.string.begin.jsdoc" + } + }, + "end": "(\\3)|(?=$|\\*/)", + "endCaptures": { + "0": { + "name": "variable.other.jsdoc" + }, + "1": { + "name": "punctuation.definition.string.end.jsdoc" + } + } + }, + { + "match": + "((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "name": "storage.type.class.jsdoc", + "match": + "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", + "captures": { + "1": { + "name": "punctuation.definition.block.tag.jsdoc" + } + } + }, + { + "include": "#inline-tags" + } + ] + }, + "brackets": { + "patterns": [ + { + "begin": "{", + "end": "}|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + }, + { + "begin": "\\[", + "end": "\\]|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "inline-tags": { + "patterns": [ + { + "name": "constant.other.description.jsdoc", + "match": "(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))", + "captures": { + "1": { + "name": "punctuation.definition.bracket.square.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.square.end.jsdoc" + } + } + }, + { + "name": "entity.name.type.instance.jsdoc", + "begin": "({)((@)(?:link(?:code|plain)?|tutorial))\\s*", + "beginCaptures": { + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + }, + "2": { + "name": "storage.type.class.jsdoc" + }, + "3": { + "name": "punctuation.definition.inline.tag.jsdoc" + } + }, + "end": "}|(?=\\*/)", + "endCaptures": { + "0": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "match": "\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.link.underline.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + }, + { + "match": "\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.description.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + } + ] + } + ] + }, + "jsdoctype": { + "patterns": [ + { + "name": "invalid.illegal.type.jsdoc", + "match": "\\G{(?:[^}*]|\\*[^/}])+$" + }, + { + "contentName": "entity.name.type.instance.jsdoc", + "begin": "\\G({)", + "beginCaptures": { + "0": { + "name": "entity.name.type.instance.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + } + }, + "end": "((}))\\s*|(?=\\*/)", + "endCaptures": { + "1": { + "name": "entity.name.type.instance.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "jsx": { + "patterns": [ + { + "include": "#jsx-tag-without-attributes-in-expression" + }, + { + "include": "#jsx-tag-in-expression" + } + ] + }, + "jsx-tag-without-attributes-in-expression": { + "begin": + "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", + "end": "(?!\\s*(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", + "patterns": [ + { + "include": "#jsx-tag-without-attributes" + } + ] + }, + "jsx-tag-without-attributes": { + "name": "meta.tag.without-attributes.js.jsx", + "begin": "(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?)", + "end": "()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "2": { + "name": "entity.name.tag.js.jsx" + }, + "3": { + "name": "support.class.component.js.jsx" + }, + "4": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "2": { + "name": "entity.name.tag.js.jsx" + }, + "3": { + "name": "support.class.component.js.jsx" + }, + "4": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "contentName": "meta.jsx.children.js.jsx", + "patterns": [ + { + "include": "#jsx-children" + } + ] + }, + "jsx-tag-in-expression": { + "begin": + "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "end": "(/>)|(?:())", + "endCaptures": { + "0": { + "name": "meta.tag.js.jsx" + }, + "1": { + "name": "punctuation.definition.tag.end.js.jsx" + }, + "2": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "3": { + "name": "entity.name.tag.js.jsx" + }, + "4": { + "name": "support.class.component.js.jsx" + }, + "5": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#jsx-tag" + } + ] + }, + "jsx-child-tag": { + "begin": + "(?x)\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "end": "(/>)|(?:())", + "endCaptures": { + "0": { + "name": "meta.tag.js.jsx" + }, + "1": { + "name": "punctuation.definition.tag.end.js.jsx" + }, + "2": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "3": { + "name": "entity.name.tag.js.jsx" + }, + "4": { + "name": "support.class.component.js.jsx" + }, + "5": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#jsx-tag" + } + ] + }, + "jsx-tag": { + "name": "meta.tag.js.jsx", + "begin": + "(?x)\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "end": "(?=(/>)|(?:()))", + "patterns": [ + { + "begin": + "(?x)\n (<)\\s*\n ((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "2": { + "name": "entity.name.tag.js.jsx" + }, + "3": { + "name": "support.class.component.js.jsx" + } + }, + "end": "(?=[/]?>)", + "contentName": "meta.tag.attributes.js.jsx", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#jsx-tag-attributes" + }, + { + "include": "#jsx-tag-attributes-illegal" + } + ] + }, + { + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "end": "(?=|/\\*|//)", + "captures": { + "1": { + "name": "entity.other.attribute-name.js.jsx" + } + } + }, + "jsx-tag-attribute-assignment": { + "name": "keyword.operator.assignment.js.jsx", + "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" + }, + "jsx-string-double-quoted": { + "name": "string.quoted.double.js.jsx", + "begin": "\"", + "end": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js.jsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-string-single-quoted": { + "name": "string.quoted.single.js.jsx", + "begin": "'", + "end": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js.jsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-tag-attributes-illegal": { + "name": "invalid.illegal.attribute.js.jsx", + "match": "\\S+" + } + } +} diff --git a/extensions/less/syntaxes/less.tmLanguage.json b/extensions/less/syntaxes/less.tmLanguage.json index f2265b2922..6b0e5814e1 100644 --- a/extensions/less/syntaxes/less.tmLanguage.json +++ b/extensions/less/syntaxes/less.tmLanguage.json @@ -1,550 +1,547 @@ { - "information_for_contributors": [ - "This file has been converted from https://github.com/atom/language-less/blob/master/grammars/less.cson", - "If you want to provide a fix or improvement, please create a pull request against the original repository.", - "Once accepted there, we are happy to receive an update request." - ], - "version": "https://github.com/atom/language-less/commit/b5b3438916bd617fe2b61e090b438c3e27034fc1", - "name": "Less", - "scopeName": "source.css.less", - "fileTypes": [ - "less", - "less.erb", - "rc", - "gtkrc", - "gtkrc-2.0", - "themerc" - ], - "patterns": [ - { - "include": "#strings" - }, - { - "captures": { - "1": { - "name": "entity.other.attribute-name.class.mixin.css" - } - }, - "match": "(\\.[_a-zA-Z][a-zA-Z0-9_-]*(?=\\())" - }, - { - "captures": { - "1": { - "name": "entity.other.attribute-name.class.css" - }, - "2": { - "name": "punctuation.definition.entity.css" - }, - "4": { - "name": "variable.other.interpolation.less" - } - }, - "match": "((\\.)([_a-zA-Z]|(@{[a-zA-Z0-9_-]+}))[a-zA-Z0-9_-]*)" - }, - { - "captures": { - "0": { - "name": "entity.other.attribute-name.parent-selector.css" - }, - "1": { - "name": "punctuation.definition.entity.css" - } - }, - "match": "(&)[a-zA-Z0-9_-]*" - }, - { - "begin": "(format|local|url|attr|counter|counters)\\s*(\\()", - "beginCaptures": { - "1": { - "name": "support.function.misc.css" - }, - "2": { - "name": "punctuation.section.function.css" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.section.function.css" - } - }, - "patterns": [ - { - "begin": "'", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.css" - } - }, - "end": "'", - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.css" - } - }, - "name": "string.quoted.single.css", - "patterns": [ - { - "match": "\\\\.", - "name": "constant.character.escape.css" - } - ] - }, - { - "begin": "\"", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.css" - } - }, - "end": "\"", - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.css" - } - }, - "name": "string.quoted.double.css", - "patterns": [ - { - "match": "\\\\(\\d{1,6}|.)", - "name": "constant.character.escape.css" - } - ] - }, - { - "match": "[^'\") \\t]+", - "name": "variable.parameter.misc.css" - } - ] - }, - { - "match": "(#)([0-9a-fA-F]{3}|[0-9a-fA-F]{6})\\b(?!.*?(?(['\"])(?:[^\\\\]|\\\\.)*?(\\6)))))?\\s*(\\])", - "name": "meta.attribute-selector.css" - }, - { - "begin": "((@)import\\b)", - "beginCaptures": { - "1": { - "name": "keyword.control.at-rule.import.less" - }, - "2": { - "name": "punctuation.definition.keyword.less" - } - }, - "end": ";", - "endCaptures": { - "0": { - "name": "punctuation.terminator.rule.css" - } - }, - "name": "meta.at-rule.import.css", - "patterns": [ - { - "match": "(?<=\\(|,|\\s)\\b(reference|optional|once|multiple|less|inline)\\b(?=\\)|,)", - "name": "keyword.control.import.option.less" - }, - { - "include": "#brace_round" - }, - { - "include": "source.css#commas" - }, - { - "include": "#strings" - } - ] - }, - { - "captures": { - "1": { - "name": "keyword.control.at-rule.fontface.css" - }, - "2": { - "name": "punctuation.definition.keyword.css" - } - }, - "match": "^\\s*((@)font-face\\b)", - "name": "meta.at-rule.fontface.css" - }, - { - "captures": { - "1": { - "name": "keyword.control.at-rule.media.css" - }, - "2": { - "name": "punctuation.definition.keyword.css" - } - }, - "match": "^\\s*((@)media\\b)", - "name": "meta.at-rule.media.css" - }, - { - "include": "source.css#media-features" - }, - { - "match": "\\b(tv|tty|screen|projection|print|handheld|embossed|braille|aural|all)\\b", - "name": "support.constant.media-type.media.css" - }, - { - "match": "\\b(portrait|landscape)\\b", - "name": "support.constant.property-value.media-property.media.css" - }, - { - "captures": { - "1": { - "name": "support.function.less" - } - }, - "match": "(\\.[a-zA-Z0-9_-]+)\\s*(;|\\()" - }, - { - "begin": "(^[ \\t]+)?(?=//)", - "beginCaptures": { - "1": { - "name": "punctuation.whitespace.comment.leading.less" - } - }, - "end": "(?!\\G)", - "patterns": [ - { - "begin": "//", - "beginCaptures": { - "0": { - "name": "punctuation.definition.comment.less" - } - }, - "end": "\\n", - "name": "comment.line.double-slash.less" - } - ] - }, - { - "match": "(@|\\-\\-)[\\w-]+(?=\\s*)", - "name": "variable.other.less", - "captures": { - "1": { - "name": "punctuation.definition.variable.less" - } - } - }, - { - "include": "#variable_interpolation" - }, - { - "begin": "{", - "beginCaptures": { - "0": { - "name": "punctuation.section.property-list.begin.bracket.curly.css" - } - }, - "end": "}", - "endCaptures": { - "0": { - "name": "punctuation.section.property-list.end.bracket.curly.css" - } - }, - "name": "meta.property-list.css", - "patterns": [ - { - "include": "source.css#pseudo-elements" - }, - { - "include": "source.css#pseudo-classes" - }, - { - "include": "source.css#tag-names" - }, - { - "include": "source.css#commas" - }, - { - "include": "#variable_interpolation" - }, - { - "include": "source.css#property-names" - }, - { - "include": "#property_values" - }, - { - "include": "$self" - } - ] - }, - { - "match": "\\!\\s*important", - "name": "keyword.other.important.css" - }, - { - "match": "\\*|\\/|\\-|\\+|~|=|<=|>=|<|>", - "name": "keyword.operator.less" - }, - { - "match": "\\b(not|and|when)\\b", - "name": "keyword.control.logical.operator.less" - }, - { - "include": "source.css#tag-names" - }, - { - "match": "(?(['\"])(?:[^\\\\]|\\\\.)*?(\\6)))))?\\s*(\\])", + "name": "meta.attribute-selector.css" + }, + { + "begin": "((@)import\\b)", + "beginCaptures": { + "1": { + "name": "keyword.control.at-rule.import.less" + }, + "2": { + "name": "punctuation.definition.keyword.less" + } + }, + "end": ";", + "endCaptures": { + "0": { + "name": "punctuation.terminator.rule.css" + } + }, + "name": "meta.at-rule.import.css", + "patterns": [ + { + "match": + "(?<=\\(|,|\\s)\\b(reference|optional|once|multiple|less|inline)\\b(?=\\)|,)", + "name": "keyword.control.import.option.less" + }, + { + "include": "#brace_round" + }, + { + "include": "source.css#commas" + }, + { + "include": "#strings" + } + ] + }, + { + "captures": { + "1": { + "name": "keyword.control.at-rule.fontface.css" + }, + "2": { + "name": "punctuation.definition.keyword.css" + } + }, + "match": "^\\s*((@)font-face\\b)", + "name": "meta.at-rule.fontface.css" + }, + { + "captures": { + "1": { + "name": "keyword.control.at-rule.media.css" + }, + "2": { + "name": "punctuation.definition.keyword.css" + } + }, + "match": "^\\s*((@)media\\b)", + "name": "meta.at-rule.media.css" + }, + { + "include": "source.css#media-features" + }, + { + "match": "\\b(tv|tty|screen|projection|print|handheld|embossed|braille|aural|all)\\b", + "name": "support.constant.media-type.media.css" + }, + { + "match": "\\b(portrait|landscape)\\b", + "name": "support.constant.property-value.media-property.media.css" + }, + { + "captures": { + "1": { + "name": "support.function.less" + } + }, + "match": "(\\.[a-zA-Z0-9_-]+)\\s*(;|\\()" + }, + { + "begin": "(^[ \\t]+)?(?=//)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.less" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "//", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.less" + } + }, + "end": "\\n", + "name": "comment.line.double-slash.less" + } + ] + }, + { + "match": "(@|\\-\\-)[\\w-]+(?=\\s*)", + "name": "variable.other.less", + "captures": { + "1": { + "name": "punctuation.definition.variable.less" + } + } + }, + { + "include": "#variable_interpolation" + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.property-list.begin.bracket.curly.css" + } + }, + "end": "}", + "endCaptures": { + "0": { + "name": "punctuation.section.property-list.end.bracket.curly.css" + } + }, + "name": "meta.property-list.css", + "patterns": [ + { + "include": "source.css#pseudo-elements" + }, + { + "include": "source.css#pseudo-classes" + }, + { + "include": "source.css#tag-names" + }, + { + "include": "source.css#commas" + }, + { + "include": "#variable_interpolation" + }, + { + "include": "source.css#property-names" + }, + { + "include": "#property_values" + }, + { + "include": "$self" + } + ] + }, + { + "match": "\\!\\s*important", + "name": "keyword.other.important.css" + }, + { + "match": "\\*|\\/|\\-|\\+|~|=|<=|>=|<|>", + "name": "keyword.operator.less" + }, + { + "match": "\\b(not|and|when)\\b", + "name": "keyword.control.logical.operator.less" + }, + { + "include": "source.css#tag-names" + }, + { + "match": "(?|~$\\\\])([\\?])(?![#\\-:!?.@*/&%^+<=>|~$\\\\])", + "end": "(?=[\\)])", + "beginCaptures": { + "1": { "name": "keyword.control message.error variable.interpolation" } + }, + "patterns": [ + { + "match": "(?:\\b|[[:space:]]+)([?])(?:\\b|[[:space:]]+)", + "name": "keyword.control message.error variable.interpolation" + }, + { "include": "#value-expression" } + ] + }, + "extension-node": { + "begin": "(?=\\[(%{1,3})[[:space:]]*[[:alpha:]])", + "end": "\\]", + "patterns": [ + { + "begin": "\\[(%{1,3})", + "end": "(?=[^_\\.'[:word:]])", + "beginCaptures": { + "1": { "name": "keyword.control.less" } + }, + "patterns": [{ "include": "#attribute-identifier" }] + }, + { "include": "#attribute-payload" } + ] + }, + "jsx": { + "patterns": [{ "include": "#jsx-head" }, { "include": "#jsx-tail" }] + }, + "jsx-attributes": { + "patterns": [ + { + "begin": "\\b([[:lower:]][[:word:]]*)\\b[[:space:]]*(=)", + "end": "(?[:lower:]])", + "comment": "meta.separator", + "beginCaptures": { + "1": { + "name": + "markup.inserted constant.language support.property-value entity.name.filename" + }, + "2": { "name": "keyword.control.less" } + }, + "patterns": [{ "include": "#value-expression-atomic-with-paths" }] + }, + { + "match": "(\\b([[:lower:]][[:word:]]*)\\b[[:space:]]*+)", + "captures": { + "1": { "comment": "meta.separator" }, + "2": { + "name": + "markup.inserted constant.language support.property-value entity.name.filename" + } + } + } + ] + }, + "jsx-body": { + "begin": "((>))", + "end": "(?=))|(?=])[[:space:]]*+", + "comment": "meta.separator", + "patterns": [ + { "include": "#module-path-simple" }, + { + "match": "\\b[[:lower:]][[:word:]]*\\b", + "name": "entity.name.tag.inline.any.html" + } + ] + }, + { "include": "#jsx-attributes" }, + { "include": "#jsx-body" } + ] + }, + "jsx-tail": { + "begin": "\\G(/>)|()", + "applyEndPatternLast": true, + "comment": "meta.separator", + "beginCaptures": { + "1": { "name": "punctuation.definition.tag.end.js" }, + "2": { "name": "punctuation.definition.tag.begin.js" } + }, + "endCaptures": { + "1": { "name": "punctuation.definition.tag.end.js" } + }, + "patterns": [ + { "include": "#module-path-simple" }, + { + "match": "\\b[[:lower:]][[:word:]]*\\b", + "name": "entity.name.tag.inline.any.html" + } + ] + }, + "module-name-extended": { + "patterns": [ + { "include": "#module-name-simple" }, + { + "begin": "([\\(])", + "end": "([\\)])", + "captures": { + "1": { + "name": + "entity.other.attribute-name.css constant.language constant.numeric" + } + }, + "patterns": [{ "include": "#module-path-extended" }] + } + ] + }, + "module-name-simple": { + "match": "\\b[[:upper:]][[:word:]]*\\b", + "name": "support.class entity.name.class" + }, + "module-path-extended": { + "patterns": [ + { "include": "#module-name-extended" }, + { "include": "#comment" }, + { + "comment": "NOTE: end early to avoid too much reparsing", + "begin": "([\\.])", + "end": "(?<=[[:word:]\\)])|(?=[^\\.[:upper:]/])", + "beginCaptures": { + "1": { "name": "keyword.control.less" } + }, + "patterns": [ + { + "begin": "(?<=[\\.])", + "end": "(?<=[[:word:]\\)])|(?=[^\\.[:upper:]/])", + "patterns": [ + { "include": "#comment" }, + { "include": "#module-name-extended" } + ] + } + ] + } + ] + }, + "module-path-extended-prefix": { + "begin": "(?=\\b[[:upper:]])", + "end": + "([\\.])|(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "endCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [{ "include": "#module-path-extended" }] + }, + "module-path-simple": { + "patterns": [ + { "include": "#module-name-simple" }, + { "include": "#comment" }, + { + "comment": "NOTE: end early to avoid too much reparsing", + "begin": "([\\.])", + "end": "(?<=[[:word:]\\)])|(?=[^\\.[:upper:]/])", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [ + { + "begin": "(?<=[\\.])", + "end": "(?<=[[:word:]\\)])|(?=[^\\.[:upper:]/])", + "patterns": [ + { "include": "#comment" }, + { "include": "#module-name-simple" } + ] + } + ] + } + ] + }, + "module-path-simple-prefix": { + "begin": "(?=\\b[[:upper:]])", + "end": + "([\\.])|(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "endCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [{ "include": "#module-path-simple" }] + }, + "module-item-class-type": { + "comment": "FIXME: proper parsing", + "begin": "\\b(class)\\b", + "end": + "(;)|(?=}|\\b(and|class|constraint|exception|external|include|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "keyword.other" } + }, + "endCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [ + { + "begin": "(?:\\G|^)[[:space:]]*\\b(type)\\b", + "end": "(?==)", + "beginCaptures": { + "1": { + "name": + "entity.other.attribute-name.css constant.language constant.numeric" + } + }, + "patterns": [{ "include": "#module-item-type-bind-name-tyvars" }] + }, + { + "begin": "(=)", + "end": "(?=;)", + "beginCaptures": { + "1": { "name": "keyword.control.less" } + }, + "patterns": [ + { "include": "#attribute" }, + { "include": "#comment" }, + { "include": "#class-item-inherit" }, + { "include": "#class-item-method" } + ] + } + ] + }, + "module-item-exception": { + "begin": "\\b(exception)\\b", + "end": + "(;)|(?=}|\\b(class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "keyword.other" } + }, + "endCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [{ "include": "#module-item-type-bind-body-item" }] + }, + "module-item-external": { + "begin": "\\b(external)\\b", + "end": + "(;)|(?=}|\\b(class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "storage.type" } + }, + "endCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [ + { "include": "#module-item-let-value-bind-name-or-pattern" }, + { "include": "#module-item-let-value-bind-type" }, + { + "begin": "(=)", + "end": + "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "keyword.control.less" } + }, + "patterns": [ + { "include": "#attribute" }, + { + "begin": "\"", + "end": "\"", + "name": "string.double string.regexp", + "patterns": [ + { "include": "#value-literal-string-escape" }, + { + "match": "(?:(%)(.*?)|(caml.*?))(?=\"|(?:[^\\\\\\n]$))", + "captures": { + "1": { + "name": + "entity.other.attribute-name.css constant.language constant.numeric" + }, + "2": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + }, + "3": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + } + } + ] + } + ] + } + ] + }, + "module-item-include": { + "begin": "\\b(include)\\b", + "end": + "(;)|(?=}|\\b(class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|type|val)\\b)", + "beginCaptures": { + "1": { "name": "keyword.control.include" } + }, + "endCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [{ "include": "#signature-expression" }] + }, + "module-item-let": { + "begin": "\\b(let)\\b", + "end": + "(;)|(?=}|\\b(class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "storage.type" } + }, + "endCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [ + { "include": "#module-item-let-module" }, + { "include": "#module-item-let-value" } + ] + }, + "module-item-let-module": { + "begin": "(?:\\G|^)[[:space:]]*\\b(module)\\b", + "end": + "(?=[;}]|\\b(class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|type|val|with)\\b)", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.control storage.type message.error" + } + }, + "patterns": [ + { "include": "#comment" }, + { "include": "#module-item-let-module-and" }, + { "include": "#module-item-let-module-rec" }, + { "include": "#module-item-let-module-bind-name-params-type-body" } + ] + }, + "module-item-let-module-and": { + "begin": "\\b(and)\\b", + "end": + "(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "storage.type" } + }, + "patterns": [{ "include": "#module-item-let-module-bind-name-params-type-body" }] + }, + "module-item-let-module-bind-body": { + "begin": "(=>?)", + "end": + "(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "keyword.control.less" } + }, + "patterns": [{ "include": "#structure-expression" }] + }, + "module-item-let-module-bind-name-params": { + "begin": "\\b([[:upper:]][[:word:]]*)\\b", + "end": + "(?=[;:}=]|\\b(class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "support.class entity.name.class" } + }, + "patterns": [{ "include": "#comment" }, { "include": "#module-item-let-module-param" }] + }, + "module-item-let-module-bind-name-params-type-body": { + "begin": "(?:\\G|^)", + "end": + "(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "patterns": [ + { "include": "#comment" }, + { "include": "#module-item-let-module-bind-name-params" }, + { "include": "#module-item-let-module-bind-type" }, + { "include": "#module-item-let-module-bind-body" } + ] + }, + "module-item-let-module-bind-type": { + "begin": "(:)", + "end": + "(?=[;}=]|\\b(and|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|rec|type|val)\\b)", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [{ "include": "#signature-expression" }] + }, + "module-item-let-module-param": { + "begin": "(?=\\()", + "end": "\\)", + "patterns": [ + { + "begin": "\\(", + "end": "(?=[:])", + "patterns": [{ "include": "#comment" }, { "include": "#module-name-simple" }] + }, + { + "begin": "(:)", + "end": "(?=\\))", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [{ "include": "#signature-expression" }] + } + ] + }, + "module-item-let-module-rec": { + "begin": "(?:\\G|^)[[:space:]]*\\b(rec)\\b", + "end": + "(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "keyword.control storage.modifier.rec" } + }, + "patterns": [{ "include": "#module-item-let-module-bind-name-params-type-body" }] + }, + "module-item-let-value": { + "patterns": [ + { "include": "#module-item-let-value-and" }, + { "include": "#module-item-let-value-rec" }, + { "include": "#module-item-let-value-bind-name-params-type-body" } + ] + }, + "module-item-let-value-and": { + "begin": "\\b(and)\\b", + "end": + "(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "storage.type" } + }, + "patterns": [{ "include": "#module-item-let-value-bind-name-params-type-body" }] + }, + "module-item-let-value-bind-body": { + "begin": "(=>?)", + "end": + "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "keyword.control.less" } + }, + "patterns": [{ "include": "#value-expression" }] + }, + "module-item-let-value-bind-name-or-pattern": { + "begin": + "(?<=[^[:word:]]and|^and|[^[:word:]]external|^external|[^[:word:]]let|^let|[^[:word:]]method|^method|[^[:word:]]rec|^rec)[[:space:]]*", + "end": + "(?<=[^[:space:]])|(?=[[:space:]]|[;:}=]|\\b(and|as|class|constraint|exception|external|for|include|inherit|let|method|module|nonrec|open|private|rec|switch|try|type|val|while|with)\\b)", + "patterns": [ + { "include": "#comment" }, + { + "match": "\\b(?:([_][[:word:]]+)|([[:lower:]][[:word:]]*))\\b", + "captures": { + "1": { "name": "comment" }, + "2": { "name": "entity.name.function" } + } + }, + { "include": "#module-item-let-value-bind-parens-params" }, + { "include": "#pattern" } + ] + }, + "module-item-let-value-bind-name-params-type-body": { + "begin": + "(?<=[^[:word:]]and|^and|[^[:word:]]external|^external|[^[:word:]]let|^let|[^[:word:]]method|^method|[^[:word:]]rec|^rec)", + "end": + "(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "patterns": [ + { + "comment": "FIXME; hack for punned arguments", + "begin": "(::)", + "end": "(?<=[[:space:]])", + "beginCaptures": { + "1": { "name": "keyword.control" } + }, + "patterns": [ + { "include": "#pattern" }, + { + "begin": "(=)", + "end": "(\\?)|(?<=[^[:space:]=][[:space:]])(?=[[:space:]]*+[^\\.])", + "beginCaptures": { + "1": { + "name": "markup.inserted keyword.control.less message.error" + } + }, + "endCaptures": { + "1": { "name": "storage.type" } + }, + "patterns": [{ "include": "#value-expression-atomic-with-paths" }] + } + ] + }, + { "include": "#module-item-let-value-bind-name-or-pattern" }, + { "include": "#module-item-let-value-bind-params-type" }, + { "include": "#module-item-let-value-bind-type" }, + { "include": "#module-item-let-value-bind-body" } + ] + }, + "module-item-let-value-bind-params-type": { + "begin": "(?=[^[:space:]:=])", + "end": + "(?=[;}=]|\\b(class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "patterns": [ + { "include": "#comment" }, + { "include": "#module-item-let-value-param" }, + { + "begin": "(?]|[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|val|with)\\b)", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [ + { + "begin": "\\b(type)\\b", + "end": "([\\.])", + "beginCaptures": { + "1": { + "name": + "entity.other.attribute-name.css constant.language constant.numeric" + } + }, + "endCaptures": { + "1": { "name": "entity.name.function" } + }, + "patterns": [{ "include": "#pattern-variable" }] + }, + { "include": "#type-expression" } + ] + }, + "module-item-let-value-param": { + "patterns": [ + { "include": "#module-item-let-value-param-label" }, + { "include": "#module-item-let-value-param-type" }, + { "include": "#module-item-let-value-param-module" }, + { "include": "#pattern" } + ] + }, + "module-item-let-value-param-label": { + "patterns": [ + { + "begin": "(\\b[[:lower:]][[:word:]]*\\b)?[[:space:]]*(::)", + "end": "(?<=[[:space:]])", + "beginCaptures": { + "1": { + "name": + "markup.inserted constant.language support.property-value entity.name.filename" + }, + "2": { "name": "keyword.control" } + }, + "patterns": [ + { "include": "#pattern" }, + { + "begin": "(=)", + "end": "(\\?)|(?<=[^[:space:]=][[:space:]])(?=[[:space:]]*+[^\\.])", + "beginCaptures": { + "1": { + "name": "markup.inserted keyword.control.less message.error" + } + }, + "endCaptures": { + "1": { "name": "storage.type" } + }, + "patterns": [{ "include": "#value-expression-atomic-with-paths" }] + } + ] + } + ] + }, + "module-item-let-value-param-module": { + "comment": "FIXME: merge with pattern-parens", + "begin": "\\([[:space:]]*(?=\\b(module)\\b)", + "end": "\\)", + "patterns": [ + { + "begin": "\\b(module)\\b", + "end": "(?=\\))", + "beginCaptures": { + "1": { "name": "keyword.other message.error" } + }, + "patterns": [ + { + "match": "\\b[[:upper:]][[:word:]]*\\b", + "name": "support.class entity.name.class" + } + ] + } + ] + }, + "module-item-let-value-param-type": { + "comment": "FIXME: merge with pattern-parens", + "begin": "\\((?=\\b(type)\\b)", + "end": "\\)", + "patterns": [ + { + "begin": "\\b(type)\\b", + "end": "(?=\\))", + "beginCaptures": { + "1": { + "name": + "entity.other.attribute-name.css constant.language constant.numeric" + } + }, + "patterns": [{ "include": "#pattern-variable" }] + } + ] + }, + "module-item-let-value-rec": { + "begin": "(?:\\G|^)[[:space:]]*\\b(rec)\\b", + "end": + "(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "keyword.control storage.modifier message.error" } + }, + "patterns": [{ "include": "#module-item-let-value-bind-name-params-type-body" }] + }, + "module-item-module": { + "comment": "NOTE: this is to support the let-module case without the let prefix", + "begin": "\\b(module)\\b[[:space:]]*(?!\\b(type)\\b|$)", + "end": + "(;)|(?=}|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "storage.type message.error" } + }, + "endCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [ + { "include": "#module-item-let-module-and" }, + { "include": "#module-item-let-module-rec" }, + { "include": "#module-item-let-module-bind-name-params-type-body" } + ] + }, + "module-item-module-type": { + "begin": "\\b(module)\\b[[:space:]]*(?=\\b(type)\\b|$)", + "end": + "(;)|(?=}|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|val|with)\\b)", + "beginCaptures": { + "1": { "name": "keyword.control message.error" } + }, + "endCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [ + { + "begin": "(?:\\G|^)[[:space:]]*\\b(type)\\b", + "end": "(?==)", + "beginCaptures": { + "1": { + "name": + "entity.other.attribute-name.css constant.language constant.numeric" + } + }, + "patterns": [ + { "include": "#comment" }, + { + "match": "([[:upper:]][[:word:]]*)", + "captures": { + "1": { "name": "support.class entity.name.class" } + } + } + ] + }, + { + "begin": "(=)", + "end": "(?=;)", + "beginCaptures": { + "1": { "name": "keyword.control.less" } + }, + "patterns": [{ "include": "#comment" }, { "include": "#signature-expression" }] + } + ] + }, + "module-item-open": { + "begin": "\\b(open)\\b", + "end": + "(;)|(?=}|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "keyword.control.open" } + }, + "endCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [{ "include": "#comment" }, { "include": "#module-path-simple" }] + }, + "module-item-type": { + "comment": + "FIXME: the semi-colon is optional so we can re-use this for hover, which does not print the trailing ;", + "begin": "\\b(type)\\b", + "end": + "(;)|(?=[\\)}]|\\b(class|exception|external|include|inherit|let|method|nonrec|open|private|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "keyword.other" } + }, + "endCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [ + { "include": "#module-item-type-and" }, + { "include": "#module-item-type-constraint" }, + { "include": "#module-item-type-bind" } + ] + }, + "module-item-type-and": { + "comment": "FIXME: the optional `type` is for module constraints", + "begin": "\\b(and)\\b([[:space:]]*type)?", + "end": + "(?=[;\\)}]|\\b(class|exception|external|include|inherit|let|method|nonrec|open|private|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "keyword.other" }, + "2": { + "name": "entity.other.attribute-name.css constant.language constant.numeric" + } + }, + "patterns": [{ "include": "#module-item-type-bind-name-tyvars-body" }] + }, + "module-item-type-bind": { + "comment": "FIXME: only allow module paths before type variables", + "patterns": [ + { "include": "#module-item-type-bind-nonrec" }, + { "include": "#module-item-type-bind-name-tyvars-body" } + ] + }, + "module-item-type-bind-body": { + "comment": "FIXME: parsing", + "begin": "(\\+?=)", + "end": + "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "keyword.control.less" } + }, + "patterns": [{ "include": "#module-item-type-bind-body-item" }] + }, + "module-item-type-bind-body-item": { + "patterns": [ + { + "match": "(=)(?!>)|\\b(private)\\b", + "captures": { + "1": { "name": "keyword.control.less" }, + "2": { + "name": + "variable.other.class.js variable.interpolation storage.modifier message.error" + } + } + }, + { + "comment": "FIXME: specialized version of variant rule that also scans for (", + "match": "\\b([[:upper:]][[:word:]]*)\\b(?![[:space:]]*[\\.\\(])", + "captures": { + "1": { + "name": + "entity.other.attribute-name.css constant.language constant.numeric" + } + } + }, + { + "begin": "(\\.\\.)", + "end": + "(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "keyword.control.less" } + } + }, + { + "begin": "(\\|)(?![#\\-:!?.@*/&%^+<=>|~$\\\\])[[:space:]]*", + "end": + "(?=[;\\)}]|\\|(?![#\\-:!?.@*/&%^+<=>|~$\\\\])|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [ + { "include": "#value-expression-constructor" }, + { + "match": "([:])|\\b(of)\\b", + "captures": { + "1": { "name": "keyword.control.less" }, + "2": { "name": "keyword.other" } + } + }, + { "include": "#type-expression" } + ] + }, + { + "comment": "FIXME: remove this once the pretty printer no longer outputs 'of'", + "match": "(:)|(\\|(?![#\\-:!?.@*/&%^+<=>|~$\\\\]))|\\b(of)\\b", + "captures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + }, + "2": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + }, + "3": { "name": "keyword.other" } + } + }, + { "include": "#type-expression" } + ] + }, + "module-item-type-bind-name-tyvars": { + "begin": "(?<=\\G|^|\\.)[[:space:]]*\\b([[:lower:]][[:word:]]*)\\b", + "end": + "(?=\\+?=|[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "entity.name.function" } + }, + "patterns": [ + { "include": "#comment" }, + { "include": "#attribute" }, + { + "match": "_", + "name": "comment" + }, + { + "comment": "FIXME: add separate type-variable rule", + "match": "([+\\-])?(?:(_)|(')([[:lower:]][[:word:]]*)\\b)(?!\\.[[:upper:]])", + "captures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + }, + "2": { "name": "comment" }, + "3": { "name": "comment" }, + "4": { "name": "variable.parameter string.other.link variable.language" } + } + } + ] + }, + "module-item-type-bind-name-tyvars-body": { + "begin": "(?=(\\G|^)[[:space:]]*\\b[[:alpha:]])", + "end": + "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "patterns": [ + { "include": "#module-path-simple-prefix" }, + { "include": "#module-item-type-bind-name-tyvars" }, + { "include": "#module-item-type-bind-body" } + ] + }, + "module-item-type-bind-nonrec": { + "begin": "(?:\\G|^)[[:space:]]*\\b(nonrec)\\b", + "end": + "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "keyword.control storage.modifier message.error" } + }, + "patterns": [{ "include": "#module-item-type-bind-name-tyvars-body" }] + }, + "module-item-type-constraint": { + "comment": "FIXME: proper parsing", + "begin": "\\b(constraint)\\b", + "end": + "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation storage.modifier message.error" + } + }, + "patterns": [ + { + "comment": "FIXME: add separate type-variable rule", + "match": "([+\\-])?(')([_[:lower:]][[:word:]]*)\\b(?!\\.[[:upper:]])", + "captures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + }, + "2": { "name": "comment" }, + "3": { "name": "variable.parameter string.other.link variable.language" } + } + }, + { + "match": "=", + "name": "keyword.control.less" + }, + { "include": "#type-expression" } + ] + }, + "object-item": { + "begin": "\\G|(;)", + "end": + "(?=[;}]|\\b(class|constraint|exception|external|include|let|module|nonrec|open|private|type|val|with)\\b)", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [{ "include": "#class-item-method" }] + }, + "operator": { + "patterns": [{ "include": "#operator-infix" }, { "include": "#operator-prefix" }] + }, + "operator-infix": { + "patterns": [ + { + "match": ";", + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + }, + { "include": "#operator-infix-assign" }, + { "include": "#operator-infix-builtin" }, + { "include": "#operator-infix-custom" }, + { "comment": "#operator-infix-custom-hash" } + ] + }, + "operator-infix-assign": { + "match": "(?|~$\\\\])(=)(?![#\\-:!?.@*/&%^+<=>|~$\\\\])", + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control.less message.error" + }, + "operator-infix-builtin": { + "match": ":=", + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control.less message.error" + }, + "operator-infix-custom": { + "match": + "(?:(?|~$\\\\])((<>))(?![#\\-:!?.@*/&%^+<=>|~$\\\\]))|([#\\-@*/&%^+<=>$\\\\][#\\-:!?.@*/&%^+<=>|~$\\\\]*|[|][#\\-:!?.@*/&%^+<=>|~$\\\\]+)", + "captures": { + "1": { "comment": "meta.separator" }, + "2": { "name": "punctuation.definition.tag.begin.js" }, + "3": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + } + }, + "operator-infix-custom-hash": { + "match": "#[\\-:!?.@*/&%^+<=>|~$]+", + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + }, + "operator-prefix": { + "patterns": [ + { "include": "#operator-prefix-bang" }, + { "include": "#operator-prefix-label-token" } + ] + }, + "operator-prefix-bang": { + "match": "![\\-:!?.@*/&%^+<=>|~$]*", + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + }, + "operator-prefix-label-token": { + "match": "[?~][\\-:!?.@*/&%^+<=>|~$]+", + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + }, + "pattern": { + "patterns": [ + { "include": "#attribute" }, + { "include": "#comment" }, + { "include": "#pattern-atomic" }, + { + "match": + "[[:space:]]*+(?:(\\|(?![#\\-:!?.@*/&%^+<=>|~$\\\\]))|\\b(as)\\b|(\\.\\.\\.?))[[:space:]]*+", + "captures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + }, + "2": { "name": "keyword.other" }, + "3": { "name": "keyword.control" } + } + } + ] + }, + "pattern-atomic": { + "patterns": [ + { + "match": "\\b(exception)\\b", + "name": "keyword.other" + }, + { "include": "#value-expression-literal" }, + { "include": "#module-path-simple-prefix" }, + { "include": "#pattern-list-or-array" }, + { "include": "#pattern-record" }, + { "include": "#pattern-variable" }, + { "include": "#pattern-parens" } + ] + }, + "pattern-guard": { + "begin": "\\b(when)\\b", + "end": "(?==>)", + "beginCaptures": { + "1": { "name": "keyword.other" } + }, + "patterns": [{ "include": "#value-expression" }] + }, + "pattern-list-or-array": { + "begin": "(\\[\\|?)(?![@%])", + "end": "(\\|?\\])", + "beginCaptures": { + "1": { + "name": "entity.other.attribute-name.css constant.language constant.numeric" + } + }, + "endCaptures": { + "1": { + "name": "entity.other.attribute-name.css constant.language constant.numeric" + } + }, + "patterns": [ + { "include": "#value-expression-literal-list-or-array-separator" }, + { "include": "#pattern" } + ] + }, + "pattern-parens": { + "begin": "(?=\\()", + "end": + "\\)|(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "patterns": [ + { "include": "#pattern-parens-lhs" }, + { "include": "#type-annotation-rhs" } + ] + }, + "pattern-parens-lhs": { + "begin": "\\(|(,)", + "end": + "(?=(?:[,:\\)]))|(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [{ "include": "#pattern" }] + }, + "record-path": { + "begin": "\\b[[:lower:]][[:word:]]*\\b", + "end": "(?=[^[:space:]\\.])(?!/\\*)", + "patterns": [{ "include": "#comment" }, { "include": "#record-path-suffix" }] + }, + "record-path-suffix": { + "begin": "(\\.)", + "end": + "(\\))|\\b([[:upper:]][[:word:]]*)\\b|\\b([[:lower:]][[:word:]]*)\\b|(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|with)\\b)", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "endCaptures": { + "1": { "name": "keyword.control" }, + "2": { "name": "support.class entity.name.class" }, + "3": { + "name": + "markup.inserted constant.language support.property-value entity.name.filename" + } + }, + "patterns": [ + { "include": "#comment" }, + { + "begin": "([\\(])", + "end": "(?=[\\)])", + "beginCaptures": { + "1": { "name": "keyword.control" } + }, + "patterns": [ + { "include": "#comment" }, + { + "match": "\\b([[:lower:]][[:word:]]*)\\b(?=[^\\)]*([\\.]))", + "captures": { + "1": { + "name": + "markup.inserted constant.language support.property-value entity.name.filename" + }, + "2": { "name": "keyword.other" } + } + }, + { + "match": "([\\.])", + "name": "keyword.control.less" + }, + { + "match": "\\b([[:lower:]][[:word:]]*)\\b[[:space:]]*", + "captures": { + "1": { + "name": "variable.parameter string.other.link variable.language" + } + } + }, + { "include": "#value-expression" } + ] + } + ] + }, + "pattern-record": { + "begin": "{", + "end": "}", + "patterns": [{ "include": "#comment" }, { "include": "#pattern-record-item" }] + }, + "pattern-record-field": { + "begin": "\\b([_][[:word:]]*)\\b|\\b([[:lower:]][[:word:]]*)\\b", + "end": "(,)|(?=})", + "beginCaptures": { + "1": { "name": "comment" }, + "2": { + "name": + "markup.inserted constant.language support.property-value entity.name.filename" + } + }, + "endCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [ + { "include": "#comment" }, + { + "begin": "\\G(:)", + "end": "(?=[,}])", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [{ "include": "#pattern" }] + } + ] }, - { "include": "#structure-expression-block-item" }, - { "include": "#value-expression" } - ] - }, - "class-item-inherit": { - "begin": "\\b(inherit)\\b", - "end": "(;)|(?=}|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.other" } - }, - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#value-expression" } - ] - }, - "class-item-method": { - "begin": "\\b(method)\\b", - "end": "(;)|(?=}|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "storage.type" } - }, - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#module-item-let-value-bind-name-params-type-body" } - ] - }, - "comment": { - "name": "comment", - "patterns": [ - { "include": "#comment-block-doc" }, - { "include": "#comment-block" } - ] - }, - "comment-block": { - "begin": "/\\*", - "end": "\\*/", - "name": "comment.block", - "patterns": [ - { "include": "#comment" } - ] - }, - "comment-block-doc": { - "begin": "/\\*\\*(?!/)", - "end": "\\*/", - "name": "comment.block.documentation", - "patterns": [ - { "include": "#comment" } - ] - }, - "condition-lhs": { - "begin": "(?|~$\\\\])([\\?])(?![#\\-:!?.@*/&%^+<=>|~$\\\\])", - "end": "(?=[\\)])", - "beginCaptures": { - "1": { "name": "keyword.control message.error variable.interpolation" } - }, - "patterns": [ - { - "match": "(?:\\b|[[:space:]]+)([?])(?:\\b|[[:space:]]+)", - "name": "keyword.control message.error variable.interpolation" + "pattern-record-item": { + "patterns": [ + { "include": "#module-path-simple-prefix" }, + { "include": "#pattern-record-field" } + ] }, - { "include": "#value-expression" } - ] - }, - "extension-node": { - "begin": "(?=\\[(%{1,3})[[:space:]]*[[:alpha:]])", - "end": "\\]", - "patterns": [ - { - "begin": "\\[(%{1,3})", - "end": "(?=[^_\\.'[:word:]])", - "beginCaptures": { - "1": { "name": "keyword.control.less" } - }, - "patterns": [ - { "include": "#attribute-identifier" } - ] - }, - { "include": "#attribute-payload" } - ] - }, - "jsx": { - "patterns": [ - { "include": "#jsx-head" }, - { "include": "#jsx-tail" } - ] - }, - "jsx-attributes": { - "patterns": [ - { - "begin": "\\b([[:lower:]][[:word:]]*)\\b[[:space:]]*(=)", - "end": "(?[:lower:]])", - "comment": "meta.separator", - "beginCaptures": { - "1": { "name": "markup.inserted constant.language support.property-value entity.name.filename" }, - "2": { "name": "keyword.control.less" } - }, - "patterns": [ - { "include": "#value-expression-atomic-with-paths" } - ] - }, - { - "match": "(\\b([[:lower:]][[:word:]]*)\\b[[:space:]]*+)", - "captures": { - "1": { "comment": "meta.separator" }, - "2": { "name": "markup.inserted constant.language support.property-value entity.name.filename" } - } - } - ] - }, - "jsx-body": { - "begin": "((>))", - "end": "(?=))|(?=])[[:space:]]*+", - "comment": "meta.separator", - "patterns": [ - { "include": "#module-path-simple" }, - { - "match": "\\b[[:lower:]][[:word:]]*\\b", - "name": "entity.name.tag.inline.any.html" - } - ] - }, - { "include": "#jsx-attributes" }, - { "include": "#jsx-body" } - ] - }, - "jsx-tail": { - "begin": "\\G(/>)|()", - "applyEndPatternLast": true, - "comment": "meta.separator", - "beginCaptures": { - "1": { "name": "punctuation.definition.tag.end.js" }, - "2": { "name": "punctuation.definition.tag.begin.js" } - }, - "endCaptures": { - "1": { "name": "punctuation.definition.tag.end.js" } - }, - "patterns": [ - { "include": "#module-path-simple" }, - { - "match": "\\b[[:lower:]][[:word:]]*\\b", - "name": "entity.name.tag.inline.any.html" - } - ] - }, - "module-name-extended": { - "patterns": [ - { "include": "#module-name-simple" }, - { - "begin": "([\\(])", - "end": "([\\)])", - "captures": { - "1": { "name": "entity.other.attribute-name.css constant.language constant.numeric" } - }, - "patterns": [ - { "include": "#module-path-extended" } - ] - } - ] - }, - "module-name-simple": { - "match": "\\b[[:upper:]][[:word:]]*\\b", - "name": "support.class entity.name.class" - }, - "module-path-extended": { - "patterns": [ - { "include": "#module-name-extended" }, - { "include": "#comment" }, - { - "comment": "NOTE: end early to avoid too much reparsing", - "begin": "([\\.])", - "end": "(?<=[[:word:]\\)])|(?=[^\\.[:upper:]/])", - "beginCaptures": { - "1": { "name": "keyword.control.less" } - }, - "patterns": [ - { - "begin": "(?<=[\\.])", - "end": "(?<=[[:word:]\\)])|(?=[^\\.[:upper:]/])", - "patterns": [ + "signature-expression": { + "patterns": [ + { + "comment": "FIXME: scan for :upper: to disambiguate type/signature in hover", + "begin": "(?=\\([[:space:]]*[[:upper:]][[:word:]]*[[:space:]]*:)", + "end": "(?=[;])", + "patterns": [ + { + "begin": "(?=\\()", + "end": "(?=[;]|=>)", + "patterns": [{ "include": "#module-item-let-module-param" }] + }, + { + "begin": "(=>)", + "end": "(?=[;\\(])", + "beginCaptures": { + "1": { "name": "markup.inserted keyword.control.less" } + }, + "patterns": [{ "include": "#structure-expression" }] + } + ] + }, + { + "begin": "\\b(module)\\b[[:space:]]*\\b(type)\\b([[:space:]]*\\b(of)\\b)?", + "end": + "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { + "name": + "markup.inserted keyword.other variable.other.readwrite.instance" + }, + "2": { + "name": + "entity.other.attribute-name.css constant.language constant.numeric" + }, + "3": { + "name": + "markup.inserted keyword.other variable.other.readwrite.instance" + } + }, + "patterns": [ + { "include": "#comment" }, + { "include": "#module-path-simple" }, + { + "match": "\\b([[:upper:]][[:word:]]*)\\b", + "name": "support.class entity.name.class" + } + ] + }, + { "include": "#signature-expression-constraints" }, + { "include": "#structure-expression" } + ] + }, + "signature-expression-constraints": { + "begin": "(?=\\b(with))", + "end": + "(?=[;\\)}]|\\b(class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|val)\\b)", + "patterns": [ + { + "begin": "\\b(and|with)\\b", + "end": + "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|val|with)\\b)", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation storage.modifier message.error" + } + }, + "patterns": [ + { "include": "#comment" }, + { + "comment": + "FIXME: special version of #module-item-type with non-consuming `;`. Atom seems to need this to work.", + "begin": "\\b(type)\\b", + "end": + "(?=[;\\)}]|\\b(class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|val|with)\\b)", + "beginCaptures": { + "1": { + "name": + "entity.other.attribute-name.css constant.language constant.numeric" + } + }, + "patterns": [ + { "include": "#module-item-type-and" }, + { "include": "#module-item-type-constraint" }, + { "include": "#module-item-type-bind" } + ] + }, + { + "begin": "(?=\\b(module)\\b)", + "end": + "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|val|with)\\b)", + "patterns": [ + { + "begin": "\\b(module)\\b", + "end": + "(?=:?=|[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|type|val|with)\\b)", + "beginCaptures": { + "1": { + "name": + "markup.inserted keyword.control storage.type variable.other.readwrite.instance" + } + }, + "patterns": [ + { "include": "#comment" }, + { "include": "#module-path-simple" }, + { + "match": "[[:upper:]][[:word:]]*", + "name": "support.class entity.name.class" + } + ] + }, + { + "begin": "(:=)|(=)", + "end": + "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|type|val|with)\\b)", + "beginCaptures": { + "1": { + "name": + "markup.inserted keyword.control.less message.error" + }, + "2": { "name": "markup.inserted keyword.control.less" } + }, + "patterns": [{ "include": "#structure-expression" }] + } + ] + } + ] + } + ] + }, + "structure-expression": { + "patterns": [ { "include": "#comment" }, - { "include": "#module-name-extended" } - ] - } - ] - } - ] - }, - "module-path-extended-prefix": { - "begin": "(?=\\b[[:upper:]])", - "end": "([\\.])|(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#module-path-extended" } - ] - }, - "module-path-simple": { - "patterns": [ - { "include": "#module-name-simple" }, - { "include": "#comment" }, - { - "comment": "NOTE: end early to avoid too much reparsing", - "begin": "([\\.])", - "end": "(?<=[[:word:]\\)])|(?=[^\\.[:upper:]/])", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { - "begin": "(?<=[\\.])", - "end": "(?<=[[:word:]\\)])|(?=[^\\.[:upper:]/])", - "patterns": [ + { + "comment": + "FIXME: scan for :upper: or `val` to disambiguate types from signatures for hover", + "begin": "\\((?=[[:space:]]*(\\b(val)\\b|[^'\\[<[:lower:]]))", + "end": + "\\)|(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|with)\\b)", + "patterns": [ + { "include": "#comment" }, + { + "comment": + "FIXME: might need to refactor this or include more expressions", + "include": "#structure-expression-block" + }, + { + "begin": "\\b(val)\\b", + "end": + "(?=\\))|(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "keyword.other" } + }, + "patterns": [ + { "include": "#comment" }, + { + "match": "\\b([[:lower:]][[:word:]]*)\\b", + "name": "support.class entity.name.class" + } + ] + }, + { "include": "#module-path-simple" }, + { + "begin": "(:)", + "end": + "(?=[\\)])|(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val)\\b)", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [{ "include": "#signature-expression" }] + } + ] + }, + { "include": "#module-path-simple" }, + { "include": "#structure-expression-block" } + ] + }, + "structure-expression-block": { + "begin": "{", + "end": "}", + "patterns": [{ "include": "#structure-expression-block-item" }] + }, + "structure-expression-block-item": { + "patterns": [ + { "include": "#attribute" }, { "include": "#comment" }, - { "include": "#module-name-simple" } - ] - } - ] - } - ] - }, - "module-path-simple-prefix": { - "begin": "(?=\\b[[:upper:]])", - "end": "([\\.])|(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#module-path-simple" } - ] - }, - "module-item-class-type": { - "comment": "FIXME: proper parsing", - "begin": "\\b(class)\\b", - "end": "(;)|(?=}|\\b(and|class|constraint|exception|external|include|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.other" } - }, - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { - "begin": "(?:\\G|^)[[:space:]]*\\b(type)\\b", - "end": "(?==)", - "beginCaptures": { - "1": { "name": "entity.other.attribute-name.css constant.language constant.numeric" } - }, - "patterns": [ - { "include": "#module-item-type-bind-name-tyvars" } - ] - }, - { - "begin": "(=)", - "end": "(?=;)", - "beginCaptures": { - "1": { "name": "keyword.control.less" } - }, - "patterns": [ - { "include": "#attribute" }, - { "include": "#comment" }, - { "include": "#class-item-inherit" }, - { "include": "#class-item-method" } - ] - } - ] - }, - "module-item-exception": { - "begin": "\\b(exception)\\b", - "end": "(;)|(?=}|\\b(class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.other" } - }, - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#module-item-type-bind-body-item" } - ] - }, - "module-item-external": { - "begin": "\\b(external)\\b", - "end": "(;)|(?=}|\\b(class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "storage.type" } - }, - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#module-item-let-value-bind-name-or-pattern" }, - { "include": "#module-item-let-value-bind-type" }, - { - "begin": "(=)", - "end": "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control.less" } - }, - "patterns": [ - { "include": "#attribute" }, - { - "begin": "\"", - "end": "\"", - "name": "string.double string.regexp", - "patterns": [ - { "include": "#value-literal-string-escape" }, - { - "match": "(?:(%)(.*?)|(caml.*?))(?=\"|(?:[^\\\\\\n]$))", - "captures": { - "1": { "name": "entity.other.attribute-name.css constant.language constant.numeric" }, - "2": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" }, - "3": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error"} - } - } - ] - } - ] - } - ] - }, - "module-item-include": { - "begin": "\\b(include)\\b", - "end": "(;)|(?=}|\\b(class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|type|val)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control.include" } - }, - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#signature-expression" } - ] - }, - "module-item-let": { - "begin": "\\b(let)\\b", - "end": "(;)|(?=}|\\b(class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "storage.type" } - }, - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#module-item-let-module" }, - { "include": "#module-item-let-value" } - ] - }, - "module-item-let-module": { - "begin": "(?:\\G|^)[[:space:]]*\\b(module)\\b", - "end": "(?=[;}]|\\b(class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.control storage.type message.error" } - }, - "patterns": [ - { "include": "#comment" }, - { "include": "#module-item-let-module-and" }, - { "include": "#module-item-let-module-rec" }, - { "include": "#module-item-let-module-bind-name-params-type-body" } - ] - }, - "module-item-let-module-and": { - "begin": "\\b(and)\\b", - "end": "(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "storage.type" } - }, - "patterns": [ - { "include": "#module-item-let-module-bind-name-params-type-body" } - ] - }, - "module-item-let-module-bind-body": { - "begin": "(=>?)", - "end": "(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control.less" } - }, - "patterns": [ - { "include": "#structure-expression" } - ] - }, - "module-item-let-module-bind-name-params": { - "begin": "\\b([[:upper:]][[:word:]]*)\\b", - "end": "(?=[;:}=]|\\b(class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "support.class entity.name.class" } - }, - "patterns": [ - { "include": "#comment" }, - { "include": "#module-item-let-module-param" } - ] - }, - "module-item-let-module-bind-name-params-type-body": { - "begin": "(?:\\G|^)", - "end": "(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "patterns": [ - { "include": "#comment" }, - { "include": "#module-item-let-module-bind-name-params" }, - { "include": "#module-item-let-module-bind-type" }, - { "include": "#module-item-let-module-bind-body" } - ] - }, - "module-item-let-module-bind-type": { - "begin": "(:)", - "end": "(?=[;}=]|\\b(and|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|rec|type|val)\\b)", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#signature-expression" } - ] - }, - "module-item-let-module-param": { - "begin": "(?=\\()", - "end": "\\)", - "patterns": [ - { - "begin": "\\(", - "end": "(?=[:])", - "patterns": [ - { "include": "#comment" }, - { "include": "#module-name-simple" } - ] - }, - { - "begin": "(:)", - "end": "(?=\\))", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#signature-expression" } - ] - } - ] - }, - "module-item-let-module-rec": { - "begin": "(?:\\G|^)[[:space:]]*\\b(rec)\\b", - "end": "(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control storage.modifier.rec" } - }, - "patterns": [ - { "include": "#module-item-let-module-bind-name-params-type-body" } - ] - }, - "module-item-let-value": { - "patterns": [ - { "include": "#module-item-let-value-and" }, - { "include": "#module-item-let-value-rec" }, - { "include": "#module-item-let-value-bind-name-params-type-body" } - ] - }, - "module-item-let-value-and": { - "begin": "\\b(and)\\b", - "end": "(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "storage.type" } - }, - "patterns": [ - { "include": "#module-item-let-value-bind-name-params-type-body" } - ] - }, - "module-item-let-value-bind-body": { - "begin": "(=>?)", - "end": "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control.less" } - }, - "patterns": [ - { "include": "#value-expression" } - ] - }, - "module-item-let-value-bind-name-or-pattern": { - "begin": "(?<=[^[:word:]]and|^and|[^[:word:]]external|^external|[^[:word:]]let|^let|[^[:word:]]method|^method|[^[:word:]]rec|^rec)[[:space:]]*", - "end": "(?<=[^[:space:]])|(?=[[:space:]]|[;:}=]|\\b(and|as|class|constraint|exception|external|for|include|inherit|let|method|module|nonrec|open|private|rec|switch|try|type|val|while|with)\\b)", - "patterns": [ - { "include": "#comment" }, - { - "match": "\\b(?:([_][[:word:]]+)|([[:lower:]][[:word:]]*))\\b", - "captures": { - "1": { "name": "comment" }, - "2": { "name": "entity.name.function" } - } - }, - { "include": "#module-item-let-value-bind-parens-params" }, - { "include": "#pattern" } - ] - }, - "module-item-let-value-bind-name-params-type-body": { - "begin": "(?<=[^[:word:]]and|^and|[^[:word:]]external|^external|[^[:word:]]let|^let|[^[:word:]]method|^method|[^[:word:]]rec|^rec)", - "end": "(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "patterns": [ - { - "comment": "FIXME; hack for punned arguments", - "begin": "(::)", - "end": "(?<=[[:space:]])", - "beginCaptures": { - "1": { "name": "keyword.control" } - }, - "patterns": [ - { "include": "#pattern" }, - { - "begin": "(=)", - "end": "(\\?)|(?<=[^[:space:]=][[:space:]])(?=[[:space:]]*+[^\\.])", - "beginCaptures": { - "1": { "name": "markup.inserted keyword.control.less message.error" } - }, - "endCaptures": { - "1": { "name": "storage.type" } - }, - "patterns": [ - { "include": "#value-expression-atomic-with-paths" } - ] - } - ] - }, - { "include": "#module-item-let-value-bind-name-or-pattern" }, - { "include": "#module-item-let-value-bind-params-type" }, - { "include": "#module-item-let-value-bind-type" }, - { "include": "#module-item-let-value-bind-body" } - ] - }, - "module-item-let-value-bind-params-type": { - "begin": "(?=[^[:space:]:=])", - "end": "(?=[;}=]|\\b(class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "patterns": [ - { "include": "#comment" }, - { "include": "#module-item-let-value-param" }, - { - "begin": "(?]|[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|val|with)\\b)", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { - "begin": "\\b(type)\\b", - "end": "([\\.])", - "beginCaptures": { - "1": { "name": "entity.other.attribute-name.css constant.language constant.numeric" } - }, - "endCaptures": { - "1": { "name": "entity.name.function" } - }, - "patterns": [ - { "include": "#pattern-variable" } - ] - }, - { "include": "#type-expression" } - ] - }, - "module-item-let-value-param": { - "patterns": [ - { "include": "#module-item-let-value-param-label" }, - { "include": "#module-item-let-value-param-type" }, - { "include": "#module-item-let-value-param-module" }, - { "include": "#pattern" } - ] - }, - "module-item-let-value-param-label": { - "patterns": [ - { - "begin": "(\\b[[:lower:]][[:word:]]*\\b)?[[:space:]]*(::)", - "end": "(?<=[[:space:]])", - "beginCaptures": { - "1": { "name": "markup.inserted constant.language support.property-value entity.name.filename" }, - "2": { "name": "keyword.control" } - }, - "patterns": [ - { "include": "#pattern" }, - { - "begin": "(=)", - "end": "(\\?)|(?<=[^[:space:]=][[:space:]])(?=[[:space:]]*+[^\\.])", - "beginCaptures": { - "1": { "name": "markup.inserted keyword.control.less message.error" } - }, - "endCaptures": { - "1": { "name": "storage.type" } - }, - "patterns": [ - { "include": "#value-expression-atomic-with-paths" } - ] - } - ] - } - ] - }, - "module-item-let-value-param-module": { - "comment": "FIXME: merge with pattern-parens", - "begin": "\\([[:space:]]*(?=\\b(module)\\b)", - "end": "\\)", - "patterns": [ - { - "begin": "\\b(module)\\b", - "end": "(?=\\))", - "beginCaptures": { - "1": { "name": "keyword.other message.error" } - }, - "patterns": [ - { - "match": "\\b[[:upper:]][[:word:]]*\\b", - "name": "support.class entity.name.class" - } - ] - } - ] - }, - "module-item-let-value-param-type": { - "comment": "FIXME: merge with pattern-parens", - "begin": "\\((?=\\b(type)\\b)", - "end": "\\)", - "patterns": [ - { - "begin": "\\b(type)\\b", - "end": "(?=\\))", - "beginCaptures": { - "1": { "name": "entity.other.attribute-name.css constant.language constant.numeric" } - }, - "patterns": [ - { "include": "#pattern-variable" } - ] - } - ] - }, - "module-item-let-value-rec": { - "begin": "(?:\\G|^)[[:space:]]*\\b(rec)\\b", - "end": "(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control storage.modifier message.error" } - }, - "patterns": [ - { "include": "#module-item-let-value-bind-name-params-type-body" } - ] - }, - "module-item-module": { - "comment": "NOTE: this is to support the let-module case without the let prefix", - "begin": "\\b(module)\\b[[:space:]]*(?!\\b(type)\\b|$)", - "end": "(;)|(?=}|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "storage.type message.error" } - }, - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#module-item-let-module-and" }, - { "include": "#module-item-let-module-rec" }, - { "include": "#module-item-let-module-bind-name-params-type-body" } - ] - }, - "module-item-module-type": { - "begin": "\\b(module)\\b[[:space:]]*(?=\\b(type)\\b|$)", - "end": "(;)|(?=}|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control message.error" } - }, - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { - "begin": "(?:\\G|^)[[:space:]]*\\b(type)\\b", - "end": "(?==)", - "beginCaptures": { - "1": { "name": "entity.other.attribute-name.css constant.language constant.numeric" } - }, - "patterns": [ - { "include": "#comment" }, - { - "match": "([[:upper:]][[:word:]]*)", - "captures": { - "1": { "name": "support.class entity.name.class" } - } - } - ] - }, - { - "begin": "(=)", - "end": "(?=;)", - "beginCaptures": { - "1": { "name": "keyword.control.less" } - }, - "patterns": [ - { "include": "#comment" }, - { "include": "#signature-expression" } - ] - } - ] - }, - "module-item-open": { - "begin": "\\b(open)\\b", - "end": "(;)|(?=}|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control.open" } - }, - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#comment" }, - { "include": "#module-path-simple" } - ] - }, - "module-item-type": { - "comment": "FIXME: the semi-colon is optional so we can re-use this for hover, which does not print the trailing ;", - "begin": "\\b(type)\\b", - "end": "(;)|(?=[\\)}]|\\b(class|exception|external|include|inherit|let|method|nonrec|open|private|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.other" } - }, - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#module-item-type-and" }, - { "include": "#module-item-type-constraint" }, - { "include": "#module-item-type-bind" } - ] - }, - "module-item-type-and": { - "comment": "FIXME: the optional `type` is for module constraints", - "begin": "\\b(and)\\b([[:space:]]*type)?", - "end": "(?=[;\\)}]|\\b(class|exception|external|include|inherit|let|method|nonrec|open|private|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.other" }, - "2": { "name": "entity.other.attribute-name.css constant.language constant.numeric" } - }, - "patterns": [ - { "include": "#module-item-type-bind-name-tyvars-body" } - ] - }, - "module-item-type-bind": { - "comment": "FIXME: only allow module paths before type variables", - "patterns": [ - { "include": "#module-item-type-bind-nonrec" }, - { "include": "#module-item-type-bind-name-tyvars-body" } - ] - }, - "module-item-type-bind-body": { - "comment": "FIXME: parsing", - "begin": "(\\+?=)", - "end": "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control.less" } - }, - "patterns": [ - { "include": "#module-item-type-bind-body-item" } - ] - }, - "module-item-type-bind-body-item": { - "patterns": [ - { - "match": "(=)(?!>)|\\b(private)\\b", - "captures": { - "1": { "name": "keyword.control.less" }, - "2": { "name": "variable.other.class.js variable.interpolation storage.modifier message.error" } - } - }, - { - "comment": "FIXME: specialized version of variant rule that also scans for (", - "match": "\\b([[:upper:]][[:word:]]*)\\b(?![[:space:]]*[\\.\\(])", - "captures": { - "1": { "name": "entity.other.attribute-name.css constant.language constant.numeric" } - } - }, - { - "begin": "(\\.\\.)", - "end": "(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control.less" } - } - }, - { - "begin": "(\\|)(?![#\\-:!?.@*/&%^+<=>|~$\\\\])[[:space:]]*", - "end": "(?=[;\\)}]|\\|(?![#\\-:!?.@*/&%^+<=>|~$\\\\])|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#value-expression-constructor" }, - { - "match": "([:])|\\b(of)\\b", - "captures": { - "1": { "name": "keyword.control.less" }, - "2": { "name": "keyword.other" } - } - }, - { "include": "#type-expression" } - ] - }, - { - "comment": "FIXME: remove this once the pretty printer no longer outputs 'of'", - "match": "(:)|(\\|(?![#\\-:!?.@*/&%^+<=>|~$\\\\]))|\\b(of)\\b", - "captures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" }, - "2": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" }, - "3": { "name": "keyword.other" } - } - }, - { "include": "#type-expression" } - ] - }, - "module-item-type-bind-name-tyvars": { - "begin": "(?<=\\G|^|\\.)[[:space:]]*\\b([[:lower:]][[:word:]]*)\\b", - "end": "(?=\\+?=|[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "entity.name.function" } - }, - "patterns": [ - { "include": "#comment" }, - { "include": "#attribute" }, - { - "match": "_", - "name": "comment" - }, - { - "comment": "FIXME: add separate type-variable rule", - "match": "([+\\-])?(?:(_)|(')([[:lower:]][[:word:]]*)\\b)(?!\\.[[:upper:]])", - "captures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" }, - "2": { "name": "comment" }, - "3": { "name": "comment" }, - "4": { "name": "variable.parameter string.other.link variable.language" } - } - } - ] - }, - "module-item-type-bind-name-tyvars-body": { - "begin": "(?=(\\G|^)[[:space:]]*\\b[[:alpha:]])", - "end": "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "patterns": [ - { "include": "#module-path-simple-prefix" }, - { "include": "#module-item-type-bind-name-tyvars" }, - { "include": "#module-item-type-bind-body" } - ] - }, - "module-item-type-bind-nonrec": { - "begin": "(?:\\G|^)[[:space:]]*\\b(nonrec)\\b", - "end": "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control storage.modifier message.error" } - }, - "patterns": [ - { "include": "#module-item-type-bind-name-tyvars-body" } - ] - }, - "module-item-type-constraint": { - "comment": "FIXME: proper parsing", - "begin": "\\b(constraint)\\b", - "end": "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation storage.modifier message.error" } - }, - "patterns": [ - { - "comment": "FIXME: add separate type-variable rule", - "match": "([+\\-])?(')([_[:lower:]][[:word:]]*)\\b(?!\\.[[:upper:]])", - "captures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" }, - "2": { "name": "comment" }, - "3": { "name": "variable.parameter string.other.link variable.language" } - } - }, - { - "match": "=", - "name": "keyword.control.less" - }, - { "include": "#type-expression" } - ] - }, - "object-item": { - "begin": "\\G|(;)", - "end": "(?=[;}]|\\b(class|constraint|exception|external|include|let|module|nonrec|open|private|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#class-item-method" } - ] - }, - "operator": { - "patterns": [ - { "include": "#operator-infix" }, - { "include": "#operator-prefix" } - ] - }, - "operator-infix": { - "patterns": [ - { - "match": ";", - "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" - }, - { "include": "#operator-infix-assign" }, - { "include": "#operator-infix-builtin" }, - { "include": "#operator-infix-custom" }, - { "comment": "#operator-infix-custom-hash" } - ] - }, - "operator-infix-assign": { - "match": "(?|~$\\\\])(=)(?![#\\-:!?.@*/&%^+<=>|~$\\\\])", - "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control.less message.error" - }, - "operator-infix-builtin": { - "match": ":=", - "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control.less message.error" - }, - "operator-infix-custom": { - "match": "(?:(?|~$\\\\])((<>))(?![#\\-:!?.@*/&%^+<=>|~$\\\\]))|([#\\-@*/&%^+<=>$\\\\][#\\-:!?.@*/&%^+<=>|~$\\\\]*|[|][#\\-:!?.@*/&%^+<=>|~$\\\\]+)", - "captures": { - "1": { "comment": "meta.separator" }, - "2": { "name": "punctuation.definition.tag.begin.js" }, - "3": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - } - }, - "operator-infix-custom-hash": { - "match": "#[\\-:!?.@*/&%^+<=>|~$]+", - "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" - }, - "operator-prefix": { - "patterns": [ - { "include": "#operator-prefix-bang" }, - { "include": "#operator-prefix-label-token" } - ] - }, - "operator-prefix-bang": { - "match": "![\\-:!?.@*/&%^+<=>|~$]*", - "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" - }, - "operator-prefix-label-token": { - "match": "[?~][\\-:!?.@*/&%^+<=>|~$]+", - "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" - }, - "pattern": { - "patterns": [ - { "include": "#attribute" }, - { "include": "#comment" }, - { "include": "#pattern-atomic" }, - { - "match": "[[:space:]]*+(?:(\\|(?![#\\-:!?.@*/&%^+<=>|~$\\\\]))|\\b(as)\\b|(\\.\\.\\.?))[[:space:]]*+", - "captures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" }, - "2": { "name": "keyword.other" }, - "3": { "name": "keyword.control" } - } - } - ] - }, - "pattern-atomic": { - "patterns": [ - { - "match": "\\b(exception)\\b", - "name": "keyword.other" - }, - { "include": "#value-expression-literal" }, - { "include": "#module-path-simple-prefix" }, - { "include": "#pattern-list-or-array" }, - { "include": "#pattern-record" }, - { "include": "#pattern-variable" }, - { "include": "#pattern-parens" } - ] - }, - "pattern-guard": { - "begin": "\\b(when)\\b", - "end": "(?==>)", - "beginCaptures": { - "1": { "name": "keyword.other" } - }, - "patterns": [ - { "include": "#value-expression" } - ] - }, - "pattern-list-or-array": { - "begin": "(\\[\\|?)(?![@%])", - "end": "(\\|?\\])", - "beginCaptures": { - "1": { "name": "entity.other.attribute-name.css constant.language constant.numeric" } - }, - "endCaptures": { - "1": { "name": "entity.other.attribute-name.css constant.language constant.numeric" } - }, - "patterns": [ - { "include": "#value-expression-literal-list-or-array-separator" }, - { "include": "#pattern" } - ] - }, - "pattern-parens": { - "begin": "(?=\\()", - "end": "\\)|(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "patterns": [ - { "include": "#pattern-parens-lhs" }, - { "include": "#type-annotation-rhs" } - ] - }, - "pattern-parens-lhs": { - "begin": "\\(|(,)", - "end": "(?=(?:[,:\\)]))|(?=[;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#pattern" } - ] - }, - "record-path": { - "begin": "\\b[[:lower:]][[:word:]]*\\b", - "end": "(?=[^[:space:]\\.])(?!/\\*)", - "patterns": [ - { "include": "#comment" }, - { "include": "#record-path-suffix" } - ] - }, - "record-path-suffix": { - "begin": "(\\.)", - "end": "(\\))|\\b([[:upper:]][[:word:]]*)\\b|\\b([[:lower:]][[:word:]]*)\\b|(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|with)\\b)", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "endCaptures": { - "1": { "name": "keyword.control" }, - "2": { "name": "support.class entity.name.class" }, - "3": { "name": "markup.inserted constant.language support.property-value entity.name.filename" } - }, - "patterns": [ - { "include": "#comment" }, - { - "begin": "([\\(])", - "end": "(?=[\\)])", - "beginCaptures": { - "1": { "name": "keyword.control" } - }, - "patterns": [ - { "include": "#comment" }, - { - "match": "\\b([[:lower:]][[:word:]]*)\\b(?=[^\\)]*([\\.]))", - "captures": { - "1": { "name": "markup.inserted constant.language support.property-value entity.name.filename" }, - "2": { "name": "keyword.other" } - } - }, - { - "match": "([\\.])", - "name": "keyword.control.less" - }, - { - "match": "\\b([[:lower:]][[:word:]]*)\\b[[:space:]]*", - "captures": { - "1": { "name": "variable.parameter string.other.link variable.language" } - } - }, - { "include": "#value-expression" } - ] - } - ] - }, - "pattern-record": { - "begin": "{", - "end": "}", - "patterns": [ - { "include": "#comment" }, - { "include": "#pattern-record-item" } - ] - }, - "pattern-record-field": { - "begin": "\\b([_][[:word:]]*)\\b|\\b([[:lower:]][[:word:]]*)\\b", - "end": "(,)|(?=})", - "beginCaptures": { - "1": { "name": "comment" }, - "2": { "name": "markup.inserted constant.language support.property-value entity.name.filename" } - }, - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#comment" }, - { - "begin": "\\G(:)", - "end": "(?=[,}])", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#pattern" } - ] - } - ] - }, - "pattern-record-item": { - "patterns": [ - { "include": "#module-path-simple-prefix" }, - { "include": "#pattern-record-field" } - ] - }, - "pattern-variable": { - "patterns": [ - { - "match": "\\b(_(?:[[:lower:]][[:word:]]*)?)\\b(?!\\.[[:upper:]])", - "captures": { - "1": { "name": "comment" } - } - }, - { - "match": "\\b([[:lower:]][[:word:]]*)\\b(?!\\.[[:upper:]])", - "captures": { - "1": { "name": "variable.language string.other.link" } - } - } - ] - }, - "signature-expression": { - "patterns": [ - { - "comment": "FIXME: scan for :upper: to disambiguate type/signature in hover", - "begin": "(?=\\([[:space:]]*[[:upper:]][[:word:]]*[[:space:]]*:)", - "end": "(?=[;])", - "patterns": [ - { - "begin": "(?=\\()", - "end": "(?=[;]|=>)", - "patterns": [ - { "include": "#module-item-let-module-param" } - ] - }, - { - "begin": "(=>)", - "end": "(?=[;\\(])", - "beginCaptures": { - "1": { "name": "markup.inserted keyword.control.less" } - }, - "patterns": [ - { "include": "#structure-expression" } - ] - } - ] - }, - { - "begin": "\\b(module)\\b[[:space:]]*\\b(type)\\b([[:space:]]*\\b(of)\\b)?", - "end": "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "markup.inserted keyword.other variable.other.readwrite.instance" }, - "2": { "name": "entity.other.attribute-name.css constant.language constant.numeric" }, - "3": { "name": "markup.inserted keyword.other variable.other.readwrite.instance" } - }, - "patterns": [ - { "include": "#comment" }, - { "include": "#module-path-simple" }, - { - "match": "\\b([[:upper:]][[:word:]]*)\\b", - "name": "support.class entity.name.class" + { "include": "#module-item-exception" }, + { "include": "#module-item-external" }, + { "include": "#module-item-include" }, + { "include": "#module-item-let" }, + { "include": "#module-item-class-type" }, + { "include": "#module-item-module-type" }, + { "include": "#module-item-module" }, + { "include": "#module-item-open" }, + { "include": "#module-item-type" } + ] + }, + "type-annotation-rhs": { + "begin": "(?|~$\\\\])([:])(?![#\\-:!?.@*/&%^+<=>|~$\\\\])", + "end": + "(?=\\))|(?=[,;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [{ "include": "#type-expression" }] + }, + "type-expression": { + "patterns": [ + { + "match": "([\\.])", + "name": "entity.name.function" + }, + { "include": "#type-expression-atomic" }, + { "include": "#type-expression-arrow" } + ] + }, + "type-expression-atomic": { + "patterns": [ + { "include": "#attribute" }, + { "include": "#comment" }, + { "include": "#module-path-extended-prefix" }, + { "include": "#type-expression-label" }, + { + "match": "\\b(as)\\b", + "name": + "variable.other.class.js variable.interpolation storage.modifier message.error" + }, + { "include": "#type-expression-constructor" }, + { "include": "#type-expression-object" }, + { "include": "#type-expression-parens" }, + { "include": "#type-expression-polymorphic-variant" }, + { "include": "#type-expression-record" }, + { "include": "#type-expression-variable" } + ] + }, + "type-expression-arrow": { + "match": "=>", + "name": "markup.inserted keyword.control.less" + }, + "type-expression-constructor": { + "match": "(_)(?![[:alnum:]])|\\b([_[:lower:]][[:word:]]*)\\b(?!\\.[[:upper:]])", + "captures": { + "1": { "name": "comment" }, + "2": { "name": "support.type string.regexp" } } - ] - }, - { "include": "#signature-expression-constraints" }, - { "include": "#structure-expression" } - ] - }, - "signature-expression-constraints": { - "begin": "(?=\\b(with))", - "end": "(?=[;\\)}]|\\b(class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|val)\\b)", - "patterns": [ - { - "begin": "\\b(and|with)\\b", - "end": "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|val|with)\\b)", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation storage.modifier message.error" } - }, - "patterns": [ - { "include": "#comment" }, - { - "comment": "FIXME: special version of #module-item-type with non-consuming `;`. Atom seems to need this to work.", - "begin": "\\b(type)\\b", - "end": "(?=[;\\)}]|\\b(class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|val|with)\\b)", - "beginCaptures": { - "1": { "name": "entity.other.attribute-name.css constant.language constant.numeric" } - }, - "patterns": [ - { "include": "#module-item-type-and" }, - { "include": "#module-item-type-constraint" }, - { "include": "#module-item-type-bind" } - ] - }, - { - "begin": "(?=\\b(module)\\b)", - "end": "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|val|with)\\b)", - "patterns": [ - { - "begin": "\\b(module)\\b", - "end": "(?=:?=|[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "markup.inserted keyword.control storage.type variable.other.readwrite.instance" } - }, - "patterns": [ - { "include": "#comment" }, - { "include": "#module-path-simple" }, - { - "match": "[[:upper:]][[:word:]]*", - "name": "support.class entity.name.class" + }, + "type-expression-label": { + "begin": "\\b([_[:lower:]][[:word:]]*)\\b(::)", + "end": "(?<==>)", + "beginCaptures": { + "1": { + "name": + "markup.inserted constant.language support.property-value entity.name.filename" + }, + "2": { "name": "keyword.control" } + }, + "patterns": [ + { "include": "#type-expression" }, + { + "match": "(\\?)", + "captures": { + "1": { "name": "keyword.control.less" } + } + } + ] + }, + "type-expression-object": { + "comment": "FIXME: separate sub-rules", + "begin": "(<)", + "end": "(>)", + "captures": { + "1": { "name": "entity.name.function" } + }, + "patterns": [ + { + "begin": "(\\.\\.)", + "end": "(?=>)", + "beginCaptures": { + "1": { + "name": + "entity.other.attribute-name.css constant.language constant.numeric" + } } - ] }, { - "begin": "(:=)|(=)", - "end": "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "markup.inserted keyword.control.less message.error" }, - "2": { "name": "markup.inserted keyword.control.less" } - }, - "patterns": [ - { "include": "#structure-expression" } - ] - } - ] + "comment": "FIXME: method item", + "begin": "(?=[_[:lower:]])", + "end": "(,)|(?=>)", + "endCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [ + { + "comment": "FIXME: method name", + "begin": "(?=[_[:lower:]])", + "end": "(?=:)", + "patterns": [ + { + "match": "\\b([_[:lower:]][[:word:]]*)\\b", + "captures": { + "1": { + "name": + "markup.inserted constant.language support.property-value entity.name.filename" + } + } + } + ] + }, + { + "comment": "FIXME: method type", + "begin": "(:)", + "end": "(?=[,>])", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [{ "include": "#type-expression" }] + } + ] + } + ] + }, + "type-expression-parens": { + "comment": "FIXME: proper tuple types", + "begin": "\\(", + "end": "\\)", + "patterns": [ + { + "begin": "\\b(module)\\b", + "end": "(?=[\\)])", + "beginCaptures": { + "1": { "name": "keyword.other message.error" } + }, + "patterns": [ + { "include": "#module-path-extended" }, + { "include": "#signature-expression-constraints" } + ] + }, + { + "match": ",", + "name": "keyword.control.less" + }, + { "include": "#type-expression" } + ] + }, + "type-expression-polymorphic-variant": { + "comment": "FIXME: proper parsing", + "begin": "(\\[)([<>])?", + "end": "(\\])", + "captures": { + "1": { "name": "entity.name.function" }, + "2": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [ + { + "begin": "(\\|)?(?![#\\-:!?.@*/&%^+<=>|~$\\\\])[[:space:]]*", + "end": + "(?=[;)}\\]]|\\|(?![#\\-:!?.@*/&%^+<=>|~$\\\\])|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [ + { "include": "#value-expression-constructor" }, + { + "match": "([:])|\\b(of)\\b|([&])", + "captures": { + "1": { "name": "keyword.control.less" }, + "2": { "name": "keyword.other" }, + "3": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + } + }, + { "include": "#value-expression-constructor-polymorphic" }, + { "include": "#type-expression" } + ] + } + ] + }, + "type-expression-record": { + "begin": "{", + "end": "}", + "patterns": [{ "include": "#type-expression-record-item" }] + }, + "type-expression-record-field-sans-modifier": { + "begin": "\\b([_[:lower:]][[:word:]]*)\\b", + "end": "(,)|(?=[,}])", + "beginCaptures": { + "1": { + "name": + "markup.inserted constant.language support.property-value entity.name.filename" + } + }, + "endCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [ + { "include": "#comment" }, + { + "begin": "(:)", + "end": "(?=[,}])", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [{ "include": "#type-expression" }] + } + ] + }, + "type-expression-record-field": { + "patterns": [ + { + "begin": "\\b(mutable)\\b", + "end": "(?<=[,])|(?=})", + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation storage.modifier message.error" + } + }, + "patterns": [{ "include": "#type-expression-record-field-sans-modifier" }] + }, + { "include": "#type-expression-record-field-sans-modifier" } + ] + }, + "type-expression-record-item": { + "patterns": [ + { "include": "#comment" }, + { "include": "#module-path-simple-prefix" }, + { "include": "#type-expression-record-field" } + ] + }, + "type-expression-variable": { + "match": "(')([_[:lower:]][[:word:]]*)\\b(?!\\.[[:upper:]])", + "captures": { + "1": { "name": "comment" }, + "2": { "name": "variable.parameter string.other.link variable.language" } } - ] - } - ] - }, - "structure-expression": { - "patterns": [ - { "include": "#comment" }, - { - "comment": "FIXME: scan for :upper: or `val` to disambiguate types from signatures for hover", - "begin": "\\((?=[[:space:]]*(\\b(val)\\b|[^'\\[<[:lower:]]))", - "end": "\\)|(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|with)\\b)", - "patterns": [ - { "include": "#comment" }, - { - "comment": "FIXME: might need to refactor this or include more expressions", - "include": "#structure-expression-block" - }, - { - "begin": "\\b(val)\\b", - "end": "(?=\\))|(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.other" } - }, - "patterns": [ + }, + "value-expression": { + "patterns": [ + { "include": "#attribute" }, { "include": "#comment" }, + { "include": "#extension-node" }, + { "include": "#jsx" }, + { "include": "#operator" }, + { "include": "#value-expression-builtin" }, + { "include": "#value-expression-if-then-else" }, + { "include": "#value-expression-atomic" }, + { "include": "#module-path-simple-prefix" }, { - "match": "\\b([[:lower:]][[:word:]]*)\\b", - "name": "support.class entity.name.class" - } - ] - }, - { "include": "#module-path-simple" }, - { - "begin": "(:)", - "end": "(?=[\\)])|(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val)\\b)", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#signature-expression" } - ] + "match": "[:?]", + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + }, + { "include": "#record-path" } + ] + }, + "value-expression-atomic": { + "patterns": [ + { "include": "#value-expression-literal" }, + { "include": "#value-expression-literal-list-or-array" }, + { "include": "#value-expression-for" }, + { "include": "#value-expression-fun" }, + { "include": "#value-expression-block-or-record-or-object" }, + { "include": "#value-expression-label" }, + { "include": "#value-expression-parens" }, + { "include": "#value-expression-switch" }, + { "include": "#value-expression-try" }, + { "include": "#value-expression-while" } + ] + }, + "value-expression-atomic-with-paths": { + "patterns": [ + { "include": "#value-expression-atomic" }, + { "include": "#module-path-simple-prefix" }, + { "include": "#record-path-suffix" } + ] + }, + "value-expression-block": { + "begin": "{", + "end": "}", + "patterns": [{ "include": "#value-expression-block-item" }] + }, + "value-expression-block-item": { + "patterns": [ + { "include": "#module-item-let" }, + { "include": "#module-item-open" }, + { "include": "#value-expression" } + ] + }, + "value-expression-block-look": { + "begin": + "(?![[:space:]]*($|\\.\\.\\.|([[:upper:]][[:word:]]*\\.)*([[:lower:]][[:word:]]*)[[:space:]]*(?:,|:(?![=]))))", + "end": "(?=})", + "patterns": [{ "include": "#value-expression-block-item" }] + }, + "value-expression-block-or-record-or-object": { + "begin": "{", + "end": "}", + "patterns": [ + { "include": "#comment" }, + { "include": "#module-path-simple-prefix" }, + { "include": "#value-expression-object-look" }, + { "include": "#value-expression-record-look" }, + { "include": "#value-expression-block-look" } + ] + }, + "value-expression-builtin": { + "match": + "\\b(assert|decr|failwith|fprintf|ignore|incr|land|lazy|lor|lsl|lsr|lxor|mod|new|not|printf|ref)\\b|\\b(raise)\\b", + "captures": { + "1": { "name": "keyword.control message.error" }, + "2": { "name": "keyword.control.trycatch" } } - ] - }, - { "include": "#module-path-simple" }, - { "include": "#structure-expression-block" } - ] - }, - "structure-expression-block": { - "begin": "{", - "end": "}", - "patterns": [ - { "include": "#structure-expression-block-item" } - ] - }, - "structure-expression-block-item": { - "patterns": [ - { "include": "#attribute" }, - { "include": "#comment" }, - { "include": "#module-item-exception" }, - { "include": "#module-item-external" }, - { "include": "#module-item-include" }, - { "include": "#module-item-let" }, - { "include": "#module-item-class-type" }, - { "include": "#module-item-module-type" }, - { "include": "#module-item-module" }, - { "include": "#module-item-open" }, - { "include": "#module-item-type" } - ] - }, - "type-annotation-rhs": { - "begin": "(?|~$\\\\])([:])(?![#\\-:!?.@*/&%^+<=>|~$\\\\])", - "end": "(?=\\))|(?=[,;}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#type-expression" } - ] - }, - "type-expression": { - "patterns": [ - { - "match": "([\\.])", - "name": "entity.name.function" - }, - { "include": "#type-expression-atomic" }, - { "include": "#type-expression-arrow" } - ] - }, - "type-expression-atomic": { - "patterns": [ - { "include": "#attribute" }, - { "include": "#comment" }, - { "include": "#module-path-extended-prefix" }, - { "include": "#type-expression-label" }, - { - "match": "\\b(as)\\b", - "name": "variable.other.class.js variable.interpolation storage.modifier message.error" - }, - { "include": "#type-expression-constructor" }, - { "include": "#type-expression-object" }, - { "include": "#type-expression-parens" }, - { "include": "#type-expression-polymorphic-variant" }, - { "include": "#type-expression-record" }, - { "include": "#type-expression-variable" } - ] - }, - "type-expression-arrow": { - "match": "=>", - "name": "markup.inserted keyword.control.less" - }, - "type-expression-constructor": { - "match": "(_)(?![[:alnum:]])|\\b([_[:lower:]][[:word:]]*)\\b(?!\\.[[:upper:]])", - "captures": { - "1": { "name": "comment" }, - "2": { "name": "support.type string.regexp" } - } - }, - "type-expression-label": { - "begin": "\\b([_[:lower:]][[:word:]]*)\\b(::)", - "end": "(?<==>)", - "beginCaptures": { - "1": { "name": "markup.inserted constant.language support.property-value entity.name.filename" }, - "2": { "name": "keyword.control" } - }, - "patterns": [ - { "include": "#type-expression" }, - { - "match": "(\\?)", - "captures": { - "1": { "name": "keyword.control.less" } - } - } - ] - }, - "type-expression-object": { - "comment": "FIXME: separate sub-rules", - "begin": "(<)", - "end": "(>)", - "captures": { - "1": { "name": "entity.name.function" } - }, - "patterns": [ - { - "begin": "(\\.\\.)", - "end": "(?=>)", - "beginCaptures": { - "1": { "name": "entity.other.attribute-name.css constant.language constant.numeric" } - } - }, - { - "comment": "FIXME: method item", - "begin": "(?=[_[:lower:]])", - "end": "(,)|(?=>)", - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { - "comment": "FIXME: method name", - "begin": "(?=[_[:lower:]])", - "end": "(?=:)", - "patterns": [ - { - "match": "\\b([_[:lower:]][[:word:]]*)\\b", - "captures": { - "1": { "name": "markup.inserted constant.language support.property-value entity.name.filename" } - } - } - ] - }, - { - "comment": "FIXME: method type", - "begin": "(:)", - "end": "(?=[,>])", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#type-expression" } - ] + }, + "value-expression-constructor": { + "match": "\\b([[:upper:]][[:word:]]*)\\b(?![[:space:]]*[\\.])", + "captures": { + "1": { + "name": "entity.other.attribute-name.css constant.language constant.numeric" + } } - ] - } - ] - }, - "type-expression-parens": { - "comment": "FIXME: proper tuple types", - "begin": "\\(", - "end": "\\)", - "patterns": [ - { - "begin": "\\b(module)\\b", - "end": "(?=[\\)])", - "beginCaptures": { - "1": { "name": "keyword.other message.error" } - }, - "patterns": [ - { "include": "#module-path-extended" }, - { "include": "#signature-expression-constraints" } - ] - }, - { - "match": ",", - "name": "keyword.control.less" - }, - { "include": "#type-expression" } - ] - }, - "type-expression-polymorphic-variant": { - "comment": "FIXME: proper parsing", - "begin": "(\\[)([<>])?", - "end": "(\\])", - "captures": { - "1": { "name": "entity.name.function" }, - "2": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { - "begin": "(\\|)?(?![#\\-:!?.@*/&%^+<=>|~$\\\\])[[:space:]]*", - "end": "(?=[;)}\\]]|\\|(?![#\\-:!?.@*/&%^+<=>|~$\\\\])|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#value-expression-constructor" }, - { - "match": "([:])|\\b(of)\\b|([&])", - "captures": { - "1": { "name": "keyword.control.less" }, - "2": { "name": "keyword.other" }, - "3": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - } - }, - { "include": "#value-expression-constructor-polymorphic" }, - { "include": "#type-expression" } - ] - } - ] - }, - "type-expression-record": { - "begin": "{", - "end": "}", - "patterns": [ - { "include": "#type-expression-record-item" } - ] - }, - "type-expression-record-field-sans-modifier": { - "begin": "\\b([_[:lower:]][[:word:]]*)\\b", - "end": "(,)|(?=[,}])", - "beginCaptures": { - "1": { "name": "markup.inserted constant.language support.property-value entity.name.filename" } - }, - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#comment" }, - { - "begin": "(:)", - "end": "(?=[,}])", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#type-expression" } - ] - } - ] - }, - "type-expression-record-field": { - "patterns": [ - { - "begin": "\\b(mutable)\\b", - "end": "(?<=[,])|(?=})", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation storage.modifier message.error" } - }, - "patterns": [ - { "include": "#type-expression-record-field-sans-modifier" } - ] - }, - { "include": "#type-expression-record-field-sans-modifier" } - ] - }, - "type-expression-record-item": { - "patterns": [ - { "include": "#comment" }, - { "include": "#module-path-simple-prefix" }, - { "include": "#type-expression-record-field" } - ] - }, - "type-expression-variable": { - "match": "(')([_[:lower:]][[:word:]]*)\\b(?!\\.[[:upper:]])", - "captures": { - "1": { "name": "comment" }, - "2": { "name": "variable.parameter string.other.link variable.language" } - } - }, - "value-expression": { - "patterns": [ - { "include": "#attribute" }, - { "include": "#comment" }, - { "include": "#extension-node" }, - { "include": "#jsx" }, - { "include": "#operator" }, - { "include": "#value-expression-builtin" }, - { "include": "#value-expression-if-then-else" }, - { "include": "#value-expression-atomic" }, - { "include": "#module-path-simple-prefix" }, - { - "match": "[:?]", - "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" - }, - { "include": "#record-path" } - ] - }, - "value-expression-atomic": { - "patterns": [ - { "include": "#value-expression-literal" }, - { "include": "#value-expression-literal-list-or-array" }, - { "include": "#value-expression-for" }, - { "include": "#value-expression-fun" }, - { "include": "#value-expression-block-or-record-or-object" }, - { "include": "#value-expression-label" }, - { "include": "#value-expression-parens" }, - { "include": "#value-expression-switch" }, - { "include": "#value-expression-try" }, - { "include": "#value-expression-while" } - ] - }, - "value-expression-atomic-with-paths": { - "patterns": [ - { "include": "#value-expression-atomic" }, - { "include": "#module-path-simple-prefix" }, - { "include": "#record-path-suffix" } - ] - }, - "value-expression-block": { - "begin": "{", - "end": "}", - "patterns": [ - { "include": "#value-expression-block-item" } - ] - }, - "value-expression-block-item": { - "patterns": [ - { "include": "#module-item-let" }, - { "include": "#module-item-open" }, - { "include": "#value-expression" } - ] - }, - "value-expression-block-look": { - "begin": "(?![[:space:]]*($|\\.\\.\\.|([[:upper:]][[:word:]]*\\.)*([[:lower:]][[:word:]]*)[[:space:]]*(?:,|:(?![=]))))", - "end": "(?=})", - "patterns": [ - { "include": "#value-expression-block-item" } - ] - }, - "value-expression-block-or-record-or-object": { - "begin": "{", - "end": "}", - "patterns": [ - { "include": "#comment" }, - { "include": "#module-path-simple-prefix" }, - { "include": "#value-expression-object-look" }, - { "include": "#value-expression-record-look" }, - { "include": "#value-expression-block-look" } - ] - }, - "value-expression-builtin": { - "match": "\\b(assert|decr|failwith|fprintf|ignore|incr|land|lazy|lor|lsl|lsr|lxor|mod|new|not|printf|ref)\\b|\\b(raise)\\b", - "captures": { - "1": { "name": "keyword.control message.error" }, - "2": { "name": "keyword.control.trycatch" } - } - }, - "value-expression-constructor": { - "match": "\\b([[:upper:]][[:word:]]*)\\b(?![[:space:]]*[\\.])", - "captures": { - "1": { "name": "entity.other.attribute-name.css constant.language constant.numeric" } - } - }, - "value-expression-constructor-polymorphic": { - "match": "(`)([[:alpha:]][[:word:]]*)\\b(?!\\.)", - "captures": { - "1": { "name": "constant.other.symbol keyword.control.less variable.parameter" }, - "2": { "name": "entity.other.attribute-name.css constant.language constant.numeric" } - } - }, - "value-expression-for": { - "begin": "(?=\\b(for)\\b)", - "end": "(?<=})|(?=[;]|\\b(and|as|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|rec|type|val|with)\\b)", - "patterns": [ - { "include": "#value-expression-for-head" }, - { "include": "#value-expression-block" } - ] - }, - "value-expression-for-head": { - "begin": "(?=\\b(for)\\b)", - "end": "(?={)|(?=[;]|\\b(and|as|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|rec|type|val|with)\\b)", - "patterns": [ - { - "begin": "\\b(for)\\b", - "end": "(?=\\b(in)\\b)|(?=[;]|\\b(and|as|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control.loop" } - }, - "patterns": [ - { "include": "#comment" }, - { "include": "#pattern-variable" } - ] - }, - { - "begin": "\\b(in)\\b", - "end": "(?=\\b(to)\\b)|(?=[;]|\\b(and|as|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control.loop" } - }, - "patterns": [ - { "include": "#comment" }, - { "include": "#value-expression-atomic-with-paths" } - ] - }, - { - "begin": "\\b(to)\\b", - "end": "(?={)|(?=[;]|\\b(and|as|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control.loop" } - }, - "patterns": [ - { "include": "#comment" }, - { "include": "#value-expression-atomic-with-paths" } - ] - }, - { "include": "#value-expression-block" } - ] - }, - "value-expression-fun": { - "begin": "\\b(fun)\\b", - "end": "(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control" } - }, - "patterns": [ - { "include": "#value-expression-fun-pattern-match-rule-lhs" }, - { "include": "#value-expression-fun-pattern-match-rule-rhs" } - ] - }, - "value-expression-fun-pattern-match-rule-lhs": { - "begin": "(?=\\|(?![#\\-:!?.@*/&%^+<=>|~$\\\\]))|(?<=fun)", - "end": "(\\|(?![#\\-:!?.@*/&%^+<=>|~$\\\\]))|(?==>)|(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", - "applyEndPatternLast": true, - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#module-item-let-value-param" } - ] - }, - "value-expression-fun-pattern-match-rule-rhs": { - "begin": "(=>)", - "end": "(?=[;\\)}]|\\|(?![#\\-:!?.@*/&%^+<=>|~$\\\\])|\\b(and)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control.less" } - }, - "patterns": [ - { "include": "#value-expression" } - ] - }, - "value-expression-if-then-else": { - "begin": "\\b(if)\\b", - "end": "(?=[;\\)\\]}])", - "applyEndPatternLast": true, - "beginCaptures": { - "1": { "name": "keyword.control.conditional" } - }, - "patterns": [ - { "include": "#comment" }, - { - "begin": "\\b(else)\\b", - "end": "(?=[;\\)\\]}])", - "beginCaptures": { - "1": { "name": "keyword.control.conditional" } - }, - "patterns": [ - { "include": "#value-expression" } - ] - }, - { "include": "#value-expression-atomic-with-paths" } - ] - }, - "value-expression-lazy": { - "comment": "FIXME", - "match": "\\b(lazy)\\b", - "captures": { - "1": { "name": "keyword.other" } - } - }, - "value-expression-label": { - "begin": "\\b([_[:lower:]][[:word:]]*)\\b[[:space:]]*(::)(\\?)?", - "end": "(?![[:space:]])", - "beginCaptures": { - "1": { "name": "markup.inserted constant.language support.property-value entity.name.filename" }, - "2": { "name": "keyword.control" }, - "3": { "name": "storage.type" } - }, - "patterns": [ - { "include": "#value-expression" } - ] - }, - "value-expression-literal": { - "patterns": [ - { "include": "#value-expression-literal-boolean" }, - { "include": "#value-expression-literal-character" }, - { "include": "#value-expression-constructor" }, - { "include": "#value-expression-constructor-polymorphic" }, - { "include": "#value-expression-lazy" }, - { "include": "#value-expression-literal-numeric" }, - { "include": "#value-expression-literal-string" }, - { "include": "#value-expression-literal-unit" } - ] - }, - "value-expression-literal-boolean": { - "match": "\\b(false|true)\\b", - "name": "entity.other.attribute-name.css constant.language constant.numeric" - }, - "value-expression-literal-character": { - "match": "(')([[:space:]]|[[:graph:]]|\\\\[\\\\\"'ntbr]|\\\\[[:digit:]][[:digit:]][[:digit:]]|\\\\x[[:xdigit:]][[:xdigit:]]|\\\\o[0-3][0-7][0-7])(')", - "name": "constant.character" - }, - "value-expression-literal-list-or-array": { - "begin": "(\\[\\|?)(?![@%])", - "end": "(\\|?\\])", - "beginCaptures": { - "1": { "name": "constant.language.list" } - }, - "endCaptures": { - "1": { "name": "constant.language.list" } - }, - "patterns": [ - { "include": "#value-expression-literal-list-or-array-separator" }, - { "include": "#value-expression" }, - { "include": "#value-expression-literal-list-or-array" } - ] - }, - "value-expression-literal-list-or-array-separator": { - "match": "(,)|(\\.\\.\\.)", - "captures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" }, - "2": { "name": "keyword.control" } - } - }, - "value-expression-literal-numeric": { - "patterns": [ - { - "match": "([-])?([[:digit:]][_[:digit:]]*)(?:(\\.)([_[:digit:]]*))?(?:([eE])([\\-\\+])?([[:digit:]][_[:digit:]]*))?(?![bBoOxX])", - "captures": { - "1": { "name": "keyword.control.less" }, - "2": { "name": "constant.numeric" }, - "3": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" }, - "4": { "name": "constant.numeric" }, - "5": { "name": "keyword.control.less" }, - "6": { "name": "keyword.control.less" }, - "7": { "name": "constant.numeric" } - } - }, - { - "match": "([-])?(0[xX])([[:xdigit:]][_[:xdigit:]]*)(?:(\\.)([_[:xdigit:]]*))?(?:([pP])([\\-\\+])?([[:digit:]][_[:digit:]]*))?", - "captures": { - "1": { "name": "keyword.control.less" }, - "2": { "name": "keyword.control.less" }, - "3": { "name": "constant.numeric" }, - "4": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" }, - "5": { "name": "constant.numeric" }, - "6": { "name": "keyword.control.less" }, - "7": { "name": "keyword.control.less" }, - "8": { "name": "constant.numeric" } - } - }, - { - "match": "([-])?(0[oO])([0-7][_0-7]*)", - "captures": { - "1": { "name": "keyword.control.less" }, - "2": { "name": "keyword.control.less" }, - "3": { "name": "constant.numeric" } - } - }, - { - "match": "([-])?(0[bB])([0-1][_0-1]*)", - "captures": { - "1": { "name": "keyword.control.less" }, - "2": { "name": "keyword.control.less" }, - "3": { "name": "constant.numeric" } - } - } - ] - }, - "value-expression-literal-string": { - "patterns": [ - { - "begin": "(?|~$\\\\]))|(?<=fun)", + "end": + "(\\|(?![#\\-:!?.@*/&%^+<=>|~$\\\\]))|(?==>)|(?=[;\\)}]|\\b(and|class|constraint|exception|external|include|inherit|let|method|module|nonrec|open|private|rec|type|val|with)\\b)", + "applyEndPatternLast": true, + "beginCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "endCaptures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + } + }, + "patterns": [{ "include": "#module-item-let-value-param" }] + }, + "value-expression-fun-pattern-match-rule-rhs": { + "begin": "(=>)", + "end": "(?=[;\\)}]|\\|(?![#\\-:!?.@*/&%^+<=>|~$\\\\])|\\b(and)\\b)", + "beginCaptures": { + "1": { "name": "keyword.control.less" } + }, + "patterns": [{ "include": "#value-expression" }] + }, + "value-expression-if-then-else": { + "begin": "\\b(if)\\b", + "end": "(?=[;\\)\\]}])", + "applyEndPatternLast": true, + "beginCaptures": { + "1": { "name": "keyword.control.conditional" } + }, + "patterns": [ + { "include": "#comment" }, + { + "begin": "\\b(else)\\b", + "end": "(?=[;\\)\\]}])", + "beginCaptures": { + "1": { "name": "keyword.control.conditional" } + }, + "patterns": [{ "include": "#value-expression" }] + }, + { "include": "#value-expression-atomic-with-paths" } + ] + }, + "value-expression-lazy": { + "comment": "FIXME", + "match": "\\b(lazy)\\b", + "captures": { + "1": { "name": "keyword.other" } } - ] - }, - { - "begin": "\\b[[:upper:]][[:word:]]*\\b", - "end": "(,)|(?=})", - "beginCaptures": { - "1": { "name": "support.class entity.name.class" } - }, - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#module-path-simple-prefix" }, - { - "begin": "(:)", - "end": "(?=[,}])", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { "include": "#value-expression" } - ] + }, + "value-expression-label": { + "begin": "\\b([_[:lower:]][[:word:]]*)\\b[[:space:]]*(::)(\\?)?", + "end": "(?![[:space:]])", + "beginCaptures": { + "1": { + "name": + "markup.inserted constant.language support.property-value entity.name.filename" + }, + "2": { "name": "keyword.control" }, + "3": { "name": "storage.type" } + }, + "patterns": [{ "include": "#value-expression" }] + }, + "value-expression-literal": { + "patterns": [ + { "include": "#value-expression-literal-boolean" }, + { "include": "#value-expression-literal-character" }, + { "include": "#value-expression-constructor" }, + { "include": "#value-expression-constructor-polymorphic" }, + { "include": "#value-expression-lazy" }, + { "include": "#value-expression-literal-numeric" }, + { "include": "#value-expression-literal-string" }, + { "include": "#value-expression-literal-unit" } + ] + }, + "value-expression-literal-boolean": { + "match": "\\b(false|true)\\b", + "name": "entity.other.attribute-name.css constant.language constant.numeric" + }, + "value-expression-literal-character": { + "match": + "(')([[:space:]]|[[:graph:]]|\\\\[\\\\\"'ntbr]|\\\\[[:digit:]][[:digit:]][[:digit:]]|\\\\x[[:xdigit:]][[:xdigit:]]|\\\\o[0-3][0-7][0-7])(')", + "name": "constant.character" + }, + "value-expression-literal-list-or-array": { + "begin": "(\\[\\|?)(?![@%])", + "end": "(\\|?\\])", + "beginCaptures": { + "1": { "name": "constant.language.list" } + }, + "endCaptures": { + "1": { "name": "constant.language.list" } + }, + "patterns": [ + { "include": "#value-expression-literal-list-or-array-separator" }, + { "include": "#value-expression" }, + { "include": "#value-expression-literal-list-or-array" } + ] + }, + "value-expression-literal-list-or-array-separator": { + "match": "(,)|(\\.\\.\\.)", + "captures": { + "1": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + }, + "2": { "name": "keyword.control" } } - ] - }, - { - "begin": "\\b([[:lower:]][[:word:]]*)\\b", - "end": "(,)|(?=})", - "beginCaptures": { - "1": { "name": "markup.inserted constant.language support.property-value entity.name.filename" } - }, - "endCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ - { - "begin": "(:)", - "end": "(?=[,}])", - "beginCaptures": { - "1": { "name": "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" } - }, - "patterns": [ + }, + "value-expression-literal-numeric": { + "patterns": [ + { + "match": + "([-])?([[:digit:]][_[:digit:]]*)(?:(\\.)([_[:digit:]]*))?(?:([eE])([\\-\\+])?([[:digit:]][_[:digit:]]*))?(?![bBoOxX])", + "captures": { + "1": { "name": "keyword.control.less" }, + "2": { "name": "constant.numeric" }, + "3": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + }, + "4": { "name": "constant.numeric" }, + "5": { "name": "keyword.control.less" }, + "6": { "name": "keyword.control.less" }, + "7": { "name": "constant.numeric" } + } + }, + { + "match": + "([-])?(0[xX])([[:xdigit:]][_[:xdigit:]]*)(?:(\\.)([_[:xdigit:]]*))?(?:([pP])([\\-\\+])?([[:digit:]][_[:digit:]]*))?", + "captures": { + "1": { "name": "keyword.control.less" }, + "2": { "name": "keyword.control.less" }, + "3": { "name": "constant.numeric" }, + "4": { + "name": + "variable.other.class.js variable.interpolation keyword.operator keyword.control message.error" + }, + "5": { "name": "constant.numeric" }, + "6": { "name": "keyword.control.less" }, + "7": { "name": "keyword.control.less" }, + "8": { "name": "constant.numeric" } + } + }, + { + "match": "([-])?(0[oO])([0-7][_0-7]*)", + "captures": { + "1": { "name": "keyword.control.less" }, + "2": { "name": "keyword.control.less" }, + "3": { "name": "constant.numeric" } + } + }, + { + "match": "([-])?(0[bB])([0-1][_0-1]*)", + "captures": { + "1": { "name": "keyword.control.less" }, + "2": { "name": "keyword.control.less" }, + "3": { "name": "constant.numeric" } + } + } + ] + }, + "value-expression-literal-string": { + "patterns": [ + { + "begin": "(?|~$\\\\]))", + "end": "(?==>|[;\\)}])", + "patterns": [{ "include": "#pattern-guard" }, { "include": "#pattern" }] + }, + "value-expression-switch-pattern-match-rule-rhs": { + "begin": "(=>)", + "end": "(?=}|\\|(?![#\\-:!?.@*/&%^+<=>|~$\\\\]))", + "beginCaptures": { + "1": { "name": "keyword.control.less" } + }, + "patterns": [{ "include": "#value-expression-block-item" }] + }, + "value-expression-try": { + "begin": "\\b(try)\\b", + "end": + "(?<=})|(?=[;\\)]|\\b(and|as|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|rec|type|val|with)\\b)", + "beginCaptures": { + "1": { "name": "keyword.control.trycatch" } + }, + "patterns": [ + { "include": "#value-expression-try-head" }, + { "include": "#value-expression-switch-body" } + ] + }, + "value-expression-try-head": { + "begin": "(?<=try)", + "end": + "(?|~$\\\\]))", - "end": "(?==>|[;\\)}])", - "patterns": [ - { "include": "#pattern-guard" }, - { "include": "#pattern" } - ] - }, - "value-expression-switch-pattern-match-rule-rhs": { - "begin": "(=>)", - "end": "(?=}|\\|(?![#\\-:!?.@*/&%^+<=>|~$\\\\]))", - "beginCaptures": { - "1": { "name": "keyword.control.less" } - }, - "patterns": [ - { "include": "#value-expression-block-item" } - ] - }, - "value-expression-try": { - "begin": "\\b(try)\\b", - "end": "(?<=})|(?=[;\\)]|\\b(and|as|class|constraint|exception|external|include|inherit|let|method|nonrec|open|private|rec|type|val|with)\\b)", - "beginCaptures": { - "1": { "name": "keyword.control.trycatch" } - }, - "patterns": [ - { "include": "#value-expression-try-head" }, - { "include": "#value-expression-switch-body" } - ] - }, - "value-expression-try-head": { - "begin": "(?<=try)", - "end": "(?=|<|>|from|to|through)", - "name": "keyword.control.operator" - }, - { - "include": "#variable" - }, - { - "include": "#property_values" - }, - { - "include": "$self" - } - ] - }, - "at_rule_function": { - "patterns": [ - { - "begin": "\\s*((@)function\\b)\\s*", - "captures": { - "1": { - "name": "keyword.control.at-rule.function.scss" - }, - "2": { - "name": "punctuation.definition.keyword.scss" - }, - "3": { - "name": "entity.name.function.scss" - } - }, - "end": "\\s*(?={)", - "name": "meta.at-rule.function.scss", - "patterns": [ - { - "include": "#function_attributes" - } - ] - }, - { - "captures": { - "1": { - "name": "keyword.control.at-rule.function.scss" - }, - "2": { - "name": "punctuation.definition.keyword.scss" - }, - "3": { - "name": "entity.name.function.scss" - } - }, - "match": "\\s*((@)function\\b)\\s*", - "name": "meta.at-rule.function.scss" - } - ] - }, - "at_rule_if": { - "begin": "\\s*((@)if\\b)\\s*", - "captures": { - "1": { - "name": "keyword.control.if.scss" - }, - "2": { - "name": "punctuation.definition.keyword.scss" - } - }, - "end": "\\s*(?={)", - "name": "meta.at-rule.if.scss", - "patterns": [ - { - "include": "#conditional_operators" - }, - { - "include": "#variable" - }, - { - "include": "#property_values" - } - ] - }, - "at_rule_import": { - "begin": "\\s*((@)import\\b)\\s*", - "captures": { - "1": { - "name": "keyword.control.at-rule.import.scss" - }, - "2": { - "name": "punctuation.definition.keyword.scss" - } - }, - "end": "\\s*((?=;)|(?=}))", - "name": "meta.at-rule.import.scss", - "patterns": [ - { - "include": "#variable" - }, - { - "include": "#string_single" - }, - { - "include": "#string_double" - }, - { - "include": "#functions" - }, - { - "include": "#comment_line" - } - ] - }, - "at_rule_include": { - "patterns": [ - { - "begin": "(?<=@include)\\s+([\\w-]+)\\s*(\\()", - "beginCaptures": { - "1": { - "name": "entity.name.function.scss" - }, - "2": { - "name": "punctuation.definition.parameters.begin.bracket.round.scss" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.definition.parameters.end.bracket.round.scss" - } - }, - "name": "meta.at-rule.include.scss", - "patterns": [ - { - "include": "#function_attributes" - } - ] - }, - { - "match": "(?<=@include)\\s+([\\w-]+)", - "captures": { - "0": { - "name": "meta.at-rule.include.scss" - }, - "1": { - "name": "entity.name.function.scss" - } - } - }, - { - "match": "((@)include)\\b", - "captures": { - "0": { - "name": "meta.at-rule.include.scss" - }, - "1": { - "name": "keyword.control.at-rule.include.scss" - }, - "2": { - "name": "punctuation.definition.keyword.scss" - } - } - } - ] - }, - "at_rule_keyframes": { - "begin": "(?<=^|\\s)(@)(?:-(?:webkit|moz)-)?keyframes\\b", - "beginCaptures": { - "0": { - "name": "keyword.control.at-rule.keyframes.scss" - }, - "1": { - "name": "punctuation.definition.keyword.scss" - } - }, - "end": "(?<=})", - "name": "meta.at-rule.keyframes.scss", - "patterns": [ - { - "match": "(?<=@keyframes)\\s+((?:[_A-Za-z][-\\w]|-[_A-Za-z])[-\\w]*)", - "captures": { - "1": { - "name": "entity.name.function.scss" - } - } - }, - { - "begin": "(?<=@keyframes)\\s+(\")", - "beginCaptures": { - "1": { - "name": "punctuation.definition.string.begin.scss" - } - }, - "end": "\"", - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.scss" - } - }, - "name": "string.quoted.double.scss", - "contentName": "entity.name.function.scss", - "patterns": [ - { - "match": "\\\\(\\h{1,6}|.)", - "name": "constant.character.escape.scss" - }, - { - "include": "#interpolation" - } - ] - }, - { - "begin": "(?<=@keyframes)\\s+(')", - "beginCaptures": { - "1": { - "name": "punctuation.definition.string.begin.scss" - } - }, - "end": "'", - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.scss" - } - }, - "name": "string.quoted.single.scss", - "contentName": "entity.name.function.scss", - "patterns": [ - { - "match": "\\\\(\\h{1,6}|.)", - "name": "constant.character.escape.scss" - }, - { - "include": "#interpolation" - } - ] - }, - { - "begin": "{", - "beginCaptures": { - "0": { - "name": "punctuation.section.keyframes.begin.scss" - } - }, - "end": "}", - "endCaptures": { - "0": { - "name": "punctuation.section.keyframes.end.scss" - } - }, - "patterns": [ - { - "match": "\\b(?:(?:100|[1-9]\\d|\\d)%|from|to)(?=\\s*{)", - "name": "entity.other.attribute-name.scss" - }, - { - "include": "#flow_control" - }, - { - "include": "#interpolation" - }, - { - "include": "#property_list" - }, - { - "include": "#rules" - } - ] - } - ] - }, - "at_rule_media": { - "patterns": [ - { - "begin": "^\\s*((@)media)\\b", - "beginCaptures": { - "1": { - "name": "keyword.control.at-rule.media.scss" - }, - "2": { - "name": "punctuation.definition.keyword.scss" - } - }, - "end": "\\s*(?={)", - "name": "meta.at-rule.media.scss", - "patterns": [ - { - "include": "#comment_block" - }, - { - "include": "#comment_line" - }, - { - "match": "\\b(only)\\b", - "name": "keyword.control.operator.css.scss" - }, - { - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.definition.media-query.begin.bracket.round.scss" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.definition.media-query.end.bracket.round.scss" - } - }, - "name": "meta.property-list.media-query.scss", - "patterns": [ - { - "begin": "(?=|<|>", - "name": "keyword.operator.comparison.scss" - }, - "logical_operators": { - "match": "\\b(not|or|and)\\b", - "name": "keyword.operator.logical.scss" - }, - "map": { - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.definition.map.begin.bracket.round.scss" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.definition.map.end.bracket.round.scss" - } - }, - "name": "meta.definition.variable.map.scss", - "patterns": [ - { - "include": "#comment_block" - }, - { - "include": "#comment_line" - }, - { - "match": "\\b([\\w-]+)\\s*(:)", - "captures": { - "1": { - "name": "support.type.map.key.scss" - }, - "2": { - "name": "punctuation.separator.key-value.scss" - } - } - }, - { - "match": ",", - "name": "punctuation.separator.delimiter.scss" - }, - { - "include": "#map" - }, - { - "include": "#property_values" - }, - { - "include": "#variable" - } - ] - }, - "operators": { - "match": "[-+*/](?!\\s*[-+*/])", - "name": "keyword.operator.css" - }, - "parameters": { - "patterns": [ - { - "include": "#variable" - }, - { - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.definition.begin.bracket.round.scss" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.definition.end.bracket.round.scss" - } - }, - "patterns": [ - { - "include": "#function_attributes" - } - ] - }, - { - "include": "#property_values" - }, - { - "include": "#comment_block" - }, - { - "match": "[^'\",) \\t]+", - "name": "variable.parameter.url.scss" - }, - { - "match": ",", - "name": "punctuation.separator.delimiter.scss" - } - ] - }, - "properties": { - "patterns": [ - { - "begin": "(?+~|] # - Another selector\n | /\\* # - A block comment\n)", - "name": "entity.other.attribute-name.class.css", - "captures": { - "1": { - "name": "punctuation.definition.entity.css" - }, - "2": { - "patterns": [ - { - "include": "#interpolation" - }, - { - "match": "\\\\([0-9a-fA-F]{1,6}|.)", - "name": "constant.character.escape.scss" - }, - { - "match": "\\$|}", - "name": "invalid.illegal.scss" - } - ] - } - } - }, - "selector_custom": { - "match": "\\b([a-zA-Z0-9]+(-[a-zA-Z0-9]+)+)(?=\\.|\\s++[^:]|\\s*[,\\[{]|:(link|visited|hover|active|focus|target|lang|disabled|enabled|checked|indeterminate|root|nth-(child|last-child|of-type|last-of-type)|first-child|last-child|first-of-type|last-of-type|only-child|only-of-type|empty|not|valid|invalid)(\\([0-9A-Za-z]*\\))?)", - "name": "entity.name.tag.custom.scss" - }, - "selector_id": { - "match": "(?x)\n(\\#) # Valid id-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= $ # - End of the line\n | [\\s,.\\#)\\[:{>+~|] # - Another selector\n | /\\* # - A block comment\n)", - "name": "entity.other.attribute-name.id.css", - "captures": { - "1": { - "name": "punctuation.definition.entity.css" - }, - "2": { - "patterns": [ - { - "include": "#interpolation" - }, - { - "match": "\\\\([0-9a-fA-F]{1,6}|.)", - "name": "constant.character.escape.scss" - }, - { - "match": "\\$|}", - "name": "invalid.illegal.identifier.scss" - } - ] - } - } - }, - "selector_placeholder": { - "match": "(?x)\n(%) # Valid placeholder-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= ; # - End of statement\n | $ # - End of the line\n | [\\s,.\\#)\\[:{>+~|] # - Another selector\n | /\\* # - A block comment\n)", - "name": "entity.other.attribute-name.placeholder.css", - "captures": { - "1": { - "name": "punctuation.definition.entity.css" - }, - "2": { - "patterns": [ - { - "include": "#interpolation" - }, - { - "match": "\\\\([0-9a-fA-F]{1,6}|.)", - "name": "constant.character.escape.scss" - }, - { - "match": "\\$|}", - "name": "invalid.illegal.identifier.scss" - } - ] - } - } - }, - "parent_selector_suffix": { - "match": "(?x)\n(?<=&)\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= $ # - End of the line\n | [\\s,.\\#)\\[:{>+~|] # - Another selector\n | /\\* # - A block comment\n)", - "name": "entity.other.attribute-name.parent-selector-suffix.css", - "captures": { - "1": { - "name": "punctuation.definition.entity.css" - }, - "2": { - "patterns": [ - { - "include": "#interpolation" - }, - { - "match": "\\\\([0-9a-fA-F]{1,6}|.)", - "name": "constant.character.escape.scss" - }, - { - "match": "\\$|}", - "name": "invalid.illegal.identifier.scss" - } - ] - } - } - }, - "selector_pseudo_class": { - "patterns": [ - { - "begin": "((:)\\bnth-(?:child|last-child|of-type|last-of-type))(\\()", - "beginCaptures": { - "1": { - "name": "entity.other.attribute-name.pseudo-class.css" - }, - "2": { - "name": "punctuation.definition.entity.css" - }, - "3": { - "name": "punctuation.definition.pseudo-class.begin.bracket.round.css" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.definition.pseudo-class.end.bracket.round.css" - } - }, - "patterns": [ - { - "include": "#interpolation" - }, - { - "match": "\\d+", - "name": "constant.numeric.css" - }, - { - "match": "(?<=\\d)n\\b|\\b(n|even|odd)\\b", - "name": "constant.other.scss" - }, - { - "match": "\\w+", - "name": "invalid.illegal.scss" - } - ] - }, - { - "include": "source.css#pseudo-classes" - }, - { - "include": "source.css#pseudo-elements" - }, - { - "include": "source.css#functional-pseudo-classes" - } - ] - }, - "selectors": { - "patterns": [ - { - "include": "source.css#tag-names" - }, - { - "include": "#selector_custom" - }, - { - "include": "#selector_class" - }, - { - "include": "#selector_id" - }, - { - "include": "#selector_pseudo_class" - }, - { - "include": "#tag_wildcard" - }, - { - "include": "#tag_parent_reference" - }, - { - "include": "source.css#pseudo-elements" - }, - { - "include": "#selector_attribute" - }, - { - "include": "#selector_placeholder" - }, - { - "include": "#parent_selector_suffix" - } - ] - }, - "string_double": { - "begin": "\"", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.scss" - } - }, - "end": "\"", - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.scss" - } - }, - "name": "string.quoted.double.scss", - "patterns": [ - { - "match": "\\\\(\\h{1,6}|.)", - "name": "constant.character.escape.scss" - }, - { - "include": "#interpolation" - } - ] - }, - "string_single": { - "begin": "'", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.scss" - } - }, - "end": "'", - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.scss" - } - }, - "name": "string.quoted.single.scss", - "patterns": [ - { - "match": "\\\\(\\h{1,6}|.)", - "name": "constant.character.escape.scss" - }, - { - "include": "#interpolation" - } - ] - }, - "tag_parent_reference": { - "match": "&", - "name": "entity.name.tag.reference.scss" - }, - "tag_wildcard": { - "match": "\\*", - "name": "entity.name.tag.wildcard.scss" - }, - "variable": { - "patterns": [ - { - "include": "#variables" - }, - { - "include": "#interpolation" - } - ] - }, - "variable_setting": { - "begin": "(?=\\$[\\w-]+\\s*:)", - "end": ";", - "endCaptures": { - "0": { - "name": "punctuation.terminator.rule.scss" - } - }, - "contentName": "meta.definition.variable.scss", - "patterns": [ - { - "match": "\\$[\\w-]+(?=\\s*:)", - "name": "variable.scss" - }, - { - "begin": ":", - "beginCaptures": { - "0": { - "name": "punctuation.separator.key-value.scss" - } - }, - "end": "(?=;)", - "patterns": [ - { - "include": "#comment_block" - }, - { - "include": "#comment_line" - }, - { - "include": "#map" - }, - { - "include": "#property_values" - }, - { - "include": "#variable" - }, - { - "match": ",", - "name": "punctuation.separator.delimiter.scss" - } - ] - } - ] - }, - "variables": { - "match": "(\\$|\\-\\-)[A-Za-z0-9_-]+\\b", - "name": "variable.scss" - } - } -} \ No newline at end of file + "information_for_contributors": [ + "This file has been converted from https://github.com/atom/language-sass/blob/master/grammars/scss.cson", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": + "https://github.com/atom/language-sass/commit/a07688bd078f420f56df6221e9263d80e738869b", + "scopeName": "source.css.scss", + "name": "SCSS", + "fileTypes": ["scss", "css.scss", "css.scss.erb", "scss.erb", "scss.liquid"], + "patterns": [ + { + "include": "#variable_setting" + }, + { + "include": "#at_rule_include" + }, + { + "include": "#at_rule_import" + }, + { + "include": "#general" + }, + { + "include": "#flow_control" + }, + { + "include": "#rules" + }, + { + "include": "#property_list" + }, + { + "include": "#at_rule_mixin" + }, + { + "include": "#at_rule_media" + }, + { + "include": "#at_rule_function" + }, + { + "include": "#at_rule_charset" + }, + { + "include": "#at_rule_option" + }, + { + "include": "#at_rule_namespace" + }, + { + "include": "#at_rule_fontface" + }, + { + "include": "#at_rule_page" + }, + { + "include": "#at_rule_keyframes" + }, + { + "include": "#at_rule_at_root" + }, + { + "include": "#at_rule_supports" + }, + { + "match": ";", + "name": "punctuation.terminator.rule.css" + } + ], + "repository": { + "at_rule_charset": { + "begin": "\\s*((@)charset\\b)\\s*", + "captures": { + "1": { + "name": "keyword.control.at-rule.charset.scss" + }, + "2": { + "name": "punctuation.definition.keyword.scss" + } + }, + "end": "\\s*((?=;|$))", + "name": "meta.at-rule.charset.scss", + "patterns": [ + { + "include": "#variable" + }, + { + "include": "#string_single" + }, + { + "include": "#string_double" + } + ] + }, + "at_rule_content": { + "begin": "\\s*((@)content\\b)\\s*", + "captures": { + "1": { + "name": "keyword.control.content.scss" + } + }, + "end": "\\s*((?=;))", + "name": "meta.content.scss", + "patterns": [ + { + "include": "#variable" + }, + { + "include": "#selectors" + }, + { + "include": "#property_values" + } + ] + }, + "at_rule_each": { + "begin": "\\s*((@)each\\b)\\s*", + "captures": { + "1": { + "name": "keyword.control.each.scss" + }, + "2": { + "name": "punctuation.definition.keyword.scss" + } + }, + "end": "\\s*((?=}))", + "name": "meta.at-rule.each.scss", + "patterns": [ + { + "match": "\\b(in|,)\\b", + "name": "keyword.control.operator" + }, + { + "include": "#variable" + }, + { + "include": "#property_values" + }, + { + "include": "$self" + } + ] + }, + "at_rule_else": { + "begin": "\\s*((@)else(\\s*(if)?))\\s*", + "captures": { + "1": { + "name": "keyword.control.else.scss" + }, + "2": { + "name": "punctuation.definition.keyword.scss" + } + }, + "end": "\\s*(?={)", + "name": "meta.at-rule.else.scss", + "patterns": [ + { + "include": "#conditional_operators" + }, + { + "include": "#variable" + }, + { + "include": "#property_values" + } + ] + }, + "at_rule_extend": { + "begin": "\\s*((@)extend\\b)\\s*", + "captures": { + "1": { + "name": "keyword.control.at-rule.extend.scss" + }, + "2": { + "name": "punctuation.definition.keyword.scss" + } + }, + "end": "\\s*(?=;)", + "name": "meta.at-rule.extend.scss", + "patterns": [ + { + "include": "#variable" + }, + { + "include": "#selectors" + }, + { + "include": "#property_values" + } + ] + }, + "at_rule_fontface": { + "patterns": [ + { + "begin": "^\\s*((@)font-face\\b)", + "beginCaptures": { + "1": { + "name": "keyword.control.at-rule.fontface.scss" + }, + "2": { + "name": "punctuation.definition.keyword.scss" + } + }, + "end": "\\s*(?={)", + "name": "meta.at-rule.fontface.scss", + "patterns": [ + { + "include": "#function_attributes" + } + ] + } + ] + }, + "at_rule_for": { + "begin": "\\s*((@)for\\b)\\s*", + "captures": { + "1": { + "name": "keyword.control.for.scss" + }, + "2": { + "name": "punctuation.definition.keyword.scss" + } + }, + "end": "\\s*(?={)", + "name": "meta.at-rule.for.scss", + "patterns": [ + { + "match": "(==|!=|<=|>=|<|>|from|to|through)", + "name": "keyword.control.operator" + }, + { + "include": "#variable" + }, + { + "include": "#property_values" + }, + { + "include": "$self" + } + ] + }, + "at_rule_function": { + "patterns": [ + { + "begin": "\\s*((@)function\\b)\\s*", + "captures": { + "1": { + "name": "keyword.control.at-rule.function.scss" + }, + "2": { + "name": "punctuation.definition.keyword.scss" + }, + "3": { + "name": "entity.name.function.scss" + } + }, + "end": "\\s*(?={)", + "name": "meta.at-rule.function.scss", + "patterns": [ + { + "include": "#function_attributes" + } + ] + }, + { + "captures": { + "1": { + "name": "keyword.control.at-rule.function.scss" + }, + "2": { + "name": "punctuation.definition.keyword.scss" + }, + "3": { + "name": "entity.name.function.scss" + } + }, + "match": "\\s*((@)function\\b)\\s*", + "name": "meta.at-rule.function.scss" + } + ] + }, + "at_rule_if": { + "begin": "\\s*((@)if\\b)\\s*", + "captures": { + "1": { + "name": "keyword.control.if.scss" + }, + "2": { + "name": "punctuation.definition.keyword.scss" + } + }, + "end": "\\s*(?={)", + "name": "meta.at-rule.if.scss", + "patterns": [ + { + "include": "#conditional_operators" + }, + { + "include": "#variable" + }, + { + "include": "#property_values" + } + ] + }, + "at_rule_import": { + "begin": "\\s*((@)import\\b)\\s*", + "captures": { + "1": { + "name": "keyword.control.at-rule.import.scss" + }, + "2": { + "name": "punctuation.definition.keyword.scss" + } + }, + "end": "\\s*((?=;)|(?=}))", + "name": "meta.at-rule.import.scss", + "patterns": [ + { + "include": "#variable" + }, + { + "include": "#string_single" + }, + { + "include": "#string_double" + }, + { + "include": "#functions" + }, + { + "include": "#comment_line" + } + ] + }, + "at_rule_include": { + "patterns": [ + { + "begin": "(?<=@include)\\s+([\\w-]+)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.scss" + }, + "2": { + "name": "punctuation.definition.parameters.begin.bracket.round.scss" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.end.bracket.round.scss" + } + }, + "name": "meta.at-rule.include.scss", + "patterns": [ + { + "include": "#function_attributes" + } + ] + }, + { + "match": "(?<=@include)\\s+([\\w-]+)", + "captures": { + "0": { + "name": "meta.at-rule.include.scss" + }, + "1": { + "name": "entity.name.function.scss" + } + } + }, + { + "match": "((@)include)\\b", + "captures": { + "0": { + "name": "meta.at-rule.include.scss" + }, + "1": { + "name": "keyword.control.at-rule.include.scss" + }, + "2": { + "name": "punctuation.definition.keyword.scss" + } + } + } + ] + }, + "at_rule_keyframes": { + "begin": "(?<=^|\\s)(@)(?:-(?:webkit|moz)-)?keyframes\\b", + "beginCaptures": { + "0": { + "name": "keyword.control.at-rule.keyframes.scss" + }, + "1": { + "name": "punctuation.definition.keyword.scss" + } + }, + "end": "(?<=})", + "name": "meta.at-rule.keyframes.scss", + "patterns": [ + { + "match": "(?<=@keyframes)\\s+((?:[_A-Za-z][-\\w]|-[_A-Za-z])[-\\w]*)", + "captures": { + "1": { + "name": "entity.name.function.scss" + } + } + }, + { + "begin": "(?<=@keyframes)\\s+(\")", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.scss" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.scss" + } + }, + "name": "string.quoted.double.scss", + "contentName": "entity.name.function.scss", + "patterns": [ + { + "match": "\\\\(\\h{1,6}|.)", + "name": "constant.character.escape.scss" + }, + { + "include": "#interpolation" + } + ] + }, + { + "begin": "(?<=@keyframes)\\s+(')", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.scss" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.scss" + } + }, + "name": "string.quoted.single.scss", + "contentName": "entity.name.function.scss", + "patterns": [ + { + "match": "\\\\(\\h{1,6}|.)", + "name": "constant.character.escape.scss" + }, + { + "include": "#interpolation" + } + ] + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.keyframes.begin.scss" + } + }, + "end": "}", + "endCaptures": { + "0": { + "name": "punctuation.section.keyframes.end.scss" + } + }, + "patterns": [ + { + "match": "\\b(?:(?:100|[1-9]\\d|\\d)%|from|to)(?=\\s*{)", + "name": "entity.other.attribute-name.scss" + }, + { + "include": "#flow_control" + }, + { + "include": "#interpolation" + }, + { + "include": "#property_list" + }, + { + "include": "#rules" + } + ] + } + ] + }, + "at_rule_media": { + "patterns": [ + { + "begin": "^\\s*((@)media)\\b", + "beginCaptures": { + "1": { + "name": "keyword.control.at-rule.media.scss" + }, + "2": { + "name": "punctuation.definition.keyword.scss" + } + }, + "end": "\\s*(?={)", + "name": "meta.at-rule.media.scss", + "patterns": [ + { + "include": "#comment_block" + }, + { + "include": "#comment_line" + }, + { + "match": "\\b(only)\\b", + "name": "keyword.control.operator.css.scss" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": + "punctuation.definition.media-query.begin.bracket.round.scss" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": + "punctuation.definition.media-query.end.bracket.round.scss" + } + }, + "name": "meta.property-list.media-query.scss", + "patterns": [ + { + "begin": "(?=|<|>", + "name": "keyword.operator.comparison.scss" + }, + "logical_operators": { + "match": "\\b(not|or|and)\\b", + "name": "keyword.operator.logical.scss" + }, + "map": { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.map.begin.bracket.round.scss" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.map.end.bracket.round.scss" + } + }, + "name": "meta.definition.variable.map.scss", + "patterns": [ + { + "include": "#comment_block" + }, + { + "include": "#comment_line" + }, + { + "match": "\\b([\\w-]+)\\s*(:)", + "captures": { + "1": { + "name": "support.type.map.key.scss" + }, + "2": { + "name": "punctuation.separator.key-value.scss" + } + } + }, + { + "match": ",", + "name": "punctuation.separator.delimiter.scss" + }, + { + "include": "#map" + }, + { + "include": "#property_values" + }, + { + "include": "#variable" + } + ] + }, + "operators": { + "match": "[-+*/](?!\\s*[-+*/])", + "name": "keyword.operator.css" + }, + "parameters": { + "patterns": [ + { + "include": "#variable" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.begin.bracket.round.scss" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.end.bracket.round.scss" + } + }, + "patterns": [ + { + "include": "#function_attributes" + } + ] + }, + { + "include": "#property_values" + }, + { + "include": "#comment_block" + }, + { + "match": "[^'\",) \\t]+", + "name": "variable.parameter.url.scss" + }, + { + "match": ",", + "name": "punctuation.separator.delimiter.scss" + } + ] + }, + "properties": { + "patterns": [ + { + "begin": "(?+~|] # - Another selector\n | /\\* # - A block comment\n)", + "name": "entity.other.attribute-name.class.css", + "captures": { + "1": { + "name": "punctuation.definition.entity.css" + }, + "2": { + "patterns": [ + { + "include": "#interpolation" + }, + { + "match": "\\\\([0-9a-fA-F]{1,6}|.)", + "name": "constant.character.escape.scss" + }, + { + "match": "\\$|}", + "name": "invalid.illegal.scss" + } + ] + } + } + }, + "selector_custom": { + "match": + "\\b([a-zA-Z0-9]+(-[a-zA-Z0-9]+)+)(?=\\.|\\s++[^:]|\\s*[,\\[{]|:(link|visited|hover|active|focus|target|lang|disabled|enabled|checked|indeterminate|root|nth-(child|last-child|of-type|last-of-type)|first-child|last-child|first-of-type|last-of-type|only-child|only-of-type|empty|not|valid|invalid)(\\([0-9A-Za-z]*\\))?)", + "name": "entity.name.tag.custom.scss" + }, + "selector_id": { + "match": + "(?x)\n(\\#) # Valid id-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= $ # - End of the line\n | [\\s,.\\#)\\[:{>+~|] # - Another selector\n | /\\* # - A block comment\n)", + "name": "entity.other.attribute-name.id.css", + "captures": { + "1": { + "name": "punctuation.definition.entity.css" + }, + "2": { + "patterns": [ + { + "include": "#interpolation" + }, + { + "match": "\\\\([0-9a-fA-F]{1,6}|.)", + "name": "constant.character.escape.scss" + }, + { + "match": "\\$|}", + "name": "invalid.illegal.identifier.scss" + } + ] + } + } + }, + "selector_placeholder": { + "match": + "(?x)\n(%) # Valid placeholder-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= ; # - End of statement\n | $ # - End of the line\n | [\\s,.\\#)\\[:{>+~|] # - Another selector\n | /\\* # - A block comment\n)", + "name": "entity.other.attribute-name.placeholder.css", + "captures": { + "1": { + "name": "punctuation.definition.entity.css" + }, + "2": { + "patterns": [ + { + "include": "#interpolation" + }, + { + "match": "\\\\([0-9a-fA-F]{1,6}|.)", + "name": "constant.character.escape.scss" + }, + { + "match": "\\$|}", + "name": "invalid.illegal.identifier.scss" + } + ] + } + } + }, + "parent_selector_suffix": { + "match": + "(?x)\n(?<=&)\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= $ # - End of the line\n | [\\s,.\\#)\\[:{>+~|] # - Another selector\n | /\\* # - A block comment\n)", + "name": "entity.other.attribute-name.parent-selector-suffix.css", + "captures": { + "1": { + "name": "punctuation.definition.entity.css" + }, + "2": { + "patterns": [ + { + "include": "#interpolation" + }, + { + "match": "\\\\([0-9a-fA-F]{1,6}|.)", + "name": "constant.character.escape.scss" + }, + { + "match": "\\$|}", + "name": "invalid.illegal.identifier.scss" + } + ] + } + } + }, + "selector_pseudo_class": { + "patterns": [ + { + "begin": "((:)\\bnth-(?:child|last-child|of-type|last-of-type))(\\()", + "beginCaptures": { + "1": { + "name": "entity.other.attribute-name.pseudo-class.css" + }, + "2": { + "name": "punctuation.definition.entity.css" + }, + "3": { + "name": "punctuation.definition.pseudo-class.begin.bracket.round.css" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.pseudo-class.end.bracket.round.css" + } + }, + "patterns": [ + { + "include": "#interpolation" + }, + { + "match": "\\d+", + "name": "constant.numeric.css" + }, + { + "match": "(?<=\\d)n\\b|\\b(n|even|odd)\\b", + "name": "constant.other.scss" + }, + { + "match": "\\w+", + "name": "invalid.illegal.scss" + } + ] + }, + { + "include": "source.css#pseudo-classes" + }, + { + "include": "source.css#pseudo-elements" + }, + { + "include": "source.css#functional-pseudo-classes" + } + ] + }, + "selectors": { + "patterns": [ + { + "include": "source.css#tag-names" + }, + { + "include": "#selector_custom" + }, + { + "include": "#selector_class" + }, + { + "include": "#selector_id" + }, + { + "include": "#selector_pseudo_class" + }, + { + "include": "#tag_wildcard" + }, + { + "include": "#tag_parent_reference" + }, + { + "include": "source.css#pseudo-elements" + }, + { + "include": "#selector_attribute" + }, + { + "include": "#selector_placeholder" + }, + { + "include": "#parent_selector_suffix" + } + ] + }, + "string_double": { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.scss" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.scss" + } + }, + "name": "string.quoted.double.scss", + "patterns": [ + { + "match": "\\\\(\\h{1,6}|.)", + "name": "constant.character.escape.scss" + }, + { + "include": "#interpolation" + } + ] + }, + "string_single": { + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.scss" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.scss" + } + }, + "name": "string.quoted.single.scss", + "patterns": [ + { + "match": "\\\\(\\h{1,6}|.)", + "name": "constant.character.escape.scss" + }, + { + "include": "#interpolation" + } + ] + }, + "tag_parent_reference": { + "match": "&", + "name": "entity.name.tag.reference.scss" + }, + "tag_wildcard": { + "match": "\\*", + "name": "entity.name.tag.wildcard.scss" + }, + "variable": { + "patterns": [ + { + "include": "#variables" + }, + { + "include": "#interpolation" + } + ] + }, + "variable_setting": { + "begin": "(?=\\$[\\w-]+\\s*:)", + "end": ";", + "endCaptures": { + "0": { + "name": "punctuation.terminator.rule.scss" + } + }, + "contentName": "meta.definition.variable.scss", + "patterns": [ + { + "match": "\\$[\\w-]+(?=\\s*:)", + "name": "variable.scss" + }, + { + "begin": ":", + "beginCaptures": { + "0": { + "name": "punctuation.separator.key-value.scss" + } + }, + "end": "(?=;)", + "patterns": [ + { + "include": "#comment_block" + }, + { + "include": "#comment_line" + }, + { + "include": "#map" + }, + { + "include": "#property_values" + }, + { + "include": "#variable" + }, + { + "match": ",", + "name": "punctuation.separator.delimiter.scss" + } + ] + } + ] + }, + "variables": { + "match": "(\\$|\\-\\-)[A-Za-z0-9_-]+\\b", + "name": "variable.scss" + } + } +} diff --git a/extensions/theme-icons-seti/icons/seti-icon-theme.json b/extensions/theme-icons-seti/icons/seti-icon-theme.json index e5d6f7ecc2..0705ed838d 100644 --- a/extensions/theme-icons-seti/icons/seti-icon-theme.json +++ b/extensions/theme-icons-seti/icons/seti-icon-theme.json @@ -1,1426 +1,1427 @@ { - "information_for_contributors": [ - "This file has been generated from data in https://github.com/jesseweed/seti-ui", - "- icon definitions: https://github.com/jesseweed/seti-ui/blob/master/styles/_fonts/seti.less", - "- icon colors: https://github.com/jesseweed/seti-ui/blob/master/styles/ui-variables.less", - "- file associations: https://github.com/jesseweed/seti-ui/blob/master/styles/components/icons/mapping.less", - "If you want to provide a fix or improvement, please create a pull request against the jesseweed/seti-ui repository.", - "Once accepted there, we are happy to receive an update request." - ], - "fonts": [ - { - "id": "seti", - "src": [ - { - "path": "./seti.woff", - "format": "woff" - } - ], - "weight": "normal", - "style": "normal", - "size": "150%" - } - ], - "iconDefinitions": { - "_R": { - "fontCharacter": "\\E001" - }, - "_apple": { - "fontCharacter": "\\E002" - }, - "_asm_light": { - "fontCharacter": "\\E003", - "fontColor": "#b8383d" - }, - "_asm": { - "fontCharacter": "\\E003", - "fontColor": "#cc3e44" - }, - "_audio_light": { - "fontCharacter": "\\E004", - "fontColor": "#9068b0" - }, - "_audio": { - "fontCharacter": "\\E004", - "fontColor": "#a074c4" - }, - "_babel_light": { - "fontCharacter": "\\E005", - "fontColor": "#b7b73b" - }, - "_babel": { - "fontCharacter": "\\E005", - "fontColor": "#cbcb41" - }, - "_bower_light": { - "fontCharacter": "\\E006", - "fontColor": "#cc6d2e" - }, - "_bower": { - "fontCharacter": "\\E006", - "fontColor": "#e37933" - }, - "_bsl_light": { - "fontCharacter": "\\E007", - "fontColor": "#b8383d" - }, - "_bsl": { - "fontCharacter": "\\E007", - "fontColor": "#cc3e44" - }, - "_c-sharp_light": { - "fontCharacter": "\\E008", - "fontColor": "#498ba7" - }, - "_c-sharp": { - "fontCharacter": "\\E008", - "fontColor": "#519aba" - }, - "_c_light": { - "fontCharacter": "\\E009", - "fontColor": "#b7b73b" - }, - "_c": { - "fontCharacter": "\\E009", - "fontColor": "#cbcb41" - }, - "_cake_light": { - "fontCharacter": "\\E00A", - "fontColor": "#b8383d" - }, - "_cake": { - "fontCharacter": "\\E00A", - "fontColor": "#cc3e44" - }, - "_cake_php_light": { - "fontCharacter": "\\E00B", - "fontColor": "#b8383d" - }, - "_cake_php": { - "fontCharacter": "\\E00B", - "fontColor": "#cc3e44" - }, - "_checkbox-unchecked": { - "fontCharacter": "\\E00C" - }, - "_checkbox": { - "fontCharacter": "\\E00D" - }, - "_cjsx": { - "fontCharacter": "\\E00E" - }, - "_clock_light": { - "fontCharacter": "\\E00F", - "fontColor": "#627379" - }, - "_clock": { - "fontCharacter": "\\E00F", - "fontColor": "#6d8086" - }, - "_code-climate_light": { - "fontCharacter": "\\E010", - "fontColor": "#7fae42" - }, - "_code-climate": { - "fontCharacter": "\\E010", - "fontColor": "#8dc149" - }, - "_coffee_light": { - "fontCharacter": "\\E011", - "fontColor": "#b7b73b" - }, - "_coffee": { - "fontCharacter": "\\E011", - "fontColor": "#cbcb41" - }, - "_coffee_erb": { - "fontCharacter": "\\E012" - }, - "_coldfusion_light": { - "fontCharacter": "\\E013", - "fontColor": "#498ba7" - }, - "_coldfusion": { - "fontCharacter": "\\E013", - "fontColor": "#519aba" - }, - "_config_light": { - "fontCharacter": "\\E014", - "fontColor": "#627379" - }, - "_config": { - "fontCharacter": "\\E014", - "fontColor": "#6d8086" - }, - "_cpp_light": { - "fontCharacter": "\\E015", - "fontColor": "#9068b0" - }, - "_cpp": { - "fontCharacter": "\\E015", - "fontColor": "#a074c4" - }, - "_css_light": { - "fontCharacter": "\\E016", - "fontColor": "#498ba7" - }, - "_css": { - "fontCharacter": "\\E016", - "fontColor": "#519aba" - }, - "_csv_light": { - "fontCharacter": "\\E017", - "fontColor": "#7fae42" - }, - "_csv": { - "fontCharacter": "\\E017", - "fontColor": "#8dc149" - }, - "_d_light": { - "fontCharacter": "\\E018", - "fontColor": "#b8383d" - }, - "_d": { - "fontCharacter": "\\E018", - "fontColor": "#cc3e44" - }, - "_db_light": { - "fontCharacter": "\\E019", - "fontColor": "#dd4b78" - }, - "_db": { - "fontCharacter": "\\E019", - "fontColor": "#f55385" - }, - "_default_light": { - "fontCharacter": "\\E01A", - "fontColor": "#bfc2c1" - }, - "_default": { - "fontCharacter": "\\E01A", - "fontColor": "#d4d7d6" - }, - "_deprecation-cop": { - "fontCharacter": "\\E01B" - }, - "_docker_light": { - "fontCharacter": "\\E01C", - "fontColor": "#dd4b78" - }, - "_docker": { - "fontCharacter": "\\E01C", - "fontColor": "#f55385" - }, - "_editorconfig": { - "fontCharacter": "\\E01D" - }, - "_ejs_light": { - "fontCharacter": "\\E01E", - "fontColor": "#b7b73b" - }, - "_ejs": { - "fontCharacter": "\\E01E", - "fontColor": "#cbcb41" - }, - "_elixir_light": { - "fontCharacter": "\\E01F", - "fontColor": "#9068b0" - }, - "_elixir": { - "fontCharacter": "\\E01F", - "fontColor": "#a074c4" - }, - "_elixir_script_light": { - "fontCharacter": "\\E020", - "fontColor": "#9068b0" - }, - "_elixir_script": { - "fontCharacter": "\\E020", - "fontColor": "#a074c4" - }, - "_elm_light": { - "fontCharacter": "\\E021", - "fontColor": "#498ba7" - }, - "_elm": { - "fontCharacter": "\\E021", - "fontColor": "#519aba" - }, - "_error": { - "fontCharacter": "\\E022" - }, - "_eslint_light": { - "fontCharacter": "\\E023", - "fontColor": "#455155" - }, - "_eslint": { - "fontCharacter": "\\E023", - "fontColor": "#4d5a5e" - }, - "_f-sharp_light": { - "fontCharacter": "\\E024", - "fontColor": "#498ba7" - }, - "_f-sharp": { - "fontCharacter": "\\E024", - "fontColor": "#519aba" - }, - "_favicon_light": { - "fontCharacter": "\\E025", - "fontColor": "#b7b73b" - }, - "_favicon": { - "fontCharacter": "\\E025", - "fontColor": "#cbcb41" - }, - "_firebase_light": { - "fontCharacter": "\\E026", - "fontColor": "#cc6d2e" - }, - "_firebase": { - "fontCharacter": "\\E026", - "fontColor": "#e37933" - }, - "_firefox_light": { - "fontCharacter": "\\E027", - "fontColor": "#cc6d2e" - }, - "_firefox": { - "fontCharacter": "\\E027", - "fontColor": "#e37933" - }, - "_folder": { - "fontCharacter": "\\E028" - }, - "_font_light": { - "fontCharacter": "\\E029", - "fontColor": "#b8383d" - }, - "_font": { - "fontCharacter": "\\E029", - "fontColor": "#cc3e44" - }, - "_git_light": { - "fontCharacter": "\\E02A", - "fontColor": "#3b4b52" - }, - "_git": { - "fontCharacter": "\\E02A", - "fontColor": "#41535b" - }, - "_git_folder": { - "fontCharacter": "\\E02B" - }, - "_git_ignore": { - "fontCharacter": "\\E02C" - }, - "_github": { - "fontCharacter": "\\E02D" - }, - "_go_light": { - "fontCharacter": "\\E02E", - "fontColor": "#498ba7" - }, - "_go": { - "fontCharacter": "\\E02E", - "fontColor": "#519aba" - }, - "_go2_light": { - "fontCharacter": "\\E02F", - "fontColor": "#498ba7" - }, - "_go2": { - "fontCharacter": "\\E02F", - "fontColor": "#519aba" - }, - "_gradle_light": { - "fontCharacter": "\\E030", - "fontColor": "#7fae42" - }, - "_gradle": { - "fontCharacter": "\\E030", - "fontColor": "#8dc149" - }, - "_grails_light": { - "fontCharacter": "\\E031", - "fontColor": "#7fae42" - }, - "_grails": { - "fontCharacter": "\\E031", - "fontColor": "#8dc149" - }, - "_grunt_light": { - "fontCharacter": "\\E032", - "fontColor": "#cc6d2e" - }, - "_grunt": { - "fontCharacter": "\\E032", - "fontColor": "#e37933" - }, - "_gulp_light": { - "fontCharacter": "\\E033", - "fontColor": "#b8383d" - }, - "_gulp": { - "fontCharacter": "\\E033", - "fontColor": "#cc3e44" - }, - "_hacklang": { - "fontCharacter": "\\E034" - }, - "_haml_light": { - "fontCharacter": "\\E035", - "fontColor": "#b8383d" - }, - "_haml": { - "fontCharacter": "\\E035", - "fontColor": "#cc3e44" - }, - "_haskell_light": { - "fontCharacter": "\\E036", - "fontColor": "#9068b0" - }, - "_haskell": { - "fontCharacter": "\\E036", - "fontColor": "#a074c4" - }, - "_heroku_light": { - "fontCharacter": "\\E037", - "fontColor": "#9068b0" - }, - "_heroku": { - "fontCharacter": "\\E037", - "fontColor": "#a074c4" - }, - "_hex_light": { - "fontCharacter": "\\E038", - "fontColor": "#b8383d" - }, - "_hex": { - "fontCharacter": "\\E038", - "fontColor": "#cc3e44" - }, - "_html_light": { - "fontCharacter": "\\E039", - "fontColor": "#cc6d2e" - }, - "_html": { - "fontCharacter": "\\E039", - "fontColor": "#e37933" - }, - "_html_erb": { - "fontCharacter": "\\E03A" - }, - "_ignored_light": { - "fontCharacter": "\\E03B", - "fontColor": "#3b4b52" - }, - "_ignored": { - "fontCharacter": "\\E03B", - "fontColor": "#41535b" - }, - "_illustrator_light": { - "fontCharacter": "\\E03C", - "fontColor": "#b7b73b" - }, - "_illustrator": { - "fontCharacter": "\\E03C", - "fontColor": "#cbcb41" - }, - "_image_light": { - "fontCharacter": "\\E03D", - "fontColor": "#9068b0" - }, - "_image": { - "fontCharacter": "\\E03D", - "fontColor": "#a074c4" - }, - "_info_light": { - "fontCharacter": "\\E03E", - "fontColor": "#498ba7" - }, - "_info": { - "fontCharacter": "\\E03E", - "fontColor": "#519aba" - }, - "_ionic_light": { - "fontCharacter": "\\E03F", - "fontColor": "#498ba7" - }, - "_ionic": { - "fontCharacter": "\\E03F", - "fontColor": "#519aba" - }, - "_jade_light": { - "fontCharacter": "\\E040", - "fontColor": "#b8383d" - }, - "_jade": { - "fontCharacter": "\\E040", - "fontColor": "#cc3e44" - }, - "_java_light": { - "fontCharacter": "\\E041", - "fontColor": "#b8383d" - }, - "_java": { - "fontCharacter": "\\E041", - "fontColor": "#cc3e44" - }, - "_javascript_light": { - "fontCharacter": "\\E042", - "fontColor": "#498ba7" - }, - "_javascript": { - "fontCharacter": "\\E042", - "fontColor": "#519aba" - }, - "_jenkins_light": { - "fontCharacter": "\\E043", - "fontColor": "#b8383d" - }, - "_jenkins": { - "fontCharacter": "\\E043", - "fontColor": "#cc3e44" - }, - "_jinja_light": { - "fontCharacter": "\\E044", - "fontColor": "#b8383d" - }, - "_jinja": { - "fontCharacter": "\\E044", - "fontColor": "#cc3e44" - }, - "_js_erb": { - "fontCharacter": "\\E045" - }, - "_json_light": { - "fontCharacter": "\\E046", - "fontColor": "#b7b73b" - }, - "_json": { - "fontCharacter": "\\E046", - "fontColor": "#cbcb41" - }, - "_julia_light": { - "fontCharacter": "\\E047", - "fontColor": "#9068b0" - }, - "_julia": { - "fontCharacter": "\\E047", - "fontColor": "#a074c4" - }, - "_karma_light": { - "fontCharacter": "\\E048", - "fontColor": "#7fae42" - }, - "_karma": { - "fontCharacter": "\\E048", - "fontColor": "#8dc149" - }, - "_less_light": { - "fontCharacter": "\\E049", - "fontColor": "#498ba7" - }, - "_less": { - "fontCharacter": "\\E049", - "fontColor": "#519aba" - }, - "_license_light": { - "fontCharacter": "\\E04A", - "fontColor": "#b8383d" - }, - "_license": { - "fontCharacter": "\\E04A", - "fontColor": "#cc3e44" - }, - "_liquid_light": { - "fontCharacter": "\\E04B", - "fontColor": "#7fae42" - }, - "_liquid": { - "fontCharacter": "\\E04B", - "fontColor": "#8dc149" - }, - "_livescript_light": { - "fontCharacter": "\\E04C", - "fontColor": "#498ba7" - }, - "_livescript": { - "fontCharacter": "\\E04C", - "fontColor": "#519aba" - }, - "_lock_light": { - "fontCharacter": "\\E04D", - "fontColor": "#7fae42" - }, - "_lock": { - "fontCharacter": "\\E04D", - "fontColor": "#8dc149" - }, - "_lua_light": { - "fontCharacter": "\\E04E", - "fontColor": "#498ba7" - }, - "_lua": { - "fontCharacter": "\\E04E", - "fontColor": "#519aba" - }, - "_makefile_light": { - "fontCharacter": "\\E04F", - "fontColor": "#498ba7" - }, - "_makefile": { - "fontCharacter": "\\E04F", - "fontColor": "#519aba" - }, - "_markdown_light": { - "fontCharacter": "\\E050", - "fontColor": "#498ba7" - }, - "_markdown": { - "fontCharacter": "\\E050", - "fontColor": "#519aba" - }, - "_maven_light": { - "fontCharacter": "\\E051", - "fontColor": "#b8383d" - }, - "_maven": { - "fontCharacter": "\\E051", - "fontColor": "#cc3e44" - }, - "_mdo_light": { - "fontCharacter": "\\E052", - "fontColor": "#b8383d" - }, - "_mdo": { - "fontCharacter": "\\E052", - "fontColor": "#cc3e44" - }, - "_mustache_light": { - "fontCharacter": "\\E053", - "fontColor": "#cc6d2e" - }, - "_mustache": { - "fontCharacter": "\\E053", - "fontColor": "#e37933" - }, - "_new-file": { - "fontCharacter": "\\E054" - }, - "_npm_light": { - "fontCharacter": "\\E055", - "fontColor": "#b8383d" - }, - "_npm": { - "fontCharacter": "\\E055", - "fontColor": "#cc3e44" - }, - "_npm_ignored_light": { - "fontCharacter": "\\E056", - "fontColor": "#3b4b52" - }, - "_npm_ignored": { - "fontCharacter": "\\E056", - "fontColor": "#41535b" - }, - "_nunjucks_light": { - "fontCharacter": "\\E057", - "fontColor": "#7fae42" - }, - "_nunjucks": { - "fontCharacter": "\\E057", - "fontColor": "#8dc149" - }, - "_ocaml_light": { - "fontCharacter": "\\E058", - "fontColor": "#cc6d2e" - }, - "_ocaml": { - "fontCharacter": "\\E058", - "fontColor": "#e37933" - }, - "_pdf_light": { - "fontCharacter": "\\E059", - "fontColor": "#b8383d" - }, - "_pdf": { - "fontCharacter": "\\E059", - "fontColor": "#cc3e44" - }, - "_perl_light": { - "fontCharacter": "\\E05A", - "fontColor": "#498ba7" - }, - "_perl": { - "fontCharacter": "\\E05A", - "fontColor": "#519aba" - }, - "_photoshop_light": { - "fontCharacter": "\\E05B", - "fontColor": "#498ba7" - }, - "_photoshop": { - "fontCharacter": "\\E05B", - "fontColor": "#519aba" - }, - "_php_light": { - "fontCharacter": "\\E05C", - "fontColor": "#9068b0" - }, - "_php": { - "fontCharacter": "\\E05C", - "fontColor": "#a074c4" - }, - "_powershell_light": { - "fontCharacter": "\\E05D", - "fontColor": "#498ba7" - }, - "_powershell": { - "fontCharacter": "\\E05D", - "fontColor": "#519aba" - }, - "_project": { - "fontCharacter": "\\E05E" - }, - "_pug_light": { - "fontCharacter": "\\E05F", - "fontColor": "#b8383d" - }, - "_pug": { - "fontCharacter": "\\E05F", - "fontColor": "#cc3e44" - }, - "_puppet_light": { - "fontCharacter": "\\E060", - "fontColor": "#b7b73b" - }, - "_puppet": { - "fontCharacter": "\\E060", - "fontColor": "#cbcb41" - }, - "_python_light": { - "fontCharacter": "\\E061", - "fontColor": "#498ba7" - }, - "_python": { - "fontCharacter": "\\E061", - "fontColor": "#519aba" - }, - "_rails": { - "fontCharacter": "\\E062" - }, - "_react_light": { - "fontCharacter": "\\E063", - "fontColor": "#498ba7" - }, - "_react": { - "fontCharacter": "\\E063", - "fontColor": "#519aba" - }, - "_rollup_light": { - "fontCharacter": "\\E064", - "fontColor": "#b8383d" - }, - "_rollup": { - "fontCharacter": "\\E064", - "fontColor": "#cc3e44" - }, - "_ruby_light": { - "fontCharacter": "\\E065", - "fontColor": "#b8383d" - }, - "_ruby": { - "fontCharacter": "\\E065", - "fontColor": "#cc3e44" - }, - "_rust_light": { - "fontCharacter": "\\E066", - "fontColor": "#627379" - }, - "_rust": { - "fontCharacter": "\\E066", - "fontColor": "#6d8086" - }, - "_salesforce_light": { - "fontCharacter": "\\E067", - "fontColor": "#498ba7" - }, - "_salesforce": { - "fontCharacter": "\\E067", - "fontColor": "#519aba" - }, - "_sass_light": { - "fontCharacter": "\\E068", - "fontColor": "#dd4b78" - }, - "_sass": { - "fontCharacter": "\\E068", - "fontColor": "#f55385" - }, - "_sbt_light": { - "fontCharacter": "\\E069", - "fontColor": "#498ba7" - }, - "_sbt": { - "fontCharacter": "\\E069", - "fontColor": "#519aba" - }, - "_scala_light": { - "fontCharacter": "\\E06A", - "fontColor": "#b8383d" - }, - "_scala": { - "fontCharacter": "\\E06A", - "fontColor": "#cc3e44" - }, - "_search": { - "fontCharacter": "\\E06B" - }, - "_settings": { - "fontCharacter": "\\E06C" - }, - "_shell_light": { - "fontCharacter": "\\E06D", - "fontColor": "#455155" - }, - "_shell": { - "fontCharacter": "\\E06D", - "fontColor": "#4d5a5e" - }, - "_slim_light": { - "fontCharacter": "\\E06E", - "fontColor": "#cc6d2e" - }, - "_slim": { - "fontCharacter": "\\E06E", - "fontColor": "#e37933" - }, - "_smarty_light": { - "fontCharacter": "\\E06F", - "fontColor": "#b7b73b" - }, - "_smarty": { - "fontCharacter": "\\E06F", - "fontColor": "#cbcb41" - }, - "_spring_light": { - "fontCharacter": "\\E070", - "fontColor": "#7fae42" - }, - "_spring": { - "fontCharacter": "\\E070", - "fontColor": "#8dc149" - }, - "_stylus_light": { - "fontCharacter": "\\E071", - "fontColor": "#7fae42" - }, - "_stylus": { - "fontCharacter": "\\E071", - "fontColor": "#8dc149" - }, - "_sublime_light": { - "fontCharacter": "\\E072", - "fontColor": "#cc6d2e" - }, - "_sublime": { - "fontCharacter": "\\E072", - "fontColor": "#e37933" - }, - "_svg_light": { - "fontCharacter": "\\E073", - "fontColor": "#9068b0" - }, - "_svg": { - "fontCharacter": "\\E073", - "fontColor": "#a074c4" - }, - "_swift_light": { - "fontCharacter": "\\E074", - "fontColor": "#cc6d2e" - }, - "_swift": { - "fontCharacter": "\\E074", - "fontColor": "#e37933" - }, - "_terraform_light": { - "fontCharacter": "\\E075", - "fontColor": "#9068b0" - }, - "_terraform": { - "fontCharacter": "\\E075", - "fontColor": "#a074c4" - }, - "_tex_light": { - "fontCharacter": "\\E076", - "fontColor": "#bfc2c1" - }, - "_tex": { - "fontCharacter": "\\E076", - "fontColor": "#d4d7d6" - }, - "_time-cop": { - "fontCharacter": "\\E077" - }, - "_todo": { - "fontCharacter": "\\E078" - }, - "_twig_light": { - "fontCharacter": "\\E079", - "fontColor": "#7fae42" - }, - "_twig": { - "fontCharacter": "\\E079", - "fontColor": "#8dc149" - }, - "_typescript_light": { - "fontCharacter": "\\E07A", - "fontColor": "#498ba7" - }, - "_typescript": { - "fontCharacter": "\\E07A", - "fontColor": "#519aba" - }, - "_vala_light": { - "fontCharacter": "\\E07B", - "fontColor": "#627379" - }, - "_vala": { - "fontCharacter": "\\E07B", - "fontColor": "#6d8086" - }, - "_video_light": { - "fontCharacter": "\\E07C", - "fontColor": "#dd4b78" - }, - "_video": { - "fontCharacter": "\\E07C", - "fontColor": "#f55385" - }, - "_vue_light": { - "fontCharacter": "\\E07D", - "fontColor": "#7fae42" - }, - "_vue": { - "fontCharacter": "\\E07D", - "fontColor": "#8dc149" - }, - "_windows_light": { - "fontCharacter": "\\E07E", - "fontColor": "#498ba7" - }, - "_windows": { - "fontCharacter": "\\E07E", - "fontColor": "#519aba" - }, - "_word_light": { - "fontCharacter": "\\E07F", - "fontColor": "#498ba7" - }, - "_word": { - "fontCharacter": "\\E07F", - "fontColor": "#519aba" - }, - "_xls_light": { - "fontCharacter": "\\E080", - "fontColor": "#7fae42" - }, - "_xls": { - "fontCharacter": "\\E080", - "fontColor": "#8dc149" - }, - "_xml_light": { - "fontCharacter": "\\E081", - "fontColor": "#cc6d2e" - }, - "_xml": { - "fontCharacter": "\\E081", - "fontColor": "#e37933" - }, - "_yarn_light": { - "fontCharacter": "\\E082", - "fontColor": "#498ba7" - }, - "_yarn": { - "fontCharacter": "\\E082", - "fontColor": "#519aba" - }, - "_yml_light": { - "fontCharacter": "\\E083", - "fontColor": "#9068b0" - }, - "_yml": { - "fontCharacter": "\\E083", - "fontColor": "#a074c4" - }, - "_zip_light": { - "fontCharacter": "\\E084", - "fontColor": "#627379" - }, - "_zip": { - "fontCharacter": "\\E084", - "fontColor": "#6d8086" - } - }, - "file": "_default", - "fileExtensions": { - "bsl": "_bsl", - "mdo": "_mdo", - "asm": "_asm", - "s": "_asm", - "h": "_c", - "cfc": "_coldfusion", - "cfm": "_coldfusion", - "config": "_config", - "cfg": "_config", - "conf": "_config", - "cson": "_json", - "css.map": "_css", - "sss": "_css", - "csv": "_csv", - "xls": "_xls", - "xlsx": "_xls", - "cake": "_cake", - "ctp": "_cake_php", - "d": "_d", - "doc": "_word", - "docx": "_word", - "ejs": "_ejs", - "ex": "_elixir", - "exs": "_elixir_script", - "elm": "_elm", - "ico": "_favicon", - "gitignore": "_git", - "gitconfig": "_git", - "gitkeep": "_git", - "gitattributes": "_git", - "gitmodules": "_git", - "slide": "_go", - "article": "_go", - "gradle": "_gradle", - "gsp": "_grails", - "haml": "_haml", - "hjs": "_mustache", - "hs": "_haskell", - "lhs": "_haskell", - "class": "_java", - "classpath": "_java", - "js.map": "_javascript", - "spec.js": "_javascript", - "es": "_javascript", - "es5": "_javascript", - "es7": "_javascript", - "jinja": "_jinja", - "jinja2": "_jinja", - "jl": "_julia", - "js": "_javascript", - "liquid": "_liquid", - "ls": "_livescript", - "md": "_markdown", - "mustache": "_mustache", - "stache": "_mustache", - "njk": "_nunjucks", - "nunjucks": "_nunjucks", - "nunjs": "_nunjucks", - "nunj": "_nunjucks", - "njs": "_nunjucks", - "nj": "_nunjucks", - "npm-debug.log": "_npm", - "npmignore": "_npm", - "npmrc": "_npm", - "ml": "_ocaml", - "mli": "_ocaml", - "cmx": "_ocaml", - "cmxa": "_ocaml", - "php.inc": "_php", - "pug": "_pug", - "pp": "_puppet", - "epp": "_puppet", - "cjsx": "_react", - "erb.html": "_ruby", - "html.erb": "_ruby", - "sass": "_sass", - "springbeans": "_spring", - "slim": "_slim", - "smarty.tpl": "_smarty", - "sbt": "_sbt", - "scala": "_scala", - "styl": "_stylus", - "tf": "_terraform", - "tf.json": "_terraform", - "tex": "_tex", - "sty": "_tex", - "dtx": "_tex", - "ins": "_tex", - "txt": "_default", - "toml": "_config", - "twig": "_twig", - "vala": "_vala", - "vapi": "_vala", - "vue": "_vue", - "jar": "_zip", - "zip": "_zip", - "ai": "_illustrator", - "psd": "_photoshop", - "pdf": "_pdf", - "eot": "_font", - "ttf": "_font", - "woff": "_font", - "woff2": "_font", - "gif": "_image", - "jpg": "_image", - "jpeg": "_image", - "png": "_image", - "pxm": "_image", - "svg": "_svg", - "svgx": "_image", - "webp": "_image", - "sublime-project": "_sublime", - "sublime-workspace": "_sublime", - "component": "_salesforce", - "cls": "_salesforce", - "fish": "_shell", - "mov": "_video", - "ogv": "_video", - "webm": "_video", - "avi": "_video", - "mpg": "_video", - "mp4": "_video", - "mp3": "_audio", - "ogg": "_audio", - "wav": "_audio", - "babelrc": "_babel", - "bowerrc": "_bower", - "dockerignore": "_docker", - "codeclimate.yml": "_code-climate", - "eslintrc": "_eslint", - "eslintrc.js": "_eslint", - "eslintrc.yaml": "_eslint", - "eslintrc.yml": "_eslint", - "eslintrc.json": "_eslint", - "eslintignore": "_eslint", - "firebaserc": "_firebase", - "jshintrc": "_javascript", - "jscsrc": "_javascript", - "direnv": "_config", - "env": "_config", - "static": "_config", - "editorconfig": "_config", - "slugignore": "_config", - "tmp": "_clock", - "htaccess": "_config", - "key": "_lock", - "cert": "_lock", - "ds_store": "_ignored", - "ts": "_typescript", - "tsx": "_react" - }, - "fileNames": { - "mix": "_hex", - "karma.conf.js": "_karma", - "karma.conf.coffee": "_karma", - "readme.md": "_info", - "changelog.md": "_clock", - "changelog": "_clock", - "version.md": "_clock", - "version": "_clock", - "mvnw": "_maven", - "mime.types": "_config", - "jenkinsfile": "_jenkins", - "bower.json": "_bower", - "docker-healthcheck": "_docker", - "docker-compose.yml": "_docker", - "firebase.json": "_firebase", - "geckodriver": "_firefox", - "gruntfile.js": "_grunt", - "gruntfile.babel.js": "_grunt", - "gruntfile.coffee": "_grunt", - "gulpfile": "_gulp", - "ionic.config.json": "_ionic", - "ionic.project": "_ionic", - "rollup.config.js": "_rollup", - "sass-lint.yml": "_sass", - "yarn.clean": "_yarn", - "yarn.lock": "_yarn", - "license": "_license", - "licence": "_license", - "copying": "_license", - "compiling": "_license", - "contributing": "_license", - "qmakefile": "_makefile", - "omakefile": "_makefile", - "cmakelists.txt": "_makefile", - "procfile": "_heroku", - "todo": "_todo", - "npm-debug.log": "_npm_ignored" - }, - "languageIds": { - "bat": "_windows", - "coffeescript": "_coffee", - "c": "_c", - "cpp": "_cpp", - "csharp": "_c-sharp", - "css": "_css", - "dockerfile": "_docker", - "fsharp": "_f-sharp", - "go": "_go2", - "groovy": "_grails", - "handlebars": "_mustache", - "html": "_html", - "properties": "_java", - "java": "_java", - "javascriptreact": "_react", - "javascript": "_javascript", - "json": "_json", - "less": "_less", - "lua": "_lua", - "makefile": "_makefile", - "markdown": "_markdown", - "objective-c": "_c", - "perl": "_perl", - "php": "_php", - "powershell": "_powershell", - "jade": "_jade", - "python": "_python", - "ruby": "_ruby", - "rust": "_rust", - "scss": "_sass", - "shellscript": "_shell", - "sql": "_db", - "swift": "_swift", - "typescript": "_typescript", - "typescriptreact": "_react", - "xml": "_xml", - "yaml": "_yml" - }, - "light": { - "file": "_default_light", - "fileExtensions": { - "bsl": "_bsl_light", - "mdo": "_mdo_light", - "asm": "_asm_light", - "s": "_asm_light", - "h": "_c_light", - "cfc": "_coldfusion_light", - "cfm": "_coldfusion_light", - "config": "_config_light", - "cfg": "_config_light", - "conf": "_config_light", - "cson": "_json_light", - "css.map": "_css_light", - "sss": "_css_light", - "csv": "_csv_light", - "xls": "_xls_light", - "xlsx": "_xls_light", - "cake": "_cake_light", - "ctp": "_cake_php_light", - "d": "_d_light", - "doc": "_word_light", - "docx": "_word_light", - "ejs": "_ejs_light", - "ex": "_elixir_light", - "exs": "_elixir_script_light", - "elm": "_elm_light", - "ico": "_favicon_light", - "gitignore": "_git_light", - "gitconfig": "_git_light", - "gitkeep": "_git_light", - "gitattributes": "_git_light", - "gitmodules": "_git_light", - "slide": "_go_light", - "article": "_go_light", - "gradle": "_gradle_light", - "gsp": "_grails_light", - "haml": "_haml_light", - "hjs": "_mustache_light", - "hs": "_haskell_light", - "lhs": "_haskell_light", - "class": "_java_light", - "classpath": "_java_light", - "js.map": "_javascript_light", - "spec.js": "_javascript_light", - "es": "_javascript_light", - "es5": "_javascript_light", - "es7": "_javascript_light", - "jinja": "_jinja_light", - "jinja2": "_jinja_light", - "jl": "_julia_light", - "liquid": "_liquid_light", - "ls": "_livescript_light", - "mustache": "_mustache_light", - "stache": "_mustache_light", - "njk": "_nunjucks_light", - "nunjucks": "_nunjucks_light", - "nunjs": "_nunjucks_light", - "nunj": "_nunjucks_light", - "njs": "_nunjucks_light", - "nj": "_nunjucks_light", - "npm-debug.log": "_npm_light", - "npmignore": "_npm_light", - "npmrc": "_npm_light", - "ml": "_ocaml_light", - "mli": "_ocaml_light", - "cmx": "_ocaml_light", - "cmxa": "_ocaml_light", - "php.inc": "_php_light", - "pug": "_pug_light", - "pp": "_puppet_light", - "epp": "_puppet_light", - "cjsx": "_react_light", - "erb.html": "_ruby_light", - "html.erb": "_ruby_light", - "sass": "_sass_light", - "springbeans": "_spring_light", - "slim": "_slim_light", - "smarty.tpl": "_smarty_light", - "sbt": "_sbt_light", - "scala": "_scala_light", - "styl": "_stylus_light", - "tf": "_terraform_light", - "tf.json": "_terraform_light", - "tex": "_tex_light", - "sty": "_tex_light", - "dtx": "_tex_light", - "ins": "_tex_light", - "txt": "_default_light", - "toml": "_config_light", - "twig": "_twig_light", - "vala": "_vala_light", - "vapi": "_vala_light", - "vue": "_vue_light", - "jar": "_zip_light", - "zip": "_zip_light", - "ai": "_illustrator_light", - "psd": "_photoshop_light", - "pdf": "_pdf_light", - "eot": "_font_light", - "ttf": "_font_light", - "woff": "_font_light", - "woff2": "_font_light", - "gif": "_image_light", - "jpg": "_image_light", - "jpeg": "_image_light", - "png": "_image_light", - "pxm": "_image_light", - "svg": "_svg_light", - "svgx": "_image_light", - "sublime-project": "_sublime_light", - "sublime-workspace": "_sublime_light", - "component": "_salesforce_light", - "cls": "_salesforce_light", - "fish": "_shell_light", - "mov": "_video_light", - "ogv": "_video_light", - "webm": "_video_light", - "avi": "_video_light", - "mpg": "_video_light", - "mp4": "_video_light", - "mp3": "_audio_light", - "ogg": "_audio_light", - "wav": "_audio_light", - "babelrc": "_babel_light", - "bowerrc": "_bower_light", - "dockerignore": "_docker_light", - "codeclimate.yml": "_code-climate_light", - "eslintrc": "_eslint_light", - "eslintrc.js": "_eslint_light", - "eslintrc.yaml": "_eslint_light", - "eslintrc.yml": "_eslint_light", - "eslintrc.json": "_eslint_light", - "eslintignore": "_eslint_light", - "firebaserc": "_firebase_light", - "jshintrc": "_javascript_light", - "jscsrc": "_javascript_light", - "direnv": "_config_light", - "env": "_config_light", - "static": "_config_light", - "editorconfig": "_config_light", - "slugignore": "_config_light", - "tmp": "_clock_light", - "htaccess": "_config_light", - "key": "_lock_light", - "cert": "_lock_light", - "ds_store": "_ignored_light" - }, - "languageIds": { - "bat": "_windows_light", - "coffeescript": "_coffee_light", - "c": "_c_light", - "cpp": "_cpp_light", - "csharp": "_c-sharp_light", - "css": "_css_light", - "dockerfile": "_docker_light", - "fsharp": "_f-sharp_light", - "go": "_go2_light", - "groovy": "_grails_light", - "handlebars": "_mustache_light", - "html": "_html_light", - "properties": "_java_light", - "java": "_java_light", - "javascriptreact": "_react_light", - "javascript": "_javascript_light", - "json": "_json_light", - "less": "_less_light", - "lua": "_lua_light", - "makefile": "_makefile_light", - "markdown": "_markdown_light", - "objective-c": "_c_light", - "perl": "_perl_light", - "php": "_php_light", - "powershell": "_powershell_light", - "jade": "_jade_light", - "python": "_python_light", - "ruby": "_ruby_light", - "rust": "_rust_light", - "scss": "_sass_light", - "shellscript": "_shell_light", - "sql": "_db_light", - "swift": "_swift_light", - "typescript": "_typescript_light", - "typescriptreact": "_react_light", - "xml": "_xml_light", - "yaml": "_yml_light" - }, - "fileNames": { - "mix": "_hex_light", - "karma.conf.js": "_karma_light", - "karma.conf.coffee": "_karma_light", - "readme.md": "_info_light", - "changelog.md": "_clock_light", - "changelog": "_clock_light", - "version.md": "_clock_light", - "version": "_clock_light", - "mvnw": "_maven_light", - "mime.types": "_config_light", - "jenkinsfile": "_jenkins_light", - "bower.json": "_bower_light", - "docker-healthcheck": "_docker_light", - "docker-compose.yml": "_docker_light", - "firebase.json": "_firebase_light", - "geckodriver": "_firefox_light", - "gruntfile.js": "_grunt_light", - "gruntfile.babel.js": "_grunt_light", - "gruntfile.coffee": "_grunt_light", - "gulpfile": "_gulp_light", - "ionic.config.json": "_ionic_light", - "ionic.project": "_ionic_light", - "rollup.config.js": "_rollup_light", - "sass-lint.yml": "_sass_light", - "yarn.clean": "_yarn_light", - "yarn.lock": "_yarn_light", - "license": "_license_light", - "licence": "_license_light", - "copying": "_license_light", - "compiling": "_license_light", - "contributing": "_license_light", - "qmakefile": "_makefile_light", - "omakefile": "_makefile_light", - "cmakelists.txt": "_makefile_light", - "procfile": "_heroku_light", - "npm-debug.log": "_npm_ignored_light" - } - }, - "version": "https://github.com/jesseweed/seti-ui/commit/c44b29c7a5b2f189fccfd58ceea02b117678caa9" + "information_for_contributors": [ + "This file has been generated from data in https://github.com/jesseweed/seti-ui", + "- icon definitions: https://github.com/jesseweed/seti-ui/blob/master/styles/_fonts/seti.less", + "- icon colors: https://github.com/jesseweed/seti-ui/blob/master/styles/ui-variables.less", + "- file associations: https://github.com/jesseweed/seti-ui/blob/master/styles/components/icons/mapping.less", + "If you want to provide a fix or improvement, please create a pull request against the jesseweed/seti-ui repository.", + "Once accepted there, we are happy to receive an update request." + ], + "fonts": [ + { + "id": "seti", + "src": [ + { + "path": "./seti.woff", + "format": "woff" + } + ], + "weight": "normal", + "style": "normal", + "size": "150%" + } + ], + "iconDefinitions": { + "_R": { + "fontCharacter": "\\E001" + }, + "_apple": { + "fontCharacter": "\\E002" + }, + "_asm_light": { + "fontCharacter": "\\E003", + "fontColor": "#b8383d" + }, + "_asm": { + "fontCharacter": "\\E003", + "fontColor": "#cc3e44" + }, + "_audio_light": { + "fontCharacter": "\\E004", + "fontColor": "#9068b0" + }, + "_audio": { + "fontCharacter": "\\E004", + "fontColor": "#a074c4" + }, + "_babel_light": { + "fontCharacter": "\\E005", + "fontColor": "#b7b73b" + }, + "_babel": { + "fontCharacter": "\\E005", + "fontColor": "#cbcb41" + }, + "_bower_light": { + "fontCharacter": "\\E006", + "fontColor": "#cc6d2e" + }, + "_bower": { + "fontCharacter": "\\E006", + "fontColor": "#e37933" + }, + "_bsl_light": { + "fontCharacter": "\\E007", + "fontColor": "#b8383d" + }, + "_bsl": { + "fontCharacter": "\\E007", + "fontColor": "#cc3e44" + }, + "_c-sharp_light": { + "fontCharacter": "\\E008", + "fontColor": "#498ba7" + }, + "_c-sharp": { + "fontCharacter": "\\E008", + "fontColor": "#519aba" + }, + "_c_light": { + "fontCharacter": "\\E009", + "fontColor": "#b7b73b" + }, + "_c": { + "fontCharacter": "\\E009", + "fontColor": "#cbcb41" + }, + "_cake_light": { + "fontCharacter": "\\E00A", + "fontColor": "#b8383d" + }, + "_cake": { + "fontCharacter": "\\E00A", + "fontColor": "#cc3e44" + }, + "_cake_php_light": { + "fontCharacter": "\\E00B", + "fontColor": "#b8383d" + }, + "_cake_php": { + "fontCharacter": "\\E00B", + "fontColor": "#cc3e44" + }, + "_checkbox-unchecked": { + "fontCharacter": "\\E00C" + }, + "_checkbox": { + "fontCharacter": "\\E00D" + }, + "_cjsx": { + "fontCharacter": "\\E00E" + }, + "_clock_light": { + "fontCharacter": "\\E00F", + "fontColor": "#627379" + }, + "_clock": { + "fontCharacter": "\\E00F", + "fontColor": "#6d8086" + }, + "_code-climate_light": { + "fontCharacter": "\\E010", + "fontColor": "#7fae42" + }, + "_code-climate": { + "fontCharacter": "\\E010", + "fontColor": "#8dc149" + }, + "_coffee_light": { + "fontCharacter": "\\E011", + "fontColor": "#b7b73b" + }, + "_coffee": { + "fontCharacter": "\\E011", + "fontColor": "#cbcb41" + }, + "_coffee_erb": { + "fontCharacter": "\\E012" + }, + "_coldfusion_light": { + "fontCharacter": "\\E013", + "fontColor": "#498ba7" + }, + "_coldfusion": { + "fontCharacter": "\\E013", + "fontColor": "#519aba" + }, + "_config_light": { + "fontCharacter": "\\E014", + "fontColor": "#627379" + }, + "_config": { + "fontCharacter": "\\E014", + "fontColor": "#6d8086" + }, + "_cpp_light": { + "fontCharacter": "\\E015", + "fontColor": "#9068b0" + }, + "_cpp": { + "fontCharacter": "\\E015", + "fontColor": "#a074c4" + }, + "_css_light": { + "fontCharacter": "\\E016", + "fontColor": "#498ba7" + }, + "_css": { + "fontCharacter": "\\E016", + "fontColor": "#519aba" + }, + "_csv_light": { + "fontCharacter": "\\E017", + "fontColor": "#7fae42" + }, + "_csv": { + "fontCharacter": "\\E017", + "fontColor": "#8dc149" + }, + "_d_light": { + "fontCharacter": "\\E018", + "fontColor": "#b8383d" + }, + "_d": { + "fontCharacter": "\\E018", + "fontColor": "#cc3e44" + }, + "_db_light": { + "fontCharacter": "\\E019", + "fontColor": "#dd4b78" + }, + "_db": { + "fontCharacter": "\\E019", + "fontColor": "#f55385" + }, + "_default_light": { + "fontCharacter": "\\E01A", + "fontColor": "#bfc2c1" + }, + "_default": { + "fontCharacter": "\\E01A", + "fontColor": "#d4d7d6" + }, + "_deprecation-cop": { + "fontCharacter": "\\E01B" + }, + "_docker_light": { + "fontCharacter": "\\E01C", + "fontColor": "#dd4b78" + }, + "_docker": { + "fontCharacter": "\\E01C", + "fontColor": "#f55385" + }, + "_editorconfig": { + "fontCharacter": "\\E01D" + }, + "_ejs_light": { + "fontCharacter": "\\E01E", + "fontColor": "#b7b73b" + }, + "_ejs": { + "fontCharacter": "\\E01E", + "fontColor": "#cbcb41" + }, + "_elixir_light": { + "fontCharacter": "\\E01F", + "fontColor": "#9068b0" + }, + "_elixir": { + "fontCharacter": "\\E01F", + "fontColor": "#a074c4" + }, + "_elixir_script_light": { + "fontCharacter": "\\E020", + "fontColor": "#9068b0" + }, + "_elixir_script": { + "fontCharacter": "\\E020", + "fontColor": "#a074c4" + }, + "_elm_light": { + "fontCharacter": "\\E021", + "fontColor": "#498ba7" + }, + "_elm": { + "fontCharacter": "\\E021", + "fontColor": "#519aba" + }, + "_error": { + "fontCharacter": "\\E022" + }, + "_eslint_light": { + "fontCharacter": "\\E023", + "fontColor": "#455155" + }, + "_eslint": { + "fontCharacter": "\\E023", + "fontColor": "#4d5a5e" + }, + "_f-sharp_light": { + "fontCharacter": "\\E024", + "fontColor": "#498ba7" + }, + "_f-sharp": { + "fontCharacter": "\\E024", + "fontColor": "#519aba" + }, + "_favicon_light": { + "fontCharacter": "\\E025", + "fontColor": "#b7b73b" + }, + "_favicon": { + "fontCharacter": "\\E025", + "fontColor": "#cbcb41" + }, + "_firebase_light": { + "fontCharacter": "\\E026", + "fontColor": "#cc6d2e" + }, + "_firebase": { + "fontCharacter": "\\E026", + "fontColor": "#e37933" + }, + "_firefox_light": { + "fontCharacter": "\\E027", + "fontColor": "#cc6d2e" + }, + "_firefox": { + "fontCharacter": "\\E027", + "fontColor": "#e37933" + }, + "_folder": { + "fontCharacter": "\\E028" + }, + "_font_light": { + "fontCharacter": "\\E029", + "fontColor": "#b8383d" + }, + "_font": { + "fontCharacter": "\\E029", + "fontColor": "#cc3e44" + }, + "_git_light": { + "fontCharacter": "\\E02A", + "fontColor": "#3b4b52" + }, + "_git": { + "fontCharacter": "\\E02A", + "fontColor": "#41535b" + }, + "_git_folder": { + "fontCharacter": "\\E02B" + }, + "_git_ignore": { + "fontCharacter": "\\E02C" + }, + "_github": { + "fontCharacter": "\\E02D" + }, + "_go_light": { + "fontCharacter": "\\E02E", + "fontColor": "#498ba7" + }, + "_go": { + "fontCharacter": "\\E02E", + "fontColor": "#519aba" + }, + "_go2_light": { + "fontCharacter": "\\E02F", + "fontColor": "#498ba7" + }, + "_go2": { + "fontCharacter": "\\E02F", + "fontColor": "#519aba" + }, + "_gradle_light": { + "fontCharacter": "\\E030", + "fontColor": "#7fae42" + }, + "_gradle": { + "fontCharacter": "\\E030", + "fontColor": "#8dc149" + }, + "_grails_light": { + "fontCharacter": "\\E031", + "fontColor": "#7fae42" + }, + "_grails": { + "fontCharacter": "\\E031", + "fontColor": "#8dc149" + }, + "_grunt_light": { + "fontCharacter": "\\E032", + "fontColor": "#cc6d2e" + }, + "_grunt": { + "fontCharacter": "\\E032", + "fontColor": "#e37933" + }, + "_gulp_light": { + "fontCharacter": "\\E033", + "fontColor": "#b8383d" + }, + "_gulp": { + "fontCharacter": "\\E033", + "fontColor": "#cc3e44" + }, + "_hacklang": { + "fontCharacter": "\\E034" + }, + "_haml_light": { + "fontCharacter": "\\E035", + "fontColor": "#b8383d" + }, + "_haml": { + "fontCharacter": "\\E035", + "fontColor": "#cc3e44" + }, + "_haskell_light": { + "fontCharacter": "\\E036", + "fontColor": "#9068b0" + }, + "_haskell": { + "fontCharacter": "\\E036", + "fontColor": "#a074c4" + }, + "_heroku_light": { + "fontCharacter": "\\E037", + "fontColor": "#9068b0" + }, + "_heroku": { + "fontCharacter": "\\E037", + "fontColor": "#a074c4" + }, + "_hex_light": { + "fontCharacter": "\\E038", + "fontColor": "#b8383d" + }, + "_hex": { + "fontCharacter": "\\E038", + "fontColor": "#cc3e44" + }, + "_html_light": { + "fontCharacter": "\\E039", + "fontColor": "#cc6d2e" + }, + "_html": { + "fontCharacter": "\\E039", + "fontColor": "#e37933" + }, + "_html_erb": { + "fontCharacter": "\\E03A" + }, + "_ignored_light": { + "fontCharacter": "\\E03B", + "fontColor": "#3b4b52" + }, + "_ignored": { + "fontCharacter": "\\E03B", + "fontColor": "#41535b" + }, + "_illustrator_light": { + "fontCharacter": "\\E03C", + "fontColor": "#b7b73b" + }, + "_illustrator": { + "fontCharacter": "\\E03C", + "fontColor": "#cbcb41" + }, + "_image_light": { + "fontCharacter": "\\E03D", + "fontColor": "#9068b0" + }, + "_image": { + "fontCharacter": "\\E03D", + "fontColor": "#a074c4" + }, + "_info_light": { + "fontCharacter": "\\E03E", + "fontColor": "#498ba7" + }, + "_info": { + "fontCharacter": "\\E03E", + "fontColor": "#519aba" + }, + "_ionic_light": { + "fontCharacter": "\\E03F", + "fontColor": "#498ba7" + }, + "_ionic": { + "fontCharacter": "\\E03F", + "fontColor": "#519aba" + }, + "_jade_light": { + "fontCharacter": "\\E040", + "fontColor": "#b8383d" + }, + "_jade": { + "fontCharacter": "\\E040", + "fontColor": "#cc3e44" + }, + "_java_light": { + "fontCharacter": "\\E041", + "fontColor": "#b8383d" + }, + "_java": { + "fontCharacter": "\\E041", + "fontColor": "#cc3e44" + }, + "_javascript_light": { + "fontCharacter": "\\E042", + "fontColor": "#498ba7" + }, + "_javascript": { + "fontCharacter": "\\E042", + "fontColor": "#519aba" + }, + "_jenkins_light": { + "fontCharacter": "\\E043", + "fontColor": "#b8383d" + }, + "_jenkins": { + "fontCharacter": "\\E043", + "fontColor": "#cc3e44" + }, + "_jinja_light": { + "fontCharacter": "\\E044", + "fontColor": "#b8383d" + }, + "_jinja": { + "fontCharacter": "\\E044", + "fontColor": "#cc3e44" + }, + "_js_erb": { + "fontCharacter": "\\E045" + }, + "_json_light": { + "fontCharacter": "\\E046", + "fontColor": "#b7b73b" + }, + "_json": { + "fontCharacter": "\\E046", + "fontColor": "#cbcb41" + }, + "_julia_light": { + "fontCharacter": "\\E047", + "fontColor": "#9068b0" + }, + "_julia": { + "fontCharacter": "\\E047", + "fontColor": "#a074c4" + }, + "_karma_light": { + "fontCharacter": "\\E048", + "fontColor": "#7fae42" + }, + "_karma": { + "fontCharacter": "\\E048", + "fontColor": "#8dc149" + }, + "_less_light": { + "fontCharacter": "\\E049", + "fontColor": "#498ba7" + }, + "_less": { + "fontCharacter": "\\E049", + "fontColor": "#519aba" + }, + "_license_light": { + "fontCharacter": "\\E04A", + "fontColor": "#b8383d" + }, + "_license": { + "fontCharacter": "\\E04A", + "fontColor": "#cc3e44" + }, + "_liquid_light": { + "fontCharacter": "\\E04B", + "fontColor": "#7fae42" + }, + "_liquid": { + "fontCharacter": "\\E04B", + "fontColor": "#8dc149" + }, + "_livescript_light": { + "fontCharacter": "\\E04C", + "fontColor": "#498ba7" + }, + "_livescript": { + "fontCharacter": "\\E04C", + "fontColor": "#519aba" + }, + "_lock_light": { + "fontCharacter": "\\E04D", + "fontColor": "#7fae42" + }, + "_lock": { + "fontCharacter": "\\E04D", + "fontColor": "#8dc149" + }, + "_lua_light": { + "fontCharacter": "\\E04E", + "fontColor": "#498ba7" + }, + "_lua": { + "fontCharacter": "\\E04E", + "fontColor": "#519aba" + }, + "_makefile_light": { + "fontCharacter": "\\E04F", + "fontColor": "#498ba7" + }, + "_makefile": { + "fontCharacter": "\\E04F", + "fontColor": "#519aba" + }, + "_markdown_light": { + "fontCharacter": "\\E050", + "fontColor": "#498ba7" + }, + "_markdown": { + "fontCharacter": "\\E050", + "fontColor": "#519aba" + }, + "_maven_light": { + "fontCharacter": "\\E051", + "fontColor": "#b8383d" + }, + "_maven": { + "fontCharacter": "\\E051", + "fontColor": "#cc3e44" + }, + "_mdo_light": { + "fontCharacter": "\\E052", + "fontColor": "#b8383d" + }, + "_mdo": { + "fontCharacter": "\\E052", + "fontColor": "#cc3e44" + }, + "_mustache_light": { + "fontCharacter": "\\E053", + "fontColor": "#cc6d2e" + }, + "_mustache": { + "fontCharacter": "\\E053", + "fontColor": "#e37933" + }, + "_new-file": { + "fontCharacter": "\\E054" + }, + "_npm_light": { + "fontCharacter": "\\E055", + "fontColor": "#b8383d" + }, + "_npm": { + "fontCharacter": "\\E055", + "fontColor": "#cc3e44" + }, + "_npm_ignored_light": { + "fontCharacter": "\\E056", + "fontColor": "#3b4b52" + }, + "_npm_ignored": { + "fontCharacter": "\\E056", + "fontColor": "#41535b" + }, + "_nunjucks_light": { + "fontCharacter": "\\E057", + "fontColor": "#7fae42" + }, + "_nunjucks": { + "fontCharacter": "\\E057", + "fontColor": "#8dc149" + }, + "_ocaml_light": { + "fontCharacter": "\\E058", + "fontColor": "#cc6d2e" + }, + "_ocaml": { + "fontCharacter": "\\E058", + "fontColor": "#e37933" + }, + "_pdf_light": { + "fontCharacter": "\\E059", + "fontColor": "#b8383d" + }, + "_pdf": { + "fontCharacter": "\\E059", + "fontColor": "#cc3e44" + }, + "_perl_light": { + "fontCharacter": "\\E05A", + "fontColor": "#498ba7" + }, + "_perl": { + "fontCharacter": "\\E05A", + "fontColor": "#519aba" + }, + "_photoshop_light": { + "fontCharacter": "\\E05B", + "fontColor": "#498ba7" + }, + "_photoshop": { + "fontCharacter": "\\E05B", + "fontColor": "#519aba" + }, + "_php_light": { + "fontCharacter": "\\E05C", + "fontColor": "#9068b0" + }, + "_php": { + "fontCharacter": "\\E05C", + "fontColor": "#a074c4" + }, + "_powershell_light": { + "fontCharacter": "\\E05D", + "fontColor": "#498ba7" + }, + "_powershell": { + "fontCharacter": "\\E05D", + "fontColor": "#519aba" + }, + "_project": { + "fontCharacter": "\\E05E" + }, + "_pug_light": { + "fontCharacter": "\\E05F", + "fontColor": "#b8383d" + }, + "_pug": { + "fontCharacter": "\\E05F", + "fontColor": "#cc3e44" + }, + "_puppet_light": { + "fontCharacter": "\\E060", + "fontColor": "#b7b73b" + }, + "_puppet": { + "fontCharacter": "\\E060", + "fontColor": "#cbcb41" + }, + "_python_light": { + "fontCharacter": "\\E061", + "fontColor": "#498ba7" + }, + "_python": { + "fontCharacter": "\\E061", + "fontColor": "#519aba" + }, + "_rails": { + "fontCharacter": "\\E062" + }, + "_react_light": { + "fontCharacter": "\\E063", + "fontColor": "#498ba7" + }, + "_react": { + "fontCharacter": "\\E063", + "fontColor": "#519aba" + }, + "_rollup_light": { + "fontCharacter": "\\E064", + "fontColor": "#b8383d" + }, + "_rollup": { + "fontCharacter": "\\E064", + "fontColor": "#cc3e44" + }, + "_ruby_light": { + "fontCharacter": "\\E065", + "fontColor": "#b8383d" + }, + "_ruby": { + "fontCharacter": "\\E065", + "fontColor": "#cc3e44" + }, + "_rust_light": { + "fontCharacter": "\\E066", + "fontColor": "#627379" + }, + "_rust": { + "fontCharacter": "\\E066", + "fontColor": "#6d8086" + }, + "_salesforce_light": { + "fontCharacter": "\\E067", + "fontColor": "#498ba7" + }, + "_salesforce": { + "fontCharacter": "\\E067", + "fontColor": "#519aba" + }, + "_sass_light": { + "fontCharacter": "\\E068", + "fontColor": "#dd4b78" + }, + "_sass": { + "fontCharacter": "\\E068", + "fontColor": "#f55385" + }, + "_sbt_light": { + "fontCharacter": "\\E069", + "fontColor": "#498ba7" + }, + "_sbt": { + "fontCharacter": "\\E069", + "fontColor": "#519aba" + }, + "_scala_light": { + "fontCharacter": "\\E06A", + "fontColor": "#b8383d" + }, + "_scala": { + "fontCharacter": "\\E06A", + "fontColor": "#cc3e44" + }, + "_search": { + "fontCharacter": "\\E06B" + }, + "_settings": { + "fontCharacter": "\\E06C" + }, + "_shell_light": { + "fontCharacter": "\\E06D", + "fontColor": "#455155" + }, + "_shell": { + "fontCharacter": "\\E06D", + "fontColor": "#4d5a5e" + }, + "_slim_light": { + "fontCharacter": "\\E06E", + "fontColor": "#cc6d2e" + }, + "_slim": { + "fontCharacter": "\\E06E", + "fontColor": "#e37933" + }, + "_smarty_light": { + "fontCharacter": "\\E06F", + "fontColor": "#b7b73b" + }, + "_smarty": { + "fontCharacter": "\\E06F", + "fontColor": "#cbcb41" + }, + "_spring_light": { + "fontCharacter": "\\E070", + "fontColor": "#7fae42" + }, + "_spring": { + "fontCharacter": "\\E070", + "fontColor": "#8dc149" + }, + "_stylus_light": { + "fontCharacter": "\\E071", + "fontColor": "#7fae42" + }, + "_stylus": { + "fontCharacter": "\\E071", + "fontColor": "#8dc149" + }, + "_sublime_light": { + "fontCharacter": "\\E072", + "fontColor": "#cc6d2e" + }, + "_sublime": { + "fontCharacter": "\\E072", + "fontColor": "#e37933" + }, + "_svg_light": { + "fontCharacter": "\\E073", + "fontColor": "#9068b0" + }, + "_svg": { + "fontCharacter": "\\E073", + "fontColor": "#a074c4" + }, + "_swift_light": { + "fontCharacter": "\\E074", + "fontColor": "#cc6d2e" + }, + "_swift": { + "fontCharacter": "\\E074", + "fontColor": "#e37933" + }, + "_terraform_light": { + "fontCharacter": "\\E075", + "fontColor": "#9068b0" + }, + "_terraform": { + "fontCharacter": "\\E075", + "fontColor": "#a074c4" + }, + "_tex_light": { + "fontCharacter": "\\E076", + "fontColor": "#bfc2c1" + }, + "_tex": { + "fontCharacter": "\\E076", + "fontColor": "#d4d7d6" + }, + "_time-cop": { + "fontCharacter": "\\E077" + }, + "_todo": { + "fontCharacter": "\\E078" + }, + "_twig_light": { + "fontCharacter": "\\E079", + "fontColor": "#7fae42" + }, + "_twig": { + "fontCharacter": "\\E079", + "fontColor": "#8dc149" + }, + "_typescript_light": { + "fontCharacter": "\\E07A", + "fontColor": "#498ba7" + }, + "_typescript": { + "fontCharacter": "\\E07A", + "fontColor": "#519aba" + }, + "_vala_light": { + "fontCharacter": "\\E07B", + "fontColor": "#627379" + }, + "_vala": { + "fontCharacter": "\\E07B", + "fontColor": "#6d8086" + }, + "_video_light": { + "fontCharacter": "\\E07C", + "fontColor": "#dd4b78" + }, + "_video": { + "fontCharacter": "\\E07C", + "fontColor": "#f55385" + }, + "_vue_light": { + "fontCharacter": "\\E07D", + "fontColor": "#7fae42" + }, + "_vue": { + "fontCharacter": "\\E07D", + "fontColor": "#8dc149" + }, + "_windows_light": { + "fontCharacter": "\\E07E", + "fontColor": "#498ba7" + }, + "_windows": { + "fontCharacter": "\\E07E", + "fontColor": "#519aba" + }, + "_word_light": { + "fontCharacter": "\\E07F", + "fontColor": "#498ba7" + }, + "_word": { + "fontCharacter": "\\E07F", + "fontColor": "#519aba" + }, + "_xls_light": { + "fontCharacter": "\\E080", + "fontColor": "#7fae42" + }, + "_xls": { + "fontCharacter": "\\E080", + "fontColor": "#8dc149" + }, + "_xml_light": { + "fontCharacter": "\\E081", + "fontColor": "#cc6d2e" + }, + "_xml": { + "fontCharacter": "\\E081", + "fontColor": "#e37933" + }, + "_yarn_light": { + "fontCharacter": "\\E082", + "fontColor": "#498ba7" + }, + "_yarn": { + "fontCharacter": "\\E082", + "fontColor": "#519aba" + }, + "_yml_light": { + "fontCharacter": "\\E083", + "fontColor": "#9068b0" + }, + "_yml": { + "fontCharacter": "\\E083", + "fontColor": "#a074c4" + }, + "_zip_light": { + "fontCharacter": "\\E084", + "fontColor": "#627379" + }, + "_zip": { + "fontCharacter": "\\E084", + "fontColor": "#6d8086" + } + }, + "file": "_default", + "fileExtensions": { + "bsl": "_bsl", + "mdo": "_mdo", + "asm": "_asm", + "s": "_asm", + "h": "_c", + "cfc": "_coldfusion", + "cfm": "_coldfusion", + "config": "_config", + "cfg": "_config", + "conf": "_config", + "cson": "_json", + "css.map": "_css", + "sss": "_css", + "csv": "_csv", + "xls": "_xls", + "xlsx": "_xls", + "cake": "_cake", + "ctp": "_cake_php", + "d": "_d", + "doc": "_word", + "docx": "_word", + "ejs": "_ejs", + "ex": "_elixir", + "exs": "_elixir_script", + "elm": "_elm", + "ico": "_favicon", + "gitignore": "_git", + "gitconfig": "_git", + "gitkeep": "_git", + "gitattributes": "_git", + "gitmodules": "_git", + "slide": "_go", + "article": "_go", + "gradle": "_gradle", + "gsp": "_grails", + "haml": "_haml", + "hjs": "_mustache", + "hs": "_haskell", + "lhs": "_haskell", + "class": "_java", + "classpath": "_java", + "js.map": "_javascript", + "spec.js": "_javascript", + "es": "_javascript", + "es5": "_javascript", + "es7": "_javascript", + "jinja": "_jinja", + "jinja2": "_jinja", + "jl": "_julia", + "js": "_javascript", + "liquid": "_liquid", + "ls": "_livescript", + "md": "_markdown", + "mustache": "_mustache", + "stache": "_mustache", + "njk": "_nunjucks", + "nunjucks": "_nunjucks", + "nunjs": "_nunjucks", + "nunj": "_nunjucks", + "njs": "_nunjucks", + "nj": "_nunjucks", + "npm-debug.log": "_npm", + "npmignore": "_npm", + "npmrc": "_npm", + "ml": "_ocaml", + "mli": "_ocaml", + "cmx": "_ocaml", + "cmxa": "_ocaml", + "php.inc": "_php", + "pug": "_pug", + "pp": "_puppet", + "epp": "_puppet", + "cjsx": "_react", + "erb.html": "_ruby", + "html.erb": "_ruby", + "sass": "_sass", + "springbeans": "_spring", + "slim": "_slim", + "smarty.tpl": "_smarty", + "sbt": "_sbt", + "scala": "_scala", + "styl": "_stylus", + "tf": "_terraform", + "tf.json": "_terraform", + "tex": "_tex", + "sty": "_tex", + "dtx": "_tex", + "ins": "_tex", + "txt": "_default", + "toml": "_config", + "twig": "_twig", + "vala": "_vala", + "vapi": "_vala", + "vue": "_vue", + "jar": "_zip", + "zip": "_zip", + "ai": "_illustrator", + "psd": "_photoshop", + "pdf": "_pdf", + "eot": "_font", + "ttf": "_font", + "woff": "_font", + "woff2": "_font", + "gif": "_image", + "jpg": "_image", + "jpeg": "_image", + "png": "_image", + "pxm": "_image", + "svg": "_svg", + "svgx": "_image", + "webp": "_image", + "sublime-project": "_sublime", + "sublime-workspace": "_sublime", + "component": "_salesforce", + "cls": "_salesforce", + "fish": "_shell", + "mov": "_video", + "ogv": "_video", + "webm": "_video", + "avi": "_video", + "mpg": "_video", + "mp4": "_video", + "mp3": "_audio", + "ogg": "_audio", + "wav": "_audio", + "babelrc": "_babel", + "bowerrc": "_bower", + "dockerignore": "_docker", + "codeclimate.yml": "_code-climate", + "eslintrc": "_eslint", + "eslintrc.js": "_eslint", + "eslintrc.yaml": "_eslint", + "eslintrc.yml": "_eslint", + "eslintrc.json": "_eslint", + "eslintignore": "_eslint", + "firebaserc": "_firebase", + "jshintrc": "_javascript", + "jscsrc": "_javascript", + "direnv": "_config", + "env": "_config", + "static": "_config", + "editorconfig": "_config", + "slugignore": "_config", + "tmp": "_clock", + "htaccess": "_config", + "key": "_lock", + "cert": "_lock", + "ds_store": "_ignored", + "ts": "_typescript", + "tsx": "_react" + }, + "fileNames": { + "mix": "_hex", + "karma.conf.js": "_karma", + "karma.conf.coffee": "_karma", + "readme.md": "_info", + "changelog.md": "_clock", + "changelog": "_clock", + "version.md": "_clock", + "version": "_clock", + "mvnw": "_maven", + "mime.types": "_config", + "jenkinsfile": "_jenkins", + "bower.json": "_bower", + "docker-healthcheck": "_docker", + "docker-compose.yml": "_docker", + "firebase.json": "_firebase", + "geckodriver": "_firefox", + "gruntfile.js": "_grunt", + "gruntfile.babel.js": "_grunt", + "gruntfile.coffee": "_grunt", + "gulpfile": "_gulp", + "ionic.config.json": "_ionic", + "ionic.project": "_ionic", + "rollup.config.js": "_rollup", + "sass-lint.yml": "_sass", + "yarn.clean": "_yarn", + "yarn.lock": "_yarn", + "license": "_license", + "licence": "_license", + "copying": "_license", + "compiling": "_license", + "contributing": "_license", + "qmakefile": "_makefile", + "omakefile": "_makefile", + "cmakelists.txt": "_makefile", + "procfile": "_heroku", + "todo": "_todo", + "npm-debug.log": "_npm_ignored" + }, + "languageIds": { + "bat": "_windows", + "coffeescript": "_coffee", + "c": "_c", + "cpp": "_cpp", + "csharp": "_c-sharp", + "css": "_css", + "dockerfile": "_docker", + "fsharp": "_f-sharp", + "go": "_go2", + "groovy": "_grails", + "handlebars": "_mustache", + "html": "_html", + "properties": "_java", + "java": "_java", + "javascriptreact": "_react", + "javascript": "_javascript", + "json": "_json", + "less": "_less", + "lua": "_lua", + "makefile": "_makefile", + "markdown": "_markdown", + "objective-c": "_c", + "perl": "_perl", + "php": "_php", + "powershell": "_powershell", + "jade": "_jade", + "python": "_python", + "ruby": "_ruby", + "rust": "_rust", + "scss": "_sass", + "shellscript": "_shell", + "sql": "_db", + "swift": "_swift", + "typescript": "_typescript", + "typescriptreact": "_react", + "xml": "_xml", + "yaml": "_yml" + }, + "light": { + "file": "_default_light", + "fileExtensions": { + "bsl": "_bsl_light", + "mdo": "_mdo_light", + "asm": "_asm_light", + "s": "_asm_light", + "h": "_c_light", + "cfc": "_coldfusion_light", + "cfm": "_coldfusion_light", + "config": "_config_light", + "cfg": "_config_light", + "conf": "_config_light", + "cson": "_json_light", + "css.map": "_css_light", + "sss": "_css_light", + "csv": "_csv_light", + "xls": "_xls_light", + "xlsx": "_xls_light", + "cake": "_cake_light", + "ctp": "_cake_php_light", + "d": "_d_light", + "doc": "_word_light", + "docx": "_word_light", + "ejs": "_ejs_light", + "ex": "_elixir_light", + "exs": "_elixir_script_light", + "elm": "_elm_light", + "ico": "_favicon_light", + "gitignore": "_git_light", + "gitconfig": "_git_light", + "gitkeep": "_git_light", + "gitattributes": "_git_light", + "gitmodules": "_git_light", + "slide": "_go_light", + "article": "_go_light", + "gradle": "_gradle_light", + "gsp": "_grails_light", + "haml": "_haml_light", + "hjs": "_mustache_light", + "hs": "_haskell_light", + "lhs": "_haskell_light", + "class": "_java_light", + "classpath": "_java_light", + "js.map": "_javascript_light", + "spec.js": "_javascript_light", + "es": "_javascript_light", + "es5": "_javascript_light", + "es7": "_javascript_light", + "jinja": "_jinja_light", + "jinja2": "_jinja_light", + "jl": "_julia_light", + "liquid": "_liquid_light", + "ls": "_livescript_light", + "mustache": "_mustache_light", + "stache": "_mustache_light", + "njk": "_nunjucks_light", + "nunjucks": "_nunjucks_light", + "nunjs": "_nunjucks_light", + "nunj": "_nunjucks_light", + "njs": "_nunjucks_light", + "nj": "_nunjucks_light", + "npm-debug.log": "_npm_light", + "npmignore": "_npm_light", + "npmrc": "_npm_light", + "ml": "_ocaml_light", + "mli": "_ocaml_light", + "cmx": "_ocaml_light", + "cmxa": "_ocaml_light", + "php.inc": "_php_light", + "pug": "_pug_light", + "pp": "_puppet_light", + "epp": "_puppet_light", + "cjsx": "_react_light", + "erb.html": "_ruby_light", + "html.erb": "_ruby_light", + "sass": "_sass_light", + "springbeans": "_spring_light", + "slim": "_slim_light", + "smarty.tpl": "_smarty_light", + "sbt": "_sbt_light", + "scala": "_scala_light", + "styl": "_stylus_light", + "tf": "_terraform_light", + "tf.json": "_terraform_light", + "tex": "_tex_light", + "sty": "_tex_light", + "dtx": "_tex_light", + "ins": "_tex_light", + "txt": "_default_light", + "toml": "_config_light", + "twig": "_twig_light", + "vala": "_vala_light", + "vapi": "_vala_light", + "vue": "_vue_light", + "jar": "_zip_light", + "zip": "_zip_light", + "ai": "_illustrator_light", + "psd": "_photoshop_light", + "pdf": "_pdf_light", + "eot": "_font_light", + "ttf": "_font_light", + "woff": "_font_light", + "woff2": "_font_light", + "gif": "_image_light", + "jpg": "_image_light", + "jpeg": "_image_light", + "png": "_image_light", + "pxm": "_image_light", + "svg": "_svg_light", + "svgx": "_image_light", + "sublime-project": "_sublime_light", + "sublime-workspace": "_sublime_light", + "component": "_salesforce_light", + "cls": "_salesforce_light", + "fish": "_shell_light", + "mov": "_video_light", + "ogv": "_video_light", + "webm": "_video_light", + "avi": "_video_light", + "mpg": "_video_light", + "mp4": "_video_light", + "mp3": "_audio_light", + "ogg": "_audio_light", + "wav": "_audio_light", + "babelrc": "_babel_light", + "bowerrc": "_bower_light", + "dockerignore": "_docker_light", + "codeclimate.yml": "_code-climate_light", + "eslintrc": "_eslint_light", + "eslintrc.js": "_eslint_light", + "eslintrc.yaml": "_eslint_light", + "eslintrc.yml": "_eslint_light", + "eslintrc.json": "_eslint_light", + "eslintignore": "_eslint_light", + "firebaserc": "_firebase_light", + "jshintrc": "_javascript_light", + "jscsrc": "_javascript_light", + "direnv": "_config_light", + "env": "_config_light", + "static": "_config_light", + "editorconfig": "_config_light", + "slugignore": "_config_light", + "tmp": "_clock_light", + "htaccess": "_config_light", + "key": "_lock_light", + "cert": "_lock_light", + "ds_store": "_ignored_light" + }, + "languageIds": { + "bat": "_windows_light", + "coffeescript": "_coffee_light", + "c": "_c_light", + "cpp": "_cpp_light", + "csharp": "_c-sharp_light", + "css": "_css_light", + "dockerfile": "_docker_light", + "fsharp": "_f-sharp_light", + "go": "_go2_light", + "groovy": "_grails_light", + "handlebars": "_mustache_light", + "html": "_html_light", + "properties": "_java_light", + "java": "_java_light", + "javascriptreact": "_react_light", + "javascript": "_javascript_light", + "json": "_json_light", + "less": "_less_light", + "lua": "_lua_light", + "makefile": "_makefile_light", + "markdown": "_markdown_light", + "objective-c": "_c_light", + "perl": "_perl_light", + "php": "_php_light", + "powershell": "_powershell_light", + "jade": "_jade_light", + "python": "_python_light", + "ruby": "_ruby_light", + "rust": "_rust_light", + "scss": "_sass_light", + "shellscript": "_shell_light", + "sql": "_db_light", + "swift": "_swift_light", + "typescript": "_typescript_light", + "typescriptreact": "_react_light", + "xml": "_xml_light", + "yaml": "_yml_light" + }, + "fileNames": { + "mix": "_hex_light", + "karma.conf.js": "_karma_light", + "karma.conf.coffee": "_karma_light", + "readme.md": "_info_light", + "changelog.md": "_clock_light", + "changelog": "_clock_light", + "version.md": "_clock_light", + "version": "_clock_light", + "mvnw": "_maven_light", + "mime.types": "_config_light", + "jenkinsfile": "_jenkins_light", + "bower.json": "_bower_light", + "docker-healthcheck": "_docker_light", + "docker-compose.yml": "_docker_light", + "firebase.json": "_firebase_light", + "geckodriver": "_firefox_light", + "gruntfile.js": "_grunt_light", + "gruntfile.babel.js": "_grunt_light", + "gruntfile.coffee": "_grunt_light", + "gulpfile": "_gulp_light", + "ionic.config.json": "_ionic_light", + "ionic.project": "_ionic_light", + "rollup.config.js": "_rollup_light", + "sass-lint.yml": "_sass_light", + "yarn.clean": "_yarn_light", + "yarn.lock": "_yarn_light", + "license": "_license_light", + "licence": "_license_light", + "copying": "_license_light", + "compiling": "_license_light", + "contributing": "_license_light", + "qmakefile": "_makefile_light", + "omakefile": "_makefile_light", + "cmakelists.txt": "_makefile_light", + "procfile": "_heroku_light", + "npm-debug.log": "_npm_ignored_light" + } + }, + "version": + "https://github.com/jesseweed/seti-ui/commit/c44b29c7a5b2f189fccfd58ceea02b117678caa9" } diff --git a/extensions/theme-icons-seti/package.json b/extensions/theme-icons-seti/package.json index b78d475f84..25102540ca 100644 --- a/extensions/theme-icons-seti/package.json +++ b/extensions/theme-icons-seti/package.json @@ -1,19 +1,19 @@ { - "name": "theme-icons-seti", - "private": true, - "version": "0.0.1", + "name": "theme-icons-seti", + "private": true, + "version": "0.0.1", "description": "A file icon theme made out of the Seti UI file icons", - "publisher": "onivim", - "engines": { - "oni": "0.2.19" - }, - "contributes": { - "iconThemes": [ - { - "id": "theme-icons-seti", - "label": "Seti (Oni)", - "path": "./icons/seti-icon-theme.json" - } - ] - } + "publisher": "onivim", + "engines": { + "oni": "0.2.19" + }, + "contributes": { + "iconThemes": [ + { + "id": "theme-icons-seti", + "label": "Seti (Oni)", + "path": "./icons/seti-icon-theme.json" + } + ] + } } diff --git a/extensions/theme-nord/package.json b/extensions/theme-nord/package.json index 41ccdd033d..c84d0357fb 100644 --- a/extensions/theme-nord/package.json +++ b/extensions/theme-nord/package.json @@ -1,19 +1,21 @@ { - "name": "theme-nord", - "version": "0.0.1", - "description": "Nord theme, customized for Oni", - "engines": { - "oni": "0.2.18" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "contributes": { - "themes": [{ - "name": "nord", - "path": "colors/nord.json" - }] - }, - "author": "", - "license": "MIT" + "name": "theme-nord", + "version": "0.0.1", + "description": "Nord theme, customized for Oni", + "engines": { + "oni": "0.2.18" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "contributes": { + "themes": [ + { + "name": "nord", + "path": "colors/nord.json" + } + ] + }, + "author": "", + "license": "MIT" } diff --git a/extensions/theme-onedark/package.json b/extensions/theme-onedark/package.json index 2fab303231..ff179753cc 100644 --- a/extensions/theme-onedark/package.json +++ b/extensions/theme-onedark/package.json @@ -1,19 +1,21 @@ { - "name": "theme-onedark", - "version": "0.0.1", - "description": "One-dark theme, set for Oni", - "engines": { - "oni": "0.2.18" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "contributes": { - "themes": [{ - "name": "onedark", - "path": "colors/onedark.json" - }] - }, - "author": "", - "license": "MIT" + "name": "theme-onedark", + "version": "0.0.1", + "description": "One-dark theme, set for Oni", + "engines": { + "oni": "0.2.18" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "contributes": { + "themes": [ + { + "name": "onedark", + "path": "colors/onedark.json" + } + ] + }, + "author": "", + "license": "MIT" } diff --git a/extensions/theme-solarized/colors/solarized8_dark.json b/extensions/theme-solarized/colors/solarized8_dark.json index 7153d033e8..ae4229d2fb 100644 --- a/extensions/theme-solarized/colors/solarized8_dark.json +++ b/extensions/theme-solarized/colors/solarized8_dark.json @@ -1,45 +1,45 @@ { - "name": "solarized8_dark", - "baseVimTheme": "solarized8_dark", - "colors": { - "background": "#073642", - "foreground": "#839496", + "name": "solarized8_dark", + "baseVimTheme": "solarized8_dark", + "colors": { + "background": "#073642", + "foreground": "#839496", - "title.background": "#002b36", - "title.foreground": "#839496", + "title.background": "#002b36", + "title.foreground": "#839496", - "editor.background": "#073642", - "editor.foreground": "#586e75", + "editor.background": "#073642", + "editor.foreground": "#586e75", - "tabs.background": "#073642", - "tabs.foreground": "#839496", + "tabs.background": "#073642", + "tabs.foreground": "#839496", - "toolTip.background": "#002b36", - "toolTip.foreground": "#839496", - "toolTip.border": "#505050", + "toolTip.background": "#002b36", + "toolTip.foreground": "#839496", + "toolTip.border": "#505050", - "menu.background": "#002b36", - "menu.foreground": "#839496", - "menu.border": "#505050", + "menu.background": "#002b36", + "menu.foreground": "#839496", + "menu.border": "#505050", - "contextMenu.background": "#002b36", - "contextMenu.foreground": "#839496", - "contextMenu.border": "#505050", - "contextMenu.highlight": "#3F4652", + "contextMenu.background": "#002b36", + "contextMenu.foreground": "#839496", + "contextMenu.border": "#505050", + "contextMenu.highlight": "#3F4652", - "statusBar.background": "#073642", - "statusBar.foreground": "#839496", + "statusBar.background": "#073642", + "statusBar.foreground": "#839496", - "highlight.mode.insert.background": "#2aa198", - "highlight.mode.insert.foreground": "#fdf6e3", + "highlight.mode.insert.background": "#2aa198", + "highlight.mode.insert.foreground": "#fdf6e3", - "highlight.mode.normal.background": "#839496", - "highlight.mode.normal.foreground": "#fdf6e3", + "highlight.mode.normal.background": "#839496", + "highlight.mode.normal.foreground": "#fdf6e3", - "highlight.mode.operator.background": "#d19a66", - "highlight.mode.operator.foreground": "#fdf6e3", + "highlight.mode.operator.background": "#d19a66", + "highlight.mode.operator.foreground": "#fdf6e3", - "highlight.mode.visual.background": "#d33682", - "highlight.mode.visual.foreground": "#fdf6e3" - } + "highlight.mode.visual.background": "#d33682", + "highlight.mode.visual.foreground": "#fdf6e3" + } } diff --git a/extensions/theme-solarized/colors/solarized8_light.json b/extensions/theme-solarized/colors/solarized8_light.json index 55a43b401f..fffd6ec4a8 100644 --- a/extensions/theme-solarized/colors/solarized8_light.json +++ b/extensions/theme-solarized/colors/solarized8_light.json @@ -1,45 +1,45 @@ { - "name": "solarized8_light", - "baseVimTheme": "solarized8_light", - "colors": { - "background": "#073642", - "foreground": "#839496", + "name": "solarized8_light", + "baseVimTheme": "solarized8_light", + "colors": { + "background": "#073642", + "foreground": "#839496", - "title.background": "#002b36", - "title.foreground": "#839496", + "title.background": "#002b36", + "title.foreground": "#839496", - "editor.background": "#002b36", - "editor.foreground": "#586e75", + "editor.background": "#002b36", + "editor.foreground": "#586e75", - "tabs.background": "#002b36", - "tabs.foreground": "#839496", + "tabs.background": "#002b36", + "tabs.foreground": "#839496", - "toolTip.background": "#002b36", - "toolTip.foreground": "#839496", - "toolTip.border": "#505050", + "toolTip.background": "#002b36", + "toolTip.foreground": "#839496", + "toolTip.border": "#505050", - "menu.background": "#002b36", - "menu.foreground": "#839496", - "menu.border": "#505050", + "menu.background": "#002b36", + "menu.foreground": "#839496", + "menu.border": "#505050", - "contextMenu.background": "#002b36", - "contextMenu.foreground": "#839496", - "contextMenu.border": "#505050", - "contextMenu.highlight": "#3F4652", + "contextMenu.background": "#002b36", + "contextMenu.foreground": "#839496", + "contextMenu.border": "#505050", + "contextMenu.highlight": "#3F4652", - "statusBar.background": "#839496", - "statusBar.foreground": "#073642", + "statusBar.background": "#839496", + "statusBar.foreground": "#073642", - "highlight.mode.insert.background": "#2aa198", - "highlight.mode.insert.foreground": "#fdf6e3", + "highlight.mode.insert.background": "#2aa198", + "highlight.mode.insert.foreground": "#fdf6e3", - "highlight.mode.normal.background": "#839496", - "highlight.mode.normal.foreground": "#fdf6e3", + "highlight.mode.normal.background": "#839496", + "highlight.mode.normal.foreground": "#fdf6e3", - "highlight.mode.operator.background": "#d19a66", - "highlight.mode.operator.foreground": "#fdf6e3", + "highlight.mode.operator.background": "#d19a66", + "highlight.mode.operator.foreground": "#fdf6e3", - "highlight.mode.visual.background": "#d33682", - "highlight.mode.visual.foreground": "#fdf6e3" - } + "highlight.mode.visual.background": "#d33682", + "highlight.mode.visual.foreground": "#fdf6e3" + } } diff --git a/extensions/theme-solarized/package.json b/extensions/theme-solarized/package.json index 3d40ffb006..e0ed9f42a0 100644 --- a/extensions/theme-solarized/package.json +++ b/extensions/theme-solarized/package.json @@ -1,25 +1,25 @@ { - "name": "theme-solarized", - "version": "0.0.1", - "description": "Solarized theme, set for Oni", - "engines": { - "oni": "0.2.18" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "contributes": { - "themes": [ - { - "name": "solarized8_dark", - "path": "colors/solarized8_dark.json" - }, - { - "name": "solarized8_light", - "path": "colors/solarized8_light.json" - } - ] - }, - "author": "", - "license": "MIT" + "name": "theme-solarized", + "version": "0.0.1", + "description": "Solarized theme, set for Oni", + "engines": { + "oni": "0.2.18" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "contributes": { + "themes": [ + { + "name": "solarized8_dark", + "path": "colors/solarized8_dark.json" + }, + { + "name": "solarized8_light", + "path": "colors/solarized8_light.json" + } + ] + }, + "author": "", + "license": "MIT" } diff --git a/extensions/typescript/syntaxes/TypeScript.tmLanguage.json b/extensions/typescript/syntaxes/TypeScript.tmLanguage.json index 70717a1ef0..5e0eba55b6 100644 --- a/extensions/typescript/syntaxes/TypeScript.tmLanguage.json +++ b/extensions/typescript/syntaxes/TypeScript.tmLanguage.json @@ -1,3997 +1,4084 @@ { - "information_for_contributors": [ - "This file has been converted from https://github.com/Microsoft/TypeScript-TmLanguage/blob/master/TypeScript.tmLanguage", - "If you want to provide a fix or improvement, please create a pull request against the original repository.", - "Once accepted there, we are happy to receive an update request." - ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/8361b1a232501c67911c81a4664a9460d7922c6b", - "name": "TypeScript", - "scopeName": "source.ts", - "fileTypes": [ - "ts" - ], - "uuid": "ef98eb90-bf9b-11e4-bb52-0800200c9a66", - "patterns": [ - { - "include": "#directives" - }, - { - "include": "#statements" - }, - { - "name": "comment.line.shebang.ts", - "match": "\\A(#!).*(?=$)", - "captures": { - "1": { - "name": "punctuation.definition.comment.ts" - } - } - } - ], - "repository": { - "statements": { - "patterns": [ - { - "include": "#string" - }, - { - "include": "#template" - }, - { - "include": "#comment" - }, - { - "include": "#declaration" - }, - { - "include": "#control-statement" - }, - { - "include": "#after-operator-block-as-object-literal" - }, - { - "include": "#decl-block" - }, - { - "include": "#expression" - }, - { - "include": "#punctuation-semicolon" - } - ] - }, - "declaration": { - "patterns": [ - { - "include": "#decorator" - }, - { - "include": "#var-expr" - }, - { - "include": "#function-declaration" - }, - { - "include": "#class-declaration" - }, - { - "include": "#interface-declaration" - }, - { - "include": "#enum-declaration" - }, - { - "include": "#namespace-declaration" - }, - { - "include": "#type-alias-declaration" - }, - { - "include": "#import-equals-declaration" - }, - { - "include": "#import-declaration" - }, - { - "include": "#export-declaration" - } - ] - }, - "control-statement": { - "patterns": [ - { - "include": "#switch-statement" - }, - { - "include": "#for-loop" - }, - { - "name": "keyword.control.trycatch.ts", - "match": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", - "beginCaptures": { - "1": { - "name": "meta.definition.variable.ts entity.name.function.ts" - } - }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", - "patterns": [ - { - "include": "#var-single-variable-type-annotation" - } - ] - }, - { - "name": "meta.var-single-variable.expr.ts", - "begin": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", - "beginCaptures": { - "1": { - "name": "meta.definition.variable.ts variable.other.constant.ts" - } - }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", - "patterns": [ - { - "include": "#var-single-variable-type-annotation" - } - ] - }, - { - "name": "meta.var-single-variable.expr.ts", - "begin": "([_$[:alpha:]][_$[:alnum:]]*)", - "beginCaptures": { - "1": { - "name": "meta.definition.variable.ts variable.other.readwrite.ts" - } - }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", - "patterns": [ - { - "include": "#var-single-variable-type-annotation" - } - ] - } - ] - }, - "var-single-variable-type-annotation": { - "patterns": [ - { - "include": "#type-annotation" - }, - { - "include": "#string" - }, - { - "include": "#comment" - } - ] - }, - "destructuring-variable": { - "patterns": [ - { - "name": "meta.object-binding-pattern-variable.ts", - "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", - "captures": { - "1": { - "name": "storage.modifier.ts" - }, - "2": { - "name": "keyword.operator.rest.ts" - }, - "3": { - "name": "entity.name.function.ts variable.language.this.ts" - }, - "4": { - "name": "entity.name.function.ts" - }, - "5": { - "name": "keyword.operator.optional.ts" - } - } - }, - { - "match": "(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" - }, - { - "name": "meta.definition.property.ts variable.object.property.ts", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - }, - { - "name": "keyword.operator.optional.ts", - "match": "\\?" - } - ] - } - ] - }, - "variable-initializer": { - "patterns": [ - { - "begin": "(?)", - "captures": { - "1": { - "name": "storage.modifier.async.ts" - }, - "2": { - "name": "variable.parameter.ts" - } - } - }, - { - "name": "meta.arrow.ts", - "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", - "beginCaptures": { - "1": { - "name": "storage.modifier.async.ts" - } - }, - "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#type-parameters" - }, - { - "include": "#function-parameters" - }, - { - "include": "#arrow-return-type" - } - ] - }, - { - "name": "meta.arrow.ts", - "begin": "=>", - "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.ts" - } - }, - "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", - "patterns": [ - { - "include": "#decl-block" - }, - { - "include": "#expression" - } - ] - } - ] - }, - "indexer-declaration": { - "name": "meta.indexer.declaration.ts", - "begin": "(?:(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", - "captures": { - "0": { - "name": "meta.object-literal.key.ts" - }, - "1": { - "name": "entity.name.function.ts" - } - } - }, - { - "name": "meta.object.member.ts", - "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", - "captures": { - "0": { - "name": "meta.object-literal.key.ts" - } - } - }, - { - "name": "meta.object.member.ts", - "begin": "\\.\\.\\.", - "beginCaptures": { - "0": { - "name": "keyword.operator.spread.ts" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "name": "meta.object.member.ts", - "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", - "captures": { - "1": { - "name": "variable.other.readwrite.ts" - } - } - }, - { - "name": "meta.object.member.ts", - "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", - "end": "(?=,|\\}|$)", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "name": "meta.object.member.ts", - "begin": ":", - "beginCaptures": { - "0": { - "name": "meta.object-literal.key.ts punctuation.separator.key-value.ts" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "include": "#punctuation-comma" - } - ] - }, - "ternary-expression": { - "begin": "(\\?)", - "beginCaptures": { - "0": { - "name": "keyword.operator.ternary.ts" - } - }, - "end": "(:)", - "endCaptures": { - "0": { - "name": "keyword.operator.ternary.ts" - } - }, - "patterns": [ - { - "include": "#expression" - } - ] - }, - "function-call": { - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", - "patterns": [ - { - "name": "meta.function-call.ts", - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", - "patterns": [ - { - "include": "#literal" - }, - { - "include": "#support-objects" - }, - { - "include": "#object-identifiers" - }, - { - "include": "#punctuation-accessor" - }, - { - "name": "keyword.operator.expression.import.ts", - "match": "(?![\\.\\$])\\bimport(?=\\s*[\\(]\\s*[\\\"\\'\\`])" - }, - { - "name": "entity.name.function.ts", - "match": "([_$[:alpha:]][_$[:alnum:]]*)" - } - ] - }, - { - "include": "#comment" - }, - { - "name": "meta.type.parameters.ts", - "begin": "\\<", - "beginCaptures": { - "0": { - "name": "punctuation.definition.typeparameters.begin.ts" - } - }, - "end": "\\>", - "endCaptures": { - "0": { - "name": "punctuation.definition.typeparameters.end.ts" - } - }, - "patterns": [ - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - { - "include": "#paren-expression" - } - ] - }, - "new-expr": { - "name": "new.expr.ts", - "begin": "(?*?]|[^+]\\+))\\s*(<)(?!)\\s*", - "endCaptures": { - "1": { - "name": "meta.brace.angle.ts" - } - }, - "patterns": [ - { - "include": "#type" - } - ] - }, - { - "name": "cast.expr.ts", - "begin": "(?:(?<=^))\\s*(<)(?=[_$[:alpha:]][_$[:alnum:]]*\\s*>)", - "beginCaptures": { - "1": { - "name": "meta.brace.angle.ts" - } - }, - "end": "(\\>)\\s*", - "endCaptures": { - "1": { - "name": "meta.brace.angle.ts" - } - }, - "patterns": [ - { - "include": "#type" - } - ] - } - ] - }, - "expression-operators": { - "patterns": [ - { - "name": "keyword.control.flow.ts", - "match": "(?>=|>>>=|\\|=" - }, - { - "name": "keyword.operator.bitwise.shift.ts", - "match": "<<|>>>|>>" - }, - { - "name": "keyword.operator.comparison.ts", - "match": "===|!==|==|!=" - }, - { - "name": "keyword.operator.relational.ts", - "match": "<=|>=|<>|<|>" - }, - { - "name": "keyword.operator.logical.ts", - "match": "\\!|&&|\\|\\|" - }, - { - "name": "keyword.operator.bitwise.ts", - "match": "\\&|~|\\^|\\|" - }, - { - "name": "keyword.operator.assignment.ts", - "match": "\\=" - }, - { - "name": "keyword.operator.decrement.ts", - "match": "--" - }, - { - "name": "keyword.operator.increment.ts", - "match": "\\+\\+" - }, - { - "name": "keyword.operator.arithmetic.ts", - "match": "%|\\*|/|-|\\+" - }, - { - "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", - "captures": { - "1": { - "name": "keyword.operator.arithmetic.ts" - } - } - } - ] - }, - "typeof-operator": { - "name": "keyword.operator.expression.typeof.ts", - "match": "(?=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "captures": { - "1": { - "name": "punctuation.accessor.ts" - }, - "2": { - "name": "support.constant.dom.ts" - }, - "3": { - "name": "support.variable.property.dom.ts" - } - } - }, - { - "name": "support.class.node.ts", - "match": "(?x)(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", - "captures": { - "1": { - "name": "punctuation.accessor.ts" - }, - "2": { - "name": "entity.name.function.ts" - } - } - }, - { - "match": "(\\.)\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", - "captures": { - "1": { - "name": "punctuation.accessor.ts" - }, - "2": { - "name": "variable.other.constant.property.ts" - } - } - }, - { - "match": "(\\.)\\s*([_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "punctuation.accessor.ts" - }, - "2": { - "name": "variable.other.property.ts" - } - } - }, - { - "name": "variable.other.constant.ts", - "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" - }, - { - "name": "variable.other.readwrite.ts", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - } - ] - }, - "object-identifiers": { - "patterns": [ - { - "name": "support.class.ts", - "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\.\\s*prototype\\b(?!\\$))" - }, - { - "match": "(?x)(\\.)\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "punctuation.accessor.ts" - }, - "2": { - "name": "variable.other.constant.object.property.ts" - }, - "3": { - "name": "variable.other.object.property.ts" - } - } - }, - { - "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "variable.other.constant.object.ts" - }, - "2": { - "name": "variable.other.object.ts" - } - } - } - ] - }, - "type-annotation": { - "patterns": [ - { - "name": "meta.type.annotation.ts", - "begin": "(:)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.ts" - } - }, - "end": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - }, - { - "name": "meta.type.annotation.ts", - "begin": "(:)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.ts" - } - }, - "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - } - ] - }, - "return-type": { - "patterns": [ - { - "name": "meta.return.type.ts", - "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.ts" - } - }, - "end": "(?|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", - "patterns": [ - { - "begin": "(?<=[:])(?=\\s*\\{)", - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "include": "#type-predicate-operator" - }, - { - "include": "#type" - } - ] - }, - "type-parameters": { - "name": "meta.type.parameters.ts", - "begin": "(<)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.begin.ts" - } - }, - "end": "(>)", - "endCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.end.ts" - } - }, - "patterns": [ - { - "include": "#comment" - }, - { - "name": "storage.modifier.ts", - "match": "(?)" - }, - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - "type": { - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#string" - }, - { - "include": "#numeric-literal" - }, - { - "include": "#type-primitive" - }, - { - "include": "#type-builtin-literals" - }, - { - "include": "#type-parameters" - }, - { - "include": "#type-tuple" - }, - { - "include": "#type-object" - }, - { - "include": "#type-operators" - }, - { - "include": "#type-fn-type-parameters" - }, - { - "include": "#type-paren-or-function-parameters" - }, - { - "include": "#type-function-return-type" - }, - { - "include": "#type-name" - } - ] - }, - "type-primitive": { - "name": "support.type.primitive.ts", - "match": "(?)\n ))\n )\n )\n)", - "end": "(?<=\\))", - "patterns": [ - { - "include": "#function-parameters" - } - ] - } - ] - }, - "type-function-return-type": { - "patterns": [ - { - "name": "meta.type.function.return.ts", - "begin": "(=>)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "storage.type.function.arrow.ts" - } - }, - "end": "(?)(?]|//|$)", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - }, - { - "name": "meta.type.function.return.ts", - "begin": "=>", - "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.ts" - } - }, - "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - } - ] - }, - "type-function-return-type-core": { - "patterns": [ - { - "include": "#comment" - }, - { - "begin": "(?<==>)(?=\\s*\\{)", - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "include": "#type-predicate-operator" - }, - { - "include": "#type" - } - ] - }, - "type-operators": { - "patterns": [ - { - "include": "#typeof-operator" - }, - { - "begin": "([&|])(?=\\s*\\{)", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.ts" - } - }, - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "begin": "[&|]", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.ts" - } - }, - "end": "(?=\\S)" - }, - { - "name": "keyword.operator.expression.keyof.ts", - "match": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", - "beginCaptures": { - "1": { - "name": "punctuation.definition.string.begin.ts" - } - }, - "end": "(/)([gimuy]*)", - "endCaptures": { - "1": { - "name": "punctuation.definition.string.end.ts" - }, - "2": { - "name": "keyword.other.ts" - } - }, - "patterns": [ - { - "include": "#regexp" - } - ] - }, - { - "name": "string.regexp.ts", - "begin": "(?\\s*$)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.comment.ts" - } - }, - "end": "(?=^)", - "patterns": [ - { - "name": "meta.tag.ts", - "begin": "(<)(reference|amd-dependency|amd-module)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.tag.directive.ts" - }, - "2": { - "name": "entity.name.tag.directive.ts" - } - }, - "end": "/>", - "endCaptures": { - "0": { - "name": "punctuation.definition.tag.directive.ts" - } - }, - "patterns": [ - { - "name": "entity.other.attribute-name.directive.ts", - "match": "path|types|no-default-lib|name" - }, - { - "name": "keyword.operator.assignment.ts", - "match": "=" - }, - { - "include": "#string" - } - ] - } - ] - }, - "docblock": { - "patterns": [ - { - "match": "(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "constant.language.access-type.jsdoc" - } - } - }, - { - "match": "(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "entity.name.type.instance.jsdoc" - }, - "4": { - "name": "punctuation.definition.bracket.angle.begin.jsdoc" - }, - "5": { - "name": "constant.other.email.link.underline.jsdoc" - }, - "6": { - "name": "punctuation.definition.bracket.angle.end.jsdoc" - } - } - }, - { - "match": "(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "entity.name.type.instance.jsdoc" - }, - "4": { - "name": "keyword.operator.control.jsdoc" - }, - "5": { - "name": "entity.name.type.instance.jsdoc" - } - } - }, - { - "name": "meta.example.jsdoc", - "begin": "((@)example)\\s+", - "end": "(?=@|\\*/)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "patterns": [ - { - "match": "^\\s\\*\\s+" - }, - { - "contentName": "constant.other.description.jsdoc", - "begin": "\\G(<)caption(>)", - "beginCaptures": { - "0": { - "name": "entity.name.tag.inline.jsdoc" - }, - "1": { - "name": "punctuation.definition.bracket.angle.begin.jsdoc" - }, - "2": { - "name": "punctuation.definition.bracket.angle.end.jsdoc" - } - }, - "end": "()|(?=\\*/)", - "endCaptures": { - "0": { - "name": "entity.name.tag.inline.jsdoc" - }, - "1": { - "name": "punctuation.definition.bracket.angle.begin.jsdoc" - }, - "2": { - "name": "punctuation.definition.bracket.angle.end.jsdoc" - } - } - }, - { - "match": "[^\\s@*](?:[^*]|\\*[^/])*", - "captures": { - "0": { - "name": "source.embedded.ts" - } - } - } - ] - }, - { - "match": "(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "constant.language.symbol-type.jsdoc" - } - } - }, - { - "match": "(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.link.underline.jsdoc" - }, - "4": { - "name": "entity.name.type.instance.jsdoc" - } - } - }, - { - "match": "(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.jsdoc" - } - } - }, - { - "match": "(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.jsdoc" - } - } - }, - { - "begin": "((@)typedef)\\s+(?={)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", - "patterns": [ - { - "include": "#jsdoctype" - }, - { - "name": "entity.name.type.instance.jsdoc", - "match": "(?:[^@\\s*/]|\\*[^/])+" - } - ] - }, - { - "begin": "((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", - "patterns": [ - { - "include": "#jsdoctype" - }, - { - "name": "variable.other.jsdoc", - "match": "([A-Za-z_$][\\w$.\\[\\]]*)" - }, - { - "name": "variable.other.jsdoc", - "match": "(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", - "captures": { - "1": { - "name": "punctuation.definition.optional-value.begin.bracket.square.jsdoc" - }, - "2": { - "name": "keyword.operator.assignment.jsdoc" - }, - "3": { - "name": "source.embedded.ts" - }, - "4": { - "name": "punctuation.definition.optional-value.end.bracket.square.jsdoc" - }, - "5": { - "name": "invalid.illegal.syntax.jsdoc" - } - } - } - ] - }, - { - "begin": "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", - "patterns": [ - { - "include": "#jsdoctype" - } - ] - }, - { - "match": "(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "entity.name.type.instance.jsdoc" - } - } - }, - { - "contentName": "variable.other.jsdoc", - "begin": "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.jsdoc" - }, - "4": { - "name": "punctuation.definition.string.begin.jsdoc" - } - }, - "end": "(\\3)|(?=$|\\*/)", - "endCaptures": { - "0": { - "name": "variable.other.jsdoc" - }, - "1": { - "name": "punctuation.definition.string.end.jsdoc" - } - } - }, - { - "match": "((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.jsdoc" - } - } - }, - { - "name": "storage.type.class.jsdoc", - "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", - "captures": { - "1": { - "name": "punctuation.definition.block.tag.jsdoc" - } - } - }, - { - "include": "#inline-tags" - } - ] - }, - "brackets": { - "patterns": [ - { - "begin": "{", - "end": "}|(?=\\*/)", - "patterns": [ - { - "include": "#brackets" - } - ] - }, - { - "begin": "\\[", - "end": "\\]|(?=\\*/)", - "patterns": [ - { - "include": "#brackets" - } - ] - } - ] - }, - "inline-tags": { - "patterns": [ - { - "name": "constant.other.description.jsdoc", - "match": "(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))", - "captures": { - "1": { - "name": "punctuation.definition.bracket.square.begin.jsdoc" - }, - "2": { - "name": "punctuation.definition.bracket.square.end.jsdoc" - } - } - }, - { - "name": "entity.name.type.instance.jsdoc", - "begin": "({)((@)(?:link(?:code|plain)?|tutorial))\\s*", - "beginCaptures": { - "1": { - "name": "punctuation.definition.bracket.curly.begin.jsdoc" - }, - "2": { - "name": "storage.type.class.jsdoc" - }, - "3": { - "name": "punctuation.definition.inline.tag.jsdoc" - } - }, - "end": "}|(?=\\*/)", - "endCaptures": { - "0": { - "name": "punctuation.definition.bracket.curly.end.jsdoc" - } - }, - "patterns": [ - { - "match": "\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?", - "captures": { - "1": { - "name": "variable.other.link.underline.jsdoc" - }, - "2": { - "name": "punctuation.separator.pipe.jsdoc" - } - } - }, - { - "match": "\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?", - "captures": { - "1": { - "name": "variable.other.description.jsdoc" - }, - "2": { - "name": "punctuation.separator.pipe.jsdoc" - } - } - } - ] - } - ] - }, - "jsdoctype": { - "patterns": [ - { - "name": "invalid.illegal.type.jsdoc", - "match": "\\G{(?:[^}*]|\\*[^/}])+$" - }, - { - "contentName": "entity.name.type.instance.jsdoc", - "begin": "\\G({)", - "beginCaptures": { - "0": { - "name": "entity.name.type.instance.jsdoc" - }, - "1": { - "name": "punctuation.definition.bracket.curly.begin.jsdoc" - } - }, - "end": "((}))\\s*|(?=\\*/)", - "endCaptures": { - "1": { - "name": "entity.name.type.instance.jsdoc" - }, - "2": { - "name": "punctuation.definition.bracket.curly.end.jsdoc" - } - }, - "patterns": [ - { - "include": "#brackets" - } - ] - } - ] - } - } -} \ No newline at end of file + "information_for_contributors": [ + "This file has been converted from https://github.com/Microsoft/TypeScript-TmLanguage/blob/master/TypeScript.tmLanguage", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": + "https://github.com/Microsoft/TypeScript-TmLanguage/commit/8361b1a232501c67911c81a4664a9460d7922c6b", + "name": "TypeScript", + "scopeName": "source.ts", + "fileTypes": ["ts"], + "uuid": "ef98eb90-bf9b-11e4-bb52-0800200c9a66", + "patterns": [ + { + "include": "#directives" + }, + { + "include": "#statements" + }, + { + "name": "comment.line.shebang.ts", + "match": "\\A(#!).*(?=$)", + "captures": { + "1": { + "name": "punctuation.definition.comment.ts" + } + } + } + ], + "repository": { + "statements": { + "patterns": [ + { + "include": "#string" + }, + { + "include": "#template" + }, + { + "include": "#comment" + }, + { + "include": "#declaration" + }, + { + "include": "#control-statement" + }, + { + "include": "#after-operator-block-as-object-literal" + }, + { + "include": "#decl-block" + }, + { + "include": "#expression" + }, + { + "include": "#punctuation-semicolon" + } + ] + }, + "declaration": { + "patterns": [ + { + "include": "#decorator" + }, + { + "include": "#var-expr" + }, + { + "include": "#function-declaration" + }, + { + "include": "#class-declaration" + }, + { + "include": "#interface-declaration" + }, + { + "include": "#enum-declaration" + }, + { + "include": "#namespace-declaration" + }, + { + "include": "#type-alias-declaration" + }, + { + "include": "#import-equals-declaration" + }, + { + "include": "#import-declaration" + }, + { + "include": "#export-declaration" + } + ] + }, + "control-statement": { + "patterns": [ + { + "include": "#switch-statement" + }, + { + "include": "#for-loop" + }, + { + "name": "keyword.control.trycatch.ts", + "match": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.ts entity.name.function.ts" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + }, + { + "name": "meta.var-single-variable.expr.ts", + "begin": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.ts variable.other.constant.ts" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + }, + { + "name": "meta.var-single-variable.expr.ts", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.ts variable.other.readwrite.ts" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + } + ] + }, + "var-single-variable-type-annotation": { + "patterns": [ + { + "include": "#type-annotation" + }, + { + "include": "#string" + }, + { + "include": "#comment" + } + ] + }, + "destructuring-variable": { + "patterns": [ + { + "name": "meta.object-binding-pattern-variable.ts", + "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.ts" + }, + "2": { + "name": "keyword.operator.rest.ts" + }, + "3": { + "name": "entity.name.function.ts variable.language.this.ts" + }, + "4": { + "name": "entity.name.function.ts" + }, + "5": { + "name": "keyword.operator.optional.ts" + } + } + }, + { + "match": + "(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + }, + { + "name": "meta.definition.property.ts variable.object.property.ts", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.ts", + "match": "\\?" + } + ] + } + ] + }, + "variable-initializer": { + "patterns": [ + { + "begin": "(?)", + "captures": { + "1": { + "name": "storage.modifier.async.ts" + }, + "2": { + "name": "variable.parameter.ts" + } + } + }, + { + "name": "meta.arrow.ts", + "begin": + "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.ts" + } + }, + "end": + "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.ts", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.ts" + } + }, + "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "patterns": [ + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.ts", + "begin": + "(?:(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "0": { + "name": "meta.object-literal.key.ts" + }, + "1": { + "name": "entity.name.function.ts" + } + } + }, + { + "name": "meta.object.member.ts", + "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", + "captures": { + "0": { + "name": "meta.object-literal.key.ts" + } + } + }, + { + "name": "meta.object.member.ts", + "begin": "\\.\\.\\.", + "beginCaptures": { + "0": { + "name": "keyword.operator.spread.ts" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.ts", + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", + "captures": { + "1": { + "name": "variable.other.readwrite.ts" + } + } + }, + { + "name": "meta.object.member.ts", + "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", + "end": "(?=,|\\}|$)", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.ts", + "begin": ":", + "beginCaptures": { + "0": { + "name": "meta.object-literal.key.ts punctuation.separator.key-value.ts" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "include": "#punctuation-comma" + } + ] + }, + "ternary-expression": { + "begin": "(\\?)", + "beginCaptures": { + "0": { + "name": "keyword.operator.ternary.ts" + } + }, + "end": "(:)", + "endCaptures": { + "0": { + "name": "keyword.operator.ternary.ts" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "function-call": { + "begin": + "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", + "end": + "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", + "patterns": [ + { + "name": "meta.function-call.ts", + "begin": + "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", + "end": + "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", + "patterns": [ + { + "include": "#literal" + }, + { + "include": "#support-objects" + }, + { + "include": "#object-identifiers" + }, + { + "include": "#punctuation-accessor" + }, + { + "name": "keyword.operator.expression.import.ts", + "match": "(?![\\.\\$])\\bimport(?=\\s*[\\(]\\s*[\\\"\\'\\`])" + }, + { + "name": "entity.name.function.ts", + "match": "([_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + { + "include": "#comment" + }, + { + "name": "meta.type.parameters.ts", + "begin": "\\<", + "beginCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.begin.ts" + } + }, + "end": "\\>", + "endCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.end.ts" + } + }, + "patterns": [ + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + { + "include": "#paren-expression" + } + ] + }, + "new-expr": { + "name": "new.expr.ts", + "begin": "(?*?]|[^+]\\+))\\s*(<)(?!)\\s*", + "endCaptures": { + "1": { + "name": "meta.brace.angle.ts" + } + }, + "patterns": [ + { + "include": "#type" + } + ] + }, + { + "name": "cast.expr.ts", + "begin": "(?:(?<=^))\\s*(<)(?=[_$[:alpha:]][_$[:alnum:]]*\\s*>)", + "beginCaptures": { + "1": { + "name": "meta.brace.angle.ts" + } + }, + "end": "(\\>)\\s*", + "endCaptures": { + "1": { + "name": "meta.brace.angle.ts" + } + }, + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "expression-operators": { + "patterns": [ + { + "name": "keyword.control.flow.ts", + "match": "(?>=|>>>=|\\|=" + }, + { + "name": "keyword.operator.bitwise.shift.ts", + "match": "<<|>>>|>>" + }, + { + "name": "keyword.operator.comparison.ts", + "match": "===|!==|==|!=" + }, + { + "name": "keyword.operator.relational.ts", + "match": "<=|>=|<>|<|>" + }, + { + "name": "keyword.operator.logical.ts", + "match": "\\!|&&|\\|\\|" + }, + { + "name": "keyword.operator.bitwise.ts", + "match": "\\&|~|\\^|\\|" + }, + { + "name": "keyword.operator.assignment.ts", + "match": "\\=" + }, + { + "name": "keyword.operator.decrement.ts", + "match": "--" + }, + { + "name": "keyword.operator.increment.ts", + "match": "\\+\\+" + }, + { + "name": "keyword.operator.arithmetic.ts", + "match": "%|\\*|/|-|\\+" + }, + { + "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", + "captures": { + "1": { + "name": "keyword.operator.arithmetic.ts" + } + } + } + ] + }, + "typeof-operator": { + "name": "keyword.operator.expression.typeof.ts", + "match": "(?=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "support.constant.dom.ts" + }, + "3": { + "name": "support.variable.property.dom.ts" + } + } + }, + { + "name": "support.class.node.ts", + "match": + "(?x)(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "entity.name.function.ts" + } + } + }, + { + "match": "(\\.)\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "variable.other.constant.property.ts" + } + } + }, + { + "match": "(\\.)\\s*([_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "variable.other.property.ts" + } + } + }, + { + "name": "variable.other.constant.ts", + "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" + }, + { + "name": "variable.other.readwrite.ts", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "object-identifiers": { + "patterns": [ + { + "name": "support.class.ts", + "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\.\\s*prototype\\b(?!\\$))" + }, + { + "match": + "(?x)(\\.)\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "variable.other.constant.object.property.ts" + }, + "3": { + "name": "variable.other.object.property.ts" + } + } + }, + { + "match": + "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "variable.other.constant.object.ts" + }, + "2": { + "name": "variable.other.object.ts" + } + } + } + ] + }, + "type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.ts", + "begin": "(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.ts" + } + }, + "end": + "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + }, + { + "name": "meta.type.annotation.ts", + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.ts" + } + }, + "end": + "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "return-type": { + "patterns": [ + { + "name": "meta.return.type.ts", + "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.ts" + } + }, + "end": "(?|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "begin": "(?<=[:])(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-parameters": { + "name": "meta.type.parameters.ts", + "begin": "(<)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.begin.ts" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.ts" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.ts", + "match": "(?)" + }, + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "type": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#numeric-literal" + }, + { + "include": "#type-primitive" + }, + { + "include": "#type-builtin-literals" + }, + { + "include": "#type-parameters" + }, + { + "include": "#type-tuple" + }, + { + "include": "#type-object" + }, + { + "include": "#type-operators" + }, + { + "include": "#type-fn-type-parameters" + }, + { + "include": "#type-paren-or-function-parameters" + }, + { + "include": "#type-function-return-type" + }, + { + "include": "#type-name" + } + ] + }, + "type-primitive": { + "name": "support.type.primitive.ts", + "match": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.ts", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.ts" + } + }, + "end": "(?)(?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.ts", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.ts" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.ts" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.ts" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.ts", + "match": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.ts" + } + }, + "end": "(/)([gimuy]*)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.ts" + }, + "2": { + "name": "keyword.other.ts" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "string.regexp.ts", + "begin": + "(?\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.ts" + } + }, + "end": "(?=^)", + "patterns": [ + { + "name": "meta.tag.ts", + "begin": "(<)(reference|amd-dependency|amd-module)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.directive.ts" + }, + "2": { + "name": "entity.name.tag.directive.ts" + } + }, + "end": "/>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.directive.ts" + } + }, + "patterns": [ + { + "name": "entity.other.attribute-name.directive.ts", + "match": "path|types|no-default-lib|name" + }, + { + "name": "keyword.operator.assignment.ts", + "match": "=" + }, + { + "include": "#string" + } + ] + } + ] + }, + "docblock": { + "patterns": [ + { + "match": "(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.access-type.jsdoc" + } + } + }, + { + "match": + "(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "5": { + "name": "constant.other.email.link.underline.jsdoc" + }, + "6": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": + "(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "keyword.operator.control.jsdoc" + }, + "5": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "name": "meta.example.jsdoc", + "begin": "((@)example)\\s+", + "end": "(?=@|\\*/)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "patterns": [ + { + "match": "^\\s\\*\\s+" + }, + { + "contentName": "constant.other.description.jsdoc", + "begin": "\\G(<)caption(>)", + "beginCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + }, + "end": "()|(?=\\*/)", + "endCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "[^\\s@*](?:[^*]|\\*[^/])*", + "captures": { + "0": { + "name": "source.embedded.ts" + } + } + } + ] + }, + { + "match": + "(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.symbol-type.jsdoc" + } + } + }, + { + "match": + "(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.link.underline.jsdoc" + }, + "4": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "match": + "(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "match": + "(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "begin": "((@)typedef)\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "entity.name.type.instance.jsdoc", + "match": "(?:[^@\\s*/]|\\*[^/])+" + } + ] + }, + { + "begin": + "((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "variable.other.jsdoc", + "match": "([A-Za-z_$][\\w$.\\[\\]]*)" + }, + { + "name": "variable.other.jsdoc", + "match": + "(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", + "captures": { + "1": { + "name": + "punctuation.definition.optional-value.begin.bracket.square.jsdoc" + }, + "2": { + "name": "keyword.operator.assignment.jsdoc" + }, + "3": { + "name": "source.embedded.ts" + }, + "4": { + "name": + "punctuation.definition.optional-value.end.bracket.square.jsdoc" + }, + "5": { + "name": "invalid.illegal.syntax.jsdoc" + } + } + } + ] + }, + { + "begin": + "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + } + ] + }, + { + "match": + "(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "contentName": "variable.other.jsdoc", + "begin": "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + }, + "4": { + "name": "punctuation.definition.string.begin.jsdoc" + } + }, + "end": "(\\3)|(?=$|\\*/)", + "endCaptures": { + "0": { + "name": "variable.other.jsdoc" + }, + "1": { + "name": "punctuation.definition.string.end.jsdoc" + } + } + }, + { + "match": + "((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "name": "storage.type.class.jsdoc", + "match": + "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", + "captures": { + "1": { + "name": "punctuation.definition.block.tag.jsdoc" + } + } + }, + { + "include": "#inline-tags" + } + ] + }, + "brackets": { + "patterns": [ + { + "begin": "{", + "end": "}|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + }, + { + "begin": "\\[", + "end": "\\]|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "inline-tags": { + "patterns": [ + { + "name": "constant.other.description.jsdoc", + "match": "(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))", + "captures": { + "1": { + "name": "punctuation.definition.bracket.square.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.square.end.jsdoc" + } + } + }, + { + "name": "entity.name.type.instance.jsdoc", + "begin": "({)((@)(?:link(?:code|plain)?|tutorial))\\s*", + "beginCaptures": { + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + }, + "2": { + "name": "storage.type.class.jsdoc" + }, + "3": { + "name": "punctuation.definition.inline.tag.jsdoc" + } + }, + "end": "}|(?=\\*/)", + "endCaptures": { + "0": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "match": "\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.link.underline.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + }, + { + "match": "\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.description.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + } + ] + } + ] + }, + "jsdoctype": { + "patterns": [ + { + "name": "invalid.illegal.type.jsdoc", + "match": "\\G{(?:[^}*]|\\*[^/}])+$" + }, + { + "contentName": "entity.name.type.instance.jsdoc", + "begin": "\\G({)", + "beginCaptures": { + "0": { + "name": "entity.name.type.instance.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + } + }, + "end": "((}))\\s*|(?=\\*/)", + "endCaptures": { + "1": { + "name": "entity.name.type.instance.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + } + } +} diff --git a/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json b/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json index 477576d481..070db17a17 100644 --- a/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json +++ b/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json @@ -1,4259 +1,4351 @@ { - "information_for_contributors": [ - "This file has been converted from https://github.com/Microsoft/TypeScript-TmLanguage/blob/master/TypeScriptReact.tmLanguage", - "If you want to provide a fix or improvement, please create a pull request against the original repository.", - "Once accepted there, we are happy to receive an update request." - ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/8361b1a232501c67911c81a4664a9460d7922c6b", - "name": "TypeScriptReact", - "scopeName": "source.tsx", - "fileTypes": [ - "tsx" - ], - "uuid": "805375ec-d614-41f5-8993-5843fe63ea82", - "patterns": [ - { - "include": "#directives" - }, - { - "include": "#statements" - }, - { - "name": "comment.line.shebang.ts", - "match": "\\A(#!).*(?=$)", - "captures": { - "1": { - "name": "punctuation.definition.comment.ts" - } - } - } - ], - "repository": { - "statements": { - "patterns": [ - { - "include": "#string" - }, - { - "include": "#template" - }, - { - "include": "#comment" - }, - { - "include": "#declaration" - }, - { - "include": "#control-statement" - }, - { - "include": "#after-operator-block-as-object-literal" - }, - { - "include": "#decl-block" - }, - { - "include": "#expression" - }, - { - "include": "#punctuation-semicolon" - } - ] - }, - "declaration": { - "patterns": [ - { - "include": "#decorator" - }, - { - "include": "#var-expr" - }, - { - "include": "#function-declaration" - }, - { - "include": "#class-declaration" - }, - { - "include": "#interface-declaration" - }, - { - "include": "#enum-declaration" - }, - { - "include": "#namespace-declaration" - }, - { - "include": "#type-alias-declaration" - }, - { - "include": "#import-equals-declaration" - }, - { - "include": "#import-declaration" - }, - { - "include": "#export-declaration" - } - ] - }, - "control-statement": { - "patterns": [ - { - "include": "#switch-statement" - }, - { - "include": "#for-loop" - }, - { - "name": "keyword.control.trycatch.tsx", - "match": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", - "beginCaptures": { - "1": { - "name": "meta.definition.variable.tsx entity.name.function.tsx" - } - }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", - "patterns": [ - { - "include": "#var-single-variable-type-annotation" - } - ] - }, - { - "name": "meta.var-single-variable.expr.tsx", - "begin": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", - "beginCaptures": { - "1": { - "name": "meta.definition.variable.tsx variable.other.constant.tsx" - } - }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", - "patterns": [ - { - "include": "#var-single-variable-type-annotation" - } - ] - }, - { - "name": "meta.var-single-variable.expr.tsx", - "begin": "([_$[:alpha:]][_$[:alnum:]]*)", - "beginCaptures": { - "1": { - "name": "meta.definition.variable.tsx variable.other.readwrite.tsx" - } - }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", - "patterns": [ - { - "include": "#var-single-variable-type-annotation" - } - ] - } - ] - }, - "var-single-variable-type-annotation": { - "patterns": [ - { - "include": "#type-annotation" - }, - { - "include": "#string" - }, - { - "include": "#comment" - } - ] - }, - "destructuring-variable": { - "patterns": [ - { - "name": "meta.object-binding-pattern-variable.tsx", - "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", - "captures": { - "1": { - "name": "storage.modifier.tsx" - }, - "2": { - "name": "keyword.operator.rest.tsx" - }, - "3": { - "name": "entity.name.function.tsx variable.language.this.tsx" - }, - "4": { - "name": "entity.name.function.tsx" - }, - "5": { - "name": "keyword.operator.optional.tsx" - } - } - }, - { - "match": "(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" - }, - { - "name": "meta.definition.property.tsx variable.object.property.tsx", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - }, - { - "name": "keyword.operator.optional.tsx", - "match": "\\?" - } - ] - } - ] - }, - "variable-initializer": { - "patterns": [ - { - "begin": "(?)", - "captures": { - "1": { - "name": "storage.modifier.async.tsx" - }, - "2": { - "name": "variable.parameter.tsx" - } - } - }, - { - "name": "meta.arrow.tsx", - "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", - "beginCaptures": { - "1": { - "name": "storage.modifier.async.tsx" - } - }, - "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#type-parameters" - }, - { - "include": "#function-parameters" - }, - { - "include": "#arrow-return-type" - } - ] - }, - { - "name": "meta.arrow.tsx", - "begin": "=>", - "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.tsx" - } - }, - "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", - "patterns": [ - { - "include": "#decl-block" - }, - { - "include": "#expression" - } - ] - } - ] - }, - "indexer-declaration": { - "name": "meta.indexer.declaration.tsx", - "begin": "(?:(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", - "captures": { - "0": { - "name": "meta.object-literal.key.tsx" - }, - "1": { - "name": "entity.name.function.tsx" - } - } - }, - { - "name": "meta.object.member.tsx", - "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", - "captures": { - "0": { - "name": "meta.object-literal.key.tsx" - } - } - }, - { - "name": "meta.object.member.tsx", - "begin": "\\.\\.\\.", - "beginCaptures": { - "0": { - "name": "keyword.operator.spread.tsx" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "name": "meta.object.member.tsx", - "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", - "captures": { - "1": { - "name": "variable.other.readwrite.tsx" - } - } - }, - { - "name": "meta.object.member.tsx", - "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", - "end": "(?=,|\\}|$)", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "name": "meta.object.member.tsx", - "begin": ":", - "beginCaptures": { - "0": { - "name": "meta.object-literal.key.tsx punctuation.separator.key-value.tsx" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "include": "#punctuation-comma" - } - ] - }, - "ternary-expression": { - "begin": "(\\?)", - "beginCaptures": { - "0": { - "name": "keyword.operator.ternary.tsx" - } - }, - "end": "(:)", - "endCaptures": { - "0": { - "name": "keyword.operator.ternary.tsx" - } - }, - "patterns": [ - { - "include": "#expression" - } - ] - }, - "function-call": { - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", - "patterns": [ - { - "name": "meta.function-call.tsx", - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", - "patterns": [ - { - "include": "#literal" - }, - { - "include": "#support-objects" - }, - { - "include": "#object-identifiers" - }, - { - "include": "#punctuation-accessor" - }, - { - "name": "keyword.operator.expression.import.tsx", - "match": "(?![\\.\\$])\\bimport(?=\\s*[\\(]\\s*[\\\"\\'\\`])" - }, - { - "name": "entity.name.function.tsx", - "match": "([_$[:alpha:]][_$[:alnum:]]*)" - } - ] - }, - { - "include": "#comment" - }, - { - "name": "meta.type.parameters.tsx", - "begin": "\\<", - "beginCaptures": { - "0": { - "name": "punctuation.definition.typeparameters.begin.tsx" - } - }, - "end": "\\>", - "endCaptures": { - "0": { - "name": "punctuation.definition.typeparameters.end.tsx" - } - }, - "patterns": [ - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - { - "include": "#paren-expression" - } - ] - }, - "new-expr": { - "name": "new.expr.tsx", - "begin": "(?>=|>>>=|\\|=" - }, - { - "name": "keyword.operator.bitwise.shift.tsx", - "match": "<<|>>>|>>" - }, - { - "name": "keyword.operator.comparison.tsx", - "match": "===|!==|==|!=" - }, - { - "name": "keyword.operator.relational.tsx", - "match": "<=|>=|<>|<|>" - }, - { - "name": "keyword.operator.logical.tsx", - "match": "\\!|&&|\\|\\|" - }, - { - "name": "keyword.operator.bitwise.tsx", - "match": "\\&|~|\\^|\\|" - }, - { - "name": "keyword.operator.assignment.tsx", - "match": "\\=" - }, - { - "name": "keyword.operator.decrement.tsx", - "match": "--" - }, - { - "name": "keyword.operator.increment.tsx", - "match": "\\+\\+" - }, - { - "name": "keyword.operator.arithmetic.tsx", - "match": "%|\\*|/|-|\\+" - }, - { - "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", - "captures": { - "1": { - "name": "keyword.operator.arithmetic.tsx" - } - } - } - ] - }, - "typeof-operator": { - "name": "keyword.operator.expression.typeof.tsx", - "match": "(?=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "captures": { - "1": { - "name": "punctuation.accessor.tsx" - }, - "2": { - "name": "support.constant.dom.tsx" - }, - "3": { - "name": "support.variable.property.dom.tsx" - } - } - }, - { - "name": "support.class.node.tsx", - "match": "(?x)(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", - "captures": { - "1": { - "name": "punctuation.accessor.tsx" - }, - "2": { - "name": "entity.name.function.tsx" - } - } - }, - { - "match": "(\\.)\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", - "captures": { - "1": { - "name": "punctuation.accessor.tsx" - }, - "2": { - "name": "variable.other.constant.property.tsx" - } - } - }, - { - "match": "(\\.)\\s*([_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "punctuation.accessor.tsx" - }, - "2": { - "name": "variable.other.property.tsx" - } - } - }, - { - "name": "variable.other.constant.tsx", - "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" - }, - { - "name": "variable.other.readwrite.tsx", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - } - ] - }, - "object-identifiers": { - "patterns": [ - { - "name": "support.class.tsx", - "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\.\\s*prototype\\b(?!\\$))" - }, - { - "match": "(?x)(\\.)\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "punctuation.accessor.tsx" - }, - "2": { - "name": "variable.other.constant.object.property.tsx" - }, - "3": { - "name": "variable.other.object.property.tsx" - } - } - }, - { - "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "variable.other.constant.object.tsx" - }, - "2": { - "name": "variable.other.object.tsx" - } - } - } - ] - }, - "type-annotation": { - "patterns": [ - { - "name": "meta.type.annotation.tsx", - "begin": "(:)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.tsx" - } - }, - "end": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - }, - { - "name": "meta.type.annotation.tsx", - "begin": "(:)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.tsx" - } - }, - "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - } - ] - }, - "return-type": { - "patterns": [ - { - "name": "meta.return.type.tsx", - "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.tsx" - } - }, - "end": "(?|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", - "patterns": [ - { - "begin": "(?<=[:])(?=\\s*\\{)", - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "include": "#type-predicate-operator" - }, - { - "include": "#type" - } - ] - }, - "type-parameters": { - "name": "meta.type.parameters.tsx", - "begin": "(<)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.begin.tsx" - } - }, - "end": "(>)", - "endCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.end.tsx" - } - }, - "patterns": [ - { - "include": "#comment" - }, - { - "name": "storage.modifier.tsx", - "match": "(?)" - }, - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - "type": { - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#string" - }, - { - "include": "#numeric-literal" - }, - { - "include": "#type-primitive" - }, - { - "include": "#type-builtin-literals" - }, - { - "include": "#type-parameters" - }, - { - "include": "#type-tuple" - }, - { - "include": "#type-object" - }, - { - "include": "#type-operators" - }, - { - "include": "#type-fn-type-parameters" - }, - { - "include": "#type-paren-or-function-parameters" - }, - { - "include": "#type-function-return-type" - }, - { - "include": "#type-name" - } - ] - }, - "type-primitive": { - "name": "support.type.primitive.tsx", - "match": "(?)\n ))\n )\n )\n)", - "end": "(?<=\\))", - "patterns": [ - { - "include": "#function-parameters" - } - ] - } - ] - }, - "type-function-return-type": { - "patterns": [ - { - "name": "meta.type.function.return.tsx", - "begin": "(=>)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "storage.type.function.arrow.tsx" - } - }, - "end": "(?)(?]|//|$)", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - }, - { - "name": "meta.type.function.return.tsx", - "begin": "=>", - "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.tsx" - } - }, - "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - } - ] - }, - "type-function-return-type-core": { - "patterns": [ - { - "include": "#comment" - }, - { - "begin": "(?<==>)(?=\\s*\\{)", - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "include": "#type-predicate-operator" - }, - { - "include": "#type" - } - ] - }, - "type-operators": { - "patterns": [ - { - "include": "#typeof-operator" - }, - { - "begin": "([&|])(?=\\s*\\{)", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.tsx" - } - }, - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "begin": "[&|]", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.tsx" - } - }, - "end": "(?=\\S)" - }, - { - "name": "keyword.operator.expression.keyof.tsx", - "match": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", - "beginCaptures": { - "1": { - "name": "punctuation.definition.string.begin.tsx" - } - }, - "end": "(/)([gimuy]*)", - "endCaptures": { - "1": { - "name": "punctuation.definition.string.end.tsx" - }, - "2": { - "name": "keyword.other.tsx" - } - }, - "patterns": [ - { - "include": "#regexp" - } - ] - }, - { - "name": "string.regexp.tsx", - "begin": "(?\\s*$)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.comment.tsx" - } - }, - "end": "(?=^)", - "patterns": [ - { - "name": "meta.tag.tsx", - "begin": "(<)(reference|amd-dependency|amd-module)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.tag.directive.tsx" - }, - "2": { - "name": "entity.name.tag.directive.tsx" - } - }, - "end": "/>", - "endCaptures": { - "0": { - "name": "punctuation.definition.tag.directive.tsx" - } - }, - "patterns": [ - { - "name": "entity.other.attribute-name.directive.tsx", - "match": "path|types|no-default-lib|name" - }, - { - "name": "keyword.operator.assignment.tsx", - "match": "=" - }, - { - "include": "#string" - } - ] - } - ] - }, - "docblock": { - "patterns": [ - { - "match": "(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "constant.language.access-type.jsdoc" - } - } - }, - { - "match": "(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "entity.name.type.instance.jsdoc" - }, - "4": { - "name": "punctuation.definition.bracket.angle.begin.jsdoc" - }, - "5": { - "name": "constant.other.email.link.underline.jsdoc" - }, - "6": { - "name": "punctuation.definition.bracket.angle.end.jsdoc" - } - } - }, - { - "match": "(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "entity.name.type.instance.jsdoc" - }, - "4": { - "name": "keyword.operator.control.jsdoc" - }, - "5": { - "name": "entity.name.type.instance.jsdoc" - } - } - }, - { - "name": "meta.example.jsdoc", - "begin": "((@)example)\\s+", - "end": "(?=@|\\*/)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "patterns": [ - { - "match": "^\\s\\*\\s+" - }, - { - "contentName": "constant.other.description.jsdoc", - "begin": "\\G(<)caption(>)", - "beginCaptures": { - "0": { - "name": "entity.name.tag.inline.jsdoc" - }, - "1": { - "name": "punctuation.definition.bracket.angle.begin.jsdoc" - }, - "2": { - "name": "punctuation.definition.bracket.angle.end.jsdoc" - } - }, - "end": "()|(?=\\*/)", - "endCaptures": { - "0": { - "name": "entity.name.tag.inline.jsdoc" - }, - "1": { - "name": "punctuation.definition.bracket.angle.begin.jsdoc" - }, - "2": { - "name": "punctuation.definition.bracket.angle.end.jsdoc" - } - } - }, - { - "match": "[^\\s@*](?:[^*]|\\*[^/])*", - "captures": { - "0": { - "name": "source.embedded.tsx" - } - } - } - ] - }, - { - "match": "(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "constant.language.symbol-type.jsdoc" - } - } - }, - { - "match": "(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.link.underline.jsdoc" - }, - "4": { - "name": "entity.name.type.instance.jsdoc" - } - } - }, - { - "match": "(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.jsdoc" - } - } - }, - { - "match": "(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.jsdoc" - } - } - }, - { - "begin": "((@)typedef)\\s+(?={)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", - "patterns": [ - { - "include": "#jsdoctype" - }, - { - "name": "entity.name.type.instance.jsdoc", - "match": "(?:[^@\\s*/]|\\*[^/])+" - } - ] - }, - { - "begin": "((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", - "patterns": [ - { - "include": "#jsdoctype" - }, - { - "name": "variable.other.jsdoc", - "match": "([A-Za-z_$][\\w$.\\[\\]]*)" - }, - { - "name": "variable.other.jsdoc", - "match": "(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", - "captures": { - "1": { - "name": "punctuation.definition.optional-value.begin.bracket.square.jsdoc" - }, - "2": { - "name": "keyword.operator.assignment.jsdoc" - }, - "3": { - "name": "source.embedded.tsx" - }, - "4": { - "name": "punctuation.definition.optional-value.end.bracket.square.jsdoc" - }, - "5": { - "name": "invalid.illegal.syntax.jsdoc" - } - } - } - ] - }, - { - "begin": "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - } - }, - "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", - "patterns": [ - { - "include": "#jsdoctype" - } - ] - }, - { - "match": "(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "entity.name.type.instance.jsdoc" - } - } - }, - { - "contentName": "variable.other.jsdoc", - "begin": "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", - "beginCaptures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.jsdoc" - }, - "4": { - "name": "punctuation.definition.string.begin.jsdoc" - } - }, - "end": "(\\3)|(?=$|\\*/)", - "endCaptures": { - "0": { - "name": "variable.other.jsdoc" - }, - "1": { - "name": "punctuation.definition.string.end.jsdoc" - } - } - }, - { - "match": "((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)", - "captures": { - "1": { - "name": "storage.type.class.jsdoc" - }, - "2": { - "name": "punctuation.definition.block.tag.jsdoc" - }, - "3": { - "name": "variable.other.jsdoc" - } - } - }, - { - "name": "storage.type.class.jsdoc", - "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", - "captures": { - "1": { - "name": "punctuation.definition.block.tag.jsdoc" - } - } - }, - { - "include": "#inline-tags" - } - ] - }, - "brackets": { - "patterns": [ - { - "begin": "{", - "end": "}|(?=\\*/)", - "patterns": [ - { - "include": "#brackets" - } - ] - }, - { - "begin": "\\[", - "end": "\\]|(?=\\*/)", - "patterns": [ - { - "include": "#brackets" - } - ] - } - ] - }, - "inline-tags": { - "patterns": [ - { - "name": "constant.other.description.jsdoc", - "match": "(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))", - "captures": { - "1": { - "name": "punctuation.definition.bracket.square.begin.jsdoc" - }, - "2": { - "name": "punctuation.definition.bracket.square.end.jsdoc" - } - } - }, - { - "name": "entity.name.type.instance.jsdoc", - "begin": "({)((@)(?:link(?:code|plain)?|tutorial))\\s*", - "beginCaptures": { - "1": { - "name": "punctuation.definition.bracket.curly.begin.jsdoc" - }, - "2": { - "name": "storage.type.class.jsdoc" - }, - "3": { - "name": "punctuation.definition.inline.tag.jsdoc" - } - }, - "end": "}|(?=\\*/)", - "endCaptures": { - "0": { - "name": "punctuation.definition.bracket.curly.end.jsdoc" - } - }, - "patterns": [ - { - "match": "\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?", - "captures": { - "1": { - "name": "variable.other.link.underline.jsdoc" - }, - "2": { - "name": "punctuation.separator.pipe.jsdoc" - } - } - }, - { - "match": "\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?", - "captures": { - "1": { - "name": "variable.other.description.jsdoc" - }, - "2": { - "name": "punctuation.separator.pipe.jsdoc" - } - } - } - ] - } - ] - }, - "jsdoctype": { - "patterns": [ - { - "name": "invalid.illegal.type.jsdoc", - "match": "\\G{(?:[^}*]|\\*[^/}])+$" - }, - { - "contentName": "entity.name.type.instance.jsdoc", - "begin": "\\G({)", - "beginCaptures": { - "0": { - "name": "entity.name.type.instance.jsdoc" - }, - "1": { - "name": "punctuation.definition.bracket.curly.begin.jsdoc" - } - }, - "end": "((}))\\s*|(?=\\*/)", - "endCaptures": { - "1": { - "name": "entity.name.type.instance.jsdoc" - }, - "2": { - "name": "punctuation.definition.bracket.curly.end.jsdoc" - } - }, - "patterns": [ - { - "include": "#brackets" - } - ] - } - ] - }, - "jsx": { - "patterns": [ - { - "include": "#jsx-tag-without-attributes-in-expression" - }, - { - "include": "#jsx-tag-in-expression" - } - ] - }, - "jsx-tag-without-attributes-in-expression": { - "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", - "end": "(?!\\s*(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", - "patterns": [ - { - "include": "#jsx-tag-without-attributes" - } - ] - }, - "jsx-tag-without-attributes": { - "name": "meta.tag.without-attributes.tsx", - "begin": "(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?)", - "end": "()", - "beginCaptures": { - "1": { - "name": "punctuation.definition.tag.begin.tsx" - }, - "2": { - "name": "entity.name.tag.tsx" - }, - "3": { - "name": "support.class.component.tsx" - }, - "4": { - "name": "punctuation.definition.tag.end.tsx" - } - }, - "endCaptures": { - "1": { - "name": "punctuation.definition.tag.begin.tsx" - }, - "2": { - "name": "entity.name.tag.tsx" - }, - "3": { - "name": "support.class.component.tsx" - }, - "4": { - "name": "punctuation.definition.tag.end.tsx" - } - }, - "contentName": "meta.jsx.children.tsx", - "patterns": [ - { - "include": "#jsx-children" - } - ] - }, - "jsx-tag-in-expression": { - "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", - "end": "(/>)|(?:())", - "endCaptures": { - "0": { - "name": "meta.tag.tsx" - }, - "1": { - "name": "punctuation.definition.tag.end.tsx" - }, - "2": { - "name": "punctuation.definition.tag.begin.tsx" - }, - "3": { - "name": "entity.name.tag.tsx" - }, - "4": { - "name": "support.class.component.tsx" - }, - "5": { - "name": "punctuation.definition.tag.end.tsx" - } - }, - "patterns": [ - { - "include": "#jsx-tag" - } - ] - }, - "jsx-child-tag": { - "begin": "(?x)\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", - "end": "(/>)|(?:())", - "endCaptures": { - "0": { - "name": "meta.tag.tsx" - }, - "1": { - "name": "punctuation.definition.tag.end.tsx" - }, - "2": { - "name": "punctuation.definition.tag.begin.tsx" - }, - "3": { - "name": "entity.name.tag.tsx" - }, - "4": { - "name": "support.class.component.tsx" - }, - "5": { - "name": "punctuation.definition.tag.end.tsx" - } - }, - "patterns": [ - { - "include": "#jsx-tag" - } - ] - }, - "jsx-tag": { - "name": "meta.tag.tsx", - "begin": "(?x)\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", - "end": "(?=(/>)|(?:()))", - "patterns": [ - { - "begin": "(?x)\n (<)\\s*\n ((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.tag.begin.tsx" - }, - "2": { - "name": "entity.name.tag.tsx" - }, - "3": { - "name": "support.class.component.tsx" - } - }, - "end": "(?=[/]?>)", - "contentName": "meta.tag.attributes.tsx", - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#jsx-tag-attributes" - }, - { - "include": "#jsx-tag-attributes-illegal" - } - ] - }, - { - "begin": "(>)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.tag.end.tsx" - } - }, - "end": "(?=|/\\*|//)", - "captures": { - "1": { - "name": "entity.other.attribute-name.tsx" - } - } - }, - "jsx-tag-attribute-assignment": { - "name": "keyword.operator.assignment.tsx", - "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" - }, - "jsx-string-double-quoted": { - "name": "string.quoted.double.tsx", - "begin": "\"", - "end": "\"", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.tsx" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.tsx" - } - }, - "patterns": [ - { - "include": "#jsx-entities" - } - ] - }, - "jsx-string-single-quoted": { - "name": "string.quoted.single.tsx", - "begin": "'", - "end": "'", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.tsx" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.tsx" - } - }, - "patterns": [ - { - "include": "#jsx-entities" - } - ] - }, - "jsx-tag-attributes-illegal": { - "name": "invalid.illegal.attribute.tsx", - "match": "\\S+" - } - } -} \ No newline at end of file + "information_for_contributors": [ + "This file has been converted from https://github.com/Microsoft/TypeScript-TmLanguage/blob/master/TypeScriptReact.tmLanguage", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": + "https://github.com/Microsoft/TypeScript-TmLanguage/commit/8361b1a232501c67911c81a4664a9460d7922c6b", + "name": "TypeScriptReact", + "scopeName": "source.tsx", + "fileTypes": ["tsx"], + "uuid": "805375ec-d614-41f5-8993-5843fe63ea82", + "patterns": [ + { + "include": "#directives" + }, + { + "include": "#statements" + }, + { + "name": "comment.line.shebang.ts", + "match": "\\A(#!).*(?=$)", + "captures": { + "1": { + "name": "punctuation.definition.comment.ts" + } + } + } + ], + "repository": { + "statements": { + "patterns": [ + { + "include": "#string" + }, + { + "include": "#template" + }, + { + "include": "#comment" + }, + { + "include": "#declaration" + }, + { + "include": "#control-statement" + }, + { + "include": "#after-operator-block-as-object-literal" + }, + { + "include": "#decl-block" + }, + { + "include": "#expression" + }, + { + "include": "#punctuation-semicolon" + } + ] + }, + "declaration": { + "patterns": [ + { + "include": "#decorator" + }, + { + "include": "#var-expr" + }, + { + "include": "#function-declaration" + }, + { + "include": "#class-declaration" + }, + { + "include": "#interface-declaration" + }, + { + "include": "#enum-declaration" + }, + { + "include": "#namespace-declaration" + }, + { + "include": "#type-alias-declaration" + }, + { + "include": "#import-equals-declaration" + }, + { + "include": "#import-declaration" + }, + { + "include": "#export-declaration" + } + ] + }, + "control-statement": { + "patterns": [ + { + "include": "#switch-statement" + }, + { + "include": "#for-loop" + }, + { + "name": "keyword.control.trycatch.tsx", + "match": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.tsx entity.name.function.tsx" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + }, + { + "name": "meta.var-single-variable.expr.tsx", + "begin": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.tsx variable.other.constant.tsx" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + }, + { + "name": "meta.var-single-variable.expr.tsx", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.tsx variable.other.readwrite.tsx" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + } + ] + }, + "var-single-variable-type-annotation": { + "patterns": [ + { + "include": "#type-annotation" + }, + { + "include": "#string" + }, + { + "include": "#comment" + } + ] + }, + "destructuring-variable": { + "patterns": [ + { + "name": "meta.object-binding-pattern-variable.tsx", + "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.tsx" + }, + "2": { + "name": "keyword.operator.rest.tsx" + }, + "3": { + "name": "entity.name.function.tsx variable.language.this.tsx" + }, + "4": { + "name": "entity.name.function.tsx" + }, + "5": { + "name": "keyword.operator.optional.tsx" + } + } + }, + { + "match": + "(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + }, + { + "name": "meta.definition.property.tsx variable.object.property.tsx", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.tsx", + "match": "\\?" + } + ] + } + ] + }, + "variable-initializer": { + "patterns": [ + { + "begin": "(?)", + "captures": { + "1": { + "name": "storage.modifier.async.tsx" + }, + "2": { + "name": "variable.parameter.tsx" + } + } + }, + { + "name": "meta.arrow.tsx", + "begin": + "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.tsx" + } + }, + "end": + "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.tsx", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.tsx" + } + }, + "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "patterns": [ + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.tsx", + "begin": + "(?:(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "0": { + "name": "meta.object-literal.key.tsx" + }, + "1": { + "name": "entity.name.function.tsx" + } + } + }, + { + "name": "meta.object.member.tsx", + "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", + "captures": { + "0": { + "name": "meta.object-literal.key.tsx" + } + } + }, + { + "name": "meta.object.member.tsx", + "begin": "\\.\\.\\.", + "beginCaptures": { + "0": { + "name": "keyword.operator.spread.tsx" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.tsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", + "captures": { + "1": { + "name": "variable.other.readwrite.tsx" + } + } + }, + { + "name": "meta.object.member.tsx", + "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", + "end": "(?=,|\\}|$)", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.tsx", + "begin": ":", + "beginCaptures": { + "0": { + "name": + "meta.object-literal.key.tsx punctuation.separator.key-value.tsx" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "include": "#punctuation-comma" + } + ] + }, + "ternary-expression": { + "begin": "(\\?)", + "beginCaptures": { + "0": { + "name": "keyword.operator.ternary.tsx" + } + }, + "end": "(:)", + "endCaptures": { + "0": { + "name": "keyword.operator.ternary.tsx" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "function-call": { + "begin": + "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", + "end": + "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", + "patterns": [ + { + "name": "meta.function-call.tsx", + "begin": + "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", + "end": + "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`]([^<>]|\\<\\s*[_$[:alpha:]\\{\\(\\[\\\"\\'\\`][^<>]+\\>)+>\\s*)?\\()", + "patterns": [ + { + "include": "#literal" + }, + { + "include": "#support-objects" + }, + { + "include": "#object-identifiers" + }, + { + "include": "#punctuation-accessor" + }, + { + "name": "keyword.operator.expression.import.tsx", + "match": "(?![\\.\\$])\\bimport(?=\\s*[\\(]\\s*[\\\"\\'\\`])" + }, + { + "name": "entity.name.function.tsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + { + "include": "#comment" + }, + { + "name": "meta.type.parameters.tsx", + "begin": "\\<", + "beginCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.begin.tsx" + } + }, + "end": "\\>", + "endCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.end.tsx" + } + }, + "patterns": [ + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + { + "include": "#paren-expression" + } + ] + }, + "new-expr": { + "name": "new.expr.tsx", + "begin": "(?>=|>>>=|\\|=" + }, + { + "name": "keyword.operator.bitwise.shift.tsx", + "match": "<<|>>>|>>" + }, + { + "name": "keyword.operator.comparison.tsx", + "match": "===|!==|==|!=" + }, + { + "name": "keyword.operator.relational.tsx", + "match": "<=|>=|<>|<|>" + }, + { + "name": "keyword.operator.logical.tsx", + "match": "\\!|&&|\\|\\|" + }, + { + "name": "keyword.operator.bitwise.tsx", + "match": "\\&|~|\\^|\\|" + }, + { + "name": "keyword.operator.assignment.tsx", + "match": "\\=" + }, + { + "name": "keyword.operator.decrement.tsx", + "match": "--" + }, + { + "name": "keyword.operator.increment.tsx", + "match": "\\+\\+" + }, + { + "name": "keyword.operator.arithmetic.tsx", + "match": "%|\\*|/|-|\\+" + }, + { + "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", + "captures": { + "1": { + "name": "keyword.operator.arithmetic.tsx" + } + } + } + ] + }, + "typeof-operator": { + "name": "keyword.operator.expression.typeof.tsx", + "match": "(?=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "captures": { + "1": { + "name": "punctuation.accessor.tsx" + }, + "2": { + "name": "support.constant.dom.tsx" + }, + "3": { + "name": "support.variable.property.dom.tsx" + } + } + }, + { + "name": "support.class.node.tsx", + "match": + "(?x)(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "captures": { + "1": { + "name": "punctuation.accessor.tsx" + }, + "2": { + "name": "entity.name.function.tsx" + } + } + }, + { + "match": "(\\.)\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "captures": { + "1": { + "name": "punctuation.accessor.tsx" + }, + "2": { + "name": "variable.other.constant.property.tsx" + } + } + }, + { + "match": "(\\.)\\s*([_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.tsx" + }, + "2": { + "name": "variable.other.property.tsx" + } + } + }, + { + "name": "variable.other.constant.tsx", + "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" + }, + { + "name": "variable.other.readwrite.tsx", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "object-identifiers": { + "patterns": [ + { + "name": "support.class.tsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\.\\s*prototype\\b(?!\\$))" + }, + { + "match": + "(?x)(\\.)\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.tsx" + }, + "2": { + "name": "variable.other.constant.object.property.tsx" + }, + "3": { + "name": "variable.other.object.property.tsx" + } + } + }, + { + "match": + "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "variable.other.constant.object.tsx" + }, + "2": { + "name": "variable.other.object.tsx" + } + } + } + ] + }, + "type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.tsx", + "begin": "(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.tsx" + } + }, + "end": + "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + }, + { + "name": "meta.type.annotation.tsx", + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.tsx" + } + }, + "end": + "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "return-type": { + "patterns": [ + { + "name": "meta.return.type.tsx", + "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.tsx" + } + }, + "end": "(?|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "begin": "(?<=[:])(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-parameters": { + "name": "meta.type.parameters.tsx", + "begin": "(<)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.begin.tsx" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.tsx" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.tsx", + "match": "(?)" + }, + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "type": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#numeric-literal" + }, + { + "include": "#type-primitive" + }, + { + "include": "#type-builtin-literals" + }, + { + "include": "#type-parameters" + }, + { + "include": "#type-tuple" + }, + { + "include": "#type-object" + }, + { + "include": "#type-operators" + }, + { + "include": "#type-fn-type-parameters" + }, + { + "include": "#type-paren-or-function-parameters" + }, + { + "include": "#type-function-return-type" + }, + { + "include": "#type-name" + } + ] + }, + "type-primitive": { + "name": "support.type.primitive.tsx", + "match": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.tsx", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.tsx" + } + }, + "end": "(?)(?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.tsx", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.tsx" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.tsx" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.tsx" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.tsx", + "match": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.tsx" + } + }, + "end": "(/)([gimuy]*)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.tsx" + }, + "2": { + "name": "keyword.other.tsx" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "string.regexp.tsx", + "begin": + "(?\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.tsx" + } + }, + "end": "(?=^)", + "patterns": [ + { + "name": "meta.tag.tsx", + "begin": "(<)(reference|amd-dependency|amd-module)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.directive.tsx" + }, + "2": { + "name": "entity.name.tag.directive.tsx" + } + }, + "end": "/>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.directive.tsx" + } + }, + "patterns": [ + { + "name": "entity.other.attribute-name.directive.tsx", + "match": "path|types|no-default-lib|name" + }, + { + "name": "keyword.operator.assignment.tsx", + "match": "=" + }, + { + "include": "#string" + } + ] + } + ] + }, + "docblock": { + "patterns": [ + { + "match": "(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.access-type.jsdoc" + } + } + }, + { + "match": + "(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "5": { + "name": "constant.other.email.link.underline.jsdoc" + }, + "6": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": + "(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "keyword.operator.control.jsdoc" + }, + "5": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "name": "meta.example.jsdoc", + "begin": "((@)example)\\s+", + "end": "(?=@|\\*/)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "patterns": [ + { + "match": "^\\s\\*\\s+" + }, + { + "contentName": "constant.other.description.jsdoc", + "begin": "\\G(<)caption(>)", + "beginCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + }, + "end": "()|(?=\\*/)", + "endCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "[^\\s@*](?:[^*]|\\*[^/])*", + "captures": { + "0": { + "name": "source.embedded.tsx" + } + } + } + ] + }, + { + "match": + "(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.symbol-type.jsdoc" + } + } + }, + { + "match": + "(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.link.underline.jsdoc" + }, + "4": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "match": + "(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "match": + "(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "begin": "((@)typedef)\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "entity.name.type.instance.jsdoc", + "match": "(?:[^@\\s*/]|\\*[^/])+" + } + ] + }, + { + "begin": + "((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "variable.other.jsdoc", + "match": "([A-Za-z_$][\\w$.\\[\\]]*)" + }, + { + "name": "variable.other.jsdoc", + "match": + "(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", + "captures": { + "1": { + "name": + "punctuation.definition.optional-value.begin.bracket.square.jsdoc" + }, + "2": { + "name": "keyword.operator.assignment.jsdoc" + }, + "3": { + "name": "source.embedded.tsx" + }, + "4": { + "name": + "punctuation.definition.optional-value.end.bracket.square.jsdoc" + }, + "5": { + "name": "invalid.illegal.syntax.jsdoc" + } + } + } + ] + }, + { + "begin": + "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + } + ] + }, + { + "match": + "(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "contentName": "variable.other.jsdoc", + "begin": "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + }, + "4": { + "name": "punctuation.definition.string.begin.jsdoc" + } + }, + "end": "(\\3)|(?=$|\\*/)", + "endCaptures": { + "0": { + "name": "variable.other.jsdoc" + }, + "1": { + "name": "punctuation.definition.string.end.jsdoc" + } + } + }, + { + "match": + "((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "name": "storage.type.class.jsdoc", + "match": + "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", + "captures": { + "1": { + "name": "punctuation.definition.block.tag.jsdoc" + } + } + }, + { + "include": "#inline-tags" + } + ] + }, + "brackets": { + "patterns": [ + { + "begin": "{", + "end": "}|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + }, + { + "begin": "\\[", + "end": "\\]|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "inline-tags": { + "patterns": [ + { + "name": "constant.other.description.jsdoc", + "match": "(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))", + "captures": { + "1": { + "name": "punctuation.definition.bracket.square.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.square.end.jsdoc" + } + } + }, + { + "name": "entity.name.type.instance.jsdoc", + "begin": "({)((@)(?:link(?:code|plain)?|tutorial))\\s*", + "beginCaptures": { + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + }, + "2": { + "name": "storage.type.class.jsdoc" + }, + "3": { + "name": "punctuation.definition.inline.tag.jsdoc" + } + }, + "end": "}|(?=\\*/)", + "endCaptures": { + "0": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "match": "\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.link.underline.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + }, + { + "match": "\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.description.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + } + ] + } + ] + }, + "jsdoctype": { + "patterns": [ + { + "name": "invalid.illegal.type.jsdoc", + "match": "\\G{(?:[^}*]|\\*[^/}])+$" + }, + { + "contentName": "entity.name.type.instance.jsdoc", + "begin": "\\G({)", + "beginCaptures": { + "0": { + "name": "entity.name.type.instance.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + } + }, + "end": "((}))\\s*|(?=\\*/)", + "endCaptures": { + "1": { + "name": "entity.name.type.instance.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "jsx": { + "patterns": [ + { + "include": "#jsx-tag-without-attributes-in-expression" + }, + { + "include": "#jsx-tag-in-expression" + } + ] + }, + "jsx-tag-without-attributes-in-expression": { + "begin": + "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", + "end": "(?!\\s*(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", + "patterns": [ + { + "include": "#jsx-tag-without-attributes" + } + ] + }, + "jsx-tag-without-attributes": { + "name": "meta.tag.without-attributes.tsx", + "begin": "(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?)", + "end": "()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.tsx" + }, + "2": { + "name": "entity.name.tag.tsx" + }, + "3": { + "name": "support.class.component.tsx" + }, + "4": { + "name": "punctuation.definition.tag.end.tsx" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.tsx" + }, + "2": { + "name": "entity.name.tag.tsx" + }, + "3": { + "name": "support.class.component.tsx" + }, + "4": { + "name": "punctuation.definition.tag.end.tsx" + } + }, + "contentName": "meta.jsx.children.tsx", + "patterns": [ + { + "include": "#jsx-children" + } + ] + }, + "jsx-tag-in-expression": { + "begin": + "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "end": "(/>)|(?:())", + "endCaptures": { + "0": { + "name": "meta.tag.tsx" + }, + "1": { + "name": "punctuation.definition.tag.end.tsx" + }, + "2": { + "name": "punctuation.definition.tag.begin.tsx" + }, + "3": { + "name": "entity.name.tag.tsx" + }, + "4": { + "name": "support.class.component.tsx" + }, + "5": { + "name": "punctuation.definition.tag.end.tsx" + } + }, + "patterns": [ + { + "include": "#jsx-tag" + } + ] + }, + "jsx-child-tag": { + "begin": + "(?x)\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "end": "(/>)|(?:())", + "endCaptures": { + "0": { + "name": "meta.tag.tsx" + }, + "1": { + "name": "punctuation.definition.tag.end.tsx" + }, + "2": { + "name": "punctuation.definition.tag.begin.tsx" + }, + "3": { + "name": "entity.name.tag.tsx" + }, + "4": { + "name": "support.class.component.tsx" + }, + "5": { + "name": "punctuation.definition.tag.end.tsx" + } + }, + "patterns": [ + { + "include": "#jsx-tag" + } + ] + }, + "jsx-tag": { + "name": "meta.tag.tsx", + "begin": + "(?x)\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "end": "(?=(/>)|(?:()))", + "patterns": [ + { + "begin": + "(?x)\n (<)\\s*\n ((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.tsx" + }, + "2": { + "name": "entity.name.tag.tsx" + }, + "3": { + "name": "support.class.component.tsx" + } + }, + "end": "(?=[/]?>)", + "contentName": "meta.tag.attributes.tsx", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#jsx-tag-attributes" + }, + { + "include": "#jsx-tag-attributes-illegal" + } + ] + }, + { + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.tsx" + } + }, + "end": "(?=|/\\*|//)", + "captures": { + "1": { + "name": "entity.other.attribute-name.tsx" + } + } + }, + "jsx-tag-attribute-assignment": { + "name": "keyword.operator.assignment.tsx", + "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" + }, + "jsx-string-double-quoted": { + "name": "string.quoted.double.tsx", + "begin": "\"", + "end": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.tsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.tsx" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-string-single-quoted": { + "name": "string.quoted.single.tsx", + "begin": "'", + "end": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.tsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.tsx" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-tag-attributes-illegal": { + "name": "invalid.illegal.attribute.tsx", + "match": "\\S+" + } + } +} diff --git a/main/tsconfig.json b/main/tsconfig.json index fb45702dc9..09cf836dad 100644 --- a/main/tsconfig.json +++ b/main/tsconfig.json @@ -5,10 +5,7 @@ "experimentalDecorators": true, "forceConsistentCasingInFileNames": true, "jsx": "react", - "lib": [ - "dom", - "es2017" - ], + "lib": ["dom", "es2017"], "module": "commonjs", "moduleResolution": "node", "newLine": "LF", @@ -27,10 +24,6 @@ "target": "es2015", "sourceMap": true }, - "include": [ - "src/**/*.ts" - ], - "exclude": [ - "node_modules" - ] + "include": ["src/**/*.ts"], + "exclude": ["node_modules"] } diff --git a/test/ci/AutoCompletionTest.json b/test/ci/AutoCompletionTest.json deleted file mode 100644 index bab7302f39..0000000000 --- a/test/ci/AutoCompletionTest.json +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Test scripts for QuickOpen - */ - -import * as assert from "assert" -import * as os from "os" -import * as path from "path" - -const getCompletionElement = () => { - - const elements = document.body.getElementsByClassName("autocompletion") - - if (!elements || !elements.length) { - return null - } else { - return elements[0] - } -} - -export const test = async (oni: any) => { - const dir = os.tmpdir() - const testFileName = `testFile-${new Date().getTime()}.ts` - const tempFilePath = path.join(dir, testFileName) - oni.automation.sendKeys(":e " + tempFilePath) - oni.automation.sendKeys("") - await oni.automation.sleep(500) - oni.automation.sendKeys("i") - oni.automation.sendKeys("window.a") - - // Wait for completion popup to show - await oni.automation.waitFor(() => getCompletionElement() !== null) - - // Check for 'alert' as an available completion - const completionElement = getCompletionElement() - const textContent = completionElement.textContent - - assert.ok(textContent.indexOf("alert") >= 0, "Verify 'alert' was presented as a completion") -} diff --git a/test/tsconfig.json b/test/tsconfig.json index 26ee38bd0c..8d989b5fb3 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -8,18 +8,9 @@ "allowJs": true, "outDir": "../lib_test", "jsx": "react", - "lib": [ - "dom", - "es2017" - ], + "lib": ["dom", "es2017"], "skipLibCheck": true }, - "include": [ - "**/*.tsx", - "**/*.ts", - "**/*.js" - ], - "exclude": [ - "node_modules" - ] + "include": ["**/*.tsx", "**/*.ts", "**/*.js"], + "exclude": ["node_modules"] } diff --git a/vim/core/oni-core-statusbar/package.json b/vim/core/oni-core-statusbar/package.json index ad7323d11f..1eb076a2aa 100644 --- a/vim/core/oni-core-statusbar/package.json +++ b/vim/core/oni-core-statusbar/package.json @@ -5,13 +5,10 @@ "engines": { "oni": "^0.2.3" }, - "scripts": { - }, + "scripts": {}, "oni": { "supportedFileTypes": ["*"] }, - "dependencies": { - }, - "devDependencies": { - } + "dependencies": {}, + "devDependencies": {} } diff --git a/vim/core/oni-plugin-buffers/package.json b/vim/core/oni-plugin-buffers/package.json index 54cd08271a..16937086b3 100644 --- a/vim/core/oni-plugin-buffers/package.json +++ b/vim/core/oni-plugin-buffers/package.json @@ -5,13 +5,10 @@ "engines": { "oni": "^0.2.6" }, - "scripts": { - }, + "scripts": {}, "oni": { "supportedFileTypes": ["*"] }, - "dependencies": { - }, - "devDependencies": { - } + "dependencies": {}, + "devDependencies": {} } diff --git a/vim/core/oni-plugin-git/package.json b/vim/core/oni-plugin-git/package.json index b4b25d799c..c614e67741 100644 --- a/vim/core/oni-plugin-git/package.json +++ b/vim/core/oni-plugin-git/package.json @@ -5,13 +5,10 @@ "engines": { "oni": "^0.2.6" }, - "scripts": { - }, + "scripts": {}, "oni": { "supportedFileTypes": ["*"] }, - "dependencies": { - }, - "devDependencies": { - } + "dependencies": {}, + "devDependencies": {} } diff --git a/vim/core/oni-plugin-typescript/package.json b/vim/core/oni-plugin-typescript/package.json index 347095df6c..0a24181e83 100644 --- a/vim/core/oni-plugin-typescript/package.json +++ b/vim/core/oni-plugin-typescript/package.json @@ -10,10 +10,7 @@ "test": "npm install && tsc -p tsconfig.test.json && mocha --recursive ./lib_test/test" }, "oni": { - "supportedFileTypes": [ - "javascript", - "typescript" - ] + "supportedFileTypes": ["javascript", "typescript"] }, "dependencies": {}, "devDependencies": { diff --git a/vim/core/oni-plugin-typescript/tsconfig.json b/vim/core/oni-plugin-typescript/tsconfig.json index 73e33f18bb..331f5d78e3 100644 --- a/vim/core/oni-plugin-typescript/tsconfig.json +++ b/vim/core/oni-plugin-typescript/tsconfig.json @@ -7,12 +7,6 @@ "sourceMap": true, "target": "ES5" }, - "include": [ - "src/**/*.ts" - ], - "exclude": [ - "node_modules", - "typings/browser.d.ts", - "typings/browser" - ] + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "typings/browser.d.ts", "typings/browser"] } diff --git a/vim/core/oni-plugin-typescript/tsconfig.test.json b/vim/core/oni-plugin-typescript/tsconfig.test.json index e7ba5da546..1eab6047f2 100644 --- a/vim/core/oni-plugin-typescript/tsconfig.test.json +++ b/vim/core/oni-plugin-typescript/tsconfig.test.json @@ -7,13 +7,6 @@ "sourceMap": true, "target": "ES5" }, - "include": [ - "test/**/*.ts", - "src/**/*.ts" - ], - "exclude": [ - "node_modules", - "typings/browser.d.ts", - "typings/browser" - ] + "include": ["test/**/*.ts", "src/**/*.ts"], + "exclude": ["node_modules", "typings/browser.d.ts", "typings/browser"] } From fdb93e413c6daef431c0449a817d3ce15211081d Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 30 Jan 2018 09:02:06 -0800 Subject: [PATCH 004/103] Use 'nord' colorscheme by default (#1389) --- browser/src/Services/Configuration/DefaultConfiguration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index a1163f3492..11caeb510d 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -275,7 +275,7 @@ const BaseConfiguration: IConfigurationValues = { "tabs.wrap": false, "ui.animations.enabled": true, - "ui.colorscheme": "onedark", + "ui.colorscheme": "nord", "ui.iconTheme": "theme-icons-seti", "ui.fontFamily": "BlinkMacSystemFont, 'Lucida Grande', 'Segoe UI', Ubuntu, Cantarell, sans-serif", From e8d4ee25d7c19103aa5288ba9aba7a0fd41e596e Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 30 Jan 2018 09:06:26 -0800 Subject: [PATCH 005/103] Enable sidebar by default (#1392) --- browser/src/Services/Configuration/DefaultConfiguration.ts | 3 +-- browser/src/Services/Configuration/IConfigurationValues.ts | 3 +-- browser/src/Services/Sidebar/index.ts | 5 +---- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index 11caeb510d..63266b6748 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -55,8 +55,6 @@ const BaseConfiguration: IConfigurationValues = { "editor.maxLinesForLanguageServices": 2500, - "experimental.sidebar.enabled": false, - "autoClosingPairs.enabled": true, "autoClosingPairs.default": [ { open: "{", close: "}" }, @@ -253,6 +251,7 @@ const BaseConfiguration: IConfigurationValues = { "recorder.copyScreenshotToClipboard": false, "recorder.outputPath": os.tmpdir(), + "sidebar.enabled": true, "sidebar.width": "50px", "statusbar.enabled": true, diff --git a/browser/src/Services/Configuration/IConfigurationValues.ts b/browser/src/Services/Configuration/IConfigurationValues.ts index 02d7a28891..91b5f56a94 100644 --- a/browser/src/Services/Configuration/IConfigurationValues.ts +++ b/browser/src/Services/Configuration/IConfigurationValues.ts @@ -41,8 +41,6 @@ export interface IConfigurationValues { // - textMateHighlighting "experimental.editor.textMateHighlighting.enabled": boolean - "experimental.sidebar.enabled": boolean - // The transport to use for Neovim // Valid values are "stdio" and "pipe" "experimental.neovim.transport": string @@ -200,6 +198,7 @@ export interface IConfigurationValues { // of saving to file "recorder.copyScreenshotToClipboard": boolean + "sidebar.enabled": boolean "sidebar.width": string "statusbar.enabled": boolean diff --git a/browser/src/Services/Sidebar/index.ts b/browser/src/Services/Sidebar/index.ts index 20855e08d6..40599a769a 100644 --- a/browser/src/Services/Sidebar/index.ts +++ b/browser/src/Services/Sidebar/index.ts @@ -16,16 +16,13 @@ let _sidebarManager: SidebarManager = null export const activate = (configuration: Configuration, workspace: Workspace) => { _sidebarManager = new SidebarManager() - if (configuration.getValue("experimental.sidebar.enabled")) { + if (configuration.getValue("sidebar.enabled")) { const leftDock = windowManager.getDock("left") leftDock.addSplit(new SidebarSplit(_sidebarManager)) leftDock.addSplit(new SidebarContentSplit(_sidebarManager)) _sidebarManager.add("files-o", new ExplorerSplit(workspace, commandManager, editorManager)) - const tasksPane = new SidebarPane("oni.sidebar.tasks", "Tasks") - _sidebarManager.add("cogs", tasksPane) - const bookmarksPane = new SidebarPane("oni.sidebar.bookmarks", "Bookmarks") _sidebarManager.add("bookmark", bookmarksPane) From a5b4ab3fc12baba008cf6e58ab6cd15391cbcf5f Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 30 Jan 2018 09:52:55 -0800 Subject: [PATCH 006/103] Fix workspace open regressions (#1393) --- browser/src/Services/Workspace/WorkspaceCommands.ts | 1 - main/src/menu.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/browser/src/Services/Workspace/WorkspaceCommands.ts b/browser/src/Services/Workspace/WorkspaceCommands.ts index 16c636ef02..c0afd65e28 100644 --- a/browser/src/Services/Workspace/WorkspaceCommands.ts +++ b/browser/src/Services/Workspace/WorkspaceCommands.ts @@ -97,7 +97,6 @@ export const activateCommands = ( "Workspace: Open Folder", "Set a folder as the working directory for Oni", () => openFolder(), - () => !!!workspace.activeWorkspace, ), new CallbackCommand( "workspace.openTestFile", diff --git a/main/src/menu.ts b/main/src/menu.ts index 76bafe0358..46141e0a27 100644 --- a/main/src/menu.ts +++ b/main/src/menu.ts @@ -170,7 +170,7 @@ export const buildMenu = (mainWindow, loadInit) => { { label: "Open Folder…", click(item, focusedWindow) { - executeOniCommand(focusedWindow, "oni.openFolder") + executeOniCommand(focusedWindow, "workspace.openFolder") }, }, reopenWithEncoding, From 4fe51a30226a1d4f4fdc2715926b05a39b5dfd86 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 30 Jan 2018 12:33:10 -0800 Subject: [PATCH 007/103] Revert nord's mode colors, in favor of the previous colors (#1399) --- extensions/theme-nord/colors/nord.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/theme-nord/colors/nord.json b/extensions/theme-nord/colors/nord.json index 5b8698398c..807adfb5d3 100644 --- a/extensions/theme-nord/colors/nord.json +++ b/extensions/theme-nord/colors/nord.json @@ -35,16 +35,16 @@ "statusBar.background": "#282828", "statusBar.foreground": "#c8c8c8", - "highlight.mode.insert.background": "#A3BE8C", + "highlight.mode.insert.background": "#98c379", "highlight.mode.insert.foreground": "#282c34", - "highlight.mode.normal.background": "#5E81AC", + "highlight.mode.normal.background": "#61afef", "highlight.mode.normal.foreground": "#282c34", - "highlight.mode.operator.background": "#EBCB8B", + "highlight.mode.operator.background": "#d19a66", "highlight.mode.operator.foreground": "#282c34", - "highlight.mode.visual.background": "#B48EAD", + "highlight.mode.visual.background": "#56b6c2", "highlight.mode.visual.foreground": "#282c34" } } From 011fb4cb97316df510c5c75f32b381c8991cdb81 Mon Sep 17 00:00:00 2001 From: Akin Date: Tue, 30 Jan 2018 22:02:13 +0000 Subject: [PATCH 008/103] add margin right to icons (#1400) --- browser/src/Services/Explorer/Explorer.less | 1 + 1 file changed, 1 insertion(+) diff --git a/browser/src/Services/Explorer/Explorer.less b/browser/src/Services/Explorer/Explorer.less index c379979fec..bc4531a5c3 100644 --- a/browser/src/Services/Explorer/Explorer.less +++ b/browser/src/Services/Explorer/Explorer.less @@ -32,6 +32,7 @@ flex: 0 0 auto; width: 20px; text-align: center; + margin-right: 7px; } .name { From d14e2f80441e264a5e3ded2eb2ccdbed113fedab Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 30 Jan 2018 16:31:09 -0800 Subject: [PATCH 009/103] [WIP] Fix #98 - Create basic notification UX (#1358) Fix #98 - Create basic notification UX --- browser/src/Plugins/Api/Oni.ts | 5 + .../Services/Notifications/Notification.ts | 64 +++++++ .../Notifications/NotificationStore.ts | 86 ++++++++++ .../Services/Notifications/Notifications.ts | 37 ++++ .../Notifications/NotificationsView.tsx | 162 ++++++++++++++++++ browser/src/Services/Notifications/index.ts | 17 ++ browser/src/index.tsx | 4 + .../Notifications/NotificationStoreTests.ts | 60 +++++++ browser/test/TestHelpers.ts | 4 + 9 files changed, 439 insertions(+) create mode 100644 browser/src/Services/Notifications/Notification.ts create mode 100644 browser/src/Services/Notifications/NotificationStore.ts create mode 100644 browser/src/Services/Notifications/Notifications.ts create mode 100644 browser/src/Services/Notifications/NotificationsView.tsx create mode 100644 browser/src/Services/Notifications/index.ts create mode 100644 browser/test/Services/Notifications/NotificationStoreTests.ts diff --git a/browser/src/Plugins/Api/Oni.ts b/browser/src/Plugins/Api/Oni.ts index 5eef50a3f2..e548551fb8 100644 --- a/browser/src/Plugins/Api/Oni.ts +++ b/browser/src/Plugins/Api/Oni.ts @@ -24,6 +24,7 @@ import { editorManager } from "./../../Services/EditorManager" import { inputManager } from "./../../Services/InputManager" import * as LanguageManager from "./../../Services/Language" import { getInstance as getMenuManagerInstance } from "./../../Services/Menu" +import { getInstance as getNotificationsInstance } from "./../../Services/Notifications" import { getInstance as getOverlayInstance } from "./../../Services/Overlay" import { recorder } from "./../../Services/Recorder" import { getInstance as getSidebarInstance } from "./../../Services/Sidebar" @@ -113,6 +114,10 @@ export class Oni extends EventEmitter implements OniApi.Plugin.Api { return getMenuManagerInstance() } + public get notifications(): any { + return getNotificationsInstance() + } + public get overlays(): any /* TODO */ { return getOverlayInstance() } diff --git a/browser/src/Services/Notifications/Notification.ts b/browser/src/Services/Notifications/Notification.ts new file mode 100644 index 0000000000..d67967a6d3 --- /dev/null +++ b/browser/src/Services/Notifications/Notification.ts @@ -0,0 +1,64 @@ +/** + * Notification.ts + * + * API interface for notification UX + */ + +import { Store } from "redux" + +import { Event, IEvent } from "oni-types" + +import { INotificationsState, NotificationLevel } from "./NotificationStore" + +export class Notification { + private _title: string = "" + private _detail: string = "" + private _level: NotificationLevel = "info" + + private _onClickEvent = new Event() + private _onCloseEvent = new Event() + + public get onClick(): IEvent { + return this._onClickEvent + } + + public get onClose(): IEvent { + return this._onCloseEvent + } + + constructor(private _id: string, private _store: Store) {} + + public setContents(title: string, detail: string): void { + this._title = title + this._detail = detail + } + + public setLevel(level: NotificationLevel): void { + this._level = level + } + + public show(): void { + this._store.dispatch({ + type: "SHOW_NOTIFICATION", + id: this._id, + title: this._title, + detail: this._detail, + level: this._level, + onClick: () => { + this._onClickEvent.dispatch() + this.hide() + }, + onClose: () => { + this._onCloseEvent.dispatch() + this.hide() + }, + }) + } + + public hide(): void { + this._store.dispatch({ + type: "HIDE_NOTIFICATION", + id: this._id, + }) + } +} diff --git a/browser/src/Services/Notifications/NotificationStore.ts b/browser/src/Services/Notifications/NotificationStore.ts new file mode 100644 index 0000000000..b715862676 --- /dev/null +++ b/browser/src/Services/Notifications/NotificationStore.ts @@ -0,0 +1,86 @@ +/** + * NotificationStore.ts + * + * State management for Notifications + */ + +import { Reducer, Store } from "redux" +import { createStore as createReduxStore } from "./../../Redux" + +export type NotificationLevel = "info" | "warn" | "error" + +export interface IdToNotification { + [key: string]: INotification +} + +export interface INotificationsState { + notifications: IdToNotification +} + +export const DefaultNotificationState: INotificationsState = { + notifications: {}, +} + +export interface INotification { + id: string + level: NotificationLevel + title: string + detail: string + onClick: () => void + onClose: () => void +} + +export type NotificationAction = + | { + type: "SHOW_NOTIFICATION" + id: string + level: NotificationLevel + title: string + detail: string + onClick: () => void + onClose: () => void + } + | { + type: "HIDE_NOTIFICATION" + id: string + } + +export const notificationsReducer: Reducer = ( + state: IdToNotification = {}, + action: NotificationAction, +) => { + switch (action.type) { + case "SHOW_NOTIFICATION": + return { + ...state, + [action.id]: { + id: action.id, + level: action.level, + title: action.title, + detail: action.detail, + onClick: action.onClick, + onClose: action.onClose, + }, + } + case "HIDE_NOTIFICATION": + return { + ...state, + [action.id]: null, + } + default: + return state + } +} + +export const stateReducer: Reducer = ( + state: INotificationsState = DefaultNotificationState, + action: NotificationAction, +) => { + return { + notifications: notificationsReducer(state.notifications, action), + } +} + +export const createStore = (): Store => { + return createReduxStore("Notifications", stateReducer, DefaultNotificationState) +} diff --git a/browser/src/Services/Notifications/Notifications.ts b/browser/src/Services/Notifications/Notifications.ts new file mode 100644 index 0000000000..1fa2e3355a --- /dev/null +++ b/browser/src/Services/Notifications/Notifications.ts @@ -0,0 +1,37 @@ +/** + * Notifications.ts + * + * API interface and lifecycle manager for notifications UX + */ + +import { Store } from "redux" + +import { Overlay, OverlayManager } from "./../Overlay" + +import { Notification } from "./Notification" +import { createStore, INotificationsState } from "./NotificationStore" + +import { getView } from "./NotificationsView" + +export class Notifications { + + private _id: number = 0 + private _overlay: Overlay + private _store: Store + + constructor( + private _overlayManager: OverlayManager, + ) { + this._store = createStore() + + this._overlay = this._overlayManager.createItem() + this._overlay.setContents(getView(this._store)) + this._overlay.show() + } + + public createItem(): Notification { + this._id++ + + return new Notification("notification" + this._id.toString(), this._store) + } +} diff --git a/browser/src/Services/Notifications/NotificationsView.tsx b/browser/src/Services/Notifications/NotificationsView.tsx new file mode 100644 index 0000000000..d75e3c147b --- /dev/null +++ b/browser/src/Services/Notifications/NotificationsView.tsx @@ -0,0 +1,162 @@ +/** + * NotificationsView.tsx + * + * View / React layer for Notifications + */ + +import * as React from "react" + +import { connect, Provider } from "react-redux" + +import styled, { keyframes } from "styled-components" + +import { CSSTransition, TransitionGroup } from "react-transition-group" + +import { INotification, INotificationsState } from "./NotificationStore" + +import { Icon, IconSize } from "./../../UI/Icon" + +export interface NotificationsViewProps { + notifications: INotification[] +} + +const Transition = (props: { children: any }) => { + return ( + + {props.children} + + ) +} + +const NotificationsWrapper = styled.div` + position: absolute; + top: 16px; + right: 16px; +` + +export class NotificationsView extends React.PureComponent { + public render(): JSX.Element { + return ( + + + {this.props.notifications.map(notification => { + return ( + + + + ) + })} + + + ) + } +} + +const frames = keyframes` + 0% { opacity: 0; transform: translateY(4px); } + 100% { opacity: 1; transform: translateY(0px); } +` + +const NotificationWrapper = styled.div` + background-color: red; + color: white; + width: 20em; + height: 4em; + + margin: 1em; + + display: flex; + flex-direction: row; + + justify-content: center; + align-items: center; + + pointer-events: auto; + cursor: pointer; + + overflow: hidden; + + &.notification-enter { + animation: ${frames} 0.25s ease-in; + } + + &.notification-exit { + animation: ${frames} 0.25s ease-in both reverse; + } + + &:hover { + transform: translateY(-1px); + } +` + +const NotificationIconWrapper = styled.div` + flex: 0 0 auto; + + margin: 8px; +` + +const NotificationContents = styled.div` + flex: 1 1 auto; + + display: flex; + flex-direction: column; + justify-content: center; + + overflow-y: auto; + overflow-x: hidden; + height: 100%; +` + +const NotificationTitle = styled.div` + flex: 0 0 auto; + + font-weight: bold; + font-size: 1.1em; +` + +const NotificationDescription = styled.div` + flex: 1 1 auto; + overflow-y: auto; + overflow-x: none; + + font-size: 0.9em; +` + +// export interface NotificationViewProps extends INotification { } + +export class NotificationView extends React.PureComponent { + public render(): JSX.Element { + return ( + + + + + + {this.props.title} + {this.props.detail} + + this.props.onClose}> + + + + ) + } +} + +export const mapStateToProps = (state: INotificationsState): NotificationsViewProps => { + const objs = Object.keys(state.notifications).map(key => state.notifications[key]) + + const activeNotifications = objs.filter(o => o !== null) + + return { + notifications: activeNotifications, + } +} + +const NotificationsContainer = connect(mapStateToProps)(NotificationsView) + +export const getView = (store: any) => ( + + + +) diff --git a/browser/src/Services/Notifications/index.ts b/browser/src/Services/Notifications/index.ts new file mode 100644 index 0000000000..84eae14482 --- /dev/null +++ b/browser/src/Services/Notifications/index.ts @@ -0,0 +1,17 @@ +/** + * index.ts + */ + +import { OverlayManager } from "./../Overlay" + +import { Notifications } from "./Notifications" + +let _notifications: Notifications = null + +export const activate = (overlayManager: OverlayManager): void => { + _notifications = new Notifications(overlayManager) +} + +export const getInstance = (): Notifications => { + return _notifications +} diff --git a/browser/src/index.tsx b/browser/src/index.tsx index b53f9765e8..fd49657370 100644 --- a/browser/src/index.tsx +++ b/browser/src/index.tsx @@ -40,6 +40,7 @@ const start = async (args: string[]): Promise => { const globalCommandsPromise = import("./Services/Commands/GlobalCommands") const inputManagerPromise = import("./Services/InputManager") const languageManagerPromise = import("./Services/Language") + const notificationsPromise = import("./Services/Notifications") const snippetPromise = import("./Services/Snippets") const taksPromise = import("./Services/Tasks") const workspacePromise = import("./Services/Workspace") @@ -124,6 +125,9 @@ const start = async (args: string[]): Promise => { Menu.activate(overlayManager) const menuManager = Menu.getInstance() + const Notifications = await notificationsPromise + Notifications.activate(overlayManager) + const Tasks = await taksPromise Tasks.activate(menuManager) const tasks = Tasks.getInstance() diff --git a/browser/test/Services/Notifications/NotificationStoreTests.ts b/browser/test/Services/Notifications/NotificationStoreTests.ts new file mode 100644 index 0000000000..02c01fb185 --- /dev/null +++ b/browser/test/Services/Notifications/NotificationStoreTests.ts @@ -0,0 +1,60 @@ +import * as assert from "assert" + +import { createStore } from "./../../../src/Services/Notifications/NotificationStore" + +describe("NotificationStore", () => { + it("'SHOW_NOTIFICATION' adds a notification store", () => { + const store = createStore() + + // tslint:disable-next-line + const testFunc = () => {} + + store.dispatch({ + type: "SHOW_NOTIFICATION", + id: "test_notification", + title: "title-test", + detail: "detail-test", + level: "info", + onClick: testFunc, + onClose: testFunc, + }) + + const state = store.getState() + + assert.deepEqual(state.notifications, { + ["test_notification"]: { + id: "test_notification", + title: "title-test", + detail: "detail-test", + level: "info", + onClick: testFunc, + onClose: testFunc, + }, + }) + }) + + it("'HIDE_NOTIFICATION' removes a notification from the store", () => { + const store = createStore() + + store.dispatch({ + type: "SHOW_NOTIFICATION", + id: "test_notification", + title: "title-test", + detail: "detail-test", + level: "info", + }) + + store.dispatch({ + type: "HIDE_NOTIFICATION", + id: "test_notification", + }) + + const state = store.getState() + + assert.deepEqual( + state.notifications, + { test_notification: null }, + "Validate notification was removed", + ) + }) +}) diff --git a/browser/test/TestHelpers.ts b/browser/test/TestHelpers.ts index 71b0c77e10..f75e9bd863 100644 --- a/browser/test/TestHelpers.ts +++ b/browser/test/TestHelpers.ts @@ -11,6 +11,10 @@ export const runAllTimers = (): void => { global["clock"].runAll() // tslint:disable-line } +export const tick = (timeInMilliseconds: number): void => { + global["clock"].tick(timeInMilliseconds) // tslint:disable-line +} + /** * Wait for pending promise calls - needed for any code paths that have an asynchronous timer or use `Promise.resolve` */ From 4c0588822a1f7b0781546442b7499f13a4a515ca Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 30 Jan 2018 16:56:28 -0800 Subject: [PATCH 010/103] Automation: Inline configuration settings, instead of needing to specify an external file (#1401) * Use embedded config * Handle case where there are no settings * Fix generation of configuration file --- test/ci/Editor.ExternalCommandLine.config.js | 7 ---- test/ci/Editor.ExternalCommandLineTest.ts | 4 ++- test/common/runInProcTest.ts | 37 ++++++++++++++++++-- 3 files changed, 37 insertions(+), 11 deletions(-) delete mode 100644 test/ci/Editor.ExternalCommandLine.config.js diff --git a/test/ci/Editor.ExternalCommandLine.config.js b/test/ci/Editor.ExternalCommandLine.config.js deleted file mode 100644 index 8896ee0801..0000000000 --- a/test/ci/Editor.ExternalCommandLine.config.js +++ /dev/null @@ -1,7 +0,0 @@ -// For more information on customizing Oni, -// check out our wiki page: -// https://github.com/onivim/oni/wiki/Configuration - -module.exports = { - "experimental.commandline.mode": true, -}; diff --git a/test/ci/Editor.ExternalCommandLineTest.ts b/test/ci/Editor.ExternalCommandLineTest.ts index 0196ad77bc..f31e6c96a9 100644 --- a/test/ci/Editor.ExternalCommandLineTest.ts +++ b/test/ci/Editor.ExternalCommandLineTest.ts @@ -19,5 +19,7 @@ export const test = async (oni: Oni.Plugin.Api) => { // Bring in custom config to turn off animations, in order to reduce noise. export const settings = { - configPath: "Editor.ExternalCommandLine.config.js", + config: { + "experimental.commandline.mode": true, + }, } diff --git a/test/common/runInProcTest.ts b/test/common/runInProcTest.ts index 553d651df4..c2aaaa6d73 100644 --- a/test/common/runInProcTest.ts +++ b/test/common/runInProcTest.ts @@ -23,14 +23,45 @@ const loadTest = (rootPath: string, testName: string): ITestCase => { const normalizedMeta: ITestCase = { name: testDescription.name || testName, testPath: normalizePath(testPath), - configPath: testDescription.configPath - ? normalizePath(path.join(rootPath, testDescription.configPath)) - : "", + configPath: getConfigPath(testMeta.settings, rootPath), } return normalizedMeta } +import * as os from "os" + +const getConfigPath = (settings: any, rootPath: string) => { + if (!settings) { + return "" + } else if (settings.configPath) { + return normalizePath(path.join(rootPath, settings.configPath)) + } else if (settings.config) { + return normalizePath(serializeConfig(settings.config)) + } else { + return "" + } +} + +// Helper method to write a config to a temporary folder +// Returns the path to the serialized config +const serializeConfig = (configValues: { [key: string]: any }): string => { + const stringifiedConfig = Object.keys(configValues).map( + key => `"${key}": ${configValues[key]},`, + ) + + const outputConfig = `module.exports = {${stringifiedConfig.join(os.EOL)}}` + + const folder = os.tmpdir() + const fileName = "config_" + new Date().getTime().toString() + ".js" + + const fullFilepath = path.join(folder, fileName) + console.log("Writing config to: " + fullFilepath) + console.log("Config contents: " + outputConfig) + fs.writeFileSync(fullFilepath, outputConfig) + return fullFilepath +} + const startTime = new Date().getTime() const logWithTimeStamp = (message: string) => { From c2a2244c61d07df4d3fabe52428b00d712731429 Mon Sep 17 00:00:00 2001 From: Akin Date: Wed, 31 Jan 2018 00:59:24 +0000 Subject: [PATCH 011/103] upgrade ocaml lsp and fix diagnostic typo (#1404) --- .../src/Services/Configuration/ReasonConfiguration.ts | 4 ++-- package.json | 2 +- yarn.lock | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/browser/src/Services/Configuration/ReasonConfiguration.ts b/browser/src/Services/Configuration/ReasonConfiguration.ts index 6f28ff149f..034ebe50c8 100644 --- a/browser/src/Services/Configuration/ReasonConfiguration.ts +++ b/browser/src/Services/Configuration/ReasonConfiguration.ts @@ -32,8 +32,8 @@ export const ocamlAndReasonConfiguration = { debounce: { linter: 500, }, - diagnostic: { - tools: ["merlin"], + diagnostics: { + tools: ["bsb", "merlin"], }, path: { bsb: wrapCommand("bsb"), diff --git a/package.json b/package.json index 0394986a38..cbdda6a98f 100644 --- a/package.json +++ b/package.json @@ -205,7 +205,7 @@ "marked": "^0.3.6", "minimist": "1.2.0", "msgpack-lite": "0.1.26", - "ocaml-language-server": "1.0.12", + "ocaml-language-server": "^1.0.21", "oni-api": "^0.0.26", "oni-neovim-binaries": "0.1.0", "oni-ripgrep": "0.0.3", diff --git a/yarn.lock b/yarn.lock index e62b492d7d..a41ef71025 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4450,9 +4450,9 @@ obuf@^1.0.0, obuf@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.1.tgz#104124b6c602c6796881a042541d36db43a5264e" -ocaml-language-server@1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/ocaml-language-server/-/ocaml-language-server-1.0.12.tgz#5af38c8f6355b7074006586627472122ac24fd2e" +ocaml-language-server@^1.0.21: + version "1.0.21" + resolved "https://registry.yarnpkg.com/ocaml-language-server/-/ocaml-language-server-1.0.21.tgz#baa4d732395910d942f696d35e10983efc43e6e8" dependencies: async "2.6.0" glob "7.1.2" @@ -4462,7 +4462,7 @@ ocaml-language-server@1.0.12: vscode-jsonrpc "3.5.0" vscode-languageclient "3.5.0" vscode-languageserver "3.5.0" - vscode-languageserver-types "3.5.0" + vscode-languageserver-protocol "3.5.0" vscode-uri "1.0.1" on-finished@~2.3.0: @@ -6746,7 +6746,7 @@ vscode-languageclient@3.5.0: dependencies: vscode-languageserver-protocol "^3.5.0" -vscode-languageserver-protocol@^3.5.0: +vscode-languageserver-protocol@3.5.0, vscode-languageserver-protocol@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0.tgz#067c5cbe27709795398d119692c97ebba1452209" dependencies: From 262098fefd7e82bb69b0b9b68ff66ba6af3d18d8 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 30 Jan 2018 18:09:49 -0800 Subject: [PATCH 012/103] Input: Reverse lookup API (#1365) * Add 'getBoundKeys' method and unit tests * Show bound keys in command palette * Add keyparser info * Merge master * Get parsing tests green * Fix missed semicolon * Revert suppressing the file open behavior * Clean up typescript package file * Fix lint issue * Add KeyBindingInfo * Improve look and feel of reverse bindings * Restore pinned icon in quick open * Fix lint issues --- .../NeovimEditor/WelcomeBufferLayer.tsx | 16 +++- browser/src/Input/KeyParser.ts | 86 +++++++++++++++++++ browser/src/Services/InputManager.ts | 21 +++++ browser/src/Services/Menu/MenuComponent.tsx | 8 +- browser/src/Services/Menu/MenuFilter.ts | 9 +- .../Services/Notifications/Notifications.ts | 5 +- .../src/Services/QuickOpen/PinnedIconView.tsx | 18 ++++ browser/src/Services/QuickOpen/QuickOpen.ts | 6 +- browser/src/Services/Tasks.ts | 4 +- browser/src/UI/components/KeyBindingInfo.tsx | 70 +++++++++++++++ browser/test/Input/InputManagerTests.ts | 27 ++++++ browser/test/Input/KeyParserTests.ts | 34 ++++++++ .../WindowManager/LinearSplitProviderTests.ts | 5 +- 13 files changed, 286 insertions(+), 23 deletions(-) create mode 100644 browser/src/Input/KeyParser.ts create mode 100644 browser/src/Services/QuickOpen/PinnedIconView.tsx create mode 100644 browser/src/UI/components/KeyBindingInfo.tsx create mode 100644 browser/test/Input/KeyParserTests.ts diff --git a/browser/src/Editor/NeovimEditor/WelcomeBufferLayer.tsx b/browser/src/Editor/NeovimEditor/WelcomeBufferLayer.tsx index d86327d613..3acdf95124 100644 --- a/browser/src/Editor/NeovimEditor/WelcomeBufferLayer.tsx +++ b/browser/src/Editor/NeovimEditor/WelcomeBufferLayer.tsx @@ -8,6 +8,8 @@ import * as React from "react" import styled, { keyframes } from "styled-components" +import { inputManager, InputManager } from "./../../Services/InputManager" + import * as Oni from "oni-api" import { withProps } from "./../../UI/components/common" @@ -167,20 +169,24 @@ export class WelcomeBufferLayer implements Oni.EditorLayer { className="enable-mouse" style={{ animation: `${entranceFull} 0.25s ease-in 0.1s forwards` }} > - + ) } } +export interface WelcomeViewProps { + inputManager: InputManager +} + export interface WelcomeViewState { version: string } import { getMetadata } from "./../../Services/Metadata" -export class WelcomeView extends React.PureComponent<{}, WelcomeViewState> { - constructor(props: any) { +export class WelcomeView extends React.PureComponent { + constructor(props: WelcomeViewProps) { super(props) this.state = { @@ -282,7 +288,9 @@ export class WelcomeView extends React.PureComponent<{}, WelcomeViewState> { /> { + const chord: IKey[] = [] + + let idx = 0 + + while (idx < keys.length) { + if (keys[idx] !== "<") { + chord.push(parseKey(keys[idx])) + } else { + const endIndex = getNextCharacter(keys, idx + 1) + // Malformed if there isn't a corresponding '>' + if (endIndex === -1) { + return { chord } + } + + const keyContents = keys.substring(idx + 1, endIndex) + chord.push(parseKey(keyContents)) + idx = endIndex + 1 + } + + idx++ + } + + return { + chord, + } +} + +const getNextCharacter = (str: string, startIndex: number): number => { + let i = startIndex + while (i < str.length) { + if (str[i] === ">") { + return i + } + i++ + } + + return -1 +} + +export const parseKey = (key: string): IKey => { + if (key.indexOf("-") === -1) { + return { + character: key, + shift: false, + alt: false, + control: false, + meta: false, + } + } + + const hasControl = key.indexOf("c-") >= 0 || key.indexOf("C-") >= 0 + const hasShift = key.indexOf("s-") >= 0 || key.indexOf("S-") >= 0 + const hasAlt = key.indexOf("a-") >= 0 || key.indexOf("A-") >= 0 + const hasMeta = key.indexOf("m-") >= 0 || key.indexOf("M-") >= 0 + + const lastIndexoFHyphen = key.lastIndexOf("-") + const finalKey = key.substring(lastIndexoFHyphen + 1, key.length) + + return { + character: finalKey, + shift: hasShift, + alt: hasAlt, + control: hasControl, + meta: hasMeta, + } +} diff --git a/browser/src/Services/InputManager.ts b/browser/src/Services/InputManager.ts index a5a116a868..79b7bde48b 100644 --- a/browser/src/Services/InputManager.ts +++ b/browser/src/Services/InputManager.ts @@ -8,6 +8,8 @@ export type ActionOrCommand = string | ActionFunction export type FilterFunction = () => boolean +import { IKeyChord, parseKeysFromVimString } from "./../Input/KeyParser" + export interface KeyBinding { action: ActionOrCommand filter?: FilterFunction @@ -69,6 +71,25 @@ export class InputManager implements Oni.InputManager { return !!this._boundKeys[keyChord] } + // Returns an array of keys bound to a command + public getBoundKeys(command: string): string[] { + return Object.keys(this._boundKeys).reduce( + (prev: string[], currentValue: string) => { + const bindings = this._boundKeys[currentValue] + if (bindings.find(b => b.action === command)) { + return [...prev, currentValue] + } else { + return prev + } + }, + [] as string[], + ) + } + + public parseKeys(keys: string): IKeyChord { + return parseKeysFromVimString(keys) + } + /** * Internal Methods */ diff --git a/browser/src/Services/Menu/MenuComponent.tsx b/browser/src/Services/Menu/MenuComponent.tsx index 3514f0d84f..191032e440 100644 --- a/browser/src/Services/Menu/MenuComponent.tsx +++ b/browser/src/Services/Menu/MenuComponent.tsx @@ -6,7 +6,7 @@ import * as take from "lodash/take" import * as Oni from "oni-api" import { HighlightTextByIndex } from "./../../UI/components/HighlightText" -import { Visible } from "./../../UI/components/Visible" +// import { Visible } from "./../../UI/components/Visible" import { Icon, IconSize } from "./../../UI/Icon" import { focusManager } from "./../FocusManager" @@ -156,6 +156,7 @@ export interface IMenuItemProps { detail: string detailHighlights: number[] pinned: boolean + additionalComponent?: JSX.Element onClick: () => void } @@ -173,7 +174,6 @@ export class MenuItem extends React.PureComponent { ) : ( this.props.icon ) - return (
this.props.onClick()}> {icon} @@ -189,9 +189,7 @@ export class MenuItem extends React.PureComponent { highlightIndices={this.props.detailHighlights} highlightClassName={"highlight"} /> - - - + {this.props.additionalComponent}
) } diff --git a/browser/src/Services/Menu/MenuFilter.ts b/browser/src/Services/Menu/MenuFilter.ts index 849b479ce8..270a82ae8e 100644 --- a/browser/src/Services/Menu/MenuFilter.ts +++ b/browser/src/Services/Menu/MenuFilter.ts @@ -7,7 +7,7 @@ import * as Fuse from "fuse.js" import * as sortBy from "lodash/sortBy" -import * as Oni from "oni-api" +// import * as Oni from "oni-api" import { configuration } from "./../../Services/Configuration" @@ -38,10 +38,7 @@ export const shouldFilterbeCaseSensitive = (searchString: string): boolean => { } } -export const fuseFilter = ( - options: Oni.Menu.MenuOption[], - searchString: string, -): IMenuOptionWithHighlights[] => { +export const fuseFilter = (options: any[], searchString: string): IMenuOptionWithHighlights[] => { if (!searchString) { const opt = options.map(o => { return { @@ -53,6 +50,7 @@ export const fuseFilter = ( metadata: o.metadata, detailHighlights: [], labelHighlights: [], + additionalComponent: o.additionalComponent, } }) @@ -123,6 +121,7 @@ export const fuseFilter = ( metadata: f.item.metadata, labelHighlights: convertArrayOfPairsToIndices(labelHighlights), detailHighlights: convertArrayOfPairsToIndices(detailHighlights), + additionalComponent: f.item.additionalComponent, } }) diff --git a/browser/src/Services/Notifications/Notifications.ts b/browser/src/Services/Notifications/Notifications.ts index 1fa2e3355a..370cb57819 100644 --- a/browser/src/Services/Notifications/Notifications.ts +++ b/browser/src/Services/Notifications/Notifications.ts @@ -14,14 +14,11 @@ import { createStore, INotificationsState } from "./NotificationStore" import { getView } from "./NotificationsView" export class Notifications { - private _id: number = 0 private _overlay: Overlay private _store: Store - constructor( - private _overlayManager: OverlayManager, - ) { + constructor(private _overlayManager: OverlayManager) { this._store = createStore() this._overlay = this._overlayManager.createItem() diff --git a/browser/src/Services/QuickOpen/PinnedIconView.tsx b/browser/src/Services/QuickOpen/PinnedIconView.tsx new file mode 100644 index 0000000000..b6a24216e0 --- /dev/null +++ b/browser/src/Services/QuickOpen/PinnedIconView.tsx @@ -0,0 +1,18 @@ +/** + * PinnedIconView.tsx + * + * Shows the pinned icon for recently navigated items in quick open + */ + +import * as React from "react" + +import { Visible } from "./../../UI/components/Visible" +import { Icon } from "./../../UI/Icon" + +export const render = (props: { pinned: boolean }) => { + return ( + + + + ) +} diff --git a/browser/src/Services/QuickOpen/QuickOpen.ts b/browser/src/Services/QuickOpen/QuickOpen.ts index 4ad302e00a..bc1d01f444 100644 --- a/browser/src/Services/QuickOpen/QuickOpen.ts +++ b/browser/src/Services/QuickOpen/QuickOpen.ts @@ -18,6 +18,7 @@ import { editorManager } from "./../EditorManager" import { fuseFilter, Menu, MenuManager } from "./../Menu" import { FinderProcess } from "./FinderProcess" +import { render as renderPinnedIcon } from "./PinnedIconView" import { QuickOpenItem, QuickOpenType } from "./QuickOpenItem" import { regexFilter } from "./RegExFilter" import * as RipGrep from "./RipGrep" @@ -248,19 +249,20 @@ export class QuickOpen { process.env[process.platform === "win32" ? "USERPROFILE" : "HOME"] === process.cwd() ) } - // Show menu based on items given private _setItemsFromQuickOpenItems(items: QuickOpenItem[]): void { const options = items.map(qitem => { const f = qitem.item.trim() const file = path.basename(f) const folder = path.dirname(f) + const pinned = this._seenItems.indexOf(f) >= 0 return { icon: getFileIcon(file) as any, label: file, detail: folder, - pinned: this._seenItems.indexOf(f) >= 0, + pinned, + additionalComponent: renderPinnedIcon({ pinned }), } }) diff --git a/browser/src/Services/Tasks.ts b/browser/src/Services/Tasks.ts index 63dc255823..44536a882a 100644 --- a/browser/src/Services/Tasks.ts +++ b/browser/src/Services/Tasks.ts @@ -17,6 +17,8 @@ import * as Oni from "oni-api" import { Menu, MenuManager } from "./../Services/Menu" +import { render as renderKeyBindingInfo } from "./../UI/components/KeyBindingInfo" + export interface ITask { name: string detail: string @@ -50,9 +52,9 @@ export class Tasks { .filter(t => t.name || t.detail) .map(f => { return { - icon: "tasks", label: f.name, detail: f.detail, + additionalComponent: renderKeyBindingInfo({ command: f.command }), } }) diff --git a/browser/src/UI/components/KeyBindingInfo.tsx b/browser/src/UI/components/KeyBindingInfo.tsx new file mode 100644 index 0000000000..7552f87b0f --- /dev/null +++ b/browser/src/UI/components/KeyBindingInfo.tsx @@ -0,0 +1,70 @@ +/** + * KeyBindingInfo.tsx + * + * Helper component to show a key binding, based on a command + */ + +import styled from "styled-components" + +import * as React from "react" + +import { inputManager } from "./../../Services/InputManager" + +export interface IKeyBindingInfoProps { + command: string +} + +const KeyWrapper = styled.span` + color: ${props => props.theme["highlight.mode.normal.background"]}; + font-size: 0.9em; +` + +export class KeyBindingInfo extends React.PureComponent { + public render(): JSX.Element { + if (!inputManager) { + return null + } + + const boundKeys = inputManager.getBoundKeys(this.props.command) + + if (!boundKeys || !boundKeys.length) { + return null + } + + const parsedKeys = inputManager.parseKeys(boundKeys[0]) + + if (!parsedKeys || !parsedKeys.chord || !parsedKeys.chord.length) { + return null + } + + const firstChord = parsedKeys.chord[0] + + const elems: JSX.Element[] = [] + + if (firstChord.meta) { + elems.push({"meta"}) + elems.push({"+"}) + } + + if (firstChord.control) { + elems.push({"control"}) + elems.push({"+"}) + } + + if (firstChord.alt) { + elems.push({"alt"}) + elems.push({"+"}) + } + + if (firstChord.shift) { + elems.push({"shift"}) + elems.push({"+"}) + } + + elems.push({firstChord.character}) + + return {elems} + } +} + +export const render = (props: IKeyBindingInfoProps) => diff --git a/browser/test/Input/InputManagerTests.ts b/browser/test/Input/InputManagerTests.ts index a72ef4c9a5..503a029443 100644 --- a/browser/test/Input/InputManagerTests.ts +++ b/browser/test/Input/InputManagerTests.ts @@ -52,5 +52,32 @@ describe("InputManager", () => { assert.strictEqual(count, 0, "Handler should not have been called.") assert.strictEqual(handled, false) }) + + describe("getBoundKeys", () => { + it("returns empty array if no key bound to command", () => { + const im = new InputManager() + + const boundKeys = im.getBoundKeys("test.command") + assert.deepEqual(boundKeys, [], "Validate no keys bound") + }) + + it("returns key bound to command", () => { + const im = new InputManager() + im.bind("", "test.command") + + const boundKeys = im.getBoundKeys("test.command") + assert.deepEqual(boundKeys, [""], "Validate the bound key is returned") + }) + + it("does not return key if bound and then unbind", () => { + const im = new InputManager() + const unbind = im.bind("", "test.command") + + unbind() + + const boundKeys = im.getBoundKeys("test.command") + assert.deepEqual(boundKeys, [], "Validate no bound keys are returned") + }) + }) }) }) diff --git a/browser/test/Input/KeyParserTests.ts b/browser/test/Input/KeyParserTests.ts new file mode 100644 index 0000000000..0a98be824e --- /dev/null +++ b/browser/test/Input/KeyParserTests.ts @@ -0,0 +1,34 @@ +/** + * KeyParserTests.ts + */ + +import * as assert from "assert" + +import * as KeyParser from "./../../src/Input/KeyParser" + +describe("KeyParser", () => { + describe("parseKeysFromVimString", () => { + it("parses a basic key", () => { + const result = KeyParser.parseKeysFromVimString("a") + + assert.deepEqual(result.chord, [ + { character: "a", shift: false, alt: false, control: false, meta: false }, + ]) + }) + + it("parses multiple keys in a row", () => { + const result = KeyParser.parseKeysFromVimString("ab") + assert.deepEqual(result.chord, [ + { character: "a", shift: false, alt: false, control: false, meta: false }, + { character: "b", shift: false, alt: false, control: false, meta: false }, + ]) + }) + + it("parses modifier keys", () => { + const result = KeyParser.parseKeysFromVimString("") + assert.deepEqual(result.chord, [ + { character: "a", shift: false, alt: false, control: true, meta: false }, + ]) + }) + }) +}) diff --git a/browser/test/Services/WindowManager/LinearSplitProviderTests.ts b/browser/test/Services/WindowManager/LinearSplitProviderTests.ts index 69756af913..c45f795ea3 100644 --- a/browser/test/Services/WindowManager/LinearSplitProviderTests.ts +++ b/browser/test/Services/WindowManager/LinearSplitProviderTests.ts @@ -1,4 +1,3 @@ - /** * LinearSplitProviderTests.ts */ @@ -8,7 +7,9 @@ import * as assert from "assert" import { LinearSplitProvider } from "./../../../src/Services/WindowManager" export class MockWindowSplit { - public render(): JSX.Element { return null } + public render(): JSX.Element { + return null + } } describe("LinearSplitProviderTests", () => { From d02e750c3a520653ac76ca4bbaea858b7ace94e8 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 31 Jan 2018 07:32:26 -0800 Subject: [PATCH 013/103] Add 'react-virtualized' for scrollbars in Menu (#1352) * Add react-virtualized as dependency; start hooking up to menu * Add rendered styles * Hook up width autosizer * Hook up min width * Start plumbing through configuration settings to store * Hook up configuration values * Fix styling of menu * Add radix parameter * Bump up max items to show setting --- .../Configuration/DefaultConfiguration.ts | 2 + .../Configuration/IConfigurationValues.ts | 2 + browser/src/Services/Menu/Menu.less | 23 +-- browser/src/Services/Menu/Menu.ts | 25 +++- .../src/Services/Menu/MenuActionCreators.ts | 10 ++ browser/src/Services/Menu/MenuActions.ts | 9 ++ browser/src/Services/Menu/MenuComponent.tsx | 131 +++++++++++++----- browser/src/Services/Menu/MenuReducer.ts | 19 ++- browser/src/Services/Menu/MenuState.ts | 16 +++ browser/src/Services/Menu/index.ts | 5 +- browser/src/index.tsx | 2 +- package.json | 2 + yarn.lock | 29 +++- 13 files changed, 216 insertions(+), 59 deletions(-) diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index 63266b6748..21670a503a 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -247,6 +247,8 @@ const BaseConfiguration: IConfigurationValues = { }, "menu.caseSensitive": "smart", + "menu.rowHeight": 40, + "menu.maxItemsToShow": 8, "recorder.copyScreenshotToClipboard": false, "recorder.outputPath": os.tmpdir(), diff --git a/browser/src/Services/Configuration/IConfigurationValues.ts b/browser/src/Services/Configuration/IConfigurationValues.ts index 91b5f56a94..9bc24fd9ee 100644 --- a/browser/src/Services/Configuration/IConfigurationValues.ts +++ b/browser/src/Services/Configuration/IConfigurationValues.ts @@ -189,6 +189,8 @@ export interface IConfigurationValues { // - if `'smart'`, is case sensitive if the query string // contains uppercase characters "menu.caseSensitive": string | boolean + "menu.rowHeight": number + "menu.maxItemsToShow": number // Output path to save screenshots and recordings "recorder.outputPath": string diff --git a/browser/src/Services/Menu/Menu.less b/browser/src/Services/Menu/Menu.less index 1f6c71d955..ae581934c7 100644 --- a/browser/src/Services/Menu/Menu.less +++ b/browser/src/Services/Menu/Menu.less @@ -46,31 +46,16 @@ .items { .item { - padding: 4px; - margin-top: 4px; - - display: flex; - flex-direction: row; - align-items: center; - - user-select: none; - -webkit-user-drag: none; - cursor: pointer; - font-size: @font-size-normal; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - .fa:not(.fa-spin) { - padding-right: 8px; + padding-left: 4px; + padding-right: 4px; } &:hover { - background-color: rgba(0, 0, 0, 0.2); + background-color: rgba(0, 0, 0, 0.1); } &.selected { - .box-shadow; - background-color: rgba(0, 0, 0, 0.2); + background-color: rgba(0, 0, 0, 0.1); } .label { diff --git a/browser/src/Services/Menu/Menu.ts b/browser/src/Services/Menu/Menu.ts index 236301f636..f726b352a4 100644 --- a/browser/src/Services/Menu/Menu.ts +++ b/browser/src/Services/Menu/Menu.ts @@ -17,6 +17,7 @@ import * as State from "./MenuState" import { MenuContainer } from "./MenuComponent" +import { Configuration } from "./../Configuration" import { Overlay, OverlayManager } from "./../Overlay" export interface IMenuOptionWithHighlights extends Oni.Menu.MenuOption { @@ -39,14 +40,25 @@ export const menuActions: typeof ActionCreators = bindActionCreators( menuStore.dispatch, ) +export const sanitizeConfigurationValue = (value: any, defaultValue: number): number => { + const parsedValue = parseInt(value, 10) + return parsedValue > 0 ? parsedValue : defaultValue +} + export class MenuManager { private _id: number = 0 private _overlay: Overlay - constructor(private _overlayManager: OverlayManager) { + constructor(private _configuration: Configuration, private _overlayManager: OverlayManager) { this._overlay = this._overlayManager.createItem() this._overlay.setContents(MenuContainer()) this._overlay.show() + + this._configuration.onConfigurationChanged.subscribe(() => { + this._updateConfiguration() + }) + + this._updateConfiguration() } public create(): Menu { @@ -77,6 +89,17 @@ export class MenuManager { menuState.menu.onSelectItem(idx) } } + + private _updateConfiguration(): void { + const values = this._configuration.getValues() + const rowHeightUnsanitized = values["menu.rowHeight"] + const maxItemsUnsanitized = values["menu.maxItemsToShow"] + + menuActions.setMenuConfiguration( + sanitizeConfigurationValue(rowHeightUnsanitized, 40), + sanitizeConfigurationValue(maxItemsUnsanitized, 6), + ) + } } export class Menu implements Oni.Menu.MenuInstance { diff --git a/browser/src/Services/Menu/MenuActionCreators.ts b/browser/src/Services/Menu/MenuActionCreators.ts index 14eb14e526..d3b05cf3e6 100644 --- a/browser/src/Services/Menu/MenuActionCreators.ts +++ b/browser/src/Services/Menu/MenuActionCreators.ts @@ -24,6 +24,16 @@ const notifySelectedItemChange = (contextMenuState: any) => { } } +export const setMenuConfiguration = (rowHeight: number, maxItemsToShow: number) => { + return { + type: "SET_MENU_CONFIGURATION", + payload: { + rowHeight, + maxItemsToShow, + }, + } +} + export const showPopupMenu = ( id: string, opts?: MenuActions.IMenuOptions, diff --git a/browser/src/Services/Menu/MenuActions.ts b/browser/src/Services/Menu/MenuActions.ts index 4f29d89c66..76ca6527a8 100644 --- a/browser/src/Services/Menu/MenuActions.ts +++ b/browser/src/Services/Menu/MenuActions.ts @@ -15,6 +15,14 @@ export interface IMenuOptions { onFilterTextChanged?: (newText: string) => void } +export interface ISetConfigurationMenuAction { + type: "SET_MENU_CONFIGURATION" + payload: { + rowHeight: number + maxItemsToShow: number + } +} + export interface IShowMenuAction { type: "SHOW_MENU" payload: { @@ -70,6 +78,7 @@ export interface IPreviousMenuAction { export type MenuAction = | IShowMenuAction + | ISetConfigurationMenuAction | ISetMenuLoading | ISetMenuItems | IFilterMenuAction diff --git a/browser/src/Services/Menu/MenuComponent.tsx b/browser/src/Services/Menu/MenuComponent.tsx index 191032e440..eb8f126d8a 100644 --- a/browser/src/Services/Menu/MenuComponent.tsx +++ b/browser/src/Services/Menu/MenuComponent.tsx @@ -1,7 +1,9 @@ import * as React from "react" import { connect, Provider } from "react-redux" -import * as take from "lodash/take" +import styled from "styled-components" + +import { AutoSizer, List } from "react-virtualized" import * as Oni from "oni-api" @@ -15,6 +17,8 @@ import { IMenuOptionWithHighlights, menuStore } from "./Menu" import * as ActionCreators from "./MenuActionCreators" import * as State from "./MenuState" +import { withProps } from "./../../UI/components/common" + import { TextInputView } from "./../../UI/components/LightweightText" export interface IMenuProps { @@ -26,6 +30,9 @@ export interface IMenuProps { items: IMenuOptionWithHighlights[] isLoading: boolean + rowHeight: number + maxItemsToShow: number + backgroundColor: string foregroundColor: string } @@ -44,21 +51,20 @@ export class MenuView extends React.PureComponent { return null } - // TODO: sync max display items (10) with value in Reducer.popupMenuReducer() (Reducer.ts) - const initialItems = take(this.props.items, 10) - - // const pinnedItems = initialItems.filter(f => f.pinned) - // const unpinnedItems = initialItems.filter(f => !f.pinned) - const items = initialItems.map((menuItem, index) => ( - // FIXME: undefined - this.props.onSelect(index)} - /> - )) + const rowRenderer = (props: { key: string; index: number; style: React.CSSProperties }) => { + const item = this.props.items[props.index] + return ( +
+ this.props.onSelect(props.index)} + /> +
+ ) + } const menuStyle = { backgroundColor: this.props.backgroundColor, @@ -67,6 +73,9 @@ export class MenuView extends React.PureComponent { const footerClassName = "footer " + (this.props.isLoading ? "loading" : "loaded") + const height = + Math.min(this.props.items.length, this.props.maxItemsToShow) * this.props.rowHeight + return (
@@ -76,7 +85,22 @@ export class MenuView extends React.PureComponent { foregroundColor={this.props.foregroundColor} onChange={evt => this._onChange(evt)} /> -
{items}
+
+
+ + {({ width }) => ( + + )} + +
+
{ const EmptyArray: any[] = [] const noop = () => {} // tslint:disable-line +const NullProps: any = { + visible: false, + selectedIndex: 0, + filterText: "", + items: EmptyArray, + backgroundColor: "black", + foregroundColor: "white", + onSelect: noop, + isLoading: true, + rowHeight: 0, + maxItemsToShow: 0, +} -const mapStateToProps = (state: State.IMenus) => { +const mapStateToProps = ( + state: State.IMenus, +): any => { if (!state.menu) { - return { - visible: false, - selectedIndex: 0, - filterText: "", - items: EmptyArray, - backgroundColor: "black", - foregroundColor: "white", - onSelect: noop, - isLoading: true, - } + return NullProps } else { const popupMenu = state.menu return { @@ -123,11 +152,13 @@ const mapStateToProps = (state: State.IMenus { +const mapDispatchToProps = (dispatch: any): any => { const dispatchFilterText = (text: string) => { dispatch(ActionCreators.filterMenu(text)) } @@ -137,7 +168,7 @@ const mapDispatchToProps = (dispatch: any) => { } } -export const ConnectedMenu = connect(mapStateToProps, mapDispatchToProps)(MenuView) +export const ConnectedMenu: any = connect(mapStateToProps, mapDispatchToProps)(MenuView) export const MenuContainer = () => { return ( @@ -158,8 +189,38 @@ export interface IMenuItemProps { pinned: boolean additionalComponent?: JSX.Element onClick: () => void + height: number +} + +export interface IMenuItemWrapperProps { + isSelected: boolean } +const MenuItemWrapper = withProps(styled.div)` + position: absolute; + top: 4px; + left: 0px; + right: 4px; + bottom: 4px; + + border-left: ${props => + props.isSelected + ? "4px solid " + props.theme["highlight.mode.normal.background"] + : "4px solid transparent"}; + + display: flex; + flex-direction: row; + align-items: center; + + user-select: none; + -webkit-user-drag:none; + cursor: pointer; + font-size: 1em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +` + export class MenuItem extends React.PureComponent { public render(): JSX.Element { let className = "item" @@ -175,7 +236,12 @@ export class MenuItem extends React.PureComponent { this.props.icon ) return ( -
this.props.onClick()}> + this.props.onClick()} + style={{ height: this.props.height + "px" }} + > {icon} { highlightIndices={this.props.detailHighlights} highlightClassName={"highlight"} /> - {this.props.additionalComponent} -
+ ) } } diff --git a/browser/src/Services/Menu/MenuReducer.ts b/browser/src/Services/Menu/MenuReducer.ts index 12ff70e4b0..bc839a5f0b 100644 --- a/browser/src/Services/Menu/MenuReducer.ts +++ b/browser/src/Services/Menu/MenuReducer.ts @@ -15,16 +15,33 @@ export function createReducer() { ): State.IMenus => { return { ...s, + configuration: configurationReducer(s.configuration, a), menu: popupMenuReducer(s.menu, a), } } + const configurationReducer = ( + s: State.IMenuConfigurationSettings = State.DefaultMenuConfigurationSettings, + a: Actions.MenuAction, + ) => { + switch (a.type) { + case "SET_MENU_CONFIGURATION": + return { + ...s, + rowHeight: a.payload.rowHeight, + maxItemsToShow: a.payload.maxItemsToShow, + } + default: + return s + } + } + function popupMenuReducer( s: State.IMenu | null, a: any, ): State.IMenu { // TODO: sync max display items (10) with value in Menu.render() (Menu.tsx) - const size = s ? Math.min(10, s.filteredOptions.length) : 0 + const size = s && s.filteredOptions ? s.filteredOptions.length : 0 switch (a.type) { case "SHOW_MENU": { diff --git a/browser/src/Services/Menu/MenuState.ts b/browser/src/Services/Menu/MenuState.ts index ca8d29c1bc..868484221d 100644 --- a/browser/src/Services/Menu/MenuState.ts +++ b/browser/src/Services/Menu/MenuState.ts @@ -7,6 +7,18 @@ export interface IMenus { // TOOD: In the future, could handle multiple menus here... menu: IMenu + + configuration: IMenuConfigurationSettings +} + +export interface IMenuConfigurationSettings { + rowHeight: number + maxItemsToShow: number +} + +export const DefaultMenuConfigurationSettings: IMenuConfigurationSettings = { + rowHeight: 40, + maxItemsToShow: 6, } export interface IMenu { @@ -33,5 +45,9 @@ export interface IMenu { export function createDefaultState(): IMenus { return { menu: null, + configuration: { + rowHeight: 20, + maxItemsToShow: 10, + }, } } diff --git a/browser/src/Services/Menu/index.ts b/browser/src/Services/Menu/index.ts index cbac4838f5..f2c5345cfb 100644 --- a/browser/src/Services/Menu/index.ts +++ b/browser/src/Services/Menu/index.ts @@ -2,13 +2,14 @@ export * from "./Menu" export * from "./MenuComponent" export * from "./MenuFilter" +import { Configuration } from "./../Configuration" import { OverlayManager } from "./../Overlay" import { MenuManager } from "./Menu" let _menuManager: MenuManager -export const activate = (overlayManager: OverlayManager) => { - _menuManager = new MenuManager(overlayManager) +export const activate = (configuration: Configuration, overlayManager: OverlayManager) => { + _menuManager = new MenuManager(configuration, overlayManager) } export const getInstance = (): MenuManager => { diff --git a/browser/src/index.tsx b/browser/src/index.tsx index fd49657370..4b75fb2d6d 100644 --- a/browser/src/index.tsx +++ b/browser/src/index.tsx @@ -122,7 +122,7 @@ const start = async (args: string[]): Promise => { const overlayManager = Overlay.getInstance() const Menu = await menuPromise - Menu.activate(overlayManager) + Menu.activate(configuration, overlayManager) const menuManager = Menu.getInstance() const Notifications = await notificationsPromise diff --git a/package.json b/package.json index cbdda6a98f..479c6cb034 100644 --- a/package.json +++ b/package.json @@ -243,6 +243,7 @@ "@types/react-motion": "0.0.23", "@types/react-redux": "5.0.12", "@types/react-transition-group": "2.0.6", + "@types/react-virtualized": "^9.7.10", "@types/shelljs": "^0.7.7", "@types/sinon": "1.16.32", "autoprefixer": "6.4.0", @@ -283,6 +284,7 @@ "pretty-quick": "^1.2.2", "react-hot-loader": "1.3.1", "react-motion": "0.5.2", + "react-virtualized": "^9.18.0", "react-redux": "5.0.6", "react-transition-group": "2.2.1", "redux": "3.7.2", diff --git a/yarn.lock b/yarn.lock index a41ef71025..2e50e7c214 100644 --- a/yarn.lock +++ b/yarn.lock @@ -120,6 +120,10 @@ version "8.0.53" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.53.tgz#396b35af826fa66aad472c8cb7b8d5e277f4e6d8" +"@types/prop-types@*": + version "15.5.2" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.2.tgz#3c6b8dceb2906cc87fe4358e809f9d20c8d59be1" + "@types/react-dom@16.0.3": version "16.0.3" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.0.3.tgz#8accad7eabdab4cca3e1a56f5ccb57de2da0ff64" @@ -146,6 +150,13 @@ dependencies: "@types/react" "*" +"@types/react-virtualized@^9.7.10": + version "9.7.10" + resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.7.10.tgz#f55ee6138cef17a4adf2893494d32b8407f0103b" + dependencies: + "@types/prop-types" "*" + "@types/react" "*" + "@types/react@*": version "16.0.25" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.0.25.tgz#bf696b83fe480c5e0eff4335ee39ebc95884a1ed" @@ -1271,7 +1282,7 @@ clap@^1.0.9: dependencies: chalk "^1.1.3" -classnames@2.2.5, classnames@^2.2.5: +classnames@2.2.5, classnames@^2.2.3, classnames@^2.2.5: version "2.2.5" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" @@ -1981,6 +1992,10 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" +"dom-helpers@^2.4.0 || ^3.0.0": + version "3.3.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6" + dom-helpers@^3.2.0: version "3.2.1" resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a" @@ -3924,7 +3939,7 @@ longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.0, loose-envify@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: @@ -5339,6 +5354,16 @@ react-transition-group@2.2.1: prop-types "^15.5.8" warning "^3.0.0" +react-virtualized@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.18.0.tgz#d95ccdcfe82c7791da661be3ebc59f4bbc224f07" + dependencies: + babel-runtime "^6.26.0" + classnames "^2.2.3" + dom-helpers "^2.4.0 || ^3.0.0" + loose-envify "^1.3.0" + prop-types "^15.5.4" + react@16.0.0: version "16.0.0" resolved "https://registry.yarnpkg.com/react/-/react-16.0.0.tgz#ce7df8f1941b036f02b2cca9dbd0cb1f0e855e2d" From a9768d9cffd829262c58443be4484e4a1d7b9839 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 31 Jan 2018 07:51:57 -0800 Subject: [PATCH 014/103] #366 - Part 1 - Keyboard accessibility for non-vim UX (#1376) * Start prototyping sneak UI * Some progress towards prototyping sneak UI * Add 'sneak-style' UI + helper component * Fix up lint issues / remove addressed comments * Add bold highlighting, use colors from colorscheme * Tweak visual styling of sneaks * Fix lint issues * Add placeholder binding for s/S --- browser/src/Input/KeyBindings.ts | 5 + .../src/Services/Explorer/ExplorerView.tsx | 14 +- browser/src/Services/Sidebar/SidebarView.tsx | 14 +- browser/src/Services/Sneak.tsx | 238 ++++++++++++++++++ browser/src/UI/components/Sneakable.tsx | 62 +++++ browser/src/UI/components/Tabs.tsx | 41 +-- browser/src/UI/components/common.ts | 8 + browser/src/index.tsx | 9 +- 8 files changed, 360 insertions(+), 31 deletions(-) create mode 100644 browser/src/Services/Sneak.tsx create mode 100644 browser/src/UI/components/Sneakable.tsx diff --git a/browser/src/Input/KeyBindings.ts b/browser/src/Input/KeyBindings.ts index 389101cdaf..6b0314cdc1 100644 --- a/browser/src/Input/KeyBindings.ts +++ b/browser/src/Input/KeyBindings.ts @@ -106,4 +106,9 @@ export const applyDefaultKeyBindings = (oni: Oni.Plugin.Api, config: Configurati input.bind("", "explorer.open") input.bind("", "explorer.delete") + + // TODO: Scope 's' to just the local window + input.bind("s", "sneak.show", () => isNormalMode() && !menu.isMenuOpen()) + input.bind("S", "sneak.show", () => isNormalMode() && !menu.isMenuOpen()) + input.bind(["", ""], "sneak.hide") } diff --git a/browser/src/Services/Explorer/ExplorerView.tsx b/browser/src/Services/Explorer/ExplorerView.tsx index 7837c185f3..c79150ad01 100644 --- a/browser/src/Services/Explorer/ExplorerView.tsx +++ b/browser/src/Services/Explorer/ExplorerView.tsx @@ -164,6 +164,8 @@ export interface IExplorerViewProps extends IExplorerViewContainerProps { isActive: boolean } +import { Sneakable } from "./../../UI/components/Sneakable" + export class ExplorerView extends React.PureComponent { public render(): JSX.Element { const ids = this.props.nodes.map(node => node.id) @@ -175,11 +177,13 @@ export class ExplorerView extends React.PureComponent { onSelectionChanged={this.props.onSelectionChanged} render={(selectedId: string) => { const nodes = this.props.nodes.map(node => ( - this.props.onClick(node.id)} - /> + this.props.onClick(node.id)}> + this.props.onClick(node.id)} + /> + )) return ( diff --git a/browser/src/Services/Sidebar/SidebarView.tsx b/browser/src/Services/Sidebar/SidebarView.tsx index 2964764db0..12a906b104 100644 --- a/browser/src/Services/Sidebar/SidebarView.tsx +++ b/browser/src/Services/Sidebar/SidebarView.tsx @@ -14,6 +14,8 @@ import { ISidebarEntry, ISidebarState } from "./SidebarStore" import styled from "styled-components" import { withProps } from "./../../UI/components/common" +import { Sneakable } from "./../../UI/components/Sneakable" + export interface ISidebarIconProps { active: boolean focused: boolean @@ -56,11 +58,13 @@ const SidebarIconInner = styled.div` export class SidebarIcon extends React.PureComponent { public render(): JSX.Element { return ( - - - - - + + + + + + + ) } } diff --git a/browser/src/Services/Sneak.tsx b/browser/src/Services/Sneak.tsx new file mode 100644 index 0000000000..82bd298251 --- /dev/null +++ b/browser/src/Services/Sneak.tsx @@ -0,0 +1,238 @@ +/** + * Sneak.tsx + * + * Provides the 'sneak layer' UI + */ + +import * as React from "react" + +import { Shapes } from "oni-api" +import { IDisposable } from "oni-types" + +import { CallbackCommand, CommandManager } from "./CommandManager" + +import { Overlay, OverlayManager } from "./Overlay" + +import { TextInputView } from "./../UI/components/LightweightText" + +export interface ISneakInfo { + rectangle: Shapes.Rectangle + callback: () => void +} + +export interface IAugmentedSneakInfo extends ISneakInfo { + triggerKeys: string +} + +export type SneakProvider = () => ISneakInfo[] + +export class Sneak { + private _activeOverlay: Overlay + private _providers: SneakProvider[] = [] + + constructor(private _overlayManager: OverlayManager) {} + + public get isActive(): boolean { + return !!this._activeOverlay + } + + public addSneakProvider(provider: SneakProvider): IDisposable { + this._providers.push(provider) + const dispose = () => (this._providers = this._providers.filter(prov => prov !== provider)) + return { dispose } + } + + public show(): void { + const rects = this._collectSneakRectangles() + + const augmentedRects = this._augmentSneakRectangles(rects) + + if (this._activeOverlay) { + this._activeOverlay.hide() + this._activeOverlay = null + } + + this._activeOverlay = this._overlayManager.createItem() + + this._activeOverlay.setContents( + this._onComplete(info)} />, + ) + this._activeOverlay.show() + } + + public close(): void { + if (this._activeOverlay) { + this._activeOverlay.hide() + this._activeOverlay = null + } + } + + private _onComplete(sneakInfo: ISneakInfo): void { + this.close() + sneakInfo.callback() + } + + private _augmentSneakRectangles(sneaks: ISneakInfo[]): IAugmentedSneakInfo[] { + return sneaks.map((sneak, idx) => { + return { + ...sneak, + triggerKeys: this._getLabelFromIndex(idx, sneaks.length), + } + }) + } + + private _getLabelFromIndex(index: number, max: number): string { + const firstDigit = Math.floor(index / 26) + const secondDigit = index - firstDigit * 26 + return String.fromCharCode(97 + firstDigit, 97 + secondDigit).toUpperCase() + } + + private _collectSneakRectangles(): ISneakInfo[] { + const ret = this._providers.reduce((prev: ISneakInfo[], cur: SneakProvider) => { + const sneaks = cur().filter(s => !!s) + return [...prev, ...sneaks] + }, []) + + return ret + } +} + +export interface ISneakViewProps { + sneaks: IAugmentedSneakInfo[] + onComplete: (sneakInfo: ISneakInfo) => void +} + +export const TestSneaks = [ + { + triggerKeys: "AA", + rectangle: Shapes.Rectangle.create(10, 10, 100, 100), + callback: () => { + alert("testing") + }, + }, + { + triggerKeys: "AB", + rectangle: Shapes.Rectangle.create(50, 50, 50, 50), + callback: () => { + alert("testing2") + }, + }, +] + +import { boxShadow, OverlayWrapper } from "./../UI/components/common" + +export interface ISneakViewState { + filterText: string +} + +// Render a keyboard input? +// Grab input while 'sneaking'? +export class SneakView extends React.PureComponent { + constructor(props: ISneakViewProps) { + super(props) + + this.state = { + filterText: "", + } + } + + public render(): JSX.Element { + const normalizedFilterText = this.state.filterText.toUpperCase() + const filteredSneaks = this.props.sneaks.filter( + sneak => sneak.triggerKeys.indexOf(normalizedFilterText) === 0, + ) + const sneaks = filteredSneaks.map(si => ( + + )) + + if (filteredSneaks.length === 1) { + this.props.onComplete(filteredSneaks[0]) + } + + return ( + +
+ { + this.setState({ filterText: evt.currentTarget.value }) + }} + backgroundColor={"black"} + foregroundColor={"white"} + /> +
+ {sneaks} +
+ ) + } +} + +export interface ISneakItemViewProps { + sneak: IAugmentedSneakInfo + filterLength: number +} + +import styled from "styled-components" + +const SneakItemWrapper = styled.div` + ${boxShadow} background-color: ${props => props.theme["highlight.mode.visual.background"]}; + color: ${props => props.theme["highlight.mode.visual.foreground"]}; +` + +const SneakItemViewSize = 20 +const px = (num: number): string => num.toString() + "px" +export class SneakItemView extends React.PureComponent { + public render(): JSX.Element { + const style: React.CSSProperties = { + position: "absolute", + left: px(this.props.sneak.rectangle.x), + top: px(this.props.sneak.rectangle.y), + width: px(SneakItemViewSize), + height: px(SneakItemViewSize), + } + + return ( + + + {this.props.sneak.triggerKeys.substring(0, this.props.filterLength)} + + + {this.props.sneak.triggerKeys.substring( + this.props.filterLength, + this.props.sneak.triggerKeys.length, + )} + + + ) + } +} + +let _sneak: Sneak + +export const activate = (commandManager: CommandManager, overlayManager: OverlayManager) => { + _sneak = new Sneak(overlayManager) + + commandManager.registerCommand( + new CallbackCommand( + "sneak.show", + "Sneak: Current Window", + "Show commands for current window", + () => { + _sneak.show() + }, + ), + ) + + commandManager.registerCommand( + new CallbackCommand( + "sneak.hide", + "Sneak: Hide", + "Hide sneak view", + () => _sneak.close(), + () => _sneak.isActive, + ), + ) +} + +export const getInstance = (): Sneak => { + return _sneak +} diff --git a/browser/src/UI/components/Sneakable.tsx b/browser/src/UI/components/Sneakable.tsx new file mode 100644 index 0000000000..c24dd074b5 --- /dev/null +++ b/browser/src/UI/components/Sneakable.tsx @@ -0,0 +1,62 @@ +/** + * Sneakable + * + * Helper for easily integrating 'sneak mode' with UI elements + */ + +import * as React from "react" + +import { Shapes } from "oni-api" +import { IDisposable } from "oni-types" + +import { /* SneakProvider, Sneak,*/ getInstance as getSneak } from "./../../Services/Sneak" + +export interface ISneakableProps { + callback?: () => void +} + +export class Sneakable extends React.PureComponent { + private _subscription: IDisposable + private _element: HTMLDivElement = null + + public componentDidMount() { + this._cleanupSubscription() + + this._subscription = getSneak().addSneakProvider(() => { + if (this._element) { + const rect = this._element.getBoundingClientRect() + + return [ + { + callback: this.props.callback + ? this.props.callback + : () => this._element.click(), + rectangle: Shapes.Rectangle.create( + rect.left, + rect.top, + rect.width, + rect.height, + ), + }, + ] + } else { + return null + } + }) + } + + public componentWillUnmount(): void { + this._cleanupSubscription() + } + + public _cleanupSubscription(): void { + if (this._subscription) { + this._subscription.dispose() + this._subscription = null + } + } + + public render(): JSX.Element { + return
(this._element = elem)}>{this.props.children}
+ } +} diff --git a/browser/src/UI/components/Tabs.tsx b/browser/src/UI/components/Tabs.tsx index d423701e06..0adf1f331f 100644 --- a/browser/src/UI/components/Tabs.tsx +++ b/browser/src/UI/components/Tabs.tsx @@ -14,6 +14,7 @@ import * as State from "./../../Editor/NeovimEditor/NeovimEditorStore" import { addDefaultUnitIfNeeded } from "./../../Font" +import { Sneakable } from "./../../UI/components/Sneakable" import { Icon } from "./../../UI/Icon" import { FileIcon } from "./../../Services/FileIcon" @@ -105,8 +106,8 @@ export class Tabs extends React.PureComponent { } export interface ITabPropsWithClick extends ITabProps { - onClickName: React.EventHandler> - onClickClose: React.EventHandler> + onClickName: () => void + onClickClose: () => void backgroundColor: string foregroundColor: string @@ -132,26 +133,28 @@ export const Tab = (props: ITabPropsWithClick) => { } return ( -
-
- -
-
- {props.name} -
-
-
- + props.onClickName()}> +
+
+ +
+
+ {props.name}
-
-
+
+
+ +
+
+
+
-
+ ) } diff --git a/browser/src/UI/components/common.ts b/browser/src/UI/components/common.ts index 4ee4e72c67..595de96a8f 100644 --- a/browser/src/UI/components/common.ts +++ b/browser/src/UI/components/common.ts @@ -41,6 +41,14 @@ const enableMouse = css` pointer-events: auto; ` +export const OverlayWrapper = styled.div` + position: absolute; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; +` + const fontSizeSmall = `font-size: 0.9em;` const fallBackFonts = ` diff --git a/browser/src/index.tsx b/browser/src/index.tsx index 4b75fb2d6d..36464a781a 100644 --- a/browser/src/index.tsx +++ b/browser/src/index.tsx @@ -32,7 +32,6 @@ const start = async (args: string[]): Promise => { const menuPromise = import("./Services/Menu") const sharedNeovimInstancePromise = import("./neovim/SharedNeovimInstance") - const autoClosingPairsPromise = import("./Services/AutoClosingPairs") const browserWindowConfigurationSynchronizerPromise = import("./Services/BrowserWindowConfigurationSynchronizer") const colorsPromise = import("./Services/Colors") const diagnosticsPromise = import("./Services/Diagnostics") @@ -121,6 +120,11 @@ const start = async (args: string[]): Promise => { Overlay.activate() const overlayManager = Overlay.getInstance() + const sneakPromise = import("./Services/Sneak") + const { commandManager } = await import("./Services/CommandManager") + const Sneak = await sneakPromise + Sneak.activate(commandManager, overlayManager) + const Menu = await menuPromise Menu.activate(configuration, overlayManager) const menuManager = Menu.getInstance() @@ -190,7 +194,8 @@ const start = async (args: string[]): Promise => { createLanguageClientsFromConfiguration(configuration.getValues()) const { inputManager } = await inputManagerPromise - const { commandManager } = await import("./Services/CommandManager") + + const autoClosingPairsPromise = import("./Services/AutoClosingPairs") const AutoClosingPairs = await autoClosingPairsPromise AutoClosingPairs.activate(configuration, editorManager, inputManager, languageManager) From 4341b6fd7d9259dce256a4b5ee854cf7aca184e2 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 31 Jan 2018 09:58:55 -0800 Subject: [PATCH 015/103] UX: Make top border for explorer/sidebar/editor behave consistently (#1403) * Clean up border behavior for split * Spruce up border on sidebar icons * Fix lint issue --- .../Services/Sidebar/SidebarContentSplit.tsx | 72 +++++++++++++++++-- browser/src/Services/Sidebar/SidebarView.tsx | 14 ++-- 2 files changed, 76 insertions(+), 10 deletions(-) diff --git a/browser/src/Services/Sidebar/SidebarContentSplit.tsx b/browser/src/Services/Sidebar/SidebarContentSplit.tsx index 41f17b20d0..2556a98468 100644 --- a/browser/src/Services/Sidebar/SidebarContentSplit.tsx +++ b/browser/src/Services/Sidebar/SidebarContentSplit.tsx @@ -4,8 +4,10 @@ import * as React from "react" import { connect, Provider } from "react-redux" - import styled from "styled-components" + +import { Event, IDisposable, IEvent } from "oni-types" + import { enableMouse, withProps } from "./../../UI/components/common" import { ISidebarEntry, ISidebarState, SidebarManager, SidebarPane } from "./SidebarStore" @@ -22,6 +24,9 @@ export const getActiveEntry = (state: ISidebarState): ISidebarEntry => { * Split that is the container for the active sidebar item */ export class SidebarContentSplit { + private _onEnterEvent = new Event() + private _onLeaveEvent = new Event() + public get activePane(): SidebarPane { const entry = getActiveEntry(this._sidebarManager.store.getState()) @@ -35,6 +40,8 @@ export class SidebarContentSplit { if (pane && pane.enter) { pane.enter() } + + this._onEnterEvent.dispatch() } public leave(): void { @@ -42,21 +49,32 @@ export class SidebarContentSplit { if (pane && pane.leave) { pane.leave() } + + this._onLeaveEvent.dispatch() } public render(): JSX.Element { return ( - + ) } } -export interface ISidebarContentViewProps { +export interface ISidebarContentViewProps extends ISidebarContentContainerProps { activeEntry: ISidebarEntry } +export interface ISidebarContentContainerProps { + onEnter: IEvent + onLeave: IEvent +} + +export interface ISidebarContentViewState { + active: boolean +} + export const SidebarContentWrapper = withProps<{}>(styled.div)` ${enableMouse} width: 200px; @@ -104,7 +122,40 @@ export const SidebarInnerPaneWrapper = withProps<{}>(styled.div)` overflow-y: auto; ` -export class SidebarContentView extends React.PureComponent { +export class SidebarContentView extends React.PureComponent< + ISidebarContentViewProps, + ISidebarContentViewState +> { + private _subs: IDisposable[] = [] + + constructor(props: ISidebarContentViewProps) { + super(props) + this.state = { + active: false, + } + } + + public componentDidMount(): void { + this._cleanSubscriptions() + const s1 = this.props.onEnter.subscribe(() => + this.setState({ + active: true, + }), + ) + + const s2 = this.props.onLeave.subscribe(() => + this.setState({ + active: false, + }), + ) + + this._subs = [s1, s2] + } + + public componentWillUnmount(): void { + this._cleanSubscriptions() + } + public render(): JSX.Element { if (!this.props.activeEntry) { return null @@ -115,16 +166,25 @@ export class SidebarContentView extends React.PureComponent - + {activeEntry.pane.render()} ) } + + private _cleanSubscriptions(): void { + this._subs.forEach(s => s.dispose()) + this._subs = [] + } } -export const mapStateToProps = (state: ISidebarState): ISidebarContentViewProps => { +export const mapStateToProps = ( + state: ISidebarState, + containerProps: ISidebarContentContainerProps, +): ISidebarContentViewProps => { const activeEntry = getActiveEntry(state) return { + ...containerProps, activeEntry, } } diff --git a/browser/src/Services/Sidebar/SidebarView.tsx b/browser/src/Services/Sidebar/SidebarView.tsx index 12a906b104..b4b6b26656 100644 --- a/browser/src/Services/Sidebar/SidebarView.tsx +++ b/browser/src/Services/Sidebar/SidebarView.tsx @@ -33,19 +33,19 @@ const SidebarIconWrapper = withProps(styled.div)` outline: none; cursor: pointer; opacity: ${props => (props.active ? 0.9 : 0.75)}; - border: 1px solid ${props => + border-left: 2px solid ${props => props.focused ? props.theme["sidebar.selection.border"] : "transparent"}; background-color: ${props => props.active ? props.theme["editor.background"] : props.theme.background}; transition: transform 0.2s ease-in; - transform: ${props => (props.active || props.focused ? "translateX(2px)" : "translateX(0px)")}; + transform: ${props => (props.active || props.focused ? "translateY(0px)" : "translateY(0px)")}; &.active { opacity: 0.75; } &:hover { - transform: translateX(2px); + transform: translateY(0px); opacity: 0.9; } ` @@ -83,6 +83,7 @@ export interface ISidebarContainerProps { export interface ISidebarWrapperProps { width: string + isActive: boolean } const SidebarWrapper = withProps(styled.div)` @@ -91,6 +92,11 @@ const SidebarWrapper = withProps(styled.div)` display: flex; flex-direction: column; + border-top: ${props => + props.isActive + ? "2px solid " + props.theme["highlight.mode.normal.background"] + : "2px solid transparent"}; + color: ${props => props.theme["sidebar.foreground"]}; width: ${props => props.width}; ` @@ -104,7 +110,7 @@ export class SidebarView extends React.PureComponent { const ids = this.props.entries.map(e => e.id) return ( - + Date: Wed, 31 Jan 2018 15:42:54 -0800 Subject: [PATCH 016/103] Welcome: Hook up Vim navigation (#1398) * Allow buffer layers to handle input * Styling cleanup * Revert hardcoding the welcome experience --- browser/src/Editor/BufferManager.ts | 43 +++- .../Editor/NeovimEditor/BufferLayerManager.ts | 4 + .../src/Editor/NeovimEditor/NeovimEditor.tsx | 12 +- .../NeovimEditor/NeovimEditorActions.ts | 4 +- .../Editor/NeovimEditor/NeovimEditorStore.ts | 4 +- .../NeovimEditor/WelcomeBufferLayer.tsx | 193 +++++++++++------- browser/src/UI/components/VimNavigator.tsx | 4 +- 7 files changed, 185 insertions(+), 79 deletions(-) diff --git a/browser/src/Editor/BufferManager.ts b/browser/src/Editor/BufferManager.ts index a6b9aa6871..b473b2e80c 100644 --- a/browser/src/Editor/BufferManager.ts +++ b/browser/src/Editor/BufferManager.ts @@ -13,6 +13,8 @@ import "rxjs/add/observable/defer" import "rxjs/add/observable/from" import "rxjs/add/operator/concatMap" +import { Store } from "redux" + import * as Oni from "oni-api" import { @@ -33,15 +35,19 @@ import { } from "./BufferHighlights" import * as Actions from "./NeovimEditor/NeovimEditorActions" +import * as State from "./NeovimEditor/NeovimEditorStore" import * as Constants from "./../Constants" import * as Log from "./../Log" +import { IBufferLayer } from "./NeovimEditor/BufferLayerManager" + export interface IBuffer extends Oni.Buffer { getCursorPosition(): Promise + handleInput(key: string): boolean } -export class Buffer implements Oni.Buffer { +export class Buffer implements IBuffer { private _id: string private _filePath: string private _language: string @@ -84,12 +90,13 @@ export class Buffer implements Oni.Buffer { constructor( private _neovimInstance: NeovimInstance, private _actions: typeof Actions, + private _store: Store, evt: EventContext, ) { this.updateFromEvent(evt) } - public addLayer(layer: Oni.EditorLayer): void { + public addLayer(layer: IBufferLayer): void { this._actions.addBufferLayer(parseInt(this._id, 10), layer) } @@ -179,6 +186,30 @@ export class Buffer implements Oni.Buffer { .toPromise() } + public handleInput(key: string): boolean { + const state = this._store.getState() + + const layers: IBufferLayer[] = state.layers[this._id] + + if (!layers || !layers.length) { + return false + } + + const result = layers.reduce((prev, curr) => { + if (prev) { + return true + } + + if (!curr || !curr.handleInput) { + return false + } else { + return curr.handleInput(key) + } + }, false) + + return result + } + public async getOrCreateHighlightGroup( highlight: SyntaxHighlighting.IHighlight | string, ): Promise { @@ -300,7 +331,11 @@ export class BufferManager { private _filePathToId: { [filePath: string]: string } = {} private _bufferList: { [id: string]: InactiveBuffer } = {} - constructor(private _neovimInstance: NeovimInstance, private _actions: typeof Actions) {} + constructor( + private _neovimInstance: NeovimInstance, + private _actions: typeof Actions, + private _store: Store, + ) {} public updateBufferFromEvent(evt: EventContext): Buffer { const id = evt.bufferNumber.toString() @@ -313,7 +348,7 @@ export class BufferManager { if (currentBuffer) { currentBuffer.updateFromEvent(evt) } else { - const buf = new Buffer(this._neovimInstance, this._actions, evt) + const buf = new Buffer(this._neovimInstance, this._actions, this._store, evt) this._idToBuffer[id] = buf } diff --git a/browser/src/Editor/NeovimEditor/BufferLayerManager.ts b/browser/src/Editor/NeovimEditor/BufferLayerManager.ts index ed3d43addd..a1e8b9b6ef 100644 --- a/browser/src/Editor/NeovimEditor/BufferLayerManager.ts +++ b/browser/src/Editor/NeovimEditor/BufferLayerManager.ts @@ -9,6 +9,10 @@ import * as Oni from "oni-api" export type BufferLayerFactory = (buf: Oni.Buffer) => Oni.EditorLayer export type BufferFilter = (buf: Oni.Buffer) => boolean +export interface IBufferLayer extends Oni.EditorLayer { + handleInput?: (key: string) => boolean +} + export const createBufferFilterFromLanguage = (language: string) => (buf: Oni.Buffer): boolean => { if (!language || language === "*") { return true diff --git a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx index 5893175fe6..1b1cd1cdb4 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx @@ -66,7 +66,7 @@ import { Workspace } from "./../../Services/Workspace" import { Editor, IEditor } from "./../Editor" -import { BufferManager } from "./../BufferManager" +import { BufferManager, IBuffer } from "./../BufferManager" import { CompletionMenu } from "./CompletionMenu" import { HoverRenderer } from "./HoverRenderer" import { NeovimPopupMenu } from "./NeovimPopupMenu" @@ -180,7 +180,7 @@ export class NeovimEditor extends Editor implements IEditor { this._contextMenuManager = new ContextMenuManager(this._toolTipsProvider, this._colors) this._neovimInstance = new NeovimInstance(100, 100, this._configuration) - this._bufferManager = new BufferManager(this._neovimInstance, this._actions) + this._bufferManager = new BufferManager(this._neovimInstance, this._actions, this._store) this._screen = new NeovimScreen() this._hoverRenderer = new HoverRenderer( @@ -795,6 +795,14 @@ export class NeovimEditor extends Editor implements IEditor { await sleep(this._configuration.getValue("debug.fakeLag.neovimInput")) } + // Check if any of the buffer layers can handle the input... + const buf: IBuffer = this.activeBuffer as IBuffer + const result = buf.handleInput(key) + + if (result) { + return + } + await this._neovimInstance.input(key) } diff --git a/browser/src/Editor/NeovimEditor/NeovimEditorActions.ts b/browser/src/Editor/NeovimEditor/NeovimEditorActions.ts index c8610b6907..4c9114869d 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditorActions.ts +++ b/browser/src/Editor/NeovimEditor/NeovimEditorActions.ts @@ -20,6 +20,8 @@ import { IConfigurationValues } from "./../../Services/Configuration" import { Errors } from "./../../Services/Diagnostics" import { IThemeColors } from "./../../Services/Themes" +import { IBufferLayer } from "./../NeovimEditor/BufferLayerManager" + export type DispatchFunction = (action: any) => void export type GetStateFunction = () => State.IState @@ -45,7 +47,7 @@ export interface IAddBufferLayerAction { type: "ADD_BUFFER_LAYER" payload: { bufferId: number - layer: Oni.EditorLayer + layer: IBufferLayer } } diff --git a/browser/src/Editor/NeovimEditor/NeovimEditorStore.ts b/browser/src/Editor/NeovimEditor/NeovimEditorStore.ts index 2ed3096fba..48d9624b0a 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditorStore.ts +++ b/browser/src/Editor/NeovimEditor/NeovimEditorStore.ts @@ -16,8 +16,10 @@ import { DefaultThemeColors, IThemeColors } from "./../../Services/Themes" import { createStore as createReduxStore } from "./../../Redux" +import { IBufferLayer } from "./../NeovimEditor/BufferLayerManager" + export interface Layers { - [id: number]: Oni.EditorLayer[] + [id: number]: IBufferLayer[] } export interface Buffers { [filePath: string]: IBuffer diff --git a/browser/src/Editor/NeovimEditor/WelcomeBufferLayer.tsx b/browser/src/Editor/NeovimEditor/WelcomeBufferLayer.tsx index 3acdf95124..76edfb1c37 100644 --- a/browser/src/Editor/NeovimEditor/WelcomeBufferLayer.tsx +++ b/browser/src/Editor/NeovimEditor/WelcomeBufferLayer.tsx @@ -13,6 +13,7 @@ import { inputManager, InputManager } from "./../../Services/InputManager" import * as Oni from "oni-api" import { withProps } from "./../../UI/components/common" +import { VimNavigator } from "./../../UI/components/VimNavigator" const WelcomeWrapper = withProps<{}>(styled.div)` background-color: ${p => p.theme["editor.background"]}; @@ -97,13 +98,25 @@ const WelcomeButtonHoverStyled = ` // box-shadow: 0 4px 8px 2px rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.1); -const WelcomeButtonWrapper = withProps<{}>(styled.div)` +export interface WelcomeButtonWrapperProps { + selected: boolean +} + +const WelcomeButtonWrapper = withProps(styled.div)` border: 0px solid ${props => props.theme.foreground}; + border-left: ${props => + props.selected + ? "4px solid " + props.theme["highlight.mode.normal.background"] + : "4px solid transparent"}; + border-right: 4px solid transparent; color: ${props => props.theme.foreground}; background-color: ${props => props.theme.background}; cursor: pointer; + transition: transform 0.25s; + transform: ${props => (props.selected ? "translateX(-4px)" : "translateX(0px)")}; + width: 100%; margin: 8px 0px; padding: 8px; @@ -137,12 +150,13 @@ export interface WelcomeButtonProps { title: string description: string command: string + selected: boolean } export class WelcomeButton extends React.PureComponent { public render(): JSX.Element { return ( - + {this.props.title} {this.props.description} @@ -185,6 +199,17 @@ export interface WelcomeViewState { import { getMetadata } from "./../../Services/Metadata" +export const ButtonIds = [ + "oni.tutor.open", + "oni.docs.open", + "oni.configuration.open", + "oni.themes.open", + "workspace.newFile", + "workspace.openFolder", + "tasks.show", + "editor.openExCommands", +] + export class WelcomeView extends React.PureComponent { constructor(props: WelcomeViewProps) { super(props) @@ -232,77 +257,105 @@ export class WelcomeView extends React.PureComponent - -
- Learn - - -
-
- Customize - - -
-
- Quick Commands - - - - -
-
+ ( + + )} + />
) } } + +export interface IWelcomeBufferLayerCommandsViewProps { + selectedId: string +} + +export class WelcomeBufferLayerCommandsView extends React.PureComponent< + IWelcomeBufferLayerCommandsViewProps, + {} +> { + public render(): JSX.Element { + return ( + +
+ Learn + + +
+
+ Customize + + +
+
+ Quick Commands + + + + +
+
+ ) + } +} diff --git a/browser/src/UI/components/VimNavigator.tsx b/browser/src/UI/components/VimNavigator.tsx index c95d97e368..6f16526063 100644 --- a/browser/src/UI/components/VimNavigator.tsx +++ b/browser/src/UI/components/VimNavigator.tsx @@ -31,6 +31,8 @@ export interface IVimNavigatorProps { onSelectionChanged?: (selectedId: string) => void render: (selectedId: string) => JSX.Element + + style?: React.CSSProperties } export interface IVimNavigatorState { @@ -79,7 +81,7 @@ export class VimNavigator extends React.PureComponent +
{this.props.render(this.state.selectedId)}
{this.props.active ? inputElement : null}
From dd949a780c5d1277d44bc39a384d4052dd4cbe81 Mon Sep 17 00:00:00 2001 From: Akin Date: Wed, 31 Jan 2018 23:46:45 +0000 Subject: [PATCH 017/103] Feature/navigate to project root (#1402) * [WIP] implementation of project root search * add module declaration for find up * add configuration settings for autodetection and project markers * switch to use change dir command * call autoDetectWorkspace on bufEnter --- .../src/Editor/NeovimEditor/NeovimEditor.tsx | 1 + .../Configuration/DefaultConfiguration.ts | 10 ++++++ .../Configuration/IConfigurationValues.ts | 3 ++ browser/src/Services/Workspace/Workspace.ts | 32 +++++++++++++++++-- browser/src/Services/Workspace/find-up.d.ts | 1 + 5 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 browser/src/Services/Workspace/find-up.d.ts diff --git a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx index 1b1cd1cdb4..0f3fbdba00 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx @@ -865,6 +865,7 @@ export class NeovimEditor extends Editor implements IEditor { private async _onBufEnter(evt: BufferEventContext): Promise { const buf = this._bufferManager.updateBufferFromEvent(evt.current) this._bufferManager.populateBufferList(evt) + this._workspace.autoDetectWorkspace(buf.filePath) const lastBuffer = this.activeBuffer if (lastBuffer && lastBuffer.filePath !== buf.filePath) { diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index 21670a503a..cc6b2873b1 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -284,6 +284,16 @@ const BaseConfiguration: IConfigurationValues = { "ui.fontSmoothing": "auto", "workspace.defaultWorkspace": null, + "workspace.autoDetectWorkspace": "noworkspace", + "workspace.autoDetectRootFiles": [ + ".git", + "node_modules", + ".svn", + "package.json", + ".hg", + ".bzr", + "build.xml", + ], } const MacConfigOverrides: Partial = { diff --git a/browser/src/Services/Configuration/IConfigurationValues.ts b/browser/src/Services/Configuration/IConfigurationValues.ts index 9bc24fd9ee..839c9522ec 100644 --- a/browser/src/Services/Configuration/IConfigurationValues.ts +++ b/browser/src/Services/Configuration/IConfigurationValues.ts @@ -16,6 +16,7 @@ export interface ITokenColorsSetting { } export type FontSmoothingOptions = "auto" | "antialiased" | "subpixel-antialiased" | "none" +export type DetectionSettings = "always" | "noworkspace" | "never" export interface IConfigurationValues { activate: (oni: Oni.Plugin.Api) => void @@ -249,6 +250,8 @@ export interface IConfigurationValues { // Path to the default workspace. The default workspace // will be opened if no workspace is specified in configuration. "workspace.defaultWorkspace": string + "workspace.autoDetectWorkspace": DetectionSettings + "workspace.autoDetectRootFiles": string[] // Handle other, non-predefined configuration keys [configurationKey: string]: any diff --git a/browser/src/Services/Workspace/Workspace.ts b/browser/src/Services/Workspace/Workspace.ts index 208181614d..38fd54bce2 100644 --- a/browser/src/Services/Workspace/Workspace.ts +++ b/browser/src/Services/Workspace/Workspace.ts @@ -6,7 +6,9 @@ */ import { remote } from "electron" +import * as findup from "find-up" import { stat } from "fs" +import * as path from "path" import { promisify } from "util" import "rxjs/add/observable/defer" @@ -50,7 +52,7 @@ export class Workspace implements IWorkspace { return this._activeWorkspace } - constructor(private _editorManager: EditorManager) { + constructor(private _editorManager: EditorManager, private _configuration: Configuration) { this._mainWindow.on("focus", () => { this._onFocusGainedEvent.dispatch(this._lastActiveBuffer) }) @@ -128,13 +130,39 @@ export class Workspace implements IWorkspace { return false } } + + public navigateToProjectRoot = async (bufferPath: string) => { + const projectMarkers = this._configuration.getValue("workspace.autoDetectRootFiles") + const cwd = path.dirname(bufferPath) + const filePath = await findup(projectMarkers, { cwd }) + if (filePath) { + const dir = path.dirname(filePath) + this.changeDirectory(dir) + } + } + + public autoDetectWorkspace(filePath: string): void { + const settings = this._configuration.getValue("workspace.autoDetectWorkspace") + switch (settings) { + case "never": + break + case "always": + this.navigateToProjectRoot(filePath) + break + case "noworkspace": + default: + if (!this._activeWorkspace) { + this.navigateToProjectRoot(filePath) + } + } + } } let _workspace: Workspace = null let _workspaceConfiguration: WorkspaceConfiguration = null export const activate = (configuration: Configuration, editorManager: EditorManager): void => { - _workspace = new Workspace(editorManager) + _workspace = new Workspace(editorManager, configuration) _workspaceConfiguration = new WorkspaceConfiguration(configuration, _workspace) diff --git a/browser/src/Services/Workspace/find-up.d.ts b/browser/src/Services/Workspace/find-up.d.ts new file mode 100644 index 0000000000..67d5de0d7d --- /dev/null +++ b/browser/src/Services/Workspace/find-up.d.ts @@ -0,0 +1 @@ +declare module "find-up" From 0c6e0822a254efa3afa033f90a2949b528cb4ced Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 31 Jan 2018 17:30:03 -0800 Subject: [PATCH 018/103] Explorer: Empty Experience (#1410) * Add SidebarEmptyPaneView.tsx * Incorporate empty view with explorer * Fix up styling of empty view * Sneakify empty experience button * Fix lint issues --- browser/src/Input/KeyBindings.ts | 2 +- browser/src/Services/CommandManager.ts | 3 +- .../src/Services/Explorer/ExplorerSplit.tsx | 6 - .../src/Services/Explorer/ExplorerView.tsx | 15 +++ .../UI/components/SidebarEmptyPaneView.tsx | 106 ++++++++++++++++++ browser/src/UI/components/VimNavigator.tsx | 15 ++- 6 files changed, 137 insertions(+), 10 deletions(-) create mode 100644 browser/src/UI/components/SidebarEmptyPaneView.tsx diff --git a/browser/src/Input/KeyBindings.ts b/browser/src/Input/KeyBindings.ts index 6b0314cdc1..191fa7a791 100644 --- a/browser/src/Input/KeyBindings.ts +++ b/browser/src/Input/KeyBindings.ts @@ -103,8 +103,8 @@ export const applyDefaultKeyBindings = (oni: Oni.Plugin.Api, config: Configurati input.bind(["", ""], "menu.previous") input.bind(["", "", ""], "menu.close") input.bind("", "menu.select") + input.bind(["", ""], "select") - input.bind("", "explorer.open") input.bind("", "explorer.delete") // TODO: Scope 's' to just the local window diff --git a/browser/src/Services/CommandManager.ts b/browser/src/Services/CommandManager.ts index 27ff00e6c4..816fd49f04 100644 --- a/browser/src/Services/CommandManager.ts +++ b/browser/src/Services/CommandManager.ts @@ -48,8 +48,7 @@ export class CommandManager implements ITaskProvider { public registerCommand(command: Oni.Commands.ICommand): void { if (this._commandDictionary[command.command]) { - Log.error(`Tried to register multiple commands for: ${command.name}`) - return + Log.verbose(`Overwriting existing command: ${command.command}`) } this._commandDictionary[command.command] = command diff --git a/browser/src/Services/Explorer/ExplorerSplit.tsx b/browser/src/Services/Explorer/ExplorerSplit.tsx index ef8afb750c..c44b2d173b 100644 --- a/browser/src/Services/Explorer/ExplorerSplit.tsx +++ b/browser/src/Services/Explorer/ExplorerSplit.tsx @@ -70,9 +70,6 @@ export class ExplorerSplit { public enter(): void { this._store.dispatch({ type: "ENTER" }) - this._commandManager.registerCommand( - new CallbackCommand("explorer.open", null, null, () => this._onOpenItem()), - ) this._commandManager.registerCommand( new CallbackCommand("explorer.delete", null, null, () => this._onDeleteItem()), ) @@ -82,9 +79,6 @@ export class ExplorerSplit { public leave(): void { this._store.dispatch({ type: "LEAVE" }) - - this._commandManager.unregisterCommand("explorer.open") - this._commandManager.unregisterCommand("explorer.delete") } public render(): JSX.Element { diff --git a/browser/src/Services/Explorer/ExplorerView.tsx b/browser/src/Services/Explorer/ExplorerView.tsx index c79150ad01..1f32c651be 100644 --- a/browser/src/Services/Explorer/ExplorerView.tsx +++ b/browser/src/Services/Explorer/ExplorerView.tsx @@ -164,17 +164,32 @@ export interface IExplorerViewProps extends IExplorerViewContainerProps { isActive: boolean } +import { SidebarEmptyPaneView } from "./../../UI/components/SidebarEmptyPaneView" import { Sneakable } from "./../../UI/components/Sneakable" +import { commandManager } from "./../CommandManager" + export class ExplorerView extends React.PureComponent { public render(): JSX.Element { const ids = this.props.nodes.map(node => node.id) + if (!this.props.nodes || !this.props.nodes.length) { + return ( + commandManager.executeCommand("workspace.openFolder")} + /> + ) + } + return ( this.props.onClick(id)} render={(selectedId: string) => { const nodes = this.props.nodes.map(node => ( this.props.onClick(node.id)}> diff --git a/browser/src/UI/components/SidebarEmptyPaneView.tsx b/browser/src/UI/components/SidebarEmptyPaneView.tsx new file mode 100644 index 0000000000..052a08e80c --- /dev/null +++ b/browser/src/UI/components/SidebarEmptyPaneView.tsx @@ -0,0 +1,106 @@ +/** + * SidebarEmptyPaneView.tsx + */ + +import * as React from "react" +import styled from "styled-components" + +export interface ISidebarEmptyPaneViewProps { + active: boolean + contentsText: string + actionButtonText?: string + onClickButton?: () => void +} + +const Wrapper = styled.div` + border-top: 1px solid ${props => props.theme.background}; + + display: flex; + flex-direction: column; + justify-content: center; +` + +import { boxShadow, withProps } from "./common" + +const ButtonWrapper = styled.button` + background-color: ${props => props.theme.background}; + color: ${props => props.theme.foreground}; + padding: 1em; + border: 2px solid transparent; + width: 100%; + outline: none; + cursor: pointer; + transition: all 0.1s ease-in; + + &:hover { + ${boxShadow} transform: translateY(-1px); + } +` + +const Description = styled.div` + margin: 32px; + font-size: 0.9em; + text-align: center; +` + +export interface ButtonContainerProps { + selected: boolean +} + +const ButtonContainer = withProps(styled.div)` + padding-left: 32px; + padding-right: 32px; + + transition: all 0.1s ease-in; + + background-color: ${props => (props.selected ? "rgba(0, 0, 0, 0.1)" : "transparent")}; + border-left: 2px solid ${props => + props.selected ? props.theme["highlight.mode.normal.background"] : "transparent"}; +` + +import { Sneakable } from "./Sneakable" +import { VimNavigator } from "./VimNavigator" + +export interface IOniButtonProps { + text: string + onClick: () => void +} + +export class OniButton extends React.PureComponent { + public render(): JSX.Element { + return ( + + + {this.props.text} + + + ) + } +} + +export class SidebarEmptyPaneView extends React.PureComponent { + public render(): JSX.Element { + const button = this.props.actionButtonText ? ( + this.props.onClickButton && this.props.onClickButton()} + /> + ) : null + + return ( + this.props.onClickButton && this.props.onClickButton()} + render={(selectedId: string) => { + return ( + + {this.props.contentsText} + {button} + + ) + }} + /> + ) + } +} diff --git a/browser/src/UI/components/VimNavigator.tsx b/browser/src/UI/components/VimNavigator.tsx index 6f16526063..fc7710cde8 100644 --- a/browser/src/UI/components/VimNavigator.tsx +++ b/browser/src/UI/components/VimNavigator.tsx @@ -17,6 +17,8 @@ import { Event } from "oni-types" import { KeyboardInputView } from "./../../Input/KeyboardInput" import { getInstance, IMenuBinding } from "./../../neovim/SharedNeovimInstance" +import { CallbackCommand, commandManager } from "./../../Services/CommandManager" + import * as Log from "./../../Log" export interface IVimNavigatorProps { @@ -29,6 +31,7 @@ export interface IVimNavigatorProps { // onLeave: IEvent onSelectionChanged?: (selectedId: string) => void + onSelected?: (selectedId: string) => void render: (selectedId: string) => JSX.Element @@ -47,7 +50,7 @@ export class VimNavigator extends React.PureComponent 0 ? props.ids[0] : null, } } @@ -101,12 +104,22 @@ export class VimNavigator extends React.PureComponent this._select()), + ) + this._activeBinding.onCursorMoved.subscribe(newValue => { Log.info("[VimNavigator::onCursorMoved] - " + newValue) From 36e744f36cc7d3617431af3e4e1d983afd0f455a Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 31 Jan 2018 18:40:33 -0800 Subject: [PATCH 019/103] Use larger screenshot (#1411) --- test/demo/HeroScreenshot.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/demo/HeroScreenshot.ts b/test/demo/HeroScreenshot.ts index fa1feb50a9..09f9021752 100644 --- a/test/demo/HeroScreenshot.ts +++ b/test/demo/HeroScreenshot.ts @@ -27,7 +27,7 @@ export const test = async (oni: any) => { window.alert = myText => (lastAlertText = myText) // Use the `Completion.ts` file as the screenshot source - remote.getCurrentWindow().setSize(800, 600) + remote.getCurrentWindow().setSize(1200, 800) const outputPath = getDistPath() From 6152cd46c4a4f63ccdc5892ad5cde44bf03f746d Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Thu, 1 Feb 2018 12:11:13 -0800 Subject: [PATCH 020/103] Update theming for textinput components (#1417) --- browser/src/Services/Language/RenameView.tsx | 20 ++++++++--- browser/src/Services/Menu/MenuComponent.tsx | 35 ++++++++----------- browser/src/Services/Sneak.tsx | 2 -- browser/src/UI/components/LightweightText.tsx | 28 +-------------- 4 files changed, 31 insertions(+), 54 deletions(-) diff --git a/browser/src/Services/Language/RenameView.tsx b/browser/src/Services/Language/RenameView.tsx index 2caa00ff37..0fc5a8fa69 100644 --- a/browser/src/Services/Language/RenameView.tsx +++ b/browser/src/Services/Language/RenameView.tsx @@ -6,19 +6,31 @@ import * as React from "react" -import { TextInput } from "./../../UI/components/LightweightText" +import styled from "styled-components" + +import { TextInputView } from "./../../UI/components/LightweightText" export interface IRenameViewProps { tokenName: string onComplete: (val: string) => void } +const ToolTipWrapper = styled.div` + background-color: ${props => props.theme["toolTip.background"]}; + color: ${props => props.theme["toolTip.foreground"]}; + + input { + background-color: ${props => props.theme["toolTip.background"]}; + color: ${props => props.theme["toolTip.foreground"]}; + } +` + export class RenameView extends React.PureComponent { public render(): JSX.Element { return ( -
- -
+ + + ) } } diff --git a/browser/src/Services/Menu/MenuComponent.tsx b/browser/src/Services/Menu/MenuComponent.tsx index eb8f126d8a..8ceac4f8aa 100644 --- a/browser/src/Services/Menu/MenuComponent.tsx +++ b/browser/src/Services/Menu/MenuComponent.tsx @@ -32,11 +32,18 @@ export interface IMenuProps { rowHeight: number maxItemsToShow: number - - backgroundColor: string - foregroundColor: string } +const MenuStyleWrapper = styled.div` + background-color: ${props => props.theme["menu.background"]}; + color: ${props => props.theme["menu.foreground"]}; + + & input { + color: ${props => props.theme["menu.foreground"]}; + background-color: rgba(0, 0, 0.2); + } +` + export class MenuView extends React.PureComponent { private _inputElement: HTMLInputElement = null @@ -66,11 +73,6 @@ export class MenuView extends React.PureComponent { ) } - const menuStyle = { - backgroundColor: this.props.backgroundColor, - color: this.props.foregroundColor, - } - const footerClassName = "footer " + (this.props.isLoading ? "loading" : "loaded") const height = @@ -78,13 +80,8 @@ export class MenuView extends React.PureComponent { return (
-
- this._onChange(evt)} - /> + + this._onChange(evt)} />
@@ -101,7 +98,7 @@ export class MenuView extends React.PureComponent {
-
+
{ />
-
+
) } @@ -128,8 +125,6 @@ const NullProps: any = { selectedIndex: 0, filterText: "", items: EmptyArray, - backgroundColor: "black", - foregroundColor: "white", onSelect: noop, isLoading: true, rowHeight: 0, @@ -148,8 +143,6 @@ const mapStateToProps = ( selectedIndex: popupMenu.selectedIndex, filterText: popupMenu.filter, items: popupMenu.filteredOptions, - backgroundColor: popupMenu.backgroundColor, - foregroundColor: popupMenu.foregroundColor, onSelect: popupMenu.onSelectItem, isLoading: popupMenu.isLoading, rowHeight: state.configuration.rowHeight, diff --git a/browser/src/Services/Sneak.tsx b/browser/src/Services/Sneak.tsx index 82bd298251..2b225d32a8 100644 --- a/browser/src/Services/Sneak.tsx +++ b/browser/src/Services/Sneak.tsx @@ -156,8 +156,6 @@ export class SneakView extends React.PureComponent { this.setState({ filterText: evt.currentTarget.value }) }} - backgroundColor={"black"} - foregroundColor={"white"} />
{sneaks} diff --git a/browser/src/UI/components/LightweightText.tsx b/browser/src/UI/components/LightweightText.tsx index f584353c49..58b9610279 100644 --- a/browser/src/UI/components/LightweightText.tsx +++ b/browser/src/UI/components/LightweightText.tsx @@ -1,7 +1,4 @@ import * as React from "react" -import { connect } from "react-redux" - -import * as State from "./../Shell/ShellState" import { focusManager } from "./../../Services/FocusManager" @@ -10,16 +7,10 @@ export interface ITextInputViewProps { onChange?: (evt: React.ChangeEvent) => void defaultValue?: string - - backgroundColor: string - foregroundColor: string - - overrideDefaultStyle?: boolean } // TODO: Is there a better value for this? const WordRegex = /[$_a-zA-Z0-9]/i -const EmptyStyle: React.CSSProperties = {} /** * TextInputView is a lightweight input control, that implements some @@ -35,17 +26,8 @@ export class TextInputView extends React.PureComponent } public render(): JSX.Element { - const containerStyle: React.CSSProperties = this.props.overrideDefaultStyle - ? EmptyStyle - : { - padding: "4px", - border: "1px solid " + this.props.foregroundColor, - } - const inputStyle: React.CSSProperties = { outline: "none", - color: this.props.foregroundColor, - backgroundColor: this.props.backgroundColor, border: "0px", transform: "translateY(0px)", } @@ -53,7 +35,7 @@ export class TextInputView extends React.PureComponent const defaultValue = this.props.defaultValue || "" return ( -
+
} } } - -const mapStateToProps = (state: State.IState, originalProps?: Partial) => ({ - ...originalProps, - backgroundColor: state.colors["editor.background"], - foregroundColor: state.colors["editor.foreground"], -}) - -export const TextInput = connect(mapStateToProps)(TextInputView) From a913dd1902413d99ceb68454eaffe4bc1dd267ab Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Thu, 1 Feb 2018 12:11:24 -0800 Subject: [PATCH 021/103] Fix gap at top of sidebar (#1418) --- browser/src/Services/Sidebar/SidebarView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/src/Services/Sidebar/SidebarView.tsx b/browser/src/Services/Sidebar/SidebarView.tsx index b4b6b26656..7ddec712db 100644 --- a/browser/src/Services/Sidebar/SidebarView.tsx +++ b/browser/src/Services/Sidebar/SidebarView.tsx @@ -95,7 +95,7 @@ const SidebarWrapper = withProps(styled.div)` border-top: ${props => props.isActive ? "2px solid " + props.theme["highlight.mode.normal.background"] - : "2px solid transparent"}; + : "2px solid " + props.theme["editor.background"]}; color: ${props => props.theme["sidebar.foreground"]}; width: ${props => props.width}; From 87356ed6936e03eee3121a22ca5a03ccc8519c68 Mon Sep 17 00:00:00 2001 From: Akin Date: Thu, 1 Feb 2018 22:25:14 +0000 Subject: [PATCH 022/103] rename command in statusbar to open statusbar (#1421) --- vim/core/oni-core-statusbar/index.js | 58 ++++++++++++++++------------ 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/vim/core/oni-core-statusbar/index.js b/vim/core/oni-core-statusbar/index.js index 10d5a07adf..3428a3d26c 100644 --- a/vim/core/oni-core-statusbar/index.js +++ b/vim/core/oni-core-statusbar/index.js @@ -2,23 +2,23 @@ const path = require("path") const rgb = (r, g, b) => `rgb(${r}, ${g}, ${b})` -const activate = (Oni) => { +const activate = Oni => { const React = Oni.dependencies.React const items = Oni.configuration.getValue("statusbar.priority", {}) const ids = Object.keys(items) - const mode = ids.find(id => id.includes('mode')); - const linenumber = ids.find(id => id.includes('linenumber')); - const dir = ids.find(id => id.includes('workingDir')); - const gitHubRepo = ids.find(id => id.includes('gitHubRepo')); + const mode = ids.find(id => id.includes("mode")) + const linenumber = ids.find(id => id.includes("linenumber")) + const dir = ids.find(id => id.includes("workingDir")) + const gitHubRepo = ids.find(id => id.includes("gitHubRepo")) const workingDirectoryItem = Oni.statusBar.createItem(0, dir) const lineNumberItem = Oni.statusBar.createItem(1, linenumber) const modeItem = Oni.statusBar.createItem(1, mode) const gitHubRepoItem = Oni.statusBar.createItem(1, gitHubRepo) - const setMode = (mode) => { - const getBackgroundColorForMode = (m) => { + const setMode = mode => { + const getBackgroundColorForMode = m => { switch (m) { case "insert": case "replace": @@ -32,7 +32,7 @@ const activate = (Oni) => { } } - const getForegroundColorForMode = (m) => { + const getForegroundColorForMode = m => { switch (m) { case "insert": case "replace": @@ -46,7 +46,7 @@ const activate = (Oni) => { } } - const parseMode = (m) => { + const parseMode = m => { // Need to change modes like `cmdline_insert` if (m.indexOf("_") >= 0) { return m.split("_")[1] @@ -59,15 +59,19 @@ const activate = (Oni) => { width: "100%", height: "100%", display: "flex", - "alignItems": "center", - "paddingLeft": "8px", - "paddingRight": "8px", - "textTransform": "uppercase", + alignItems: "center", + paddingLeft: "8px", + paddingRight: "8px", + textTransform: "uppercase", color: getForegroundColorForMode(mode), - backgroundColor: getBackgroundColorForMode(mode) + backgroundColor: getBackgroundColorForMode(mode), } - const modeElement = React.createElement("div", { style, className: "mode" }, parseMode(mode)) + const modeElement = React.createElement( + "div", + { style, className: "mode" }, + parseMode(mode), + ) modeItem.setContents(modeElement) } @@ -76,16 +80,20 @@ const activate = (Oni) => { lineNumberItem.setContents(element) } - const setWorkingDirectory = (workingDirectory) => { + const setWorkingDirectory = workingDirectory => { if (!workingDirectory) { workingDirectory = "" } const openFolderCommand = () => { - Oni.commands.executeCommand("oni.openFolder") + Oni.commands.executeCommand("workspace.openFolder") } - const element = React.createElement("div", { style: { color: "rgb(140, 140, 140)" }, onClick: openFolderCommand }, workingDirectory) + const element = React.createElement( + "div", + { style: { color: "rgb(140, 140, 140)" }, onClick: openFolderCommand }, + workingDirectory, + ) workingDirectoryItem.setContents(element) } @@ -95,23 +103,23 @@ const activate = (Oni) => { } const gitHubIcon = Oni.ui.createIcon({ - name: 'github', - size: Oni.ui.iconSize.Default, - }); + name: "github", + size: Oni.ui.iconSize.Default, + }) const element = React.createElement("div", { onClick: openGitHubRepoCommand }, gitHubIcon) gitHubRepoItem.setContents(element) } - Oni.editors.activeEditor.onModeChanged.subscribe((newMode) => { + Oni.editors.activeEditor.onModeChanged.subscribe(newMode => { setMode(newMode) }) - Oni.editors.activeEditor.onCursorMoved.subscribe((cursor) => { + Oni.editors.activeEditor.onCursorMoved.subscribe(cursor => { setLineNumber(cursor.line + 1, cursor.column + 1) }) - Oni.workspace.onDirectoryChanged.subscribe((newDirectory) => { + Oni.workspace.onDirectoryChanged.subscribe(newDirectory => { setWorkingDirectory(newDirectory) }) @@ -128,5 +136,5 @@ const activate = (Oni) => { } module.exports = { - activate + activate, } From 8b8a5257a856ac2e1ec0a807103c287a3e3093ba Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Thu, 1 Feb 2018 15:13:05 -0800 Subject: [PATCH 023/103] Refactoring: Push some common commit / cancel handling into the TextInputView (#1420) * Refactor TextInputView to explicitly handle textbox * Fix lint issues --- browser/src/Editor/NeovimEditor/Rename.tsx | 1 + browser/src/Input/KeyBindings.ts | 2 -- browser/src/Services/FocusManager.ts | 2 +- browser/src/Services/Language/RenameView.tsx | 1 + browser/src/UI/components/LightweightText.tsx | 22 +++++++++++++++++-- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/browser/src/Editor/NeovimEditor/Rename.tsx b/browser/src/Editor/NeovimEditor/Rename.tsx index 46f7d8de48..bbc8664500 100644 --- a/browser/src/Editor/NeovimEditor/Rename.tsx +++ b/browser/src/Editor/NeovimEditor/Rename.tsx @@ -52,6 +52,7 @@ export class Rename { this._toolTipsProvider.showToolTip( _renameToolTipName, this.cancelRename()} onComplete={newValue => this._onRenameClosed(newValue)} tokenName={activeToken.tokenName} />, diff --git a/browser/src/Input/KeyBindings.ts b/browser/src/Input/KeyBindings.ts index 191fa7a791..27686769d9 100644 --- a/browser/src/Input/KeyBindings.ts +++ b/browser/src/Input/KeyBindings.ts @@ -63,8 +63,6 @@ export const applyDefaultKeyBindings = (oni: Oni.Plugin.Api, config: Configurati } input.bind("", "editor.rename", () => isNormalMode()) - input.bind("", "editor.rename.cancel") - input.bind("", "editor.rename.commit") input.bind("", "language.format") input.bind([""], "language.gotoDefinition", () => isNormalMode() && !menu.isMenuOpen()) diff --git a/browser/src/Services/FocusManager.ts b/browser/src/Services/FocusManager.ts index ae0545a865..9671789883 100644 --- a/browser/src/Services/FocusManager.ts +++ b/browser/src/Services/FocusManager.ts @@ -10,7 +10,7 @@ class FocusManager { public pushFocus(element: HTMLElement) { this._focusElementStack = [element, ...this._focusElementStack] - element.focus() + window.setTimeout(() => this.enforceFocus(), 0) } public popFocus(element: HTMLElement) { diff --git a/browser/src/Services/Language/RenameView.tsx b/browser/src/Services/Language/RenameView.tsx index 0fc5a8fa69..d9a1e7d20c 100644 --- a/browser/src/Services/Language/RenameView.tsx +++ b/browser/src/Services/Language/RenameView.tsx @@ -13,6 +13,7 @@ import { TextInputView } from "./../../UI/components/LightweightText" export interface IRenameViewProps { tokenName: string onComplete: (val: string) => void + onCancel: () => void } const ToolTipWrapper = styled.div` diff --git a/browser/src/UI/components/LightweightText.tsx b/browser/src/UI/components/LightweightText.tsx index 58b9610279..70148ded5e 100644 --- a/browser/src/UI/components/LightweightText.tsx +++ b/browser/src/UI/components/LightweightText.tsx @@ -3,6 +3,7 @@ import * as React from "react" import { focusManager } from "./../../Services/FocusManager" export interface ITextInputViewProps { + onCancel?: () => void onComplete?: (result: string) => void onChange?: (evt: React.ChangeEvent) => void @@ -35,7 +36,7 @@ export class TextInputView extends React.PureComponent const defaultValue = this.props.defaultValue || "" return ( -
+
onKeyDown={evt => this._onKeyDown(evt)} onChange={evt => this._onChange(evt)} onFocus={evt => evt.currentTarget.select()} - ref={elem => (this._element = elem)} + ref={elem => { + this._element = elem + }} />
) @@ -66,9 +69,24 @@ export class TextInputView extends React.PureComponent } } + private _cancel(): void { + if (this.props.onCancel) { + this.props.onCancel() + } + } + private _onKeyDown(keyboardEvent: React.KeyboardEvent): void { + if (keyboardEvent.keyCode === 27) { + this._cancel() + return + } + if (this._element && keyboardEvent.ctrlKey) { switch (keyboardEvent.key) { + case "[": + case "c": + this._cancel() + break case "u": { this._element.value = "" break From 216d1aaf48fa6d93f6f654708938532ff00ff9c2 Mon Sep 17 00:00:00 2001 From: Akin Date: Fri, 2 Feb 2018 00:33:49 +0000 Subject: [PATCH 024/103] Bugfix/window number error removing bufferbar highlight (#1419) * add errorboundary to editor component and handle no window no * add comment re how proceed in future * tweak fix to filter original array for falsies --- .../src/Editor/NeovimEditor/NeovimEditor.tsx | 29 ++++++++++--------- .../src/Editor/NeovimEditor/NeovimSurface.tsx | 7 +++++ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx index 0f3fbdba00..f410d701e7 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx @@ -305,7 +305,8 @@ export class NeovimEditor extends Editor implements IEditor { }) this._windowManager.onWindowStateChanged.subscribe(tabPageState => { - const inactiveIds = tabPageState.inactiveWindows.map(w => w.windowNumber) + const filteredTabState = tabPageState.inactiveWindows.filter(w => !!w) + const inactiveIds = filteredTabState.map(w => w.windowNumber) this._actions.setActiveVimTabPage(tabPageState.tabId, [ tabPageState.activeWindow.windowNumber, @@ -313,19 +314,21 @@ export class NeovimEditor extends Editor implements IEditor { ]) const { activeWindow } = tabPageState - this._actions.setWindowState( - activeWindow.windowNumber, - activeWindow.bufferId, - activeWindow.bufferFullPath, - activeWindow.column, - activeWindow.line, - activeWindow.bottomBufferLine, - activeWindow.topBufferLine, - activeWindow.dimensions, - activeWindow.bufferToScreen, - ) + if (activeWindow) { + this._actions.setWindowState( + activeWindow.windowNumber, + activeWindow.bufferId, + activeWindow.bufferFullPath, + activeWindow.column, + activeWindow.line, + activeWindow.bottomBufferLine, + activeWindow.topBufferLine, + activeWindow.dimensions, + activeWindow.bufferToScreen, + ) + } - tabPageState.inactiveWindows.map(w => { + filteredTabState.map(w => { this._actions.setInactiveWindowState(w.windowNumber, w.dimensions) }) }) diff --git a/browser/src/Editor/NeovimEditor/NeovimSurface.tsx b/browser/src/Editor/NeovimEditor/NeovimSurface.tsx index 817159fe1d..355e65d4b9 100644 --- a/browser/src/Editor/NeovimEditor/NeovimSurface.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimSurface.tsx @@ -45,6 +45,13 @@ export interface INeovimSurfaceProps { } export class NeovimSurface extends React.PureComponent { + public componentDidCatch(e: Error) { + // TODO Add an Error Page to inform user of how to proceed e.g. file bug report + // also pass error detais so user can file those + // tslint:disable-next-line + console.warn(`Error mounting the Neovim editor because`, e) + } + public render(): JSX.Element { return (
From a254186c23eb863ba23cf74abc50766501440902 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Thu, 1 Feb 2018 18:11:46 -0800 Subject: [PATCH 025/103] Automation: Change screenshot automation to navigate to root directory (#1416) * Change screenshot automation to navigate to root directory * Log automation dir * Fix logging for screenshot output * Set recorder output path after switching workspace --- test/demo/HeroScreenshot.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/demo/HeroScreenshot.ts b/test/demo/HeroScreenshot.ts index 09f9021752..0b64343a57 100644 --- a/test/demo/HeroScreenshot.ts +++ b/test/demo/HeroScreenshot.ts @@ -10,6 +10,8 @@ import { remote } from "electron" import { getDistPath, getRootPath } from "./DemoCommon" +// tslint:disable:no-console + const getCompletionElement = () => { const elements = document.body.getElementsByClassName("autocompletion") @@ -31,7 +33,7 @@ export const test = async (oni: any) => { const outputPath = getDistPath() - oni.configuration.setValues({ "recorder.outputPath": outputPath }) + await oni.workspace.changeDirectory(getRootPath()) const filePath = path.join( getRootPath(), @@ -71,7 +73,10 @@ export const test = async (oni: any) => { await oni.automation.sleep(500) + oni.configuration.setValues({ "recorder.outputPath": outputPath }) + oni.recorder.takeScreenshot(`screenshot-${process.platform}.png`) await oni.automation.waitFor(() => lastAlertText !== null, 20000) + console.log("Alert text (screenshot output path): " + lastAlertText) } From cd417d3d3fe10cab7f837377cec41971a3a1a6c4 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Thu, 1 Feb 2018 18:39:23 -0800 Subject: [PATCH 026/103] Fix regression in enter/space keys (#1423) --- browser/src/UI/components/VimNavigator.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/browser/src/UI/components/VimNavigator.tsx b/browser/src/UI/components/VimNavigator.tsx index fc7710cde8..3fc967f438 100644 --- a/browser/src/UI/components/VimNavigator.tsx +++ b/browser/src/UI/components/VimNavigator.tsx @@ -117,7 +117,13 @@ export class VimNavigator extends React.PureComponent this._select()), + new CallbackCommand( + "select", + null, + null, + () => this._select(), + () => this.props.active, + ), ) this._activeBinding.onCursorMoved.subscribe(newValue => { From 2182e62814465da418171c10a94808091b3be02d Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Thu, 1 Feb 2018 19:29:28 -0800 Subject: [PATCH 027/103] Upgrade electron to 1.8.2-beta5 (#1422) --- package.json | 4 ++-- yarn.lock | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 479c6cb034..425e43abe5 100644 --- a/package.json +++ b/package.json @@ -255,7 +255,7 @@ "coveralls": "^3.0.0", "cross-env": "3.1.3", "css-loader": "0.28.4", - "electron": "1.8.1", + "electron": "^1.8.2-beta.5", "electron-builder": "19.46.4", "electron-devtools-installer": "2.2.1", "electron-mocha": "5.0.0", @@ -284,9 +284,9 @@ "pretty-quick": "^1.2.2", "react-hot-loader": "1.3.1", "react-motion": "0.5.2", - "react-virtualized": "^9.18.0", "react-redux": "5.0.6", "react-transition-group": "2.2.1", + "react-virtualized": "^9.18.0", "redux": "3.7.2", "redux-observable": "0.17.0", "redux-thunk": "2.2.0", diff --git a/yarn.lock b/yarn.lock index 2e50e7c214..9459dda41f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2200,9 +2200,9 @@ electron-window@^0.8.0: dependencies: is-electron-renderer "^2.0.0" -electron@1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/electron/-/electron-1.8.1.tgz#19b6f39f2013e204a91a60bc3086dc7a4a07ed88" +electron@^1.8.2-beta.5: + version "1.8.2-beta.5" + resolved "https://registry.yarnpkg.com/electron/-/electron-1.8.2-beta.5.tgz#8324c483ed8cb4b052b3e13e514ddc858707fdeb" dependencies: "@types/node" "^8.0.24" electron-download "^3.0.1" From 189ce95887ea7ef31e151463f4ab7616bee9d32c Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Fri, 2 Feb 2018 09:52:13 -0800 Subject: [PATCH 028/103] [WIP] Bookmarks Pane (#1388) Bookmarks Pane --- .../src/Services/Bookmarks/BookmarksPane.tsx | 128 ++++++++++++++++++ browser/src/Services/Bookmarks/index.ts | 90 ++++++++++++ browser/src/Services/Sidebar/index.ts | 5 +- browser/src/UI/components/SidebarItemView.tsx | 77 +++++++++++ browser/src/index.tsx | 3 + 5 files changed, 300 insertions(+), 3 deletions(-) create mode 100644 browser/src/Services/Bookmarks/BookmarksPane.tsx create mode 100644 browser/src/Services/Bookmarks/index.ts create mode 100644 browser/src/UI/components/SidebarItemView.tsx diff --git a/browser/src/Services/Bookmarks/BookmarksPane.tsx b/browser/src/Services/Bookmarks/BookmarksPane.tsx new file mode 100644 index 0000000000..486f171c9e --- /dev/null +++ b/browser/src/Services/Bookmarks/BookmarksPane.tsx @@ -0,0 +1,128 @@ +/** + * BookmarksPane.tsx + * + * UX for rendering the bookmarks experience in the sidebar + */ + +import * as React from "react" + +import { Event, IDisposable, IEvent } from "oni-types" + +import { SidebarPane } from "./../Sidebar" +import { IBookmark, IBookmarksProvider } from "./index" + +import { SidebarEmptyPaneView } from "./../../UI/components/SidebarEmptyPaneView" +import { SidebarItemView } from "./../../UI/components/SidebarItemView" +import { VimNavigator } from "./../../UI/components/VimNavigator" + +export class BookmarksPane implements SidebarPane { + private _onEnter = new Event() + private _onLeave = new Event() + + constructor(private _bookmarksProvider: IBookmarksProvider) {} + + public get id(): string { + return "oni.sidebar.bookmarks" + } + + public get title(): string { + return "Bookmarks" + } + + public enter(): void { + this._onEnter.dispatch() + } + + public leave(): void { + this._onLeave.dispatch() + } + + public render(): JSX.Element { + return ( + + ) + } +} + +export interface IBookmarksPaneViewProps { + bookmarksProvider: IBookmarksProvider + onEnter: IEvent + onLeave: IEvent +} + +export interface IBookmarksPaneViewState { + bookmarks: IBookmark[] + isActive: boolean +} + +export class BookmarksPaneView extends React.PureComponent< + IBookmarksPaneViewProps, + IBookmarksPaneViewState +> { + private _subscriptions: IDisposable[] = [] + + constructor(props: IBookmarksPaneViewProps) { + super(props) + this.state = { + bookmarks: this.props.bookmarksProvider.bookmarks, + isActive: false, + } + } + + public componentDidMount(): void { + this._clearExistingSubscriptions() + + const s1 = this.props.bookmarksProvider.onBookmarksUpdated.subscribe(() => { + this.setState({ + bookmarks: this.props.bookmarksProvider.bookmarks, + }) + }) + + const s2 = this.props.onEnter.subscribe(() => this.setState({ isActive: true })) + const s3 = this.props.onLeave.subscribe(() => this.setState({ isActive: false })) + + this._subscriptions = [s1, s2, s3] + } + + public componentWillUnmount(): void { + this._clearExistingSubscriptions() + } + + public render(): JSX.Element { + if (this.state.bookmarks.length === 0) { + return ( + + ) + } else { + return ( + { + const elems = this.state.bookmarks.map(bm => ( + + )) + return
{elems}
+ }} + /> + ) + } + } + + private _clearExistingSubscriptions(): void { + this._subscriptions.forEach(sub => sub.dispose()) + this._subscriptions = [] + } +} diff --git a/browser/src/Services/Bookmarks/index.ts b/browser/src/Services/Bookmarks/index.ts new file mode 100644 index 0000000000..de826240e1 --- /dev/null +++ b/browser/src/Services/Bookmarks/index.ts @@ -0,0 +1,90 @@ +import { Event, IEvent } from "oni-types" + +import { Configuration } from "./../Configuration" +import { SidebarManager } from "./../Sidebar" + +import { BookmarksPane } from "./BookmarksPane" + +export interface IBookmark { + command: string + arguments: any[] + group: string +} + +import * as fs from "fs" +import * as Log from "./../../Log" + +export interface IBookmarksProvider { + bookmarks: IBookmark[] + onBookmarksUpdated: IEvent +} + +export class ConfigurationBookmarksProvider implements IBookmarksProvider { + private _bookmarks: IBookmark[] = [] + private _onBookmarksUpdatedEvent = new Event() + + public get bookmarks(): IBookmark[] { + return this._bookmarks + } + + public get onBookmarksUpdated(): IEvent { + return this._onBookmarksUpdatedEvent + } + + constructor(private _configuration: Configuration) { + this._configuration.onConfigurationChanged.subscribe(newValues => { + if (newValues["oni.bookmarks"]) { + this._updateFromConfiguration(newValues["oni.bookmarks"]) + } + }) + + const currentBookmarks = this._configuration.getValue("oni.bookmarks") + this._updateFromConfiguration(currentBookmarks) + } + + private _updateBookmarks(bookmarks: IBookmark[]): void { + this._bookmarks = bookmarks + this._onBookmarksUpdatedEvent.dispatch() + } + + private _updateFromConfiguration(bookmarks: string[]): void { + if (!bookmarks || !bookmarks.length) { + this._updateBookmarks([]) + return + } + + try { + const newBookmarks = bookmarks.filter(bm => fs.existsSync(bm)).map(bm => { + const stat = fs.statSync(bm) + + if (stat.isDirectory()) { + return { + command: "oni.openFolder", + arguments: [bm], + group: "Workspaces", + } + } else { + return { + command: "oni.openFile", + arguments: [bm], + group: "Files", + } + } + }) + + this._updateBookmarks(newBookmarks) + } catch (e) { + Log.warn("Error loading bookmarks: " + e) + } + } +} + +let _bookmarks: IBookmarksProvider + +export const activate = (configuration: Configuration, sidebarManager: SidebarManager) => { + _bookmarks = new ConfigurationBookmarksProvider(configuration) + + sidebarManager.add("bookmark", new BookmarksPane(_bookmarks)) +} + +export const getInstance = (): IBookmarksProvider => _bookmarks diff --git a/browser/src/Services/Sidebar/index.ts b/browser/src/Services/Sidebar/index.ts index 40599a769a..e1a34470cb 100644 --- a/browser/src/Services/Sidebar/index.ts +++ b/browser/src/Services/Sidebar/index.ts @@ -13,6 +13,8 @@ import { SidebarPane } from "./SidebarPane" let _sidebarManager: SidebarManager = null +export * from "./SidebarStore" + export const activate = (configuration: Configuration, workspace: Workspace) => { _sidebarManager = new SidebarManager() @@ -23,9 +25,6 @@ export const activate = (configuration: Configuration, workspace: Workspace) => _sidebarManager.add("files-o", new ExplorerSplit(workspace, commandManager, editorManager)) - const bookmarksPane = new SidebarPane("oni.sidebar.bookmarks", "Bookmarks") - _sidebarManager.add("bookmark", bookmarksPane) - const searchPane = new SidebarPane("oni.sidebar.search", "Search") _sidebarManager.add("search", searchPane) } diff --git a/browser/src/UI/components/SidebarItemView.tsx b/browser/src/UI/components/SidebarItemView.tsx new file mode 100644 index 0000000000..9e0216477a --- /dev/null +++ b/browser/src/UI/components/SidebarItemView.tsx @@ -0,0 +1,77 @@ +/** + * SidebarItemView.tsx + * + * Shared component for sidebar items + */ + +import * as React from "react" +import styled from "styled-components" + +import { withProps } from "./common" + +export interface ISidebarItemViewProps { + text: string + isFocused: boolean + isContainer: boolean + indentationLevel: number + icon?: JSX.Element +} + +const px = (num: number): string => num.toString() + "px" + +const SidebarItemStyleWrapper = withProps(styled.div)` + padding-left: ${props => px(INDENT_AMOUNT * props.indentationLevel)}; + border-left: ${props => + props.isFocused + ? "4px solid " + props.theme["highlight.mode.normal.background"] + : "4px solid transparent"}; + + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 4px; + position: relative; + + .icon { + flex: 0 0 auto; + width: 20px; + text-align: center; + margin-right: 7px; + } + + .name { + flex: 1 1 auto; + } +` + +const SidebarItemBackground = withProps(styled.div)` + background-color: ${props => { + if (props.isFocused) { + return props.theme["highlight.mode.normal.background"] + } else { + return "rgb(0, 0, 0)" + } + }}; + opacity: ${props => (props.isContainer || props.isFocused ? "0.2" : "0")}; + + position: absolute; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; +` + +const INDENT_AMOUNT = 6 + +export class SidebarItemView extends React.PureComponent { + public render(): JSX.Element { + return ( + + +
{this.props.icon}
+
{this.props.text}
+
+ ) + } +} diff --git a/browser/src/index.tsx b/browser/src/index.tsx index 36464a781a..05aa5fc16d 100644 --- a/browser/src/index.tsx +++ b/browser/src/index.tsx @@ -209,6 +209,9 @@ const start = async (args: string[]): Promise => { const ThemePicker = await themePickerPromise ThemePicker.activate(configuration, menuManager, Themes.getThemeManagerInstance()) + const Bookmarks = await import("./Services/Bookmarks") + Bookmarks.activate(configuration, Sidebar.getInstance()) + Performance.endMeasure("Oni.Start.Activate") checkForUpdates() From 2b472510801bfac0537a3a0b7941eb21f3c1e57d Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Fri, 2 Feb 2018 09:52:45 -0800 Subject: [PATCH 029/103] Fix #1396 - Navigation Quirks (#1425) * Add option to disable loading init vim explicitly * Clean up configuration settings - as opposed to adding a new option, push the configuration upward * Fix configuration settings for shared instance --- .../src/Editor/NeovimEditor/NeovimEditor.tsx | 3 +++ browser/src/neovim/NeovimProcessSpawner.ts | 26 +++++++++++++------ browser/src/neovim/SharedNeovimInstance.ts | 2 ++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx index f410d701e7..e0a26d7ae9 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx @@ -690,6 +690,9 @@ export class NeovimEditor extends Editor implements IEditor { const startOptions: INeovimStartOptions = { runtimePaths: this._pluginManager.getAllRuntimePaths(), transport: this._configuration.getValue("experimental.neovim.transport"), + neovimPath: this._configuration.getValue("debug.neovimPath"), + loadInitVim: this._configuration.getValue("oni.loadInitVim"), + useDefaultConfig: this._configuration.getValue("oni.useDefaultConfig"), } await this._neovimInstance.start(startOptions) diff --git a/browser/src/neovim/NeovimProcessSpawner.ts b/browser/src/neovim/NeovimProcessSpawner.ts index cbd1d448a0..089df1d7df 100644 --- a/browser/src/neovim/NeovimProcessSpawner.ts +++ b/browser/src/neovim/NeovimProcessSpawner.ts @@ -4,7 +4,6 @@ import * as path from "path" import * as Platform from "./../Platform" import { spawnProcess } from "./../Plugins/Api/Process" -import { configuration } from "./../Services/Configuration" import { Session } from "./Session" @@ -22,11 +21,24 @@ export type MsgPackTransport = "stdio" | "pipe" export interface INeovimStartOptions { runtimePaths?: string[] transport?: MsgPackTransport + + // If `true`, load init.vim from default path + // If a string, override and load init.vim from the specified path + loadInitVim: boolean | string + + // Whether or not to use Oni's default, opinionated plugins + useDefaultConfig: boolean + + // Explicitly specify the path to Neovim. If not specified, + // the default path will be used. + neovimPath?: string } const DefaultStartOptions: INeovimStartOptions = { runtimePaths: [], transport: "stdio", + loadInitVim: true, + useDefaultConfig: true, } const getSessionFromProcess = async ( @@ -85,18 +97,16 @@ export const startNeovim = async ( nvimProcessPath = remapPathToUnpackedAsar(nvimProcessPath) - const neovimPath = configuration.getValue("debug.neovimPath") - - if (neovimPath) { - nvimProcessPath = neovimPath + if (options.neovimPath) { + nvimProcessPath = options.neovimPath } - Log.info("[NeovimProcessSpawnwer::startNeovim] Neovim process path: " + nvimProcessPath) + Log.info("[NeovimProcessSpawner::startNeovim] Neovim process path: " + nvimProcessPath) const joinedRuntimePaths = runtimePaths.map(p => remapPathToUnpackedAsar(p)).join(",") - const loadInitVimConfigOption = configuration.getValue("oni.loadInitVim") - const useDefaultConfig = configuration.getValue("oni.useDefaultConfig") + const loadInitVimConfigOption = options.loadInitVim + const useDefaultConfig = options.useDefaultConfig let initVimArg = [] initVimArg = loadInitVimConfigOption || !useDefaultConfig ? [] : ["-u", noopInitVimPath] diff --git a/browser/src/neovim/SharedNeovimInstance.ts b/browser/src/neovim/SharedNeovimInstance.ts index 4f839b5656..38c8a9a081 100644 --- a/browser/src/neovim/SharedNeovimInstance.ts +++ b/browser/src/neovim/SharedNeovimInstance.ts @@ -154,6 +154,8 @@ class SharedNeovimInstance implements SharedNeovimInstance { public async start(): Promise { const startOptions: INeovimStartOptions = { runtimePaths: this._pluginManager.getAllRuntimePaths(), + loadInitVim: false, + useDefaultConfig: true, } this._initPromise = this._neovimInstance.start(startOptions) From 6a895cd12f94c908c42ad5efe14c863fc5def73d Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Fri, 2 Feb 2018 11:36:52 -0800 Subject: [PATCH 030/103] Initial RipGrep workspace search integration (#1394) * Initial search integration * Get search working, rendering in quickfix * Fix lint issues --- browser/src/Plugins/Api/Oni.ts | 5 + browser/src/Services/Search.tsx | 181 ++++++++++++++++++++++++++++++++ browser/src/index.tsx | 3 + 3 files changed, 189 insertions(+) create mode 100644 browser/src/Services/Search.tsx diff --git a/browser/src/Plugins/Api/Oni.ts b/browser/src/Plugins/Api/Oni.ts index e548551fb8..f6ea5e738d 100644 --- a/browser/src/Plugins/Api/Oni.ts +++ b/browser/src/Plugins/Api/Oni.ts @@ -27,6 +27,7 @@ import { getInstance as getMenuManagerInstance } from "./../../Services/Menu" import { getInstance as getNotificationsInstance } from "./../../Services/Notifications" import { getInstance as getOverlayInstance } from "./../../Services/Overlay" import { recorder } from "./../../Services/Recorder" +import { getInstance as getSearchInstance } from "./../../Services/Search" import { getInstance as getSidebarInstance } from "./../../Services/Sidebar" import { getInstance as getSnippetsInstance } from "./../../Services/Snippets" import { getInstance as getStatusBarInstance } from "./../../Services/StatusBar" @@ -126,6 +127,10 @@ export class Oni extends EventEmitter implements OniApi.Plugin.Api { return Process } + public get search(): any { + return getSearchInstance() + } + public get sidebar(): any { return getSidebarInstance() } diff --git a/browser/src/Services/Search.tsx b/browser/src/Services/Search.tsx new file mode 100644 index 0000000000..d5397f6312 --- /dev/null +++ b/browser/src/Services/Search.tsx @@ -0,0 +1,181 @@ +/** + * Search + * + * Service for workspace-wide search + */ + +import { Event, IEvent } from "oni-types" + +import { FinderProcess } from "./QuickOpen/FinderProcess" +import * as RipGrep from "./QuickOpen/RipGrep" + +export interface ISearchResultItem { + fileName: string + line: number + column: number + text: string +} + +export interface ISearchResult { + items: ISearchResultItem[] + isComplete: boolean +} + +export interface ISearchQuery { + onSearchStarted: IEvent + onSearchCompleted: IEvent + + start(): void + cancel(): void +} + +export interface ISearchOptions { + searchQuery: string + fileFilter: string + workspace: string +} + +export interface ISearchProvider { + search(opts: ISearchOptions): ISearchQuery +} + +export class RipGrepSearchProvider { + public search(opts: ISearchOptions): ISearchQuery { + return new RipGrepSearchQuery(opts) + } +} + +export const getArgumentsFromSearchOptions = (searchOpts: ISearchOptions): string[] => { + const args = [] + + args.push("--vimgrep") + args.push("-e") + args.push(searchOpts.searchQuery) + + if (searchOpts.fileFilter) { + args.push("-g") + args.push(searchOpts.fileFilter) + } + + args.push("--") + args.push(".") + + return args +} + +// Command format: +// E:\\oni\\node_modules\\oni-ripgrep\\bin\\rg.exe" --vimgrep -e test -g *.tsx -- .', [], { shell: true, cwd: "E:\\oni" }).stdout.toString() + +export const ripGrepLineToSearchResultItem = (ripGrepResult: string): ISearchResultItem => { + if (!ripGrepResult || ripGrepResult.length === 0) { + return null + } + + const splitString = ripGrepResult.split(":") + + if (splitString.length < 4) { + return null + } + + const [fileName, line, column, ...result] = splitString + + const text = result.join(":") + + const ret: ISearchResultItem = { + fileName, + line: parseInt(line, 10), + column: parseInt(column, 10), + text, + } + return ret +} + +export class RipGrepSearchQuery { + private _onSearchStartedEvent = new Event() + private _onSearchCompletedEvent = new Event() + private _finderProcess: FinderProcess + + private _items: ISearchResultItem[] = [] + + public get onSearchStarted(): IEvent { + return this._onSearchStartedEvent + } + + public get onSearchCompleted(): IEvent { + return this._onSearchCompletedEvent + } + + constructor(opts: ISearchOptions) { + const args = getArgumentsFromSearchOptions(opts) + const visualizer = new QuickFixSearchResultsViewer(editorManager) + + this._finderProcess = new FinderProcess(RipGrep.getCommand() + " " + args.join(" "), "\n") + + this._finderProcess.onData.subscribe((items: string[]) => { + const searchResultItems = items + .map(ripGrepLineToSearchResultItem) + .filter(item => item !== null) + + this._items = [...this._items, ...searchResultItems] + + visualizer.showResult({ + items: this._items, + isComplete: false, + }) + }) + + this._finderProcess.onComplete.subscribe(() => { + this._onSearchCompletedEvent.dispatch({ + items: this._items, + isComplete: true, + }) + + visualizer.showResult({ + items: this._items, + isComplete: true, + }) + }) + } + + public start(): void { + this._items = [] + this._finderProcess.start() + } + + public cancel(): void { + this._finderProcess.stop() + } +} + +import { editorManager, EditorManager } from "./../Services/EditorManager" + +export interface ISearchResultsViewer { + showResults(results: ISearchResult): void +} + +const itemsToQuickFixItems = (item: ISearchResultItem) => ({ + filename: item.fileName, + lnum: item.line, + col: item.column, + text: item.text, +}) + +export class QuickFixSearchResultsViewer { + constructor(private _editorManager: EditorManager) {} + + public showResult(results: ISearchResult): void { + const quickFixEntries = results.items.map(itemsToQuickFixItems) + + const neovim: any = this._editorManager.activeEditor.neovim + neovim.quickFix.setqflist(quickFixEntries, "Search Results") + neovim.command(":copen") + } +} + +let _search: ISearchProvider = null + +export const activate = () => { + _search = new RipGrepSearchProvider() +} + +export const getInstance = (): ISearchProvider => _search diff --git a/browser/src/index.tsx b/browser/src/index.tsx index 05aa5fc16d..7c7d1bfd21 100644 --- a/browser/src/index.tsx +++ b/browser/src/index.tsx @@ -187,6 +187,9 @@ const start = async (args: string[]): Promise => { diagnostics.start(languageManager) + const Search = await import("./Services/Search") + Search.activate() + Performance.startMeasure("Oni.Start.Activate") const api = pluginManager.startApi() configuration.activate(api) From a74466a212cc438f50dbe1b2b3641f79736e260f Mon Sep 17 00:00:00 2001 From: Ryan C Date: Fri, 2 Feb 2018 20:44:58 +0000 Subject: [PATCH 031/103] Update default config. (#1429) --- configuration/config.default.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/configuration/config.default.js b/configuration/config.default.js index f70969f715..b2fa43d63d 100644 --- a/configuration/config.default.js +++ b/configuration/config.default.js @@ -2,10 +2,10 @@ // check out our wiki page: // https://github.com/onivim/oni/wiki/Configuration -const activate = (oni) => { +const activate = oni => { console.log("config activated") - // Input + // Input // // Add input bindings here: // @@ -24,17 +24,17 @@ const deactivate = () => { module.exports = { activate, deactivate, - //add custom config here, such as + //add custom config here, such as - "ui.colorscheme": "onedark", + "ui.colorscheme": "nord", - //"oni.useDefaultConfig": true, - //"oni.bookmarks": ["~/Documents"], - //"oni.loadInitVim": false, - //"editor.fontSize": "14px", - //"editor.fontFamily": "Monaco" + //"oni.useDefaultConfig": true, + //"oni.bookmarks": ["~/Documents"], + //"oni.loadInitVim": false, + //"editor.fontSize": "14px", + //"editor.fontFamily": "Monaco" - // UI customizations + // UI customizations "ui.animations.enabled": true, "ui.fontSmoothing": "auto", } From 23e053375ca76d4617dee106c6e87d2fe6dded96 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Fri, 2 Feb 2018 15:48:55 -0800 Subject: [PATCH 032/103] Handle enter event directly in the TextInputView (#1432) --- .../NeovimEditor/NeovimEditorCommands.ts | 16 -------------- browser/src/Editor/NeovimEditor/Rename.tsx | 22 +++---------------- browser/src/UI/components/LightweightText.tsx | 11 ++++++---- 3 files changed, 10 insertions(+), 39 deletions(-) diff --git a/browser/src/Editor/NeovimEditor/NeovimEditorCommands.ts b/browser/src/Editor/NeovimEditor/NeovimEditorCommands.ts index 237617e180..6159444e70 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditorCommands.ts +++ b/browser/src/Editor/NeovimEditor/NeovimEditorCommands.ts @@ -126,8 +126,6 @@ export class NeovimEditorCommands { return !this._menuManager.isMenuOpen() } - const isRenameActive = () => this._rename.isRenameActive() - const commands = [ new CallbackCommand( "contextMenu.select", @@ -202,20 +200,6 @@ export class NeovimEditorCommands { new CallbackCommand("editor.rename", "Rename", "Rename an item", () => this._rename.startRename(), ), - new CallbackCommand( - "editor.rename.commit", - null, - null, - () => this._rename.commitRename(), - isRenameActive, - ), - new CallbackCommand( - "editor.rename.cancel", - null, - null, - () => this._rename.cancelRename(), - isRenameActive, - ), new CallbackCommand("editor.quickInfo.show", null, null, () => this._languageEditorIntegration.showHover(), diff --git a/browser/src/Editor/NeovimEditor/Rename.tsx b/browser/src/Editor/NeovimEditor/Rename.tsx index bbc8664500..c54350b2b3 100644 --- a/browser/src/Editor/NeovimEditor/Rename.tsx +++ b/browser/src/Editor/NeovimEditor/Rename.tsx @@ -18,7 +18,6 @@ import { IToolTipsProvider } from "./ToolTipsProvider" const _renameToolTipName = "rename-tool-tip" export class Rename { private _isRenameActive: boolean - private _isRenameCommitted: boolean constructor( private _editor: Oni.Editor, @@ -27,10 +26,6 @@ export class Rename { private _workspace: Workspace, ) {} - public isRenameActive(): boolean { - return this._isRenameActive - } - public async startRename(): Promise { if (this._isRenameActive) { return @@ -53,7 +48,7 @@ export class Rename { _renameToolTipName, this.cancelRename()} - onComplete={newValue => this._onRenameClosed(newValue)} + onComplete={newValue => this.commitRename(newValue)} tokenName={activeToken.tokenName} />, { @@ -64,25 +59,14 @@ export class Rename { ) } - public commitRename(): void { + public commitRename(newValue: string): void { Log.verbose("[RENAME] Committing rename") - this._isRenameCommitted = true - this._isRenameActive = false + this.doRename(newValue) this.closeToolTip() } public cancelRename(): void { Log.verbose("[RENAME] Cancelling") - this._isRenameCommitted = false - this.closeToolTip() - } - - public _onRenameClosed(newValue: string): void { - Log.verbose("[RENAME] _onRenameClosed") - if (this._isRenameCommitted) { - this._isRenameCommitted = false - this.doRename(newValue) - } this.closeToolTip() } diff --git a/browser/src/UI/components/LightweightText.tsx b/browser/src/UI/components/LightweightText.tsx index 70148ded5e..7aff1e7a6c 100644 --- a/browser/src/UI/components/LightweightText.tsx +++ b/browser/src/UI/components/LightweightText.tsx @@ -54,10 +54,6 @@ export class TextInputView extends React.PureComponent public componentWillUnmount(): void { if (this._element) { - if (this.props.onComplete) { - this.props.onComplete(this._element.value) - } - focusManager.popFocus(this._element) this._element = null } @@ -81,6 +77,13 @@ export class TextInputView extends React.PureComponent return } + if (keyboardEvent.keyCode === 13) { + if (this.props.onComplete) { + this.props.onComplete(this._element.value) + } + return + } + if (this._element && keyboardEvent.ctrlKey) { switch (keyboardEvent.key) { case "[": From 6ec62e08e77ac6ee723e1e6d2aa63e0b9cf75bde Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Fri, 2 Feb 2018 17:38:17 -0800 Subject: [PATCH 033/103] Sidebar: Search UX (#1428) * Add saerch file * Add some initial UX * Hook up empty experience to search pane * Hook up workspace changes to search view state * Start hooking up and styling text inputs * More styling work * Factor open folder and make it directly callable off of the workspace object * Initial search UX * Integrate search provider with search ux * Wire up onchange properties * Starting wiring up search UX -> search provider * Add search provider --- browser/src/Plugins/Api/Oni.ts | 5 - .../{Search.tsx => Search/SearchProvider.ts} | 25 +- browser/src/Services/Search/SearchTextBox.tsx | 68 +++++ browser/src/Services/Search/index.tsx | 246 ++++++++++++++++++ browser/src/Services/Sidebar/index.ts | 5 - browser/src/Services/Workspace/Workspace.ts | 20 ++ .../Services/Workspace/WorkspaceCommands.ts | 23 +- .../UI/components/SidebarEmptyPaneView.tsx | 16 +- browser/src/index.tsx | 6 +- 9 files changed, 351 insertions(+), 63 deletions(-) rename browser/src/Services/{Search.tsx => Search/SearchProvider.ts} (85%) create mode 100644 browser/src/Services/Search/SearchTextBox.tsx create mode 100644 browser/src/Services/Search/index.tsx diff --git a/browser/src/Plugins/Api/Oni.ts b/browser/src/Plugins/Api/Oni.ts index f6ea5e738d..e548551fb8 100644 --- a/browser/src/Plugins/Api/Oni.ts +++ b/browser/src/Plugins/Api/Oni.ts @@ -27,7 +27,6 @@ import { getInstance as getMenuManagerInstance } from "./../../Services/Menu" import { getInstance as getNotificationsInstance } from "./../../Services/Notifications" import { getInstance as getOverlayInstance } from "./../../Services/Overlay" import { recorder } from "./../../Services/Recorder" -import { getInstance as getSearchInstance } from "./../../Services/Search" import { getInstance as getSidebarInstance } from "./../../Services/Sidebar" import { getInstance as getSnippetsInstance } from "./../../Services/Snippets" import { getInstance as getStatusBarInstance } from "./../../Services/StatusBar" @@ -127,10 +126,6 @@ export class Oni extends EventEmitter implements OniApi.Plugin.Api { return Process } - public get search(): any { - return getSearchInstance() - } - public get sidebar(): any { return getSidebarInstance() } diff --git a/browser/src/Services/Search.tsx b/browser/src/Services/Search/SearchProvider.ts similarity index 85% rename from browser/src/Services/Search.tsx rename to browser/src/Services/Search/SearchProvider.ts index d5397f6312..1e22abd37a 100644 --- a/browser/src/Services/Search.tsx +++ b/browser/src/Services/Search/SearchProvider.ts @@ -6,8 +6,8 @@ import { Event, IEvent } from "oni-types" -import { FinderProcess } from "./QuickOpen/FinderProcess" -import * as RipGrep from "./QuickOpen/RipGrep" +import { FinderProcess } from "./../QuickOpen/FinderProcess" +import * as RipGrep from "./../QuickOpen/RipGrep" export interface ISearchResultItem { fileName: string @@ -107,7 +107,6 @@ export class RipGrepSearchQuery { constructor(opts: ISearchOptions) { const args = getArgumentsFromSearchOptions(opts) - const visualizer = new QuickFixSearchResultsViewer(editorManager) this._finderProcess = new FinderProcess(RipGrep.getCommand() + " " + args.join(" "), "\n") @@ -117,11 +116,6 @@ export class RipGrepSearchQuery { .filter(item => item !== null) this._items = [...this._items, ...searchResultItems] - - visualizer.showResult({ - items: this._items, - isComplete: false, - }) }) this._finderProcess.onComplete.subscribe(() => { @@ -129,11 +123,6 @@ export class RipGrepSearchQuery { items: this._items, isComplete: true, }) - - visualizer.showResult({ - items: this._items, - isComplete: true, - }) }) } @@ -147,7 +136,7 @@ export class RipGrepSearchQuery { } } -import { editorManager, EditorManager } from "./../Services/EditorManager" +import { EditorManager } from "./../EditorManager" export interface ISearchResultsViewer { showResults(results: ISearchResult): void @@ -171,11 +160,3 @@ export class QuickFixSearchResultsViewer { neovim.command(":copen") } } - -let _search: ISearchProvider = null - -export const activate = () => { - _search = new RipGrepSearchProvider() -} - -export const getInstance = (): ISearchProvider => _search diff --git a/browser/src/Services/Search/SearchTextBox.tsx b/browser/src/Services/Search/SearchTextBox.tsx new file mode 100644 index 0000000000..b270b8e426 --- /dev/null +++ b/browser/src/Services/Search/SearchTextBox.tsx @@ -0,0 +1,68 @@ +/** + * SearchTextBox.tsx + * + * Component for textbox in search + */ + +import * as React from "react" + +import styled from "styled-components" +import { TextInputView } from "./../../UI/components/LightweightText" +import { withProps, boxShadow } from "./../../UI/components/common" + +export interface ISearchTextBoxProps { + isActive: boolean + isFocused: boolean + val: string + + onDismiss: () => void + onCommit: (newValue: string) => void + onChangeText: (newValue: string) => void +} + +const SearchBoxContainerWrapper = withProps(styled.div)` + padding: 8px; + + background-color: ${props => (props.isFocused ? "rgba(0, 0, 0, 0.1)" : "transparent")}; + border-left: 2px solid ${props => + props.isFocused ? props.theme["highlight.mode.normal.background"] : "transparent"}; +` + +const SearchTextBoxWrapper = withProps(styled.div)` + padding: 8px; + border: ${props => + props.isActive + ? "2px solid " + props.theme["highlight.mode.normal.background"] + : "1px solid " + props.theme["editor.foreground"]}; + margin: 8px; + background-color: ${props => props.theme["background"]}; + + ${props => (props.isActive ? boxShadow : "")}; + + transition: all 0.1s ease-in; + + input { + background-color: transparent; + color: ${props => props.theme["editor.foreground"]} + } +` + +export class SearchTextBox extends React.PureComponent { + public render(): JSX.Element { + const inner = this.props.isActive ? ( + this.props.onChangeText(elem.currentTarget.value)} + onComplete={this.props.onCommit} + /> + ) : ( +
{this.props.val}
+ ) + return ( + + {inner} + + ) + } +} diff --git a/browser/src/Services/Search/index.tsx b/browser/src/Services/Search/index.tsx new file mode 100644 index 0000000000..ed75164a6c --- /dev/null +++ b/browser/src/Services/Search/index.tsx @@ -0,0 +1,246 @@ +/** + * Search/index.tsx + * + * Entry point for search-related features + */ + +import * as React from "react" + +import { Event, IDisposable, IEvent } from "oni-types" + +import { EditorManager } from "./../EditorManager" +import { SidebarManager } from "./../Sidebar" +import { Workspace } from "./../Workspace" + +export * from "./SearchProvider" + +import { + ISearchProvider, + ISearchOptions, + ISearchQuery, + RipGrepSearchProvider, + QuickFixSearchResultsViewer, +} from "./SearchProvider" + +import { SearchTextBox } from "./SearchTextBox" + +export class SearchPane { + private _onEnter = new Event() + private _onLeave = new Event() + + private _searchProvider: ISearchProvider + private _currentQuery: ISearchQuery + + public get id(): string { + return "oni.sidebar.search" + } + + public get title(): string { + return "Search" + } + + constructor(private _editorManager: EditorManager, private _workspace: Workspace) { + this._searchProvider = new RipGrepSearchProvider() + } + + public enter(): void { + this._onEnter.dispatch() + } + + public leave(): void { + this._onLeave.dispatch() + } + + public render(): JSX.Element { + return ( + this._onSearchOptionsChanged(opts)} + /> + ) + } + + private _onSearchOptionsChanged(searchOpts: ISearchOptions): void { + console.log("changed: " + searchOpts) + + if (this._currentQuery) { + this._currentQuery.cancel() + } + + const query = this._searchProvider.search(searchOpts) + + query.start() + + query.onSearchCompleted.subscribe(result => { + const visualizer = new QuickFixSearchResultsViewer(this._editorManager) + visualizer.showResult(result) + }) + + this._currentQuery = query + } +} + +import styled from "styled-components" + +import { SidebarEmptyPaneView } from "./../../UI/components/SidebarEmptyPaneView" +import { VimNavigator } from "./../../UI/components/VimNavigator" + +const Label = styled.div` + margin: 8px; +` + +export interface ISearchPaneViewProps { + workspace: Workspace + onEnter: IEvent + onLeave: IEvent + + onSearchOptionsChanged: (opts: ISearchOptions) => void +} + +export interface ISearchPaneViewState { + activeWorkspace: string + isActive: boolean + activeTextbox: string + + searchQuery: string + fileFilter: string +} + +export class SearchPaneView extends React.PureComponent< + ISearchPaneViewProps, + ISearchPaneViewState +> { + private _subscriptions: IDisposable[] = [] + + constructor(props: ISearchPaneViewProps) { + super(props) + + this.state = { + activeWorkspace: this.props.workspace.activeWorkspace, + isActive: false, + activeTextbox: null, + searchQuery: "Type to search...", + fileFilter: "*.*", + } + } + + public componentDidMount(): void { + this._cleanExistingSubscriptions() + + const s1 = this.props.onEnter.subscribe(() => this.setState({ isActive: true })) + const s2 = this.props.onLeave.subscribe(() => this.setState({ isActive: false })) + const s3 = this.props.workspace.onDirectoryChanged.subscribe((wd: string) => + this.setState({ activeWorkspace: wd }), + ) + + this._subscriptions = [s1, s2, s3] + } + + public componentWillUnmount(): void { + this._cleanExistingSubscriptions() + } + + private _cleanExistingSubscriptions(): void { + this._subscriptions.forEach(s => s.dispose()) + this._subscriptions = [] + } + + public render(): JSX.Element { + if (!this.state.activeWorkspace) { + return ( + this.props.workspace.openFolder()} + /> + ) + } + + return ( + { + this._onSelected(selectedId) + }} + render={(selectedId: string) => { + return ( +
+ + this._onChangeSearchQuery(val)} + onCommit={() => this._clearActiveTextbox()} + onDismiss={() => this._clearActiveTextbox()} + isFocused={selectedId === "textbox.query"} + isActive={this.state.activeTextbox === "textbox.query"} + /> + + this._onChangeFilesFilter(val)} + onCommit={() => this._clearActiveTextbox()} + onDismiss={() => this._clearActiveTextbox()} + isFocused={selectedId === "textbox.filter"} + isActive={this.state.activeTextbox === "textbox.filter"} + /> +
+ ) + }} + /> + ) + } + + private _onChangeFilesFilter(val: string): void { + this.setState({ + fileFilter: val, + }) + + this._startSearch() + } + + private _onChangeSearchQuery(val: string): void { + this.setState({ + searchQuery: val, + }) + + this._startSearch() + } + + // private _onCommit(): void { + + // } + + private _clearActiveTextbox(): void { + this.setState({ activeTextbox: null }) + } + + private _onSelected(selectedId: string): void { + if (selectedId === "button.search") { + this._startSearch() + } else if (selectedId === "textbox.query") { + this.setState({ activeTextbox: "textbox.query" }) + } else if (selectedId === "textbox.filter") { + this.setState({ activeTextbox: "textbox.filter" }) + } + } + + private _startSearch(): void { + this.props.onSearchOptionsChanged({ + searchQuery: this.state.searchQuery, + fileFilter: this.state.fileFilter, + workspace: this.props.workspace.activeWorkspace, + }) + } +} + +export const activate = ( + editorManager: EditorManager, + sidebarManager: SidebarManager, + workspace: Workspace, +) => { + sidebarManager.add("search", new SearchPane(editorManager, workspace)) +} diff --git a/browser/src/Services/Sidebar/index.ts b/browser/src/Services/Sidebar/index.ts index e1a34470cb..bf74eca198 100644 --- a/browser/src/Services/Sidebar/index.ts +++ b/browser/src/Services/Sidebar/index.ts @@ -9,8 +9,6 @@ import { SidebarContentSplit } from "./SidebarContentSplit" import { SidebarSplit } from "./SidebarSplit" import { SidebarManager } from "./SidebarStore" -import { SidebarPane } from "./SidebarPane" - let _sidebarManager: SidebarManager = null export * from "./SidebarStore" @@ -24,9 +22,6 @@ export const activate = (configuration: Configuration, workspace: Workspace) => leftDock.addSplit(new SidebarContentSplit(_sidebarManager)) _sidebarManager.add("files-o", new ExplorerSplit(workspace, commandManager, editorManager)) - - const searchPane = new SidebarPane("oni.sidebar.search", "Search") - _sidebarManager.add("search", searchPane) } } diff --git a/browser/src/Services/Workspace/Workspace.ts b/browser/src/Services/Workspace/Workspace.ts index 38fd54bce2..480c0f3508 100644 --- a/browser/src/Services/Workspace/Workspace.ts +++ b/browser/src/Services/Workspace/Workspace.ts @@ -141,6 +141,26 @@ export class Workspace implements IWorkspace { } } + public openFolder(): void { + const dialogOptions: any = { + title: "Open Folder", + properties: ["openDirectory"], + } + + remote.dialog.showOpenDialog( + remote.getCurrentWindow(), + dialogOptions, + async (folder: string[]) => { + if (!folder || !folder[0]) { + return + } + + const folderToOpen = folder[0] + await this.changeDirectory(folderToOpen) + }, + ) + } + public autoDetectWorkspace(filePath: string): void { const settings = this._configuration.getValue("workspace.autoDetectWorkspace") switch (settings) { diff --git a/browser/src/Services/Workspace/WorkspaceCommands.ts b/browser/src/Services/Workspace/WorkspaceCommands.ts index c0afd65e28..31de100ca5 100644 --- a/browser/src/Services/Workspace/WorkspaceCommands.ts +++ b/browser/src/Services/Workspace/WorkspaceCommands.ts @@ -6,7 +6,6 @@ import * as fs from "fs" import * as path from "path" -import { remote } from "electron" import * as mkdirp from "mkdirp" import { CallbackCommand, commandManager } from "./../CommandManager" @@ -21,26 +20,6 @@ export const activateCommands = ( editorManager: EditorManager, workspace: Workspace, ) => { - const openFolder = () => { - const dialogOptions: any = { - title: "Open Folder", - properties: ["openDirectory"], - } - - remote.dialog.showOpenDialog( - remote.getCurrentWindow(), - dialogOptions, - async (folder: string[]) => { - if (!folder || !folder[0]) { - return - } - - const folderToOpen = folder[0] - await workspace.changeDirectory(folderToOpen) - }, - ) - } - const openTestFileInSplit = () => { const mappedFile = getTestFileMappedToCurrentFile() @@ -96,7 +75,7 @@ export const activateCommands = ( "workspace.openFolder", "Workspace: Open Folder", "Set a folder as the working directory for Oni", - () => openFolder(), + () => workspace.openFolder(), ), new CallbackCommand( "workspace.openTestFile", diff --git a/browser/src/UI/components/SidebarEmptyPaneView.tsx b/browser/src/UI/components/SidebarEmptyPaneView.tsx index 052a08e80c..2cb05bb10b 100644 --- a/browser/src/UI/components/SidebarEmptyPaneView.tsx +++ b/browser/src/UI/components/SidebarEmptyPaneView.tsx @@ -62,6 +62,7 @@ import { Sneakable } from "./Sneakable" import { VimNavigator } from "./VimNavigator" export interface IOniButtonProps { + focused: boolean text: string onClick: () => void } @@ -69,11 +70,13 @@ export interface IOniButtonProps { export class OniButton extends React.PureComponent { public render(): JSX.Element { return ( - - - {this.props.text} - - + + + + {this.props.text} + + + ) } } @@ -82,6 +85,7 @@ export class SidebarEmptyPaneView extends React.PureComponent this.props.onClickButton && this.props.onClickButton()} /> @@ -96,7 +100,7 @@ export class SidebarEmptyPaneView extends React.PureComponent {this.props.contentsText} - {button} + {button} ) }} diff --git a/browser/src/index.tsx b/browser/src/index.tsx index 7c7d1bfd21..687ec8632b 100644 --- a/browser/src/index.tsx +++ b/browser/src/index.tsx @@ -187,9 +187,6 @@ const start = async (args: string[]): Promise => { diagnostics.start(languageManager) - const Search = await import("./Services/Search") - Search.activate() - Performance.startMeasure("Oni.Start.Activate") const api = pluginManager.startApi() configuration.activate(api) @@ -209,6 +206,9 @@ const start = async (args: string[]): Promise => { const Snippets = await snippetPromise Snippets.activate() + const Search = await import("./Services/Search") + Search.activate(editorManager, Sidebar.getInstance(), workspace) + const ThemePicker = await themePickerPromise ThemePicker.activate(configuration, menuManager, Themes.getThemeManagerInstance()) From 3543cd2f5337ad721d47be45b4e7458af0c66494 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Fri, 2 Feb 2018 18:35:03 -0800 Subject: [PATCH 034/103] Change sneak binding to control g (#1433) --- browser/src/Input/KeyBindings.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/browser/src/Input/KeyBindings.ts b/browser/src/Input/KeyBindings.ts index 27686769d9..a3b157ad1d 100644 --- a/browser/src/Input/KeyBindings.ts +++ b/browser/src/Input/KeyBindings.ts @@ -106,7 +106,6 @@ export const applyDefaultKeyBindings = (oni: Oni.Plugin.Api, config: Configurati input.bind("", "explorer.delete") // TODO: Scope 's' to just the local window - input.bind("s", "sneak.show", () => isNormalMode() && !menu.isMenuOpen()) - input.bind("S", "sneak.show", () => isNormalMode() && !menu.isMenuOpen()) + input.bind("", "sneak.show", () => isNormalMode() && !menu.isMenuOpen()) input.bind(["", ""], "sneak.hide") } From e8fc9e0b4f655e1dd15d1408a2ef5b578d89f5e2 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Fri, 2 Feb 2018 19:22:46 -0800 Subject: [PATCH 035/103] [WIP] Sidebar: Plugins Pane (#1431) * Add initial plugins sidebar pane * Add initial plugins pane / initialize * Add plugin sources * Categorize plugins by default / user --- browser/src/Plugins/Plugin.ts | 13 +- browser/src/Plugins/PluginManager.ts | 40 +++-- browser/src/Plugins/PluginSidebarPane.tsx | 166 ++++++++++++++++++ browser/src/UI/components/SidebarItemView.tsx | 28 +++ browser/src/index.tsx | 6 +- 5 files changed, 237 insertions(+), 16 deletions(-) create mode 100644 browser/src/Plugins/PluginSidebarPane.tsx diff --git a/browser/src/Plugins/Plugin.ts b/browser/src/Plugins/Plugin.ts index 42c7fd7865..85ea1ba50e 100644 --- a/browser/src/Plugins/Plugin.ts +++ b/browser/src/Plugins/Plugin.ts @@ -11,14 +11,25 @@ import * as PackageMetadataParser from "./PackageMetadataParser" export class Plugin { private _oniPluginMetadata: Capabilities.IPluginMetadata private _oni: Oni + private _id: string + + public get id(): string { + return this._id + } public get metadata(): Capabilities.IPluginMetadata { return this._oniPluginMetadata } - constructor(private _pluginRootDirectory: string) { + public get source(): string { + return this._source + } + + constructor(private _pluginRootDirectory: string, private _source: string) { const packageJsonPath = path.join(this._pluginRootDirectory, "package.json") + this._id = path.basename(this._pluginRootDirectory) + if (fs.existsSync(packageJsonPath)) { this._oniPluginMetadata = PackageMetadataParser.readMetadata(packageJsonPath) } diff --git a/browser/src/Plugins/PluginManager.ts b/browser/src/Plugins/PluginManager.ts index 40da3ff417..002c51b888 100644 --- a/browser/src/Plugins/PluginManager.ts +++ b/browser/src/Plugins/PluginManager.ts @@ -24,21 +24,33 @@ export class PluginManager { constructor(private _config: Configuration) {} public discoverPlugins(): void { - this._rootPluginPaths.push(corePluginsRoot) - this._rootPluginPaths.push(extensionsRoot) + const corePluginRootPaths: string[] = [corePluginsRoot, extensionsRoot] + const corePlugins: Plugin[] = this._getAllPluginPaths(corePluginRootPaths).map(p => + this._createPlugin(p, "core"), + ) + let defaultPluginRootPaths: string[] = [] + let defaultPlugins: Plugin[] = [] if (this._config.getValue("oni.useDefaultConfig")) { - this._rootPluginPaths.push(defaultPluginsRoot) - this._rootPluginPaths.push(path.join(defaultPluginsRoot, "bundle")) - } + defaultPluginRootPaths = [defaultPluginsRoot, path.join(defaultPluginsRoot, "bundle")] - this._rootPluginPaths.push(path.join(getUserConfigFolderPath(), "plugins")) + defaultPlugins = this._getAllPluginPaths(defaultPluginRootPaths).map(p => + this._createPlugin(p, "default"), + ) + } - const allPluginPaths = this._getAllPluginPaths() - this._plugins = allPluginPaths.map(pluginRootDirectory => - this._createPlugin(pluginRootDirectory), + const userPluginsRootPath = [path.join(getUserConfigFolderPath(), "plugins")] + const userPlugins = this._getAllPluginPaths(userPluginsRootPath).map(p => + this._createPlugin(p, "user"), ) + this._rootPluginPaths = [ + ...corePluginRootPaths, + ...defaultPluginRootPaths, + ...userPluginsRootPath, + ] + this._plugins = [...corePlugins, ...defaultPlugins, ...userPlugins] + this._anonymousPlugin = new AnonymousPlugin() } @@ -51,18 +63,18 @@ export class PluginManager { } public getAllRuntimePaths(): string[] { - const pluginPaths = this._getAllPluginPaths() + const pluginPaths = this._getAllPluginPaths(this._rootPluginPaths) return pluginPaths.concat(this._rootPluginPaths) } - private _createPlugin(pluginRootDirectory: string): Plugin { - return new Plugin(pluginRootDirectory) + private _createPlugin(pluginRootDirectory: string, source: string): Plugin { + return new Plugin(pluginRootDirectory, source) } - private _getAllPluginPaths(): string[] { + private _getAllPluginPaths(rootPluginPaths: string[]): string[] { const paths: string[] = [] - this._rootPluginPaths.forEach(rp => { + rootPluginPaths.forEach(rp => { const subPaths = getDirectories(rp) paths.push(...subPaths) }) diff --git a/browser/src/Plugins/PluginSidebarPane.tsx b/browser/src/Plugins/PluginSidebarPane.tsx new file mode 100644 index 0000000000..463c924e2d --- /dev/null +++ b/browser/src/Plugins/PluginSidebarPane.tsx @@ -0,0 +1,166 @@ +/** + * PluginsSidebarPane.tsx + * + * Sidebar pane for managing plugins + */ + +import * as React from "react" + +import { Event, IDisposable, IEvent } from "oni-types" + +import { SidebarManager, SidebarPane } from "./../Services/Sidebar" + +import { SidebarContainerView, SidebarItemView } from "./../UI/components/SidebarItemView" +import { VimNavigator } from "./../UI/components/VimNavigator" + +import { PluginManager } from "./../Plugins/PluginManager" + +export class PluginsSidebarPane implements SidebarPane { + private _onEnter = new Event() + private _onLeave = new Event() + + public get id(): string { + return "oni.sidebar.plugins" + } + + public get title(): string { + return "Plugins" + } + + public enter(): void { + this._onEnter.dispatch() + } + + public leave(): void { + this._onLeave.dispatch() + } + + constructor(private _pluginManager: PluginManager) {} + + public render(): JSX.Element { + return ( + + ) + } +} + +export interface IPluginsSidebarPaneViewProps { + onEnter: IEvent + onLeave: IEvent + + pluginManager: PluginManager +} + +export interface IPluginsSidebarPaneViewState { + isActive: boolean + defaultPluginsExpanded: boolean + userPluginsExpanded: boolean +} + +export class PluginsSidebarPaneView extends React.PureComponent< + IPluginsSidebarPaneViewProps, + IPluginsSidebarPaneViewState +> { + private _subscriptions: IDisposable[] = [] + + constructor(props: IPluginsSidebarPaneViewProps) { + super(props) + + this.state = { + isActive: false, + defaultPluginsExpanded: false, + userPluginsExpanded: true, + } + } + + public componentDidMount(): void { + this._clearExistingSubscriptions() + + const s2 = this.props.onEnter.subscribe(() => this.setState({ isActive: true })) + const s3 = this.props.onLeave.subscribe(() => this.setState({ isActive: false })) + + this._subscriptions = [s2, s3] + } + + public componentWillUnmount(): void { + this._clearExistingSubscriptions() + } + + public render(): JSX.Element { + const plugins = this.props.pluginManager.plugins + + const defaultPlugins = plugins.filter(p => p.source === "default") + const userPlugins = plugins.filter(p => p.source === "user") + + const defaultPluginIds = this.state.defaultPluginsExpanded + ? defaultPlugins.map(p => p.id) + : [] + const userPluginIds = this.state.userPluginsExpanded ? userPlugins.map(p => p.id) : [] + + const allIds = [ + "container.default", + ...defaultPluginIds, + "container.user", + ...userPluginIds, + ] + + return ( + { + const defaultPluginItems = defaultPlugins.map(p => ( + + )) + + const userPluginItems = userPlugins.map(p => ( + + )) + + return ( +
+ + {defaultPluginItems} + + + {userPluginItems} + +
+ ) + }} + /> + ) + } + + private _clearExistingSubscriptions(): void { + this._subscriptions.forEach(sub => sub.dispose()) + this._subscriptions = [] + } +} + +export const activate = (pluginManager: PluginManager, sidebarManager: SidebarManager) => { + const pane = new PluginsSidebarPane(pluginManager) + sidebarManager.add("plug", pane) +} diff --git a/browser/src/UI/components/SidebarItemView.tsx b/browser/src/UI/components/SidebarItemView.tsx index 9e0216477a..3cb1ff40b7 100644 --- a/browser/src/UI/components/SidebarItemView.tsx +++ b/browser/src/UI/components/SidebarItemView.tsx @@ -75,3 +75,31 @@ export class SidebarItemView extends React.PureComponent { + public render(): JSX.Element { + const caretStyle = { + transform: this.props.isExpanded ? "rotateZ(45deg)" : "rotateZ(0deg)", + } + const icon = + + return ( +
+ + {this.props.isExpanded ? this.props.children : null} +
+ ) + } +} diff --git a/browser/src/index.tsx b/browser/src/index.tsx index 687ec8632b..0e88609b6c 100644 --- a/browser/src/index.tsx +++ b/browser/src/index.tsx @@ -180,6 +180,7 @@ const start = async (args: string[]): Promise => { Performance.startMeasure("Oni.Start.Sidebar") const Sidebar = await sidebarPromise Sidebar.activate(configuration, workspace) + const sidebarManager = Sidebar.getInstance() Performance.endMeasure("Oni.Start.Sidebar") const createLanguageClientsFromConfiguration = @@ -213,7 +214,10 @@ const start = async (args: string[]): Promise => { ThemePicker.activate(configuration, menuManager, Themes.getThemeManagerInstance()) const Bookmarks = await import("./Services/Bookmarks") - Bookmarks.activate(configuration, Sidebar.getInstance()) + Bookmarks.activate(configuration, sidebarManager) + + const PluginsSidebarPane = await import("./Plugins/PluginSidebarPane") + PluginsSidebarPane.activate(pluginManager, sidebarManager) Performance.endMeasure("Oni.Start.Activate") From 7061f55d4c237f6596e0d1c0e62a741ccde37a1e Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sat, 3 Feb 2018 14:11:11 -0800 Subject: [PATCH 036/103] Update CONTRIBUTING.md with guidelines for becoming a collaborator, and bounties. --- CONTRIBUTING.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b01bcf2241..a52187bfd4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,11 +25,40 @@ Any code change should be submitted as a pull request. The description should ex The bigger the pull request, the longer it will take to review and merge. Try to break down large pull requests in smaller chunks that are easier to review and merge. It is also always helpful to have some context for your pull request. What was the purpose? Why does it matter to you? +A PR requires approval for either the maintainer, or a collaborator. + ## Financial contributions We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/oni). Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed. +### Bounties + +The primary allotment of our [open collective](https://opencollective.com/oni) budget is dedicated to bounties. Developing features and fixing bugs is a loit of work, and those go directly to the developers doing this work via bounties. It is the role of the _maintainer_ to set bounties and clear completion criteria. Issues that have a bounty associated with them will have a `bounty` label as well as an amount, ie, `bounty-50` means a $50 bounty. + +* Guidelines: + * The fix for the bug/feature/issue _MUST_ be complete and _MUST_ be covered by tests to be eligible for a bounty. + * If you begin working on an issue with an associated bounty, open a PR with "WIP" and the bug number in the title, as well as reference the issue #. This is important to reduce duplicate work. + * Upon completion, bounties are payable via an [open collective expense]. + +If you questions about the guidelines, please don't hesitate to contact the maintainer. + +## Roles + +There are various roles and responsibilities in managing an open-source project. Users that are active and have a positive impact on the project and community will be recognized and have the option of assuming additional responsibilities. + +* **Maintainer** - A maintainer communicates goals and drives the vision for the project. The maintainer is responsible for breaking down hurdles and supporting contributors. In addition, the maintainer triages issues, produces releases, assigns bounties, and establishes completion criteria. Today, there is one maintainer, but that isn't a strict requirement. +* **Collaborator** - A collaborator is an established member of the project that is recognized for their impact and contributions. They can triage and close issues, approve PRs from other contributors / collaborators, and can approve expenses on our [open collective](https://opencollective.com/oni) +* **Contributor** - A contributor is a developer that has submitted a successful PR for the project. + +### Becoming a collaborator + +A collaborator is a contributor who has been recognized for the impact they've had on the project, over a sustained period of time. In general, this means the following: + +* **Supporting the community** - helping others in issues and chat, supporting new developers, creating a positive and supportive environment. +* **Technical impact** - involvement in a core technical piece of the editor, or a broad impact on the ecosystem. +* **Positive and collaborative mindset** - creating good vibes, willingness to give and receive constructive feedback, being a team player. + ## Questions If you have any questions, create an [issue](issue) (protip: do a quick search first to see if someone else didn't ask the same question before!). From 4b15249af1f4b2c042360de2bbbe98b8a8a185a2 Mon Sep 17 00:00:00 2001 From: Ryan C Date: Tue, 6 Feb 2018 01:04:58 +0000 Subject: [PATCH 037/103] [WIP] Fix #1258 - Fix quotes auto-insertion (#1375) * Added a check for if the open and close character are equal. * Refactor for easier testing. * Start to setup CI test. * Added (broken) unit tests. Need to fix the last one and actually validate they are doing what I think they are. * Fixed up comments in CI tests. * Fix lint issues. * Add missing semi-colon. * Swap to using a cursor in the MockBuffer object. * Swap test to use third form of quote type. * Temporarily added sleep to test. * Fix potential race condition by waiting for return of function. * Update final await, to guarantee the input of all keys. Using the old line count was causing the tests to finish early sometimes. --- browser/src/Services/AutoClosingPairs.ts | 60 ++++++++++++-- browser/test/Mocks/index.ts | 13 ++- .../test/Services/AutoClosingPairsTests.ts | 81 ++++++++++++++++++- .../Services/Snippets/SnippetSessionTests.ts | 6 +- test/ci/Api.Buffer.AddLayer.tsx | 4 +- test/ci/Api.Overlays.AddRemoveTest.tsx | 4 +- test/ci/AutoClosingPairsTest.config.js | 13 +++ test/ci/AutoClosingPairsTest.ts | 20 +++-- test/ci/AutoCompletionTest-CSS.ts | 2 +- test/ci/AutoCompletionTest-HTML.ts | 2 +- test/ci/AutoCompletionTest-TypeScript.ts | 2 +- test/ci/Common.ts | 2 +- 12 files changed, 174 insertions(+), 35 deletions(-) create mode 100644 test/ci/AutoClosingPairsTest.config.js diff --git a/browser/src/Services/AutoClosingPairs.ts b/browser/src/Services/AutoClosingPairs.ts index e0b3986a9e..36192535df 100644 --- a/browser/src/Services/AutoClosingPairs.ts +++ b/browser/src/Services/AutoClosingPairs.ts @@ -6,6 +6,7 @@ import * as Oni from "oni-api" +import { IBuffer } from "./../Editor/BufferManager" import { Configuration } from "./Configuration" import { EditorManager } from "./EditorManager" import { InputManager } from "./InputManager" @@ -31,15 +32,14 @@ export const activate = ( let subscriptions: Oni.DisposeFunction[] = [] - const handleOpenCharacter = (pair: IAutoClosingPair, editor: Oni.Editor) => () => { + const handleOpenCharacter = ( + pair: IAutoClosingPair, + editor: Oni.Editor, + openCharacterSameAsClosed: boolean, + ) => () => { const neovim: NeovimInstance = editor.neovim as any neovim.blockInput(async (inputFunc: any) => { - // TODO: PERFORMANCE: Look at how to collapse this instead of needed multiple asynchronous calls. - await inputFunc(pair.open + pair.close) - - const pos = await neovim.callFunction("getpos", ["."]) - const [, oneBasedLine, oneBasedColumn] = pos - await editor.activeBuffer.setCursorPosition(oneBasedLine - 1, oneBasedColumn - 2) + await checkOpenCharacter(inputFunc, pair, editor, openCharacterSameAsClosed) }) return true @@ -161,10 +161,20 @@ export const activate = ( const autoClosingPairs = getAutoClosingPairs(configuration, newBuffer.language) autoClosingPairs.forEach(pair => { + if (pair.open === pair.close) { + subscriptions.push( + inputManager.bind( + pair.open, + handleOpenCharacter(pair, editorManager.activeEditor, true), + insertModeFilter, + ), + ) + } + subscriptions.push( inputManager.bind( pair.open, - handleOpenCharacter(pair, editorManager.activeEditor), + handleOpenCharacter(pair, editorManager.activeEditor, false), insertModeFilter, ), ) @@ -213,6 +223,40 @@ export const getWhiteSpacePrefix = (str: string): string => { } } +export const checkOpenCharacter = async ( + inputFunc: any, + pair: IAutoClosingPair, + editor: Oni.Editor, + openCharacterSameAsClosed: boolean, +): Promise => { + // TODO: PERFORMANCE: Look at how to collapse this instead of needed multiple asynchronous calls. + + const activeBuffer = editor.activeBuffer as IBuffer + + if (openCharacterSameAsClosed) { + const lines = await (activeBuffer as any).getLines( + activeBuffer.cursor.line, + activeBuffer.cursor.line + 1, + false, + ) + const currentLine = lines[0] + + if (currentLine[activeBuffer.cursor.column] === pair.open) { + await activeBuffer.setCursorPosition( + activeBuffer.cursor.line, + activeBuffer.cursor.column + 1, + ) + + return + } + } + + await inputFunc(pair.open + pair.close) + + const pos = await activeBuffer.getCursorPosition() + await editor.activeBuffer.setCursorPosition(pos.line, pos.character - 1) +} + const getAutoClosingPairs = ( configuration: Configuration, language: string, diff --git a/browser/test/Mocks/index.ts b/browser/test/Mocks/index.ts index 43585c9c15..3a462c5b9d 100644 --- a/browser/test/Mocks/index.ts +++ b/browser/test/Mocks/index.ts @@ -149,7 +149,7 @@ export class MockEditor extends Editor { export class MockBuffer { private _mockHighlights = new MockBufferHighlightsUpdater() - private _cursorPosition = types.Position.create(0, 0) + private _cursor = { line: 0, column: 0 } public get id(): string { return "1" @@ -171,6 +171,10 @@ export class MockBuffer { return this._mockHighlights } + public get cursor(): Oni.Cursor { + return this._cursor + } + public constructor( private _language: string = "test_language", private _filePath: string = "test_filepath", @@ -178,11 +182,12 @@ export class MockBuffer { ) {} public async getCursorPosition(): Promise { - return this._cursorPosition + return types.Position.create(this._cursor.line, this._cursor.column) } - public setCursorPosition(position: types.Position) { - this._cursorPosition = position + public setCursorPosition(line: number, column: number) { + this._cursor.column = column + this._cursor.line = line } public setLinesSync(lines: string[]): void { diff --git a/browser/test/Services/AutoClosingPairsTests.ts b/browser/test/Services/AutoClosingPairsTests.ts index 48da6d3f44..c82e9a25a9 100644 --- a/browser/test/Services/AutoClosingPairsTests.ts +++ b/browser/test/Services/AutoClosingPairsTests.ts @@ -1,22 +1,95 @@ import * as assert from "assert" -import * as AutoClosingPairs from "./../../src/Services/AutoClosingPairs" +import * as Mocks from "./../Mocks" + +import { + checkOpenCharacter, + getWhiteSpacePrefix, + IAutoClosingPair, +} from "./../../src/Services/AutoClosingPairs" describe("AutoClosingPairs", () => { describe("getWhitespacePrefix", () => { it("returns empty if the string doesn't have whitespace", () => { - const result = AutoClosingPairs.getWhiteSpacePrefix("test") + const result = getWhiteSpacePrefix("test") assert.strictEqual(result, "") }) it("returns tab", () => { - const result = AutoClosingPairs.getWhiteSpacePrefix("\ttest") + const result = getWhiteSpacePrefix("\ttest") assert.strictEqual(result, "\t") }) it("returns spaces", () => { - const result = AutoClosingPairs.getWhiteSpacePrefix(" test") + const result = getWhiteSpacePrefix(" test") assert.strictEqual(result, " ") }) }) + + describe("handleOpenCharacter", () => { + let mockEditor: Mocks.MockEditor + let mockBuffer: Mocks.MockBuffer + + beforeEach(() => { + mockEditor = new Mocks.MockEditor() + mockBuffer = new Mocks.MockBuffer("typescript", "test.ts", [""]) + mockEditor.simulateBufferEnter(mockBuffer) + }) + + it("inserts both characters of the pair", async () => { + const pair = { open: "(", close: ")" } as IAutoClosingPair + + mockBuffer.setLinesSync(["("]) + await checkOpenCharacter( + (str: string) => { + mockBuffer.setLinesSync([str]) + }, + pair, + mockEditor as any, + false, + ) + + const [firstLine] = await mockBuffer.getLines(0, 1) + + assert.strictEqual(firstLine, "()") + }) + + it("doesn't duplicate quote on close", async () => { + const pair = { open: '"', close: '"' } as IAutoClosingPair + + mockBuffer.setLinesSync(['"Oni"']) + mockBuffer.setCursorPosition(0, 4) + await checkOpenCharacter( + (str: string) => { + mockBuffer.setLinesSync([str]) + }, + pair, + mockEditor as any, + true, + ) + + const [firstLine] = await mockBuffer.getLines(0, 1) + + assert.strictEqual(firstLine, '"Oni"') + }) + + it("moves the cursor correctly onto the closing quote", async () => { + const pair = { open: "'", close: "'" } as IAutoClosingPair + + mockBuffer.setLinesSync(["'Oni'"]) + mockBuffer.setCursorPosition(0, 4) + + await checkOpenCharacter( + (str: string) => { + mockBuffer.setLinesSync([str]) + }, + pair, + mockEditor as any, + true, + ) + + const endCursorPos = await mockBuffer.getCursorPosition() + assert.strictEqual(endCursorPos.character, 5) + }) + }) }) diff --git a/browser/test/Services/Snippets/SnippetSessionTests.ts b/browser/test/Services/Snippets/SnippetSessionTests.ts index ac9cf47896..dd6e1e96bf 100644 --- a/browser/test/Services/Snippets/SnippetSessionTests.ts +++ b/browser/test/Services/Snippets/SnippetSessionTests.ts @@ -4,8 +4,6 @@ import * as assert from "assert" -import * as types from "vscode-languageserver-types" - import { OniSnippet } from "./../../../src/Services/Snippets/OniSnippet" import { SnippetSession } from "./../../../src/Services/Snippets/SnippetSession" @@ -39,7 +37,7 @@ describe("SnippetSession", () => { // Add a line, and move cursor to line mockBuffer.setLinesSync(["someline"]) - mockBuffer.setCursorPosition(types.Position.create(0, 4)) + mockBuffer.setCursorPosition(0, 4) await snippetSession.start() @@ -54,7 +52,7 @@ describe("SnippetSession", () => { // Add a line, and move cursor to line mockBuffer.setLinesSync(["someline"]) - mockBuffer.setCursorPosition(types.Position.create(0, 4)) + mockBuffer.setCursorPosition(0, 4) await snippetSession.start() diff --git a/test/ci/Api.Buffer.AddLayer.tsx b/test/ci/Api.Buffer.AddLayer.tsx index 4866cb5b89..b790a702af 100644 --- a/test/ci/Api.Buffer.AddLayer.tsx +++ b/test/ci/Api.Buffer.AddLayer.tsx @@ -1,7 +1,5 @@ /** - * Test script to verify the scenario where no neovim is installed - * - * We should be showing a descriptive error message... + * Test script for the Oni Layers API, tests the adding of new files and splits. */ import * as React from "react" diff --git a/test/ci/Api.Overlays.AddRemoveTest.tsx b/test/ci/Api.Overlays.AddRemoveTest.tsx index dee89d028c..0241bb1cee 100644 --- a/test/ci/Api.Overlays.AddRemoveTest.tsx +++ b/test/ci/Api.Overlays.AddRemoveTest.tsx @@ -1,7 +1,5 @@ /** - * Test script to verify the scenario where no neovim is installed - * - * We should be showing a descriptive error message... + * Test script for the Oni Overlays API, tests the Show / Hide functions. */ import * as React from "react" diff --git a/test/ci/AutoClosingPairsTest.config.js b/test/ci/AutoClosingPairsTest.config.js new file mode 100644 index 0000000000..bb707a8d46 --- /dev/null +++ b/test/ci/AutoClosingPairsTest.config.js @@ -0,0 +1,13 @@ +// For more information on customizing Oni, +// check out our wiki page: +// https://github.com/onivim/oni/wiki/Configuration + +module.exports = { + "autoClosingPairs.default": [ + { open: "{", close: "}" }, + { open: "[", close: "]" }, + { open: "(", close: ")" }, + { open: '"', close: '"' }, + ], + "autoClosingPairs.enabled": true, +}; diff --git a/test/ci/AutoClosingPairsTest.ts b/test/ci/AutoClosingPairsTest.ts index 5e15341dec..e5f7dc0c9b 100644 --- a/test/ci/AutoClosingPairsTest.ts +++ b/test/ci/AutoClosingPairsTest.ts @@ -1,7 +1,6 @@ /** - * Test script to verify the scenario where no neovim is installed + * Test script to verify the behaviour of the auto closing pair feature. * - * We should be showing a descriptive error message... */ import * as assert from "assert" @@ -21,7 +20,8 @@ export const test = async (oni: Oni.Plugin.Api) => { // Wait for the '{' binding to show up, so we get // a deterministic result. - await oni.automation.waitFor(() => oni.input.hasBinding("{")) + await oni.automation.waitFor(() => oni.input.hasBinding("(")) + await oni.automation.waitFor(() => oni.input.hasBinding(")")) oni.automation.sendKeys("i") await oni.automation.waitFor(() => oni.editors.activeEditor.mode === "insert") @@ -36,20 +36,30 @@ export const test = async (oni: Oni.Plugin.Api) => { oni.automation.sendKeys(" => ") oni.automation.sendKeys("{") oni.automation.sendKeys("") + oni.automation.sendKeys("let testString = ") + oni.automation.sendKeys('"') + oni.automation.sendKeys("Oni") + oni.automation.sendKeys('"') + oni.automation.sendKeys("") // Because the input is asynchronous, we need to use `waitFor` to wait // for them to complete. - await oni.automation.waitFor(() => oni.editors.activeEditor.activeBuffer.lineCount === 5) + await oni.automation.waitFor(() => oni.editors.activeEditor.mode === "normal") const lines: string[] = await oni.editors.activeEditor.activeBuffer.getLines(0, 5) const expectedResult = [ "const test = {", " window.setTimeout(() => {", - " ", + ' let testString = "Oni"', " })", "}", ] assert.deepEqual(lines, expectedResult, "Verify lines are as expected") } + +// Bring in custom config to include the "" pair, which isn't part of the default config. +export const settings = { + configPath: "AutoClosingPairTest.config.js", +} diff --git a/test/ci/AutoCompletionTest-CSS.ts b/test/ci/AutoCompletionTest-CSS.ts index 16baf046ab..b0f7b75f64 100644 --- a/test/ci/AutoCompletionTest-CSS.ts +++ b/test/ci/AutoCompletionTest-CSS.ts @@ -1,5 +1,5 @@ /** - * Test scripts for QuickOpen + * Test scripts for Auto Complete for a CSS file. */ import * as assert from "assert" diff --git a/test/ci/AutoCompletionTest-HTML.ts b/test/ci/AutoCompletionTest-HTML.ts index 43287fbab1..9c0f06d77b 100644 --- a/test/ci/AutoCompletionTest-HTML.ts +++ b/test/ci/AutoCompletionTest-HTML.ts @@ -1,5 +1,5 @@ /** - * Test scripts for QuickOpen + * Test scripts for Auto Complete for a HTML file. */ import * as assert from "assert" diff --git a/test/ci/AutoCompletionTest-TypeScript.ts b/test/ci/AutoCompletionTest-TypeScript.ts index 4956d0cb2f..b357a7beda 100644 --- a/test/ci/AutoCompletionTest-TypeScript.ts +++ b/test/ci/AutoCompletionTest-TypeScript.ts @@ -1,5 +1,5 @@ /** - * Test scripts for QuickOpen + * Test scripts for Auto Complete for a Typescript file. */ import * as assert from "assert" diff --git a/test/ci/Common.ts b/test/ci/Common.ts index 4783ea1206..44ff2e99f8 100644 --- a/test/ci/Common.ts +++ b/test/ci/Common.ts @@ -1,5 +1,5 @@ /** - * Test scripts for QuickOpen + * Common functions used across the CI tests. */ import * as Oni from "oni-api" From 7e4c461161109f96dd620811d4494f3f2ee52972 Mon Sep 17 00:00:00 2001 From: Akin Date: Tue, 6 Feb 2018 01:05:42 +0000 Subject: [PATCH 038/103] Bugfix/use editor dimensions (#1318) * add marked to render html in quick info * Add styling changes to QuickInfo * add marked and pre styling * attempt to fix keys react * add font family to container * split out markdown function add link in text component * add markdown to editor - temp * remove highlight.js * remove the horrid cdm link function * add background to code block * add minContent logic reduce padding * fix inner ref in tooltip container fix code font and markdown styles Note bug re rendering if width changes * fix lint errors * remove unhelpful conditional * tweak and positioning * use fit content with a max width * add word break to fix maxwidth bug * force descendants to use parent font * [WIP] do not render special title comp * revert changes * re-add min-width * Revert "re-add min-width" This reverts commit 35c342008afc51f9bf1922a5aa14aad7de1c5e4f. * Revert "revert changes" This reverts commit 2d8bf6b5f2e26a7730023990d6bc922b18039a14. * Revert "Revert "revert changes"" oh goooooood This reverts commit 8e47a865f0ec5a5abfad943b71b653609f500e84. * Revert "Revert "re-add min-width"" ....sigh This reverts commit 2f02306745a8626509584fa69e712db5fd4fd290. * Revert "re-add min-width" This reverts commit 35c342008afc51f9bf1922a5aa14aad7de1c5e4f. * Revert "revert changes" This reverts commit 2d8bf6b5f2e26a7730023990d6bc922b18039a14. * Revert "[WIP] do not render special title comp" This reverts commit 9f3dfef6534bdf1088212880d45e6f585e92ca2a. * Add a container element also use fit-content this means that there will occasionally be too much right padding but *personally* this seems preferable to vscodes solution to use word break: break all which splits midword etc... * Remove common class in quickinfo and border bottom * revert to using word-break * add max height * add max height to documentation * remove max height from container * add max height and overflow * add max-height to each element * add full ternary to hover * Revert "add full ternary to hover" This reverts commit 617684d56ec771f6b276b54e37f29d60cf00d59f. * Revert "Revert "add full ternary to hover"" This reverts commit 63cef8504503252a81cf6aa0a7dde1c7526cb1d2. * Revert "Revert "Revert "add full ternary to hover""" This reverts commit 835c4a88ff71b01c49d1de740f660526a5eda84c. * Revert "Revert "add full ternary to hover"" This reverts commit 63cef8504503252a81cf6aa0a7dde1c7526cb1d2. * Revert "add full ternary to hover" This reverts commit 617684d56ec771f6b276b54e37f29d60cf00d59f. * attempt to fix package and yarn.lock * fix package and lock add keys to signatures * remove keys not unique enough * remove erroneous setState commits are a shambles... * fix check to prevent rendering tooltip if no elements * remove :empty selector as it removes empty styling elems * re-add title styling * make code block wrap in hover tool tip * pass padding as a props to instances of info title comp * fix padding for titles, darken tooltip * Handle code block overflow stop * add overlflow overlay * fix error style highlight * remove styles from code block * set quickinfo container height to fit content add padding default of 0.5rem and max height to documentation and title * get dimensions for active editor and use this for cursor positioner * use focused editor width to in cursorpositioner * remove unused dependency in tooltip * [WIP] get component height inside editor * tidy up changes * revert rxjs to master version * update yarn lock to mirror reversion of rxjs * revert unnecessary changes * use editor viewport for as main height and width saved * remove references to focused editor --- .../src/Editor/NeovimEditor/NeovimEditor.tsx | 11 +-------- .../NeovimEditor/NeovimEditorReducer.ts | 6 +++-- .../src/Editor/NeovimEditor/NeovimSurface.tsx | 24 +++++++++++++++++-- browser/src/UI/components/QuickInfo.tsx | 9 ++++--- browser/src/UI/components/WindowSplitHost.tsx | 1 - 5 files changed, 33 insertions(+), 18 deletions(-) diff --git a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx index e0a26d7ae9..534f6431a4 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx @@ -70,7 +70,7 @@ import { BufferManager, IBuffer } from "./../BufferManager" import { CompletionMenu } from "./CompletionMenu" import { HoverRenderer } from "./HoverRenderer" import { NeovimPopupMenu } from "./NeovimPopupMenu" -import { NeovimSurface } from "./NeovimSurface" +import NeovimSurface from "./NeovimSurface" import { ContextMenuManager } from "./../../Services/ContextMenu" @@ -245,15 +245,6 @@ export class NeovimEditor extends Editor implements IEditor { this._symbols, ) - const updateViewport = () => { - const width = document.body.offsetWidth - const height = document.body.offsetHeight - - this._actions.setViewport(width, height) - } - window.addEventListener("resize", updateViewport) - updateViewport() - this._tasks.registerTaskProvider(commandManager) this._tasks.registerTaskProvider(errorService) diff --git a/browser/src/Editor/NeovimEditor/NeovimEditorReducer.ts b/browser/src/Editor/NeovimEditor/NeovimEditorReducer.ts index aa26689a0f..c69f9933f1 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditorReducer.ts +++ b/browser/src/Editor/NeovimEditor/NeovimEditorReducer.ts @@ -193,11 +193,13 @@ export const definitionReducer = (s: State.IDefinition, a: Actions.SimpleAction) } export const viewportReducer = (s: State.IViewport, a: Actions.ISetViewportAction) => { + const { width, height } = a.payload switch (a.type) { case "SET_VIEWPORT": return { - width: a.payload.width, - height: a.payload.height, + ...s, + width, + height, } default: return s diff --git a/browser/src/Editor/NeovimEditor/NeovimSurface.tsx b/browser/src/Editor/NeovimEditor/NeovimSurface.tsx index 355e65d4b9..9e2ffc6699 100644 --- a/browser/src/Editor/NeovimEditor/NeovimSurface.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimSurface.tsx @@ -5,6 +5,7 @@ */ import * as React from "react" +import { connect } from "react-redux" import { IEvent } from "oni-types" @@ -20,6 +21,7 @@ import { TypingPrediction } from "./../../UI/components/TypingPredictions" import { TypingPredictionManager } from "./../../Services/TypingPredictionManager" +import { setViewport } from "./../NeovimEditor/NeovimEditorActions" import { NeovimBufferLayers } from "./NeovimBufferLayersView" import { NeovimEditorLoadingOverlay } from "./NeovimEditorLoadingOverlay" import { NeovimInput } from "./NeovimInput" @@ -42,9 +44,26 @@ export interface INeovimSurfaceProps { onBounceEnd: () => void onTabClose?: (tabId: number) => void onTabSelect?: (tabId: number) => void + setViewport: any } -export class NeovimSurface extends React.PureComponent { +class NeovimSurface extends React.Component { + private observer: any + private _editor: HTMLDivElement + + public componentDidMount(): void { + // tslint:disable-next-line + this.observer = new window["ResizeObserver"](([entry]: any) => { + this.setDimensions(entry.contentRect.width, entry.contentRect.height) + }) + + this.observer.observe(this._editor) + } + + public setDimensions = (width: number, height: number) => { + this.props.setViewport(width, height) + } + public componentDidCatch(e: Error) { // TODO Add an Error Page to inform user of how to proceed e.g. file bug report // also pass error detais so user can file those @@ -64,7 +83,7 @@ export class NeovimSurface extends React.PureComponent />
-
+
(this._editor = e)}> ) } } +export default connect(null, { setViewport })(NeovimSurface) diff --git a/browser/src/UI/components/QuickInfo.tsx b/browser/src/UI/components/QuickInfo.tsx index 12ade9d070..1fc256b7ba 100644 --- a/browser/src/UI/components/QuickInfo.tsx +++ b/browser/src/UI/components/QuickInfo.tsx @@ -34,8 +34,10 @@ const childStyles = css` ${codeBlockStyle}; } - /* All code blocks are set to black but - this is overriden for code blocks INSIDE a Pre element */ + /* + All code blocks are set to black but + this is overriden for code blocks INSIDE a Pre element + */ code { background-color: ${p => p.theme["editor.hover.contents.codeblock.background"]}; @@ -63,7 +65,8 @@ export const Documentation = styled.div` ${childStyles}; pre { - ${smallScrollbar} ${codeBlockStyle}; + ${smallScrollbar}; + ${codeBlockStyle}; } ` // NOTE: Currently with a max-width in CursorPositioner the text diff --git a/browser/src/UI/components/WindowSplitHost.tsx b/browser/src/UI/components/WindowSplitHost.tsx index 94d51fc18a..9f660e5351 100644 --- a/browser/src/UI/components/WindowSplitHost.tsx +++ b/browser/src/UI/components/WindowSplitHost.tsx @@ -21,7 +21,6 @@ export class WindowSplitHost extends React.PureComponent
{this.props.split.render()}
From 1b95bcf2d7a164af25ba70f02587057350cf4568 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 6 Feb 2018 10:37:09 -0800 Subject: [PATCH 039/103] Command Palette: Two small bug fixes (#1445) * Add some extra padding when there is no icon in the menu * Fix lint issue --- .../Editor/NeovimEditor/NeovimEditorCommands.ts | 4 ++-- browser/src/Services/Menu/MenuComponent.tsx | 17 ++++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/browser/src/Editor/NeovimEditor/NeovimEditorCommands.ts b/browser/src/Editor/NeovimEditor/NeovimEditorCommands.ts index 6159444e70..dbb468f09d 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditorCommands.ts +++ b/browser/src/Editor/NeovimEditor/NeovimEditorCommands.ts @@ -213,14 +213,14 @@ export class NeovimEditorCommands { ), new CallbackCommand( "oni.config.openConfigJs", - "Edit Oni Config", + "Configuration: Edit Oni Config", "Edit configuration file ('config.js') for Oni", () => openDefaultConfig(), ), new CallbackCommand( "oni.config.openInitVim", - "Edit Neovim Config", + "Configuration: Edit Neovim Config", "Edit configuration file ('init.vim') for Neovim", () => this._neovimInstance.openInitVim(), ), diff --git a/browser/src/Services/Menu/MenuComponent.tsx b/browser/src/Services/Menu/MenuComponent.tsx index 8ceac4f8aa..1ee2bfb3e4 100644 --- a/browser/src/Services/Menu/MenuComponent.tsx +++ b/browser/src/Services/Menu/MenuComponent.tsx @@ -222,12 +222,15 @@ export class MenuItem extends React.PureComponent { className += " selected" } - const icon = - this.props.icon && typeof this.props.icon === "string" ? ( - - ) : ( - this.props.icon - ) + let iconToUse: any = + + if (this.props.icon) { + iconToUse = + typeof this.props.icon === "string" + ? (iconToUse = ) + : this.props.icon + } + return ( { onClick={() => this.props.onClick()} style={{ height: this.props.height + "px" }} > - {icon} + {iconToUse} Date: Tue, 6 Feb 2018 18:53:02 +0000 Subject: [PATCH 040/103] add functionality to keep selected tab in view (#1444) Add functionality to keep selected tab in view --- browser/src/UI/components/Tabs.tsx | 83 +++++++++++++++++------------- 1 file changed, 48 insertions(+), 35 deletions(-) diff --git a/browser/src/UI/components/Tabs.tsx b/browser/src/UI/components/Tabs.tsx index 0adf1f331f..3471fd9db0 100644 --- a/browser/src/UI/components/Tabs.tsx +++ b/browser/src/UI/components/Tabs.tsx @@ -116,46 +116,59 @@ export interface ITabPropsWithClick extends ITabProps { maxWidth: string } -export const Tab = (props: ITabPropsWithClick) => { - const cssClasses = classNames("tab", { - selected: props.isSelected, - "not-selected": !props.isSelected, - "is-dirty": props.isDirty, - "not-dirty": !props.isDirty, - }) - - const style = { - backgroundColor: props.backgroundColor, - color: props.foregroundColor, - maxWidth: props.maxWidth, - height: props.height, - borderTop: "2px solid " + props.highlightColor, +export class Tab extends React.Component { + private _tab: HTMLDivElement + public componentWillReceiveProps(next: ITabPropsWithClick) { + if (next.isSelected && this._tab) { + this._tab.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" }) + } } + public render() { + const cssClasses = classNames("tab", { + selected: this.props.isSelected, + "not-selected": !this.props.isSelected, + "is-dirty": this.props.isDirty, + "not-dirty": !this.props.isDirty, + }) - return ( - props.onClickName()}> -
-
- -
-
- {props.name} -
-
-
- + const style = { + backgroundColor: this.props.backgroundColor, + color: this.props.foregroundColor, + maxWidth: this.props.maxWidth, + height: this.props.height, + borderTop: "2px solid " + this.props.highlightColor, + } + + return ( + this.props.onClickName()}> +
(this._tab = e)} + className={cssClasses} + title={this.props.description} + style={style} + > +
+ +
+
+ {this.props.name}
-
-
+
+
+ +
+
+
+
-
- - ) + + ) + } } const getTabName = (name: string): string => { From 8d0e2c1d0b162e4523d9de57be01db8c7e7d18d1 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 6 Feb 2018 11:54:54 -0800 Subject: [PATCH 041/103] Sidebar: Initial vim marks integration (#1430) * Stub out marks integration * Start adding marks integration * Add test case for mark line parser * Add marks object / integration * Integrate full set of marks * Use neovim marks as data source * Remove ConfigurationBookmarksProvider * Start splitting marks between global / local * Hook up containers to bookmarks pane * Fix lint issues * Update marks on buffer enter * Clean up marks UI a bit --- .../src/Services/Bookmarks/BookmarksPane.tsx | 128 +++++++++++++-- browser/src/Services/Bookmarks/index.ts | 98 ++++++------ .../Configuration/DefaultConfiguration.ts | 2 + .../Configuration/IConfigurationValues.ts | 2 + browser/src/UI/components/SidebarItemView.tsx | 6 +- browser/src/index.tsx | 2 +- browser/src/neovim/NeovimInstance.ts | 8 + browser/src/neovim/NeovimMarks.ts | 147 ++++++++++++++++++ browser/src/neovim/index.ts | 1 + browser/test/neovim/NeovimMarksTests.ts | 23 +++ vim/core/oni-core-interop/plugin/init.vim | 19 +++ 11 files changed, 367 insertions(+), 69 deletions(-) create mode 100644 browser/src/neovim/NeovimMarks.ts create mode 100644 browser/test/neovim/NeovimMarksTests.ts diff --git a/browser/src/Services/Bookmarks/BookmarksPane.tsx b/browser/src/Services/Bookmarks/BookmarksPane.tsx index 486f171c9e..24a3cb162f 100644 --- a/browser/src/Services/Bookmarks/BookmarksPane.tsx +++ b/browser/src/Services/Bookmarks/BookmarksPane.tsx @@ -6,13 +6,17 @@ import * as React from "react" +import styled from "styled-components" + +import * as path from "path" + import { Event, IDisposable, IEvent } from "oni-types" import { SidebarPane } from "./../Sidebar" import { IBookmark, IBookmarksProvider } from "./index" import { SidebarEmptyPaneView } from "./../../UI/components/SidebarEmptyPaneView" -import { SidebarItemView } from "./../../UI/components/SidebarItemView" +import { SidebarContainerView, SidebarItemView } from "./../../UI/components/SidebarItemView" import { VimNavigator } from "./../../UI/components/VimNavigator" export class BookmarksPane implements SidebarPane { @@ -26,7 +30,7 @@ export class BookmarksPane implements SidebarPane { } public get title(): string { - return "Bookmarks" + return "Marks" } public enter(): void { @@ -57,6 +61,59 @@ export interface IBookmarksPaneViewProps { export interface IBookmarksPaneViewState { bookmarks: IBookmark[] isActive: boolean + + isGlobalSectionExpanded: boolean + isLocalSectionExpanded: boolean +} + +const BookmarkItemWrapper = styled.div` + display: flex; + flex-direction: row; + + justify-content: center; + align-items; center; + margin-left: 8px; +` + +const BookmarkIconWrapper = styled.div` + padding: 8px; + margin: 4px; + background-color: rgba(0, 0, 0, 0.2); + flex: 0 0 auto; +` + +const BookmarkDescriptionWrapper = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + + margin-left: 8px; + flex: 1 1 auto; + overflow: hidden; +` + +const BookmarkTitleWrapper = styled.div` + text-overflow: ellipsis; + white-space: nowrap; +` + +const BookmarkLocationWrapper = styled.div` + font-size: 0.8em; + text-overflow: ellipsis; +` + +const BookmarkItemView = (props: { bookmark: IBookmark }) => { + return ( + + {props.bookmark.id} + + {path.basename(props.bookmark.text)} + + {props.bookmark.line + ", " + props.bookmark.column} + + + + ) } export class BookmarksPaneView extends React.PureComponent< @@ -70,6 +127,8 @@ export class BookmarksPaneView extends React.PureComponent< this.state = { bookmarks: this.props.bookmarksProvider.bookmarks, isActive: false, + isGlobalSectionExpanded: true, + isLocalSectionExpanded: true, } } @@ -101,26 +160,71 @@ export class BookmarksPaneView extends React.PureComponent< /> ) } else { + const globalMarks = this.state.bookmarks.filter(bm => bm.group === "Global Marks") + const localMarks = this.state.bookmarks.filter(bm => bm.group === "Local Marks") + + const globalMarkIds = this.state.isGlobalSectionExpanded + ? globalMarks.map(bm => bm.id) + : [] + const localMarkIds = this.state.isLocalSectionExpanded + ? localMarks.map(bm => bm.id) + : [] + + const mapToItems = (selectedId: string) => (bm: IBookmark) => ( + } + isFocused={selectedId === bm.id} + isContainer={false} + indentationLevel={0} + /> + ) + + const allIds = [ + "container.global", + ...globalMarkIds, + "container.local", + ...localMarkIds, + ] + return ( this._onSelected(id)} render={selectedId => { - const elems = this.state.bookmarks.map(bm => ( - - )) - return
{elems}
+ const mapFunc = mapToItems(selectedId) + return ( +
+ + {globalMarks.map(mapFunc)} + + + {localMarks.map(mapFunc)} + +
+ ) }} /> ) } } + private _onSelected(id: string): void { + if (id === "container.global") { + this.setState({ isGlobalSectionExpanded: !this.state.isGlobalSectionExpanded }) + } else if (id === "container.local") { + this.setState({ isLocalSectionExpanded: !this.state.isLocalSectionExpanded }) + } + } + private _clearExistingSubscriptions(): void { this._subscriptions.forEach(sub => sub.dispose()) this._subscriptions = [] diff --git a/browser/src/Services/Bookmarks/index.ts b/browser/src/Services/Bookmarks/index.ts index de826240e1..fddfc37624 100644 --- a/browser/src/Services/Bookmarks/index.ts +++ b/browser/src/Services/Bookmarks/index.ts @@ -1,88 +1,78 @@ import { Event, IEvent } from "oni-types" import { Configuration } from "./../Configuration" +import { EditorManager } from "./../EditorManager" import { SidebarManager } from "./../Sidebar" import { BookmarksPane } from "./BookmarksPane" +import { INeovimMarkInfo, INeovimMarks } from "./../../neovim" + export interface IBookmark { - command: string - arguments: any[] group: string + text: string + line: number + column: number + id: string } -import * as fs from "fs" -import * as Log from "./../../Log" - export interface IBookmarksProvider { bookmarks: IBookmark[] onBookmarksUpdated: IEvent + selectBookmark(bookmark: IBookmark): void } -export class ConfigurationBookmarksProvider implements IBookmarksProvider { - private _bookmarks: IBookmark[] = [] - private _onBookmarksUpdatedEvent = new Event() +const marksToBookmarks = (mark: INeovimMarkInfo): IBookmark => ({ + id: mark.mark, + group: mark.global ? "Global Marks" : "Local Marks", + text: mark.text, + line: mark.line, + column: mark.column, +}) + +export class NeovimBookmarksProvider implements IBookmarksProvider { + private _lastBookmarks: IBookmark[] = [] + private _onBookmarksUpdated = new Event() public get bookmarks(): IBookmark[] { - return this._bookmarks + return this._lastBookmarks } public get onBookmarksUpdated(): IEvent { - return this._onBookmarksUpdatedEvent + return this._onBookmarksUpdated } - constructor(private _configuration: Configuration) { - this._configuration.onConfigurationChanged.subscribe(newValues => { - if (newValues["oni.bookmarks"]) { - this._updateFromConfiguration(newValues["oni.bookmarks"]) - } - }) - - const currentBookmarks = this._configuration.getValue("oni.bookmarks") - this._updateFromConfiguration(currentBookmarks) - } + constructor(private _neovimMarks: INeovimMarks) { + this._neovimMarks.onMarksUpdated.subscribe(marks => { + this._lastBookmarks = marks.map(marksToBookmarks) - private _updateBookmarks(bookmarks: IBookmark[]): void { - this._bookmarks = bookmarks - this._onBookmarksUpdatedEvent.dispatch() + this._onBookmarksUpdated.dispatch() + }) } - private _updateFromConfiguration(bookmarks: string[]): void { - if (!bookmarks || !bookmarks.length) { - this._updateBookmarks([]) - return - } - - try { - const newBookmarks = bookmarks.filter(bm => fs.existsSync(bm)).map(bm => { - const stat = fs.statSync(bm) - - if (stat.isDirectory()) { - return { - command: "oni.openFolder", - arguments: [bm], - group: "Workspaces", - } - } else { - return { - command: "oni.openFile", - arguments: [bm], - group: "Files", - } - } - }) - - this._updateBookmarks(newBookmarks) - } catch (e) { - Log.warn("Error loading bookmarks: " + e) - } + public selectBookmark(bookmark: IBookmark): void { + alert("Selecting bookmark: " + bookmark.id) } } let _bookmarks: IBookmarksProvider -export const activate = (configuration: Configuration, sidebarManager: SidebarManager) => { - _bookmarks = new ConfigurationBookmarksProvider(configuration) +export const activate = ( + configuration: Configuration, + editorManager: EditorManager, + sidebarManager: SidebarManager, +) => { + const marksEnabled = + configuration.getValue("sidebar.enabled") && configuration.getValue("sidebar.marks.enabled") + + if (!marksEnabled) { + return + } + + // TODO: Push bookmarks provider to editor + const neovim: any = editorManager.activeEditor.neovim + neovim.marks.watchMarks() + _bookmarks = new NeovimBookmarksProvider(neovim.marks) sidebarManager.add("bookmark", new BookmarksPane(_bookmarks)) } diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index cc6b2873b1..f36f7fe1f4 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -256,6 +256,8 @@ const BaseConfiguration: IConfigurationValues = { "sidebar.enabled": true, "sidebar.width": "50px", + "sidebar.marks.enabled": true, + "statusbar.enabled": true, "statusbar.fontSize": "0.9em", "statusbar.priority": { diff --git a/browser/src/Services/Configuration/IConfigurationValues.ts b/browser/src/Services/Configuration/IConfigurationValues.ts index 839c9522ec..f86e26cda4 100644 --- a/browser/src/Services/Configuration/IConfigurationValues.ts +++ b/browser/src/Services/Configuration/IConfigurationValues.ts @@ -204,6 +204,8 @@ export interface IConfigurationValues { "sidebar.enabled": boolean "sidebar.width": string + "sidebar.marks.enabled": boolean + "statusbar.enabled": boolean "statusbar.fontSize": string diff --git a/browser/src/UI/components/SidebarItemView.tsx b/browser/src/UI/components/SidebarItemView.tsx index 3cb1ff40b7..2f5f4347da 100644 --- a/browser/src/UI/components/SidebarItemView.tsx +++ b/browser/src/UI/components/SidebarItemView.tsx @@ -10,7 +10,7 @@ import styled from "styled-components" import { withProps } from "./common" export interface ISidebarItemViewProps { - text: string + text: string | JSX.Element isFocused: boolean isContainer: boolean indentationLevel: number @@ -42,6 +42,7 @@ const SidebarItemStyleWrapper = withProps(styled.div)` .name { flex: 1 1 auto; + overflow: hidden; } ` @@ -66,10 +67,11 @@ const INDENT_AMOUNT = 6 export class SidebarItemView extends React.PureComponent { public render(): JSX.Element { + const icon = this.props.icon ?
{this.props.icon}
: null return ( -
{this.props.icon}
+ {icon}
{this.props.text}
) diff --git a/browser/src/index.tsx b/browser/src/index.tsx index 0e88609b6c..843983faae 100644 --- a/browser/src/index.tsx +++ b/browser/src/index.tsx @@ -214,7 +214,7 @@ const start = async (args: string[]): Promise => { ThemePicker.activate(configuration, menuManager, Themes.getThemeManagerInstance()) const Bookmarks = await import("./Services/Bookmarks") - Bookmarks.activate(configuration, sidebarManager) + Bookmarks.activate(configuration, editorManager, Sidebar.getInstance()) const PluginsSidebarPane = await import("./Plugins/PluginSidebarPane") PluginsSidebarPane.activate(pluginManager, sidebarManager) diff --git a/browser/src/neovim/NeovimInstance.ts b/browser/src/neovim/NeovimInstance.ts index f016b9f84b..194b6a066b 100644 --- a/browser/src/neovim/NeovimInstance.ts +++ b/browser/src/neovim/NeovimInstance.ts @@ -17,6 +17,7 @@ import { Configuration } from "./../Services/Configuration" import * as Actions from "./actions" import { NeovimBufferReference } from "./MsgPack" import { INeovimAutoCommands, NeovimAutoCommands } from "./NeovimAutoCommands" +import { INeovimMarks, NeovimMarks } from "./NeovimMarks" import { INeovimStartOptions, startNeovim } from "./NeovimProcessSpawner" import { IQuickFixList, QuickFixList } from "./QuickFix" import { IPixelPosition, IPosition } from "./Screen" @@ -125,6 +126,7 @@ export interface INeovimInstance { onCommandLineSetCursorPosition: IEvent autoCommands: INeovimAutoCommands + marks: INeovimMarks screenToPixels(row: number, col: number): IPixelPosition @@ -192,6 +194,7 @@ export class NeovimInstance extends EventEmitter implements INeovimInstance { private _cols: number private _quickFix: QuickFixList + private _marks: NeovimMarks private _initComplete: boolean private _onDirectoryChanged = new Event() @@ -311,6 +314,10 @@ export class NeovimInstance extends EventEmitter implements INeovimInstance { return this._autoCommands } + public get marks(): INeovimMarks { + return this._marks + } + constructor(widthInPixels: number, heightInPixels: number, configuration: Configuration) { super() this._configuration = configuration @@ -322,6 +329,7 @@ export class NeovimInstance extends EventEmitter implements INeovimInstance { this._quickFix = new QuickFixList(this) this._autoCommands = new NeovimAutoCommands(this) + this._marks = new NeovimMarks(this) this._bufferUpdateManager = new NeovimBufferUpdateManager(this._configuration, this) } diff --git a/browser/src/neovim/NeovimMarks.ts b/browser/src/neovim/NeovimMarks.ts new file mode 100644 index 0000000000..fe8d431a7f --- /dev/null +++ b/browser/src/neovim/NeovimMarks.ts @@ -0,0 +1,147 @@ +/** + * NeovimMarks.ts + * + * Strongly typed interface to Neovim's mark functionality + */ + +import { Event, IEvent } from "oni-types" + +import { NeovimInstance } from "./NeovimInstance" + +export interface INeovimMarkInfo { + mark: string + global: boolean + line: number + column: number + text: string +} + +export interface INeovimMarks { + onMarksUpdated: IEvent + + /** + * Call to start watching marks. Note that this forces + * the mappings to the canonical `ma`, etc. + */ + watchMarks(): void +} + +const parseMarks = (marks: string): INeovimMarkInfo[] => { + if (!marks) { + return [] + } + + const allLines = marks.split("\n") + + // First two lines are a new line and the headers - + // we don't care about those. + const [, , ...markLines] = allLines + + const ret = markLines.map(ml => parseMarkLine(ml)) + + return ret +} + +const isWhitespace = (character: string): boolean => /\s/.test(character) +const isAlphaNumeric = (character: string): boolean => /^[a-z0-9]+$/i.test(character) + +const getNextNonWhitespaceCharacter = (str: string, start: number): number => { + let idx = start + while (idx < str.length) { + if (!isWhitespace(str[idx])) { + return idx + } + idx++ + } + + return -1 +} + +const getNextWhitespaceCharacter = (str: string, start: number): number => { + let idx = start + while (idx < str.length) { + if (isWhitespace(str[idx])) { + return idx + } + idx++ + } + + return -1 +} + +const isLowerCase = (str: string) => str.toLowerCase() === str + +export const parseMarkLine = (markLine: string): INeovimMarkInfo => { + const markStartIndex = getNextNonWhitespaceCharacter(markLine, 0) + const markEndIndex = getNextWhitespaceCharacter(markLine, markStartIndex + 1) + + const lineStartIndex = getNextNonWhitespaceCharacter(markLine, markEndIndex + 1) + const lineEndIndex = getNextWhitespaceCharacter(markLine, lineStartIndex + 1) + + const columnStartIndex = getNextNonWhitespaceCharacter(markLine, lineEndIndex + 1) + const columnEndIndex = getNextWhitespaceCharacter(markLine, columnStartIndex + 1) + + const textStartIndex = getNextNonWhitespaceCharacter(markLine, columnEndIndex + 1) + + const mark = markLine.substring(markStartIndex, markEndIndex) + const lineNumber = parseInt(markLine.substring(lineStartIndex, lineEndIndex), 10) + const column = parseInt(markLine.substring(columnStartIndex, columnEndIndex), 10) + const text = markLine.substring(textStartIndex, markLine.length) + const isGlobal = !isLowerCase(mark) + + return { + mark, + line: lineNumber, + column, + text, + global: isGlobal, + } +} + +export class NeovimMarks { + private _onMarksUpdatedEvent = new Event() + private _isWatching: boolean = false + + public get onMarksUpdated(): IEvent { + return this._onMarksUpdatedEvent + } + + constructor(private _neovimInstance: NeovimInstance) {} + + public watchMarks(): void { + if (this._isWatching) { + return + } + this._isWatching = true + this._neovimInstance.callFunction("OniListenForMarks", []) + + this._neovimInstance.onOniCommand.subscribe(val => { + if (val === "_internal.notifyMarksChanged") { + this._updateMarks() + } + }) + + this._neovimInstance.autoCommands.onBufEnter.subscribe(val => { + this._updateMarks() + }) + } + + private async _updateMarks(): Promise { + const latestMarks = await this._readMarks() + this._onMarksUpdatedEvent.dispatch(latestMarks) + } + + private async _readMarks(): Promise { + const markInfo: string = await this._neovimInstance.request("nvim_command_output", [ + ":marks", + ]) + + const allMarks = parseMarks(markInfo) + + // We'll only show the alpha-numeric marks, because those are + // the only ones we're tracking updates on. + + const marks = allMarks.filter(am => isAlphaNumeric(am.mark)) + return marks + } +} diff --git a/browser/src/neovim/index.ts b/browser/src/neovim/index.ts index bd0536f069..99363c065d 100644 --- a/browser/src/neovim/index.ts +++ b/browser/src/neovim/index.ts @@ -5,5 +5,6 @@ export * from "./Screen" export * from "./Session" export * from "./NeovimProcessSpawner" export * from "./NeovimInstance" +export * from "./NeovimMarks" export * from "./NeovimWindowManager" export * from "./QuickFix" diff --git a/browser/test/neovim/NeovimMarksTests.ts b/browser/test/neovim/NeovimMarksTests.ts new file mode 100644 index 0000000000..8605dc5991 --- /dev/null +++ b/browser/test/neovim/NeovimMarksTests.ts @@ -0,0 +1,23 @@ +/** + * NeovimMarksTest.ts + */ + +import * as assert from "assert" + +import { parseMarkLine } from "./../../src/neovim/NeovimMarks" + +describe("NeovimMarks", () => { + describe("parseMarkLine", () => { + it("parses a simple line", () => { + const line = " A 1 10 some Text" + + const markInfo = parseMarkLine(line) + + assert.strictEqual(markInfo.line, 1) + assert.strictEqual(markInfo.column, 10) + assert.strictEqual(markInfo.mark, "A") + assert.strictEqual(markInfo.global, true) + assert.strictEqual(markInfo.text, "some Text") + }) + }) +}) diff --git a/vim/core/oni-core-interop/plugin/init.vim b/vim/core/oni-core-interop/plugin/init.vim index 724fe70af2..33c8a8dac6 100644 --- a/vim/core/oni-core-interop/plugin/init.vim +++ b/vim/core/oni-core-interop/plugin/init.vim @@ -214,6 +214,25 @@ function! OniNextWindow( direction ) endif endfunction +function! OniSetMarkAndReport(mark) + execute 'normal! m' . a:mark + call OniCommand("_internal.notifyMarksChanged") +endfunction + +let s:all_marks = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + +function! OniListenForMarks() + + let n = 0 + let s:maxmarks = strlen(s:all_marks) + while n < s:maxmarks + let c = strpart(s:all_marks, n, 1) + execute "nnoremap m" . c . " : call OniSetMarkAndReport('" . c . "')" + let n = n + 1 + endwhile + call OniCommand("_internal.notifyMarksChanged") +endfunction + nnoremap gd :call OniCommand("language.gotoDefinition") nnoremap h :call OniNextWindow('h') nnoremap j :call OniNextWindow('j') From 3784778a4c3ed1f1e656c57b099c986de0feb3b6 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 6 Feb 2018 12:07:19 -0800 Subject: [PATCH 042/103] Sidebar - Search: Debounce search requests (#1448) * Add debounce logic to search provider * Add additional logging for finder process --- browser/src/Services/QuickOpen/FinderProcess.ts | 9 +++++++++ browser/src/Services/Search/index.tsx | 12 ++++++++++++ 2 files changed, 21 insertions(+) diff --git a/browser/src/Services/QuickOpen/FinderProcess.ts b/browser/src/Services/QuickOpen/FinderProcess.ts index 2c41efd185..bc77ba832b 100644 --- a/browser/src/Services/QuickOpen/FinderProcess.ts +++ b/browser/src/Services/QuickOpen/FinderProcess.ts @@ -8,6 +8,8 @@ import { ChildProcess, spawn } from "child_process" import { Event, IEvent } from "oni-types" +import * as Log from "./../../Log" + export class FinderProcess { private _process: ChildProcess @@ -32,6 +34,13 @@ export class FinderProcess { return } + if (Log.isDebugLoggingEnabled()) { + Log.debug( + "[FinderProcess::start] Starting finder process with this command: " + + this._command, + ) + } + this._process = spawn(this._command, [], { shell: true }) this._process.stdout.on("data", data => { if (!data) { diff --git a/browser/src/Services/Search/index.tsx b/browser/src/Services/Search/index.tsx index ed75164a6c..9a102b4cdc 100644 --- a/browser/src/Services/Search/index.tsx +++ b/browser/src/Services/Search/index.tsx @@ -8,6 +8,8 @@ import * as React from "react" import { Event, IDisposable, IEvent } from "oni-types" +import { Subject } from "rxjs/Subject" + import { EditorManager } from "./../EditorManager" import { SidebarManager } from "./../Sidebar" import { Workspace } from "./../Workspace" @@ -31,6 +33,8 @@ export class SearchPane { private _searchProvider: ISearchProvider private _currentQuery: ISearchQuery + private _searchOptionsObservable = new Subject() + public get id(): string { return "oni.sidebar.search" } @@ -41,6 +45,10 @@ export class SearchPane { constructor(private _editorManager: EditorManager, private _workspace: Workspace) { this._searchProvider = new RipGrepSearchProvider() + + this._searchOptionsObservable.debounceTime(100).subscribe((opts: ISearchOptions) => { + this._startNewSearch(opts) + }) } public enter(): void { @@ -63,6 +71,10 @@ export class SearchPane { } private _onSearchOptionsChanged(searchOpts: ISearchOptions): void { + this._searchOptionsObservable.next(searchOpts) + } + + private _startNewSearch(searchOpts: ISearchOptions): void { console.log("changed: " + searchOpts) if (this._currentQuery) { From 4973ef97668cb899c6aba296cac67d0b729bbe21 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 6 Feb 2018 15:08:06 -0800 Subject: [PATCH 043/103] Bugfix: Scrollbar keys (#1450) * Add distinguished key, and filter for duplicates * Fix lint issues --- browser/src/UI/components/BufferScrollBar.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/browser/src/UI/components/BufferScrollBar.tsx b/browser/src/UI/components/BufferScrollBar.tsx index a0608e8af1..24bfb5de53 100644 --- a/browser/src/UI/components/BufferScrollBar.tsx +++ b/browser/src/UI/components/BufferScrollBar.tsx @@ -1,9 +1,12 @@ import * as React from "react" +import * as uniqBy from "lodash/uniqBy" import styled from "styled-components" import { bufferScrollBarSize } from "./common" +import { EmptyArray } from "./../../Utility" + export interface IBufferScrollBarProps { windowId: number bufferSize: number @@ -59,9 +62,10 @@ export class BufferScrollBar extends React.PureComponent { + const uniqueMarkers = uniqBy(markers, m => m.id) + const markerElements = uniqueMarkers.map(m => { const line = m.line const pos = line / this.props.bufferSize * this.props.height const size = "2px" @@ -74,7 +78,7 @@ export class BufferScrollBar extends React.PureComponent + return
}) return ( From aa678392d2729c47f06ea5e16113971b71e4b3a0 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 6 Feb 2018 15:08:19 -0800 Subject: [PATCH 044/103] Scope down search and remove filter for now (#1451) --- browser/src/Services/Search/index.tsx | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/browser/src/Services/Search/index.tsx b/browser/src/Services/Search/index.tsx index 9a102b4cdc..744e14c9a9 100644 --- a/browser/src/Services/Search/index.tsx +++ b/browser/src/Services/Search/index.tsx @@ -134,7 +134,7 @@ export class SearchPaneView extends React.PureComponent< isActive: false, activeTextbox: null, searchQuery: "Type to search...", - fileFilter: "*.*", + fileFilter: null, } } @@ -174,7 +174,7 @@ export class SearchPaneView extends React.PureComponent< return ( { this._onSelected(selectedId) }} @@ -190,7 +190,7 @@ export class SearchPaneView extends React.PureComponent< isFocused={selectedId === "textbox.query"} isActive={this.state.activeTextbox === "textbox.query"} /> - + {/* this._onChangeFilesFilter(val)} @@ -198,7 +198,7 @@ export class SearchPaneView extends React.PureComponent< onDismiss={() => this._clearActiveTextbox()} isFocused={selectedId === "textbox.filter"} isActive={this.state.activeTextbox === "textbox.filter"} - /> + />*/}
) }} @@ -206,13 +206,13 @@ export class SearchPaneView extends React.PureComponent< ) } - private _onChangeFilesFilter(val: string): void { - this.setState({ - fileFilter: val, - }) + // private _onChangeFilesFilter(val: string): void { + // this.setState({ + // fileFilter: val, + // }) - this._startSearch() - } + // this._startSearch() + // } private _onChangeSearchQuery(val: string): void { this.setState({ From 8599ba721ac5a0e168ef8c530ce82f03abb9bf48 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 6 Feb 2018 15:29:01 -0800 Subject: [PATCH 045/103] Add configuration gate for plugins (#1452) --- browser/src/Plugins/PluginSidebarPane.tsx | 13 ++++++++++--- .../Services/Configuration/DefaultConfiguration.ts | 1 + .../Services/Configuration/IConfigurationValues.ts | 1 + browser/src/index.tsx | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/browser/src/Plugins/PluginSidebarPane.tsx b/browser/src/Plugins/PluginSidebarPane.tsx index 463c924e2d..2e0eaef78a 100644 --- a/browser/src/Plugins/PluginSidebarPane.tsx +++ b/browser/src/Plugins/PluginSidebarPane.tsx @@ -8,6 +8,7 @@ import * as React from "react" import { Event, IDisposable, IEvent } from "oni-types" +import { Configuration } from "./../Services/Configuration" import { SidebarManager, SidebarPane } from "./../Services/Sidebar" import { SidebarContainerView, SidebarItemView } from "./../UI/components/SidebarItemView" @@ -160,7 +161,13 @@ export class PluginsSidebarPaneView extends React.PureComponent< } } -export const activate = (pluginManager: PluginManager, sidebarManager: SidebarManager) => { - const pane = new PluginsSidebarPane(pluginManager) - sidebarManager.add("plug", pane) +export const activate = ( + configuration: Configuration, + pluginManager: PluginManager, + sidebarManager: SidebarManager, +) => { + if (configuration.getValue("sidebar.plugins.enabled")) { + const pane = new PluginsSidebarPane(pluginManager) + sidebarManager.add("plug", pane) + } } diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index f36f7fe1f4..9544c859f2 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -257,6 +257,7 @@ const BaseConfiguration: IConfigurationValues = { "sidebar.width": "50px", "sidebar.marks.enabled": true, + "sidebar.plugins.enabled": false, "statusbar.enabled": true, "statusbar.fontSize": "0.9em", diff --git a/browser/src/Services/Configuration/IConfigurationValues.ts b/browser/src/Services/Configuration/IConfigurationValues.ts index f86e26cda4..fd4c549378 100644 --- a/browser/src/Services/Configuration/IConfigurationValues.ts +++ b/browser/src/Services/Configuration/IConfigurationValues.ts @@ -205,6 +205,7 @@ export interface IConfigurationValues { "sidebar.width": string "sidebar.marks.enabled": boolean + "sidebar.plugins.enabled": boolean "statusbar.enabled": boolean "statusbar.fontSize": string diff --git a/browser/src/index.tsx b/browser/src/index.tsx index 843983faae..f8477b8e92 100644 --- a/browser/src/index.tsx +++ b/browser/src/index.tsx @@ -217,7 +217,7 @@ const start = async (args: string[]): Promise => { Bookmarks.activate(configuration, editorManager, Sidebar.getInstance()) const PluginsSidebarPane = await import("./Plugins/PluginSidebarPane") - PluginsSidebarPane.activate(pluginManager, sidebarManager) + PluginsSidebarPane.activate(configuration, pluginManager, sidebarManager) Performance.endMeasure("Oni.Start.Activate") From 52fac3fcf1a37df4d573c283cd64cdcc8c208ac5 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 6 Feb 2018 15:55:10 -0800 Subject: [PATCH 046/103] Add entrance animations for sidebar icons (#1453) --- browser/src/Services/Sidebar/SidebarContentSplit.tsx | 9 ++++++++- browser/src/Services/Sidebar/SidebarView.tsx | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/browser/src/Services/Sidebar/SidebarContentSplit.tsx b/browser/src/Services/Sidebar/SidebarContentSplit.tsx index 2556a98468..ff57ffcfec 100644 --- a/browser/src/Services/Sidebar/SidebarContentSplit.tsx +++ b/browser/src/Services/Sidebar/SidebarContentSplit.tsx @@ -4,7 +4,7 @@ import * as React from "react" import { connect, Provider } from "react-redux" -import styled from "styled-components" +import styled, { keyframes } from "styled-components" import { Event, IDisposable, IEvent } from "oni-types" @@ -75,6 +75,11 @@ export interface ISidebarContentViewState { active: boolean } +const EntranceKeyframes = keyframes` + 0% { opacity: 0.5; transform: translateX(-5px); } + 100%% { opacity: 1; transform: translateX(0px); } +` + export const SidebarContentWrapper = withProps<{}>(styled.div)` ${enableMouse} width: 200px; @@ -84,6 +89,8 @@ export const SidebarContentWrapper = withProps<{}>(styled.div)` user-select: none; cursor: default; + animation: ${EntranceKeyframes} 0.25s ease-in forwards; + display: flex; flex-direction: column; ` diff --git a/browser/src/Services/Sidebar/SidebarView.tsx b/browser/src/Services/Sidebar/SidebarView.tsx index 7ddec712db..7f34c80ff5 100644 --- a/browser/src/Services/Sidebar/SidebarView.tsx +++ b/browser/src/Services/Sidebar/SidebarView.tsx @@ -11,7 +11,7 @@ import { Icon, IconSize } from "./../../UI/Icon" import { ISidebarEntry, ISidebarState } from "./SidebarStore" -import styled from "styled-components" +import styled, { keyframes } from "styled-components" import { withProps } from "./../../UI/components/common" import { Sneakable } from "./../../UI/components/Sneakable" @@ -25,6 +25,11 @@ export interface ISidebarIconProps { import { VimNavigator } from "./../../UI/components/VimNavigator" +const EntranceKeyframes = keyframes` + 0% { opacity: 0.5; transform: scale(0.5) translateX(-10px); } + 100%% { opacity: 1; transform: scale(1.0) translateX(0px); } +` + const SidebarIconWrapper = withProps(styled.div)` display: flex; justify-content: center; @@ -40,6 +45,8 @@ const SidebarIconWrapper = withProps(styled.div)` transition: transform 0.2s ease-in; transform: ${props => (props.active || props.focused ? "translateY(0px)" : "translateY(0px)")}; + animation: ${EntranceKeyframes} 0.1s ease-in forwards; + &.active { opacity: 0.75; } From aab2ed9aa6b1b1b8af4d315d02c55899fa08300a Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 6 Feb 2018 18:13:02 -0800 Subject: [PATCH 047/103] Re-introduce delay for querying definition that was removed during refactoring (#1454) --- browser/src/Services/Language/LanguageStore.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/browser/src/Services/Language/LanguageStore.ts b/browser/src/Services/Language/LanguageStore.ts index 0f773d0085..93896a9f66 100644 --- a/browser/src/Services/Language/LanguageStore.ts +++ b/browser/src/Services/Language/LanguageStore.ts @@ -244,6 +244,8 @@ export const queryForDefinitionEpic = ( ): Epic => (action$, store) => action$ .ofType("CURSOR_MOVED") + .debounceTime(configuration.getValue("editor.quickInfo.delay")) + .filter(() => store.getState().mode === "normal") .filter( () => store.getState().mode === "normal" && From fbfb27a73c39f87b5c63cf9a472d228f42cb0a01 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 6 Feb 2018 19:19:48 -0800 Subject: [PATCH 048/103] Fix #1473: Run integration tests against local electron on developer machines (#1456) * Generalize automation to work against local build and against dist build on CI machines * Fix lint issue --- test/common/Oni.ts | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/test/common/Oni.ts b/test/common/Oni.ts index 3737a76b24..84f79489d6 100644 --- a/test/common/Oni.ts +++ b/test/common/Oni.ts @@ -7,7 +7,17 @@ const log = (msg: string) => { console.log(msg) // tslint:disable-line no-console } -const getExecutablePath = () => { +const isCiBuild = () => { + const ciBuild = !!( + process.env.ONI_AUTOMATION_USE_DIST_BUILD || + process.env.CONTINUOUS_INTEGRATION /* set by travis */ || + process.env.APPVEYOR + ) /* set by appveyor */ + log("isCiBuild: " + ciBuild) + return ciBuild +} + +const getExecutablePathOnCiMachine = () => { switch (process.platform) { case "win32": return path.join(__dirname, "..", "..", "..", "dist", "win-ia32-unpacked", "Oni.exe") @@ -40,6 +50,18 @@ const getExecutablePath = () => { } } +const getExecutablePathLocally = () => { + const nodeModulesBinPath = path.join(__dirname, "..", "..", "..", "node_modules", ".bin") + return process.platform === "win32" + ? path.join(nodeModulesBinPath, "electron.cmd") + : path.join(nodeModulesBinPath, "electron") +} + +const getArgsForCiMachine = () => [] +const getArgsForLocalExecution = () => [ + path.join(__dirname, "..", "..", "..", "lib", "main", "src", "main.js"), +] + export interface OniStartOptions { configurationPath?: string } @@ -52,13 +74,17 @@ export class Oni { } public async start(options: OniStartOptions = {}): Promise { - const executablePath = getExecutablePath() + const ciBuild = isCiBuild() + const executablePath = ciBuild ? getExecutablePathOnCiMachine() : getExecutablePathLocally() + const executableArgs = ciBuild ? getArgsForCiMachine() : getArgsForLocalExecution() log("Using executable path: " + executablePath) + log("Using executable args: " + executableArgs) log("Start options: " + JSON.stringify(options)) this._app = new Application({ path: executablePath, + args: executableArgs, env: options.configurationPath ? { ONI_CONFIG_FILE: options.configurationPath } : {}, }) From f1701ac1160cceec43601308b4318e1cfca9825b Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 7 Feb 2018 07:40:20 -0800 Subject: [PATCH 049/103] Check that completionItem actually exists before accessing provider (#1457) --- browser/src/Services/Completion/CompletionProviders.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/src/Services/Completion/CompletionProviders.ts b/browser/src/Services/Completion/CompletionProviders.ts index 5a6535909c..25dfe522c1 100644 --- a/browser/src/Services/Completion/CompletionProviders.ts +++ b/browser/src/Services/Completion/CompletionProviders.ts @@ -64,7 +64,7 @@ export class CompletionProviders implements ICompletionsRequestor { filePath: string, completionItem: ICompletionInfoWithProvider, ): Promise { - if (completionItem.__provider) { + if (completionItem && completionItem.__provider) { const prov = this._getProviderById(completionItem.__provider) if (prov && prov.getCompletionDetails) { From ada88bb12a25c7977b848bcb6437a535c4d55b94 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 7 Feb 2018 09:56:54 -0800 Subject: [PATCH 050/103] Fix regression in react/redux devtools (#1467) * Gate isDevelopment on webpack build environment variable, too * Update electron-devtools-installer --- main/src/main.ts | 2 +- package.json | 2 +- yarn.lock | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/main/src/main.ts b/main/src/main.ts index 6de4679513..eb51a58bb0 100644 --- a/main/src/main.ts +++ b/main/src/main.ts @@ -11,7 +11,7 @@ import { makeSingleInstance } from "./ProcessLifecycle" global["getLogs"] = Log.getAllLogs // tslint:disable-line no-string-literal -const isDevelopment = process.env.NODE_ENV === "development" +const isDevelopment = process.env.NODE_ENV === "development" || process.env.ONI_WEBPACK_LOAD === "1" const isDebug = process.argv.filter(arg => arg.indexOf("--debug") >= 0).length > 0 interface IWindowState { diff --git a/package.json b/package.json index 425e43abe5..140208e9ea 100644 --- a/package.json +++ b/package.json @@ -257,7 +257,7 @@ "css-loader": "0.28.4", "electron": "^1.8.2-beta.5", "electron-builder": "19.46.4", - "electron-devtools-installer": "2.2.1", + "electron-devtools-installer": "^2.2.3", "electron-mocha": "5.0.0", "electron-rebuild": "1.6.0", "extract-zip": "1.6.0", diff --git a/yarn.lock b/yarn.lock index 9459dda41f..b5c1ebbfdf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2100,9 +2100,9 @@ electron-chromedriver@~1.6.0: electron-download "^3.1.0" extract-zip "^1.6.0" -electron-devtools-installer@2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/electron-devtools-installer/-/electron-devtools-installer-2.2.1.tgz#0beb73ccbf65cbc4d09e706cebda638f839b8c55" +electron-devtools-installer@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/electron-devtools-installer/-/electron-devtools-installer-2.2.3.tgz#58b9a4ec507377bc46e091cd43714188e0c369be" dependencies: "7zip" "0.0.6" cross-unzip "0.0.2" From 53622ac8acafed23afeac01f25c5f311c56d0c63 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 7 Feb 2018 10:00:19 -0800 Subject: [PATCH 051/103] Update AWS key for media uploads (#1462) * Update access key to use IAM user * Update tokens * Update keys, add S3 deploy strategy * Fix up appveyor yml --- .travis.yml | 19 +++++++++++++++++-- appveyor.yml | 29 ++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index efd36a2105..f9d6e835fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,9 +36,9 @@ after_success: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then node_modules/.bin/coveralls < .nyc_output/lcov.info; fi deploy: - provider: s3 - access_key_id: AKIAIPVCKNWKWB2XULQQ + access_key_id: AKIAIYMATI2CEFTHPBOQ secret_access_key: - secure: IKLeZsM1R8pq/eBqBCnsFe6iSF+ZHaokY6yBf6FtxaqHw7qJR3RQ9XI9N7mooKXOAsp7prDBNW6sdciGmzXpDW7myDz5eEfmVOIZxb6zq0XUwsikkgrzgS22bMkj32CZuRzR8agzF7US+G6OfVo+MIhChOPKBfqkbUbQdWm0tYX0NJsNyt8Ax8GdyzAj98cazw5tV2HWT7M11EKQCssc1CiFWqR51Zqmy34d/jEWJEe+P3avRDpNCJf6uuzfrtpn1swCb0EY7aZGDischXwRJDyZ6GXrjECxazN2T7JwcwKw/Y+XOeiwp5H+ell+1C/tZMXcn8OyOZurVQdG7MNGHil0Jt/t4QL6XpNXXF8I1k1LQDty7SPnZRKaAYo8rNyDFqGt5oVLvTm8GD9KjI4rGPt7VvzUQS5SITRnI1m6wq0YDdVqcR9/Z2cLmXHmzhOmB3FLCTKQXXCMaG1dAzlYQDOspo9RKr+nuDpherNMSiqSeVUM97UrfRQ2pC/JfoL/f6j2jt88Y7XfF9x48h+6Pm8ny5rlSaU4otnVpgAeoMEMED5s93zZrVxF7ydyZ0ZvBLKfK13mJwleCq3R1DbYStp1bor0MFwVoVRRRLcxIo6bhlmJsd0qhIFXL8BcE1wLzDITnXVxAxg9izRPYPcSgRLyjJ1SqaxoT89cO0YlNEU= + secure: S4f/aczEABGAMKk2tmVSkoGx+T2TLPmz5z6x6RKaM+eDmAaVSAELlIj1eAz6Tu2lv3jz+cpyAIISZNC/phORsJWwzbSZHVycLrMG0N3fDTqKFxu1fl6L3b3exRe9SiKXug73ZvHfktzd/XfRcgZKop4qgrwGiM57m0ZuZb/j1LkgjytTuvNAUxXbA84I8LZs/NhY17XuXq+KPlGElIHy3UFoGqQ8pBnTypkIU5rQTsoeAxXLBE8JAFfz+nBGZ7dx6OMbQcKX5jKh/gR3vk+4aTgV8gNE2Zp24ErjSqF2zly/gP9nE2DpfR7jqpZVHnb/v+OEjRDS80tLhPo8Dbibzwt2ZZNADpYBjSGtphwAmq4DCvJ7ORExOB5+O3wmXKQGdItyBTS7sW44n6BTyv87WxWuCaSDQ9QaO9PrbJdN5YGEYeRxSTM7Mn0t72IILkfFCUeSg6fl6tFs9iWIj5zltbxH1GQsRpA8j1Idg4O+894KnQABtw/YKh6rrdeYS9y/100qAjtV6qYyiP2IdPqMWGuasOiz87q3CQ8Ejd7uhiTjAaINVqos+0k04Yf5+rT4MqkeXnYFzjXuXcqDlpq6yJIZv3aD+PMSlZi2WmTYnPJXQFndHo/x9FhEh90UF9WdO5S27ySRSo8XQT4DyL3ToPkqz8y0slNmaNqiqMouQAU= bucket: oni-media local-dir: dist/media acl: public_read @@ -47,6 +47,21 @@ deploy: on: condition: $TRAVIS_OS_NAME = osx repo: onivim/oni + - provider: s3 + access_key_id: AKIAIYMATI2CEFTHPBOQ + secret_access_key: + secure: S4f/aczEABGAMKk2tmVSkoGx+T2TLPmz5z6x6RKaM+eDmAaVSAELlIj1eAz6Tu2lv3jz+cpyAIISZNC/phORsJWwzbSZHVycLrMG0N3fDTqKFxu1fl6L3b3exRe9SiKXug73ZvHfktzd/XfRcgZKop4qgrwGiM57m0ZuZb/j1LkgjytTuvNAUxXbA84I8LZs/NhY17XuXq+KPlGElIHy3UFoGqQ8pBnTypkIU5rQTsoeAxXLBE8JAFfz+nBGZ7dx6OMbQcKX5jKh/gR3vk+4aTgV8gNE2Zp24ErjSqF2zly/gP9nE2DpfR7jqpZVHnb/v+OEjRDS80tLhPo8Dbibzwt2ZZNADpYBjSGtphwAmq4DCvJ7ORExOB5+O3wmXKQGdItyBTS7sW44n6BTyv87WxWuCaSDQ9QaO9PrbJdN5YGEYeRxSTM7Mn0t72IILkfFCUeSg6fl6tFs9iWIj5zltbxH1GQsRpA8j1Idg4O+894KnQABtw/YKh6rrdeYS9y/100qAjtV6qYyiP2IdPqMWGuasOiz87q3CQ8Ejd7uhiTjAaINVqos+0k04Yf5+rT4MqkeXnYFzjXuXcqDlpq6yJIZv3aD+PMSlZi2WmTYnPJXQFndHo/x9FhEh90UF9WdO5S27ySRSo8XQT4DyL3ToPkqz8y0slNmaNqiqMouQAU= + bucket: oni-builds + files: + - dist/*.dmg + - dist/*.zip + upload-dir: osx_builds + acl: public_read + region: us-west-2 + skip_cleanup: true + on: + condition: $TRAVIS_OS_NAME = osx + repo: onivim/oni - provider: releases api_key: secure: AjQUeQNockqkBrVQCOQGyKq+sZ9C4SabSqp/bmXayKTB+7AmM8oohenxC09Sc4/dmIW1PQnDYL/4fjclJSRaywV5oiPqUnfhTveALkKFErmYnhA8oFi3VJYg4Tbszb2lYGITLOluuuAZGw67JZIuuiXzw/yOUfdWTmRCAVGzTmqkPsusYg56L4iRBWDwYQ3mhHsuNKFO7SIx1nJatj5hK9AkDJlcVilpA5IuWLWOHLY7nplFPUPUwMkRd99nifB7ITycbaAX4zLwp2U2wCb2uSTOzsFNfXykksf8AlreH0615Jb+T39/dDwQurDAQE3h+KUH5QhEvRJ1uphkGvx/x6Vn0LkJuSqS5DLeSATmVOVRK2f6AXcymvn/64qxizjlBR7bBoUxM55311qWJNKKk2FYFTAIW5fMzN0MRbaulpnpBwmhnBvd03rOMIghnvClHv2m8Eh5A6ppPnLcl2Vn7jsrqTmMm+PM1ppIWhCpvC7xn4digx1GGHXlYzfHkDxtnHwHcbj+WOkc+j4ha8Os+1ctdT3OJXz5rwW4viorSIhWryK+G36beguXe5YaoeMcK9Vzmb+S0lHdA7RuCWiJ31i/9ZMbzBhLkdcf/wfj9n3mkqmzvc4Uc1NM8FHQ23URsodSHpTdDi7q25Eqge/JP82AqJ2zAWA+QKVg54xCQQc= diff --git a/appveyor.yml b/appveyor.yml index 4f25f06179..669a60af08 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -40,15 +40,26 @@ artifacts: name: DemoScreenshot deploy: - provider: GitHub - repository: onivim/oni - auth_token: - secure: 7+dYCBtYLMoaH4xvTno1mAw8mb4CPFYAcosPI8kRTmcqYKehzmhpChU825uGdaB6 - draft: false - prerelease: false - force_update: true - on: - appveyor_repo_tag: true + - provider: GitHub + repository: onivim/oni + auth_token: + secure: 7+dYCBtYLMoaH4xvTno1mAw8mb4CPFYAcosPI8kRTmcqYKehzmhpChU825uGdaB6 + draft: false + prerelease: false + force_update: true + on: + appveyor_repo_tag: true + + - provider: S3 + access_key_id: AKIAIYMATI2CEFTHPBOQ + secret_access_key: + secure: brqAO0yA6DSxwRbf7IbbmhvyEoQqSeetdrq4mutR2aaeLJBQu6by4u1Td+wq5Msc + bucket: oni-builds + region: us-west-2 + unzip: false + set_public: true + folder: windows_builds + artifact: SetupExe, ProductZip # Post-install test scripts. test_script: From 3c9c488edabbb9fa3aa6e07e7676d72c560d3f70 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 7 Feb 2018 11:29:55 -0800 Subject: [PATCH 052/103] Update config.yml --- .github/config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/config.yml b/.github/config.yml index 32d94f4cea..b641ac9d06 100644 --- a/.github/config.yml +++ b/.github/config.yml @@ -1,3 +1,5 @@ # Comment to be posted to on first time issues newIssueWelcomeComment: > Hello and welcome to the Oni repository! Thanks for opening your first issue here. To help us out, please make sure to include as much detail as possible - including screenshots and logs, if possible. +backers: +- 13532591 From 2a962972f6f19c61803ef348e80f0af6d84357e6 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 7 Feb 2018 11:36:57 -0800 Subject: [PATCH 053/103] Add current set of backers to backers.yml --- .github/config.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/config.yml b/.github/config.yml index b641ac9d06..5ee8cbe6b3 100644 --- a/.github/config.yml +++ b/.github/config.yml @@ -3,3 +3,13 @@ newIssueWelcomeComment: > Hello and welcome to the Oni repository! Thanks for opening your first issue here. To help us out, please make sure to include as much detail as possible - including screenshots and logs, if possible. backers: - 13532591 +- 5097613 +- 22454918 +- 347552 +- 977348 +- 28748 +- 2835826 +- 515720 +- 124171 +- 230476 +- 10102132 From 372e8e3bac55831b69b16e95f70868117957ae7d Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 7 Feb 2018 11:38:31 -0800 Subject: [PATCH 054/103] Update config.yml with additional backers --- .github/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/config.yml b/.github/config.yml index 5ee8cbe6b3..03bf29e449 100644 --- a/.github/config.yml +++ b/.github/config.yml @@ -13,3 +13,6 @@ backers: - 124171 - 230476 - 10102132 +- 10038688 +- 817509 +- 163128 From 06c5653fa9d90ead318241392c94054c688d3f9d Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 7 Feb 2018 13:34:11 -0800 Subject: [PATCH 055/103] Disable marks by default due to #1461 (#1466) --- browser/src/Services/Configuration/DefaultConfiguration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index 9544c859f2..f15e98d413 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -256,7 +256,7 @@ const BaseConfiguration: IConfigurationValues = { "sidebar.enabled": true, "sidebar.width": "50px", - "sidebar.marks.enabled": true, + "sidebar.marks.enabled": false, "sidebar.plugins.enabled": false, "statusbar.enabled": true, From 529b530ed3630e055898dca1545b18ae0e24c1f7 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 7 Feb 2018 14:07:25 -0800 Subject: [PATCH 056/103] Window Manager: Clicking on windows should focus window (#1468) * Set up window click to focus window * Add 'noop' function as helper utility --- browser/src/UI/components/WindowSplitHost.tsx | 6 +++++- browser/src/UI/components/WindowSplits.tsx | 6 ++++++ browser/src/Utility.ts | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/browser/src/UI/components/WindowSplitHost.tsx b/browser/src/UI/components/WindowSplitHost.tsx index 9f660e5351..ffdcba686b 100644 --- a/browser/src/UI/components/WindowSplitHost.tsx +++ b/browser/src/UI/components/WindowSplitHost.tsx @@ -12,6 +12,7 @@ export interface IWindowSplitHostProps { split: Oni.IWindowSplit containerClassName: string isFocused: boolean + onClick: (evt: React.MouseEvent) => void } /** @@ -22,7 +23,10 @@ export class WindowSplitHost extends React.PureComponent +
(!this.props.isFocused ? this.props.onClick(evt) : null)} + >
{this.props.split.render()}
) diff --git a/browser/src/UI/components/WindowSplits.tsx b/browser/src/UI/components/WindowSplits.tsx index f08258c544..78bac69413 100644 --- a/browser/src/UI/components/WindowSplits.tsx +++ b/browser/src/UI/components/WindowSplits.tsx @@ -12,6 +12,8 @@ import { WindowSplitHost } from "./WindowSplitHost" import { ISplitInfo, WindowManager } from "./../../Services/WindowManager" +import { noop } from "./../../Utility" + export interface IWindowSplitsProps { windowManager: WindowManager } @@ -37,6 +39,7 @@ export class Dock extends React.PureComponent { containerClassName="split" split={s} isFocused={this.props.activeSplit === s} + onClick={noop} />
@@ -109,6 +112,9 @@ export class WindowSplits extends React.PureComponent { + this.props.windowManager.focusSplit(split) + }} /> ) } diff --git a/browser/src/Utility.ts b/browser/src/Utility.ts index 409072c921..1a8d80177b 100644 --- a/browser/src/Utility.ts +++ b/browser/src/Utility.ts @@ -29,6 +29,7 @@ export function nodeRequire(moduleName: string): any { } export const EmptyArray: any[] = [] +export const noop = () => {} // tslint:disable-line export const normalizePath = (fileName: string) => fileName.split("\\").join("/") From 831406793485d32278f2e5aaf396636b67bd261d Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 7 Feb 2018 15:30:25 -0800 Subject: [PATCH 057/103] Fix #1436 - Automation: Use empty config if no configuration is specified (#1455) * Use empty config if no configuration is specified, instead of falling back to users config * Fix config collision * Remove unnecessary logging --- test/common/runInProcTest.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/test/common/runInProcTest.ts b/test/common/runInProcTest.ts index c2aaaa6d73..260f9e5639 100644 --- a/test/common/runInProcTest.ts +++ b/test/common/runInProcTest.ts @@ -32,14 +32,17 @@ const loadTest = (rootPath: string, testName: string): ITestCase => { import * as os from "os" const getConfigPath = (settings: any, rootPath: string) => { - if (!settings) { - return "" - } else if (settings.configPath) { + settings = settings || {} + + if (settings.configPath) { return normalizePath(path.join(rootPath, settings.configPath)) } else if (settings.config) { return normalizePath(serializeConfig(settings.config)) } else { - return "" + // Fix #1436 - if no config is specified, we'll just use + // the empty config, so that the user's config doesn't + // impact the test results. + return normalizePath(serializeConfig({})) } } @@ -74,13 +77,13 @@ const logWithTimeStamp = (message: string) => { export const runInProcTest = (rootPath: string, testName: string, timeout: number = 5000) => { describe(testName, () => { - const testCase = loadTest(rootPath, testName) - + let testCase: ITestCase let oni: Oni beforeEach(async () => { logWithTimeStamp("BEFORE EACH: " + testName) + testCase = loadTest(rootPath, testName) const startOptions = { configurationPath: testCase.configPath, } From ca94a25884cf9baf21e6cccb8754d4cf8024c6c6 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 7 Feb 2018 15:55:15 -0800 Subject: [PATCH 058/103] Fix 'file' section in travis.yml (#1472) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f9d6e835fc..7fe5cf6451 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,7 +52,7 @@ deploy: secret_access_key: secure: S4f/aczEABGAMKk2tmVSkoGx+T2TLPmz5z6x6RKaM+eDmAaVSAELlIj1eAz6Tu2lv3jz+cpyAIISZNC/phORsJWwzbSZHVycLrMG0N3fDTqKFxu1fl6L3b3exRe9SiKXug73ZvHfktzd/XfRcgZKop4qgrwGiM57m0ZuZb/j1LkgjytTuvNAUxXbA84I8LZs/NhY17XuXq+KPlGElIHy3UFoGqQ8pBnTypkIU5rQTsoeAxXLBE8JAFfz+nBGZ7dx6OMbQcKX5jKh/gR3vk+4aTgV8gNE2Zp24ErjSqF2zly/gP9nE2DpfR7jqpZVHnb/v+OEjRDS80tLhPo8Dbibzwt2ZZNADpYBjSGtphwAmq4DCvJ7ORExOB5+O3wmXKQGdItyBTS7sW44n6BTyv87WxWuCaSDQ9QaO9PrbJdN5YGEYeRxSTM7Mn0t72IILkfFCUeSg6fl6tFs9iWIj5zltbxH1GQsRpA8j1Idg4O+894KnQABtw/YKh6rrdeYS9y/100qAjtV6qYyiP2IdPqMWGuasOiz87q3CQ8Ejd7uhiTjAaINVqos+0k04Yf5+rT4MqkeXnYFzjXuXcqDlpq6yJIZv3aD+PMSlZi2WmTYnPJXQFndHo/x9FhEh90UF9WdO5S27ySRSo8XQT4DyL3ToPkqz8y0slNmaNqiqMouQAU= bucket: oni-builds - files: + file: - dist/*.dmg - dist/*.zip upload-dir: osx_builds From 8433b78c4195d9d79c08370932676aa0279cde10 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 7 Feb 2018 18:14:37 -0800 Subject: [PATCH 059/103] Clean up animation so it doesn't execute every sidebar transition (#1471) --- browser/src/Services/Sidebar/SidebarContentSplit.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/browser/src/Services/Sidebar/SidebarContentSplit.tsx b/browser/src/Services/Sidebar/SidebarContentSplit.tsx index ff57ffcfec..837ae0c29a 100644 --- a/browser/src/Services/Sidebar/SidebarContentSplit.tsx +++ b/browser/src/Services/Sidebar/SidebarContentSplit.tsx @@ -117,7 +117,7 @@ export const SidebarHeaderWrapper = withProps(styled.div)` export class SidebarHeaderView extends React.PureComponent { public render(): JSX.Element { return ( - + {this.props.headerName} ) @@ -172,9 +172,11 @@ export class SidebarContentView extends React.PureComponent< const header = activeEntry && activeEntry.pane ? activeEntry.pane.title : null return ( - + - {activeEntry.pane.render()} + + {activeEntry.pane.render()} + ) } From 75b37fcb52ac039a9316bb6dffcf290641fbfa44 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 7 Feb 2018 18:59:54 -0800 Subject: [PATCH 060/103] Refactoring: Migrate window management state to redux store (#1449) * Start sketching out window store * Hook up window split component to store * Remove unused WindowState file * Wire up primary split again * Get windows rendering again * Set splitId * Set up editor to grab focus by default, due to timing issue with the redux store implementation * Get navigation working with parity to functionality today * Fix lint issues * Update markdown preview to use new window API * Bring in latest oni-api * Merge with focus fix --- .../src/Editor/NeovimEditor/NeovimInput.tsx | 2 + .../src/Editor/NeovimEditor/NeovimSurface.tsx | 1 + browser/src/Input/KeyboardInput.tsx | 6 + browser/src/Renderer/CanvasRenderer.ts | 8 + browser/src/Services/Sidebar/index.ts | 5 +- .../WindowManager/LinearSplitProvider.ts | 17 +- .../WindowManager/RelationalSplitNavigator.ts | 10 +- .../WindowManager/SingleSplitProvider.ts | 22 +- .../src/Services/WindowManager/WindowDock.ts | 64 ++--- .../Services/WindowManager/WindowManager.ts | 219 ++++++++++++++---- .../WindowManager/WindowManagerStore.ts | 126 ++++++++++ .../src/Services/WindowManager/WindowState.ts | 38 --- browser/src/Services/WindowManager/index.ts | 19 +- browser/src/UI/Shell/ShellView.tsx | 6 +- browser/src/UI/components/WindowSplits.tsx | 87 +++---- browser/src/startEditors.ts | 2 +- .../WindowManager/LinearSplitProviderTests.ts | 4 + .../RelationalSplitNavigatorTests.ts.ts | 4 + .../oni-plugin-markdown-preview/src/index.tsx | 6 +- package.json | 2 +- yarn.lock | 6 +- 21 files changed, 421 insertions(+), 233 deletions(-) create mode 100644 browser/src/Services/WindowManager/WindowManagerStore.ts delete mode 100644 browser/src/Services/WindowManager/WindowState.ts diff --git a/browser/src/Editor/NeovimEditor/NeovimInput.tsx b/browser/src/Editor/NeovimEditor/NeovimInput.tsx index da4f9987bf..928e78c984 100644 --- a/browser/src/Editor/NeovimEditor/NeovimInput.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimInput.tsx @@ -25,6 +25,7 @@ export interface INeovimInputProps { onImeEnd: () => void onKeyDown?: (key: string) => void + startActive?: boolean typingPrediction: TypingPredictionManager } @@ -46,6 +47,7 @@ export class NeovimInput extends React.PureComponent { return (
(this._mouseElement = elem)} className="stack enable-mouse"> {
+ onKeyDown?: (key: string) => void onImeStart?: () => void onImeEnd?: () => void @@ -89,6 +91,10 @@ export class KeyboardInputView extends React.PureComponent< }) this._disposables.push(d1) } + + if (this.props.startActive && this._keyboardElement) { + focusManager.setFocus(this._keyboardElement) + } } public componentWillUnmount(): void { diff --git a/browser/src/Renderer/CanvasRenderer.ts b/browser/src/Renderer/CanvasRenderer.ts index 0a43cf3f78..98a8df3187 100644 --- a/browser/src/Renderer/CanvasRenderer.ts +++ b/browser/src/Renderer/CanvasRenderer.ts @@ -71,6 +71,10 @@ export class CanvasRenderer implements INeovimRenderer { } public redrawAll(screenInfo: IScreen): void { + if (!this._editorElement) { + return + } + const cellsToUpdate: IPosition[] = [] this._setContext() @@ -96,6 +100,10 @@ export class CanvasRenderer implements INeovimRenderer { } public draw(screenInfo: IScreen): void { + if (!this._editorElement) { + return + } + const cellsToUpdate: IPosition[] = [] for (let x = 0; x < screenInfo.width; x++) { for (let y = 0; y < screenInfo.height; y++) { diff --git a/browser/src/Services/Sidebar/index.ts b/browser/src/Services/Sidebar/index.ts index bf74eca198..38edb48ab0 100644 --- a/browser/src/Services/Sidebar/index.ts +++ b/browser/src/Services/Sidebar/index.ts @@ -17,9 +17,8 @@ export const activate = (configuration: Configuration, workspace: Workspace) => _sidebarManager = new SidebarManager() if (configuration.getValue("sidebar.enabled")) { - const leftDock = windowManager.getDock("left") - leftDock.addSplit(new SidebarSplit(_sidebarManager)) - leftDock.addSplit(new SidebarContentSplit(_sidebarManager)) + windowManager.createSplit("left", new SidebarSplit(_sidebarManager)) + windowManager.createSplit("left", new SidebarContentSplit(_sidebarManager)) _sidebarManager.add("files-o", new ExplorerSplit(workspace, commandManager, editorManager)) } diff --git a/browser/src/Services/WindowManager/LinearSplitProvider.ts b/browser/src/Services/WindowManager/LinearSplitProvider.ts index fc33ec9559..3d85e73d8f 100644 --- a/browser/src/Services/WindowManager/LinearSplitProvider.ts +++ b/browser/src/Services/WindowManager/LinearSplitProvider.ts @@ -5,10 +5,9 @@ * a tree-based hierarchy of horizontal and vertical splits */ -import * as Oni from "oni-api" - import { Direction, + IAugmentedSplitInfo, IWindowSplitProvider, SingleSplitProvider, SplitDirection, @@ -20,11 +19,11 @@ export class LinearSplitProvider implements IWindowSplitProvider { constructor(private _direction: SplitDirection) {} - public contains(split: Oni.IWindowSplit): boolean { + public contains(split: IAugmentedSplitInfo): boolean { return this._getProviderForSplit(split) != null } - public close(split: Oni.IWindowSplit): boolean { + public close(split: IAugmentedSplitInfo): boolean { const containingSplit = this._getProviderForSplit(split) if (!containingSplit) { @@ -43,9 +42,9 @@ export class LinearSplitProvider implements IWindowSplitProvider { } public split( - split: Oni.IWindowSplit, + split: IAugmentedSplitInfo, direction: SplitDirection, - referenceSplit?: Oni.IWindowSplit, + referenceSplit?: IAugmentedSplitInfo, ): boolean { // If there is no reference split, we can just tack this split on if (!referenceSplit) { @@ -78,7 +77,7 @@ export class LinearSplitProvider implements IWindowSplitProvider { return true } - public move(split: Oni.IWindowSplit, direction: Direction): Oni.IWindowSplit { + public move(split: IAugmentedSplitInfo, direction: Direction): IAugmentedSplitInfo { if (!split) { if (this._direction === "horizontal") { const index = direction === "left" ? this._splitProviders.length - 1 : 0 @@ -127,7 +126,7 @@ export class LinearSplitProvider implements IWindowSplitProvider { return this._splitProviders[newIndex].move(null, direction) } - public getState(): SplitOrLeaf { + public getState(): SplitOrLeaf { return { type: "Split", direction: this._direction, @@ -150,7 +149,7 @@ export class LinearSplitProvider implements IWindowSplitProvider { } } - private _getProviderForSplit(split: Oni.IWindowSplit): IWindowSplitProvider { + private _getProviderForSplit(split: IAugmentedSplitInfo): IWindowSplitProvider { const providers = this._splitProviders.filter(prov => prov.contains(split)) return providers.length > 0 ? providers[0] : null diff --git a/browser/src/Services/WindowManager/RelationalSplitNavigator.ts b/browser/src/Services/WindowManager/RelationalSplitNavigator.ts index f0e73cb71b..02ff850f0a 100644 --- a/browser/src/Services/WindowManager/RelationalSplitNavigator.ts +++ b/browser/src/Services/WindowManager/RelationalSplitNavigator.ts @@ -5,9 +5,7 @@ * navigation relationships between other split provdiers */ -import * as Oni from "oni-api" - -import { Direction, getInverseDirection, IWindowSplitNavigator } from "./index" +import { Direction, getInverseDirection, IAugmentedSplitInfo, IWindowSplitNavigator } from "./index" export interface WindowSplitRelationship { from: IWindowSplitNavigator @@ -41,11 +39,11 @@ export class RelationalSplitNavigator implements IWindowSplitNavigator { this._addToProvidersIfNeeded(to) } - public contains(split: Oni.IWindowSplit): boolean { + public contains(split: IAugmentedSplitInfo): boolean { return this._getContainingSplit(split) !== null } - public move(split: Oni.IWindowSplit, direction: Direction): Oni.IWindowSplit { + public move(split: IAugmentedSplitInfo, direction: Direction): IAugmentedSplitInfo { // If there is no current split, that means we are entering if (split === null) { // Need to find the furthest split in the *reverse* direction. @@ -98,7 +96,7 @@ export class RelationalSplitNavigator implements IWindowSplitNavigator { return this._getFurthestSplitInDirection(direction, currentRelationship.to) } - private _getContainingSplit(split: Oni.IWindowSplit): IWindowSplitNavigator { + private _getContainingSplit(split: IAugmentedSplitInfo): IWindowSplitNavigator { const providers = this._providers.filter(s => s.contains(split)) return providers.length === 0 ? null : providers[0] } diff --git a/browser/src/Services/WindowManager/SingleSplitProvider.ts b/browser/src/Services/WindowManager/SingleSplitProvider.ts index bc55466115..58fa19def8 100644 --- a/browser/src/Services/WindowManager/SingleSplitProvider.ts +++ b/browser/src/Services/WindowManager/SingleSplitProvider.ts @@ -4,18 +4,22 @@ * Split provider for a leaf node */ -import * as Oni from "oni-api" - -import { Direction, IWindowSplitProvider, SplitDirection, SplitOrLeaf } from "./index" +import { + Direction, + IAugmentedSplitInfo, + IWindowSplitProvider, + SplitDirection, + SplitOrLeaf, +} from "./index" export class SingleSplitProvider implements IWindowSplitProvider { - constructor(private _split: Oni.IWindowSplit) {} + constructor(private _split: IAugmentedSplitInfo) {} - public contains(split: Oni.IWindowSplit): boolean { + public contains(split: IAugmentedSplitInfo): boolean { return this._split === split } - public move(split: Oni.IWindowSplit, direction: Direction): Oni.IWindowSplit { + public move(split: IAugmentedSplitInfo, direction: Direction): IAugmentedSplitInfo { if (split === null) { return this._split } else { @@ -23,15 +27,15 @@ export class SingleSplitProvider implements IWindowSplitProvider { } } - public split(split: Oni.IWindowSplit, direction: SplitDirection): boolean { + public split(split: IAugmentedSplitInfo, direction: SplitDirection): boolean { return false } - public close(split: Oni.IWindowSplit): boolean { + public close(split: IAugmentedSplitInfo): boolean { return false } - public getState(): SplitOrLeaf { + public getState(): SplitOrLeaf { return { type: "Leaf", contents: this._split, diff --git a/browser/src/Services/WindowManager/WindowDock.ts b/browser/src/Services/WindowManager/WindowDock.ts index 916c969b83..b11e072440 100644 --- a/browser/src/Services/WindowManager/WindowDock.ts +++ b/browser/src/Services/WindowManager/WindowDock.ts @@ -2,49 +2,28 @@ * WindowDock.ts */ -import * as Oni from "oni-api" -import { Event, IEvent } from "oni-types" +import { Direction, IAugmentedSplitInfo, IWindowSplitNavigator } from "./index" -import { Direction, SplitDirection } from "./index" +export type DockStateGetter = () => IAugmentedSplitInfo[] -export interface IWindowDock { - splits: Oni.IWindowSplit[] +export class WindowDockNavigator implements IWindowSplitNavigator { + constructor(private _stateGetter: DockStateGetter) {} - onSplitsChanged: IEvent - - addSplit(split: Oni.IWindowSplit): void - removeSplit(split: Oni.IWindowSplit): void -} - -export class WindowDock implements IWindowDock { - private _splits: Oni.IWindowSplit[] = [] - private _onSplitsChangedEvent: Event = new Event() - - public get splits(): Oni.IWindowSplit[] { - return this._splits + public contains(split: IAugmentedSplitInfo): boolean { + const splits = this._stateGetter() + return splits.indexOf(split) >= 0 } - public get onSplitsChanged(): IEvent { - return this._onSplitsChangedEvent - } - - public contains(split: Oni.IWindowSplit): boolean { - return this._splits.indexOf(split) >= 0 - } + public move(startSplit: IAugmentedSplitInfo, direction: Direction): IAugmentedSplitInfo { + const splits = this._stateGetter() - public split(startSplit: Oni.IWindowSplit, splitDirection: SplitDirection): boolean { - this.addSplit(startSplit) - return true - } - - public move(startSplit: Oni.IWindowSplit, direction: Direction): Oni.IWindowSplit { - const currentIndex = this._splits.indexOf(startSplit) + const currentIndex = splits.indexOf(startSplit) if (currentIndex === -1) { if (direction === "left") { - return this._splits[this._splits.length - 1] + return splits[splits.length - 1] } else if (direction === "right") { - return this._splits[0] + return splits[0] } else { return null } @@ -53,25 +32,10 @@ export class WindowDock implements IWindowDock { // TODO: Generalize this - this is baked for a 'left dock' case right now const newIndex = direction === "left" ? currentIndex - 1 : currentIndex + 1 - if (newIndex >= 0 && newIndex < this._splits.length) { - return this._splits[newIndex] + if (newIndex >= 0 && newIndex < splits.length) { + return splits[newIndex] } else { return null } } - - public addSplit(split: Oni.IWindowSplit): void { - this._splits = [...this._splits, split] - this._onSplitsChangedEvent.dispatch() - } - - public close(split: Oni.IWindowSplit): boolean { - this.removeSplit(split) - return true - } - - public removeSplit(split: Oni.IWindowSplit): void { - this._splits = this._splits.filter(s => s !== split) - this._onSplitsChangedEvent.dispatch() - } } diff --git a/browser/src/Services/WindowManager/WindowManager.ts b/browser/src/Services/WindowManager/WindowManager.ts index 7544552309..95025e66d8 100644 --- a/browser/src/Services/WindowManager/WindowManager.ts +++ b/browser/src/Services/WindowManager/WindowManager.ts @@ -8,33 +8,95 @@ * to the active editor, and managing transitions between editors. */ +import { Store } from "redux" + import * as Oni from "oni-api" import { Event, IEvent } from "oni-types" import { Direction, SplitDirection } from "./index" import { LinearSplitProvider } from "./LinearSplitProvider" import { RelationalSplitNavigator } from "./RelationalSplitNavigator" -import { WindowDock } from "./WindowDock" -import { ISplitInfo } from "./WindowState" +import { WindowDockNavigator } from "./WindowDock" + +import { createStore, IAugmentedSplitInfo, ISplitInfo, WindowState } from "./WindowManagerStore" + +export interface IWindowSplitHandle { + id: string + + close(): void + + // Later: + // show() + // hide() + // focus() + // setSize() +} + +class WindowSplitHandle implements IWindowSplitHandle { + public get id(): string { + return this._id + } + + constructor( + private _store: Store, + private _windowManager: WindowManager, + private _id: string, + ) {} + + public hide(): void { + this._store.dispatch({ + type: "HIDE_SPLIT", + splitId: this._id, + }) + } + + public show(): void { + this._store.dispatch({ + type: "SHOW_SPLIT", + splitId: this._id, + }) + } + + public close(): void { + this._windowManager.close(this._id) + } +} + +export class AugmentedWindow implements IAugmentedSplitInfo { + public get id(): string { + return this._id + } + + constructor(private _id: string, private _innerSplit: Oni.IWindowSplit | any) {} + + public render(): JSX.Element { + return this._innerSplit.render() + } + + public enter(): void { + if (this._innerSplit.enter) { + this._innerSplit.enter() + } + } + + public leave(): void { + if (this._innerSplit.leave) { + this._innerSplit.leave() + } + } +} export class WindowManager { - private _activeSplit: any + private _lastId: number = 0 + private _idToSplit: { [key: string]: IAugmentedSplitInfo } = {} - private _onActiveSplitChangedEvent = new Event() - private _onSplitChanged = new Event>() private _onUnhandledMoveEvent = new Event() - private _leftDock: WindowDock = null + private _leftDock: WindowDockNavigator = null private _primarySplit: LinearSplitProvider private _rootNavigator: RelationalSplitNavigator - public get onActiveSplitChanged(): IEvent { - return this._onActiveSplitChangedEvent - } - - public get onSplitChanged(): IEvent> { - return this._onSplitChanged - } + private _store: Store public get onUnhandledMove(): IEvent { return this._onUnhandledMoveEvent @@ -50,37 +112,100 @@ export class WindowManager { return this._primarySplit.getState() as ISplitInfo } - public get activeSplit(): Oni.IWindowSplit { - return this._activeSplit + public get store(): Store { + return this._store } - public set activeSplit(split: Oni.IWindowSplit) { - this._focusNewSplit(split) + public get activeSplit(): IAugmentedSplitInfo { + const focusedSplit = this._store.getState().focusedSplitId + + if (!focusedSplit) { + return null + } + + return this._idToSplit[focusedSplit] } constructor() { this._rootNavigator = new RelationalSplitNavigator() - this._leftDock = new WindowDock() + this._store = createStore() + this._leftDock = new WindowDockNavigator(() => this._store.getState().docks.left) this._primarySplit = new LinearSplitProvider("horizontal") - this._rootNavigator.setRelationship(this._leftDock, this._primarySplit, "right") } - public split( - direction: SplitDirection, + // public split( + // direction: SplitDirection, + // newSplit: Oni.IWindowSplit, + // referenceSplit?: Oni.IWindowSplit, + // ) { + + // this._primarySplit.split(augmentedWindow, direction, referenceSplit) + // const newState = this._primarySplit.getState() as ISplitInfo + + // this._store.dispatch({ + // type: "SET_PRIMARY_SPLITS", + // splits: newState, + // }) + + // this._focusNewSplit(newSplit) + // } + + public createSplit( + splitLocation: Direction | SplitDirection, newSplit: Oni.IWindowSplit, - referenceSplit?: Oni.IWindowSplit, - ) { - this._primarySplit.split(newSplit, direction, referenceSplit) - const newState = this._primarySplit.getState() as ISplitInfo + referenceSplit?: any, + ): IWindowSplitHandle { + const nextId = this._lastId++ + const windowId = "oni.window." + nextId.toString() + + const augmentedWindow = new AugmentedWindow(windowId, newSplit) + + this._idToSplit[windowId] = augmentedWindow + + switch (splitLocation) { + case "right": + case "up": + case "down": + case "left": { + this._store.dispatch({ + type: "ADD_DOCK_SPLIT", + dock: splitLocation, + split: augmentedWindow, + }) + break + } + case "horizontal": + case "vertical": + this._primarySplit.split(augmentedWindow, splitLocation, referenceSplit) + const newState = this._primarySplit.getState() as ISplitInfo + + this._store.dispatch({ + type: "SET_PRIMARY_SPLITS", + splits: newState, + }) + + this._focusNewSplit(augmentedWindow) + } - this._onSplitChanged.dispatch(newState) - this._focusNewSplit(newSplit) + return new WindowSplitHandle(this._store, this, windowId) } public move(direction: Direction): void { - const newSplit = this._rootNavigator.move(this._activeSplit, direction) + const focusedSplit = this._store.getState().focusedSplitId + + if (!focusedSplit) { + return + } + + const activeSplit = this._idToSplit[focusedSplit] + + if (!activeSplit) { + return + } + + const newSplit = this._rootNavigator.move(activeSplit, direction) if (newSplit) { this._focusNewSplit(newSplit) @@ -105,40 +230,36 @@ export class WindowManager { this.move("down") } - public getDock(direction: Direction): WindowDock { - if (direction === "left") { - return this._leftDock - } else { - // TODO - return null - } - } + public close(splitId: any) { + const split = this._idToSplit[splitId] + this._primarySplit.close(split) - // TODO: Deprecate - public showDock(direction: SplitDirection, split: Oni.IWindowSplit) { - // TODO - } + const state = this._primarySplit.getState() + this._store.dispatch({ + type: "SET_PRIMARY_SPLITS", + splits: state, + }) - public close(split: Oni.IWindowSplit) { - this._primarySplit.close(split) - this._onSplitChanged.dispatch(this.splitRoot) + this._idToSplit[splitId] = null } - public focusSplit(split: Oni.IWindowSplit): void { + public focusSplit(splitId: string): void { + const split = this._idToSplit[splitId] this._focusNewSplit(split) } private _focusNewSplit(newSplit: any): void { - if (this._activeSplit && this._activeSplit.leave) { - this._activeSplit.leave() + if (this.activeSplit && this.activeSplit.leave) { + this.activeSplit.leave() } - this._activeSplit = newSplit + this._store.dispatch({ + type: "SET_FOCUSED_SPLIT", + splitId: newSplit.id, + }) if (newSplit && newSplit.enter) { newSplit.enter() } - - this._onActiveSplitChangedEvent.dispatch(this._activeSplit) } } diff --git a/browser/src/Services/WindowManager/WindowManagerStore.ts b/browser/src/Services/WindowManager/WindowManagerStore.ts new file mode 100644 index 0000000000..4bb17a7759 --- /dev/null +++ b/browser/src/Services/WindowManager/WindowManagerStore.ts @@ -0,0 +1,126 @@ +/** + * WindowManagerStore.ts + * + * Redux store for managing window state + */ + +import * as Oni from "oni-api" + +import { Reducer, Store } from "redux" +import { createStore as createReduxStore } from "./../../Redux" + +import { Direction, ISplitInfo, SplitDirection } from "./index" + +export interface IAugmentedSplitInfo extends Oni.IWindowSplit { + // Internal bookkeeping + id: string + + // Potential API methods + enter?(): void + leave?(): void +} + +export type SplitOrLeaf = ISplitInfo | ISplitLeaf + +export interface ISplitInfo { + type: "Split" + splits: Array> + direction: SplitDirection +} + +export interface ISplitLeaf { + type: "Leaf" + contents: T +} + +type WindowActions = + | { + type: "ADD_DOCK_SPLIT" + dock: Direction + split: IAugmentedSplitInfo + } + | { + type: "SET_PRIMARY_SPLITS" + splits: ISplitInfo + } + | { + type: "SET_FOCUSED_SPLIT" + splitId: string + } + | { + type: "SHOW_SPLIT" + splitId: string + } + | { + type: "HIDE_SPLIT" + splitId: string + } + +export interface DockWindows { + [key: string]: IAugmentedSplitInfo[] +} + +export const DefaultDocksState: DockWindows = { + left: [], + right: [], + up: [], + down: [], +} + +export interface WindowState { + docks: DockWindows + + primarySplit: ISplitInfo + + focusedSplitId: string + hiddenSplits: string[] +} + +export const DefaultWindowState: WindowState = { + docks: DefaultDocksState, + primarySplit: null, + focusedSplitId: null, + hiddenSplits: [], +} + +export const reducer: Reducer = ( + state: WindowState = DefaultWindowState, + action: WindowActions, +) => { + switch (action.type) { + case "SET_PRIMARY_SPLITS": + return { + ...state, + primarySplit: action.splits, + } + case "SET_FOCUSED_SPLIT": + return { + ...state, + focusedSplitId: action.splitId, + } + default: + return { + ...state, + docks: docksReducer(state.docks, action), + } + } +} + +export const docksReducer: Reducer = ( + state: DockWindows = DefaultDocksState, + action: WindowActions, +) => { + switch (action.type) { + case "ADD_DOCK_SPLIT": + return { + ...state, + [action.dock]: [...state[action.dock], action.split], + } + default: + return state + } +} + +export const createStore = (): Store => { + return createReduxStore("WindowManager", reducer, DefaultWindowState, []) +} diff --git a/browser/src/Services/WindowManager/WindowState.ts b/browser/src/Services/WindowManager/WindowState.ts deleted file mode 100644 index 056e926360..0000000000 --- a/browser/src/Services/WindowManager/WindowState.ts +++ /dev/null @@ -1,38 +0,0 @@ -/** - * WindowSplit.ts - * - * Handles managing split state transitions, like: - * - Applying a split - * - Closing a split - */ - -import { Direction, SplitDirection } from "./index" - -export type SplitOrLeaf = ISplitInfo | ISplitLeaf - -export interface ISplitInfo { - type: "Split" - splits: Array> - direction: SplitDirection -} - -export interface ISplitLeaf { - type: "Leaf" - contents: T -} - -export const getFurthestSplitInDirection = ( - root: SplitOrLeaf, - direction: Direction, -): ISplitLeaf => { - if (!root) { - return null - } - - switch (root.type) { - case "Leaf": - return root - case "Split": - return getFurthestSplitInDirection(root.splits[0], direction) - } -} diff --git a/browser/src/Services/WindowManager/index.ts b/browser/src/Services/WindowManager/index.ts index a521690569..8688465751 100644 --- a/browser/src/Services/WindowManager/index.ts +++ b/browser/src/Services/WindowManager/index.ts @@ -8,14 +8,12 @@ * to the active editor, and managing transitions between editors. */ -import * as Oni from "oni-api" - export * from "./LinearSplitProvider" export * from "./RelationalSplitNavigator" export * from "./SingleSplitProvider" export * from "./WindowDock" export * from "./WindowManager" -export * from "./WindowState" +export * from "./WindowManagerStore" // TODO: Possible API types? export type Direction = "up" | "down" | "left" | "right" @@ -36,16 +34,15 @@ export const getInverseDirection = (direction: Direction): Direction => { } } -import { SplitOrLeaf } from "./WindowState" - import { WindowManager } from "./WindowManager" +import { IAugmentedSplitInfo, SplitOrLeaf } from "./WindowManagerStore" /** * Interface for something that can navigate between window splits */ export interface IWindowSplitNavigator { - contains(split: Oni.IWindowSplit): boolean - move(startSplit: Oni.IWindowSplit, direction: Direction): Oni.IWindowSplit + contains(split: IAugmentedSplitInfo): boolean + move(startSplit: IAugmentedSplitInfo, direction: Direction): IAugmentedSplitInfo } /** @@ -57,12 +54,12 @@ export interface IWindowSplitNavigator { */ export interface IWindowSplitProvider extends IWindowSplitNavigator { split( - newSplit: Oni.IWindowSplit, + newSplit: IAugmentedSplitInfo, direction: SplitDirection, - referenceSplit?: Oni.IWindowSplit, + referenceSplit?: IAugmentedSplitInfo, ): boolean - close(split: Oni.IWindowSplit): boolean - getState(): SplitOrLeaf + close(split: IAugmentedSplitInfo): boolean + getState(): SplitOrLeaf } export const windowManager = new WindowManager() diff --git a/browser/src/UI/Shell/ShellView.tsx b/browser/src/UI/Shell/ShellView.tsx index c0d7b97fb6..0a9575c8ae 100644 --- a/browser/src/UI/Shell/ShellView.tsx +++ b/browser/src/UI/Shell/ShellView.tsx @@ -4,6 +4,8 @@ import * as React from "react" +import { Provider } from "react-redux" + import * as Platform from "./../../Platform" import { getKeyEventToVimKey } from "./../../Input/Keyboard" @@ -47,7 +49,9 @@ export class ShellView extends React.PureComponent
- + + +
diff --git a/browser/src/UI/components/WindowSplits.tsx b/browser/src/UI/components/WindowSplits.tsx index 78bac69413..a6e4a746b7 100644 --- a/browser/src/UI/components/WindowSplits.tsx +++ b/browser/src/UI/components/WindowSplits.tsx @@ -6,27 +6,32 @@ import * as React from "react" -import * as Oni from "oni-api" +import { connect } from "react-redux" import { WindowSplitHost } from "./WindowSplitHost" -import { ISplitInfo, WindowManager } from "./../../Services/WindowManager" +import { + IAugmentedSplitInfo, + ISplitInfo, + WindowManager, + WindowState, +} from "./../../Services/WindowManager" import { noop } from "./../../Utility" -export interface IWindowSplitsProps { - windowManager: WindowManager +export interface IWindowSplitsProps extends IWindowSplitsContainerProps { + activeSplitId: string + splitRoot: ISplitInfo + leftDock: IAugmentedSplitInfo[] } -export interface IWindowSplitsState { - activeSplit: Oni.IWindowSplit - splitRoot: ISplitInfo - leftDock: Oni.IWindowSplit[] +export interface IWindowSplitsContainerProps { + windowManager: WindowManager } export interface IDockProps { - activeSplit: Oni.IWindowSplit - splits: Oni.IWindowSplit[] + activeSplitId: string + splits: IAugmentedSplitInfo[] } export class Dock extends React.PureComponent { @@ -38,7 +43,7 @@ export class Dock extends React.PureComponent { key={i} containerClassName="split" split={s} - isFocused={this.props.activeSplit === s} + isFocused={this.props.activeSplitId === s.id} onClick={noop} />
@@ -50,39 +55,9 @@ export class Dock extends React.PureComponent { } } -export class WindowSplits extends React.PureComponent { - constructor(props: IWindowSplitsProps) { - super(props) - - this.state = { - activeSplit: props.windowManager.activeSplit, - splitRoot: props.windowManager.splitRoot, - leftDock: [...props.windowManager.getDock("left").splits], - } - } - - public componentDidMount(): void { - this.props.windowManager.onSplitChanged.subscribe(newSplit => { - this.setState({ - splitRoot: newSplit, - }) - }) - - this.props.windowManager.getDock("left").onSplitsChanged.subscribe(() => { - this.setState({ - leftDock: [...this.props.windowManager.getDock("left").splits], - }) - }) - - this.props.windowManager.onActiveSplitChanged.subscribe(newSplit => { - this.setState({ - activeSplit: newSplit, - }) - }) - } - +export class WindowSplitsView extends React.PureComponent { public render() { - if (!this.state.splitRoot) { + if (!this.props.splitRoot) { return null } @@ -93,11 +68,11 @@ export class WindowSplits extends React.PureComponent { + const editors = this.props.splitRoot.splits.map((splitNode, i) => { if (splitNode.type === "Split") { return null } else { - const split: Oni.IWindowSplit = splitNode.contents + const split: IAugmentedSplitInfo = splitNode.contents if (!split) { return ( @@ -111,9 +86,9 @@ export class WindowSplits extends React.PureComponent { - this.props.windowManager.focusSplit(split) + this.props.windowManager.focusSplit(split.id) }} /> ) @@ -121,15 +96,27 @@ export class WindowSplits extends React.PureComponent 0 ?
: null - return (
- + {editors}
) } } + +const mapStateToProps = ( + state: WindowState, + containerProps: IWindowSplitsContainerProps, +): IWindowSplitsProps => { + return { + ...containerProps, + activeSplitId: state.focusedSplitId, + leftDock: state.docks.left, + splitRoot: state.primarySplit, + } +} + +export const WindowSplits = connect(mapStateToProps)(WindowSplitsView) diff --git a/browser/src/startEditors.ts b/browser/src/startEditors.ts index f1a983c182..23f625bc8c 100644 --- a/browser/src/startEditors.ts +++ b/browser/src/startEditors.ts @@ -49,7 +49,7 @@ export const startEditors = async ( workspace, ) editorManager.setActiveEditor(editor) - windowManager.split("horizontal", editor) + windowManager.createSplit("horizontal", editor) await editor.init(args) } diff --git a/browser/test/Services/WindowManager/LinearSplitProviderTests.ts b/browser/test/Services/WindowManager/LinearSplitProviderTests.ts index c45f795ea3..2e00e54969 100644 --- a/browser/test/Services/WindowManager/LinearSplitProviderTests.ts +++ b/browser/test/Services/WindowManager/LinearSplitProviderTests.ts @@ -7,6 +7,10 @@ import * as assert from "assert" import { LinearSplitProvider } from "./../../../src/Services/WindowManager" export class MockWindowSplit { + public get id(): string { + return "mock.window" + } + public render(): JSX.Element { return null } diff --git a/browser/test/Services/WindowManager/RelationalSplitNavigatorTests.ts.ts b/browser/test/Services/WindowManager/RelationalSplitNavigatorTests.ts.ts index 43f1f3065c..5d8f05334c 100644 --- a/browser/test/Services/WindowManager/RelationalSplitNavigatorTests.ts.ts +++ b/browser/test/Services/WindowManager/RelationalSplitNavigatorTests.ts.ts @@ -10,6 +10,10 @@ import { } from "./../../../src/Services/WindowManager" export class MockWindowSplit { + public get id(): string { + return "mock.window" + } + public render(): JSX.Element { return null } diff --git a/extensions/oni-plugin-markdown-preview/src/index.tsx b/extensions/oni-plugin-markdown-preview/src/index.tsx index 8ce7e3538f..cd715c41e9 100644 --- a/extensions/oni-plugin-markdown-preview/src/index.tsx +++ b/extensions/oni-plugin-markdown-preview/src/index.tsx @@ -168,6 +168,7 @@ class MarkdownPreview extends React.PureComponent this.onBufferEnter(args)) @@ -184,14 +185,15 @@ class MarkdownPreviewEditor implements Oni.IWindowSplit { public open(): void { if (!this._open) { this._open = true - this._oni.windows.split(1, this) + // TODO: Update API + this._split = this._oni.windows.createSplit("vertical", this) } } public close(): void { if (this._open) { this._open = false - this._oni.windows.close(this) + this._split.close() } } diff --git a/package.json b/package.json index 140208e9ea..cbf6380ac6 100644 --- a/package.json +++ b/package.json @@ -206,7 +206,7 @@ "minimist": "1.2.0", "msgpack-lite": "0.1.26", "ocaml-language-server": "^1.0.21", - "oni-api": "^0.0.26", + "oni-api": "^0.0.30", "oni-neovim-binaries": "0.1.0", "oni-ripgrep": "0.0.3", "oni-types": "0.0.4", diff --git a/yarn.lock b/yarn.lock index b5c1ebbfdf..4a5e2d5c07 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4502,9 +4502,9 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" -oni-api@^0.0.26: - version "0.0.26" - resolved "https://registry.yarnpkg.com/oni-api/-/oni-api-0.0.26.tgz#07a23e6d12a61eed9bfecab0d0514ad9d785a210" +oni-api@^0.0.30: + version "0.0.30" + resolved "https://registry.yarnpkg.com/oni-api/-/oni-api-0.0.30.tgz#8bf54d15131f8f1cb5a72552d0383248a4622508" oni-neovim-binaries@0.1.0: version "0.1.0" From cc07a7be9b5500f40c0225701d4ab9b10351e441 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 7 Feb 2018 19:26:57 -0800 Subject: [PATCH 061/103] Add overflow handling to explorer items (#1473) --- browser/src/Services/Explorer/Explorer.less | 3 +++ 1 file changed, 3 insertions(+) diff --git a/browser/src/Services/Explorer/Explorer.less b/browser/src/Services/Explorer/Explorer.less index bc4531a5c3..d32f82e888 100644 --- a/browser/src/Services/Explorer/Explorer.less +++ b/browser/src/Services/Explorer/Explorer.less @@ -37,6 +37,9 @@ .name { flex: 1 1 auto; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } } } From 767ea3f1a450a7e38e223b3d77b3b4c3b66dba7c Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Thu, 8 Feb 2018 10:37:49 -0800 Subject: [PATCH 062/103] Add script to copy packed files to s3_dist folder (#1476) --- .gitignore | 1 + .travis.yml | 5 +--- build/script/CopyPackedFilesForS3Upload.js | 35 ++++++++++++++++++++++ build/script/travis-build.sh | 2 ++ package.json | 1 + 5 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 build/script/CopyPackedFilesForS3Upload.js diff --git a/.gitignore b/.gitignore index 9ea330c92d..9f2d426ae3 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ $LOCALAPPDATA lib lib_test dist +s3_dist ### https://raw.github.com/github/gitignore/2b3b1f428fb84dc4ba3ad2307ec44af3c5799848/Node.gitignore diff --git a/.travis.yml b/.travis.yml index 7fe5cf6451..5d271f35c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,15 +52,12 @@ deploy: secret_access_key: secure: S4f/aczEABGAMKk2tmVSkoGx+T2TLPmz5z6x6RKaM+eDmAaVSAELlIj1eAz6Tu2lv3jz+cpyAIISZNC/phORsJWwzbSZHVycLrMG0N3fDTqKFxu1fl6L3b3exRe9SiKXug73ZvHfktzd/XfRcgZKop4qgrwGiM57m0ZuZb/j1LkgjytTuvNAUxXbA84I8LZs/NhY17XuXq+KPlGElIHy3UFoGqQ8pBnTypkIU5rQTsoeAxXLBE8JAFfz+nBGZ7dx6OMbQcKX5jKh/gR3vk+4aTgV8gNE2Zp24ErjSqF2zly/gP9nE2DpfR7jqpZVHnb/v+OEjRDS80tLhPo8Dbibzwt2ZZNADpYBjSGtphwAmq4DCvJ7ORExOB5+O3wmXKQGdItyBTS7sW44n6BTyv87WxWuCaSDQ9QaO9PrbJdN5YGEYeRxSTM7Mn0t72IILkfFCUeSg6fl6tFs9iWIj5zltbxH1GQsRpA8j1Idg4O+894KnQABtw/YKh6rrdeYS9y/100qAjtV6qYyiP2IdPqMWGuasOiz87q3CQ8Ejd7uhiTjAaINVqos+0k04Yf5+rT4MqkeXnYFzjXuXcqDlpq6yJIZv3aD+PMSlZi2WmTYnPJXQFndHo/x9FhEh90UF9WdO5S27ySRSo8XQT4DyL3ToPkqz8y0slNmaNqiqMouQAU= bucket: oni-builds - file: - - dist/*.dmg - - dist/*.zip + local-dir: s3_dist upload-dir: osx_builds acl: public_read region: us-west-2 skip_cleanup: true on: - condition: $TRAVIS_OS_NAME = osx repo: onivim/oni - provider: releases api_key: diff --git a/build/script/CopyPackedFilesForS3Upload.js b/build/script/CopyPackedFilesForS3Upload.js new file mode 100644 index 0000000000..8a08801d0f --- /dev/null +++ b/build/script/CopyPackedFilesForS3Upload.js @@ -0,0 +1,35 @@ +/** + * Helper script to copy the packaged files to an 's3' folder + * for upload to s3 + */ + +const path = require("path") +const fs = require("fs") +const mkdirp = require("mkdirp") + +const rootPath = path.join(__dirname, "..", "..") +const distPath = path.join(rootPath, "dist") +const s3_distPath = path.join(rootPath, "s3_dist") + +console.log(`Creating 's3_dist' folder at: ${s3_distPath}`) +mkdirp.sync(s3_distPath) + +// Get all files in 'dist'.. +const filesAndFolder = fs.readdirSync(distPath) + +// And copy the files to `s3_dist` +filesAndFolder.forEach(f => { + console.log("- Checking: " + f) + + const fullPath = path.join(distPath, f) + const stat = fs.statSync(fullPath) + + if (stat.isFile()) { + const destPath = path.join(s3_distPath, f) + console.log(`-- Copying ${fullPath} to ${destPath}`) + fs.copyFileSync(fullPath, destPath) + console.log(`-- Copy successful`) + } +}) + +console.log("CopyPackedFilesForS3Upload::Complete") diff --git a/build/script/travis-build.sh b/build/script/travis-build.sh index 947a3f754c..1155afb9b1 100755 --- a/build/script/travis-build.sh +++ b/build/script/travis-build.sh @@ -38,3 +38,5 @@ if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then # npm run ccov:test:browser # npm run ccov:report fi + +npm run copy-dist-to-s3 diff --git a/package.json b/package.json index cbf6380ac6..4f7073b96e 100644 --- a/package.json +++ b/package.json @@ -131,6 +131,7 @@ "build:test:integration": "cd test && tsc -p tsconfig.json", "build:test:unit": "cd browser && tsc -p tsconfig.test.json", "copy-icons": "node build/CopyIcons.js", + "copy-dist-to-s3": "node build/script/CopyPackedFilesForS3Upload.js", "debug:test:unit:browser": "cd browser && tsc -p tsconfig.test.json && electron-mocha --interactive --debug --renderer --require testHelpers.js --recursive ../lib_test/browser/test", "demo": "npm run build:test && mocha -t 30000 lib_test/test/Demo.js", From 09a3b70e5a3dc57a053f68e9c106dba203218048 Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 8 Feb 2018 11:15:45 -0800 Subject: [PATCH 063/103] [ISSUE-1439]: Display a list of all failed tests at the bottom of the CITest output (#1474) --- test/CiTests.ts | 24 ++++++++++++++++++++++-- test/common/runInProcTest.ts | 24 +++++++++++++++++++++++- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/test/CiTests.ts b/test/CiTests.ts index 659a6255c0..2989458959 100644 --- a/test/CiTests.ts +++ b/test/CiTests.ts @@ -5,7 +5,7 @@ import * as path from "path" import * as mkdirp from "mkdirp" -import { Oni, runInProcTest } from "./common" +import { IFailedTest, Oni, runInProcTest } from "./common" const LongTimeout = 5000 @@ -49,13 +49,33 @@ export interface ITestCase { configPath: string } +const FGRED = "\x1b[31m" +const FGWHITE = "\x1b[37m" +const FGGREEN = "\x1b[32m" +const FGYELLOW = "\x1b[33m" + // tslint:disable-next-line only-arrow-functions describe("ci tests", function() { const tests = Platform.isWindows() ? [...CiTests, ...WindowsOnlyTests] : Platform.isMac() ? [...CiTests, ...OSXOnlyTests] : CiTests + const testFailures: IFailedTest[] = [] CiTests.forEach(test => { - runInProcTest(path.join(__dirname, "ci"), test) + runInProcTest(path.join(__dirname, "ci"), test, 5000, testFailures) + }) + + // After all of the tests are completed display failures + after(() => { + if (testFailures.length > 0) { + console.log("\n", FGRED, "---- FAILED TESTS ----\n") + testFailures.forEach(failure => { + console.log(FGYELLOW, " [FAILED]:", FGWHITE, failure.test) + console.log(FGWHITE, " Expected:", FGGREEN, failure.expected) + console.log(FGWHITE, " Actual:", FGRED, failure.actual) + console.log(FGWHITE, " Path:", failure.path, "\n") + }) + console.log("") + } }) }) diff --git a/test/common/runInProcTest.ts b/test/common/runInProcTest.ts index 260f9e5639..cf0e89e2ea 100644 --- a/test/common/runInProcTest.ts +++ b/test/common/runInProcTest.ts @@ -12,6 +12,13 @@ export interface ITestCase { configPath: string } +export interface IFailedTest { + test: string + path: string + expected: any + actual: any +} + const normalizePath = p => p.split("\\").join("/") const loadTest = (rootPath: string, testName: string): ITestCase => { @@ -75,7 +82,12 @@ const logWithTimeStamp = (message: string) => { console.log(`[${deltaInSeconds}] ${message}`) } -export const runInProcTest = (rootPath: string, testName: string, timeout: number = 5000) => { +export const runInProcTest = ( + rootPath: string, + testName: string, + timeout: number = 5000, + failures: IFailedTest[] = null, +) => { describe(testName, () => { let testCase: ITestCase let oni: Oni @@ -139,6 +151,16 @@ export const runInProcTest = (rootPath: string, testName: string, timeout: numbe console.log("") const result = JSON.parse(resultText) + if (failures && !result.passed) { + const failedTest: IFailedTest = { + test: testName, + path: testCase.testPath, + expected: result.exception.expected, + actual: result.exception.actual, + } + failures.push(failedTest) + } + assert.ok(result.passed) }) }) From e92115daab1cdf299554b76f1300806d33f24f1c Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Thu, 8 Feb 2018 11:39:48 -0800 Subject: [PATCH 064/103] Sidebar: Add toggle functionality (#1477) * Add hook for showing / hiding sidebar * Add toggle functionality to sidebar * This adds a command / key binding to toggle sidebar visibility * Fix lint issues --- browser/src/Input/KeyBindings.ts | 2 + .../Services/Sidebar/SidebarContentSplit.tsx | 2 +- browser/src/Services/Sidebar/SidebarSplit.tsx | 2 +- browser/src/Services/Sidebar/SidebarStore.ts | 28 +++++++++++- browser/src/Services/Sidebar/index.ts | 15 ++++--- .../Services/WindowManager/WindowManager.ts | 45 ++++++++++++------- .../WindowManager/WindowManagerStore.ts | 17 +++++++ browser/src/UI/components/WindowSplits.tsx | 3 +- 8 files changed, 86 insertions(+), 28 deletions(-) diff --git a/browser/src/Input/KeyBindings.ts b/browser/src/Input/KeyBindings.ts index a3b157ad1d..8b5bae3774 100644 --- a/browser/src/Input/KeyBindings.ts +++ b/browser/src/Input/KeyBindings.ts @@ -108,4 +108,6 @@ export const applyDefaultKeyBindings = (oni: Oni.Plugin.Api, config: Configurati // TODO: Scope 's' to just the local window input.bind("", "sneak.show", () => isNormalMode() && !menu.isMenuOpen()) input.bind(["", ""], "sneak.hide") + + input.bind("", "sidebar.toggle", isNormalMode) } diff --git a/browser/src/Services/Sidebar/SidebarContentSplit.tsx b/browser/src/Services/Sidebar/SidebarContentSplit.tsx index 837ae0c29a..40e2d57003 100644 --- a/browser/src/Services/Sidebar/SidebarContentSplit.tsx +++ b/browser/src/Services/Sidebar/SidebarContentSplit.tsx @@ -33,7 +33,7 @@ export class SidebarContentSplit { return entry && entry.pane ? entry.pane : null } - constructor(private _sidebarManager: SidebarManager = new SidebarManager()) {} + constructor(private _sidebarManager: SidebarManager) {} public enter(): void { const pane: any = this.activePane diff --git a/browser/src/Services/Sidebar/SidebarSplit.tsx b/browser/src/Services/Sidebar/SidebarSplit.tsx index 890d2c2639..b4b94fdc61 100644 --- a/browser/src/Services/Sidebar/SidebarSplit.tsx +++ b/browser/src/Services/Sidebar/SidebarSplit.tsx @@ -12,7 +12,7 @@ import { SidebarManager } from "./SidebarStore" import { Sidebar } from "./SidebarView" export class SidebarSplit { - constructor(private _sidebarManager: SidebarManager = new SidebarManager()) {} + constructor(private _sidebarManager: SidebarManager) {} public enter(): void { this._sidebarManager.setActiveEntry(this._sidebarManager.activeEntryId) diff --git a/browser/src/Services/Sidebar/SidebarStore.ts b/browser/src/Services/Sidebar/SidebarStore.ts index e764349c32..b0fc710343 100644 --- a/browser/src/Services/Sidebar/SidebarStore.ts +++ b/browser/src/Services/Sidebar/SidebarStore.ts @@ -7,6 +7,10 @@ import { Reducer, Store } from "redux" import { createStore as createReduxStore } from "./../../Redux" +import { WindowManager, WindowSplitHandle } from "./../WindowManager" +import { SidebarContentSplit } from "./SidebarContentSplit" +import { SidebarSplit } from "./SidebarSplit" + import * as Oni from "oni-api" export interface ISidebarState { @@ -38,6 +42,9 @@ export interface SidebarPane extends Oni.IWindowSplit { export class SidebarManager { private _store: Store + private _iconSplit: WindowSplitHandle + private _contentSplit: WindowSplitHandle + public get activeEntryId(): string { return this._store.getState().activeEntryId } @@ -50,8 +57,11 @@ export class SidebarManager { return this._store } - constructor() { + constructor(private _windowManager: WindowManager) { this._store = createStore() + + this._iconSplit = this._windowManager.createSplit("left", new SidebarSplit(this)) + this._contentSplit = this._windowManager.createSplit("left", new SidebarContentSplit(this)) } public setActiveEntry(id: string): void { @@ -60,6 +70,22 @@ export class SidebarManager { type: "SET_ACTIVE_ID", activeEntryId: id, }) + + if (!this._contentSplit.isVisible) { + this._contentSplit.show() + } + } + } + + public toggleSidebarVisibility(): void { + if (this._contentSplit.isVisible) { + this._contentSplit.hide() + + if (this._contentSplit.isFocused) { + this._iconSplit.focus() + } + } else { + this._contentSplit.show() } } diff --git a/browser/src/Services/Sidebar/index.ts b/browser/src/Services/Sidebar/index.ts index 38edb48ab0..e561ab9256 100644 --- a/browser/src/Services/Sidebar/index.ts +++ b/browser/src/Services/Sidebar/index.ts @@ -5,8 +5,6 @@ import { windowManager } from "./../../Services/WindowManager" import { Workspace } from "./../../Services/Workspace" import { ExplorerSplit } from "./../Explorer/ExplorerSplit" -import { SidebarContentSplit } from "./SidebarContentSplit" -import { SidebarSplit } from "./SidebarSplit" import { SidebarManager } from "./SidebarStore" let _sidebarManager: SidebarManager = null @@ -14,13 +12,16 @@ let _sidebarManager: SidebarManager = null export * from "./SidebarStore" export const activate = (configuration: Configuration, workspace: Workspace) => { - _sidebarManager = new SidebarManager() - if (configuration.getValue("sidebar.enabled")) { - windowManager.createSplit("left", new SidebarSplit(_sidebarManager)) - windowManager.createSplit("left", new SidebarContentSplit(_sidebarManager)) - + _sidebarManager = new SidebarManager(windowManager) _sidebarManager.add("files-o", new ExplorerSplit(workspace, commandManager, editorManager)) + + commandManager.registerCommand({ + command: "sidebar.toggle", + name: "Sidebar: Toggle", + detail: "Show / hide the contents of the sidebar pane.", + execute: () => _sidebarManager.toggleSidebarVisibility(), + }) } } diff --git a/browser/src/Services/WindowManager/WindowManager.ts b/browser/src/Services/WindowManager/WindowManager.ts index 95025e66d8..fbfdd1e289 100644 --- a/browser/src/Services/WindowManager/WindowManager.ts +++ b/browser/src/Services/WindowManager/WindowManager.ts @@ -18,25 +18,27 @@ import { LinearSplitProvider } from "./LinearSplitProvider" import { RelationalSplitNavigator } from "./RelationalSplitNavigator" import { WindowDockNavigator } from "./WindowDock" -import { createStore, IAugmentedSplitInfo, ISplitInfo, WindowState } from "./WindowManagerStore" - -export interface IWindowSplitHandle { - id: string - - close(): void - - // Later: - // show() - // hide() - // focus() - // setSize() -} - -class WindowSplitHandle implements IWindowSplitHandle { +import { + createStore, + IAugmentedSplitInfo, + ISplitInfo, + leftDockSelector, + WindowState, +} from "./WindowManagerStore" + +export class WindowSplitHandle implements Oni.WindowSplitHandle { public get id(): string { return this._id } + public get isVisible(): boolean { + return this._store.getState().hiddenSplits.indexOf(this._id) === -1 + } + + public get isFocused(): boolean { + return this._store.getState().focusedSplitId === this._id + } + constructor( private _store: Store, private _windowManager: WindowManager, @@ -57,6 +59,15 @@ class WindowSplitHandle implements IWindowSplitHandle { }) } + public focus(): void { + // TODO: + this._windowManager.focusSplit(this._id) + } + + public setSize(size: number): void { + // TODO + } + public close(): void { this._windowManager.close(this._id) } @@ -130,7 +141,7 @@ export class WindowManager { this._rootNavigator = new RelationalSplitNavigator() this._store = createStore() - this._leftDock = new WindowDockNavigator(() => this._store.getState().docks.left) + this._leftDock = new WindowDockNavigator(() => leftDockSelector(this._store.getState())) this._primarySplit = new LinearSplitProvider("horizontal") this._rootNavigator.setRelationship(this._leftDock, this._primarySplit, "right") } @@ -156,7 +167,7 @@ export class WindowManager { splitLocation: Direction | SplitDirection, newSplit: Oni.IWindowSplit, referenceSplit?: any, - ): IWindowSplitHandle { + ): WindowSplitHandle { const nextId = this._lastId++ const windowId = "oni.window." + nextId.toString() diff --git a/browser/src/Services/WindowManager/WindowManagerStore.ts b/browser/src/Services/WindowManager/WindowManagerStore.ts index 4bb17a7759..962c93661f 100644 --- a/browser/src/Services/WindowManager/WindowManagerStore.ts +++ b/browser/src/Services/WindowManager/WindowManagerStore.ts @@ -98,6 +98,19 @@ export const reducer: Reducer = ( ...state, focusedSplitId: action.splitId, } + case "SHOW_SPLIT": + return { + ...state, + hiddenSplits: state.hiddenSplits.filter(s => s !== action.splitId), + } + case "HIDE_SPLIT": + return { + ...state, + hiddenSplits: [ + ...state.hiddenSplits.filter(s => s !== action.splitId), + action.splitId, + ], + } default: return { ...state, @@ -121,6 +134,10 @@ export const docksReducer: Reducer = ( } } +export const leftDockSelector = (state: WindowState) => { + return state.docks.left.filter(s => state.hiddenSplits.indexOf(s.id) === -1) +} + export const createStore = (): Store => { return createReduxStore("WindowManager", reducer, DefaultWindowState, []) } diff --git a/browser/src/UI/components/WindowSplits.tsx b/browser/src/UI/components/WindowSplits.tsx index a6e4a746b7..2a83053481 100644 --- a/browser/src/UI/components/WindowSplits.tsx +++ b/browser/src/UI/components/WindowSplits.tsx @@ -13,6 +13,7 @@ import { WindowSplitHost } from "./WindowSplitHost" import { IAugmentedSplitInfo, ISplitInfo, + leftDockSelector, WindowManager, WindowState, } from "./../../Services/WindowManager" @@ -114,7 +115,7 @@ const mapStateToProps = ( return { ...containerProps, activeSplitId: state.focusedSplitId, - leftDock: state.docks.left, + leftDock: leftDockSelector(state), splitRoot: state.primarySplit, } } From 0c609fe801c79c595e3322e707e79b50d88583bf Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Thu, 8 Feb 2018 12:34:55 -0800 Subject: [PATCH 065/103] Sidebar - Explorer: Add subtle animation for caret when expanding / collapsing (#1479) * Refactor explorer to use common component, and update animation in shared container * Fix lint issues --- browser/src/CSS.ts | 1 - browser/src/Services/Explorer/Explorer.less | 46 --------- .../src/Services/Explorer/ExplorerView.tsx | 95 +++---------------- browser/src/UI/components/SidebarItemView.tsx | 19 +++- 4 files changed, 28 insertions(+), 133 deletions(-) delete mode 100644 browser/src/Services/Explorer/Explorer.less diff --git a/browser/src/CSS.ts b/browser/src/CSS.ts index 08af231703..cc2a5a88eb 100644 --- a/browser/src/CSS.ts +++ b/browser/src/CSS.ts @@ -10,7 +10,6 @@ export const activate = () => { require("./Services/ContextMenu/ContextMenu.less") // tslint:disable-line - require("./Services/Explorer/Explorer.less") // tslint:disable-line require("./Services/Menu/Menu.less") require("./UI/components/Error.less") diff --git a/browser/src/Services/Explorer/Explorer.less b/browser/src/Services/Explorer/Explorer.less deleted file mode 100644 index d32f82e888..0000000000 --- a/browser/src/Services/Explorer/Explorer.less +++ /dev/null @@ -1,46 +0,0 @@ -@import (reference) "./../../UI/components/common.less"; - -.explorer { - transform: translateX(-3px); - transition: transform 0.25s ease; - user-select: none; - cursor: default; - - display: flex; - flex-direction: column; - - .header { - flex: 0 0 auto; - } - - .loaded & { - transform: translateX(0px); - } - - .items { - flex: 1 1 auto; - overflow-y: auto; - - .item { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - padding: 4px; - - .icon { - flex: 0 0 auto; - width: 20px; - text-align: center; - margin-right: 7px; - } - - .name { - flex: 1 1 auto; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - } - } -} diff --git a/browser/src/Services/Explorer/ExplorerView.tsx b/browser/src/Services/Explorer/ExplorerView.tsx index 1f32c651be..b87ce6781c 100644 --- a/browser/src/Services/Explorer/ExplorerView.tsx +++ b/browser/src/Services/Explorer/ExplorerView.tsx @@ -7,10 +7,8 @@ import * as React from "react" import { connect } from "react-redux" import styled from "styled-components" -// import { IEvent } from "oni-types" - -// import { KeyboardInputView } from "./../../Input/KeyboardInput" +import { SidebarContainerView, SidebarItemView } from "./../../UI/components/SidebarItemView" import { VimNavigator } from "./../../UI/components/VimNavigator" import { FileIcon } from "./../FileIcon" @@ -18,36 +16,6 @@ import { FileIcon } from "./../FileIcon" import * as ExplorerSelectors from "./ExplorerSelectors" import { IExplorerState } from "./ExplorerStore" -require("./Explorer.less") // tslint:disable-line - -export interface IFileViewProps { - fileName: string - isSelected: boolean - indentationLevel: number -} - -const INDENT_AMOUNT = 6 - -export class FileView extends React.PureComponent { - public render(): JSX.Element { - const style = { - paddingLeft: (INDENT_AMOUNT * this.props.indentationLevel).toString() + "px", - borderLeft: this.props.isSelected - ? "4px solid rgb(97, 175, 239)" - : "4px solid transparent", - backgroundColor: this.props.isSelected ? "rgba(97, 175, 239, 0.1)" : "transparent", - } - return ( -
-
- -
-
{this.props.fileName}
-
- ) - } -} - export interface INodeViewProps { node: ExplorerSelectors.ExplorerNode isSelected: boolean @@ -86,28 +54,30 @@ export class NodeView extends React.PureComponent { switch (node.type) { case "file": return ( - } /> ) case "container": return ( - ) case "folder": return ( - ) @@ -117,43 +87,6 @@ export class NodeView extends React.PureComponent { } } -export interface IContainerViewProps { - isContainer: boolean - expanded: boolean - name: string - isSelected: boolean - indentationLevel?: number -} - -export class ContainerView extends React.PureComponent { - public render(): JSX.Element { - const indentLevel = this.props.indentationLevel || 0 - - const headerStyle = { - paddingLeft: (indentLevel * INDENT_AMOUNT).toString() + "px", - backgroundColor: this.props.isContainer - ? "#1e2127" - : this.props.isSelected ? "rgba(97, 175, 239, 0.1)" : "transparent", - borderLeft: this.props.isSelected - ? "4px solid rgb(97, 175, 239)" - : "4px solid transparent", - } - - const caretStyle = { - transform: this.props.expanded ? "rotateZ(45deg)" : "rotateZ(0deg)", - } - - return ( -
-
- -
-
{this.props.name}
-
- ) - } -} - export interface IExplorerViewContainerProps { onSelectionChanged: (id: string) => void onClick: (id: string) => void diff --git a/browser/src/UI/components/SidebarItemView.tsx b/browser/src/UI/components/SidebarItemView.tsx index 2f5f4347da..28d75137d8 100644 --- a/browser/src/UI/components/SidebarItemView.tsx +++ b/browser/src/UI/components/SidebarItemView.tsx @@ -30,7 +30,8 @@ const SidebarItemStyleWrapper = withProps(styled.div)` flex-direction: row; justify-content: center; align-items: center; - padding: 4px; + padding-top: 4px; + padding-bottom: 4px; position: relative; .icon { @@ -43,15 +44,19 @@ const SidebarItemStyleWrapper = withProps(styled.div)` .name { flex: 1 1 auto; overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } ` const SidebarItemBackground = withProps(styled.div)` background-color: ${props => { - if (props.isFocused) { + if (props.isFocused && !props.isContainer) { return props.theme["highlight.mode.normal.background"] - } else { + } else if (props.isContainer) { return "rgb(0, 0, 0)" + } else { + return "transparent" } }}; opacity: ${props => (props.isContainer || props.isFocused ? "0.2" : "0")}; @@ -82,23 +87,27 @@ export interface ISidebarContainerViewProps { text: string isExpanded: boolean isFocused: boolean + indentationLevel?: number + isContainer?: boolean } export class SidebarContainerView extends React.PureComponent { public render(): JSX.Element { const caretStyle = { transform: this.props.isExpanded ? "rotateZ(45deg)" : "rotateZ(0deg)", + transition: "transform 0.1s ease-in", } const icon = + const indentationlevel = this.props.indentationLevel || 0 return (
{this.props.isExpanded ? this.props.children : null}
From 99f51fa422d076c6f20958c59bb5862e25bd4615 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Thu, 8 Feb 2018 13:52:38 -0800 Subject: [PATCH 066/103] Set branch name for uploads (#1480) --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5d271f35c7..037661ad0f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,7 +53,7 @@ deploy: secure: S4f/aczEABGAMKk2tmVSkoGx+T2TLPmz5z6x6RKaM+eDmAaVSAELlIj1eAz6Tu2lv3jz+cpyAIISZNC/phORsJWwzbSZHVycLrMG0N3fDTqKFxu1fl6L3b3exRe9SiKXug73ZvHfktzd/XfRcgZKop4qgrwGiM57m0ZuZb/j1LkgjytTuvNAUxXbA84I8LZs/NhY17XuXq+KPlGElIHy3UFoGqQ8pBnTypkIU5rQTsoeAxXLBE8JAFfz+nBGZ7dx6OMbQcKX5jKh/gR3vk+4aTgV8gNE2Zp24ErjSqF2zly/gP9nE2DpfR7jqpZVHnb/v+OEjRDS80tLhPo8Dbibzwt2ZZNADpYBjSGtphwAmq4DCvJ7ORExOB5+O3wmXKQGdItyBTS7sW44n6BTyv87WxWuCaSDQ9QaO9PrbJdN5YGEYeRxSTM7Mn0t72IILkfFCUeSg6fl6tFs9iWIj5zltbxH1GQsRpA8j1Idg4O+894KnQABtw/YKh6rrdeYS9y/100qAjtV6qYyiP2IdPqMWGuasOiz87q3CQ8Ejd7uhiTjAaINVqos+0k04Yf5+rT4MqkeXnYFzjXuXcqDlpq6yJIZv3aD+PMSlZi2WmTYnPJXQFndHo/x9FhEh90UF9WdO5S27ySRSo8XQT4DyL3ToPkqz8y0slNmaNqiqMouQAU= bucket: oni-builds local-dir: s3_dist - upload-dir: osx_builds + upload-dir: $TRAVIS_BRANCH acl: public_read region: us-west-2 skip_cleanup: true diff --git a/appveyor.yml b/appveyor.yml index 669a60af08..3960bb5120 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -58,7 +58,7 @@ deploy: region: us-west-2 unzip: false set_public: true - folder: windows_builds + folder: $(APPVEYOR_REPO_BRANCH) artifact: SetupExe, ProductZip # Post-install test scripts. From e43fc979fef4e594dd4361abe6ecd0564e180f3a Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Thu, 8 Feb 2018 15:26:43 -0800 Subject: [PATCH 067/103] Add back additional component in menu (#1481) --- browser/src/Services/Menu/MenuComponent.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/browser/src/Services/Menu/MenuComponent.tsx b/browser/src/Services/Menu/MenuComponent.tsx index 1ee2bfb3e4..df909cf5bc 100644 --- a/browser/src/Services/Menu/MenuComponent.tsx +++ b/browser/src/Services/Menu/MenuComponent.tsx @@ -251,6 +251,7 @@ export class MenuItem extends React.PureComponent { highlightIndices={this.props.detailHighlights} highlightClassName={"highlight"} /> + {this.props.additionalComponent} ) } From ab0704a25c4db2425d193809942d26da7d0562a7 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Thu, 8 Feb 2018 15:26:56 -0800 Subject: [PATCH 068/103] Search: Add 'control+shift+f' / 'meta+shift+f' keyboard shortcut (#1482) * Add initial shortcut plus ability to focus a particular sidebar pane * Add control-shift-f/meta-shift-f shortcut * Fix keybinding on Mac --- browser/src/Input/KeyBindings.ts | 2 + browser/src/Services/Search/index.tsx | 48 ++++++++++++++++++-- browser/src/Services/Sidebar/SidebarStore.ts | 6 +++ browser/src/index.tsx | 2 +- 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/browser/src/Input/KeyBindings.ts b/browser/src/Input/KeyBindings.ts index 8b5bae3774..3089a93393 100644 --- a/browser/src/Input/KeyBindings.ts +++ b/browser/src/Input/KeyBindings.ts @@ -32,6 +32,7 @@ export const applyDefaultKeyBindings = (oni: Oni.Plugin.Api, config: Configurati input.bind("", "oni.editor.minimize") input.bind("", "oni.editor.hide") input.bind("", "buffer.toggle") + input.bind("", "search.searchAllFiles") if (config.getValue("editor.clipboard.enabled")) { input.bind("", "editor.clipboard.yank", isVisualMode) @@ -50,6 +51,7 @@ export const applyDefaultKeyBindings = (oni: Oni.Plugin.Api, config: Configurati input.bind("", "language.symbols.workspace", () => !menu.isMenuOpen()) input.bind("", "language.symbols.document") input.bind("", "buffer.toggle") + input.bind("", "search.searchAllFiles") if (config.getValue("editor.clipboard.enabled")) { input.bind("", "editor.clipboard.yank", isVisualMode) diff --git a/browser/src/Services/Search/index.tsx b/browser/src/Services/Search/index.tsx index 744e14c9a9..f6afc6e74d 100644 --- a/browser/src/Services/Search/index.tsx +++ b/browser/src/Services/Search/index.tsx @@ -10,6 +10,7 @@ import { Event, IDisposable, IEvent } from "oni-types" import { Subject } from "rxjs/Subject" +import { CommandManager } from "./../CommandManager" import { EditorManager } from "./../EditorManager" import { SidebarManager } from "./../Sidebar" import { Workspace } from "./../Workspace" @@ -29,6 +30,7 @@ import { SearchTextBox } from "./SearchTextBox" export class SearchPane { private _onEnter = new Event() private _onLeave = new Event() + private _shouldFocusAutomatically: boolean = false private _searchProvider: ISearchProvider private _currentQuery: ISearchQuery @@ -43,12 +45,20 @@ export class SearchPane { return "Search" } - constructor(private _editorManager: EditorManager, private _workspace: Workspace) { + constructor( + private _editorManager: EditorManager, + private _workspace: Workspace, + private _onFocusEvent: IEvent, + ) { this._searchProvider = new RipGrepSearchProvider() this._searchOptionsObservable.debounceTime(100).subscribe((opts: ISearchOptions) => { this._startNewSearch(opts) }) + + this._onFocusEvent.subscribe(() => { + this._shouldFocusAutomatically = true + }) } public enter(): void { @@ -60,12 +70,16 @@ export class SearchPane { } public render(): JSX.Element { + const immedateFocus = this._shouldFocusAutomatically + this._shouldFocusAutomatically = false return ( this._onSearchOptionsChanged(opts)} + focusImmediately={immedateFocus} /> ) } @@ -107,6 +121,8 @@ export interface ISearchPaneViewProps { workspace: Workspace onEnter: IEvent onLeave: IEvent + onFocus: IEvent + focusImmediately?: boolean onSearchOptionsChanged: (opts: ISearchOptions) => void } @@ -147,7 +163,17 @@ export class SearchPaneView extends React.PureComponent< this.setState({ activeWorkspace: wd }), ) - this._subscriptions = [s1, s2, s3] + const s4 = this.props.onFocus.subscribe(() => + this.setState({ activeTextbox: "textbox.query" }), + ) + + this._subscriptions = [s1, s2, s3, s4] + + if (this.props.focusImmediately) { + this.setState({ + activeTextbox: "textbox.query", + }) + } } public componentWillUnmount(): void { @@ -250,9 +276,25 @@ export class SearchPaneView extends React.PureComponent< } export const activate = ( + commandManager: CommandManager, editorManager: EditorManager, sidebarManager: SidebarManager, workspace: Workspace, ) => { - sidebarManager.add("search", new SearchPane(editorManager, workspace)) + const onFocusEvent = new Event() + sidebarManager.add("search", new SearchPane(editorManager, workspace, onFocusEvent)) + + const searchAllFiles = () => { + sidebarManager.setActiveEntry("oni.sidebar.search") + + onFocusEvent.dispatch() + } + + commandManager.registerCommand({ + command: "search.searchAllFiles", + name: "Search: All files", + detail: "Search across files in the active workspace", + execute: searchAllFiles, + enabled: () => !!workspace.activeWorkspace, + }) } diff --git a/browser/src/Services/Sidebar/SidebarStore.ts b/browser/src/Services/Sidebar/SidebarStore.ts index b0fc710343..17331c4d81 100644 --- a/browser/src/Services/Sidebar/SidebarStore.ts +++ b/browser/src/Services/Sidebar/SidebarStore.ts @@ -77,6 +77,12 @@ export class SidebarManager { } } + public focusContents(): void { + if (this._contentSplit.isVisible) { + this._contentSplit.focus() + } + } + public toggleSidebarVisibility(): void { if (this._contentSplit.isVisible) { this._contentSplit.hide() diff --git a/browser/src/index.tsx b/browser/src/index.tsx index f8477b8e92..fca59909b6 100644 --- a/browser/src/index.tsx +++ b/browser/src/index.tsx @@ -208,7 +208,7 @@ const start = async (args: string[]): Promise => { Snippets.activate() const Search = await import("./Services/Search") - Search.activate(editorManager, Sidebar.getInstance(), workspace) + Search.activate(commandManager, editorManager, Sidebar.getInstance(), workspace) const ThemePicker = await themePickerPromise ThemePicker.activate(configuration, menuManager, Themes.getThemeManagerInstance()) From 4b53c068213959f3a199f1267657775072289450 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Fri, 9 Feb 2018 11:57:36 -0800 Subject: [PATCH 069/103] Refactoring: Move embedded browser from 'extension' -> 'core' (#1492) * Move browser back to core * Fix syntax issues in conversion --- .../src/Services/Browser}/index.tsx | 77 +++++++------------ browser/src/index.tsx | 3 + extensions/oni-layer-browser/README.md | 3 - extensions/oni-layer-browser/package.json | 16 ---- extensions/oni-layer-browser/tsconfig.json | 16 ---- package.json | 18 +---- 6 files changed, 36 insertions(+), 97 deletions(-) rename {extensions/oni-layer-browser/src => browser/src/Services/Browser}/index.tsx (75%) delete mode 100644 extensions/oni-layer-browser/README.md delete mode 100644 extensions/oni-layer-browser/package.json delete mode 100644 extensions/oni-layer-browser/tsconfig.json diff --git a/extensions/oni-layer-browser/src/index.tsx b/browser/src/Services/Browser/index.tsx similarity index 75% rename from extensions/oni-layer-browser/src/index.tsx rename to browser/src/Services/Browser/index.tsx index 4747e74968..90ff3ed3bf 100644 --- a/extensions/oni-layer-browser/src/index.tsx +++ b/browser/src/Services/Browser/index.tsx @@ -11,6 +11,12 @@ import styled from "styled-components" import * as Oni from "oni-api" import { Event, IDisposable, IEvent } from "oni-types" +import { CommandManager } from "./../CommandManager" +import { Configuration } from "./../Configuration" +import { EditorManager } from "./../EditorManager" + +import { Icon, IconSize } from "./../../UI/Icon" + const WebView = require("react-electron-web-view") // tslint:disable-line const Column = styled.div` @@ -74,20 +80,12 @@ const AddressBar = styled.div` text-align: left; ` -export interface Icons { - backIcon: any - forwardIcon: any - reloadIcon: any - cancelIcon: any - debugIcon: any -} - export class BrowserLayer implements Oni.EditorLayer { private _goBackEvent = new Event() private _goForwardEvent = new Event() private _reloadEvent = new Event() - constructor(private _url: string, private _icons: Icons) {} + constructor(private _url: string) {} public get id(): string { return "oni.browser" @@ -97,7 +95,6 @@ export class BrowserLayer implements Oni.EditorLayer { return ( goForward: IEvent @@ -150,22 +146,24 @@ export class BrowserView extends React.PureComponent { this._goBack()}> - {this.props.icons.backIcon} + this._goForward()}> - {this.props.icons.forwardIcon} + this._reload()}> - {this.props.icons.reloadIcon} + {this.props.url} - {this.props.icons.debugIcon} + + + this._initializeElement(elem)} + ref={(elem: HTMLElement) => this._initializeElement(elem)} src={this.props.url} style={{ position: "absolute", @@ -204,40 +202,23 @@ export class BrowserView extends React.PureComponent { } } -export const activate = (oni: Oni.Plugin.Api) => { +export const activate = ( + commandManager: CommandManager, + configuration: Configuration, + editorManager: EditorManager, +) => { let count = 0 const activeLayers: { [bufferId: string]: BrowserLayer } = {} const openUrl = async (url: string) => { - if (oni.configuration.getValue("experimental.browser.enabled")) { + if (configuration.getValue("experimental.browser.enabled")) { count++ - const buffer: Oni.Buffer = await (oni.editors.activeEditor as any).newFile( + const buffer: Oni.Buffer = await (editorManager.activeEditor as any).newFile( "Browser" + count.toString(), ) - const oni2: any = oni - const backIcon = oni2.ui.createIcon({ - name: "chevron-left", - size: oni2.ui.iconSize.Large, - }) - const forwardIcon = oni2.ui.createIcon({ - name: "chevron-right", - size: oni2.ui.iconSize.Large, - }) - const reloadIcon = oni2.ui.createIcon({ name: "undo", size: oni2.ui.iconSize.Large }) - const cancelIcon = oni2.ui.createIcon({ name: "times", size: oni2.ui.iconSize.Large }) - const debugIcon = oni2.ui.createIcon({ name: "bug", size: oni2.ui.iconSize.Large }) - - const icons: Icons = { - backIcon, - forwardIcon, - reloadIcon, - cancelIcon, - debugIcon, - } - - const layer = new BrowserLayer(url, icons) + const layer = new BrowserLayer(url) buffer.addLayer(layer) activeLayers[buffer.id] = layer } else { @@ -245,7 +226,7 @@ export const activate = (oni: Oni.Plugin.Api) => { } } - oni.commands.registerCommand({ + commandManager.registerCommand({ command: "browser.openUrl", execute: openUrl, name: null, @@ -253,7 +234,7 @@ export const activate = (oni: Oni.Plugin.Api) => { }) const executeCommandForLayer = (callback: (browserLayer: BrowserLayer) => void) => () => { - const activeBuffer = oni.editors.activeEditor.activeBuffer + const activeBuffer = editorManager.activeEditor.activeBuffer const browserLayer = activeLayers[activeBuffer.id] if (browserLayer) { @@ -262,11 +243,11 @@ export const activate = (oni: Oni.Plugin.Api) => { } const isBrowserLayerActive = () => - !!activeLayers[oni.editors.activeEditor.activeBuffer.id] && - !!oni.configuration.getValue("experimental.browser.enabled") + !!activeLayers[editorManager.activeEditor.activeBuffer.id] && + !!configuration.getValue("experimental.browser.enabled") // Per-layer commands - oni.commands.registerCommand({ + commandManager.registerCommand({ command: "browser.goBack", execute: executeCommandForLayer(browser => browser.goBack()), name: "Browser: Go back", @@ -274,7 +255,7 @@ export const activate = (oni: Oni.Plugin.Api) => { enabled: isBrowserLayerActive, }) - oni.commands.registerCommand({ + commandManager.registerCommand({ command: "browser.goForward", execute: executeCommandForLayer(browser => browser.goForward()), name: "Browser: Go forward", @@ -282,7 +263,7 @@ export const activate = (oni: Oni.Plugin.Api) => { enabled: isBrowserLayerActive, }) - oni.commands.registerCommand({ + commandManager.registerCommand({ command: "browser.reload", execute: executeCommandForLayer(browser => browser.reload()), name: "Browser: Reload", diff --git a/browser/src/index.tsx b/browser/src/index.tsx index fca59909b6..f069e951dd 100644 --- a/browser/src/index.tsx +++ b/browser/src/index.tsx @@ -188,6 +188,9 @@ const start = async (args: string[]): Promise => { diagnostics.start(languageManager) + const Browser = await import("./Services/Browser") + Browser.activate(commandManager, configuration, editorManager) + Performance.startMeasure("Oni.Start.Activate") const api = pluginManager.startApi() configuration.activate(api) diff --git a/extensions/oni-layer-browser/README.md b/extensions/oni-layer-browser/README.md deleted file mode 100644 index 26029e867b..0000000000 --- a/extensions/oni-layer-browser/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# oni-layer-browser - -Implementation of an embedded browser layer for Oni. This brings in an integrated browser experience, controllable in the same way that existing window splits are leveraged. diff --git a/extensions/oni-layer-browser/package.json b/extensions/oni-layer-browser/package.json deleted file mode 100644 index dbb3388b01..0000000000 --- a/extensions/oni-layer-browser/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "oni-layer-browser", - "version": "0.0.1", - "main": "lib/index.js", - "engines": { - "oni": "^0.0.1" - }, - "scripts": { - "build": "rimraf lib && tsc", - "test": "tsc -p tsconfig.test.json && mocha --recursive ./lib_test/test" - }, - "oni": {}, - "tbd-dependencies": {}, - "tbd-peerDependencies": {}, - "tbd-devDependencies": {} -} diff --git a/extensions/oni-layer-browser/tsconfig.json b/extensions/oni-layer-browser/tsconfig.json deleted file mode 100644 index c71a5d2969..0000000000 --- a/extensions/oni-layer-browser/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "moduleResolution": "node", - "preserveConstEnums": true, - "outDir": "./lib", - "jsx": "react", - "lib": ["dom", "es2017"], - "declaration": true, - "sourceMap": true, - "target": "es2015", - "skipLibCheck": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules"] -} diff --git a/package.json b/package.json index 4f7073b96e..be70260c85 100644 --- a/package.json +++ b/package.json @@ -122,8 +122,7 @@ "build:browser-debug": "webpack --config browser/webpack.debug.config.js", "build:main": "cd main && tsc -p tsconfig.json", "build:plugins": - "npm run build:plugin:oni-layer-browser && npm run build:plugin:oni-plugin-typescript && npm run build:plugin:oni-plugin-markdown-preview", - "build:plugin:oni-layer-browser": "cd extensions/oni-layer-browser && npm run build", + "npm run build:plugin:oni-plugin-typescript && npm run build:plugin:oni-plugin-markdown-preview", "build:plugin:oni-plugin-typescript": "cd vim/core/oni-plugin-typescript && npm run build", "build:plugin:oni-plugin-markdown-preview": "cd extensions/oni-plugin-markdown-preview && npm run build", @@ -144,20 +143,12 @@ "test:unit": "npm run test:unit:browser", "test:unit:browser": "npm run build:test:unit && cd browser && electron-mocha --renderer --require testHelpers.js --recursive ../lib_test/browser/test", - "fix-lint": - "npm run fix-lint:browser && npm run fix-lint:main && npm run fix-lint:test && npm run fix-lint:plugins", + "fix-lint": "npm run fix-lint:browser && npm run fix-lint:main && npm run fix-lint:test", "fix-lint:browser": "tslint --fix --project browser/tsconfig.json --exclude **/node_modules/**/* --config tslint.json && tslint --fix --project vim/core/oni-plugin-typescript/tsconfig.json --config tslint.json && tslint --fix --project extensions/oni-plugin-markdown-preview/tsconfig.json --config tslint.json", - "fix-lint:plugins": "npm run fix-lint:plugins:oni-layer-browser", - "fix-lint:plugins:oni-layer-browser": - "tslint --fix --project extensions/oni-layer-browser/tsconfig.json --config tslint.json", "fix-lint:main": "tslint --fix --project main/tsconfig.json --config tslint.json", "fix-lint:test": "tslint --fix --project test/tsconfig.json --config tslint.json", - "lint": - "npm run lint:browser && npm run lint:main && npm run lint:test && npm run lint:plugins", - "lint:plugins": "npm run lint:plugin:oni-layer-browser", - "lint:plugin:oni-layer-browser": - "tslint --project extensions/oni-layer-browser/tsconfig.json --config tslint.json", + "lint": "npm run lint:browser && npm run lint:main && npm run lint:test", "lint:browser": "tslint --project browser/tsconfig.json --config tslint.json && tslint --project vim/core/oni-plugin-typescript/tsconfig.json --config tslint.json && tslint --project extensions/oni-plugin-markdown-preview/tsconfig.json --config tslint.json", "lint:main": "tslint --project main/tsconfig.json --config tslint.json", @@ -177,8 +168,7 @@ "watch:browser": "webpack-dev-server --config browser/webpack.debug.config.js --host localhost --port 8191", "watch:plugins": - "npm run watch:plugins:oni-layer-browser && npm run watch:plugins:oni-plugin-typescript && npm run watch:plugins:oni-plugin-markdown-preview", - "watch:plugins:oni-layer-browser": "cd extensions/oni-layer-browser && tsc --watch", + "npm run watch:plugins:oni-plugin-typescript && npm run watch:plugins:oni-plugin-markdown-preview", "watch:plugins:oni-plugin-typescript": "cd vim/core/oni-plugin-typescript && tsc --watch", "watch:plugins:oni-plugin-markdown-preview": "cd extensions/oni-plugin-markdown-preview && tsc --watch", From a75e10e02ab15ae7c78bf070d6c3a12aa9d51002 Mon Sep 17 00:00:00 2001 From: Akin Date: Fri, 9 Feb 2018 20:04:26 +0000 Subject: [PATCH 070/103] add inner name component to truncate long names (#1489) --- browser/src/UI/components/Tabs.less | 1 - browser/src/UI/components/Tabs.tsx | 12 +++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/browser/src/UI/components/Tabs.less b/browser/src/UI/components/Tabs.less index ff3502f761..cf6f5bab3a 100644 --- a/browser/src/UI/components/Tabs.less +++ b/browser/src/UI/components/Tabs.less @@ -77,7 +77,6 @@ transition: opacity 0.25s; overflow: hidden; - text-overflow: ellipsis; user-select: none; .name { diff --git a/browser/src/UI/components/Tabs.tsx b/browser/src/UI/components/Tabs.tsx index 3471fd9db0..cb44c74f20 100644 --- a/browser/src/UI/components/Tabs.tsx +++ b/browser/src/UI/components/Tabs.tsx @@ -16,6 +16,7 @@ import { addDefaultUnitIfNeeded } from "./../../Font" import { Sneakable } from "./../../UI/components/Sneakable" import { Icon } from "./../../UI/Icon" +import { styled, withProps } from "./../components/common" import { FileIcon } from "./../../Services/FileIcon" @@ -55,6 +56,13 @@ export interface ITabsProps { fontSize: string } +const InnerName = withProps<{ isLong?: boolean }>(styled.span)` + ${p => p.isLong && `width: 250px;`}; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +` + export class Tabs extends React.PureComponent { public render(): JSX.Element { if (!this.props.visible) { @@ -155,7 +163,9 @@ export class Tab extends React.Component { />
- {this.props.name} + 50}> + {this.props.name} +
From 9a24b8200634b0cc354d6fc2c99506e1368f9eb0 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Fri, 9 Feb 2018 12:16:08 -0800 Subject: [PATCH 071/103] Error Handling: Add Error Boundaries on window splits (#1493) * Add error boundaries * Add initial error component * Create component for error info * Make error text selectable * Add CiTest --- .../src/Editor/NeovimEditor/NeovimSurface.tsx | 7 -- browser/src/UI/components/RedErrorScreen.tsx | 93 +++++++++++++++++++ .../UI/components/SidebarEmptyPaneView.tsx | 2 + browser/src/UI/components/WindowSplitHost.tsx | 47 +++++++++- test/CiTests.ts | 1 + test/ci/WindowManager.ErrorBoundary.tsx | 44 +++++++++ 6 files changed, 186 insertions(+), 8 deletions(-) create mode 100644 browser/src/UI/components/RedErrorScreen.tsx create mode 100644 test/ci/WindowManager.ErrorBoundary.tsx diff --git a/browser/src/Editor/NeovimEditor/NeovimSurface.tsx b/browser/src/Editor/NeovimEditor/NeovimSurface.tsx index 61b5c2af89..4834ef6afb 100644 --- a/browser/src/Editor/NeovimEditor/NeovimSurface.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimSurface.tsx @@ -64,13 +64,6 @@ class NeovimSurface extends React.Component { this.props.setViewport(width, height) } - public componentDidCatch(e: Error) { - // TODO Add an Error Page to inform user of how to proceed e.g. file bug report - // also pass error detais so user can file those - // tslint:disable-next-line - console.warn(`Error mounting the Neovim editor because`, e) - } - public render(): JSX.Element { return (
diff --git a/browser/src/UI/components/RedErrorScreen.tsx b/browser/src/UI/components/RedErrorScreen.tsx new file mode 100644 index 0000000000..670c98d8fd --- /dev/null +++ b/browser/src/UI/components/RedErrorScreen.tsx @@ -0,0 +1,93 @@ +/** + * Component displaying an error message when there is a failure + */ + +import * as React from "react" +import styled from "styled-components" + +export interface RedErrorScreenViewProps { + error: Error + info: React.ErrorInfo +} + +const RedScreenWrapper = styled.div` + width: 100%; + height: 100%; + background-color: rgba(255, 56, 96, 0.5); + color: white; + + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + pointer-events: all; +` + +const RedScreenContentsWrapper = styled.div` + max-width: 800px; +` + +const HeaderTitleWrapper = styled.div` + font-size: 2em; + font-weight: bold; +` + +const HeaderSubtitleWrapper = styled.div` + font-size: 1.2em + font-weight: bold; +` + +const ErrorSectionWrapper = styled.div` + font-weight: bold; + margin-top: 3em; + margin-bottom: 1em; +` + +const ErrorTextWrapper = styled.div` + -webkit-user-select: text; +` + +const ButtonsWrapper = styled.div` + display: flex; + flex-direction: row; + + margin-top: 4em; +` + +import { OniButton } from "./SidebarEmptyPaneView" + +import { remote } from "electron" + +const openDebugger = () => remote.getCurrentWebContents().openDevTools() +const createIssue = () => remote.shell.openExternal("https://github.com/onivim/oni/issues/new") + +export class RedErrorScreenView extends React.PureComponent { + public render(): JSX.Element { + const errorMessage = this.props.error + ? this.props.error.toString() + : "Unable to get error info" + + const additionalStack = + this.props.info && this.props.info.componentStack + ? this.props.info.componentStack.toString() + : "None" + + return ( + + + Oh no! + We encountered an error... + Error: + {errorMessage} + Additional Info: + {additionalStack} + + + + + + + ) + } +} diff --git a/browser/src/UI/components/SidebarEmptyPaneView.tsx b/browser/src/UI/components/SidebarEmptyPaneView.tsx index 2cb05bb10b..d8bdd5e531 100644 --- a/browser/src/UI/components/SidebarEmptyPaneView.tsx +++ b/browser/src/UI/components/SidebarEmptyPaneView.tsx @@ -32,6 +32,8 @@ const ButtonWrapper = styled.button` cursor: pointer; transition: all 0.1s ease-in; + pointer-events: all; + &:hover { ${boxShadow} transform: translateY(-1px); } diff --git a/browser/src/UI/components/WindowSplitHost.tsx b/browser/src/UI/components/WindowSplitHost.tsx index ffdcba686b..4ff69e6d56 100644 --- a/browser/src/UI/components/WindowSplitHost.tsx +++ b/browser/src/UI/components/WindowSplitHost.tsx @@ -8,6 +8,8 @@ import * as React from "react" import * as Oni from "oni-api" +import { RedErrorScreenView } from "./../components/RedErrorScreen" + export interface IWindowSplitHostProps { split: Oni.IWindowSplit containerClassName: string @@ -15,11 +17,54 @@ export interface IWindowSplitHostProps { onClick: (evt: React.MouseEvent) => void } +export interface WindowSplitHostState { + errorInfo: ErrorInfo +} + +export interface ErrorInfo { + error: Error + info: React.ErrorInfo +} + /** * Component responsible for rendering an individual window split */ -export class WindowSplitHost extends React.PureComponent { +export class WindowSplitHost extends React.PureComponent< + IWindowSplitHostProps, + WindowSplitHostState +> { + constructor(props: IWindowSplitHostProps) { + super(props) + + this.state = { + errorInfo: null, + } + + // Error + // React.ErrorInfo + } + + public componentDidCatch(error: Error, info: React.ErrorInfo): void { + this.setState({ + errorInfo: { + error, + info, + }, + }) + } + public render(): JSX.Element { + if (this.state.errorInfo) { + return ( +
+ +
+ ) + } + const className = this.props.containerClassName + (this.props.isFocused ? " focus" : " not-focused") return ( diff --git a/test/CiTests.ts b/test/CiTests.ts index 2989458959..dcedd51159 100644 --- a/test/CiTests.ts +++ b/test/CiTests.ts @@ -23,6 +23,7 @@ const CiTests = [ "QuickOpenTest", "StatusBar-Mode", "NoInstalledNeovim", + "WindowManager.ErrorBoundary", "Workspace.ConfigurationTest", // Regression Tests diff --git a/test/ci/WindowManager.ErrorBoundary.tsx b/test/ci/WindowManager.ErrorBoundary.tsx new file mode 100644 index 0000000000..add7f16a88 --- /dev/null +++ b/test/ci/WindowManager.ErrorBoundary.tsx @@ -0,0 +1,44 @@ +/** + * Test script to verify per-workspace configuration settings + */ + +import * as assert from "assert" +import * as fs from "fs" +import * as os from "os" +import * as path from "path" + +import * as mkdirp from "mkdirp" + +import * as Oni from "oni-api" + +import { createNewFile } from "./Common" + +export class BadLayer implements Oni.EditorLayer { + public get id(): string { + return "automation.test.layer" + } + + public render(context: Oni.EditorLayerRenderContext): JSX.Element { + throw new Error("Bad layer!") + } +} + +const getErrorElements = () => { + return document.querySelectorAll(".red-error-screen") +} + +export const test = async (oni: Oni.Plugin.Api) => { + await oni.automation.waitForEditors() + + await createNewFile("js", oni) + + oni.editors.activeEditor.activeBuffer.addLayer(new BadLayer()) + + // Wait for error screen to appear + await oni.automation.waitFor(() => getErrorElements().length === 1) + + // Validate that some details about the error are shown + const errorElement = getErrorElements()[0] + const content = errorElement.textContent + assert.ok(content.indexOf("Bad layer") >= 0) +} From fec88f118699ad3ed25a5ff734fec081f067b385 Mon Sep 17 00:00:00 2001 From: Tal Amuyal Date: Sat, 10 Feb 2018 01:23:00 +0200 Subject: [PATCH 072/103] Add tests for Markdown preview plugin (#1415) * Add tests for Markdown preview plugin * Implement plugin API * Implement mock API for oni-plugin-markdown-preview * Implement actual tests * Add custom conf that enables the markdown-preview plugin for testing * Code Review changes --- browser/src/Plugins/Api/Oni.ts | 6 ++ browser/src/Plugins/Plugin.ts | 13 +++- browser/src/Plugins/PluginManager.ts | 16 ++++ .../oni-plugin-markdown-preview/src/index.tsx | 38 +++++++--- test/CiTests.ts | 1 + test/ci/Assert.ts | 53 ++++++++++++++ test/ci/MarkdownPreviewTest.config.js | 7 ++ test/ci/MarkdownPreviewTest.tsx | 73 +++++++++++++++++++ 8 files changed, 197 insertions(+), 10 deletions(-) create mode 100644 test/ci/Assert.ts create mode 100644 test/ci/MarkdownPreviewTest.config.js create mode 100644 test/ci/MarkdownPreviewTest.tsx diff --git a/browser/src/Plugins/Api/Oni.ts b/browser/src/Plugins/Api/Oni.ts index e548551fb8..2011b3ebfd 100644 --- a/browser/src/Plugins/Api/Oni.ts +++ b/browser/src/Plugins/Api/Oni.ts @@ -14,6 +14,8 @@ import * as Process from "./Process" import { Services } from "./Services" import { Ui } from "./Ui" +import { getInstance as getPluginsManagerInstance } from "./../PluginManager" + import { automation } from "./../../Services/Automation" import { Colors, getInstance as getColors } from "./../../Services/Colors" import { commandManager } from "./../../Services/CommandManager" @@ -78,6 +80,10 @@ export class Oni extends EventEmitter implements OniApi.Plugin.Api { return Log } + public get plugins(): any { + return getPluginsManagerInstance() + } + public get recorder(): any { return recorder } diff --git a/browser/src/Plugins/Plugin.ts b/browser/src/Plugins/Plugin.ts index 85ea1ba50e..e1ee4da78c 100644 --- a/browser/src/Plugins/Plugin.ts +++ b/browser/src/Plugins/Plugin.ts @@ -12,11 +12,16 @@ export class Plugin { private _oniPluginMetadata: Capabilities.IPluginMetadata private _oni: Oni private _id: string + private _instance: any public get id(): string { return this._id } + public get instance(): any { + return this._instance + } + public get metadata(): Capabilities.IPluginMetadata { return this._oniPluginMetadata } @@ -25,6 +30,11 @@ export class Plugin { return this._source } + public get name(): string | null { + const metadata = this.metadata + return metadata === null || metadata === undefined ? null : metadata.name + } + constructor(private _pluginRootDirectory: string, private _source: string) { const packageJsonPath = path.join(this._pluginRootDirectory, "package.json") @@ -51,8 +61,9 @@ export class Plugin { try { vm.runInNewContext( - `debugger; const pluginEntryPoint = require('${moduleEntryPoint}').activate; if (!pluginEntryPoint) { console.warn('No activate method found for: ${moduleEntryPoint}'); } else { pluginEntryPoint(Oni); } `, + `debugger; const pluginEntryPoint = require('${moduleEntryPoint}').activate; if (!pluginEntryPoint) { console.warn('No activate method found for: ${moduleEntryPoint}'); } else { pluginContainer._instance = pluginEntryPoint(Oni); } `, { + pluginContainer: this, Oni: this._oni, require: window["require"], // tslint:disable-line no-string-literal console, diff --git a/browser/src/Plugins/PluginManager.ts b/browser/src/Plugins/PluginManager.ts index 002c51b888..748040686c 100644 --- a/browser/src/Plugins/PluginManager.ts +++ b/browser/src/Plugins/PluginManager.ts @@ -16,6 +16,7 @@ export class PluginManager { private _rootPluginPaths: string[] = [] private _plugins: Plugin[] = [] private _anonymousPlugin: AnonymousPlugin + private _pluginsActivated: boolean = false public get plugins(): Plugin[] { return this._plugins @@ -59,6 +60,8 @@ export class PluginManager { plugin.activate() }) + this._pluginsActivated = true + return this._anonymousPlugin.oni } @@ -68,6 +71,19 @@ export class PluginManager { return pluginPaths.concat(this._rootPluginPaths) } + public get loaded(): boolean { + return this._pluginsActivated + } + + public getPlugin(name: string): any { + for (const plugin of this._plugins) { + if (plugin.name === name) { + return plugin.instance + } + } + return null + } + private _createPlugin(pluginRootDirectory: string, source: string): Plugin { return new Plugin(pluginRootDirectory, source) } diff --git a/extensions/oni-plugin-markdown-preview/src/index.tsx b/extensions/oni-plugin-markdown-preview/src/index.tsx index cd715c41e9..0080cd9806 100644 --- a/extensions/oni-plugin-markdown-preview/src/index.tsx +++ b/extensions/oni-plugin-markdown-preview/src/index.tsx @@ -1,4 +1,4 @@ -import { Event, EventCallback, IDisposable, IEvent } from "oni-types" +import { EventCallback, IDisposable, IEvent } from "oni-types" import * as dompurify from "dompurify" import * as marked from "marked" @@ -11,6 +11,7 @@ import * as React from "react" */ interface IMarkdownPreviewProps { oni: Oni.Plugin.Api + instance: MarkdownPreviewEditor } interface IColors { @@ -65,7 +66,9 @@ class MarkdownPreview extends React.PureComponent } @@ -168,12 +171,31 @@ class MarkdownPreview extends React.PureComponent this.onBufferEnter(args)) } + public isPaneOpen(): boolean { + return this._open + } + + public getUnrenderedContent(): string { + return this._unrenderedContent + } + + public getRenderedContent(): string { + return this._renderedContent + } + + public updateContent(unrendered: string, rendered: string): void { + this._unrenderedContent = unrendered + this._renderedContent = rendered + } + public toggle(): void { if (this._open) { this.close() @@ -198,7 +220,7 @@ class MarkdownPreviewEditor implements Oni.IWindowSplit { } public render(): JSX.Element { - return + return } private onBufferEnter(bufferInfo: Oni.EditorBufferEventArgs): void { @@ -208,16 +230,12 @@ class MarkdownPreviewEditor implements Oni.IWindowSplit { } } -let preview: MarkdownPreviewEditor = null - -export const activate = (oni: any) => { +export function activate(oni: any): any { if (!oni.configuration.getValue("experimental.markdownPreview.enabled", false)) { return } - if (!preview) { - preview = new MarkdownPreviewEditor(oni) - } + const preview = new MarkdownPreviewEditor(oni) oni.commands.registerCommand( new Command( @@ -251,6 +269,8 @@ export const activate = (oni: any) => { }, ), ) + + return preview as any } class Command implements Oni.Commands.ICommand { diff --git a/test/CiTests.ts b/test/CiTests.ts index dcedd51159..25268ebeaf 100644 --- a/test/CiTests.ts +++ b/test/CiTests.ts @@ -19,6 +19,7 @@ const CiTests = [ "AutoCompletionTest-TypeScript", "Editor.ExternalCommandLineTest", "LargeFileTest", + "MarkdownPreviewTest", "PaintPerformanceTest", "QuickOpenTest", "StatusBar-Mode", diff --git a/test/ci/Assert.ts b/test/ci/Assert.ts new file mode 100644 index 0000000000..4d8b343661 --- /dev/null +++ b/test/ci/Assert.ts @@ -0,0 +1,53 @@ +/** + * An assertion framework + */ + +import * as stock_assert from "assert" + +export class Assertor { + private _lastSuccessIndex: number = 0 + + constructor(private _testName: string) {} + + public contains(containing: string, contained: string, name: string): void { + this.assert( + containing.indexOf(contained) >= 0, + `${name} expected to contain \`${contained}\`, but instead has only \`${containing}\``, + ) + } + + public isEmpty(str: string, name: string): void { + this.assert( + str.length === 0, + `${name} expected to be empty, instead it has \`${str}\` (${str.length} characters)`, + ) + } + + public defined(obj: any, name: string): void { + if (obj === null) { + this.failed(`${name} is null`) + } else if (obj === undefined) { + this.failed(`${name} is undefined`) + } else { + this._lastSuccessIndex += 1 + } + } + + /** + * A temporary solution that works around the issue that assert doesn't print the error + */ + public assert(condition: boolean, message: string): void { + if (condition) { + this._lastSuccessIndex += 1 + } else { + this.failed(message) + } + } + + private failed(message: string): void { + const index = this._lastSuccessIndex + 1 + const messagePrefix = `[${this._testName}] Assertion #${index}: ` + console.error(messagePrefix + message) // tslint:disable-line no-console + stock_assert(false, message) + } +} diff --git a/test/ci/MarkdownPreviewTest.config.js b/test/ci/MarkdownPreviewTest.config.js new file mode 100644 index 0000000000..1b1541e1c6 --- /dev/null +++ b/test/ci/MarkdownPreviewTest.config.js @@ -0,0 +1,7 @@ +// For more information on customizing Oni, +// check out our wiki page: +// https://github.com/onivim/oni/wiki/Configuration + +module.exports = { + "experimental.markdownPreview.enabled": true, +}; diff --git a/test/ci/MarkdownPreviewTest.tsx b/test/ci/MarkdownPreviewTest.tsx new file mode 100644 index 0000000000..a057ce0ef5 --- /dev/null +++ b/test/ci/MarkdownPreviewTest.tsx @@ -0,0 +1,73 @@ +/** + * Test the Markdown-preview plugin + */ + +import { Assertor } from "./Assert" +import { getTemporaryFilePath, navigateToFile } from "./Common" + +import * as Oni from "oni-api" + +interface IPluginManager { + getPlugin(name: string): any +} + +interface IOniWithPluginApi { + plugins: IPluginManager +} + +interface IMarkdownPreviewPlugin { + isPaneOpen(): boolean + getUnrenderedContent(): string + getRenderedContent(): string +} + +export const settings = { + configPath: "MarkdownPreviewTest.config.js", +} + +export async function test(typedOni: Oni.Plugin.Api) { + const assert = new Assertor("Markdown-preview") + + const typelessOni = typedOni as any + const oni = typelessOni as IOniWithPluginApi + + await typedOni.automation.waitForEditors() + + const plugins = oni.plugins + const typelessPluginsManager = plugins as any + await typedOni.automation.waitFor(() => typelessPluginsManager.loaded) + const markdownPlugin = plugins.getPlugin( + "oni-plugin-markdown-preview", + ) as IMarkdownPreviewPlugin + assert.defined(markdownPlugin, "plugin instance") + + assert.assert(!markdownPlugin.isPaneOpen(), "Preview pane is not initially closed") + + await navigateToFile(getTemporaryFilePath("md"), typedOni) + await typedOni.automation.waitFor(() => markdownPlugin.isPaneOpen()) + assert.isEmpty( + markdownPlugin.getUnrenderedContent().trim(), + "Preview pane for empty Markdown buffer", + ) + + await insertText(typedOni, "# Title 1") + assert.contains( + markdownPlugin.getRenderedContent(), + ">Title 1", + "Preview pane with rendered header element", + ) +} + +async function awaitEditorMode(oni: Oni.Plugin.Api, mode: string): Promise { + function condition(): boolean { + return oni.editors.activeEditor.mode === mode + } + await oni.automation.waitFor(condition) +} + +async function insertText(oni: Oni.Plugin.Api, text: string): Promise { + oni.automation.sendKeys("i") + await awaitEditorMode(oni, "insert") + oni.automation.sendKeys(`${text}`) + await awaitEditorMode(oni, "normal") +} From ab2a4cc208457f1176a756c327b5eaa2bab439b9 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Fri, 9 Feb 2018 16:22:23 -0800 Subject: [PATCH 073/103] Add monitor for unhandled errors / rejections, and show in notifications (#1494) --- .../Notifications/NotificationsView.tsx | 7 +- browser/src/Services/Notifications/index.ts | 2 + browser/src/Services/UnhandledErrorMonitor.ts | 90 +++++++++++++++++++ browser/src/index.tsx | 5 ++ 4 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 browser/src/Services/UnhandledErrorMonitor.ts diff --git a/browser/src/Services/Notifications/NotificationsView.tsx b/browser/src/Services/Notifications/NotificationsView.tsx index d75e3c147b..fb696c09e0 100644 --- a/browser/src/Services/Notifications/NotificationsView.tsx +++ b/browser/src/Services/Notifications/NotificationsView.tsx @@ -61,7 +61,6 @@ const NotificationWrapper = styled.div` background-color: red; color: white; width: 20em; - height: 4em; margin: 1em; @@ -112,12 +111,16 @@ const NotificationTitle = styled.div` font-weight: bold; font-size: 1.1em; + + margin-top: 0.5em; ` const NotificationDescription = styled.div` flex: 1 1 auto; overflow-y: auto; - overflow-x: none; + overflow-x: hidden; + + margin: 1em 0em; font-size: 0.9em; ` diff --git a/browser/src/Services/Notifications/index.ts b/browser/src/Services/Notifications/index.ts index 84eae14482..3bb3ad11d0 100644 --- a/browser/src/Services/Notifications/index.ts +++ b/browser/src/Services/Notifications/index.ts @@ -6,6 +6,8 @@ import { OverlayManager } from "./../Overlay" import { Notifications } from "./Notifications" +export * from "./Notifications" + let _notifications: Notifications = null export const activate = (overlayManager: OverlayManager): void => { diff --git a/browser/src/Services/UnhandledErrorMonitor.ts b/browser/src/Services/UnhandledErrorMonitor.ts new file mode 100644 index 0000000000..61c9daa7b5 --- /dev/null +++ b/browser/src/Services/UnhandledErrorMonitor.ts @@ -0,0 +1,90 @@ +/** + * UnhandledErrorMonitor + * + * Helper module to listen to unhandled errors + */ + +import { Event, IEvent } from "oni-types" + +import { Notifications } from "./Notifications" + +export class UnhandledErrorMonitor { + private _onUnhandledErrorEvent = new Event() + private _onUnhandledRejectionEvent = new Event() + + private _queuedErrors: Error[] = [] + private _queuedRejections: string[] = [] + private _started: boolean = false + + public get onUnhandledError(): IEvent { + return this._onUnhandledErrorEvent + } + + public get onUnhandledRejection(): IEvent { + return this._onUnhandledRejectionEvent + } + + constructor() { + window.addEventListener("unhandledrejection", (evt: any) => { + if (!this._started) { + this._queuedRejections.push(evt.reason) + } + + this._onUnhandledRejectionEvent.dispatch(evt.reason) + }) + + window.addEventListener("error", (evt: any) => { + if (!this._started) { + this._queuedErrors.push(evt.error) + } + + this._onUnhandledErrorEvent.dispatch(evt.error) + }) + } + + public start(): void { + this._started = true + + this._queuedRejections.forEach(rejection => + this._onUnhandledRejectionEvent.dispatch(rejection), + ) + this._queuedErrors.forEach(err => this._onUnhandledErrorEvent.dispatch(err)) + + this._queuedErrors = [] + this._queuedRejections = [] + } +} + +let _unhandledErrorMonitor: UnhandledErrorMonitor = null + +export const activate = () => { + if (!_unhandledErrorMonitor) { + _unhandledErrorMonitor = new UnhandledErrorMonitor() + } +} + +import { remote } from "electron" + +export const start = (notifications: Notifications) => { + const showError = (title: string, errorText: string) => { + const notification = notifications.createItem() + + notification.onClick.subscribe(() => { + remote.getCurrentWebContents().openDevTools() + }) + + notification.setLevel("error") + notification.setContents(title, errorText) + notification.show() + } + + _unhandledErrorMonitor.onUnhandledError.subscribe(val => { + const errorText = val ? val.toString() : "Open the debugger for more details." + showError("Unhandled Exception", errorText + "\nPlease report this error.") + }) + + _unhandledErrorMonitor.onUnhandledRejection.subscribe(val => { + const errorText: string = val ? val.toString() : "Open the debugger for more details." + showError("Unhandled Rejection", errorText + "\nPlease report this error.") + }) +} diff --git a/browser/src/index.tsx b/browser/src/index.tsx index f069e951dd..bc6abf2c9c 100644 --- a/browser/src/index.tsx +++ b/browser/src/index.tsx @@ -16,6 +16,9 @@ import { IConfigurationValues } from "./Services/Configuration/IConfigurationVal const start = async (args: string[]): Promise => { Performance.startMeasure("Oni.Start") + const UnhandledErrorMonitor = await import("./Services/UnhandledErrorMonitor") + UnhandledErrorMonitor.activate() + const Shell = await import("./UI/Shell") Shell.activate() @@ -132,6 +135,8 @@ const start = async (args: string[]): Promise => { const Notifications = await notificationsPromise Notifications.activate(overlayManager) + UnhandledErrorMonitor.start(Notifications.getInstance()) + const Tasks = await taksPromise Tasks.activate(menuManager) const tasks = Tasks.getInstance() From 945cc5be138776f91a9a380fe750e37a09a8d656 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Fri, 9 Feb 2018 16:58:06 -0800 Subject: [PATCH 074/103] #1261 - Part 1 - Add checks in automation to fail if there are any errors reported in the log (#1491) * Add checks to fail if there are any errors reported in the log * Fix first round of key errors * Fix first round of React errors * Add allowLogFailures flag to NoInstalledNeovim test * Fix error in SignatureHelpView * Try moving react from external -> bundled to get production bits * Fix issue with react build * Add 'allowLogFailures' to the new ErrorBoundary test --- .../src/Editor/NeovimEditor/HoverRenderer.tsx | 4 +- browser/src/Services/Browser/index.tsx | 16 +++--- .../src/Services/Explorer/ExplorerView.tsx | 2 +- .../Services/Language/SignatureHelpView.tsx | 15 +++-- browser/src/Services/Menu/MenuComponent.tsx | 2 +- browser/src/UI/components/Error.tsx | 6 +- browser/src/UI/components/WindowSplits.tsx | 2 +- browser/webpack.debug.config.js | 57 +++++++++---------- package.json | 1 - test/ci/NoInstalledNeovim.ts | 1 + test/ci/WindowManager.ErrorBoundary.tsx | 4 ++ test/common/runInProcTest.ts | 9 ++- yarn.lock | 6 -- 13 files changed, 70 insertions(+), 55 deletions(-) diff --git a/browser/src/Editor/NeovimEditor/HoverRenderer.tsx b/browser/src/Editor/NeovimEditor/HoverRenderer.tsx index cf2bc4f048..a6de8c389b 100644 --- a/browser/src/Editor/NeovimEditor/HoverRenderer.tsx +++ b/browser/src/Editor/NeovimEditor/HoverRenderer.tsx @@ -123,7 +123,7 @@ const getErrorElements = (errors: types.Diagnostic[], style: any): JSX.Element[] if (!errors || !errors.length) { return Selectors.EmptyArray } else { - return [] + return [] } } @@ -169,7 +169,7 @@ const getQuickInfoElementsFromHover = (hover: types.Hover): JSX.Element => { return ( titleAndContents && ( - + {titleAndContents.description && ( diff --git a/browser/src/Services/Browser/index.tsx b/browser/src/Services/Browser/index.tsx index 90ff3ed3bf..f63f39ac4f 100644 --- a/browser/src/Services/Browser/index.tsx +++ b/browser/src/Services/Browser/index.tsx @@ -17,8 +17,6 @@ import { EditorManager } from "./../EditorManager" import { Icon, IconSize } from "./../../UI/Icon" -const WebView = require("react-electron-web-view") // tslint:disable-line - const Column = styled.div` pointer-events: auto; @@ -162,9 +160,8 @@ export class BrowserView extends React.PureComponent { - this._initializeElement(elem)} - src={this.props.url} +
this._initializeElement(elem)} style={{ position: "absolute", top: "0px", @@ -197,8 +194,13 @@ export class BrowserView extends React.PureComponent { } } - private _initializeElement(elem: any) { - this._webviewElement = elem + private _initializeElement(elem: HTMLElement) { + if (elem && !this._webviewElement) { + const webviewElement = document.createElement("webview") + elem.appendChild(webviewElement) + this._webviewElement = webviewElement + this._webviewElement.src = this.props.url + } } } diff --git a/browser/src/Services/Explorer/ExplorerView.tsx b/browser/src/Services/Explorer/ExplorerView.tsx index b87ce6781c..d952ea5376 100644 --- a/browser/src/Services/Explorer/ExplorerView.tsx +++ b/browser/src/Services/Explorer/ExplorerView.tsx @@ -125,7 +125,7 @@ export class ExplorerView extends React.PureComponent { onSelected={id => this.props.onClick(id)} render={(selectedId: string) => { const nodes = this.props.nodes.map(node => ( - this.props.onClick(node.id)}> + this.props.onClick(node.id)} key={node.id}> ) + elements.push() const argumentText = remainingSignatureString.substring( parameterIndex, parameterIndex + parameterLabel.length, ) + keyIndex++ if (i === signatureHelp.activeParameter) { - elements.push() + elements.push() } else { - elements.push() + elements.push() } remainingSignatureString = remainingSignatureString.substring( @@ -59,7 +62,11 @@ export const getElementsFromType = (signatureHelp: types.SignatureHelp): JSX.Ele elements.push() - const titleContents = [{elements}] + const titleContents = [ + + {elements} + , + ] const selectedIndex = Math.min(currentItem.parameters.length, signatureHelp.activeParameter) const selectedArgument = currentItem.parameters[selectedIndex] diff --git a/browser/src/Services/Menu/MenuComponent.tsx b/browser/src/Services/Menu/MenuComponent.tsx index df909cf5bc..f5bf58be83 100644 --- a/browser/src/Services/Menu/MenuComponent.tsx +++ b/browser/src/Services/Menu/MenuComponent.tsx @@ -61,7 +61,7 @@ export class MenuView extends React.PureComponent { const rowRenderer = (props: { key: string; index: number; style: React.CSSProperties }) => { const item = this.props.items[props.index] return ( -
+
{ } const errorIcon = ( -
+
) diff --git a/browser/src/UI/components/WindowSplits.tsx b/browser/src/UI/components/WindowSplits.tsx index 2a83053481..668b047706 100644 --- a/browser/src/UI/components/WindowSplits.tsx +++ b/browser/src/UI/components/WindowSplits.tsx @@ -39,7 +39,7 @@ export class Dock extends React.PureComponent { public render(): JSX.Element { const docks = this.props.splits.map((s, i) => { return ( -
+
{ export const settings = { configPath: "NoInstalledNeovim.config.js", + allowLogFailures: true, } diff --git a/test/ci/WindowManager.ErrorBoundary.tsx b/test/ci/WindowManager.ErrorBoundary.tsx index add7f16a88..57ddea0471 100644 --- a/test/ci/WindowManager.ErrorBoundary.tsx +++ b/test/ci/WindowManager.ErrorBoundary.tsx @@ -42,3 +42,7 @@ export const test = async (oni: Oni.Plugin.Api) => { const content = errorElement.textContent assert.ok(content.indexOf("Bad layer") >= 0) } + +export const settings = { + allowLogFailures: true, +} diff --git a/test/common/runInProcTest.ts b/test/common/runInProcTest.ts index cf0e89e2ea..2a7ebea00a 100644 --- a/test/common/runInProcTest.ts +++ b/test/common/runInProcTest.ts @@ -10,6 +10,7 @@ export interface ITestCase { name: string testPath: string configPath: string + allowLogFailures: boolean } export interface IFailedTest { @@ -31,6 +32,7 @@ const loadTest = (rootPath: string, testName: string): ITestCase => { name: testDescription.name || testName, testPath: normalizePath(testPath), configPath: getConfigPath(testMeta.settings, rootPath), + allowLogFailures: testDescription.allowLogFailures, } return normalizedMeta @@ -131,7 +133,12 @@ export const runInProcTest = ( console.log("Retrieving logs...") const writeLogs = (logs: any[]): void => { logs.forEach(log => { - console.log(`[${log.level}] ${log.message}`) + const logMessage = `[${log.level}] ${log.message}` + console.log(logMessage) + + if (log.level === "SEVERE" && !testCase.allowLogFailures) { + assert.ok(false, logMessage) + } }) } diff --git a/yarn.lock b/yarn.lock index 4a5e2d5c07..77c074519e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5307,12 +5307,6 @@ react-dom@16.0.0: object-assign "^4.1.1" prop-types "^15.6.0" -react-electron-web-view@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/react-electron-web-view/-/react-electron-web-view-2.0.1.tgz#984b7bbbeb77e35bcca921dc50120fc8f2b0f27d" - dependencies: - lodash.camelcase "^4.3.0" - react-hot-api@^0.4.5: version "0.4.7" resolved "https://registry.yarnpkg.com/react-hot-api/-/react-hot-api-0.4.7.tgz#a7e22a56d252e11abd9366b61264cf4492c58171" From 22d6e69a8216d9cb18d0f8ec54b28559f4e5cdc0 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Fri, 9 Feb 2018 19:10:54 -0800 Subject: [PATCH 075/103] Tweak CONTRIBUTING.md, adding some guidelines for PRs (#1495) * Tweak the contributing guidelines, adding in some implicit ideas/assumptions I had in mind for PRs * Additional tweaks * Fix typo * Fix typo --- CONTRIBUTING.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a52187bfd4..7c21a5d409 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,14 +18,17 @@ Working on your first Pull Request? You can learn how from this _free_ series, [ ## Submitting code -Any code change should be submitted as a pull request. The description should explain what the code does and give steps to execute it. The pull request should also contain tests. +Any code change should be submitted as a pull request. The description should explain what the code does and give steps to execute it. The pull request should also contain tests. We welcome and appreciate pull requests! -## Code review process +## Code review guidelines -The bigger the pull request, the longer it will take to review and merge. Try to break down large pull requests in smaller chunks that are easier to review and merge. -It is also always helpful to have some context for your pull request. What was the purpose? Why does it matter to you? +* Keep PRs **small and scoped**. The bigger the pull request, the longer it will take to review and merge. Break down large pull requests into smaller incremental chunks - this will help catch issues earlier and be easier on both you and the maintainer. +* Following from the previous bullet point, **do not include unrelated changes in a PR**. It can be tempting to include extra styling changes or additional functionality, but these should be added as separate PRs. +* Think of each PR as **improving the quality of the codebase**. Codebases tend towards entropy and disorder unless actively managed - make sure that your change moves the quality needle in the right direction. This can take a variety of forms, including adding test coverage, reducing coupling, etc. _As we are a small team moving fast, we cannot afford to accumulate technical debt._ +* If there is ambiguity in terms of design, architecture, or implementation, it's best to get **feedback before implementing**, to save both you and the maintainer time. If you're not sure, feel free to ask! +* For your first few PRs, **don't try and change the world** - pick some small issues and get familiar with the codebase. Then, work your way up to bigger issues - this will set you up for success. -A PR requires approval for either the maintainer, or a collaborator. +PRs require approval from one other person, either a maintainer or a contributor. Keep in mind that when you approve code, you are accountable for it, too! Reviewers are the gatekeepers of quality and ensuring adherence to the guidelines above. ## Financial contributions From ef344c1b37286253f62072be1302c29670f09177 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sat, 10 Feb 2018 08:58:23 -0800 Subject: [PATCH 076/103] Make search box clickable (#1496) --- browser/src/Services/Search/SearchTextBox.tsx | 5 ++++- browser/src/Services/Search/index.tsx | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/browser/src/Services/Search/SearchTextBox.tsx b/browser/src/Services/Search/SearchTextBox.tsx index b270b8e426..54059c3d80 100644 --- a/browser/src/Services/Search/SearchTextBox.tsx +++ b/browser/src/Services/Search/SearchTextBox.tsx @@ -18,6 +18,7 @@ export interface ISearchTextBoxProps { onDismiss: () => void onCommit: (newValue: string) => void onChangeText: (newValue: string) => void + onClick: () => void } const SearchBoxContainerWrapper = withProps(styled.div)` @@ -45,6 +46,8 @@ const SearchTextBoxWrapper = withProps(styled.div)` background-color: transparent; color: ${props => props.theme["editor.foreground"]} } + + cursor: text; ` export class SearchTextBox extends React.PureComponent { @@ -60,7 +63,7 @@ export class SearchTextBox extends React.PureComponent
{this.props.val}
) return ( - + {inner} ) diff --git a/browser/src/Services/Search/index.tsx b/browser/src/Services/Search/index.tsx index f6afc6e74d..f50101d8a9 100644 --- a/browser/src/Services/Search/index.tsx +++ b/browser/src/Services/Search/index.tsx @@ -149,7 +149,7 @@ export class SearchPaneView extends React.PureComponent< activeWorkspace: this.props.workspace.activeWorkspace, isActive: false, activeTextbox: null, - searchQuery: "Type to search...", + searchQuery: "Search...", fileFilter: null, } } @@ -215,6 +215,7 @@ export class SearchPaneView extends React.PureComponent< onDismiss={() => this._clearActiveTextbox()} isFocused={selectedId === "textbox.query"} isActive={this.state.activeTextbox === "textbox.query"} + onClick={() => this._onSelected("textbox.query")} /> {/* Date: Sat, 10 Feb 2018 17:09:14 +0000 Subject: [PATCH 077/103] Bugfix/add package json to prettierignore (#1497) * actually add the new file * add typescipt package json to prettier ignore --- .prettierignore | 2 ++ vim/core/oni-plugin-typescript/package.json | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .prettierignore diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..a2cc533bde --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +package.json +vim/core/oni-plugin-typescript/package.json diff --git a/vim/core/oni-plugin-typescript/package.json b/vim/core/oni-plugin-typescript/package.json index 0a24181e83..347095df6c 100644 --- a/vim/core/oni-plugin-typescript/package.json +++ b/vim/core/oni-plugin-typescript/package.json @@ -10,7 +10,10 @@ "test": "npm install && tsc -p tsconfig.test.json && mocha --recursive ./lib_test/test" }, "oni": { - "supportedFileTypes": ["javascript", "typescript"] + "supportedFileTypes": [ + "javascript", + "typescript" + ] }, "dependencies": {}, "devDependencies": { From d3a03f25328b1d70bc3df23fed1bc3ebe42fea30 Mon Sep 17 00:00:00 2001 From: Ryan C Date: Sat, 10 Feb 2018 17:43:41 +0000 Subject: [PATCH 078/103] Stop waiting for running Oni instance at end of install. (#1500) --- build/setup.template.iss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/setup.template.iss b/build/setup.template.iss index 303a143d4a..74cf4d7b9c 100644 --- a/build/setup.template.iss +++ b/build/setup.template.iss @@ -33,7 +33,7 @@ Name: "addToRightClickMenu"; Description: "Add {{AppName}} to the right click me Name: "{group}\{{AppName}}"; Filename: "{app}\{{AppExecutableName}}" [Run] -Filename: "{app}\{{AppName}}"; Flags: postinstall skipifsilent +Filename: "{app}\{{AppName}}"; Flags: postinstall skipifsilent nowait [Code] function NeedsAddPath(Param: string): boolean; From 0a943a643654973db6d59e9812a9f35283970152 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sat, 10 Feb 2018 11:10:31 -0800 Subject: [PATCH 079/103] Add a null check before calling 'handleInput' on buffer, as there may be cases where a buffer is not available yet (#1501) --- browser/src/Editor/NeovimEditor/NeovimEditor.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx index 534f6431a4..abfd80351a 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx @@ -794,7 +794,7 @@ export class NeovimEditor extends Editor implements IEditor { // Check if any of the buffer layers can handle the input... const buf: IBuffer = this.activeBuffer as IBuffer - const result = buf.handleInput(key) + const result = buf && buf.handleInput(key) if (result) { return From 7db752a68c2e4da4cc1220d69bb673770b069f06 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sat, 10 Feb 2018 12:03:19 -0800 Subject: [PATCH 080/103] Notifications: Add configuration setting to enable / disable (#1504) * Wire up configuration settings * Add setting for notifications --- .../Configuration/DefaultConfiguration.ts | 2 ++ .../Configuration/IConfigurationValues.ts | 2 ++ .../Services/Notifications/Notifications.ts | 7 +++++++ browser/src/Services/Notifications/index.ts | 19 ++++++++++++++++++- browser/src/index.tsx | 2 +- test/demo/HeroScreenshot.ts | 6 ++++++ 6 files changed, 36 insertions(+), 2 deletions(-) diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index f15e98d413..fce1dcb221 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -250,6 +250,8 @@ const BaseConfiguration: IConfigurationValues = { "menu.rowHeight": 40, "menu.maxItemsToShow": 8, + "notifications.enabled": true, + "recorder.copyScreenshotToClipboard": false, "recorder.outputPath": os.tmpdir(), diff --git a/browser/src/Services/Configuration/IConfigurationValues.ts b/browser/src/Services/Configuration/IConfigurationValues.ts index fd4c549378..e22da124e0 100644 --- a/browser/src/Services/Configuration/IConfigurationValues.ts +++ b/browser/src/Services/Configuration/IConfigurationValues.ts @@ -193,6 +193,8 @@ export interface IConfigurationValues { "menu.rowHeight": number "menu.maxItemsToShow": number + "notifications.enabled": boolean + // Output path to save screenshots and recordings "recorder.outputPath": string diff --git a/browser/src/Services/Notifications/Notifications.ts b/browser/src/Services/Notifications/Notifications.ts index 370cb57819..9ad8b8f5b0 100644 --- a/browser/src/Services/Notifications/Notifications.ts +++ b/browser/src/Services/Notifications/Notifications.ts @@ -23,9 +23,16 @@ export class Notifications { this._overlay = this._overlayManager.createItem() this._overlay.setContents(getView(this._store)) + } + + public enable(): void { this._overlay.show() } + public disable(): void { + this._overlay.hide() + } + public createItem(): Notification { this._id++ diff --git a/browser/src/Services/Notifications/index.ts b/browser/src/Services/Notifications/index.ts index 3bb3ad11d0..e6b769ebae 100644 --- a/browser/src/Services/Notifications/index.ts +++ b/browser/src/Services/Notifications/index.ts @@ -2,16 +2,33 @@ * index.ts */ +import * as Log from "./../../Log" + import { OverlayManager } from "./../Overlay" +import { Configuration } from "./../Configuration" import { Notifications } from "./Notifications" export * from "./Notifications" let _notifications: Notifications = null -export const activate = (overlayManager: OverlayManager): void => { +export const activate = (configuration: Configuration, overlayManager: OverlayManager): void => { _notifications = new Notifications(overlayManager) + + const updateFromConfiguration = () => { + const areNotificationsEnabled = configuration.getValue("notifications.enabled") + Log.info("[Notifications] Setting enabled: " + areNotificationsEnabled) + areNotificationsEnabled ? _notifications.enable() : _notifications.disable() + } + + configuration.onConfigurationChanged.subscribe(val => { + if (typeof val["notifications.enabled"] === "boolean") { + updateFromConfiguration() + } + }) + + updateFromConfiguration() } export const getInstance = (): Notifications => { diff --git a/browser/src/index.tsx b/browser/src/index.tsx index bc6abf2c9c..1ce7bdc66c 100644 --- a/browser/src/index.tsx +++ b/browser/src/index.tsx @@ -133,7 +133,7 @@ const start = async (args: string[]): Promise => { const menuManager = Menu.getInstance() const Notifications = await notificationsPromise - Notifications.activate(overlayManager) + Notifications.activate(configuration, overlayManager) UnhandledErrorMonitor.start(Notifications.getInstance()) diff --git a/test/demo/HeroScreenshot.ts b/test/demo/HeroScreenshot.ts index 0b64343a57..643e2fdfab 100644 --- a/test/demo/HeroScreenshot.ts +++ b/test/demo/HeroScreenshot.ts @@ -80,3 +80,9 @@ export const test = async (oni: any) => { await oni.automation.waitFor(() => lastAlertText !== null, 20000) console.log("Alert text (screenshot output path): " + lastAlertText) } + +export const settings = { + config: { + "notifications.enabled": false, + }, +} From 5db8ffe8ec08df573c364df87d5a17f92364e1fa Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sat, 10 Feb 2018 12:30:38 -0800 Subject: [PATCH 081/103] Syntax Highlight - Part 1 - Extract tokenColors into theme + merge with user config (#1484) * Add TokenColors service * Plumb through token colors as dependency * Fix up issue where the token color event wasn't firing * Fix lint issues * Resolve colors to hex * Start stubbing out a test case for TokenColorsTests * Fix typing * Factor MockThemeLoader to separate file * Bring in bold/italic from nvim_get_hl_by_name * Remove TODO --- .../src/Editor/NeovimEditor/NeovimEditor.tsx | 6 ++ browser/src/Editor/OniEditor/OniEditor.tsx | 3 + browser/src/Plugins/Api/Oni.ts | 5 ++ browser/src/Services/Themes/ThemeManager.ts | 23 ++--- browser/src/Services/Themes/index.ts | 1 + browser/src/Services/TokenColors.ts | 90 +++++++++++++++++++ browser/src/index.tsx | 5 ++ browser/src/neovim/NeovimInstance.ts | 37 +++++++- browser/src/neovim/VimHighlights.ts | 61 +++++++++++++ browser/src/startEditors.ts | 3 + browser/test/Mocks/MockThemeLoader.ts | 28 ++++++ browser/test/Mocks/index.ts | 11 +++ browser/test/Services/TokenColorsTests.ts | 55 ++++++++++++ 13 files changed, 310 insertions(+), 18 deletions(-) create mode 100644 browser/src/Services/TokenColors.ts create mode 100644 browser/src/neovim/VimHighlights.ts create mode 100644 browser/test/Mocks/MockThemeLoader.ts create mode 100644 browser/test/Services/TokenColorsTests.ts diff --git a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx index abfd80351a..04cab165ed 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx @@ -44,6 +44,8 @@ import { Configuration, IConfigurationValues } from "./../../Services/Configurat import { IDiagnosticsDataSource } from "./../../Services/Diagnostics" import { Errors } from "./../../Services/Errors" import { Overlay, OverlayManager } from "./../../Services/Overlay" +import { TokenColors } from "./../../Services/TokenColors" + import * as Shell from "./../../UI/Shell" import { @@ -165,6 +167,7 @@ export class NeovimEditor extends Editor implements IEditor { private _pluginManager: PluginManager, private _tasks: Tasks, private _themeManager: ThemeManager, + private _tokenColors: TokenColors, private _workspace: Workspace, ) { super() @@ -952,6 +955,9 @@ export class NeovimEditor extends Editor implements IEditor { this._themeManager.notifyVimThemeChanged(newColorScheme, backgroundColor, foregroundColor) + const tokenColors = await this._neovimInstance.getTokenColors() + this._tokenColors.setDefaultTokenColors(tokenColors) + // Flip first render to force a full redraw this._isFirstRender = true this._scheduleRender() diff --git a/browser/src/Editor/OniEditor/OniEditor.tsx b/browser/src/Editor/OniEditor/OniEditor.tsx index 59a6844e5b..b7b6f569e7 100644 --- a/browser/src/Editor/OniEditor/OniEditor.tsx +++ b/browser/src/Editor/OniEditor/OniEditor.tsx @@ -31,6 +31,7 @@ import { ISyntaxHighlighter } from "./../../Services/SyntaxHighlighting" import { Tasks } from "./../../Services/Tasks" import { ThemeManager } from "./../../Services/Themes" +import { TokenColors } from "./../../Services/TokenColors" import { Workspace } from "./../../Services/Workspace" import { IEditor } from "./../Editor" @@ -108,6 +109,7 @@ export class OniEditor implements IEditor { pluginManager: PluginManager, tasks: Tasks, themeManager: ThemeManager, + tokenColors: TokenColors, workspace: Workspace, ) { this._neovimEditor = new NeovimEditor( @@ -121,6 +123,7 @@ export class OniEditor implements IEditor { pluginManager, tasks, themeManager, + tokenColors, workspace, ) diff --git a/browser/src/Plugins/Api/Oni.ts b/browser/src/Plugins/Api/Oni.ts index 2011b3ebfd..9d9176b3fd 100644 --- a/browser/src/Plugins/Api/Oni.ts +++ b/browser/src/Plugins/Api/Oni.ts @@ -32,6 +32,7 @@ import { recorder } from "./../../Services/Recorder" import { getInstance as getSidebarInstance } from "./../../Services/Sidebar" import { getInstance as getSnippetsInstance } from "./../../Services/Snippets" import { getInstance as getStatusBarInstance } from "./../../Services/StatusBar" +import { getInstance as getTokenColorsInstance } from "./../../Services/TokenColors" import { windowManager } from "./../../Services/WindowManager" import { getInstance as getWorkspaceInstance } from "./../../Services/Workspace" @@ -144,6 +145,10 @@ export class Oni extends EventEmitter implements OniApi.Plugin.Api { return getStatusBarInstance() } + public get tokenColors(): any { + return getTokenColorsInstance() + } + public get ui(): Ui { return this._ui } diff --git a/browser/src/Services/Themes/ThemeManager.ts b/browser/src/Services/Themes/ThemeManager.ts index 810c7539eb..f5fbb1952f 100644 --- a/browser/src/Services/Themes/ThemeManager.ts +++ b/browser/src/Services/Themes/ThemeManager.ts @@ -12,6 +12,7 @@ import { PluginManager } from "./../../Plugins/PluginManager" import { Configuration, configuration, GenericConfigurationValues } from "./../Configuration" import * as PersistentSettings from "./../Configuration/PersistentSettings" +import { TokenColor } from "./../TokenColors" import { IThemeLoader, PluginThemeLoader } from "./ThemeLoader" export interface IThemeColors { @@ -271,32 +272,18 @@ export const DefaultThemeColors: IThemeColors = { "fileExplorer.cursor.foreground": NormalMode, } -// export interface ITokenTheme { -// name: string -// scope: string[] -// settings: ITokenColorSettings -// } - -// export interface ITokenColorSettings { -// background?: string -// foreground?: string - -// bold: boolean -// italic: boolean -// } - export interface IThemeMetadata { name: string baseVimTheme?: string colors: Partial - // tokenColors: ITokenTheme[] + tokenColors: TokenColor[] } export const DefaultTheme: IThemeMetadata = { name: "default", baseVimTheme: "default", colors: DefaultThemeColors, - // tokenColors: [], + tokenColors: [], } export class ThemeManager { @@ -333,10 +320,11 @@ export class ThemeManager { // that. this._isAnonymousTheme = true - const temporaryVimTheme = { + const temporaryVimTheme: IThemeMetadata = { name, baseVimTheme: name, colors: DefaultThemeColors, + tokenColors: [], } this._updateTheme(temporaryVimTheme) @@ -364,6 +352,7 @@ export class ThemeManager { name: vimName, baseVimTheme: vimName, colors: getColorsFromBackgroundAndForeground(backgroundColor, foregroundColor), + tokenColors: [], } this._updateTheme(vimTheme) diff --git a/browser/src/Services/Themes/index.ts b/browser/src/Services/Themes/index.ts index 4cd0d69386..187aa44c4a 100644 --- a/browser/src/Services/Themes/index.ts +++ b/browser/src/Services/Themes/index.ts @@ -1,3 +1,4 @@ +export * from "./ThemeLoader" export * from "./ThemeManager" import { PluginManager } from "./../../Plugins/PluginManager" diff --git a/browser/src/Services/TokenColors.ts b/browser/src/Services/TokenColors.ts new file mode 100644 index 0000000000..951010dcf7 --- /dev/null +++ b/browser/src/Services/TokenColors.ts @@ -0,0 +1,90 @@ +/** + * TokenColors + * + * - Rationalizes colors from both the active theme and configuration + * - The 'source of truth' for tokenColors in Oni + * - Also will handle 'fallback logic' for tokenColors + */ + +import { Event, IDisposable, IEvent } from "oni-types" + +export interface TokenColor { + scope: string + settings: TokenColorStyle +} + +export interface TokenColorStyle { + foregroundColor: string + backgroundColor: string + + bold: boolean + italic: boolean +} + +import { Configuration, IConfigurationValues } from "./Configuration" +import { ThemeManager } from "./Themes" + +export class TokenColors implements IDisposable { + private _subscriptions: IDisposable[] = [] + private _tokenColors: TokenColor[] = [] + private _onTokenColorsChangedEvent: Event = new Event() + + private _defaultTokenColors: TokenColor[] = [] + + public get tokenColors(): TokenColor[] { + return this._tokenColors + } + + public get onTokenColorsChanged(): IEvent { + return this._onTokenColorsChangedEvent + } + + constructor(private _configuration: Configuration, private _themeManager: ThemeManager) { + const sub1 = this._themeManager.onThemeChanged.subscribe(() => { + this._updateTokenColors() + }) + + const sub2 = this._configuration.onConfigurationChanged.subscribe( + (newValues: Partial) => { + if (newValues["editor.tokenColors"]) { + this._updateTokenColors() + } + }, + ) + + this._subscriptions = [sub1, sub2] + } + + public setDefaultTokenColors(tokenColors: TokenColor[]): void { + this._defaultTokenColors = tokenColors || [] + this._updateTokenColors() + } + + public dispose(): void { + this._subscriptions.forEach(s => s.dispose()) + this._subscriptions = [] + } + + private _updateTokenColors(): void { + const tokenColorsFromTheme = this._themeManager.activeTheme + ? this._themeManager.activeTheme.tokenColors + : [] + const userColors = this._configuration.getValue("editor.tokenColors") + this._tokenColors = [ + ...(userColors || []), + ...(tokenColorsFromTheme || []), + ...this._defaultTokenColors, + ] + + this._onTokenColorsChangedEvent.dispatch() + } +} + +let _tokenColors: TokenColors +export const activate = (configuration: Configuration, themeManager: ThemeManager) => { + _tokenColors = new TokenColors(configuration, themeManager) +} + +export const getInstance = () => { + return _tokenColors +} diff --git a/browser/src/index.tsx b/browser/src/index.tsx index 1ce7bdc66c..e5bd73e0de 100644 --- a/browser/src/index.tsx +++ b/browser/src/index.tsx @@ -37,6 +37,7 @@ const start = async (args: string[]): Promise => { const sharedNeovimInstancePromise = import("./neovim/SharedNeovimInstance") const browserWindowConfigurationSynchronizerPromise = import("./Services/BrowserWindowConfigurationSynchronizer") const colorsPromise = import("./Services/Colors") + const tokenColorsPromise = import("./Services/TokenColors") const diagnosticsPromise = import("./Services/Diagnostics") const editorManagerPromise = import("./Services/EditorManager") const globalCommandsPromise = import("./Services/Commands/GlobalCommands") @@ -106,6 +107,9 @@ const start = async (args: string[]): Promise => { Shell.initializeColors(Colors.getInstance()) Performance.endMeasure("Oni.Start.Themes") + const TokenColors = await tokenColorsPromise + TokenColors.activate(configuration, Themes.getThemeManagerInstance()) + const BrowserWindowConfigurationSynchronizer = await browserWindowConfigurationSynchronizerPromise BrowserWindowConfigurationSynchronizer.activate(configuration, Colors.getInstance()) @@ -173,6 +177,7 @@ const start = async (args: string[]): Promise => { pluginManager, tasks, Themes.getThemeManagerInstance(), + TokenColors.getInstance(), workspace, ) diff --git a/browser/src/neovim/NeovimInstance.ts b/browser/src/neovim/NeovimInstance.ts index 194b6a066b..1d072ab8e2 100644 --- a/browser/src/neovim/NeovimInstance.ts +++ b/browser/src/neovim/NeovimInstance.ts @@ -23,9 +23,15 @@ import { IQuickFixList, QuickFixList } from "./QuickFix" import { IPixelPosition, IPosition } from "./Screen" import { Session } from "./Session" +import { PromiseQueue } from "./../Services/Language/PromiseQueue" +import { TokenColor } from "./../Services/TokenColors" import { INeovimBufferUpdate, NeovimBufferUpdateManager } from "./NeovimBufferUpdateManager" -import { PromiseQueue } from "./../Services/Language/PromiseQueue" +import { + IVimHighlight, + VimHighlightToDefaultScope, + vimHighlightToTokenColorStyle, +} from "./VimHighlights" export interface INeovimYankInfo { operator: string @@ -459,6 +465,35 @@ export class NeovimInstance extends EventEmitter implements INeovimInstance { return this._initPromise } + public async getTokenColors(): Promise { + const vimHighlights = Object.keys(VimHighlightToDefaultScope) + const atomicCalls = vimHighlights.map(highlight => { + return ["nvim_get_hl_by_name", [highlight, 1]] + }) + + const [highlightInfo] = await this._neovim.request<[IVimHighlight[]]>("nvim_call_atomic", [ + atomicCalls, + ]) + + const ret = highlightInfo.reduce( + (prev: TokenColor[], currentValue: IVimHighlight, currentIndex: number) => { + const highlightGroupName = vimHighlights[currentIndex] + const settings = vimHighlightToTokenColorStyle(currentValue) + const newScopeNames: string[] = VimHighlightToDefaultScope[highlightGroupName] || [] + + const newScopes = newScopeNames.map((scope): TokenColor => ({ + scope, + settings, + })) + + return [...prev, ...newScopes] + }, + [] as TokenColor[], + ) + + return ret + } + public setFont(fontFamily: string, fontSize: string, linePadding: number): void { this._fontFamily = fontFamily this._fontSize = fontSize diff --git a/browser/src/neovim/VimHighlights.ts b/browser/src/neovim/VimHighlights.ts new file mode 100644 index 0000000000..5921eeb8e3 --- /dev/null +++ b/browser/src/neovim/VimHighlights.ts @@ -0,0 +1,61 @@ +/** + * VimHighlights + * + * Mapping of Vim highlight groups to default scopes + */ + +import * as Color from "color" + +import { TokenColorStyle } from "./../Services/TokenColors" + +export interface IVimHighlight { + foreground: string + background: string + bold: boolean + italic: boolean +} + +export const vimHighlightToTokenColorStyle = (highlight: IVimHighlight): TokenColorStyle => { + return { + foregroundColor: Color(highlight.foreground).hex(), + backgroundColor: Color(highlight.background).hex(), + bold: highlight.bold, + italic: highlight.italic, + } +} + +export const VimHighlightToDefaultScope = { + Identifier: [ + "support.variable", + "support.variable.property.dom", + "variable.language", + "variable.parameter", + "variable.object", + "meta.object.type", + "meta.object", + ], + Function: [ + "support.function", + "entity.name", + "entity.name.type.enum", + "entity.name.type.interface", + "meta.function.call", + "meta.function", + "punctuation.accessor", + "punctuation.separator.continuation", + "punctuation.separator.comma", + "punctuation.terminator", + "punctuation.terminator", + ], + Constant: [ + "storage.type.interface", + "storage.type.enum", + "storage.type.interface", + "entity.other", + "keyword.control.import", + "keyword.control", + "variable.other.constant", + "variable.other.object", + "variable.other.property", + ], +} diff --git a/browser/src/startEditors.ts b/browser/src/startEditors.ts index 23f625bc8c..be727c55d4 100644 --- a/browser/src/startEditors.ts +++ b/browser/src/startEditors.ts @@ -18,6 +18,7 @@ import { MenuManager } from "./Services/Menu" import { OverlayManager } from "./Services/Overlay" import { Tasks } from "./Services/Tasks" import { ThemeManager } from "./Services/Themes" +import { TokenColors } from "./Services/TokenColors" import { windowManager } from "./Services/WindowManager" import { Workspace } from "./Services/Workspace" @@ -33,6 +34,7 @@ export const startEditors = async ( pluginManager: PluginManager, tasks: Tasks, themeManager: ThemeManager, + tokenColors: TokenColors, workspace: Workspace, ): Promise => { const editor = new OniEditor( @@ -46,6 +48,7 @@ export const startEditors = async ( pluginManager, tasks, themeManager, + tokenColors, workspace, ) editorManager.setActiveEditor(editor) diff --git a/browser/test/Mocks/MockThemeLoader.ts b/browser/test/Mocks/MockThemeLoader.ts new file mode 100644 index 0000000000..32845de679 --- /dev/null +++ b/browser/test/Mocks/MockThemeLoader.ts @@ -0,0 +1,28 @@ +/** + * Mocks/MockThemeLoader.ts + */ + +import { IThemeContribution } from "./../../src/Plugins/Api/Capabilities" +import { IThemeLoader, IThemeMetadata } from "./../../src/Services/Themes" + +export class MockThemeLoader implements IThemeLoader { + private _nameToTheme: { [key: string]: IThemeMetadata } = {} + + public getAllThemes(): Promise { + const themeContributions = Object.keys(this._nameToTheme).map( + (name): IThemeContribution => ({ + name, + path: null, + }), + ) + return Promise.resolve(themeContributions) + } + + public getThemeByName(name: string): Promise { + return Promise.resolve(this._nameToTheme[name]) + } + + public addTheme(name: string, theme: IThemeMetadata): void { + this._nameToTheme[name] = theme + } +} diff --git a/browser/test/Mocks/index.ts b/browser/test/Mocks/index.ts index 3a462c5b9d..a20ce8ca0a 100644 --- a/browser/test/Mocks/index.ts +++ b/browser/test/Mocks/index.ts @@ -5,6 +5,8 @@ * to exercise boundaries of class implementations */ +export * from "./MockThemeLoader" + import * as Oni from "oni-api" import { Event, IEvent } from "oni-types" @@ -21,6 +23,11 @@ import { IWorkspace } from "./../../src/Services/Workspace" export class MockConfiguration { private _currentConfigurationFiles: string[] = [] + private _onConfigurationChanged = new Event() + + public get onConfigurationChanged(): IEvent { + return this._onConfigurationChanged + } public get currentConfigurationFiles(): string[] { return this._currentConfigurationFiles @@ -45,6 +52,10 @@ export class MockConfiguration { fp => fp !== filePath, ) } + + public simulateConfigurationChangedEvent(changedConfigurationValues: any): void { + this._onConfigurationChanged.dispatch(changedConfigurationValues) + } } export class MockWorkspace implements IWorkspace { diff --git a/browser/test/Services/TokenColorsTests.ts b/browser/test/Services/TokenColorsTests.ts new file mode 100644 index 0000000000..f48fdff5fe --- /dev/null +++ b/browser/test/Services/TokenColorsTests.ts @@ -0,0 +1,55 @@ +/** + * TokenColorsTest + */ + +import * as assert from "assert" + +import { TokenColors } from "./../../src/Services/TokenColors" + +import { MockConfiguration, MockThemeLoader } from "./../Mocks" + +import { DefaultTheme, ThemeManager } from "./../../src/Services/Themes" + +describe("TokenColors", () => { + let mockConfiguration: MockConfiguration + let themeLoader: MockThemeLoader + let themeManager: ThemeManager + + beforeEach(() => { + mockConfiguration = new MockConfiguration() + themeLoader = new MockThemeLoader() + themeManager = new ThemeManager(themeLoader) + themeLoader.addTheme("testTheme", DefaultTheme) + }) + + it("setting theme triggers onTokenColorsChanged event", async () => { + const tokenColors = new TokenColors(mockConfiguration as any, themeManager) + + let hitCount = 0 + tokenColors.onTokenColorsChanged.subscribe(() => hitCount++) + + await themeManager.setTheme("testTheme") + + assert.strictEqual(hitCount, 1, "Validate onTokenColorsChanged was fired") + }) + + it("if configuration is updated, but 'editor.tokenColors' isn't there, onTokenColorsChanged should not be triggered", () => { + const tokenColors = new TokenColors(mockConfiguration as any, themeManager) + + let hitCount = 0 + tokenColors.onTokenColorsChanged.subscribe(() => hitCount++) + + mockConfiguration.simulateConfigurationChangedEvent({ someConfigValue: 2 }) + assert.strictEqual(hitCount, 0, "Validate onTokenColorsChanged was fired") + }) + + it("if 'editor.tokenColors' is updated from the config, onTokenColorsChanged event should be triggered", () => { + const tokenColors = new TokenColors(mockConfiguration as any, themeManager) + + let hitCount = 0 + tokenColors.onTokenColorsChanged.subscribe(() => hitCount++) + + mockConfiguration.simulateConfigurationChangedEvent({ "editor.tokenColors": [] }) + assert.strictEqual(hitCount, 1, "Validate onTokenColorsChanged was fired") + }) +}) From c82755a0df699cbba6833c867d046c824f64f0b4 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sat, 10 Feb 2018 13:29:50 -0800 Subject: [PATCH 082/103] Bug Fix: Notifications - cancel button doesn't do anything (#1503) * Fix cancel button behavior, and add some styling tweaks to make it a bit more obvious that it is a button * Fix lint issues --- .../Notifications/NotificationsView.tsx | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/browser/src/Services/Notifications/NotificationsView.tsx b/browser/src/Services/Notifications/NotificationsView.tsx index fb696c09e0..de82a8f0bc 100644 --- a/browser/src/Services/Notifications/NotificationsView.tsx +++ b/browser/src/Services/Notifications/NotificationsView.tsx @@ -14,6 +14,7 @@ import { CSSTransition, TransitionGroup } from "react-transition-group" import { INotification, INotificationsState } from "./NotificationStore" +import { boxShadow } from "./../../UI/components/common" import { Icon, IconSize } from "./../../UI/Icon" export interface NotificationsViewProps { @@ -74,6 +75,7 @@ const NotificationWrapper = styled.div` cursor: pointer; overflow: hidden; + transition: all 0.1s ease-in; &.notification-enter { animation: ${frames} 0.25s ease-in; @@ -84,6 +86,7 @@ const NotificationWrapper = styled.div` } &:hover { + ${boxShadow}; transform: translateY(-1px); } ` @@ -91,7 +94,12 @@ const NotificationWrapper = styled.div` const NotificationIconWrapper = styled.div` flex: 0 0 auto; - margin: 8px; + padding: 16px; + + &:hover { + ${boxShadow}; + transform: translateY(-1px); + } ` const NotificationContents = styled.div` @@ -101,6 +109,8 @@ const NotificationContents = styled.div` flex-direction: column; justify-content: center; + padding: 8px; + overflow-y: auto; overflow-x: hidden; height: 100%; @@ -138,12 +148,18 @@ export class NotificationView extends React.PureComponent { {this.props.title} {this.props.detail} - this.props.onClose}> + this._onClickClose(evt)}> ) } + + private _onClickClose(evt: React.MouseEvent): void { + this.props.onClose() + evt.stopPropagation() + evt.preventDefault() + } } export const mapStateToProps = (state: INotificationsState): NotificationsViewProps => { From 6274d251cfb361b692e74f4657b2a39680cf84d0 Mon Sep 17 00:00:00 2001 From: Akin Date: Sat, 10 Feb 2018 21:40:27 +0000 Subject: [PATCH 083/103] Bugfix/on focus split error (#1499) * await setting items as it is async in vimnavigator * add temporary fix in file explorer to pass window id * Remove SharedNeovimInstance initPromise and simply await the neovim instance starting it causes a bizarre race condition where set items could otherwise be called before the instance is initialized * add new check to see if neovim is initialized before setting items --- browser/src/Services/Explorer/ExplorerSplit.tsx | 4 +++- browser/src/Services/Sidebar/SidebarPane/SidebarPane.tsx | 4 ++-- browser/src/UI/components/VimNavigator.tsx | 6 +++--- browser/src/neovim/NeovimInstance.ts | 2 +- browser/src/neovim/SharedNeovimInstance.ts | 8 ++++---- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/browser/src/Services/Explorer/ExplorerSplit.tsx b/browser/src/Services/Explorer/ExplorerSplit.tsx index c44b2d173b..b673058e4c 100644 --- a/browser/src/Services/Explorer/ExplorerSplit.tsx +++ b/browser/src/Services/Explorer/ExplorerSplit.tsx @@ -108,7 +108,9 @@ export class ExplorerSplit { switch (selectedItem.type) { case "file": this._editorManager.activeEditor.openFile(selectedItem.filePath) - windowManager.focusSplit(this._editorManager.activeEditor as any) + // FIXME: the editor manager is not a windowSplit aka this + // Should be being called with an ID not an active editor + windowManager.focusSplit("oni.window.0") return case "folder": const isDirectoryExpanded = ExplorerSelectors.isPathExpanded( diff --git a/browser/src/Services/Sidebar/SidebarPane/SidebarPane.tsx b/browser/src/Services/Sidebar/SidebarPane/SidebarPane.tsx index 8a7c1533ad..776567c5fa 100644 --- a/browser/src/Services/Sidebar/SidebarPane/SidebarPane.tsx +++ b/browser/src/Services/Sidebar/SidebarPane/SidebarPane.tsx @@ -35,13 +35,13 @@ export class SidebarPane { ) } - public enter(): void { + public async enter(): Promise { this._menuBinding = getInstance().bindToMenu() const widgets = this._store.getState().widgets const ids = flatMap(widgets, w => w.ids) - this._menuBinding.setItems(ids) + await this._menuBinding.setItems(ids) this._menuBinding.onCursorMoved.subscribe((id: string) => { this._store.dispatch({ diff --git a/browser/src/UI/components/VimNavigator.tsx b/browser/src/UI/components/VimNavigator.tsx index 3fc967f438..7cc3d17409 100644 --- a/browser/src/UI/components/VimNavigator.tsx +++ b/browser/src/UI/components/VimNavigator.tsx @@ -110,7 +110,7 @@ export class VimNavigator extends React.PureComponent { + public async start(startOptions?: INeovimStartOptions): Promise { Performance.startMeasure("NeovimInstance.Start") this._initPromise = startNeovim(startOptions).then(nv => { Log.info("NeovimInstance: Neovim started") diff --git a/browser/src/neovim/SharedNeovimInstance.ts b/browser/src/neovim/SharedNeovimInstance.ts index 38c8a9a081..f026447c3a 100644 --- a/browser/src/neovim/SharedNeovimInstance.ts +++ b/browser/src/neovim/SharedNeovimInstance.ts @@ -103,6 +103,9 @@ export class MenuBinding extends Binding implements IMenuBinding { this._currentOptions = items this._currentId = activeId + if (!this.neovimInstance.isInitialized) { + return + } const currentWinId = await this.neovimInstance.request("nvim_get_current_win", []) const currentBufId = await this.neovimInstance.eval("bufnr('%')") const bufferLength = await this.neovimInstance.eval("line('$')") @@ -132,7 +135,6 @@ export class MenuBinding extends Binding implements IMenuBinding { } class SharedNeovimInstance implements SharedNeovimInstance { - private _initPromise: Promise private _neovimInstance: NeovimInstance public get isInitialized(): boolean { @@ -158,10 +160,8 @@ class SharedNeovimInstance implements SharedNeovimInstance { useDefaultConfig: true, } - this._initPromise = this._neovimInstance.start(startOptions) - Log.info("[SharedNeovimInstance::start] Starting...") - await this._initPromise + await this._neovimInstance.start(startOptions) Log.info("[SharedNeovimInstance::start] Started successfully!") } } From 322ae699b66dc323df39ab43f0ab47ec47c2a013 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sat, 10 Feb 2018 14:13:18 -0800 Subject: [PATCH 084/103] Add test case for toggling the sidebar split (#1508) --- .../Services/Sidebar/SidebarContentSplit.tsx | 2 +- test/CiTests.ts | 1 + test/ci/Sidebar.ToggleSplitTest.ts | 29 +++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 test/ci/Sidebar.ToggleSplitTest.ts diff --git a/browser/src/Services/Sidebar/SidebarContentSplit.tsx b/browser/src/Services/Sidebar/SidebarContentSplit.tsx index 40e2d57003..2445f74646 100644 --- a/browser/src/Services/Sidebar/SidebarContentSplit.tsx +++ b/browser/src/Services/Sidebar/SidebarContentSplit.tsx @@ -172,7 +172,7 @@ export class SidebarContentView extends React.PureComponent< const header = activeEntry && activeEntry.pane ? activeEntry.pane.title : null return ( - + {activeEntry.pane.render()} diff --git a/test/CiTests.ts b/test/CiTests.ts index 25268ebeaf..b69887ca26 100644 --- a/test/CiTests.ts +++ b/test/CiTests.ts @@ -24,6 +24,7 @@ const CiTests = [ "QuickOpenTest", "StatusBar-Mode", "NoInstalledNeovim", + "Sidebar.ToggleSplitTest", "WindowManager.ErrorBoundary", "Workspace.ConfigurationTest", diff --git a/test/ci/Sidebar.ToggleSplitTest.ts b/test/ci/Sidebar.ToggleSplitTest.ts new file mode 100644 index 0000000000..6fdd58f27c --- /dev/null +++ b/test/ci/Sidebar.ToggleSplitTest.ts @@ -0,0 +1,29 @@ +/** + * Test script to validate sidebar split toggle behavior + */ + +import * as assert from "assert" + +import * as Oni from "oni-api" + +const getSidebarSplit = () => { + return document.querySelectorAll(".sidebar-content") +} + +export const test = async (oni: Oni.Plugin.Api) => { + await oni.automation.waitForEditors() + + // Wait for sidebar split to appear + await oni.automation.waitFor(() => getSidebarSplit().length === 1) + + // Validate sidebar is hidden + oni.commands.executeCommand("sidebar.toggle") + await oni.automation.waitFor(() => getSidebarSplit().length === 0) + assert.ok(true, "Sidebar was hidden.") + + // Validate sidebar comes back + oni.commands.executeCommand("sidebar.toggle") + await oni.automation.waitFor(() => getSidebarSplit().length === 1) + + assert.ok(true, "Sidebar came back.") +} From 046541851999a07f23d4fc69cb7d26e5880d6d45 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sat, 10 Feb 2018 14:14:37 -0800 Subject: [PATCH 085/103] Automation - report running processes on test start (#1505) --- package.json | 87 +++++++++++++++++++----------------- test/common/runInProcTest.ts | 16 +++++++ yarn.lock | 8 ++++ 3 files changed, 69 insertions(+), 42 deletions(-) diff --git a/package.json b/package.json index 6de08ea9ef..fe97e88897 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,14 @@ "homepage": "https://www.onivim.io", "version": "0.2.22", "description": "NeoVim front-end with IDE-style extensibility", - "keywords": ["vim", "neovim", "text", "editor", "ide", "vim"], + "keywords": [ + "vim", + "neovim", + "text", + "editor", + "ide", + "vim" + ], "main": "./lib/main/src/main.js", "bin": { "oni": "./cli/oni", @@ -38,17 +45,30 @@ "mac": { "artifactName": "${productName}-${version}-osx.${ext}", "category": "public.app-category.developer-tools", - "target": ["dmg"], - "files": ["bin/osx/**/*"] + "target": [ + "dmg" + ], + "files": [ + "bin/osx/**/*" + ] }, "linux": { "artifactName": "${productName}-${version}-${arch}-linux.${ext}", "maintainer": "bryphe@outlook.com", - "target": ["tar.gz", "deb", "rpm"] + "target": [ + "tar.gz", + "deb", + "rpm" + ] }, "win": { - "target": ["zip", "dir"], - "files": ["bin/x86/**/*"] + "target": [ + "zip", + "dir" + ], + "files": [ + "bin/x86/**/*" + ] }, "fileAssociations": [ { @@ -121,65 +141,47 @@ "build:browser": "webpack --config browser/webpack.production.config.js", "build:browser-debug": "webpack --config browser/webpack.debug.config.js", "build:main": "cd main && tsc -p tsconfig.json", - "build:plugins": - "npm run build:plugin:oni-plugin-typescript && npm run build:plugin:oni-plugin-markdown-preview", + "build:plugins": "npm run build:plugin:oni-plugin-typescript && npm run build:plugin:oni-plugin-markdown-preview", "build:plugin:oni-plugin-typescript": "cd vim/core/oni-plugin-typescript && npm run build", - "build:plugin:oni-plugin-markdown-preview": - "cd extensions/oni-plugin-markdown-preview && npm run build", + "build:plugin:oni-plugin-markdown-preview": "cd extensions/oni-plugin-markdown-preview && npm run build", "build:test": "npm run build:test:unit && npm run build:test:integration", "build:test:integration": "cd test && tsc -p tsconfig.json", "build:test:unit": "cd browser && tsc -p tsconfig.test.json", "copy-icons": "node build/CopyIcons.js", "copy-dist-to-s3": "node build/script/CopyPackedFilesForS3Upload.js", - "debug:test:unit:browser": - "cd browser && tsc -p tsconfig.test.json && electron-mocha --interactive --debug --renderer --require testHelpers.js --recursive ../lib_test/browser/test", + "debug:test:unit:browser": "cd browser && tsc -p tsconfig.test.json && electron-mocha --interactive --debug --renderer --require testHelpers.js --recursive ../lib_test/browser/test", "demo": "npm run build:test && mocha -t 30000 lib_test/test/Demo.js", - "dist:win": - "cross-env ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES=1 build --arch ia32 --publish never", - "pack:win": - "node build/BuildSetupTemplate.js && innosetup-compiler dist/setup.iss --verbose --O=dist", + "dist:win": "cross-env ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES=1 build --arch ia32 --publish never", + "pack:win": "node build/BuildSetupTemplate.js && innosetup-compiler dist/setup.iss --verbose --O=dist", "test": "npm run test:unit && npm run test:integration", "test:integration": "npm run build:test && mocha -t 120000 lib_test/test/CiTests.js", "test:unit": "npm run test:unit:browser", - "test:unit:browser": - "npm run build:test:unit && cd browser && electron-mocha --renderer --require testHelpers.js --recursive ../lib_test/browser/test", + "test:unit:browser": "npm run build:test:unit && cd browser && electron-mocha --renderer --require testHelpers.js --recursive ../lib_test/browser/test", "fix-lint": "npm run fix-lint:browser && npm run fix-lint:main && npm run fix-lint:test", - "fix-lint:browser": - "tslint --fix --project browser/tsconfig.json --exclude **/node_modules/**/* --config tslint.json && tslint --fix --project vim/core/oni-plugin-typescript/tsconfig.json --config tslint.json && tslint --fix --project extensions/oni-plugin-markdown-preview/tsconfig.json --config tslint.json", + "fix-lint:browser": "tslint --fix --project browser/tsconfig.json --exclude **/node_modules/**/* --config tslint.json && tslint --fix --project vim/core/oni-plugin-typescript/tsconfig.json --config tslint.json && tslint --fix --project extensions/oni-plugin-markdown-preview/tsconfig.json --config tslint.json", "fix-lint:main": "tslint --fix --project main/tsconfig.json --config tslint.json", "fix-lint:test": "tslint --fix --project test/tsconfig.json --config tslint.json", "lint": "npm run lint:browser && npm run lint:main && npm run lint:test", - "lint:browser": - "tslint --project browser/tsconfig.json --config tslint.json && tslint --project vim/core/oni-plugin-typescript/tsconfig.json --config tslint.json && tslint --project extensions/oni-plugin-markdown-preview/tsconfig.json --config tslint.json", + "lint:browser": "tslint --project browser/tsconfig.json --config tslint.json && tslint --project vim/core/oni-plugin-typescript/tsconfig.json --config tslint.json && tslint --project extensions/oni-plugin-markdown-preview/tsconfig.json --config tslint.json", "lint:main": "tslint --project main/tsconfig.json --config tslint.json", - "lint:test": - "tslint --project test/tsconfig.json --config tslint.json && tslint vim/core/oni-plugin-typescript/src/**/*.ts && tslint extensions/oni-plugin-markdown-preview/src/**/*.ts", + "lint:test": "tslint --project test/tsconfig.json --config tslint.json && tslint vim/core/oni-plugin-typescript/src/**/*.ts && tslint extensions/oni-plugin-markdown-preview/src/**/*.ts", "pack": "cross-env ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES=1 build --publish never", - "ccov:instrument": - "nyc instrument --all true --sourceMap false lib_test/browser/src lib_test/browser/src_ccov", - "ccov:test:browser": - "cd browser && cross-env ONI_CCOV=1 electron-mocha --renderer --require testHelpers.js -R testCoverageReporter --recursive ../lib_test/browser/test", + "ccov:instrument": "nyc instrument --all true --sourceMap false lib_test/browser/src lib_test/browser/src_ccov", + "ccov:test:browser": "cd browser && cross-env ONI_CCOV=1 electron-mocha --renderer --require testHelpers.js -R testCoverageReporter --recursive ../lib_test/browser/test", "ccov:report": "nyc report && nyc report --reporter=html && nyc report --reporter=lcov", - "start": - "concurrently --kill-others \"npm run start-hot\" \"npm run watch:browser\" \"npm run watch:plugins\"", - "start-hot": - "cross-env ONI_WEBPACK_LOAD=1 NODE_ENV=development electron lib/main/src/main.js", + "start": "concurrently --kill-others \"npm run start-hot\" \"npm run watch:browser\" \"npm run watch:plugins\"", + "start-hot": "cross-env ONI_WEBPACK_LOAD=1 NODE_ENV=development electron lib/main/src/main.js", "start-not-dev": "cross-env electron main.js", - "watch:browser": - "webpack-dev-server --config browser/webpack.debug.config.js --host localhost --port 8191", - "watch:plugins": - "npm run watch:plugins:oni-plugin-typescript && npm run watch:plugins:oni-plugin-markdown-preview", + "watch:browser": "webpack-dev-server --config browser/webpack.debug.config.js --host localhost --port 8191", + "watch:plugins": "npm run watch:plugins:oni-plugin-typescript && npm run watch:plugins:oni-plugin-markdown-preview", "watch:plugins:oni-plugin-typescript": "cd vim/core/oni-plugin-typescript && tsc --watch", - "watch:plugins:oni-plugin-markdown-preview": - "cd extensions/oni-plugin-markdown-preview && tsc --watch", + "watch:plugins:oni-plugin-markdown-preview": "cd extensions/oni-plugin-markdown-preview && tsc --watch", "uninstall-global": "npm rm -g oni-vim", "install-global": "npm install -g oni-vim", "install:plugins": "npm run install:plugins:oni-plugin-markdown-preview", - "install:plugins:oni-plugin-markdown-preview": - "cd extensions/oni-plugin-markdown-preview && npm install --prod", + "install:plugins:oni-plugin-markdown-preview": "cd extensions/oni-plugin-markdown-preview && npm install --prod", "postinstall": "npm run install:plugins && electron-rebuild && opencollective postinstall", - "profile:webpack": - "webpack --config browser/webpack.production.config.js --profile --json > stats.json && webpack-bundle-analyzer browser/stats.json" + "profile:webpack": "webpack --config browser/webpack.production.config.js --profile --json > stats.json && webpack-bundle-analyzer browser/stats.json" }, "repository": { "type": "git", @@ -251,6 +253,7 @@ "electron-mocha": "5.0.0", "electron-rebuild": "1.6.0", "extract-zip": "1.6.0", + "find-process": "^1.1.0", "fs-extra": "4.0.2", "fuse.js": "2.6.2", "github-releases": "^0.4.1", diff --git a/test/common/runInProcTest.ts b/test/common/runInProcTest.ts index 2a7ebea00a..911d77ee8b 100644 --- a/test/common/runInProcTest.ts +++ b/test/common/runInProcTest.ts @@ -4,6 +4,8 @@ import * as path from "path" import { Oni } from "./Oni" +const findProcess = require("find-process") // tslint:disable-line + // tslint:disable:no-console export interface ITestCase { @@ -84,6 +86,18 @@ const logWithTimeStamp = (message: string) => { console.log(`[${deltaInSeconds}] ${message}`) } +const reportRunningProcess = async () => { + const electronProcesses = await findProcess("name", "electron") + const oniProcesses = await findProcess("name", "oni") + + const allProcesses = [...electronProcesses, ...oniProcesses] + + console.log("Active Processes:") + allProcesses.forEach(processInfo => { + console.log(` - Name: ${processInfo.name} PID: ${processInfo.pid}`) + }) +} + export const runInProcTest = ( rootPath: string, testName: string, @@ -97,6 +111,8 @@ export const runInProcTest = ( beforeEach(async () => { logWithTimeStamp("BEFORE EACH: " + testName) + await reportRunningProcess() + testCase = loadTest(rootPath, testName) const startOptions = { configurationPath: testCase.configPath, diff --git a/yarn.lock b/yarn.lock index 77c074519e..f622bef152 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2641,6 +2641,14 @@ find-cache-dir@^0.1.1: mkdirp "^0.5.1" pkg-dir "^1.0.0" +find-process@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-process/-/find-process-1.1.0.tgz#f21fa08220fec972b471d92ae3cf0c62bebcd5bb" + dependencies: + chalk "^2.0.1" + commander "^2.11.0" + debug "^2.6.8" + find-up@2.1.0, find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" From ca0e1f0296fa68e4cb2b91182da9a75882bb76fc Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sat, 10 Feb 2018 15:50:02 -0800 Subject: [PATCH 086/103] Re-enable code coverage (#1507) * Try re-enabling code coverage * Restrict the path remapping further --- browser/testHelpers.js | 16 +++++++--------- build/script/travis-build.sh | 7 +++---- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/browser/testHelpers.js b/browser/testHelpers.js index 43c8825b79..63b797dc33 100644 --- a/browser/testHelpers.js +++ b/browser/testHelpers.js @@ -1,9 +1,7 @@ - -const Module = require("module") +const Module = require("module") const originalRequire = Module.prototype.require if (global.window) { - const originalSetTimeout = global.setTimeout const lolex = require("lolex") @@ -19,12 +17,10 @@ if (global.window) { global.clock = clock - global.waitForPromiseResolution = (promise) => { - - return new Promise((res) => { - originalSetTimeout(() => res(), 1) + global.waitForPromiseResolution = promise => { + return new Promise(res => { + originalSetTimeout(() => res(), 1) }) - } } @@ -41,6 +37,8 @@ Module.prototype.require = function(moduleName, ...args) { // If ccov is enabled, we should pull the file from the 'ccov' folder created by `npm run ccov:instrument` // Idea adapted from: // https://github.com/MarshallOfSound/Google-Play-Music-Desktop-Player-UNOFFICIAL-/commit/1b2055b286f1f296c0d48dec714224c14acb3c34 - const ccovFile = shouldUseCodeCoverage ? moduleName.replace("src/", "src_ccov/") : moduleName + const ccovFile = shouldUseCodeCoverage + ? moduleName.replace("browser/src/", "browser/src_ccov/") + : moduleName return originalRequire.call(this, ccovFile, ...args) } diff --git a/build/script/travis-build.sh b/build/script/travis-build.sh index 1155afb9b1..262f919009 100755 --- a/build/script/travis-build.sh +++ b/build/script/travis-build.sh @@ -33,10 +33,9 @@ fi # We'll run code coverage only on Linux, for now if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - echo TODO: Code coverage... - # npm run ccov:instrument - # npm run ccov:test:browser - # npm run ccov:report + npm run ccov:instrument + npm run ccov:test:browser + npm run ccov:report fi npm run copy-dist-to-s3 From ff67b786ad5d60832b69dc2343038b15ca0e1979 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sun, 11 Feb 2018 05:43:10 -0800 Subject: [PATCH 087/103] Automation: Kill any running Oni processes prior to running the test (#1511) * Update tests to kill running Oni processes if there are any * Fix filter logic --- test/common/runInProcTest.ts | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/test/common/runInProcTest.ts b/test/common/runInProcTest.ts index 911d77ee8b..28dff7d99f 100644 --- a/test/common/runInProcTest.ts +++ b/test/common/runInProcTest.ts @@ -86,16 +86,32 @@ const logWithTimeStamp = (message: string) => { console.log(`[${deltaInSeconds}] ${message}`) } -const reportRunningProcess = async () => { - const electronProcesses = await findProcess("name", "electron") - const oniProcesses = await findProcess("name", "oni") +// Sometimes, on the automation machines, Oni will still be running +// when starting the test. It will fail if there is an existing instance +// running, so we need to make sure to finish it. +const ensureOniNotRunning = async () => { + let attempts = 0 + const maxAttempts = 5 + + while (attempts < maxAttempts) { + const oniProcesses = await findProcess("name", "oni") + console.log(`${attempts}/${maxAttempts} Active Processes:`) + oniProcesses.forEach(processInfo => { + console.log(` - Name: ${processInfo.name} PID: ${processInfo.pid}`) + }) + const isOniProcess = processInfo => processInfo.name.indexOf("oni") >= 0 + const filteredProcesses = oniProcesses.filter(isOniProcess) - const allProcesses = [...electronProcesses, ...oniProcesses] + if (filteredProcesses.length === 0) { + return + } - console.log("Active Processes:") - allProcesses.forEach(processInfo => { - console.log(` - Name: ${processInfo.name} PID: ${processInfo.pid}`) - }) + filteredProcesses.forEach(processInfo => { + console.log("Attemping to kill pid: " + processInfo.pid) + process.kill(processInfo.pid) + }) + attempts++ + } } export const runInProcTest = ( @@ -111,7 +127,9 @@ export const runInProcTest = ( beforeEach(async () => { logWithTimeStamp("BEFORE EACH: " + testName) - await reportRunningProcess() + logWithTimeStamp(" - Closing existing instances...") + await ensureOniNotRunning() + logWithTimeStamp(" - Finished closing") testCase = loadTest(rootPath, testName) const startOptions = { From a19ae99acf0befb3006e87d4b9723cc602be25cc Mon Sep 17 00:00:00 2001 From: Ryan C Date: Sun, 11 Feb 2018 14:16:39 +0000 Subject: [PATCH 088/103] Check there is files to open before attempting to open. (#1514) This was causing an error if the Open File window was open and closed without selecting anything. --- browser/src/Editor/NeovimEditor/NeovimEditor.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx index 04cab165ed..0b5ccb75c4 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx @@ -815,6 +815,10 @@ export class NeovimEditor extends Editor implements IEditor { } private async _openFiles(files: string[], action: string): Promise { + if (!files) { + return + } + await this._neovimInstance.callFunction("OniOpenFile", [action, files[0]]) for (let i = 1; i < files.length; i++) { From ede1167c170d042219bebf61a113d748c9e29c09 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sun, 11 Feb 2018 07:41:46 -0800 Subject: [PATCH 089/103] Syntax Highlight - Part 2 - Use 'TokenColor' instead of highlight groups (#1485) * Add TokenColors service * Plumb through token colors as dependency * Fix up issue where the token color event wasn't firing * Fix lint issues * Plumb token colors through the rest of the way * Put in a placeholder for converting token style * Resolve colors to hex * Start stubbing out a test case for TokenColorsTests * Update to use real colors * Update test interfaces, get tests green * Fix typing * Factor MockThemeLoader to separate file * Bring in bold/italic from nvim_get_hl_by_name * Remove TODO * Start refactoring to handle synchronizing token colors * Hook up synchronization of token colors * Scope VimHighlights down to the original configuration values * Stub out tests * Start stubbing out a mock neovim instance interface for testing requests * Add simple test cases for NeovimTokenColorSynchronizer * Fix bold/italic handling * Fix lint issue --- browser/src/Editor/BufferHighlights.ts | 6 +- browser/src/Editor/BufferManager.ts | 17 +-- .../src/Editor/NeovimEditor/HoverRenderer.tsx | 2 +- .../src/Editor/NeovimEditor/NeovimEditor.tsx | 12 ++- .../Configuration/DefaultConfiguration.ts | 35 +----- .../Configuration/IConfigurationValues.ts | 9 +- .../SyntaxHighlighting/Definitions.ts | 12 +-- .../SyntaxHighlightReconciler.ts | 53 ++++----- .../SyntaxHighlighting/SyntaxHighlighting.ts | 6 +- browser/src/neovim/NeovimInstance.ts | 7 ++ .../neovim/NeovimTokenColorSynchronizer.ts | 102 ++++++++++++++++++ browser/src/neovim/VimHighlights.ts | 36 +------ browser/test/Mocks/index.ts | 14 ++- browser/test/Mocks/neovim.ts | 2 + .../test/Mocks/neovim/MockNeovimInstance.ts | 36 +++++++ .../SyntaxHighlightingReconcilerTests.ts | 27 +++-- .../NeovimTokenColorSynchronizerTests.ts | 70 ++++++++++++ 17 files changed, 310 insertions(+), 136 deletions(-) create mode 100644 browser/src/neovim/NeovimTokenColorSynchronizer.ts create mode 100644 browser/test/Mocks/neovim/MockNeovimInstance.ts create mode 100644 browser/test/neovim/NeovimTokenColorSynchronizerTests.ts diff --git a/browser/src/Editor/BufferHighlights.ts b/browser/src/Editor/BufferHighlights.ts index ffd0fec8a2..62334325f2 100644 --- a/browser/src/Editor/BufferHighlights.ts +++ b/browser/src/Editor/BufferHighlights.ts @@ -47,12 +47,16 @@ export class BufferHighlightsUpdater implements IBufferHighlightsUpdater { } const addHighlightCalls = highlights.map(hl => { + const highlightGroup = this._neovimInstance.tokenColorSynchronizer.getHighlightGroupForTokenColor( + hl.tokenColor, + ) + return [ "nvim_buf_add_highlight", [ this._bufferId, this._highlightId, - hl.highlightGroup, + highlightGroup, hl.range.start.line, hl.range.start.character, hl.range.end.character, diff --git a/browser/src/Editor/BufferManager.ts b/browser/src/Editor/BufferManager.ts index b473b2e80c..4f160a8251 100644 --- a/browser/src/Editor/BufferManager.ts +++ b/browser/src/Editor/BufferManager.ts @@ -26,8 +26,6 @@ import { import * as LanguageManager from "./../Services/Language" import { PromiseQueue } from "./../Services/Language/PromiseQueue" -import * as SyntaxHighlighting from "./../Services/SyntaxHighlighting" - import { BufferHighlightId, BufferHighlightsUpdater, @@ -39,6 +37,7 @@ import * as State from "./NeovimEditor/NeovimEditorStore" import * as Constants from "./../Constants" import * as Log from "./../Log" +import { TokenColor } from "./../Services/TokenColors" import { IBufferLayer } from "./NeovimEditor/BufferLayerManager" @@ -209,19 +208,8 @@ export class Buffer implements IBuffer { return result } - - public async getOrCreateHighlightGroup( - highlight: SyntaxHighlighting.IHighlight | string, - ): Promise { - if (typeof highlight === "string") { - return highlight - } else { - // TODO: needed for theming integration! - return null - } - } - public async updateHighlights( + tokenColors: TokenColor[], updateFunction: (highlightsUpdater: IBufferHighlightsUpdater) => void, ): Promise { this._promiseQueue.enqueuePromise(async () => { @@ -231,6 +219,7 @@ export class Buffer implements IBuffer { this._neovimInstance, this._bufferHighlightId, ) + await this._neovimInstance.tokenColorSynchronizer.synchronizeTokenColors(tokenColors) await bufferUpdater.start() updateFunction(bufferUpdater) diff --git a/browser/src/Editor/NeovimEditor/HoverRenderer.tsx b/browser/src/Editor/NeovimEditor/HoverRenderer.tsx index a6de8c389b..061fd90042 100644 --- a/browser/src/Editor/NeovimEditor/HoverRenderer.tsx +++ b/browser/src/Editor/NeovimEditor/HoverRenderer.tsx @@ -111,7 +111,7 @@ export class HoverRenderer { } const items = scopeInfo.scopes.map((si: string) =>
  • {si}
  • ) return ( - +
    DEBUG: TextMate Scopes:
      {items}
    diff --git a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx index 0b5ccb75c4..f89dbf4bcb 100644 --- a/browser/src/Editor/NeovimEditor/NeovimEditor.tsx +++ b/browser/src/Editor/NeovimEditor/NeovimEditor.tsx @@ -261,6 +261,16 @@ export class NeovimEditor extends Editor implements IEditor { this._colors.onColorsChanged.subscribe(() => onColorsChanged()) onColorsChanged() + const onTokenColorschanged = () => { + if (this._neovimInstance.isInitialized) { + this._neovimInstance.tokenColorSynchronizer.synchronizeTokenColors( + this._tokenColors.tokenColors, + ) + } + } + + this._tokenColors.onTokenColorsChanged.subscribe(() => onTokenColorschanged()) + // Overlays // TODO: Replace `OverlayManagement` concept and associated window management code with // explicit window management: #362 @@ -484,7 +494,7 @@ export class NeovimEditor extends Editor implements IEditor { "experimental.editor.textMateHighlighting.enabled", ) this._syntaxHighlighter = textMateHighlightingEnabled - ? new SyntaxHighlighter(this._configuration, this) + ? new SyntaxHighlighter(this, this._tokenColors) : new NullSyntaxHighlighter() this._completion = new Completion( diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index fce1dcb221..171cafca12 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -115,40 +115,7 @@ const BaseConfiguration: IConfigurationValues = { "editor.cursorColumn": false, "editor.cursorColumnOpacity": 0.1, - "editor.tokenColors": [ - { - scope: "variable.object", - settings: "Identifier", - }, - { - scope: "variable.other.constant", - settings: "Constant", - }, - { - scope: "variable.language", - settings: "Identifier", - }, - { - scope: "variable.parameter", - settings: "Identifier", - }, - { - scope: "variable.other", - settings: "Identifier", - }, - { - scope: "support.function", - settings: "Function", - }, - { - scope: "entity.name", - settings: "Function", - }, - { - scope: "entity.other", - settings: "Constant", - }, - ], + "editor.tokenColors": [], "environment.additionalPaths": [], diff --git a/browser/src/Services/Configuration/IConfigurationValues.ts b/browser/src/Services/Configuration/IConfigurationValues.ts index e22da124e0..1dd32fdabc 100644 --- a/browser/src/Services/Configuration/IConfigurationValues.ts +++ b/browser/src/Services/Configuration/IConfigurationValues.ts @@ -8,12 +8,7 @@ import * as Oni from "oni-api" -import { IHighlight } from "./../SyntaxHighlighting" - -export interface ITokenColorsSetting { - scope: string - settings: IHighlight | string -} +import { TokenColor } from "./../TokenColors" export type FontSmoothingOptions = "auto" | "antialiased" | "subpixel-antialiased" | "none" export type DetectionSettings = "always" | "noworkspace" | "never" @@ -150,7 +145,7 @@ export interface IConfigurationValues { "editor.scrollBar.cursorTick.visible": boolean // Allow overriding token colors for specific textmate scopes - "editor.tokenColors": ITokenColorsSetting[] + "editor.tokenColors": TokenColor[] // Additional paths to include when launching sub-process from Oni // (and available in terminal integration, later) diff --git a/browser/src/Services/SyntaxHighlighting/Definitions.ts b/browser/src/Services/SyntaxHighlighting/Definitions.ts index 62d61316b7..0b5e6d96c7 100644 --- a/browser/src/Services/SyntaxHighlighting/Definitions.ts +++ b/browser/src/Services/SyntaxHighlighting/Definitions.ts @@ -1,16 +1,8 @@ import * as types from "vscode-languageserver-types" -export interface IHighlight { - foregroundColor: string - backgroundColor: string - - bold: boolean - italic: boolean -} - -export type HighlightGroupId = string +import { TokenColor } from "./../TokenColors" export interface HighlightInfo { range: types.Range - highlightGroup: HighlightGroupId + tokenColor: TokenColor } diff --git a/browser/src/Services/SyntaxHighlighting/SyntaxHighlightReconciler.ts b/browser/src/Services/SyntaxHighlighting/SyntaxHighlightReconciler.ts index 71b645587a..06cb4547c4 100644 --- a/browser/src/Services/SyntaxHighlighting/SyntaxHighlightReconciler.ts +++ b/browser/src/Services/SyntaxHighlighting/SyntaxHighlightReconciler.ts @@ -4,11 +4,11 @@ * Handles enhanced syntax highlighting */ -import { Configuration } from "./../Configuration" +import { TokenColor, TokenColors } from "./../TokenColors" import { NeovimEditor } from "./../../Editor/NeovimEditor" -import { HighlightGroupId, HighlightInfo } from "./Definitions" +import { HighlightInfo } from "./Definitions" import { ISyntaxHighlightLineInfo, ISyntaxHighlightState, @@ -27,7 +27,7 @@ import * as Log from "./../../Log" export class SyntaxHighlightReconciler { private _previousState: { [line: number]: ISyntaxHighlightLineInfo } = {} - constructor(private _configuration: Configuration, private _editor: NeovimEditor) {} + constructor(private _editor: NeovimEditor, private _tokenColors: TokenColors) {} public update(state: ISyntaxHighlightState) { const activeBuffer: any = this._editor.activeBuffer @@ -82,45 +82,48 @@ export class SyntaxHighlightReconciler { Log.verbose( "[SyntaxHighlightReconciler] Applying changes to " + tokens.length + " lines.", ) - activeBuffer.updateHighlights((highlightUpdater: any) => { - tokens.forEach(token => { - const line = token.line - const highlights = token.highlights - - if (Log.isDebugLoggingEnabled()) { - Log.debug( - "[SyntaxHighlightingReconciler] Updating tokens for line: " + - token.line + - " | " + - JSON.stringify(highlights), - ) - } - - highlightUpdater.setHighlightsForLine(line, highlights) - }) - }) + activeBuffer.updateHighlights( + this._tokenColors.tokenColors, + (highlightUpdater: any) => { + tokens.forEach(token => { + const line = token.line + const highlights = token.highlights + + if (Log.isDebugLoggingEnabled()) { + Log.debug( + "[SyntaxHighlightingReconciler] Updating tokens for line: " + + token.line + + " | " + + JSON.stringify(highlights), + ) + } + + highlightUpdater.setHighlightsForLine(line, highlights) + }) + }, + ) } } } private _mapTokensToHighlights(tokens: ISyntaxHighlightTokenInfo[]): HighlightInfo[] { const mapTokenToHighlight = (token: ISyntaxHighlightTokenInfo) => ({ - highlightGroup: this._getHighlightGroupFromScope(token.scopes), + tokenColor: this._getHighlightGroupFromScope(token.scopes), range: token.range, }) - return tokens.map(mapTokenToHighlight).filter(t => !!t.highlightGroup) + return tokens.map(mapTokenToHighlight).filter(t => !!t.tokenColor) } - private _getHighlightGroupFromScope(scopes: string[]): HighlightGroupId { - const configurationColors = this._configuration.getValue("editor.tokenColors") + private _getHighlightGroupFromScope(scopes: string[]): TokenColor { + const configurationColors = this._tokenColors.tokenColors for (const scope of scopes) { const matchingRule = configurationColors.find((c: any) => scope.indexOf(c.scope) === 0) if (matchingRule) { // TODO: Convert to highlight group id - return matchingRule.settings + return matchingRule } } diff --git a/browser/src/Services/SyntaxHighlighting/SyntaxHighlighting.ts b/browser/src/Services/SyntaxHighlighting/SyntaxHighlighting.ts index 15c904629f..f72653fbb3 100644 --- a/browser/src/Services/SyntaxHighlighting/SyntaxHighlighting.ts +++ b/browser/src/Services/SyntaxHighlighting/SyntaxHighlighting.ts @@ -13,7 +13,7 @@ import * as Oni from "oni-api" import { Store, Unsubscribe } from "redux" -import { Configuration } from "./../Configuration" +import { TokenColors } from "./../TokenColors" import { NeovimEditor } from "./../../Editor/NeovimEditor" @@ -34,10 +34,10 @@ export class SyntaxHighlighter implements ISyntaxHighlighter { private _reconciler: SyntaxHighlightReconciler private _unsubscribe: Unsubscribe - constructor(private _configuration: Configuration, private _editor: NeovimEditor) { + constructor(private _editor: NeovimEditor, private _tokenColors: TokenColors) { this._store = createSyntaxHighlightStore() - this._reconciler = new SyntaxHighlightReconciler(this._configuration, this._editor) + this._reconciler = new SyntaxHighlightReconciler(this._editor, this._tokenColors) this._unsubscribe = this._store.subscribe(() => { const state = this._store.getState() this._reconciler.update(state) diff --git a/browser/src/neovim/NeovimInstance.ts b/browser/src/neovim/NeovimInstance.ts index 2f429d72b9..74ce0b241a 100644 --- a/browser/src/neovim/NeovimInstance.ts +++ b/browser/src/neovim/NeovimInstance.ts @@ -26,6 +26,7 @@ import { Session } from "./Session" import { PromiseQueue } from "./../Services/Language/PromiseQueue" import { TokenColor } from "./../Services/TokenColors" import { INeovimBufferUpdate, NeovimBufferUpdateManager } from "./NeovimBufferUpdateManager" +import { NeovimTokenColorSynchronizer } from "./NeovimTokenColorSynchronizer" import { IVimHighlight, @@ -225,6 +226,7 @@ export class NeovimInstance extends EventEmitter implements INeovimInstance { private _onWildMenuSelectEvent = new Event() private _onWildMenuShowEvent = new Event() private _bufferUpdateManager: NeovimBufferUpdateManager + private _tokenColorSynchronizer: NeovimTokenColorSynchronizer private _pendingScrollTimeout: number | null = null @@ -324,6 +326,10 @@ export class NeovimInstance extends EventEmitter implements INeovimInstance { return this._marks } + public get tokenColorSynchronizer(): NeovimTokenColorSynchronizer { + return this._tokenColorSynchronizer + } + constructor(widthInPixels: number, heightInPixels: number, configuration: Configuration) { super() this._configuration = configuration @@ -336,6 +342,7 @@ export class NeovimInstance extends EventEmitter implements INeovimInstance { this._quickFix = new QuickFixList(this) this._autoCommands = new NeovimAutoCommands(this) this._marks = new NeovimMarks(this) + this._tokenColorSynchronizer = new NeovimTokenColorSynchronizer(this) this._bufferUpdateManager = new NeovimBufferUpdateManager(this._configuration, this) } diff --git a/browser/src/neovim/NeovimTokenColorSynchronizer.ts b/browser/src/neovim/NeovimTokenColorSynchronizer.ts new file mode 100644 index 0000000000..f930746cd6 --- /dev/null +++ b/browser/src/neovim/NeovimTokenColorSynchronizer.ts @@ -0,0 +1,102 @@ +/** + * NeovimTokenColorSynchronizer + * + * This is a helper that pushes all the token colors to Neovim + * as custom highlight groups. + */ + +import * as Color from "color" +import { TokenColor } from "./../Services/TokenColors" + +import { NeovimInstance } from "./NeovimInstance" + +import * as Log from "./../Log" + +const getGuiStringFromTokenColor = (color: TokenColor): string => { + if (color.settings.bold && color.settings.italic) { + return "gui=bold,italic" + } else if (color.settings.bold) { + return "gui=bold" + } else if (color.settings.italic) { + return "gui=italic" + } else { + return "gui=none" + } +} + +export class NeovimTokenColorSynchronizer { + private _currentIndex: number = 0 + private _tokenScopeSelectorToHighlightName: { [key: string]: string } = {} + private _highlightNameToHighlightValue: { [key: string]: string } = {} + + constructor(private _neovimInstance: NeovimInstance) {} + + // This method creates highlight groups for any token colors that haven't been set yet + public async synchronizeTokenColors(tokenColors: TokenColor[]): Promise { + const highlightsToAdd = tokenColors.map(tokenColor => { + const highlightName = this._getOrCreateHighlightGroup(tokenColor) + const highlightFromScope = this._convertTokenStyleToHighlightInfo(tokenColor) + + const currentHighlight = this._highlightNameToHighlightValue[highlightName] + + if (currentHighlight === highlightFromScope) { + return null + } else { + this._highlightNameToHighlightValue[highlightName] = highlightFromScope + return highlightFromScope + } + }) + + const filteredHighlights = highlightsToAdd.filter(hl => !!hl) + + const atomicCalls = filteredHighlights.map(hlCommand => { + return ["nvim_command", [hlCommand]] + }) + + if (atomicCalls.length === 0) { + return + } + + Log.info( + "[NeovimTokenColorSynchronizer::synchronizeTokenColors] Setting " + + atomicCalls.length + + " highlights", + ) + await this._neovimInstance.request("nvim_call_atomic", [atomicCalls]) + Log.info( + "[NeovimTokenColorSynchronizer::synchronizeTokenColors] Highlights set successfully", + ) + } + + /** + * Gets the highlight group for the particular token color. Requires that `synchronizeTokenColors` has been called + * previously. + */ + public getHighlightGroupForTokenColor(tokenColor: TokenColor): string { + return this._getOrCreateHighlightGroup(tokenColor) + } + + private _convertTokenStyleToHighlightInfo(tokenColor: TokenColor): string { + const name = this._getOrCreateHighlightGroup(tokenColor) + const foregroundColor = Color(tokenColor.settings.foregroundColor).hex() + const backgroundColor = Color(tokenColor.settings.backgroundColor).hex() + const gui = getGuiStringFromTokenColor(tokenColor) + return `:hi ${name} guifg=${foregroundColor} guibg=${backgroundColor} ${gui}` + } + + private _getOrCreateHighlightGroup(tokenColor: TokenColor): string { + const existingGroup = this._tokenScopeSelectorToHighlightName[tokenColor.scope] + if (existingGroup) { + return existingGroup + } else { + this._currentIndex++ + const newHighlightGroupName = "oni_highlight_" + this._currentIndex.toString() + Log.verbose( + "[NeovimTokenColorSynchronizer::_getOrCreateHighlightGroup] Creating new highlight group - " + + newHighlightGroupName, + ) + this._tokenScopeSelectorToHighlightName[tokenColor.scope] = newHighlightGroupName + return newHighlightGroupName + } + } +} diff --git a/browser/src/neovim/VimHighlights.ts b/browser/src/neovim/VimHighlights.ts index 5921eeb8e3..9c7bd5e48c 100644 --- a/browser/src/neovim/VimHighlights.ts +++ b/browser/src/neovim/VimHighlights.ts @@ -25,37 +25,7 @@ export const vimHighlightToTokenColorStyle = (highlight: IVimHighlight): TokenCo } export const VimHighlightToDefaultScope = { - Identifier: [ - "support.variable", - "support.variable.property.dom", - "variable.language", - "variable.parameter", - "variable.object", - "meta.object.type", - "meta.object", - ], - Function: [ - "support.function", - "entity.name", - "entity.name.type.enum", - "entity.name.type.interface", - "meta.function.call", - "meta.function", - "punctuation.accessor", - "punctuation.separator.continuation", - "punctuation.separator.comma", - "punctuation.terminator", - "punctuation.terminator", - ], - Constant: [ - "storage.type.interface", - "storage.type.enum", - "storage.type.interface", - "entity.other", - "keyword.control.import", - "keyword.control", - "variable.other.constant", - "variable.other.object", - "variable.other.property", - ], + Identifier: ["variable.language", "variable.object", "variable.parameter", "variable.other"], + Function: ["support.function", "entity.name"], + Constant: ["variable.other.constant", "entity.other"], } diff --git a/browser/test/Mocks/index.ts b/browser/test/Mocks/index.ts index a20ce8ca0a..f1406496df 100644 --- a/browser/test/Mocks/index.ts +++ b/browser/test/Mocks/index.ts @@ -19,8 +19,17 @@ import * as Language from "./../../src/Services/Language" import { createCompletablePromise, ICompletablePromise } from "./../../src/Utility" import { HighlightInfo } from "./../../src/Services/SyntaxHighlighting" +import { TokenColor } from "./../../src/Services/TokenColors" import { IWorkspace } from "./../../src/Services/Workspace" +export class MockTokenColors { + constructor(private _tokenColors: TokenColor[] = []) {} + + public get tokenColors(): TokenColor[] { + return this._tokenColors + } +} + export class MockConfiguration { private _currentConfigurationFiles: string[] = [] private _onConfigurationChanged = new Event() @@ -231,7 +240,10 @@ export class MockBuffer { return Promise.resolve(this._lines.slice(start, end)) } - public updateHighlights(updateFunction: (highlightUpdater: IBufferHighlightsUpdater) => void) { + public updateHighlights( + tokenColors: any[], + updateFunction: (highlightUpdater: IBufferHighlightsUpdater) => void, + ) { updateFunction(this._mockHighlights) } } diff --git a/browser/test/Mocks/neovim.ts b/browser/test/Mocks/neovim.ts index 9062d336db..5007bc3948 100644 --- a/browser/test/Mocks/neovim.ts +++ b/browser/test/Mocks/neovim.ts @@ -7,6 +7,8 @@ import * as Neovim from "./../../src/neovim" +export * from "./neovim/MockNeovimInstance" + export class MockScreen implements Neovim.IScreen { public backgroundColor: string public foregroundColor: string diff --git a/browser/test/Mocks/neovim/MockNeovimInstance.ts b/browser/test/Mocks/neovim/MockNeovimInstance.ts new file mode 100644 index 0000000000..92278f8e6f --- /dev/null +++ b/browser/test/Mocks/neovim/MockNeovimInstance.ts @@ -0,0 +1,36 @@ +/** + * Mocks/neovim/MockNeovimInstance.ts + * + * Implementations of test mocks and doubles, + * for Neovim facing classes / interfaces. + */ + +import * as Utility from "./../../../src/Utility" + +export interface NeovimRequest { + requestName: string + args: any[] +} + +export class MockNeovimInstance { + private _requests: NeovimRequest[] = [] + private _pendingPromises: Array> = [] + + public request(requestName: string, args: any[]) { + this._requests.push({ requestName, args }) + const promise = Utility.createCompletablePromise() + this._pendingPromises.push(promise) + + return promise.promise + } + + public getPendingRequests(): NeovimRequest[] { + return this._requests + } + + public flushPendingRequests(): void { + this._pendingPromises.forEach(p => p.resolve()) + this._requests = [] + this._pendingPromises = [] + } +} diff --git a/browser/test/Services/SyntaxHighlighting/SyntaxHighlightingReconcilerTests.ts b/browser/test/Services/SyntaxHighlighting/SyntaxHighlightingReconcilerTests.ts index f1baa8c0ca..a8ded134bb 100644 --- a/browser/test/Services/SyntaxHighlighting/SyntaxHighlightingReconcilerTests.ts +++ b/browser/test/Services/SyntaxHighlighting/SyntaxHighlightingReconcilerTests.ts @@ -11,26 +11,33 @@ import { SyntaxHighlightReconciler, } from "./../../../src/Services/SyntaxHighlighting" +const COLOR_BLACK = "#000000" +const COLOR_WHITE = "#FFFFFF" + describe("SyntaxHighlightReconciler", () => { let syntaxHighlightReconciler: SyntaxHighlightReconciler - let mockConfiguration: Mocks.MockConfiguration + let mockTokenColors: Mocks.MockTokenColors let mockEditor: Mocks.MockEditor let mockBuffer: Mocks.MockBuffer beforeEach(() => { - mockConfiguration = new Mocks.MockConfiguration() mockEditor = new Mocks.MockEditor() - mockConfiguration.setValue("editor.tokenColors", [ + mockTokenColors = new Mocks.MockTokenColors([ { scope: "scope.test", - settings: "Identifier", + settings: { + backgroundColor: COLOR_BLACK, + foregroundColor: COLOR_WHITE, + bold: true, + italic: true, + }, }, ]) syntaxHighlightReconciler = new SyntaxHighlightReconciler( - mockConfiguration as any, mockEditor as any, + mockTokenColors as any, ) mockBuffer = new Mocks.MockBuffer("javascript", "test.js", []) @@ -81,8 +88,16 @@ describe("SyntaxHighlightReconciler", () => { const expectedHighlights: HighlightInfo[] = [ { - highlightGroup: "Identifier", range: types.Range.create(0, 0, 0, 5), + tokenColor: { + scope: "scope.test", + settings: { + backgroundColor: COLOR_BLACK, + foregroundColor: COLOR_WHITE, + italic: true, + bold: true, + }, + }, }, ] diff --git a/browser/test/neovim/NeovimTokenColorSynchronizerTests.ts b/browser/test/neovim/NeovimTokenColorSynchronizerTests.ts new file mode 100644 index 0000000000..a6e49ccf0e --- /dev/null +++ b/browser/test/neovim/NeovimTokenColorSynchronizerTests.ts @@ -0,0 +1,70 @@ +/** + * NeovimTokenColorSynchronizerTests.ts + */ + +import * as assert from "assert" + +import { NeovimTokenColorSynchronizer } from "./../../src/neovim/NeovimTokenColorSynchronizer" +import { TokenColor } from "./../../src/Services/TokenColors" + +import { MockNeovimInstance } from "./../Mocks/neovim" + +const createTokenColor = (scope: string): TokenColor => ({ + scope, + settings: { + foregroundColor: "#FFFFFF", + backgroundColor: "#FF0000", + bold: false, + italic: false, + }, +}) + +describe("NeovimTokenColorSynchronizer", () => { + let neovimInstance: MockNeovimInstance + let tokenColorSynchronizer: NeovimTokenColorSynchronizer + + beforeEach(() => { + neovimInstance = new MockNeovimInstance() + tokenColorSynchronizer = new NeovimTokenColorSynchronizer(neovimInstance as any) + }) + + describe("synchronizeTokenColors", () => { + it("adds token color if it doesn't exist", async () => { + const color = createTokenColor("test.scope") + const promise = tokenColorSynchronizer.synchronizeTokenColors([color]) + const pendingRequests = neovimInstance.getPendingRequests() + + const firstRequest = pendingRequests[0] + assert.strictEqual(firstRequest.requestName, "nvim_call_atomic") + + const subRequests = pendingRequests[0].args + assert.strictEqual(subRequests.length, 1) + + const [subRequestName, subRequestArgs] = subRequests[0][0] + + assert.strictEqual(subRequestName, "nvim_command") + assert.ok(subRequestArgs[0].indexOf("guibg=#FF0000")) + assert.ok(subRequestArgs[0].indexOf("guifg=#FFFFFF")) + + neovimInstance.flushPendingRequests() + + await promise + }) + + it("doesn't add token color if it already exists", async () => { + // Add a token color... + const color = createTokenColor("test.scope") + const promise = tokenColorSynchronizer.synchronizeTokenColors([color]) + + neovimInstance.flushPendingRequests() + await promise + + // ...now add it again + const promise2 = tokenColorSynchronizer.synchronizeTokenColors([color]) + + // Validate there were no pending requests + assert.strictEqual(neovimInstance.getPendingRequests().length, 0) + await promise2 + }) + }) +}) From a46cd20c55bfa166c16416625790791506695a1f Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 11 Feb 2018 08:03:30 -0800 Subject: [PATCH 090/103] Added .nvmrc with node@9 (#1510) --- .nvmrc | 1 + 1 file changed, 1 insertion(+) create mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000000..ec635144f6 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +9 From d794db5652bae9582e219fc872531e1b08a4d444 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sun, 11 Feb 2018 08:13:52 -0800 Subject: [PATCH 091/103] Fix issues generating lcov (#1512) --- .travis.yml | 2 +- browser/testHelpers.js | 2 +- package.json | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 037661ad0f..a7e98addcf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,7 @@ install: script: - ./build/script/travis-build.sh after_success: - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then node_modules/.bin/coveralls < .nyc_output/lcov.info; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then node_modules/.bin/coveralls < .nyc_output/coverage/lcov.info; fi deploy: - provider: s3 access_key_id: AKIAIYMATI2CEFTHPBOQ diff --git a/browser/testHelpers.js b/browser/testHelpers.js index 63b797dc33..4586cd8a0e 100644 --- a/browser/testHelpers.js +++ b/browser/testHelpers.js @@ -38,7 +38,7 @@ Module.prototype.require = function(moduleName, ...args) { // Idea adapted from: // https://github.com/MarshallOfSound/Google-Play-Music-Desktop-Player-UNOFFICIAL-/commit/1b2055b286f1f296c0d48dec714224c14acb3c34 const ccovFile = shouldUseCodeCoverage - ? moduleName.replace("browser/src/", "browser/src_ccov/") + ? moduleName.replace("../src/", "../src_ccov/") : moduleName return originalRequire.call(this, ccovFile, ...args) } diff --git a/package.json b/package.json index fe97e88897..0a397ccdf1 100644 --- a/package.json +++ b/package.json @@ -168,7 +168,8 @@ "pack": "cross-env ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES=1 build --publish never", "ccov:instrument": "nyc instrument --all true --sourceMap false lib_test/browser/src lib_test/browser/src_ccov", "ccov:test:browser": "cd browser && cross-env ONI_CCOV=1 electron-mocha --renderer --require testHelpers.js -R testCoverageReporter --recursive ../lib_test/browser/test", - "ccov:report": "nyc report && nyc report --reporter=html && nyc report --reporter=lcov", + "ccov:report": "nyc report && npm run ccov:report:lcov", + "ccov:report:lcov": "cd .nyc_output && nyc report --reporter=lcov out.json", "start": "concurrently --kill-others \"npm run start-hot\" \"npm run watch:browser\" \"npm run watch:plugins\"", "start-hot": "cross-env ONI_WEBPACK_LOAD=1 NODE_ENV=development electron lib/main/src/main.js", "start-not-dev": "cross-env electron main.js", From 327f80bbff8cc312582b67f64e24eda946e40ac1 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sun, 11 Feb 2018 10:34:52 -0800 Subject: [PATCH 092/103] Code Coverage: Upload from script (#1519) * Log additional coverage info, move reporting into script to avoid cleanup issues * Fix typo in build script --- .travis.yml | 2 -- build/script/travis-build.sh | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a7e98addcf..c34706f525 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,8 +32,6 @@ install: - yarn install script: - ./build/script/travis-build.sh -after_success: - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then node_modules/.bin/coveralls < .nyc_output/coverage/lcov.info; fi deploy: - provider: s3 access_key_id: AKIAIYMATI2CEFTHPBOQ diff --git a/build/script/travis-build.sh b/build/script/travis-build.sh index 262f919009..757b4481be 100755 --- a/build/script/travis-build.sh +++ b/build/script/travis-build.sh @@ -36,6 +36,11 @@ if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then npm run ccov:instrument npm run ccov:test:browser npm run ccov:report + + ls -a .nyc_output + ls -a .nyc_output/coverage + + node_modules/.bin/coveralls < .nyc_output/coverage/lcov.info fi npm run copy-dist-to-s3 From d6b6697f13c53d39270ab2f9d79f2818d5c046b6 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sun, 11 Feb 2018 11:00:30 -0800 Subject: [PATCH 093/103] Improve robustness of our process-kill strategy (#1517) --- test/common/runInProcTest.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/common/runInProcTest.ts b/test/common/runInProcTest.ts index 28dff7d99f..d0d09bdb8d 100644 --- a/test/common/runInProcTest.ts +++ b/test/common/runInProcTest.ts @@ -108,7 +108,14 @@ const ensureOniNotRunning = async () => { filteredProcesses.forEach(processInfo => { console.log("Attemping to kill pid: " + processInfo.pid) - process.kill(processInfo.pid) + // Sometimes, there can be a race condition here. For example, + // the process may have closed between when we queried above + // and when we try to kill it. So we'll wrap it in a try/catch. + try { + process.kill(processInfo.pid) + } catch (ex) { + console.warn(ex) + } }) attempts++ } From b9365dd26a83e8e8eaf67a94b21bda8954d44808 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sun, 11 Feb 2018 11:38:12 -0800 Subject: [PATCH 094/103] Skip writing logs if the test passed, to make the log easier to read (#1518) --- test/common/runInProcTest.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/test/common/runInProcTest.ts b/test/common/runInProcTest.ts index d0d09bdb8d..b145a21662 100644 --- a/test/common/runInProcTest.ts +++ b/test/common/runInProcTest.ts @@ -183,14 +183,19 @@ export const runInProcTest = ( }) } - const rendererLogs: any[] = await oni.client.getRenderProcessLogs() - console.log("") - console.log("---LOGS (Renderer): " + testName) - writeLogs(rendererLogs) - console.log("--- " + testName + " ---") - console.log("Getting result...") const resultText = await oni.client.getText(".automated-test-result") + const result = JSON.parse(resultText) + + if (!result || !result.passed) { + const rendererLogs: any[] = await oni.client.getRenderProcessLogs() + console.log("") + console.log("---LOGS (Renderer): " + testName) + writeLogs(rendererLogs) + console.log("--- " + testName + " ---") + } else { + console.log("-- LOGS: Skipped writing logs because the test passed.") + } console.log("") logWithTimeStamp("---RESULT: " + testName) @@ -198,7 +203,6 @@ export const runInProcTest = ( console.log("--- " + testName + " ---") console.log("") - const result = JSON.parse(resultText) if (failures && !result.passed) { const failedTest: IFailedTest = { test: testName, From 45d7098a24dc7c8820b643943f078a4ea0a32dc6 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sun, 11 Feb 2018 16:12:57 -0800 Subject: [PATCH 095/103] Sidebar - Refactoring: Separate Explorer initialization (#1520) * Add explorer * Add explorer entry * Refactor explorer initialization to an explicit activate as opposed to being implicitly added with the sidebar --- browser/src/Services/Explorer/index.tsx | 21 +++++++++++++++++++++ browser/src/Services/Sidebar/index.ts | 3 --- browser/src/index.tsx | 9 ++++++--- 3 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 browser/src/Services/Explorer/index.tsx diff --git a/browser/src/Services/Explorer/index.tsx b/browser/src/Services/Explorer/index.tsx new file mode 100644 index 0000000000..022aefe55e --- /dev/null +++ b/browser/src/Services/Explorer/index.tsx @@ -0,0 +1,21 @@ +/** + * Explorer/index.tsx + * + * Entry point for explorer-related features + */ + +import { CommandManager } from "./../CommandManager" +import { EditorManager } from "./../EditorManager" +import { SidebarManager } from "./../Sidebar" +import { Workspace } from "./../Workspace" + +import { ExplorerSplit } from "./ExplorerSplit" + +export const activate = ( + commandManager: CommandManager, + editorManager: EditorManager, + sidebarManager: SidebarManager, + workspace: Workspace, +) => { + sidebarManager.add("files-o", new ExplorerSplit(workspace, commandManager, editorManager)) +} diff --git a/browser/src/Services/Sidebar/index.ts b/browser/src/Services/Sidebar/index.ts index e561ab9256..dc2ae0d81d 100644 --- a/browser/src/Services/Sidebar/index.ts +++ b/browser/src/Services/Sidebar/index.ts @@ -1,10 +1,8 @@ import { commandManager } from "./../../Services/CommandManager" import { Configuration } from "./../../Services/Configuration" -import { editorManager } from "./../../Services/EditorManager" import { windowManager } from "./../../Services/WindowManager" import { Workspace } from "./../../Services/Workspace" -import { ExplorerSplit } from "./../Explorer/ExplorerSplit" import { SidebarManager } from "./SidebarStore" let _sidebarManager: SidebarManager = null @@ -14,7 +12,6 @@ export * from "./SidebarStore" export const activate = (configuration: Configuration, workspace: Workspace) => { if (configuration.getValue("sidebar.enabled")) { _sidebarManager = new SidebarManager(windowManager) - _sidebarManager.add("files-o", new ExplorerSplit(workspace, commandManager, editorManager)) commandManager.registerCommand({ command: "sidebar.toggle", diff --git a/browser/src/index.tsx b/browser/src/index.tsx index e5bd73e0de..b692af46da 100644 --- a/browser/src/index.tsx +++ b/browser/src/index.tsx @@ -189,8 +189,14 @@ const start = async (args: string[]): Promise => { Performance.startMeasure("Oni.Start.Sidebar") const Sidebar = await sidebarPromise + const Explorer = await import("./Services/Explorer") + const Search = await import("./Services/Search") + Sidebar.activate(configuration, workspace) const sidebarManager = Sidebar.getInstance() + + Explorer.activate(commandManager, editorManager, Sidebar.getInstance(), workspace) + Search.activate(commandManager, editorManager, Sidebar.getInstance(), workspace) Performance.endMeasure("Oni.Start.Sidebar") const createLanguageClientsFromConfiguration = @@ -220,9 +226,6 @@ const start = async (args: string[]): Promise => { const Snippets = await snippetPromise Snippets.activate() - const Search = await import("./Services/Search") - Search.activate(commandManager, editorManager, Sidebar.getInstance(), workspace) - const ThemePicker = await themePickerPromise ThemePicker.activate(configuration, menuManager, Themes.getThemeManagerInstance()) From 952367eefba7c663424a4de2b55169062d8c6a6f Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sun, 11 Feb 2018 16:13:06 -0800 Subject: [PATCH 096/103] Make animation a bit more subtle (#1521) --- browser/src/UI/components/Tabs.tsx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/browser/src/UI/components/Tabs.tsx b/browser/src/UI/components/Tabs.tsx index cb44c74f20..cd07cb1fa2 100644 --- a/browser/src/UI/components/Tabs.tsx +++ b/browser/src/UI/components/Tabs.tsx @@ -8,6 +8,7 @@ import * as React from "react" import { connect } from "react-redux" import * as classNames from "classnames" +import { keyframes } from "styled-components" import * as BufferSelectors from "./../../Editor/NeovimEditor/NeovimEditorSelectors" import * as State from "./../../Editor/NeovimEditor/NeovimEditorStore" @@ -124,6 +125,15 @@ export interface ITabPropsWithClick extends ITabProps { maxWidth: string } +const TabEntranceKeyFrames = keyframes` + 0% { transform: translateY(-3px) rotateX(-20deg); } + 100% { transform: translateY(0px) rotateX(0deg); } +` + +const TabWrapper = styled.div` + animation: ${TabEntranceKeyFrames} 0.1s ease-in forwards; +` + export class Tab extends React.Component { private _tab: HTMLDivElement public componentWillReceiveProps(next: ITabPropsWithClick) { @@ -139,7 +149,7 @@ export class Tab extends React.Component { "not-dirty": !this.props.isDirty, }) - const style = { + const style: React.CSSProperties = { backgroundColor: this.props.backgroundColor, color: this.props.foregroundColor, maxWidth: this.props.maxWidth, @@ -149,8 +159,8 @@ export class Tab extends React.Component { return ( this.props.onClickName()}> -
    (this._tab = e)} + (this._tab = e)} className={cssClasses} title={this.props.description} style={style} @@ -175,7 +185,7 @@ export class Tab extends React.Component {
    -
    + ) } From 2600d22b70d53baef9ec00a9914f7ca587c3fbbe Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sun, 11 Feb 2018 16:16:54 -0800 Subject: [PATCH 097/103] UX: Add a simple spinner while a search query is in progress (#1522) * Refactor SearchPaneView to separate file * Add a small spinner while the search query is in progress for visual feedback --- .../src/Services/Search/SearchPaneView.tsx | 182 +++++++++++++++ .../Search/SearchResultsSpinnerView.tsx | 90 ++++++++ browser/src/Services/Search/index.tsx | 218 +++--------------- 3 files changed, 306 insertions(+), 184 deletions(-) create mode 100644 browser/src/Services/Search/SearchPaneView.tsx create mode 100644 browser/src/Services/Search/SearchResultsSpinnerView.tsx diff --git a/browser/src/Services/Search/SearchPaneView.tsx b/browser/src/Services/Search/SearchPaneView.tsx new file mode 100644 index 0000000000..292a353f25 --- /dev/null +++ b/browser/src/Services/Search/SearchPaneView.tsx @@ -0,0 +1,182 @@ +/** + * Search/index.tsx + * + * Entry point for search-related features + */ + +import * as React from "react" + +import { IDisposable, IEvent } from "oni-types" + +import { Workspace } from "./../Workspace" + +export * from "./SearchProvider" + +import { ISearchOptions } from "./SearchProvider" + +import { SearchTextBox } from "./SearchTextBox" +import styled from "styled-components" + +import { SidebarEmptyPaneView } from "./../../UI/components/SidebarEmptyPaneView" +import { VimNavigator } from "./../../UI/components/VimNavigator" + +const Label = styled.div` + margin: 8px; +` + +export interface ISearchPaneViewProps { + workspace: Workspace + onEnter: IEvent + onLeave: IEvent + onFocus: IEvent + focusImmediately?: boolean + + onSearchOptionsChanged: (opts: ISearchOptions) => void +} + +export interface ISearchPaneViewState { + activeWorkspace: string + isActive: boolean + activeTextbox: string + + searchQuery: string + fileFilter: string +} + +export class SearchPaneView extends React.PureComponent< + ISearchPaneViewProps, + ISearchPaneViewState +> { + private _subscriptions: IDisposable[] = [] + + constructor(props: ISearchPaneViewProps) { + super(props) + + this.state = { + activeWorkspace: this.props.workspace.activeWorkspace, + isActive: false, + activeTextbox: null, + searchQuery: "Search...", + fileFilter: null, + } + } + + public componentDidMount(): void { + this._cleanExistingSubscriptions() + + const s1 = this.props.onEnter.subscribe(() => this.setState({ isActive: true })) + const s2 = this.props.onLeave.subscribe(() => this.setState({ isActive: false })) + const s3 = this.props.workspace.onDirectoryChanged.subscribe((wd: string) => + this.setState({ activeWorkspace: wd }), + ) + + const s4 = this.props.onFocus.subscribe(() => + this.setState({ activeTextbox: "textbox.query" }), + ) + + this._subscriptions = [s1, s2, s3, s4] + + if (this.props.focusImmediately) { + this.setState({ + activeTextbox: "textbox.query", + }) + } + } + + public componentWillUnmount(): void { + this._cleanExistingSubscriptions() + } + + private _cleanExistingSubscriptions(): void { + this._subscriptions.forEach(s => s.dispose()) + this._subscriptions = [] + } + + public render(): JSX.Element { + if (!this.state.activeWorkspace) { + return ( + this.props.workspace.openFolder()} + /> + ) + } + + return ( + { + this._onSelected(selectedId) + }} + render={(selectedId: string) => { + return ( +
    + + this._onChangeSearchQuery(val)} + onCommit={() => this._clearActiveTextbox()} + onDismiss={() => this._clearActiveTextbox()} + isFocused={selectedId === "textbox.query"} + isActive={this.state.activeTextbox === "textbox.query"} + onClick={() => this._onSelected("textbox.query")} + /> + {/* + this._onChangeFilesFilter(val)} + onCommit={() => this._clearActiveTextbox()} + onDismiss={() => this._clearActiveTextbox()} + isFocused={selectedId === "textbox.filter"} + isActive={this.state.activeTextbox === "textbox.filter"} + />*/} +
    + ) + }} + /> + ) + } + + // private _onChangeFilesFilter(val: string): void { + // this.setState({ + // fileFilter: val, + // }) + + // this._startSearch() + // } + + private _onChangeSearchQuery(val: string): void { + this.setState({ + searchQuery: val, + }) + + this._startSearch(val) + } + + // private _onCommit(): void { + + // } + + private _clearActiveTextbox(): void { + this.setState({ activeTextbox: null }) + } + + private _onSelected(selectedId: string): void { + if (selectedId === "textbox.query") { + this.setState({ activeTextbox: "textbox.query" }) + } else if (selectedId === "textbox.filter") { + this.setState({ activeTextbox: "textbox.filter" }) + } + } + + private _startSearch(val: string): void { + this.props.onSearchOptionsChanged({ + searchQuery: val, + fileFilter: this.state.fileFilter, + workspace: this.props.workspace.activeWorkspace, + }) + } +} diff --git a/browser/src/Services/Search/SearchResultsSpinnerView.tsx b/browser/src/Services/Search/SearchResultsSpinnerView.tsx new file mode 100644 index 0000000000..a2391a341a --- /dev/null +++ b/browser/src/Services/Search/SearchResultsSpinnerView.tsx @@ -0,0 +1,90 @@ +/** + * Search/index.tsx + * + * Entry point for search-related features + */ + +import * as React from "react" + +import { IDisposable, IEvent } from "oni-types" + +import styled, { keyframes } from "styled-components" + +import { withProps } from "./../../UI/components/common" +import { Icon, IconSize } from "./../../UI/Icon" + +export interface ISearchResultSpinnerViewProps { + onSearchStarted: IEvent + onSearchFinished: IEvent +} + +export interface ISearchResultSpinnerViewState { + isActive: boolean +} + +const SpinnerWrapper = withProps<{ isActive: boolean }>(styled.div)` + opacity: ${props => (props.isActive ? "0.5" : "0")}; + transition: opacity 0.5s ease-in; + + width: 100%; + min-height: 5em; + + display: flex; + justify-content: center; + align-items: center; + + position: relative; +` + +const RotateKeyFrames = keyframes` + 0% { transform: rotateZ(0deg); } + 100% { transform: rotateZ(360deg); } +` + +const SpinnerRotator = styled.div` + animation: ${RotateKeyFrames} 0.5s linear infinite; + transform-origin: center; +` + +export class SearchResultSpinnerView extends React.PureComponent< + ISearchResultSpinnerViewProps, + ISearchResultSpinnerViewState +> { + private _subscriptions: IDisposable[] = [] + + constructor(props: ISearchResultSpinnerViewProps) { + super(props) + + this.state = { + isActive: false, + } + } + + public componentDidMount(): void { + this._cleanExistingSubscriptions() + + const s1 = this.props.onSearchStarted.subscribe(() => this.setState({ isActive: true })) + const s2 = this.props.onSearchFinished.subscribe(() => this.setState({ isActive: false })) + + this._subscriptions = [s1, s2] + } + + public componentWillUnmount(): void { + this._cleanExistingSubscriptions() + } + + private _cleanExistingSubscriptions(): void { + this._subscriptions.forEach(s => s.dispose()) + this._subscriptions = [] + } + + public render(): JSX.Element { + return ( + + + + + + ) + } +} diff --git a/browser/src/Services/Search/index.tsx b/browser/src/Services/Search/index.tsx index f50101d8a9..eb498f8efa 100644 --- a/browser/src/Services/Search/index.tsx +++ b/browser/src/Services/Search/index.tsx @@ -6,30 +6,35 @@ import * as React from "react" -import { Event, IDisposable, IEvent } from "oni-types" - import { Subject } from "rxjs/Subject" +import { Event, IEvent } from "oni-types" + import { CommandManager } from "./../CommandManager" import { EditorManager } from "./../EditorManager" import { SidebarManager } from "./../Sidebar" import { Workspace } from "./../Workspace" +import * as Log from "./../../Log" + export * from "./SearchProvider" import { - ISearchProvider, ISearchOptions, + ISearchProvider, ISearchQuery, - RipGrepSearchProvider, QuickFixSearchResultsViewer, + RipGrepSearchProvider, } from "./SearchProvider" -import { SearchTextBox } from "./SearchTextBox" +import { SearchResultSpinnerView } from "./SearchResultsSpinnerView" +import { SearchPaneView } from "./SearchPaneView" export class SearchPane { private _onEnter = new Event() private _onLeave = new Event() + private _onSearchStarted = new Event() + private _onSearchCompleted = new Event() private _shouldFocusAutomatically: boolean = false private _searchProvider: ISearchProvider @@ -52,7 +57,7 @@ export class SearchPane { ) { this._searchProvider = new RipGrepSearchProvider() - this._searchOptionsObservable.debounceTime(100).subscribe((opts: ISearchOptions) => { + this._searchOptionsObservable.auditTime(100).subscribe((opts: ISearchOptions) => { this._startNewSearch(opts) }) @@ -73,14 +78,20 @@ export class SearchPane { const immedateFocus = this._shouldFocusAutomatically this._shouldFocusAutomatically = false return ( - this._onSearchOptionsChanged(opts)} - focusImmediately={immedateFocus} - /> +
    + this._onSearchOptionsChanged(opts)} + focusImmediately={immedateFocus} + /> + +
    ) } @@ -89,17 +100,24 @@ export class SearchPane { } private _startNewSearch(searchOpts: ISearchOptions): void { - console.log("changed: " + searchOpts) - if (this._currentQuery) { this._currentQuery.cancel() } + if (!searchOpts.searchQuery || searchOpts.searchQuery.length < 1) { + return + } + + Log.verbose("[SearchPane::_startNewSearch]: " + searchOpts.searchQuery) + + this._onSearchStarted.dispatch() + const query = this._searchProvider.search(searchOpts) query.start() query.onSearchCompleted.subscribe(result => { + this._onSearchCompleted.dispatch() const visualizer = new QuickFixSearchResultsViewer(this._editorManager) visualizer.showResult(result) }) @@ -108,174 +126,6 @@ export class SearchPane { } } -import styled from "styled-components" - -import { SidebarEmptyPaneView } from "./../../UI/components/SidebarEmptyPaneView" -import { VimNavigator } from "./../../UI/components/VimNavigator" - -const Label = styled.div` - margin: 8px; -` - -export interface ISearchPaneViewProps { - workspace: Workspace - onEnter: IEvent - onLeave: IEvent - onFocus: IEvent - focusImmediately?: boolean - - onSearchOptionsChanged: (opts: ISearchOptions) => void -} - -export interface ISearchPaneViewState { - activeWorkspace: string - isActive: boolean - activeTextbox: string - - searchQuery: string - fileFilter: string -} - -export class SearchPaneView extends React.PureComponent< - ISearchPaneViewProps, - ISearchPaneViewState -> { - private _subscriptions: IDisposable[] = [] - - constructor(props: ISearchPaneViewProps) { - super(props) - - this.state = { - activeWorkspace: this.props.workspace.activeWorkspace, - isActive: false, - activeTextbox: null, - searchQuery: "Search...", - fileFilter: null, - } - } - - public componentDidMount(): void { - this._cleanExistingSubscriptions() - - const s1 = this.props.onEnter.subscribe(() => this.setState({ isActive: true })) - const s2 = this.props.onLeave.subscribe(() => this.setState({ isActive: false })) - const s3 = this.props.workspace.onDirectoryChanged.subscribe((wd: string) => - this.setState({ activeWorkspace: wd }), - ) - - const s4 = this.props.onFocus.subscribe(() => - this.setState({ activeTextbox: "textbox.query" }), - ) - - this._subscriptions = [s1, s2, s3, s4] - - if (this.props.focusImmediately) { - this.setState({ - activeTextbox: "textbox.query", - }) - } - } - - public componentWillUnmount(): void { - this._cleanExistingSubscriptions() - } - - private _cleanExistingSubscriptions(): void { - this._subscriptions.forEach(s => s.dispose()) - this._subscriptions = [] - } - - public render(): JSX.Element { - if (!this.state.activeWorkspace) { - return ( - this.props.workspace.openFolder()} - /> - ) - } - - return ( - { - this._onSelected(selectedId) - }} - render={(selectedId: string) => { - return ( -
    - - this._onChangeSearchQuery(val)} - onCommit={() => this._clearActiveTextbox()} - onDismiss={() => this._clearActiveTextbox()} - isFocused={selectedId === "textbox.query"} - isActive={this.state.activeTextbox === "textbox.query"} - onClick={() => this._onSelected("textbox.query")} - /> - {/* - this._onChangeFilesFilter(val)} - onCommit={() => this._clearActiveTextbox()} - onDismiss={() => this._clearActiveTextbox()} - isFocused={selectedId === "textbox.filter"} - isActive={this.state.activeTextbox === "textbox.filter"} - />*/} -
    - ) - }} - /> - ) - } - - // private _onChangeFilesFilter(val: string): void { - // this.setState({ - // fileFilter: val, - // }) - - // this._startSearch() - // } - - private _onChangeSearchQuery(val: string): void { - this.setState({ - searchQuery: val, - }) - - this._startSearch() - } - - // private _onCommit(): void { - - // } - - private _clearActiveTextbox(): void { - this.setState({ activeTextbox: null }) - } - - private _onSelected(selectedId: string): void { - if (selectedId === "button.search") { - this._startSearch() - } else if (selectedId === "textbox.query") { - this.setState({ activeTextbox: "textbox.query" }) - } else if (selectedId === "textbox.filter") { - this.setState({ activeTextbox: "textbox.filter" }) - } - } - - private _startSearch(): void { - this.props.onSearchOptionsChanged({ - searchQuery: this.state.searchQuery, - fileFilter: this.state.fileFilter, - workspace: this.props.workspace.activeWorkspace, - }) - } -} - export const activate = ( commandManager: CommandManager, editorManager: EditorManager, From c8dc1482a4a6a54b45604b251775b5312528e9b4 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sun, 11 Feb 2018 17:03:59 -0800 Subject: [PATCH 098/103] Bugfix: Crash in completion providers when a completion provider returns 'null' (#1516) * Add test case for CompletionProviders * Add red test case exercising crash in production * Get test green --- .../Completion/CompletionProviders.ts | 3 +- .../Completion/CompletionProvidersTests.ts | 78 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 browser/test/Services/Completion/CompletionProvidersTests.ts diff --git a/browser/src/Services/Completion/CompletionProviders.ts b/browser/src/Services/Completion/CompletionProviders.ts index 25dfe522c1..f1a04f7657 100644 --- a/browser/src/Services/Completion/CompletionProviders.ts +++ b/browser/src/Services/Completion/CompletionProviders.ts @@ -34,7 +34,8 @@ export class CompletionProviders implements ICompletionsRequestor { column: number, ): Promise { const completionItemsPromise = this._completionProviders.map(async prov => { - const items = await prov.provider.getCompletions(language, filePath, line, column) + const items = + (await prov.provider.getCompletions(language, filePath, line, column)) || [] // Tag the items with the provider id, so we know who to ask for details const augmentedItems = items.map(item => { diff --git a/browser/test/Services/Completion/CompletionProvidersTests.ts b/browser/test/Services/Completion/CompletionProvidersTests.ts new file mode 100644 index 0000000000..9ea385389d --- /dev/null +++ b/browser/test/Services/Completion/CompletionProvidersTests.ts @@ -0,0 +1,78 @@ +/** + * CompletionProvidersTests.ts + */ + +import * as assert from "assert" + +import * as types from "vscode-languageserver-types" + +import { CompletionProviders, ICompletionsRequestor } from "./../../../src/Services/Completion" + +export class MockCompletionsRequestor implements ICompletionsRequestor { + constructor(private _hardcodedCompletions: types.CompletionItem[]) {} + + public async getCompletions( + fileLanguage: string, + filePath: string, + line: number, + column: number, + ): Promise { + return this._hardcodedCompletions + } + + public async getCompletionDetails( + fileLanguage: string, + filePath: string, + completionItem: types.CompletionItem, + ): Promise { + return null + } +} + +const createCompletionItem = (item: string): types.CompletionItem => ({ + label: item, + detail: item, +}) + +describe("CompletionProvider", () => { + it("combines completions from multiple providers", async () => { + const provider1 = new MockCompletionsRequestor([ + createCompletionItem("a"), + createCompletionItem("b"), + ]) + const provider2 = new MockCompletionsRequestor([ + createCompletionItem("c"), + createCompletionItem("d"), + ]) + + const completionProviders = new CompletionProviders() + completionProviders.registerCompletionProvider("provider1", provider1) + completionProviders.registerCompletionProvider("provider2", provider2) + + const result = await completionProviders.getCompletions("lang", "file", 0, 0) + + const resultItems = result.map(i => i.label) + + assert.strictEqual(result.length, 4) + assert.deepEqual(resultItems, ["a", "b", "c", "d"]) + }) + + it("handles case where one completion provider returns null", async () => { + const provider1 = new MockCompletionsRequestor(null) + const provider2 = new MockCompletionsRequestor([ + createCompletionItem("c"), + createCompletionItem("d"), + ]) + + const completionProviders = new CompletionProviders() + completionProviders.registerCompletionProvider("provider1", provider1) + completionProviders.registerCompletionProvider("provider2", provider2) + + const result = await completionProviders.getCompletions("lang", "file", 0, 0) + + const resultItems = result.map(i => i.label) + + assert.strictEqual(result.length, 2) + assert.deepEqual(resultItems, ["c", "d"]) + }) +}) From 62bc23c42a90e3b48e7f0ec737cb907755d06877 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sun, 11 Feb 2018 20:49:16 -0800 Subject: [PATCH 099/103] Build: Enable 'npm run build-debug' again (#1515) * Add additional config for debug builds * Fix up configs to enable debug builds again --- browser/webpack.debug.config.js | 67 ++++++--------------------- browser/webpack.development.config.js | 63 +++++++++++++++++++++++++ browser/webpack.production.config.js | 11 ++--- package.json | 2 +- 4 files changed, 82 insertions(+), 61 deletions(-) create mode 100644 browser/webpack.development.config.js diff --git a/browser/webpack.debug.config.js b/browser/webpack.debug.config.js index 61b8b7cc4d..12b7e0166d 100644 --- a/browser/webpack.debug.config.js +++ b/browser/webpack.debug.config.js @@ -1,63 +1,26 @@ -var path = require("path") -var webpack = require("webpack") +const path = require("path") -module.exports = { - entry: [path.join(__dirname, "src/index.tsx")], - target: "electron-renderer", - externals: { - "vscode-jsonrpc": "require('vscode-jsonrpc')", - "vscode-textmate": "require('vscode-textmate')", - "vscode-languageserver-types": "require('vscode-languageserver-types')", - "keyboard-layout": "require('keyboard-layout')", - gifshot: "require('gifshot')", - "msgpack-lite": "require('msgpack-lite')", - "styled-components": "require('styled-components')", - }, - resolve: { - extensions: [".tsx", ".ts", ".js", ".less"], - }, - devtool: "cheap-module-eval-source-map", - module: { - rules: [ - { - test: /\.less$/, - use: [ - { - loader: "style-loader", // creates style nodes from JS strings - }, - { - loader: "css-loader", // translates CSS into CommonJS - }, - { - loader: "less-loader", // compiles Less to CSS - }, - ], - }, - { - test: /\.css$/, - use: ["style-loader", "css-loader"], - exclude: /node_modules/, - }, - { - test: /\.tsx?$/, - use: "ts-loader", - exclude: /node_modules/, - }, - ], - }, +const webpack = require("webpack") + +// Override 'development' settings +const baseConfig = require("./webpack.development.config.js") + +const debugConfig = Object.assign({}, baseConfig, { plugins: [ new webpack.DefinePlugin({ "process.env.NODE_ENV": '"development"', }), + new webpack.optimize.CommonsChunkPlugin({ + async: true, + minChunks: 2, + }), ], output: { path: path.join(__dirname, "..", "lib", "browser"), - publicPath: "http://localhost:8191/", + publicPath: "lib/browser/", filename: "bundle.js", chunkFilename: "[name].bundle.js", }, - node: { - process: false, - __dirname: false, - }, -} +}) + +module.exports = debugConfig diff --git a/browser/webpack.development.config.js b/browser/webpack.development.config.js new file mode 100644 index 0000000000..61b8b7cc4d --- /dev/null +++ b/browser/webpack.development.config.js @@ -0,0 +1,63 @@ +var path = require("path") +var webpack = require("webpack") + +module.exports = { + entry: [path.join(__dirname, "src/index.tsx")], + target: "electron-renderer", + externals: { + "vscode-jsonrpc": "require('vscode-jsonrpc')", + "vscode-textmate": "require('vscode-textmate')", + "vscode-languageserver-types": "require('vscode-languageserver-types')", + "keyboard-layout": "require('keyboard-layout')", + gifshot: "require('gifshot')", + "msgpack-lite": "require('msgpack-lite')", + "styled-components": "require('styled-components')", + }, + resolve: { + extensions: [".tsx", ".ts", ".js", ".less"], + }, + devtool: "cheap-module-eval-source-map", + module: { + rules: [ + { + test: /\.less$/, + use: [ + { + loader: "style-loader", // creates style nodes from JS strings + }, + { + loader: "css-loader", // translates CSS into CommonJS + }, + { + loader: "less-loader", // compiles Less to CSS + }, + ], + }, + { + test: /\.css$/, + use: ["style-loader", "css-loader"], + exclude: /node_modules/, + }, + { + test: /\.tsx?$/, + use: "ts-loader", + exclude: /node_modules/, + }, + ], + }, + plugins: [ + new webpack.DefinePlugin({ + "process.env.NODE_ENV": '"development"', + }), + ], + output: { + path: path.join(__dirname, "..", "lib", "browser"), + publicPath: "http://localhost:8191/", + filename: "bundle.js", + chunkFilename: "[name].bundle.js", + }, + node: { + process: false, + __dirname: false, + }, +} diff --git a/browser/webpack.production.config.js b/browser/webpack.production.config.js index 61af42eb25..5a7464482a 100644 --- a/browser/webpack.production.config.js +++ b/browser/webpack.production.config.js @@ -2,6 +2,7 @@ const path = require("path") const webpack = require("webpack") +// Override 'debug' settings const baseConfig = require("./webpack.debug.config.js") const OptimizeJsPlugin = require("optimize-js-plugin") @@ -11,7 +12,7 @@ const productionConfig = Object.assign({}, baseConfig, { devtool: false, plugins: [ new webpack.DefinePlugin({ - "process.env.NODE_ENV":'"production"' + "process.env.NODE_ENV": '"production"', }), new webpack.optimize.CommonsChunkPlugin({ async: true, @@ -19,15 +20,9 @@ const productionConfig = Object.assign({}, baseConfig, { }), new BabiliPlugin(), new OptimizeJsPlugin({ - sourceMap: false + sourceMap: false, }), ], - output: { - path: path.join(__dirname, "..", "lib", "browser"), - publicPath: "lib/browser/", - filename: "bundle.js", - chunkFilename: "[name].bundle.js" - }, }) module.exports = productionConfig diff --git a/package.json b/package.json index 0a397ccdf1..e48eb8d5eb 100644 --- a/package.json +++ b/package.json @@ -173,7 +173,7 @@ "start": "concurrently --kill-others \"npm run start-hot\" \"npm run watch:browser\" \"npm run watch:plugins\"", "start-hot": "cross-env ONI_WEBPACK_LOAD=1 NODE_ENV=development electron lib/main/src/main.js", "start-not-dev": "cross-env electron main.js", - "watch:browser": "webpack-dev-server --config browser/webpack.debug.config.js --host localhost --port 8191", + "watch:browser": "webpack-dev-server --config browser/webpack.development.config.js --host localhost --port 8191", "watch:plugins": "npm run watch:plugins:oni-plugin-typescript && npm run watch:plugins:oni-plugin-markdown-preview", "watch:plugins:oni-plugin-typescript": "cd vim/core/oni-plugin-typescript && tsc --watch", "watch:plugins:oni-plugin-markdown-preview": "cd extensions/oni-plugin-markdown-preview && tsc --watch", From 488b7f7567466c9c780b3db24fe2c86a5e4981cb Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sun, 11 Feb 2018 20:49:37 -0800 Subject: [PATCH 100/103] Some additional logging to troubleshoot failure to start test (#1525) --- browser/src/neovim/NeovimInstance.ts | 12 +++++++++++- browser/src/neovim/NeovimProcessSpawner.ts | 5 ++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/browser/src/neovim/NeovimInstance.ts b/browser/src/neovim/NeovimInstance.ts index 74ce0b241a..b360f810b9 100644 --- a/browser/src/neovim/NeovimInstance.ts +++ b/browser/src/neovim/NeovimInstance.ts @@ -839,7 +839,11 @@ export class NeovimInstance extends EventEmitter implements INeovimInstance { const externaliseTabline = !useNativeTabs const externalisePopupWindows = !useNativePopupWindows - console.log(`Neovim version reported as ${version.major}.${version.minor}.${version.patch}`) // tslint:disable-line no-console + Log.info( + `[NeovimInstance::_attachUI] Neovim version reported as ${version.major}.${ + version.minor + }.${version.patch}`, + ) // tslint:disable-line no-console const startupOptions = this._getStartupOptionsForVersion( version.major, @@ -849,6 +853,12 @@ export class NeovimInstance extends EventEmitter implements INeovimInstance { externalisePopupWindows, ) + Log.info( + `[NeovimInstance::_attachUI] Using startup options: ${JSON.stringify( + startupOptions, + )} and size: ${columns}, ${rows}`, + ) + await this._neovim.request("nvim_ui_attach", [columns, rows, startupOptions]) } diff --git a/browser/src/neovim/NeovimProcessSpawner.ts b/browser/src/neovim/NeovimProcessSpawner.ts index 089df1d7df..ea0f510fdb 100644 --- a/browser/src/neovim/NeovimProcessSpawner.ts +++ b/browser/src/neovim/NeovimProcessSpawner.ts @@ -125,8 +125,11 @@ export const startNeovim = async ( "--", ]) + Log.verbose( + "[NeovimProcessSpawner::startNeovim] Sending these args to Neovim: " + + argsToPass.toString(), + ) const nvimProc = await spawnProcess(nvimProcessPath, argsToPass, {}) - Log.info(`[NeovimProcessSpawner::startNeovim] Starting Neovim - process: ${nvimProc.pid}`) // tslint:disable-line no-console return getSessionFromProcess(nvimProc, options.transport) From b93cf750de32c3fb2bea420ea6222115daabbe49 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sun, 11 Feb 2018 20:49:47 -0800 Subject: [PATCH 101/103] Disable notifications in production builds (#1526) --- browser/src/Services/Configuration/DefaultConfiguration.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index 171cafca12..c71287352f 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -217,7 +217,9 @@ const BaseConfiguration: IConfigurationValues = { "menu.rowHeight": 40, "menu.maxItemsToShow": 8, - "notifications.enabled": true, + // TEMPORARY - Since notifications came late in the cycle for this release, + // temporarily disabling it so that we have a bit more time to stabilize. + "notifications.enabled": process.env.NODE_ENV !== "production", "recorder.copyScreenshotToClipboard": false, "recorder.outputPath": os.tmpdir(), From 2d057c3536f5a54bd68ba6e6abb0f04e7a39c545 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sun, 11 Feb 2018 20:49:57 -0800 Subject: [PATCH 102/103] Bump package version from 0.2.22 -> 0.3.0 (#1527) * Bump package version from 0.2.22 -> 0.3.0 * Actually bump version... --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e48eb8d5eb..3bfd77b35e 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,8 @@ "author": "", "email": "bryphe@outlook.com", "homepage": "https://www.onivim.io", - "version": "0.2.22", - "description": "NeoVim front-end with IDE-style extensibility", + "version": "0.3.0", + "description": "Code editor with a modern twist on modal editing - powered by neovim.", "keywords": [ "vim", "neovim", From 2336dc75849715a71472173a3b90fd97fe57eb0b Mon Sep 17 00:00:00 2001 From: Akin Date: Mon, 12 Feb 2018 15:49:40 +0000 Subject: [PATCH 103/103] Add commandline and wildmenu mode on by default (#1532) --- browser/src/Services/Configuration/DefaultConfiguration.ts | 6 +++--- browser/src/Services/Configuration/IConfigurationValues.ts | 5 +++-- browser/src/neovim/NeovimInstance.ts | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/browser/src/Services/Configuration/DefaultConfiguration.ts b/browser/src/Services/Configuration/DefaultConfiguration.ts index c71287352f..11f528032f 100644 --- a/browser/src/Services/Configuration/DefaultConfiguration.ts +++ b/browser/src/Services/Configuration/DefaultConfiguration.ts @@ -44,10 +44,10 @@ const BaseConfiguration: IConfigurationValues = { "debug.fakeLag.neovimInput": null, "experimental.editor.textMateHighlighting.enabled": false, - "experimental.commandline.mode": false, - "experimental.commandline.icons": false, + "wildmenu.mode": true, + "commandline.mode": true, + "commandline.icons": true, "experimental.welcome.enabled": false, - "experimental.wildmenu.mode": false, "experimental.neovim.transport": "stdio", // TODO: Enable pipe transport for Windows diff --git a/browser/src/Services/Configuration/IConfigurationValues.ts b/browser/src/Services/Configuration/IConfigurationValues.ts index 1dd32fdabc..08e7db9ac0 100644 --- a/browser/src/Services/Configuration/IConfigurationValues.ts +++ b/browser/src/Services/Configuration/IConfigurationValues.ts @@ -40,8 +40,9 @@ export interface IConfigurationValues { // The transport to use for Neovim // Valid values are "stdio" and "pipe" "experimental.neovim.transport": string - "experimental.commandline.mode": boolean - "experimental.commandline.icons": boolean + "wildmenu.mode": boolean + "commandline.mode": boolean + "commandline.icons": boolean "experimental.welcome.enabled": boolean diff --git a/browser/src/neovim/NeovimInstance.ts b/browser/src/neovim/NeovimInstance.ts index b360f810b9..3398cb5570 100644 --- a/browser/src/neovim/NeovimInstance.ts +++ b/browser/src/neovim/NeovimInstance.ts @@ -870,8 +870,8 @@ export class NeovimInstance extends EventEmitter implements INeovimInstance { shouldExtPopups: boolean, ) { if (major >= 0 && minor >= 2 && patch >= 1) { - const useExtCmdLine = this._configuration.getValue("experimental.commandline.mode") - const useExtWildMenu = this._configuration.getValue("experimental.wildmenu.mode") + const useExtCmdLine = this._configuration.getValue("commandline.mode") + const useExtWildMenu = this._configuration.getValue("wildmenu.mode") return { rgb: true, popupmenu_external: shouldExtPopups,